/*******************************************************************************
**
*Copyright (c) 2014 PMC-Sierra, Inc.  All rights reserved. 
*
*Redistribution and use in source and binary forms, with or without modification, are permitted provided 
*that the following conditions are met: 
*1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
*following disclaimer. 
*2. Redistributions in binary form must reproduce the above copyright notice, 
*this list of conditions and the following disclaimer in the documentation and/or other materials provided
*with the distribution. 
*
*THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED 
*WARRANTIES,INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
*FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
*FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
*NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
*BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
*LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
*SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
**
********************************************************************************/
#include <sys/cdefs.h>
#include <dev/pms/config.h>

#include <dev/pms/freebsd/driver/common/osenv.h>
#include <dev/pms/freebsd/driver/common/ostypes.h>
#include <dev/pms/freebsd/driver/common/osdebug.h>

#include <dev/pms/RefTisa/sallsdk/api/sa.h>
#include <dev/pms/RefTisa/sallsdk/api/saapi.h>
#include <dev/pms/RefTisa/sallsdk/api/saosapi.h>

#ifdef FDS_DM
#include <dev/pms/RefTisa/discovery/api/dm.h>
#include <dev/pms/RefTisa/discovery/api/dmapi.h>
#include <dev/pms/RefTisa/discovery/api/tddmapi.h>

#include <dev/pms/RefTisa/discovery/dm/dmdefs.h>
#include <dev/pms/RefTisa/discovery/dm/dmtypes.h>
#include <dev/pms/RefTisa/discovery/dm/dmproto.h>

/*****************************************************************************/
/*! \brief dmDiscover
 *  
 *
 *  Purpose: A discovery is started by this function 
 *  
 *  \param   dmRoot:              DM context handle.
 *  \param   dmPortContext:       Pointer to this instance of port context 
 *  \param   option:              Discovery option 
 * 
 *  \return: 
 *          DM_RC_SUCCESS
 *          DM_RC_FAILURE
 *
 */
/*****************************************************************************/
osGLOBAL bit32 	
dmDiscover(  
           dmRoot_t 		*dmRoot,
           dmPortContext_t	*dmPortContext,
           bit32 		option)
{
  dmIntPortContext_t        *onePortContext = agNULL;
  bit32                     ret = DM_RC_FAILURE;
  
  DM_DBG3(("dmDiscover: start\n"));
  onePortContext = (dmIntPortContext_t *)dmPortContext->dmData;
  
  if (onePortContext == agNULL)
  {
    DM_DBG1(("dmDiscover: onePortContext is NULL!!!\n"));
    return DM_RC_FAILURE;
  }
  
  if (onePortContext->valid == agFALSE)
  {
    DM_DBG1(("dmDiscover: invalid port!!!\n"));
    return DM_RC_FAILURE;
  }
  
  if (onePortContext->RegFailed == agTRUE)
  {
    DM_DBG1(("dmDiscover: Registration failed!!!\n"));
    return DM_RC_FAILURE;
  }
  
  switch ( option )
  {
  case DM_DISCOVERY_OPTION_FULL_START:
    DM_DBG3(("dmDiscover: full, pid %d\n", onePortContext->id));
    onePortContext->discovery.type = DM_DISCOVERY_OPTION_FULL_START;
    dmDiscoveryResetMCN(dmRoot, onePortContext);
    ret = dmFullDiscover(dmRoot, onePortContext);
    break;
  case DM_DISCOVERY_OPTION_INCREMENTAL_START:
    DM_DBG3(("dmDiscover: incremental, pid %d\n", onePortContext->id));
    onePortContext->discovery.type = DM_DISCOVERY_OPTION_INCREMENTAL_START;
    dmDiscoveryResetMCN(dmRoot, onePortContext);
    ret = dmIncrementalDiscover(dmRoot, onePortContext, agFALSE);
    break;
  case DM_DISCOVERY_OPTION_ABORT:
    DM_DBG3(("dmDiscover: abort\n"));
    if (onePortContext->DiscoveryState != DM_DSTATE_COMPLETED)
    {
      if (onePortContext->discovery.pendingSMP == 0)
      {
        dmDiscoverAbort(dmRoot, onePortContext);
        tddmDiscoverCB(
                       dmRoot,
                       onePortContext->dmPortContext,
                       dmDiscAborted
                       );
      }
      else
      {
        DM_DBG3(("dmDiscover: abortInProgress\n"));
        onePortContext->DiscoveryAbortInProgress = agTRUE;
        tddmDiscoverCB(
                       dmRoot,
                       dmPortContext,
                       dmDiscAbortInProgress
                       );
      }
    }
    else
    {
      DM_DBG3(("dmDiscover: no discovery to abort\n"));
      tddmDiscoverCB(
                     dmRoot,
                     dmPortContext,
                     dmDiscAbortInvalid
                     );
    }
    ret = DM_RC_SUCCESS;
    break;
  default:
    break;
  }  
  return ret;
}	   				
				
osGLOBAL bit32
dmFullDiscover(
               dmRoot_t 	    	*dmRoot, 
               dmIntPortContext_t       *onePortContext	
              )
{
  dmExpander_t              *oneExpander = agNULL;
  dmSASSubID_t              dmSASSubID;
  dmDeviceData_t            *oneExpDeviceData = agNULL;
    
  DM_DBG1(("dmFullDiscover: start\n"));

  if (onePortContext->valid == agFALSE)
  {
    DM_DBG1(("dmFullDiscover: invalid port!!!\n"));
    return DM_RC_FAILURE;
  }
  
  if (onePortContext->DiscoveryState == DM_DSTATE_STARTED)
  {
    DM_DBG1(("dmFullDiscover: no two instances of discovery allowed!!!\n"));
    return DM_RC_FAILURE;
  }
  
  onePortContext->DiscoveryState = DM_DSTATE_STARTED;
  
  dmSASSubID.sasAddressHi = onePortContext->sasRemoteAddressHi;
  dmSASSubID.sasAddressLo = onePortContext->sasRemoteAddressLo;
  
  /* check OnePortContext->discovery.discoveringExpanderList */
  oneExpander = dmExpFind(dmRoot, onePortContext, dmSASSubID.sasAddressHi, dmSASSubID.sasAddressLo);
  if (oneExpander != agNULL)
  {
    oneExpDeviceData = oneExpander->dmDevice;
  }
  else
  {
    /* check dmAllShared->mainExpanderList */
    oneExpander = dmExpMainListFind(dmRoot, onePortContext, dmSASSubID.sasAddressHi, dmSASSubID.sasAddressLo);
    if (oneExpander != agNULL)
    {
      oneExpDeviceData = oneExpander->dmDevice;
    }
  }
  
  if (oneExpDeviceData != agNULL)
  {
    dmSASSubID.initiator_ssp_stp_smp = oneExpDeviceData->initiator_ssp_stp_smp;
    dmSASSubID.target_ssp_stp_smp = oneExpDeviceData->target_ssp_stp_smp;
    oneExpDeviceData->registered = agTRUE;    
    dmAddSASToSharedcontext(dmRoot, onePortContext, &dmSASSubID, oneExpDeviceData, 0xFF);  
  }
  else
  {
    DM_DBG1(("dmFullDiscover:oneExpDeviceData is NULL!!!\n"));
    return DM_RC_FAILURE;
  }
  
  dmUpStreamDiscoverStart(dmRoot, onePortContext);
  
  return DM_RC_SUCCESS;
}	   		      

osGLOBAL bit32
dmIncrementalDiscover(
                      dmRoot_t 	    	      *dmRoot, 
                      dmIntPortContext_t      *onePortContext,
		      bit32                   flag	
                     )
{
  dmExpander_t              *oneExpander = agNULL;
  dmSASSubID_t              dmSASSubID;
  dmDeviceData_t            *oneExpDeviceData = agNULL;
  
  DM_DBG1(("dmIncrementalDiscover: start\n"));

  if (onePortContext->valid == agFALSE)
  {
    DM_DBG1(("dmIncrementalDiscover: invalid port!!!\n"));
    return DM_RC_FAILURE;
  }
  
  /* TDM triggerred; let go DM triggerred */
  if (flag == agFALSE)
  {
    if (onePortContext->DiscoveryState == DM_DSTATE_STARTED)
    {
      DM_DBG1(("dmIncrementalDiscover: no two instances of discovery allowed!!!\n"));
      return DM_RC_FAILURE;
    }
  }
  
  onePortContext->DiscoveryState = DM_DSTATE_STARTED;
  onePortContext->discovery.type = DM_DISCOVERY_OPTION_INCREMENTAL_START;
  
  dmSASSubID.sasAddressHi = onePortContext->sasRemoteAddressHi;
  dmSASSubID.sasAddressLo = onePortContext->sasRemoteAddressLo;
  
  /* check OnePortContext->discovery.discoveringExpanderList */
  oneExpander = dmExpFind(dmRoot, onePortContext, dmSASSubID.sasAddressHi, dmSASSubID.sasAddressLo);
  if (oneExpander != agNULL)
  {
    oneExpDeviceData = oneExpander->dmDevice;
  }
  else
  {
    /* check dmAllShared->mainExpanderList */
    oneExpander = dmExpMainListFind(dmRoot, onePortContext, dmSASSubID.sasAddressHi, dmSASSubID.sasAddressLo);
    if (oneExpander != agNULL)
    {
      oneExpDeviceData = oneExpander->dmDevice;
    }
  }
  
  if (oneExpDeviceData != agNULL)
  {
    dmSASSubID.initiator_ssp_stp_smp = oneExpDeviceData->initiator_ssp_stp_smp;
    dmSASSubID.target_ssp_stp_smp = oneExpDeviceData->target_ssp_stp_smp;
    oneExpDeviceData->registered = agTRUE;    
    dmAddSASToSharedcontext(dmRoot, onePortContext, &dmSASSubID, oneExpDeviceData, 0xFF);  
  }
  else
  {
    DM_DBG1(("dmIncrementalDiscover:oneExpDeviceData is NULL!!!\n"));
    return DM_RC_FAILURE;
  }
  
  dmUpStreamDiscoverStart(dmRoot, onePortContext);
  
  return DM_RC_SUCCESS;
}	   			     

osGLOBAL void
dmUpStreamDiscoverStart(
                        dmRoot_t             *dmRoot,
                        dmIntPortContext_t   *onePortContext		
                       )
{
//  dmExpander_t              *oneExpander = agNULL;
  bit32                     sasAddressHi, sasAddressLo;
  dmDeviceData_t            *oneDeviceData;
  dmExpander_t              *oneExpander = agNULL;
  
  DM_DBG3(("dmUpStreamDiscoverStart: start\n"));
  if (onePortContext->valid == agFALSE)
  {
    DM_DBG1(("dmUpStreamDiscoverStart: invalid port!!!\n"));
    return;
  }
  /*
    at this point, the 1st expander should have been registered.
    find an expander from onePortContext 
  */
  sasAddressHi = onePortContext->sasRemoteAddressHi;
  sasAddressLo = onePortContext->sasRemoteAddressLo;
  DM_DBG3(("dmUpStreamDiscoverStart: Port Remote AddrHi 0x%08x Remote AddrLo 0x%08x\n", sasAddressHi, sasAddressLo));

  oneDeviceData = dmDeviceFind(dmRoot, onePortContext, sasAddressHi, sasAddressLo);

//  oneDeviceData = oneExpander->dmDevice; 
// start here
  onePortContext->discovery.status = DISCOVERY_UP_STREAM;
  if (oneDeviceData == agNULL)
  {
    DM_DBG1(("dmUpStreamDiscoverStart: oneExpander is NULL, wrong!!!\n"));
    return;
  }
  else
  {
    if ( (oneDeviceData->SASSpecDeviceType == SAS_EDGE_EXPANDER_DEVICE)
         ||
         (oneDeviceData->SASSpecDeviceType == SAS_FANOUT_EXPANDER_DEVICE)
	 ||
	 DEVICE_IS_SMP_TARGET(oneDeviceData)
        )
    {
#if 1  /* for incremental discovery */  
      /* start here: if not on discoveringExpanderList, alloc and add 
      dmNewEXPorNot()
      */
      oneExpander = dmExpFind(dmRoot, onePortContext, sasAddressHi, sasAddressLo);
      if ( oneExpander == agNULL)
      {
        /* alloc and add */
        oneExpander = dmDiscoveringExpanderAlloc(dmRoot, onePortContext, oneDeviceData);
        if ( oneExpander != agNULL)
        {
          dmDiscoveringExpanderAdd(dmRoot, onePortContext, oneExpander);      
        }       
        else
	{
          DM_DBG1(("dmUpStreamDiscoverStart: failed to allocate expander or discovey aborted!!!\n"));
          return;
	}
      }
#endif
 
      dmUpStreamDiscovering(dmRoot, onePortContext, oneDeviceData);
    }
    else
    {
      DM_DBG1(("dmUpStreamDiscoverStart: oneDeviceData is not an Expander did %d, wrong!!!\n", oneDeviceData->id));
      return;
    }
  }
  return;
}  				

/* sends report general */
osGLOBAL void
dmUpStreamDiscovering(
                      dmRoot_t              *dmRoot,
                      dmIntPortContext_t    *onePortContext,
                      dmDeviceData_t        *oneDeviceData
                     )
{
  dmList_t          *ExpanderList;
  dmExpander_t      *oneNextExpander = agNULL;
  
  DM_DBG3(("dmUpStreamDiscovering: start\n"));
  
  if (onePortContext->valid == agFALSE)
  {
    DM_DBG1(("dmUpStreamDiscovering: invalid port!!!\n"));
    return;
  }
  
  tddmSingleThreadedEnter(dmRoot, DM_EXPANDER_LOCK);
  if (DMLIST_EMPTY(&(onePortContext->discovery.discoveringExpanderList)))
  {
    tddmSingleThreadedLeave(dmRoot, DM_EXPANDER_LOCK);
    DM_DBG3(("dmUpStreamDiscovering: should be the end\n"));
    oneNextExpander = agNULL;
  }
  else
  {
    DMLIST_DEQUEUE_FROM_HEAD(&ExpanderList, &(onePortContext->discovery.discoveringExpanderList));
    oneNextExpander = DMLIST_OBJECT_BASE(dmExpander_t, linkNode, ExpanderList);
    if ( oneNextExpander != agNULL)
    {
      DMLIST_ENQUEUE_AT_HEAD(&(oneNextExpander->linkNode), &(onePortContext->discovery.discoveringExpanderList));
      DM_DBG3(("dmUpStreamDiscovering tdsaSASUpStreamDiscovering: dequeue head\n"));
      DM_DBG3(("dmUpStreamDiscovering: expander id %d\n", oneNextExpander->id));
    }
    else
    {
      DM_DBG1(("dmUpStreamDiscovering: oneNextExpander is NULL!!!\n"));
    }
    tddmSingleThreadedLeave(dmRoot, DM_EXPANDER_LOCK);

  }
  
  if (oneNextExpander != agNULL)
  {
    dmReportGeneralSend(dmRoot, oneNextExpander->dmDevice);
  }
  else
  {
    DM_DBG3(("dmUpStreamDiscovering: No more expander list\n"));
    dmDownStreamDiscoverStart(dmRoot, onePortContext, oneDeviceData);
  }
  
  return;
}				

osGLOBAL void
dmDownStreamDiscoverStart(
                          dmRoot_t              *dmRoot,
                          dmIntPortContext_t    *onePortContext,
                          dmDeviceData_t        *oneDeviceData
                         )
{
  dmExpander_t        *UpStreamExpander;
  dmExpander_t        *oneExpander;
  
  DM_DBG3(("dmDownStreamDiscoverStart: start\n"));
  
  if (dmDiscoverCheck(dmRoot, onePortContext) == agTRUE)
  {
    DM_DBG1(("dmDownStreamDiscoverStart: invalid port or aborted discovery!!!\n"));  
    return;
  }

  /* set discovery status */
  onePortContext->discovery.status = DISCOVERY_DOWN_STREAM;

  /* If it's an expander */    
  if ( (oneDeviceData->SASSpecDeviceType == SAS_EDGE_EXPANDER_DEVICE)
       || (oneDeviceData->SASSpecDeviceType == SAS_FANOUT_EXPANDER_DEVICE)
       || DEVICE_IS_SMP_TARGET(oneDeviceData)
       )
  {
    oneExpander = oneDeviceData->dmExpander;    
    UpStreamExpander = oneExpander->dmUpStreamExpander;
    
    /* If the two expanders are the root of two edge sets; sub-to-sub */
    if ( (UpStreamExpander != agNULL) && ( UpStreamExpander->dmUpStreamExpander == oneExpander ) )
    {
      DM_DBG3(("dmDownStreamDiscoverStart: Root found pExpander=%p pUpStreamExpander=%p\n", 
               oneExpander, UpStreamExpander));
      //Saves the root expander
      onePortContext->discovery.RootExp = oneExpander;
      DM_DBG3(("dmDownStreamDiscoverStart: Root exp addrHi 0x%08x\n", oneExpander->dmDevice->SASAddressID.sasAddressHi));
      DM_DBG3(("dmDownStreamDiscoverStart: Root exp addrLo 0x%08x\n", oneExpander->dmDevice->SASAddressID.sasAddressLo));
               
      /* reset up stream inform for pExpander */
      oneExpander->dmUpStreamExpander = agNULL;      
      /* Add the pExpander to discovering list */
      dmDiscoveringExpanderAdd(dmRoot, onePortContext, oneExpander);

      /* reset up stream inform for oneExpander */
      UpStreamExpander->dmUpStreamExpander = agNULL;      
      /* Add the UpStreamExpander to discovering list */
      dmDiscoveringExpanderAdd(dmRoot, onePortContext, UpStreamExpander);
    }
    /* If the two expanders are not the root of two edge sets. eg) one root */
    else
    {
      //Saves the root expander
      onePortContext->discovery.RootExp = oneExpander;

      DM_DBG3(("dmDownStreamDiscoverStart: NO Root pExpander=%p\n", oneExpander));
      DM_DBG3(("dmDownStreamDiscoverStart: Root exp addrHi 0x%08x\n", oneExpander->dmDevice->SASAddressID.sasAddressHi));
      DM_DBG3(("dmDownStreamDiscoverStart: Root exp addrLo 0x%08x\n", oneExpander->dmDevice->SASAddressID.sasAddressLo));
      
      /* (2.2.2.1) Add the pExpander to discovering list */
      dmDiscoveringExpanderAdd(dmRoot, onePortContext, oneExpander);      
    }
  }

  /* Continue down stream discovering */
  dmDownStreamDiscovering(dmRoot, onePortContext, oneDeviceData);
  
  return;
}			 

osGLOBAL void
dmDownStreamDiscovering(
                        dmRoot_t              *dmRoot,
                        dmIntPortContext_t    *onePortContext,
                        dmDeviceData_t        *oneDeviceData
                       )
{
  dmExpander_t      *NextExpander = agNULL;
  dmList_t          *ExpanderList;
  
  DM_DBG3(("dmDownStreamDiscovering: start\n"));
  
  if (dmDiscoverCheck(dmRoot, onePortContext) == agTRUE)
  {
    DM_DBG1(("dmDownStreamDiscovering: invalid port or aborted discovery!!!\n"));  
    return;
  }

  tddmSingleThreadedEnter(dmRoot, DM_EXPANDER_LOCK);
  if (DMLIST_EMPTY(&(onePortContext->discovery.discoveringExpanderList)))
  {
    tddmSingleThreadedLeave(dmRoot, DM_EXPANDER_LOCK);
    DM_DBG3(("dmDownStreamDiscovering: should be the end\n"));
    NextExpander = agNULL;
  }
  else
  {
    DMLIST_DEQUEUE_FROM_HEAD(&ExpanderList, &(onePortContext->discovery.discoveringExpanderList));
    NextExpander = DMLIST_OBJECT_BASE(dmExpander_t, linkNode, ExpanderList);
    if ( NextExpander != agNULL)
    {
      DMLIST_ENQUEUE_AT_HEAD(&(NextExpander->linkNode), &(onePortContext->discovery.discoveringExpanderList));
      DM_DBG3(("dmDownStreamDiscovering tdsaSASDownStreamDiscovering: dequeue head\n"));
      DM_DBG3(("dmDownStreamDiscovering: expander id %d\n", NextExpander->id));
    }
    else
    {
     DM_DBG1(("dmDownStreamDiscovering: NextExpander is NULL!!!\n"));  
    }
    tddmSingleThreadedLeave(dmRoot, DM_EXPANDER_LOCK);
    
  }
  
  /* If there is an expander for continue discoving */
  if ( NextExpander != agNULL)
  {
    DM_DBG3(("dmDownStreamDiscovering: Found pNextExpander=%p discoveryStatus=0x%x\n", 
             NextExpander, onePortContext->discovery.status));

    switch (onePortContext->discovery.status)
    {
      /* If the discovery status is DISCOVERY_DOWN_STREAM */
    case DISCOVERY_DOWN_STREAM:
      /* Send report general for the next expander */
      DM_DBG3(("dmDownStreamDiscovering: DownStream pNextExpander=%p\n", NextExpander));
      DM_DBG3(("dmDownStreamDiscovering: oneDeviceData %p did %d\n", oneDeviceData, oneDeviceData->id));
      DM_DBG3(("dmDownStreamDiscovering: oneExpander %p did %d\n", oneDeviceData->dmExpander, oneDeviceData->dmExpander->id));
      
      DM_DBG3(("dmDownStreamDiscovering: 2nd oneDeviceData %p did %d\n", NextExpander->dmDevice, NextExpander->dmDevice->id));
      DM_DBG3(("dmDownStreamDiscovering: 2nd oneExpander %p did %d\n", NextExpander, NextExpander->id));
      DM_DBG3(("dmDownStreamDiscovering: 2nd used oneExpander %p did %d\n", NextExpander->dmDevice->dmExpander, NextExpander->dmDevice->dmExpander->id));
      
      if (NextExpander != NextExpander->dmDevice->dmExpander)
      {
        DM_DBG3(("dmDownStreamDiscovering: wrong!!!\n"));
      }
      
	          
      dmReportGeneralSend(dmRoot, NextExpander->dmDevice);            
      break;
      /* If the discovery status is DISCOVERY_CONFIG_ROUTING */
    case DISCOVERY_CONFIG_ROUTING:
    case DISCOVERY_REPORT_PHY_SATA:

      /* set discovery status */
      onePortContext->discovery.status = DISCOVERY_DOWN_STREAM;
      
      DM_DBG3(("dmDownStreamDiscovering: pPort->discovery.status=DISCOVERY_CONFIG_ROUTING, make it DOWN_STREAM\n"));
      /* If not the last phy */    
      if ( NextExpander->discoveringPhyId < NextExpander->dmDevice->numOfPhys )
      {      
        DM_DBG3(("dmDownStreamDiscovering: pNextExpander->discoveringPhyId=0x%x pNextExpander->numOfPhys=0x%x.  Send More Discover\n",
                 NextExpander->discoveringPhyId, NextExpander->dmDevice->numOfPhys));
        /* Send discover for the next expander */
        dmDiscoverSend(dmRoot, NextExpander->dmDevice);                  
        }
      /* If it's the last phy */    
      else
      {
        DM_DBG3(("dmDownStreamDiscovering: Last Phy, remove expander%p  start DownStream=%p\n",
                 NextExpander, NextExpander->dmDevice));
        dmDiscoveringExpanderRemove(dmRoot, onePortContext, NextExpander);
        dmDownStreamDiscovering(dmRoot, onePortContext, NextExpander->dmDevice);
      }
      break;
      
    default:
      DM_DBG3(("dmDownStreamDiscovering: *** Unknown pPort->discovery.status=0x%x\n", onePortContext->discovery.status));
    }
  }
  /* If no expander for continue discoving */
  else
  {
    DM_DBG3(("dmDownStreamDiscovering: No more expander DONE\n"));
    /* discover done */
    dmDiscoverDone(dmRoot, onePortContext, DM_RC_SUCCESS);
  }  
  
  
  return;
}		       

osGLOBAL void
dmUpStreamDiscoverExpanderPhy(
                              dmRoot_t              *dmRoot,
                              dmIntPortContext_t    *onePortContext,
                              dmExpander_t          *oneExpander,
                              smpRespDiscover_t     *pDiscoverResp
                             )
{
  agsaSASIdentify_t       sasIdentify;
  dmSASSubID_t            dmSASSubID;
  bit32                   attachedSasHi, attachedSasLo;
  dmExpander_t            *AttachedExpander = agNULL;
  bit8                    connectionRate;
  dmDeviceData_t          *oneDeviceData = agNULL;
  dmDeviceData_t          *AttachedDevice = agNULL;
  dmIntRoot_t             *dmIntRoot    = (dmIntRoot_t *)dmRoot->dmData;
  dmIntContext_t          *dmAllShared  = (dmIntContext_t *)&dmIntRoot->dmAllShared;
  
  
  DM_DBG3(("dmUpStreamDiscoverExpanderPhy: start\n"));
  
  if (dmDiscoverCheck(dmRoot, onePortContext) == agTRUE)
  {
    DM_DBG1(("dmUpStreamDiscoverExpanderPhy: invalid port or aborted discovery!!!\n"));  
    return;
  }
  
  if (oneExpander != oneExpander->dmDevice->dmExpander)
  {
    DM_DBG1(("dmUpStreamDiscoverExpanderPhy: wrong!!!\n"));
  }
  
  dm_memset(&sasIdentify, 0, sizeof(agsaSASIdentify_t));
    
  oneDeviceData = oneExpander->dmDevice;
 
  DM_DBG3(("dmUpStreamDiscoverExpanderPhy: Phy #%d of SAS %08x-%08x\n",
           oneExpander->discoveringPhyId,
           oneDeviceData->SASAddressID.sasAddressHi,
           oneDeviceData->SASAddressID.sasAddressLo));
  
  DM_DBG3(("   Attached device: %s\n",
           ( DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) == 0 ? "No Device" : 
             (DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) == 1 ? "End Device" : 
              (DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) == 2 ? "Edge Expander" : "Fanout Expander")))));
  
  
  if ( DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) != SAS_NO_DEVICE)
  {
    DM_DBG3(("   SAS address    : %08x-%08x\n",
      DISCRSP_GET_ATTACHED_SAS_ADDRESSHI(pDiscoverResp), 
              DISCRSP_GET_ATTACHED_SAS_ADDRESSLO(pDiscoverResp)));
    DM_DBG3(("   SSP Target     : %d\n", DISCRSP_IS_SSP_TARGET(pDiscoverResp)?1:0));
    DM_DBG3(("   STP Target     : %d\n", DISCRSP_IS_STP_TARGET(pDiscoverResp)?1:0));
    DM_DBG3(("   SMP Target     : %d\n", DISCRSP_IS_SMP_TARGET(pDiscoverResp)?1:0));
    DM_DBG3(("   SATA DEVICE    : %d\n", DISCRSP_IS_SATA_DEVICE(pDiscoverResp)?1:0));
    DM_DBG3(("   SSP Initiator  : %d\n", DISCRSP_IS_SSP_INITIATOR(pDiscoverResp)?1:0));
    DM_DBG3(("   STP Initiator  : %d\n", DISCRSP_IS_STP_INITIATOR(pDiscoverResp)?1:0));
    DM_DBG3(("   SMP Initiator  : %d\n", DISCRSP_IS_SMP_INITIATOR(pDiscoverResp)?1:0));
    DM_DBG3(("   Phy ID         : %d\n", pDiscoverResp->phyIdentifier));
    DM_DBG3(("   Attached Phy ID: %d\n", pDiscoverResp->attachedPhyIdentifier)); 
  }
  
  /* for debugging */
  if (oneExpander->discoveringPhyId != pDiscoverResp->phyIdentifier)
  {
    DM_DBG1(("dmUpStreamDiscoverExpanderPhy: !!! Incorrect SMP response !!!\n"));
    DM_DBG1(("dmUpStreamDiscoverExpanderPhy: Request PhyID #%d Response PhyID #%d !!!\n", oneExpander->discoveringPhyId, pDiscoverResp->phyIdentifier));
    dmhexdump("NO_DEVICE", (bit8*)pDiscoverResp, sizeof(smpRespDiscover_t));
    dmDiscoverDone(dmRoot, onePortContext, DM_RC_FAILURE);
    return;
  }
  
  /* saving routing attribute for non self-configuring expanders */
  oneExpander->routingAttribute[pDiscoverResp->phyIdentifier] = (bit8)DISCRSP_GET_ROUTINGATTRIB(pDiscoverResp);
  
  if ( oneDeviceData->SASSpecDeviceType == SAS_FANOUT_EXPANDER_DEVICE )
  {
    DM_DBG3(("dmUpStreamDiscoverExpanderPhy: SA_SAS_DEV_TYPE_FANOUT_EXPANDER\n"));
    if ( DISCRSP_GET_ROUTINGATTRIB(pDiscoverResp) == SAS_ROUTING_SUBTRACTIVE)
    {
      DM_DBG1(("dmUpStreamDiscoverExpanderPhy: **** Topology Error subtractive routing on fanout expander device!!!\n"));

      /* discovery error */
      onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo
        = DEVINFO_GET_SAS_ADDRESSLO(&oneDeviceData->agDeviceInfo);
      onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi
        = DEVINFO_GET_SAS_ADDRESSHI(&oneDeviceData->agDeviceInfo);
      onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier = oneExpander->discoveringPhyId;
      DM_DBG1(("dmUpStreamDiscoverExpanderPhy: sasAddressHi 0x%08x sasAddressLo 0x%08x phyid 0x%x\n", 
                onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi, 
                onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo,
                onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier));

      /* (2.1.3) discovery done */
      dmDiscoverDone(dmRoot, onePortContext, DM_RC_FAILURE);
      return;        
    }    
  }
  else
  {
    DM_DBG3(("dmUpStreamDiscoverExpanderPhy: SA_SAS_DEV_TYPE_EDGE_EXPANDER\n"));
    if ( DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) != SAS_NO_DEVICE)
    {
      /* Setup sasIdentify for the attached device */
      sasIdentify.phyIdentifier = pDiscoverResp->phyIdentifier;
      sasIdentify.deviceType_addressFrameType = (bit8)(pDiscoverResp->attachedDeviceType & 0x70);
      sasIdentify.initiator_ssp_stp_smp = pDiscoverResp->attached_Ssp_Stp_Smp_Sata_Initiator;
      sasIdentify.target_ssp_stp_smp = pDiscoverResp->attached_SataPS_Ssp_Stp_Smp_Sata_Target;
      *(bit32*)sasIdentify.sasAddressHi = *(bit32*)pDiscoverResp->attachedSasAddressHi;
      *(bit32*)sasIdentify.sasAddressLo = *(bit32*)pDiscoverResp->attachedSasAddressLo;

      /* incremental discovery */       
      dmSASSubID.sasAddressHi = SA_IDFRM_GET_SAS_ADDRESSHI(&sasIdentify);
      dmSASSubID.sasAddressLo = SA_IDFRM_GET_SAS_ADDRESSLO(&sasIdentify);
      dmSASSubID.initiator_ssp_stp_smp = sasIdentify.initiator_ssp_stp_smp;
      dmSASSubID.target_ssp_stp_smp = sasIdentify.target_ssp_stp_smp;
       
      attachedSasHi = DISCRSP_GET_ATTACHED_SAS_ADDRESSHI(pDiscoverResp);
      attachedSasLo = DISCRSP_GET_ATTACHED_SAS_ADDRESSLO(pDiscoverResp);
 
      /* If the phy has subtractive routing attribute */
      if ( DISCRSP_GET_ROUTINGATTRIB(pDiscoverResp) == SAS_ROUTING_SUBTRACTIVE)
      {       
        DM_DBG3(("dmUpStreamDiscoverExpanderPhy: SA_SAS_ROUTING_SUBTRACTIVE\n"));
        /* Setup upstream phys */
        dmExpanderUpStreamPhyAdd(dmRoot, oneExpander, (bit8) pDiscoverResp->attachedPhyIdentifier);
        /* If the expander already has an upsteam device set up */
        if (oneExpander->hasUpStreamDevice == agTRUE)
        {
          /* just to update MCN */          
          dmPortSASDeviceFind(dmRoot, onePortContext, attachedSasLo, attachedSasHi, oneDeviceData);
          /* If the sas address doesn't match */
          if ( ((oneExpander->upStreamSASAddressHi != attachedSasHi) ||
                (oneExpander->upStreamSASAddressLo != attachedSasLo)) &&
               (DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) == SAS_EDGE_EXPANDER_DEVICE ||
                DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) == SAS_FANOUT_EXPANDER_DEVICE)
              )
          {
            /* TODO: discovery error, callback */
            DM_DBG1(("dmUpStreamDiscoverExpanderPhy: **** Topology Error subtractive routing error - inconsistent SAS address!!!\n"));
            /* call back to notify discovery error */
            onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo
              = DEVINFO_GET_SAS_ADDRESSLO(&oneDeviceData->agDeviceInfo);
            onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi
              = DEVINFO_GET_SAS_ADDRESSHI(&oneDeviceData->agDeviceInfo);
            onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier = oneExpander->discoveringPhyId;
            DM_DBG1(("dmUpStreamDiscoverExpanderPhy: sasAddressHi 0x%08x sasAddressLo 0x%08x phyid 0x%x\n", 
                onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi, 
                onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo,
                onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier));
            /* discovery done */
            dmDiscoverDone(dmRoot, onePortContext, DM_RC_FAILURE);
          }
        }
        else
        {
          /* Setup SAS address for up stream device */
          oneExpander->hasUpStreamDevice = agTRUE;
          oneExpander->upStreamSASAddressHi = attachedSasHi;
          oneExpander->upStreamSASAddressLo = attachedSasLo;
          if ( (onePortContext->sasLocalAddressHi != attachedSasHi)
              || (onePortContext->sasLocalAddressLo != attachedSasLo) )
          {
            /* Find the device from the discovered list */
            AttachedDevice = dmPortSASDeviceFind(dmRoot, onePortContext, attachedSasLo, attachedSasHi, oneDeviceData);
            /* New device, If the device has been discovered before */
            if ( AttachedDevice != agNULL) /* old device */
            {
              DM_DBG3(("dmUpStreamDiscoverExpanderPhy: Seen This Device Before\n"));
              /* If attached device is an edge expander */
              if ( AttachedDevice->SASSpecDeviceType == SAS_EDGE_EXPANDER_DEVICE)
              {
                /* The attached device is an expander */
                AttachedExpander = AttachedDevice->dmExpander;
                /* If the two expanders are the root of the two edge expander sets */
                if ( (AttachedExpander->upStreamSASAddressHi ==
                      DEVINFO_GET_SAS_ADDRESSHI(&oneDeviceData->agDeviceInfo))
                     && (AttachedExpander->upStreamSASAddressLo ==
                        DEVINFO_GET_SAS_ADDRESSLO(&oneDeviceData->agDeviceInfo)) )
                {
                  /* Setup upstream expander for the pExpander */
                  oneExpander->dmUpStreamExpander = AttachedExpander;                
                }
                /* If the two expanders are not the root of the two edge expander sets */
                else
                {
                  /* TODO: loop found, discovery error, callback */
                  DM_DBG1(("dmUpStreamDiscoverExpanderPhy: **** Topology Error loop detection!!!\n"));
                  onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo
                    = DEVINFO_GET_SAS_ADDRESSLO(&oneDeviceData->agDeviceInfo);
                  onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi
                    = DEVINFO_GET_SAS_ADDRESSHI(&oneDeviceData->agDeviceInfo);
                  onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier = oneExpander->discoveringPhyId;
                  DM_DBG1(("dmUpStreamDiscoverExpanderPhy: sasAddressHi 0x%08x sasAddressLo 0x%08x phyid 0x%x\n", 
                           onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi, 
                           onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo,
                           onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier));                  
		                /* discovery done */
                  dmDiscoverDone(dmRoot, onePortContext, DM_RC_FAILURE);
                }  
              }
              /* If attached device is not an edge expander */
              else
              {
                /*TODO: should not happen, ASSERT */
                DM_DBG3(("dmUpStreamDiscoverExpanderPhy, *** Attached Device is not Edge. Confused!!!\n"));
              }
            } /* AttachedExpander != agNULL */
            /* New device, If the device has not been discovered before */
            else /* new device */
            {
              /* Add the device */    
              DM_DBG3(("dmUpStreamDiscoverExpanderPhy: New device\n"));
              /* read minimum rate from the configuration 
                 onePortContext->LinkRate is SPC's local link rate
              */
              connectionRate = (bit8)MIN(onePortContext->LinkRate, DISCRSP_GET_LINKRATE(pDiscoverResp));
              DM_DBG3(("dmUpStreamDiscoverExpanderPhy: link rate 0x%x\n", onePortContext->LinkRate));
              DM_DBG3(("dmUpStreamDiscoverExpanderPhy: negotiatedPhyLinkRate 0x%x\n", DISCRSP_GET_LINKRATE(pDiscoverResp))); 
              DM_DBG3(("dmUpStreamDiscoverExpanderPhy: connectionRate 0x%x\n", connectionRate));
              if (DISCRSP_IS_STP_TARGET(pDiscoverResp) || DISCRSP_IS_SATA_DEVICE(pDiscoverResp))    
              {
                /* incremental discovery */
                if (onePortContext->discovery.type == DM_DISCOVERY_OPTION_FULL_START)
                {
                  AttachedDevice = dmPortSASDeviceAdd(
                                                    dmRoot,
                                                    onePortContext,
                                                    sasIdentify,
                                                    agFALSE,
                                                    connectionRate,
                                                    dmAllShared->itNexusTimeout,
                                                    0,
                                                    STP_DEVICE_TYPE,
                                                    oneDeviceData,
                                                    oneExpander,
                                                    pDiscoverResp->phyIdentifier
                                                    );
                }
                else
                {
                  /* incremental discovery */
                  AttachedDevice = dmFindRegNValid(
                                                     dmRoot,
                                                     onePortContext,
                                                     &dmSASSubID
                                                     );
                  /* not registered and not valid; add this*/                                   
                  if (AttachedDevice == agNULL)
                  {
                    AttachedDevice = dmPortSASDeviceAdd(
                                                    dmRoot,
                                                    onePortContext,
                                                    sasIdentify,
                                                    agFALSE,
                                                    connectionRate,
                                                    dmAllShared->itNexusTimeout,
                                                    0,
                                                    STP_DEVICE_TYPE,
                                                    oneDeviceData,
                                                    oneExpander,
                                                    pDiscoverResp->phyIdentifier
                                                    );
                  }
                }
              } /* DISCRSP_IS_STP_TARGET(pDiscoverResp) || DISCRSP_IS_SATA_DEVICE(pDiscoverResp) */
              else
              {
                /* incremental discovery */
                if (onePortContext->discovery.type == DM_DISCOVERY_OPTION_FULL_START)
                {            
                  AttachedDevice = dmPortSASDeviceAdd(
                                                    dmRoot,
                                                    onePortContext,
                                                    sasIdentify,
                                                    agFALSE,
                                                    connectionRate,
                                                    dmAllShared->itNexusTimeout,
                                                    0,
                                                    SAS_DEVICE_TYPE,
                                                    oneDeviceData,
                                                    oneExpander,
                                                    pDiscoverResp->phyIdentifier
                                                    );
                }
                else
                {
                  /* incremental discovery */
                  AttachedDevice = dmFindRegNValid(
                                                     dmRoot,
                                                     onePortContext,
                                                     &dmSASSubID
                                                     );
                  /* not registered and not valid; add this*/
                  if (AttachedDevice == agNULL)
                  {
                    AttachedDevice = dmPortSASDeviceAdd(
                                                    dmRoot,
                                                    onePortContext,
                                                    sasIdentify,
                                                    agFALSE,
                                                    connectionRate,
                                                    dmAllShared->itNexusTimeout,
                                                    0,
                                                    SAS_DEVICE_TYPE,
                                                    oneDeviceData,
                                                    oneExpander,
                                                    pDiscoverResp->phyIdentifier
                                                    );
                  }                    
                }                                                    
              }
               /* If the device is added successfully */    
              if ( AttachedDevice != agNULL)
              {

                 /* (3.1.2.3.2.3.2.1) callback about new device */
                if ( DISCRSP_IS_SSP_TARGET(pDiscoverResp) 
                    || DISCRSP_IS_SSP_INITIATOR(pDiscoverResp)
                    || DISCRSP_IS_SMP_INITIATOR(pDiscoverResp)
                    || DISCRSP_IS_SMP_INITIATOR(pDiscoverResp) )
                {
                  DM_DBG3(("dmUpStreamDiscoverExpanderPhy: Found SSP/SMP SAS %08x-%08x\n",
                      attachedSasHi, attachedSasLo));
                }
                else
                {
                  DM_DBG3(("dmUpStreamDiscoverExpanderPhy: Found a SAS STP device.\n"));
                }
                 /* If the attached device is an expander */
                if ( (DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) == SAS_EDGE_EXPANDER_DEVICE) 
                    || (DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) == SAS_FANOUT_EXPANDER_DEVICE) )
                {
                  /* Allocate an expander data structure */
                  AttachedExpander = dmDiscoveringExpanderAlloc(
                                                                dmRoot,
                                                                onePortContext,
                                                                AttachedDevice
								                                                       );
    
                  DM_DBG3(("dmUpStreamDiscoverExpanderPhy: Found expander=%p\n", AttachedExpander));
                  /* If allocate successfully */
                  if ( AttachedExpander != agNULL)
                  {                  
                    /* Add the pAttachedExpander to discovering list */
                    dmDiscoveringExpanderAdd(dmRoot, onePortContext, AttachedExpander);
                    /* Setup upstream expander for the pExpander */
                    oneExpander->dmUpStreamExpander = AttachedExpander;
                  }
                  /* If failed to allocate */
                  else
                  {
                    DM_DBG1(("dmUpStreamDiscoverExpanderPhy: Failed to allocate expander data structure!!!\n"));
                    dmDiscoverDone(dmRoot, onePortContext, DM_RC_FAILURE);
                  }
                }
                /* If the attached device is an end device */
                else
                {
                  DM_DBG3(("dmUpStreamDiscoverExpanderPhy: Found end device\n"));
                  /* LP2006-05-26 added upstream device to the newly found device */
                  AttachedDevice->dmExpander = oneExpander;
                  oneExpander->dmUpStreamExpander = agNULL;
                }
              }
              else
              {
                DM_DBG1(("dmUpStreamDiscoverExpanderPhy: Failed to add a device!!!\n"));
                dmDiscoverDone(dmRoot, onePortContext, DM_RC_FAILURE);
              }
   
    
      
            } /* else, new device */
          } /* onePortContext->sasLocalAddressLo != attachedSasLo */
        } /* else */
      } /* DISCRSP_GET_ROUTINGATTRIB(pDiscoverResp) == SAS_ROUTING_SUBTRACTIVE */
    } /* DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) != SAS_NO_DEVICE */
  } /* big else */
  
  
  
   oneExpander->discoveringPhyId ++;
   if (onePortContext->discovery.status == DISCOVERY_UP_STREAM)
     {
       if ( oneExpander->discoveringPhyId < oneDeviceData->numOfPhys )
       {
         DM_DBG3(("dmUpStreamDiscoverExpanderPhy: DISCOVERY_UP_STREAM find more ...\n"));
         /* continue discovery for the next phy */  
         dmDiscoverSend(dmRoot, oneDeviceData);
       }
       else
       {
         DM_DBG3(("dmUpStreamDiscoverExpanderPhy: DISCOVERY_UP_STREAM last phy continue upstream..\n"));

         /* for MCN */
         dmUpdateAllAdjacent(dmRoot, onePortContext, oneDeviceData);         
         /* remove the expander from the discovering list */
         dmDiscoveringExpanderRemove(dmRoot, onePortContext, oneExpander);
         /* continue upstream discovering */  
         dmUpStreamDiscovering(dmRoot, onePortContext, oneDeviceData);
       }
   }
   else
   {
      DM_DBG3(("dmUpStreamDiscoverExpanderPhy: onePortContext->discovery.status not in DISCOVERY_UP_STREAM; status %d\n", onePortContext->discovery.status));  
   
   }
   
  DM_DBG3(("dmUpStreamDiscoverExpanderPhy: end return phyID#%d\n", oneExpander->discoveringPhyId - 1));
  
  return;
}	   				

osGLOBAL void
dmUpStreamDiscover2ExpanderPhy(
                              dmRoot_t              *dmRoot,
                              dmIntPortContext_t    *onePortContext,
                              dmExpander_t          *oneExpander,
                              smpRespDiscover2_t    *pDiscoverResp
                              )
{
  dmDeviceData_t          *oneDeviceData;
  dmDeviceData_t          *AttachedDevice = agNULL;
  dmExpander_t            *AttachedExpander;    
  agsaSASIdentify_t       sasIdentify;
  bit8                    connectionRate;
  bit32                   attachedSasHi, attachedSasLo;
  dmSASSubID_t            dmSASSubID;
  dmIntRoot_t             *dmIntRoot    = (dmIntRoot_t *)dmRoot->dmData;
  dmIntContext_t          *dmAllShared  = (dmIntContext_t *)&dmIntRoot->dmAllShared;
  
  DM_DBG2(("dmUpStreamDiscover2ExpanderPhy: start\n"));
  
  if (dmDiscoverCheck(dmRoot, onePortContext) == agTRUE)
  {
    DM_DBG1(("dmUpStreamDiscover2ExpanderPhy: invalid port or aborted discovery!!!\n"));  
    return;
  }
  
  if (oneExpander != oneExpander->dmDevice->dmExpander)
  {
    DM_DBG1(("dmUpStreamDiscover2ExpanderPhy: wrong!!!\n"));
  }
  
  dm_memset(&sasIdentify, 0, sizeof(agsaSASIdentify_t));
    
  oneDeviceData = oneExpander->dmDevice;
  
  DM_DBG2(("dmUpStreamDiscover2ExpanderPhy: Phy #%d of SAS %08x-%08x\n",
           oneExpander->discoveringPhyId,
           oneDeviceData->SASAddressID.sasAddressHi,
           oneDeviceData->SASAddressID.sasAddressLo));
  
  DM_DBG2(("   Attached device: %s\n",
           ( SAS2_DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) == 0 ? "No Device" : 
             (SAS2_DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) == 1 ? "End Device" : 
              (SAS2_DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) == 2 ? "Edge Expander" : "Fanout Expander")))));
  

  if ( SAS2_DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) != SAS_NO_DEVICE)
  {
    DM_DBG2(("   SAS address    : %08x-%08x\n",
      SAS2_DISCRSP_GET_ATTACHED_SAS_ADDRESSHI(pDiscoverResp), 
              SAS2_DISCRSP_GET_ATTACHED_SAS_ADDRESSLO(pDiscoverResp)));
    DM_DBG2(("   SSP Target     : %d\n", SAS2_DISCRSP_IS_SSP_TARGET(pDiscoverResp)?1:0));
    DM_DBG2(("   STP Target     : %d\n", SAS2_DISCRSP_IS_STP_TARGET(pDiscoverResp)?1:0));
    DM_DBG2(("   SMP Target     : %d\n", SAS2_DISCRSP_IS_SMP_TARGET(pDiscoverResp)?1:0));
    DM_DBG2(("   SATA DEVICE    : %d\n", SAS2_DISCRSP_IS_SATA_DEVICE(pDiscoverResp)?1:0));
    DM_DBG2(("   SSP Initiator  : %d\n", SAS2_DISCRSP_IS_SSP_INITIATOR(pDiscoverResp)?1:0));
    DM_DBG2(("   STP Initiator  : %d\n", SAS2_DISCRSP_IS_STP_INITIATOR(pDiscoverResp)?1:0));
    DM_DBG2(("   SMP Initiator  : %d\n", SAS2_DISCRSP_IS_SMP_INITIATOR(pDiscoverResp)?1:0));
    DM_DBG2(("   Phy ID         : %d\n", pDiscoverResp->phyIdentifier));
    DM_DBG2(("   Attached Phy ID: %d\n", pDiscoverResp->attachedPhyIdentifier)); 
  }
  
  if (oneExpander->discoveringPhyId != pDiscoverResp->phyIdentifier)
  {
    DM_DBG1(("dmUpStreamDiscover2ExpanderPhy: !!! Incorrect SMP response !!!\n"));
    DM_DBG1(("dmUpStreamDiscover2ExpanderPhy: Request PhyID #%d Response PhyID #%d\n", oneExpander->discoveringPhyId, pDiscoverResp->phyIdentifier));
    dmhexdump("NO_DEVICE", (bit8*)pDiscoverResp, sizeof(smpRespDiscover2_t));
    dmDiscoverDone(dmRoot, onePortContext, DM_RC_FAILURE);
    return;
  }
 
  /* saving routing attribute for non self-configuring expanders */
  oneExpander->routingAttribute[pDiscoverResp->phyIdentifier] = SAS2_DISCRSP_GET_ROUTINGATTRIB(pDiscoverResp);
  
  if ( oneDeviceData->SASSpecDeviceType == SAS_FANOUT_EXPANDER_DEVICE )
  {
    DM_DBG2(("dmUpStreamDiscover2ExpanderPhy: SA_SAS_DEV_TYPE_FANOUT_EXPANDER\n"));
    if ( SAS2_DISCRSP_GET_ROUTINGATTRIB(pDiscoverResp) == SAS_ROUTING_SUBTRACTIVE)
    {
      DM_DBG1(("dmUpStreamDiscover2ExpanderPhy: **** Topology Error subtractive routing on fanout expander device!!!\n"));

      /* discovery error */
      onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo
        = DEVINFO_GET_SAS_ADDRESSLO(&oneDeviceData->agDeviceInfo);
      onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi
        = DEVINFO_GET_SAS_ADDRESSHI(&oneDeviceData->agDeviceInfo);
      onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier = oneExpander->discoveringPhyId;
      DM_DBG1(("dmUpStreamDiscover2ExpanderPhy: sasAddressHi 0x%08x sasAddressLo 0x%08x phyid 0x%x\n", 
                onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi, 
                onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo,
                onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier));

      /* (2.1.3) discovery done */
      dmDiscoverDone(dmRoot, onePortContext, DM_RC_FAILURE);
      return;        
    }    
  }
  else
  {
    DM_DBG2(("dmUpStreamDiscover2ExpanderPhy: SA_SAS_DEV_TYPE_EDGE_EXPANDER\n"));
    
    if ( SAS2_DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) != SAS_NO_DEVICE)
    {
      /* Setup sasIdentify for the attached device */
      sasIdentify.phyIdentifier = pDiscoverResp->phyIdentifier;
      sasIdentify.deviceType_addressFrameType = pDiscoverResp->attachedDeviceTypeReason & 0x70;
      sasIdentify.initiator_ssp_stp_smp = pDiscoverResp->attached_Ssp_Stp_Smp_Sata_Initiator;
      sasIdentify.target_ssp_stp_smp = pDiscoverResp->attached_SataPS_Ssp_Stp_Smp_Sata_Target;
      *(bit32*)sasIdentify.sasAddressHi = *(bit32*)pDiscoverResp->attachedSasAddressHi;
      *(bit32*)sasIdentify.sasAddressLo = *(bit32*)pDiscoverResp->attachedSasAddressLo;

      /* incremental discovery */       
      dmSASSubID.sasAddressHi = SA_IDFRM_GET_SAS_ADDRESSHI(&sasIdentify);
      dmSASSubID.sasAddressLo = SA_IDFRM_GET_SAS_ADDRESSLO(&sasIdentify);
      dmSASSubID.initiator_ssp_stp_smp = sasIdentify.initiator_ssp_stp_smp;
      dmSASSubID.target_ssp_stp_smp = sasIdentify.target_ssp_stp_smp;
       
      attachedSasHi = SAS2_DISCRSP_GET_ATTACHED_SAS_ADDRESSHI(pDiscoverResp);
      attachedSasLo = SAS2_DISCRSP_GET_ATTACHED_SAS_ADDRESSLO(pDiscoverResp);
      
      /* If the phy has subtractive routing attribute */
      if ( SAS2_DISCRSP_GET_ROUTINGATTRIB(pDiscoverResp) == SAS_ROUTING_SUBTRACTIVE)
      {       
        DM_DBG2(("dmUpStreamDiscover2ExpanderPhy: SA_SAS_ROUTING_SUBTRACTIVE\n"));
        /* Setup upstream phys */
        dmExpanderUpStreamPhyAdd(dmRoot, oneExpander, (bit8) pDiscoverResp->attachedPhyIdentifier);
        /* If the expander already has an upsteam device set up */
        if (oneExpander->hasUpStreamDevice == agTRUE)
        {
          /* just to update MCN */          
          dmPortSASDeviceFind(dmRoot, onePortContext, attachedSasLo, attachedSasHi, oneDeviceData);          
          /* If the sas address doesn't match */
          if ( ((oneExpander->upStreamSASAddressHi != attachedSasHi) ||
                (oneExpander->upStreamSASAddressLo != attachedSasLo)) &&
               (SAS2_DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) == SAS_EDGE_EXPANDER_DEVICE ||
                SAS2_DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) == SAS_FANOUT_EXPANDER_DEVICE)
              )
          {
            /* TODO: discovery error, callback */
            DM_DBG1(("dmUpStreamDiscover2ExpanderPhy: **** Topology Error subtractive routing error - inconsistent SAS address!!!\n"));
            /* call back to notify discovery error */
            onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo
              = DEVINFO_GET_SAS_ADDRESSLO(&oneDeviceData->agDeviceInfo);
            onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi
              = DEVINFO_GET_SAS_ADDRESSHI(&oneDeviceData->agDeviceInfo);
            onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier = oneExpander->discoveringPhyId;
            DM_DBG1(("dmUpStreamDiscover2ExpanderPhy: sasAddressHi 0x%08x sasAddressLo 0x%08x phyid 0x%x\n", 
                      onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi, 
                      onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo,
                      onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier));
            /* discovery done */
            dmDiscoverDone(dmRoot, onePortContext, DM_RC_FAILURE);
          }
        }
        else
        {
          /* Setup SAS address for up stream device */
          oneExpander->hasUpStreamDevice = agTRUE;
          oneExpander->upStreamSASAddressHi = attachedSasHi;
          oneExpander->upStreamSASAddressLo = attachedSasLo;

          if ( (onePortContext->sasLocalAddressHi != attachedSasHi)
              || (onePortContext->sasLocalAddressLo != attachedSasLo) )
          {
            /* Find the device from the discovered list */
            AttachedDevice = dmPortSASDeviceFind(dmRoot, onePortContext, attachedSasLo, attachedSasHi, oneDeviceData);
            /* If the device has been discovered before */
            if ( AttachedDevice != agNULL)
            {
              DM_DBG2(("dmUpStreamDiscover2ExpanderPhy: Seen This Device Before\n"));
              /* If attached device is an edge expander */
              if ( AttachedDevice->SASSpecDeviceType == SAS_EDGE_EXPANDER_DEVICE)
              {
                /* The attached device is an expander */
                AttachedExpander = AttachedDevice->dmExpander;
                /* If the two expanders are the root of the two edge expander sets */
                if ( (AttachedExpander->upStreamSASAddressHi ==
                      DEVINFO_GET_SAS_ADDRESSHI(&oneDeviceData->agDeviceInfo))
                     && (AttachedExpander->upStreamSASAddressLo ==
                        DEVINFO_GET_SAS_ADDRESSLO(&oneDeviceData->agDeviceInfo)) )
                {
                  /* Setup upstream expander for the pExpander */
                  oneExpander->dmUpStreamExpander = AttachedExpander;                
                }
                /* If the two expanders are not the root of the two edge expander sets */
                else
                {
                  /* TODO: loop found, discovery error, callback */
                  DM_DBG1(("dmUpStreamDiscover2ExpanderPhy: **** Topology Error loop detection!!!\n"));
                  onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo
                    = DEVINFO_GET_SAS_ADDRESSLO(&oneDeviceData->agDeviceInfo);
                  onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi
                    = DEVINFO_GET_SAS_ADDRESSHI(&oneDeviceData->agDeviceInfo);
                  onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier = oneExpander->discoveringPhyId;
                  DM_DBG1(("dmUpStreamDiscover2ExpanderPhy: sasAddressHi 0x%08x sasAddressLo 0x%08x phyid 0x%x\n", 
                            onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi, 
                            onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo,
                            onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier));
                  /* discovery done */
                  dmDiscoverDone(dmRoot, onePortContext, DM_RC_FAILURE);
                }  
              }
              /* If attached device is not an edge expander */
              else
              {
                /*TODO: should not happen, ASSERT */
                DM_DBG1(("dmUpStreamDiscover2ExpanderPhy, *** Attached Device is not Edge. Confused!!!\n"));
              }
            }
            /* If the device has not been discovered before */
            else
            {
              /* Add the device */    
              DM_DBG2(("dmUpStreamDiscover2ExpanderPhy: New device\n"));
              /* read minimum rate from the configuration 
                 onePortContext->LinkRate is SPC's local link rate
              */
              connectionRate = MIN(onePortContext->LinkRate, SAS2_DISCRSP_GET_LOGICAL_LINKRATE(pDiscoverResp));
              DM_DBG2(("dmUpStreamDiscover2ExpanderPhy: link rate 0x%x\n", onePortContext->LinkRate));
              DM_DBG2(("dmUpStreamDiscover2ExpanderPhy: negotiatedPhyLinkRate 0x%x\n", SAS2_DISCRSP_GET_LINKRATE(pDiscoverResp))); 
              DM_DBG2(("dmUpStreamDiscover2ExpanderPhy: connectionRate 0x%x\n", connectionRate));
              //hhhhhhhh
              if (SAS2_DISCRSP_IS_STP_TARGET(pDiscoverResp) || SAS2_DISCRSP_IS_SATA_DEVICE(pDiscoverResp))    
              {
                /* incremental discovery */
                if (onePortContext->discovery.type == DM_DISCOVERY_OPTION_FULL_START)
                {
                  AttachedDevice = dmPortSASDeviceAdd(
                                                    dmRoot,
                                                    onePortContext,
                                                    sasIdentify,
                                                    agFALSE,
                                                    connectionRate,
                                                    dmAllShared->itNexusTimeout,
                                                    0,
                                                    STP_DEVICE_TYPE,
                                                    oneDeviceData,
                                                    oneExpander,
                                                    pDiscoverResp->phyIdentifier
                                                    );
                }
                else
                {
                  /* incremental discovery */
                  AttachedDevice = dmFindRegNValid(
                                                     dmRoot,
                                                     onePortContext,
                                                     &dmSASSubID
                                                     );
                  /* not registered and not valid; add this*/                                   
                  if (AttachedDevice == agNULL)
                  {
                    AttachedDevice = dmPortSASDeviceAdd(
                                                    dmRoot,
                                                    onePortContext,
                                                    sasIdentify,
                                                    agFALSE,
                                                    connectionRate,
                                                    dmAllShared->itNexusTimeout,
                                                    0,
                                                    STP_DEVICE_TYPE,
                                                    oneDeviceData,
                                                    oneExpander,
                                                    pDiscoverResp->phyIdentifier
                                                    );
                  }
                }
              }
              else
              {
                /* incremental discovery */
                if (onePortContext->discovery.type == DM_DISCOVERY_OPTION_FULL_START)
                {            
                  AttachedDevice = dmPortSASDeviceAdd(
                                                    dmRoot,
                                                    onePortContext,
                                                    sasIdentify,
                                                    agFALSE,
                                                    connectionRate,
                                                    dmAllShared->itNexusTimeout,
                                                    0,
                                                    SAS_DEVICE_TYPE,
                                                    oneDeviceData,
                                                    oneExpander,
                                                    pDiscoverResp->phyIdentifier
                                                    );
                }
                else
                {
                  /* incremental discovery */
                  AttachedDevice = dmFindRegNValid(
                                                     dmRoot,
                                                     onePortContext,
                                                     &dmSASSubID
                                                     );
                  /* not registered and not valid; add this*/
                  if (AttachedDevice == agNULL)
                  {
                    AttachedDevice = dmPortSASDeviceAdd(
                                                    dmRoot,
                                                    onePortContext,
                                                    sasIdentify,
                                                    agFALSE,
                                                    connectionRate,
                                                    dmAllShared->itNexusTimeout,
                                                    0,
                                                    SAS_DEVICE_TYPE,
                                                    oneDeviceData,
                                                    oneExpander,
                                                    pDiscoverResp->phyIdentifier
                                                    );
                  }                    
                }                                                    
              }
              /* If the device is added successfully */    
              if ( AttachedDevice != agNULL)
              {

                 /* (3.1.2.3.2.3.2.1) callback about new device */
                if ( SAS2_DISCRSP_IS_SSP_TARGET(pDiscoverResp) 
                    || SAS2_DISCRSP_IS_SSP_INITIATOR(pDiscoverResp)
                    || SAS2_DISCRSP_IS_SMP_INITIATOR(pDiscoverResp)
                    || SAS2_DISCRSP_IS_SMP_INITIATOR(pDiscoverResp) )
                {
                  DM_DBG2(("dmUpStreamDiscover2ExpanderPhy: Found SSP/SMP SAS %08x-%08x\n",
                      attachedSasHi, attachedSasLo));
                }
                else
                {
                  DM_DBG2(("dmUpStreamDiscover2ExpanderPhy: Found a SAS STP device.\n"));
                }
                 /* If the attached device is an expander */
                if ( (SAS2_DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) == SAS_EDGE_EXPANDER_DEVICE) 
                    || (SAS2_DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) == SAS_FANOUT_EXPANDER_DEVICE) )
                {
                  /* Allocate an expander data structure */
                  AttachedExpander = dmDiscoveringExpanderAlloc(
                                                                dmRoot,
                                                                onePortContext,
                                                                AttachedDevice
                                                               );
    
                  DM_DBG2(("dmUpStreamDiscover2ExpanderPhy: Found expander=%p\n", AttachedExpander));
                  /* If allocate successfully */
                  if ( AttachedExpander != agNULL)
                  {                  
                    /* Add the pAttachedExpander to discovering list */
                    dmDiscoveringExpanderAdd(dmRoot, onePortContext, AttachedExpander);
                    /* Setup upstream expander for the pExpander */
                    oneExpander->dmUpStreamExpander = AttachedExpander;
                  }
                  /* If failed to allocate */
                  else
                  {
                    DM_DBG1(("dmUpStreamDiscover2ExpanderPhy, Failed to allocate expander data structure!!!\n"));
                    dmDiscoverDone(dmRoot, onePortContext, DM_RC_FAILURE);
                  }
                }
                /* If the attached device is an end device */
                else
                {
                  DM_DBG2(("dmUpStreamDiscover2ExpanderPhy: Found end device\n"));
                  /* LP2006-05-26 added upstream device to the newly found device */
                  AttachedDevice->dmExpander = oneExpander;
                  oneExpander->dmUpStreamExpander = agNULL;
                }
              }
              else
              {
                DM_DBG1(("dmUpStreamDiscover2ExpanderPhy, Failed to add a device!!!\n"));
                dmDiscoverDone(dmRoot, onePortContext, DM_RC_FAILURE);
              }
            }
          }
        }
      } /* substractive routing */
    }
  }
  
   oneExpander->discoveringPhyId ++;
   if (onePortContext->discovery.status == DISCOVERY_UP_STREAM)
     {
       if ( oneExpander->discoveringPhyId < oneDeviceData->numOfPhys )
       {
         DM_DBG2(("dmUpStreamDiscover2ExpanderPhy: DISCOVERY_UP_STREAM find more ...\n"));
         /* continue discovery for the next phy */  
         dmDiscoverSend(dmRoot, oneDeviceData);
       }
       else
       {
         DM_DBG2(("dmUpStreamDiscover2ExpanderPhy: DISCOVERY_UP_STREAM last phy continue upstream..\n"));

         /* for MCN */
         dmUpdateAllAdjacent(dmRoot, onePortContext, oneDeviceData);         
         /* remove the expander from the discovering list */
         dmDiscoveringExpanderRemove(dmRoot, onePortContext, oneExpander);
         /* continue upstream discovering */  
         dmUpStreamDiscovering(dmRoot, onePortContext, oneDeviceData);
       }
   }
   else
   {
      DM_DBG2(("dmUpStreamDiscover2ExpanderPhy: onePortContext->discovery.status not in DISCOVERY_UP_STREAM; status %d\n", onePortContext->discovery.status));  
   
   }
   
  DM_DBG2(("dmUpStreamDiscover2ExpanderPhy: end return phyID#%d\n", oneExpander->discoveringPhyId - 1));
  
  return;
}			     


osGLOBAL void
dmDownStreamDiscoverExpanderPhy(
                                dmRoot_t              *dmRoot,
                                dmIntPortContext_t    *onePortContext,
                                dmExpander_t          *oneExpander,
                                smpRespDiscover_t     *pDiscoverResp
                               )
{
  agsaSASIdentify_t       sasIdentify;
  dmSASSubID_t            dmSASSubID;
  bit32                   attachedSasHi, attachedSasLo;
  dmExpander_t            *AttachedExpander;
  dmExpander_t            *UpStreamExpander;
  dmExpander_t            *ConfigurableExpander = agNULL;
  bit8                    connectionRate, negotiatedPhyLinkRate;
  bit32                   configSASAddressHi;
  bit32                   configSASAddressLo;
  bit32                   dupConfigSASAddr = agFALSE;
  dmDeviceData_t          *oneDeviceData;
  dmDeviceData_t          *AttachedDevice = agNULL;
  bit32                   SAS2SAS11Check = agFALSE;
  dmIntRoot_t             *dmIntRoot    = (dmIntRoot_t *)dmRoot->dmData;
  dmIntContext_t          *dmAllShared  = (dmIntContext_t *)&dmIntRoot->dmAllShared;
  
  
  
  DM_DBG3(("dmDownStreamDiscoverExpanderPhy: start\n"));
  DM_DBG3(("dmDownStreamDiscoverExpanderPhy: exp addrHi 0x%08x\n", oneExpander->dmDevice->SASAddressID.sasAddressHi));
  DM_DBG3(("dmDownStreamDiscoverExpanderPhy: exp addrLo 0x%08x\n", oneExpander->dmDevice->SASAddressID.sasAddressLo));	
  
  DM_ASSERT(dmRoot, "(dmDownStreamDiscoverExpanderPhy) dmRoot NULL");
  DM_ASSERT(onePortContext, "(dmDownStreamDiscoverExpanderPhy) pPort NULL");
  DM_ASSERT(oneExpander, "(dmDownStreamDiscoverExpanderPhy) pExpander NULL");
  DM_ASSERT(pDiscoverResp, "(dmDownStreamDiscoverExpanderPhy) pDiscoverResp NULL");

  DM_DBG3(("dmDownStreamDiscoverExpanderPhy: onePortContxt=%p  oneExpander=%p\n", onePortContext, oneExpander));
           
  if (dmDiscoverCheck(dmRoot, onePortContext) == agTRUE)
  {
    DM_DBG1(("dmDownStreamDiscoverExpanderPhy: invalid port or aborted discovery!!!\n"));  
    return;
  }
  
  if (oneExpander != oneExpander->dmDevice->dmExpander)
  {
    DM_DBG1(("dmDownStreamDiscoverExpanderPhy: wrong!!!\n"));
  }
  
  /* (1) Find the device structure of the expander */
  oneDeviceData = oneExpander->dmDevice;
  
  DM_ASSERT(oneDeviceData, "(dmDownStreamDiscoverExpanderPhy) pDevice NULL");
  
  /* for debugging */
  DM_DBG3(("dmDownStreamDiscoverExpanderPhy: Phy #%d of SAS %08x-%08x\n",
           oneExpander->discoveringPhyId,
           oneDeviceData->SASAddressID.sasAddressHi,
           oneDeviceData->SASAddressID.sasAddressLo));
  
  DM_DBG3(("   Attached device: %s\n",
           ( DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) == 0 ? "No Device" : 
             (DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) == 1 ? "End Device" : 
              (DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) == 2 ? "Edge Expander" : "Fanout Expander")))));
  
  
  /* for debugging */
  if (oneExpander->discoveringPhyId != pDiscoverResp->phyIdentifier)
  {
    DM_DBG1(("dmDownStreamDiscoverExpanderPhy: !!! Incorrect SMP response !!!\n"));
    DM_DBG1(("dmDownStreamDiscoverExpanderPhy: Request PhyID #%d Response PhyID #%d !!!\n", oneExpander->discoveringPhyId, pDiscoverResp->phyIdentifier));
    dmhexdump("NO_DEVICE", (bit8*)pDiscoverResp, sizeof(smpRespDiscover_t));
    dmDiscoverDone(dmRoot, onePortContext, DM_RC_FAILURE);
    return;
  }
  
  if ( DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) != SAS_NO_DEVICE)
  {
    DM_DBG3(("   SAS address    : %08x-%08x\n",
      DISCRSP_GET_ATTACHED_SAS_ADDRESSHI(pDiscoverResp), 
              DISCRSP_GET_ATTACHED_SAS_ADDRESSLO(pDiscoverResp)));
    DM_DBG3(("   SSP Target     : %d\n", DISCRSP_IS_SSP_TARGET(pDiscoverResp)?1:0));
    DM_DBG3(("   STP Target     : %d\n", DISCRSP_IS_STP_TARGET(pDiscoverResp)?1:0));
    DM_DBG3(("   SMP Target     : %d\n", DISCRSP_IS_SMP_TARGET(pDiscoverResp)?1:0));
    DM_DBG3(("   SATA DEVICE    : %d\n", DISCRSP_IS_SATA_DEVICE(pDiscoverResp)?1:0));
    DM_DBG3(("   SSP Initiator  : %d\n", DISCRSP_IS_SSP_INITIATOR(pDiscoverResp)?1:0));
    DM_DBG3(("   STP Initiator  : %d\n", DISCRSP_IS_STP_INITIATOR(pDiscoverResp)?1:0));
    DM_DBG3(("   SMP Initiator  : %d\n", DISCRSP_IS_SMP_INITIATOR(pDiscoverResp)?1:0));
    DM_DBG3(("   Phy ID         : %d\n", pDiscoverResp->phyIdentifier));
    DM_DBG3(("   Attached Phy ID: %d\n", pDiscoverResp->attachedPhyIdentifier));
    
  }
  /* end for debugging */
  
  /* saving routing attribute for non self-configuring expanders */
  oneExpander->routingAttribute[pDiscoverResp->phyIdentifier] = DISCRSP_GET_ROUTINGATTRIB(pDiscoverResp);
  
  oneExpander->discoverSMPAllowed = agTRUE;
  
  /* If a device is attached */
  if ( DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) !=  SAS_NO_DEVICE)
  {
    /* Setup sasIdentify for the attached device */
    sasIdentify.phyIdentifier = pDiscoverResp->phyIdentifier;
    sasIdentify.deviceType_addressFrameType = pDiscoverResp->attachedDeviceType & 0x70;
    sasIdentify.initiator_ssp_stp_smp = pDiscoverResp->attached_Ssp_Stp_Smp_Sata_Initiator;
    sasIdentify.target_ssp_stp_smp = pDiscoverResp->attached_SataPS_Ssp_Stp_Smp_Sata_Target;
    *(bit32*)sasIdentify.sasAddressHi = *(bit32*)pDiscoverResp->attachedSasAddressHi;
    *(bit32*)sasIdentify.sasAddressLo = *(bit32*)pDiscoverResp->attachedSasAddressLo;

    /* incremental discovery */       
    dmSASSubID.sasAddressHi = SA_IDFRM_GET_SAS_ADDRESSHI(&sasIdentify);
    dmSASSubID.sasAddressLo = SA_IDFRM_GET_SAS_ADDRESSLO(&sasIdentify);
    dmSASSubID.initiator_ssp_stp_smp = sasIdentify.initiator_ssp_stp_smp;
    dmSASSubID.target_ssp_stp_smp = sasIdentify.target_ssp_stp_smp;
        
    attachedSasHi = DISCRSP_GET_ATTACHED_SAS_ADDRESSHI(pDiscoverResp);
    attachedSasLo = DISCRSP_GET_ATTACHED_SAS_ADDRESSLO(pDiscoverResp);
  
    /* If it's a direct routing */
    if ( DISCRSP_GET_ROUTINGATTRIB(pDiscoverResp) == SAS_ROUTING_DIRECT)
    {
      /* If the attached device is an expander */
      if ( (DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) == SAS_FANOUT_EXPANDER_DEVICE)
          || (DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) == SAS_EDGE_EXPANDER_DEVICE) )

      {
        DM_DBG1(("dmDownStreamDiscoverExpanderPhy: **** Topology Error direct routing can't connect to expander!!!\n"));
        onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo
           = DEVINFO_GET_SAS_ADDRESSLO(&oneDeviceData->agDeviceInfo);
        onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi
          = DEVINFO_GET_SAS_ADDRESSHI(&oneDeviceData->agDeviceInfo);
        onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier = oneExpander->discoveringPhyId;
        DM_DBG1(("dmDownStreamDiscoverExpanderPhy: sasAddressHi 0x%08x sasAddressLo 0x%08x phyid 0x%x\n", 
                  onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi, 
                  onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo,
                  onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier));

        dmDiscoverDone(dmRoot, onePortContext, DM_RC_FAILURE);
        return;
      }
    }
  
    /* If the expander's attached device is not myself */
    if ( (attachedSasHi != onePortContext->sasLocalAddressHi)
         || (attachedSasLo != onePortContext->sasLocalAddressLo) ) 
    {
      /* Find the attached device from discovered list */
      AttachedDevice = dmPortSASDeviceFind(dmRoot, onePortContext, attachedSasLo, attachedSasHi, oneDeviceData);
      /* If the device has not been discovered before */
      if ( AttachedDevice == agNULL) //11
      {
        /* If the phy has subtractive routing attribute */
        if ( DISCRSP_GET_ROUTINGATTRIB(pDiscoverResp) == SAS_ROUTING_SUBTRACTIVE &&
             (DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) == SAS_EDGE_EXPANDER_DEVICE ||
              DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) == SAS_FANOUT_EXPANDER_DEVICE)
           )
        {
          /* TODO: discovery error, callback */
          DM_DBG1(("dmDownStreamDiscoverExpanderPhy: Deferred!!! **** Topology Error subtractive routing error - inconsistent SAS address!!!\n"));
          onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo
            = DEVINFO_GET_SAS_ADDRESSLO(&oneDeviceData->agDeviceInfo);
          onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi
            = DEVINFO_GET_SAS_ADDRESSHI(&oneDeviceData->agDeviceInfo);
          onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier = oneExpander->discoveringPhyId;
          DM_DBG1(("dmDownStreamDiscoverExpanderPhy: sasAddressHi 0x%08x sasAddressLo 0x%08x phyid 0x%x\n", 
                  onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi, 
                  onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo,
                  onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier));

          onePortContext->discovery.DeferredError = agTRUE;
        }
        else /* 11 */
        {
          /* Add the device */
          /* read minimum rate from the configuration 
             onePortContext->LinkRate is SPC's local link rate
          */
          connectionRate = MIN(onePortContext->LinkRate, DISCRSP_GET_LINKRATE(pDiscoverResp)); 
          DM_DBG3(("dmDownStreamDiscoverExpanderPhy: link rate 0x%x\n", DEVINFO_GET_LINKRATE(&oneDeviceData->agDeviceInfo)));
          DM_DBG3(("dmDownStreamDiscoverExpanderPhy: negotiatedPhyLinkRate 0x%x\n", DISCRSP_GET_LINKRATE(pDiscoverResp)));
          DM_DBG3(("dmDownStreamDiscoverExpanderPhy: connectionRate 0x%x\n", connectionRate));
          if (DISCRSP_IS_STP_TARGET(pDiscoverResp) || DISCRSP_IS_SATA_DEVICE(pDiscoverResp))    
          {
            if (onePortContext->discovery.type == DM_DISCOVERY_OPTION_FULL_START)
            {
              AttachedDevice = dmPortSASDeviceAdd(
                                                  dmRoot,
                                                  onePortContext,
                                                  sasIdentify,
                                                  agFALSE,
                                                  connectionRate,
                                                  dmAllShared->itNexusTimeout,
                                                  0,
                                                  STP_DEVICE_TYPE,
                                                  oneDeviceData,
                                                  oneExpander,
                                                  pDiscoverResp->phyIdentifier
                                                  );
            }
            else
            {
              /* incremental discovery */
              AttachedDevice = dmFindRegNValid(
                                                 dmRoot,
                                                 onePortContext,
                                                 &dmSASSubID
                                                 );
              /* not registered and not valid; add this*/                                   
              if (AttachedDevice == agNULL)
              {
                AttachedDevice = dmPortSASDeviceAdd(
                                                    dmRoot,
                                                    onePortContext,
                                                    sasIdentify,
                                                    agFALSE,
                                                    connectionRate,
                                                    dmAllShared->itNexusTimeout,
                                                    0,
                                                    STP_DEVICE_TYPE,
                                                    oneDeviceData,
                                                    oneExpander,
                                                    pDiscoverResp->phyIdentifier
                                                    );
              }
            }
	  } /* DISCRSP_IS_STP_TARGET(pDiscoverResp) || DISCRSP_IS_SATA_DEVICE(pDiscoverResp) */
          else /* 22 */
          {
            if (onePortContext->discovery.type == DM_DISCOVERY_OPTION_FULL_START)
            {            
              AttachedDevice = dmPortSASDeviceAdd(
                                                  dmRoot,
                                                  onePortContext,
                                                  sasIdentify,
                                                  agFALSE,
                                                  connectionRate,
                                                  dmAllShared->itNexusTimeout,
                                                  0,
                                                  SAS_DEVICE_TYPE,
                                                  oneDeviceData,
                                                  oneExpander,
                                                  pDiscoverResp->phyIdentifier
                                                  );
            }
            else
            {
              /* incremental discovery */
              AttachedDevice = dmFindRegNValid(
                                              dmRoot,
                                              onePortContext,
                                              &dmSASSubID
                                              );
              /* not registered and not valid; add this*/
              if (AttachedDevice == agNULL)
              {
                AttachedDevice = dmPortSASDeviceAdd(
                                                   dmRoot,
                                                   onePortContext,
                                                   sasIdentify,
                                                   agFALSE,
                                                   connectionRate,
                                                   dmAllShared->itNexusTimeout,
                                                   0,
                                                   SAS_DEVICE_TYPE,
                                                   oneDeviceData,
                                                   oneExpander,
                                                   pDiscoverResp->phyIdentifier
                                                   );
              }                    
            }                                                    
	  } /* else 22 */
          DM_DBG3(("dmDownStreamDiscoverExpanderPhy: newDevice  pDevice=%p\n", AttachedDevice));
          /* If the device is added successfully */    
          if ( AttachedDevice != agNULL)
          {
            if ( SA_IDFRM_IS_SSP_TARGET(&sasIdentify) 
                 || SA_IDFRM_IS_SMP_TARGET(&sasIdentify)
                 || SA_IDFRM_IS_SSP_INITIATOR(&sasIdentify)
                 || SA_IDFRM_IS_SMP_INITIATOR(&sasIdentify) )
            {
              DM_DBG3(("dmDownStreamDiscoverExpanderPhy: Report a new SAS device !!\n"));  
               
            }
            else
            {
              if ( SA_IDFRM_IS_STP_TARGET(&sasIdentify) || 
                   SA_IDFRM_IS_SATA_DEVICE(&sasIdentify) )
              {
                
                DM_DBG3(("dmDownStreamDiscoverExpanderPhy: Found an STP or SATA device.\n"));
              }
              else
              {
                DM_DBG3(("dmDownStreamDiscoverExpanderPhy: Found Other type of device.\n"));
              }
            }
	    
            /* LP2006-05-26 added upstream device to the newly found device */
            AttachedDevice->dmExpander = oneExpander;
            DM_DBG3(("dmDownStreamDiscoverExpanderPhy: AttachedDevice %p did %d\n", AttachedDevice, AttachedDevice->id));
            DM_DBG3(("dmDownStreamDiscoverExpanderPhy: Attached oneExpander %p did %d\n",  AttachedDevice->dmExpander,  AttachedDevice->dmExpander->id));
	    
            DM_DBG3(("dmDownStreamDiscoverExpanderPhy: oneDeviceData %p did %d\n", oneDeviceData, oneDeviceData->id));
            DM_DBG3(("dmDownStreamDiscoverExpanderPhy: oneExpander %p did %d\n",  oneDeviceData->dmExpander,  oneDeviceData->dmExpander->id));
            
	    /* If the phy has table routing attribute */
            if ( DISCRSP_GET_ROUTINGATTRIB(pDiscoverResp) == SAS_ROUTING_TABLE)
            {
              /* If the attached device is a fan out expander */
              if ( DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) == SAS_FANOUT_EXPANDER_DEVICE)
              {
                /* TODO: discovery error, callback */
                DM_DBG1(("dmDownStreamDiscoverExpanderPhy: **** Topology Error two table routing phys are connected!!!\n"));
                onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo
                  = DEVINFO_GET_SAS_ADDRESSLO(&oneDeviceData->agDeviceInfo);
                onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi
                  = DEVINFO_GET_SAS_ADDRESSHI(&oneDeviceData->agDeviceInfo);
                onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier = oneExpander->discoveringPhyId;
                DM_DBG1(("dmDownStreamDiscoverExpanderPhy: sasAddressHi 0x%08x sasAddressLo 0x%08x phyid 0x%x\n", 
                          onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi, 
                          onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo,
                          onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier));
                /* discovery done */
                dmDiscoverDone(dmRoot, onePortContext, DM_RC_FAILURE);
              }	
              else if ( DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) == SAS_EDGE_EXPANDER_DEVICE) 
              {
                /* Allocate an expander data structure */
                AttachedExpander = dmDiscoveringExpanderAlloc(dmRoot, onePortContext, AttachedDevice);
                 
                DM_DBG3(("dmDownStreamDiscoverExpanderPhy: Found a EDGE exp device.%p\n", AttachedExpander));
                /* If allocate successfully */
                if ( AttachedExpander != agNULL)
                {
                  /* set up downstream information on configurable expander */              
                  dmExpanderDownStreamPhyAdd(dmRoot, oneExpander, (bit8) oneExpander->discoveringPhyId); 
                  /* Setup upstream information */
                  dmExpanderUpStreamPhyAdd(dmRoot, AttachedExpander, (bit8) oneExpander->discoveringPhyId);
                  AttachedExpander->hasUpStreamDevice = agTRUE;
                  AttachedExpander->upStreamSASAddressHi 
                    = DEVINFO_GET_SAS_ADDRESSHI(&oneDeviceData->agDeviceInfo);
                  AttachedExpander->upStreamSASAddressLo
                    = DEVINFO_GET_SAS_ADDRESSLO(&oneDeviceData->agDeviceInfo);
                  AttachedExpander->dmUpStreamExpander = oneExpander;
                  /* (2.3.2.2.2.2.2.2.2) Add the pAttachedExpander to discovering list */
                  dmDiscoveringExpanderAdd(dmRoot, onePortContext, AttachedExpander);
                }	
                /* If failed to allocate */
                else
                {
                  DM_DBG1(("dmDownStreamDiscoverExpanderPhy: Failed to allocate expander data structure!!!\n"));
                  /*  discovery done */
                  dmDiscoverDone(dmRoot, onePortContext, DM_RC_FAILURE);
                }
              }	
	    } /* DISCRSP_GET_ROUTINGATTRIB(pDiscoverResp) == SAS_ROUTING_TABLE */
            /* If status is still DISCOVERY_DOWN_STREAM */        
            if ( onePortContext->discovery.status == DISCOVERY_DOWN_STREAM)
            {
              DM_DBG3(("dmDownStreamDiscoverExpanderPhy: 1st before\n"));
              dmDumpAllUpExp(dmRoot, onePortContext, oneExpander); 
              UpStreamExpander = oneExpander->dmUpStreamExpander;
              ConfigurableExpander = dmFindConfigurableExp(dmRoot, onePortContext, oneExpander);
              configSASAddressHi = DEVINFO_GET_SAS_ADDRESSHI(&AttachedDevice->agDeviceInfo);
              configSASAddressLo = DEVINFO_GET_SAS_ADDRESSLO(&AttachedDevice->agDeviceInfo); 
              if (ConfigurableExpander)
              { 
                if ( (ConfigurableExpander->dmDevice->SASAddressID.sasAddressHi 
                      == DEVINFO_GET_SAS_ADDRESSHI(&AttachedDevice->agDeviceInfo)) &&
                     (ConfigurableExpander->dmDevice->SASAddressID.sasAddressLo 
                      == DEVINFO_GET_SAS_ADDRESSLO(&AttachedDevice->agDeviceInfo))
                   )
                { /* directly attached between oneExpander and ConfigurableExpander */       
                  DM_DBG3(("dmDownStreamDiscoverExpanderPhy: 1st before loc 1\n"));
                  configSASAddressHi = oneExpander->dmDevice->SASAddressID.sasAddressHi;
                  configSASAddressLo = oneExpander->dmDevice->SASAddressID.sasAddressLo; 
                }
                else
                {
                  DM_DBG3(("dmDownStreamDiscoverExpanderPhy: 1st before loc 2\n"));
                  configSASAddressHi = DEVINFO_GET_SAS_ADDRESSHI(&AttachedDevice->agDeviceInfo);
                  configSASAddressLo = DEVINFO_GET_SAS_ADDRESSLO(&AttachedDevice->agDeviceInfo); 
                }                                             
              } /* if !ConfigurableExpander */
	  
              dupConfigSASAddr = dmDuplicateConfigSASAddr(dmRoot, 
                                                          ConfigurableExpander,   
                                                          configSASAddressHi,
                                                          configSASAddressLo
                                                          );
	  
              if ( ConfigurableExpander && dupConfigSASAddr == agFALSE)
              {
                DM_DBG3(("dmDownStreamDiscoverExpanderPhy: 1st q123\n"));
                UpStreamExpander->dmCurrentDownStreamExpander = oneExpander;
                ConfigurableExpander->currentDownStreamPhyIndex = 
                        dmFindCurrentDownStreamPhyIndex(dmRoot, ConfigurableExpander);
                ConfigurableExpander->dmReturnginExpander = oneExpander;
                dmRoutingEntryAdd(dmRoot,
                                  ConfigurableExpander, 
                                  ConfigurableExpander->downStreamPhys[ConfigurableExpander->currentDownStreamPhyIndex],
                                  configSASAddressHi,
                                  configSASAddressLo
                                 );
              }                       
            } /* onePortContext->discovery.status == DISCOVERY_DOWN_STREAM */
          } /* AttachedDevice != agNULL */  
          /*  If fail to add the device */    
          else
          {
            DM_DBG1(("dmDownStreamDiscoverExpanderPhy: Failed to add a device!!!\n"));
            /*  discovery done */
            dmDiscoverDone(dmRoot, onePortContext, DM_RC_FAILURE);
          }
        } /* else 11 */
      } /* AttachedDevice == agNULL */
      /* If the device has been discovered before */
      else /* haha discovered before 33 */
      {
        /* If the phy has subtractive routing attribute */
        if ( DISCRSP_GET_ROUTINGATTRIB(pDiscoverResp) == SAS_ROUTING_SUBTRACTIVE)
        {
          /* If the expander doesn't have up stream device */
          if ( oneExpander->hasUpStreamDevice == agFALSE)
          {
            /* TODO: discovery error, callback */
            DM_DBG1(("dmDownStreamDiscoverExpanderPhy: **** Topology Error loop, or end device connects to two expanders!!!\n"));
            onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo
              = DEVINFO_GET_SAS_ADDRESSLO(&oneDeviceData->agDeviceInfo);
            onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi
              = DEVINFO_GET_SAS_ADDRESSHI(&oneDeviceData->agDeviceInfo);
            onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier = oneExpander->discoveringPhyId;
            DM_DBG1(("dmDownStreamDiscoverExpanderPhy: sasAddressHi 0x%08x sasAddressLo 0x%08x phyid 0x%x\n", 
                      onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi, 
                      onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo,
                      onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier));
            /* discovery done */
            dmDiscoverDone(dmRoot, onePortContext, DM_RC_FAILURE);
          }
          /* If the expander has up stream device */
          else /* 44 */
          {
            /* If sas address doesn't match */
            if ( (oneExpander->upStreamSASAddressHi != attachedSasHi)
                 || (oneExpander->upStreamSASAddressLo != attachedSasLo) )
            {
              /* TODO: discovery error, callback */
              DM_DBG1(("dmDownStreamDiscoverExpanderPhy: **** Topology Error two subtractive phys!!!\n"));
              onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo
                = DEVINFO_GET_SAS_ADDRESSLO(&oneDeviceData->agDeviceInfo);
              onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi
                = DEVINFO_GET_SAS_ADDRESSHI(&oneDeviceData->agDeviceInfo);
              onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier = oneExpander->discoveringPhyId;
              DM_DBG1(("dmDownStreamDiscoverExpanderPhy: sasAddressHi 0x%08x sasAddressLo 0x%08x phyid 0x%x\n", 
                       onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi, 
                       onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo,
                       onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier));
              /* discovery done */
              dmDiscoverDone(dmRoot, onePortContext, DM_RC_FAILURE);
            }
          } /* else 44 */	  
        } /* DISCRSP_GET_ROUTINGATTRIB(pDiscoverResp) == SAS_ROUTING_SUBTRACTIVE */      
        /* If the phy has table routing attribute */
        else if ( DISCRSP_GET_ROUTINGATTRIB(pDiscoverResp) == SAS_ROUTING_TABLE)
        {
          /* If the attached device is a fan out expander */
          if ( DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) == SAS_FANOUT_EXPANDER_DEVICE)
          {
            /* (2.3.3.2.1.1) TODO: discovery error, callback */
            DM_DBG1(("dmDownStreamDiscoverExpanderPhy: **** Topology Error fan out expander to routing table phy!!!\n"));
            onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo
              = DEVINFO_GET_SAS_ADDRESSLO(&oneDeviceData->agDeviceInfo);
            onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi
              = DEVINFO_GET_SAS_ADDRESSHI(&oneDeviceData->agDeviceInfo);
            onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier = oneExpander->discoveringPhyId;
            DM_DBG1(("dmDownStreamDiscoverExpanderPhy: sasAddressHi 0x%08x sasAddressLo 0x%08x phyid 0x%x\n", 
                     onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi, 
                     onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo,
                     onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier));
            /* discovery done */
            dmDiscoverDone(dmRoot, onePortContext, DM_RC_FAILURE);
          }
          /* If the attached device is an edge expander */
          else if ( DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) == SAS_EDGE_EXPANDER_DEVICE) 
          {
            /* Setup up stream inform */
            AttachedExpander = AttachedDevice->dmExpander;
            DM_DBG3(("dmDownStreamDiscoverExpanderPhy: Found edge expander=%p\n", AttachedExpander));
            /* If the attached expander has up stream device */
            if ( AttachedExpander->hasUpStreamDevice == agTRUE)
            {
              /* compare the sas address */
              if ( (AttachedExpander->upStreamSASAddressHi
                    != DEVINFO_GET_SAS_ADDRESSHI(&oneDeviceData->agDeviceInfo))
                   || (AttachedExpander->upStreamSASAddressLo
                       != DEVINFO_GET_SAS_ADDRESSLO(&oneDeviceData->agDeviceInfo)))
              {
                /* TODO: discovery error, callback */
                SAS2SAS11Check = dmSAS2SAS11ErrorCheck(dmRoot, onePortContext, AttachedExpander, oneExpander, oneExpander);
                if (SAS2SAS11Check == agTRUE)
                {
                   DM_DBG1(("dmDownStreamDiscoverExpanderPhy: **** Topology Error SAS2 and SAS1.1!!!\n"));
                }
                else
                {
                  DM_DBG1(("dmDownStreamDiscoverExpanderPhy: **** Topology Error two table routing phys connected (1)!!!\n"));
                }
                onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo
                  = DEVINFO_GET_SAS_ADDRESSLO(&oneDeviceData->agDeviceInfo);
                onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi
                  = DEVINFO_GET_SAS_ADDRESSHI(&oneDeviceData->agDeviceInfo);
                onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier = oneExpander->discoveringPhyId;
                DM_DBG1(("dmDownStreamDiscoverExpanderPhy: sasAddressHi 0x%08x sasAddressLo 0x%08x phyid 0x%x\n", 
                         onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi, 
                         onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo,
                         onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier));
                /* discovery done */
                dmDiscoverDone(dmRoot, onePortContext, DM_RC_FAILURE);
              }
              else
              {
                DM_DBG3(("dmDownStreamDiscoverExpanderPhy: Add edge expander=%p\n", AttachedExpander));
                /* set up downstream information on configurable expander */

                dmExpanderDownStreamPhyAdd(dmRoot, oneExpander, (bit8) oneExpander->discoveringPhyId); 
                /* haha */
                dmExpanderUpStreamPhyAdd(dmRoot, AttachedExpander, (bit8) oneExpander->discoveringPhyId);
                /* Add the pAttachedExpander to discovering list */
                dmDiscoveringExpanderAdd(dmRoot, onePortContext, AttachedExpander);
              }
            } /* AttachedExpander->hasUpStreamDevice == agTRUE */      
            /* If the attached expander doesn't have up stream device */
            else
            {
              /* TODO: discovery error, callback */
              DM_DBG1(("dmDownStreamDiscoverExpanderPhy: **** Topology Error two table routing phys connected (2)!!!\n"));
              onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo
                = DEVINFO_GET_SAS_ADDRESSLO(&oneDeviceData->agDeviceInfo);
              onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi
                = DEVINFO_GET_SAS_ADDRESSHI(&oneDeviceData->agDeviceInfo);
              onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier = oneExpander->discoveringPhyId;
              DM_DBG1(("dmDownStreamDiscoverExpanderPhy: sasAddressHi 0x%08x sasAddressLo 0x%08x phyid 0x%x\n", 
                       onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi, 
                       onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo,
                       onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier));
              /* discovery done */
              dmDiscoverDone(dmRoot, onePortContext, DM_RC_FAILURE);
            }
          } /* DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) == SAS_EDGE_EXPANDER_DEVICE */      
        } /* DISCRSP_GET_ROUTINGATTRIB(pDiscoverResp) == SAS_ROUTING_TABLE */      
        /* do this regradless of sub or table */
        /* If status is still DISCOVERY_DOWN_STREAM */            
        if ( onePortContext->discovery.status == DISCOVERY_DOWN_STREAM)
        {
          DM_DBG3(("dmDownStreamDiscoverExpanderPhy: 2nd before\n"));
          dmDumpAllUpExp(dmRoot, onePortContext, oneExpander); 

          UpStreamExpander = oneExpander->dmUpStreamExpander;
          ConfigurableExpander = dmFindConfigurableExp(dmRoot, onePortContext, oneExpander);
          configSASAddressHi = DEVINFO_GET_SAS_ADDRESSHI(&AttachedDevice->agDeviceInfo);
          configSASAddressLo = DEVINFO_GET_SAS_ADDRESSLO(&AttachedDevice->agDeviceInfo); 
          if (ConfigurableExpander)
          { 
            if ( (ConfigurableExpander->dmDevice->SASAddressID.sasAddressHi 
                 == DEVINFO_GET_SAS_ADDRESSHI(&AttachedDevice->agDeviceInfo)) &&
                 (ConfigurableExpander->dmDevice->SASAddressID.sasAddressLo 
                   == DEVINFO_GET_SAS_ADDRESSLO(&AttachedDevice->agDeviceInfo))
               )
            { /* directly attached between oneExpander and ConfigurableExpander */       
              DM_DBG3(("dmDownStreamDiscoverExpanderPhy: 2nd before loc 1\n"));
              configSASAddressHi = oneExpander->dmDevice->SASAddressID.sasAddressHi;
              configSASAddressLo = oneExpander->dmDevice->SASAddressID.sasAddressLo; 
            }
            else
            {
              DM_DBG3(("dmDownStreamDiscoverExpanderPhy: 2nd before loc 2\n"));
              configSASAddressHi = DEVINFO_GET_SAS_ADDRESSHI(&AttachedDevice->agDeviceInfo);
              configSASAddressLo = DEVINFO_GET_SAS_ADDRESSLO(&AttachedDevice->agDeviceInfo); 
            }                                             
          } /* if !ConfigurableExpander */
          dupConfigSASAddr = dmDuplicateConfigSASAddr(dmRoot, 
                                                      ConfigurableExpander,   
                                                      configSASAddressHi,
                                                      configSASAddressLo
                                                      );
          if ( ConfigurableExpander && dupConfigSASAddr == agFALSE)
          {
            DM_DBG3(("dmDownStreamDiscoverExpanderPhy: 2nd q123 \n"));
            UpStreamExpander->dmCurrentDownStreamExpander = oneExpander;
            ConfigurableExpander->currentDownStreamPhyIndex = 
                        dmFindCurrentDownStreamPhyIndex(dmRoot, ConfigurableExpander);
            ConfigurableExpander->dmReturnginExpander = oneExpander;
            dmRoutingEntryAdd(dmRoot,
                              ConfigurableExpander, 
                              ConfigurableExpander->downStreamPhys[ConfigurableExpander->currentDownStreamPhyIndex],
                              configSASAddressHi,
                              configSASAddressLo
                             );
          }                                        
        } /* onePortContext->discovery.status == DISCOVERY_DOWN_STREAM */	  
        /* incremental discovery */
        if (onePortContext->discovery.type == DM_DISCOVERY_OPTION_INCREMENTAL_START)
        {
          connectionRate = MIN(onePortContext->LinkRate, DISCRSP_GET_LINKRATE(pDiscoverResp)); 

          if (DISCRSP_IS_STP_TARGET(pDiscoverResp) || DISCRSP_IS_SATA_DEVICE(pDiscoverResp))    
          {
            DM_DBG3(("dmDownStreamDiscoverExpanderPhy: incremental SATA_STP\n"));

            dmPortSASDeviceAdd(
                              dmRoot,
                              onePortContext,
                              sasIdentify,
                              agFALSE,
                              connectionRate,
                              dmAllShared->itNexusTimeout,
                              0,
                              STP_DEVICE_TYPE,
                              oneDeviceData,
                              oneExpander,
                              pDiscoverResp->phyIdentifier
                              );
          }
          else
          {
            DM_DBG3(("dmDownStreamDiscoverExpanderPhy: incremental SAS\n"));


             dmPortSASDeviceAdd(
                               dmRoot,
                               onePortContext,
                               sasIdentify,
                               agFALSE,
                               connectionRate,
                               dmAllShared->itNexusTimeout,
                               0,
                               SAS_DEVICE_TYPE,
                               oneDeviceData,
                               oneExpander,
                               pDiscoverResp->phyIdentifier
                               );
        
          }
        } /* onePortContext->discovery.type == DM_DISCOVERY_OPTION_INCREMENTAL_START */	
      } /* else 33 */  	    
    } /* (attachedSasLo != onePortContext->sasLocalAddressLo) */  
  
    else /* else 44 */
    {
      DM_DBG3(("dmDownStreamDiscoverExpanderPhy: Found Self\n"));
      DM_DBG3(("dmDownStreamDiscoverExpanderPhy: 3rd before\n"));
      dmDumpAllUpExp(dmRoot, onePortContext, oneExpander); 

      UpStreamExpander = oneExpander->dmUpStreamExpander;
      ConfigurableExpander = dmFindConfigurableExp(dmRoot, onePortContext, oneExpander);
      dupConfigSASAddr = dmDuplicateConfigSASAddr(dmRoot, 
                                                  ConfigurableExpander,   
                                                  onePortContext->sasLocalAddressHi,
                                                  onePortContext->sasLocalAddressLo
                                                  );
      
      if ( ConfigurableExpander && dupConfigSASAddr == agFALSE)
      {
        DM_DBG3(("dmDownStreamDiscoverExpanderPhy: 3rd q123 Setup routing table\n"));
        UpStreamExpander->dmCurrentDownStreamExpander = oneExpander;
        ConfigurableExpander->currentDownStreamPhyIndex = 
                        dmFindCurrentDownStreamPhyIndex(dmRoot, ConfigurableExpander);
        ConfigurableExpander->dmReturnginExpander = oneExpander;
        dmRoutingEntryAdd(dmRoot,
                          ConfigurableExpander, 
                          ConfigurableExpander->downStreamPhys[ConfigurableExpander->currentDownStreamPhyIndex],
                          onePortContext->sasLocalAddressHi,
                          onePortContext->sasLocalAddressLo
                         );
      } 
    } /* else 44 */  
  } /* DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) !=  SAS_NO_DEVICE */
  /* If no device is attached */
  else
  {

   DM_DBG2(("!!!!!!!!!!!!!!!!!!!!! SPIN SATA !!!!!!!!!!!!!!!!!!!!!!!!!!!\n"));
   negotiatedPhyLinkRate =	DISCRSP_GET_LINKRATE(pDiscoverResp); // added by thenil

     if (negotiatedPhyLinkRate == 0x03)
     {

        DM_DBG1(("dmDownStreamDiscover2ExpanderPhy: SPIN SATA sent reset\n"));
		dmPhyControlSend(dmRoot,
                            oneDeviceData, 
                            SMP_PHY_CONTROL_HARD_RESET, 
                                                           pDiscoverResp->phyIdentifier
                           );
    }
       
    /* do nothing */
  }
  
  
  /* Increment the discovering phy id */
  oneExpander->discoveringPhyId ++;
  
  /* If the discovery status is DISCOVERY_DOWN_STREAM */
  if ( onePortContext->discovery.status == DISCOVERY_DOWN_STREAM )
  {
    /* If not the last phy */  
    if ( oneExpander->discoveringPhyId < oneDeviceData->numOfPhys )
    {
      DM_DBG3(("dmDownStreamDiscoverExpanderPhy: More Phys to discover\n"));
      /* continue discovery for the next phy */
      dmDiscoverSend(dmRoot, oneDeviceData);
    }
    /* If the last phy */
    else
    {
      DM_DBG3(("dmDownStreamDiscoverExpanderPhy: No More Phys\n"));

      /* for MCN */
      dmUpdateAllAdjacent(dmRoot, onePortContext, oneDeviceData);  
      /* remove the expander from the discovering list */
      dmDiscoveringExpanderRemove(dmRoot, onePortContext, oneExpander);
      /* continue downstream discovering */
      dmDownStreamDiscovering(dmRoot, onePortContext, oneDeviceData);
    }  
  }
  else
  {
    DM_DBG3(("dmDownStreamDiscoverExpanderPhy: onePortContext->discovery.status not in DISCOVERY_DOWN_STREAM; status %d\n", onePortContext->discovery.status));  
  }  
  DM_DBG3(("dmDownStreamDiscoverExpanderPhy: end return phyID#%d\n", oneExpander->discoveringPhyId - 1));
 
  return;
}	   				


/* works at SAS2 expander (called in dmDownStreamDiscover2ExpanderPhy())
   if currentExpander is SAS2, called in dmDownStreamDiscover2ExpanderPhy()
   if currentExpander is SAS1.1, called in dmDownStreamDiscoverExpanderPhy()
*/
osGLOBAL bit32
dmSAS2SAS11ErrorCheck(
                      dmRoot_t              *dmRoot,
                      dmIntPortContext_t    *onePortContext,
                      dmExpander_t          *topExpander,
                      dmExpander_t          *bottomExpander,
		      dmExpander_t          *currentExpander
                     )
{
  bit32                   result = agFALSE, i = 0;
  bit8                    downStreamPhyID, upStreamPhyID; 
  
  DM_DBG2(("dmSAS2SAS11ErrorCheck: start\n"));
  
  if (topExpander == agNULL)
  {
    DM_DBG2(("dmSAS2SAS11ErrorCheck: topExpander is NULL\n"));
    return result;
  }
  if (bottomExpander == agNULL)
  {
    DM_DBG2(("dmSAS2SAS11ErrorCheck: bottomExpander is NULL\n"));
    return result;
  }
  
  if (currentExpander == agNULL)
  {
    DM_DBG2(("dmSAS2SAS11ErrorCheck: currentExpander is NULL\n"));
    return result;
  }
  
  DM_DBG2(("dmSAS2SAS11ErrorCheck: topExpander addrHi 0x%08x addrLo 0x%08x\n", 
            topExpander->dmDevice->SASAddressID.sasAddressHi, topExpander->dmDevice->SASAddressID.sasAddressLo));
  DM_DBG2(("dmSAS2SAS11ErrorCheck: bottomExpander addrHi 0x%08x addrLo 0x%08x\n", 
            bottomExpander->dmDevice->SASAddressID.sasAddressHi, bottomExpander->dmDevice->SASAddressID.sasAddressLo));
  DM_DBG2(("dmSAS2SAS11ErrorCheck: currentExpander addrHi 0x%08x addrLo 0x%08x\n", 
            currentExpander->dmDevice->SASAddressID.sasAddressHi, currentExpander->dmDevice->SASAddressID.sasAddressLo));
	    
  for (i=0;i<DM_MAX_EXPANDER_PHYS;i++)
  {
    downStreamPhyID = topExpander->downStreamPhys[i];
    upStreamPhyID = bottomExpander->upStreamPhys[i];
    if (currentExpander->SAS2 == 1)
    {
      if ( downStreamPhyID ==  upStreamPhyID &&
           topExpander->routingAttribute[downStreamPhyID] == SAS_ROUTING_TABLE &&
           bottomExpander->routingAttribute[i] == SAS_ROUTING_SUBTRACTIVE && 
           topExpander->SAS2 == 0 &&
           bottomExpander->SAS2 == 1
         )
      {
        result = agTRUE;
        break;
      }
    }	 
    else if (currentExpander->SAS2 == 0)
    {
      if ( downStreamPhyID ==  upStreamPhyID &&
           topExpander->routingAttribute[downStreamPhyID] == SAS_ROUTING_SUBTRACTIVE &&
           bottomExpander->routingAttribute[i] == SAS_ROUTING_TABLE &&
           topExpander->SAS2 == 1 &&
           bottomExpander->SAS2 == 0
         )
      {
        result = agTRUE;
        break;
      }
    }
  }
  return result;
}		     		     

osGLOBAL void
dmDownStreamDiscover2ExpanderPhy(
                                dmRoot_t              *dmRoot,
                                dmIntPortContext_t    *onePortContext,
                                dmExpander_t          *oneExpander,
                                smpRespDiscover2_t     *pDiscoverResp
                                )
{
  dmDeviceData_t          *oneDeviceData;
  dmExpander_t            *UpStreamExpander;
  dmDeviceData_t          *AttachedDevice = agNULL;
  dmExpander_t            *AttachedExpander;
  agsaSASIdentify_t       sasIdentify;
  bit8                    connectionRate;
  bit32                   attachedSasHi, attachedSasLo;
  dmSASSubID_t            dmSASSubID;
  dmExpander_t            *ConfigurableExpander = agNULL;
  bit32                   dupConfigSASAddr = agFALSE;
  bit32                   configSASAddressHi;
  bit32                   configSASAddressLo;
  bit32                   SAS2SAS11Check = agFALSE;
  dmIntRoot_t             *dmIntRoot    = (dmIntRoot_t *)dmRoot->dmData;
  dmIntContext_t          *dmAllShared  = (dmIntContext_t *)&dmIntRoot->dmAllShared;

  
  DM_DBG2(("dmDownStreamDiscover2ExpanderPhy: start\n"));
  DM_DBG2(("dmDownStreamDiscover2ExpanderPhy: exp addrHi 0x%08x\n", oneExpander->dmDevice->SASAddressID.sasAddressHi));
  DM_DBG2(("dmDownStreamDiscover2ExpanderPhy: exp addrLo 0x%08x\n", oneExpander->dmDevice->SASAddressID.sasAddressLo));	
	
  DM_ASSERT(dmRoot, "(dmDownStreamDiscover2ExpanderPhy) dmRoot NULL");
  DM_ASSERT(onePortContext, "(dmDownStreamDiscover2ExpanderPhy) pPort NULL");
  DM_ASSERT(oneExpander, "(dmDownStreamDiscover2ExpanderPhy) pExpander NULL");
  DM_ASSERT(pDiscoverResp, "(dmDownStreamDiscover2ExpanderPhy) pDiscoverResp NULL");

  DM_DBG2(("dmDownStreamDiscover2ExpanderPhy: onePortContxt=%p  oneExpander=%p  oneDeviceData=%p\n", onePortContext, oneExpander, oneExpander->dmDevice));
  
  if (dmDiscoverCheck(dmRoot, onePortContext) == agTRUE)
  {
    DM_DBG1(("dmDownStreamDiscover2ExpanderPhy: invalid port or aborted discovery!!!\n"));  
    return;
  }

  if (oneExpander != oneExpander->dmDevice->dmExpander)
  {
    DM_DBG1(("dmDownStreamDiscover2ExpanderPhy: wrong!!!\n"));
  }
      	              
           
  /* (1) Find the device structure of the expander */
  oneDeviceData = oneExpander->dmDevice;
  
  DM_ASSERT(oneDeviceData, "(dmDownStreamDiscover2ExpanderPhy) pDevice NULL");

  /* for debugging */
  DM_DBG2(("dmDownStreamDiscover2ExpanderPhy: Phy #%d of SAS %08x-%08x\n",
           oneExpander->discoveringPhyId,
           oneDeviceData->SASAddressID.sasAddressHi,
           oneDeviceData->SASAddressID.sasAddressLo));
  
  DM_DBG2(("   Attached device: %s\n",
           ( SAS2_DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) == 0 ? "No Device" : 
             (SAS2_DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) == 1 ? "End Device" : 
              (SAS2_DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) == 2 ? "Edge Expander" : "Fanout Expander")))));
              
  
  /* for debugging */
  if (oneExpander->discoveringPhyId != pDiscoverResp->phyIdentifier)
  {
    DM_DBG1(("dmDownStreamDiscover2ExpanderPhy: !!! Incorrect SMP response !!!\n"));
    DM_DBG1(("dmDownStreamDiscover2ExpanderPhy: Request PhyID #%d Response PhyID #%d\n", oneExpander->discoveringPhyId, pDiscoverResp->phyIdentifier));
    dmhexdump("NO_DEVICE", (bit8*)pDiscoverResp, sizeof(smpRespDiscover2_t));
    dmDiscoverDone(dmRoot, onePortContext, DM_RC_FAILURE);
    return;
  }
  
  if ( SAS2_DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) != SAS_NO_DEVICE)
  {
    DM_DBG2(("   SAS address    : %08x-%08x\n",
      SAS2_DISCRSP_GET_ATTACHED_SAS_ADDRESSHI(pDiscoverResp), 
              SAS2_DISCRSP_GET_ATTACHED_SAS_ADDRESSLO(pDiscoverResp)));
    DM_DBG2(("   SSP Target     : %d\n", SAS2_DISCRSP_IS_SSP_TARGET(pDiscoverResp)?1:0));
    DM_DBG2(("   STP Target     : %d\n", SAS2_DISCRSP_IS_STP_TARGET(pDiscoverResp)?1:0));
    DM_DBG2(("   SMP Target     : %d\n", SAS2_DISCRSP_IS_SMP_TARGET(pDiscoverResp)?1:0));
    DM_DBG2(("   SATA DEVICE    : %d\n", SAS2_DISCRSP_IS_SATA_DEVICE(pDiscoverResp)?1:0));
    DM_DBG2(("   SSP Initiator  : %d\n", SAS2_DISCRSP_IS_SSP_INITIATOR(pDiscoverResp)?1:0));
    DM_DBG2(("   STP Initiator  : %d\n", SAS2_DISCRSP_IS_STP_INITIATOR(pDiscoverResp)?1:0));
    DM_DBG2(("   SMP Initiator  : %d\n", SAS2_DISCRSP_IS_SMP_INITIATOR(pDiscoverResp)?1:0));
    DM_DBG2(("   Phy ID         : %d\n", pDiscoverResp->phyIdentifier));
    DM_DBG2(("   Attached Phy ID: %d\n", pDiscoverResp->attachedPhyIdentifier));
    
  }

    /* saving routing attribute for non self-configuring expanders */
  oneExpander->routingAttribute[pDiscoverResp->phyIdentifier] = SAS2_DISCRSP_GET_ROUTINGATTRIB(pDiscoverResp);
 
  
  oneExpander->discoverSMPAllowed = agTRUE;
  
  /* If a device is attached */
  if ( SAS2_DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) !=  SAS_NO_DEVICE)
  {
    /* Setup sasIdentify for the attached device */
    sasIdentify.phyIdentifier = pDiscoverResp->phyIdentifier;
    sasIdentify.deviceType_addressFrameType = pDiscoverResp->attachedDeviceTypeReason & 0x70;
    sasIdentify.initiator_ssp_stp_smp = pDiscoverResp->attached_Ssp_Stp_Smp_Sata_Initiator;
    sasIdentify.target_ssp_stp_smp = pDiscoverResp->attached_SataPS_Ssp_Stp_Smp_Sata_Target;
    *(bit32*)sasIdentify.sasAddressHi = *(bit32*)pDiscoverResp->attachedSasAddressHi;
    *(bit32*)sasIdentify.sasAddressLo = *(bit32*)pDiscoverResp->attachedSasAddressLo;

    /* incremental discovery */       
    dmSASSubID.sasAddressHi = SA_IDFRM_GET_SAS_ADDRESSHI(&sasIdentify);
    dmSASSubID.sasAddressLo = SA_IDFRM_GET_SAS_ADDRESSLO(&sasIdentify);
    dmSASSubID.initiator_ssp_stp_smp = sasIdentify.initiator_ssp_stp_smp;
    dmSASSubID.target_ssp_stp_smp = sasIdentify.target_ssp_stp_smp;
        
    attachedSasHi = SAS2_DISCRSP_GET_ATTACHED_SAS_ADDRESSHI(pDiscoverResp);
    attachedSasLo = SAS2_DISCRSP_GET_ATTACHED_SAS_ADDRESSLO(pDiscoverResp);

    /* If it's a direct routing */
    if ( SAS2_DISCRSP_GET_ROUTINGATTRIB(pDiscoverResp) == SAS_ROUTING_DIRECT)
    {
      /* If the attached device is an expander */
      if ( (SAS2_DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) == SAS_FANOUT_EXPANDER_DEVICE)
          || (SAS2_DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) == SAS_EDGE_EXPANDER_DEVICE) )

      {
        DM_DBG1(("dmDownStreamDiscover2ExpanderPhy: **** Topology Error direct routing can't connect to expander!!!\n"));
        onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo
           = DEVINFO_GET_SAS_ADDRESSLO(&oneDeviceData->agDeviceInfo);
        onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi
          = DEVINFO_GET_SAS_ADDRESSHI(&oneDeviceData->agDeviceInfo);
        onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier = oneExpander->discoveringPhyId;

        DM_DBG1(("dmDownStreamDiscover2ExpanderPhy: sasAddressHi 0x%08x sasAddressLo 0x%08x phyid 0x%x\n", 
                  onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi, 
                  onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo,
                  onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier));
        dmDiscoverDone(dmRoot, onePortContext, DM_RC_FAILURE);
        
        return;
      }
    }
    
    /* If the expander's attached device is not myself */
    if ( (attachedSasHi != onePortContext->sasLocalAddressHi)
         || (attachedSasLo != onePortContext->sasLocalAddressLo) ) 
    {
      /* Find the attached device from discovered list */
      AttachedDevice = dmPortSASDeviceFind(dmRoot, onePortContext, attachedSasLo, attachedSasHi, oneDeviceData);
      /* If the device has not been discovered before */
      if ( AttachedDevice == agNULL) //11
      {
        //qqqqqq
        if (0)	   
        {
	      DM_DBG1(("dmDownStreamDiscover2ExpanderPhy: **** Topology Error subtractive routing error - inconsistent SAS address!!!\n"));
          onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo
            = DEVINFO_GET_SAS_ADDRESSLO(&oneDeviceData->agDeviceInfo);
          onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi
            = DEVINFO_GET_SAS_ADDRESSHI(&oneDeviceData->agDeviceInfo);
          onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier = oneExpander->discoveringPhyId;
          DM_DBG1(("dmDownStreamDiscover2ExpanderPhy: sasAddressHi 0x%08x sasAddressLo 0x%08x phyid 0x%x\n", 
                    onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi, 
                    onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo,
                    onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier));
          /* discovery done */
          dmDiscoverDone(dmRoot, onePortContext, DM_RC_FAILURE);
        }
        else 
        {
          /* Add the device */
          /* read minimum rate from the configuration 
             onePortContext->LinkRate is SPC's local link rate
          */
          connectionRate = MIN(onePortContext->LinkRate, SAS2_DISCRSP_GET_LOGICAL_LINKRATE(pDiscoverResp)); 
          DM_DBG2(("dmDownStreamDiscover2ExpanderPhy: link rate 0x%x\n", DEVINFO_GET_LINKRATE(&oneDeviceData->agDeviceInfo)));
          DM_DBG2(("dmDownStreamDiscover2ExpanderPhy: negotiatedPhyLinkRate 0x%x\n", SAS2_DISCRSP_GET_LINKRATE(pDiscoverResp)));
          DM_DBG2(("dmDownStreamDiscover2ExpanderPhy: connectionRate 0x%x\n", connectionRate));

          if (SAS2_DISCRSP_IS_STP_TARGET(pDiscoverResp) || SAS2_DISCRSP_IS_SATA_DEVICE(pDiscoverResp))    
          {
            if (onePortContext->discovery.type == DM_DISCOVERY_OPTION_FULL_START)
            {
              AttachedDevice = dmPortSASDeviceAdd(
                                                 dmRoot,
                                                 onePortContext,
                                                 sasIdentify,
                                                 agFALSE,
                                                 connectionRate,
                                                 dmAllShared->itNexusTimeout,
                                                 0,
                                                 STP_DEVICE_TYPE,
                                                 oneDeviceData,
                                                 oneExpander,
                                                 pDiscoverResp->phyIdentifier
                                                 );
            }
            else
            {
              /* incremental discovery */
              AttachedDevice = dmFindRegNValid(
                                               dmRoot,
                                               onePortContext,
                                               &dmSASSubID
                                               );
              /* not registered and not valid; add this*/                                   
              if (AttachedDevice == agNULL)
              {
                AttachedDevice = dmPortSASDeviceAdd(
                                                   dmRoot,
                                                   onePortContext,
                                                   sasIdentify,
                                                   agFALSE,
                                                   connectionRate,
                                                   dmAllShared->itNexusTimeout,
                                                   0,
                                                   STP_DEVICE_TYPE,
                                                   oneDeviceData,
                                                   oneExpander,
                                                   pDiscoverResp->phyIdentifier
                                                   );
              }
            }
          }
          else
          {
            if (onePortContext->discovery.type == DM_DISCOVERY_OPTION_FULL_START)
            {            
              AttachedDevice = dmPortSASDeviceAdd(
                                                 dmRoot,
                                                 onePortContext,
                                                 sasIdentify,
                                                 agFALSE,
                                                 connectionRate,
                                                 dmAllShared->itNexusTimeout,
                                                 0,
                                                 SAS_DEVICE_TYPE,
                                                 oneDeviceData,
                                                 oneExpander,
                                                 pDiscoverResp->phyIdentifier
                                                 );
            }
            else
            {
              /* incremental discovery */
              AttachedDevice = dmFindRegNValid(
                                               dmRoot,
                                               onePortContext,
                                               &dmSASSubID
                                               );
              /* not registered and not valid; add this*/
              if (AttachedDevice == agNULL)
              {
                AttachedDevice = dmPortSASDeviceAdd(
                                                    dmRoot,
                                                    onePortContext,
                                                    sasIdentify,
                                                    agFALSE,
                                                    connectionRate,
                                                    dmAllShared->itNexusTimeout,
                                                    0,
                                                    SAS_DEVICE_TYPE,
                                                    oneDeviceData,
                                                    oneExpander,
                                                    pDiscoverResp->phyIdentifier
                                                    );
              }                    
            }                                                    
          }
          DM_DBG2(("dmDownStreamDiscover2ExpanderPhy: newDevice  pDevice=%p\n", AttachedDevice));
          /* If the device is added successfully */    
          if ( AttachedDevice != agNULL)
          {
            if ( SA_IDFRM_IS_SSP_TARGET(&sasIdentify) 
                 || SA_IDFRM_IS_SMP_TARGET(&sasIdentify)
                 || SA_IDFRM_IS_SSP_INITIATOR(&sasIdentify)
                 || SA_IDFRM_IS_SMP_INITIATOR(&sasIdentify) )
            {
              DM_DBG2(("dmDownStreamDiscover2ExpanderPhy: Report a new SAS device !!\n"));  
               
            }
            else
            {
              if ( SA_IDFRM_IS_STP_TARGET(&sasIdentify) || 
                   SA_IDFRM_IS_SATA_DEVICE(&sasIdentify) )
              {
                
                DM_DBG2(("dmDownStreamDiscover2ExpanderPhy: Found an STP or SATA device.\n"));
              }
              else
              {
                DM_DBG2(("dmDownStreamDiscover2ExpanderPhy: Found Other type of device.\n"));
              }
            }
            
            /* LP2006-05-26 added upstream device to the newly found device */
            AttachedDevice->dmExpander = oneExpander;
            DM_DBG3(("dmDownStreamDiscover2ExpanderPhy: AttachedDevice %p did %d\n", AttachedDevice, AttachedDevice->id));
            DM_DBG3(("dmDownStreamDiscover2ExpanderPhy: Attached oneExpander %p did %d\n",  AttachedDevice->dmExpander,  AttachedDevice->dmExpander->id));
	    
            DM_DBG3(("dmDownStreamDiscover2ExpanderPhy: oneDeviceData %p did %d\n", oneDeviceData, oneDeviceData->id));
            DM_DBG3(("dmDownStreamDiscover2ExpanderPhy: oneExpander %p did %d\n",  oneDeviceData->dmExpander,  oneDeviceData->dmExpander->id));
						 						 
            /* If the phy has table routing attribute */
            if ( SAS2_DISCRSP_GET_ROUTINGATTRIB(pDiscoverResp) == SAS_ROUTING_TABLE)
            {
              /* If the attached device is a fan out expander */
              if ( SAS2_DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) == SAS_FANOUT_EXPANDER_DEVICE)
              {
                /* TODO: discovery error, callback */
                DM_DBG1(("dmDownStreamDiscover2ExpanderPhy: **** Topology Error two table routing phys are connected!!!\n"));
                onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo
                  = DEVINFO_GET_SAS_ADDRESSLO(&oneDeviceData->agDeviceInfo);
                onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi
                  = DEVINFO_GET_SAS_ADDRESSHI(&oneDeviceData->agDeviceInfo);
                onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier = oneExpander->discoveringPhyId;
                DM_DBG1(("dmDownStreamDiscover2ExpanderPhy: sasAddressHi 0x%08x sasAddressLo 0x%08x phyid 0x%x\n", 
                          onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi, 
		          onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo,
		          onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier));
                /* discovery done */
                dmDiscoverDone(dmRoot, onePortContext, DM_RC_FAILURE);
              }
              else if ( SAS2_DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) == SAS_EDGE_EXPANDER_DEVICE) 
              {
                /* Allocate an expander data structure */
                AttachedExpander = dmDiscoveringExpanderAlloc(dmRoot, onePortContext, AttachedDevice);
                 
                DM_DBG2(("dmDownStreamDiscover2ExpanderPhy: Found a EDGE exp device.%p\n", AttachedExpander));
                /* If allocate successfully */
                if ( AttachedExpander != agNULL)
                {
                  /* set up downstream information on configurable expander */
 
                  dmExpanderDownStreamPhyAdd(dmRoot, oneExpander, (bit8) oneExpander->discoveringPhyId); 
             
                  /* Setup upstream information */
                  dmExpanderUpStreamPhyAdd(dmRoot, AttachedExpander, (bit8) oneExpander->discoveringPhyId);
//qqqqq		  
                  AttachedExpander->hasUpStreamDevice = agTRUE;
                  AttachedExpander->upStreamSASAddressHi 
                    = DEVINFO_GET_SAS_ADDRESSHI(&oneDeviceData->agDeviceInfo);
                  AttachedExpander->upStreamSASAddressLo
                    = DEVINFO_GET_SAS_ADDRESSLO(&oneDeviceData->agDeviceInfo);
                  AttachedExpander->dmUpStreamExpander = oneExpander;
                  /* (2.3.2.2.2.2.2.2.2) Add the pAttachedExpander to discovering list */
                  dmDiscoveringExpanderAdd(dmRoot, onePortContext, AttachedExpander);
                }	
                /* If failed to allocate */
                else
                {
                  DM_DBG1(("dmDownStreamDiscover2ExpanderPhy, Failed to allocate expander data structure!!!\n"));
                  /*  discovery done */
                  dmDiscoverDone(dmRoot, onePortContext, DM_RC_FAILURE);
                }
              }	
            }
	    //qqqqq
	    else if ( SAS2_DISCRSP_GET_ROUTINGATTRIB(pDiscoverResp) == SAS_ROUTING_SUBTRACTIVE &&
                       (SAS2_DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) == SAS_FANOUT_EXPANDER_DEVICE ||
                        SAS2_DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) == SAS_EDGE_EXPANDER_DEVICE)		     	    
	            )
	    {
              /* Allocate an expander data structure */
              AttachedExpander = dmDiscoveringExpanderAlloc(dmRoot, onePortContext, AttachedDevice);
                 
              DM_DBG2(("dmDownStreamDiscover2ExpanderPhy: Found a EDGE/FANOUT exp device.%p\n", AttachedExpander));
              /* If allocate successfully */
              if ( AttachedExpander != agNULL)
              {
                /* set up downstream information on configurable expander */
                dmExpanderDownStreamPhyAdd(dmRoot, oneExpander, (bit8) oneExpander->discoveringPhyId); 
                
                /* Setup upstream information */
                dmExpanderUpStreamPhyAdd(dmRoot, AttachedExpander, (bit8) oneExpander->discoveringPhyId);
                AttachedExpander->hasUpStreamDevice = agTRUE;
                AttachedExpander->upStreamSASAddressHi 
                  = DEVINFO_GET_SAS_ADDRESSHI(&oneDeviceData->agDeviceInfo);
                AttachedExpander->upStreamSASAddressLo
                  = DEVINFO_GET_SAS_ADDRESSLO(&oneDeviceData->agDeviceInfo);
                AttachedExpander->dmUpStreamExpander = oneExpander;
                /* (2.3.2.2.2.2.2.2.2) Add the pAttachedExpander to discovering list */
                dmDiscoveringExpanderAdd(dmRoot, onePortContext, AttachedExpander);
              }	
              /* If failed to allocate */
              else
              {
                DM_DBG1(("dmDownStreamDiscover2ExpanderPhy, Failed to allocate expander data structure (2)!!!\n"));
                /*  discovery done */
                dmDiscoverDone(dmRoot, onePortContext, DM_RC_FAILURE);
              }
		
		
	    }
            /* If status is still DISCOVERY_DOWN_STREAM */        
            if ( onePortContext->discovery.status == DISCOVERY_DOWN_STREAM &&
	         onePortContext->discovery.ConfiguresOthers == agFALSE)
            {
              DM_DBG2(("dmDownStreamDiscover2ExpanderPhy: 1st before\n"));
              dmDumpAllUpExp(dmRoot, onePortContext, oneExpander); 
              UpStreamExpander = oneExpander->dmUpStreamExpander;
              ConfigurableExpander = dmFindConfigurableExp(dmRoot, onePortContext, oneExpander);
              configSASAddressHi = DEVINFO_GET_SAS_ADDRESSHI(&AttachedDevice->agDeviceInfo);
              configSASAddressLo = DEVINFO_GET_SAS_ADDRESSLO(&AttachedDevice->agDeviceInfo); 
              if (ConfigurableExpander)
              { 
                if ( (ConfigurableExpander->dmDevice->SASAddressID.sasAddressHi 
                      == DEVINFO_GET_SAS_ADDRESSHI(&AttachedDevice->agDeviceInfo)) &&
                     (ConfigurableExpander->dmDevice->SASAddressID.sasAddressLo 
                      == DEVINFO_GET_SAS_ADDRESSLO(&AttachedDevice->agDeviceInfo))
                   )
                { /* directly attached between oneExpander and ConfigurableExpander */       
                  DM_DBG2(("dmDownStreamDiscover2ExpanderPhy: 1st before loc 1\n"));
                  configSASAddressHi = oneExpander->dmDevice->SASAddressID.sasAddressHi;
                  configSASAddressLo = oneExpander->dmDevice->SASAddressID.sasAddressLo; 
                }
                else
                {
                  DM_DBG2(("dmDownStreamDiscover2ExpanderPhy: 1st before loc 2\n"));
                  configSASAddressHi = DEVINFO_GET_SAS_ADDRESSHI(&AttachedDevice->agDeviceInfo);
                  configSASAddressLo = DEVINFO_GET_SAS_ADDRESSLO(&AttachedDevice->agDeviceInfo); 
                }                                             
              } /* if !ConfigurableExpander */
              dupConfigSASAddr = dmDuplicateConfigSASAddr(dmRoot, 
                                                            ConfigurableExpander,   
                                                            configSASAddressHi,
                                                            configSASAddressLo
                                                            );
              
                                                        
              if ( ConfigurableExpander && dupConfigSASAddr == agFALSE)
              {
                DM_DBG2(("dmDownStreamDiscover2ExpanderPhy: 1st q123\n"));
                UpStreamExpander->dmCurrentDownStreamExpander = oneExpander;
                ConfigurableExpander->currentDownStreamPhyIndex = 
                        dmFindCurrentDownStreamPhyIndex(dmRoot, ConfigurableExpander);
                ConfigurableExpander->dmReturnginExpander = oneExpander;
                dmRoutingEntryAdd(dmRoot,
                                  ConfigurableExpander, 
                                  ConfigurableExpander->downStreamPhys[ConfigurableExpander->currentDownStreamPhyIndex],
                                  configSASAddressHi,
                                  configSASAddressLo
                                 );
              }                       
            }
          } 
          /*  If fail to add the device */    
          else
          {
            DM_DBG1(("dmDownStreamDiscover2ExpanderPhy, Failed to add a device!!!\n"));
            /*  discovery done */
            dmDiscoverDone(dmRoot, onePortContext, DM_RC_FAILURE);
          }
        }
      }
      /* If the device has been discovered before */
      else /* discovered before */
      {
        /* If the phy has subtractive routing attribute */
        if ( SAS2_DISCRSP_GET_ROUTINGATTRIB(pDiscoverResp) == SAS_ROUTING_SUBTRACTIVE)
        {
          /* If the expander doesn't have up stream device */
          if ( oneExpander->hasUpStreamDevice == agFALSE)
          {
            /* TODO: discovery error, callback */
            DM_DBG1(("dmDownStreamDiscover2ExpanderPhy: **** Topology Error loop, or end device connects to two expanders!!!\n"));
            onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo
              = DEVINFO_GET_SAS_ADDRESSLO(&oneDeviceData->agDeviceInfo);
            onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi
              = DEVINFO_GET_SAS_ADDRESSHI(&oneDeviceData->agDeviceInfo);
            onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier = oneExpander->discoveringPhyId;
            DM_DBG1(("dmDownStreamDiscover2ExpanderPhy: sasAddressHi 0x%08x sasAddressLo 0x%08x phyid 0x%x\n", 
                      onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi, 
                      onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo,
                      onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier));
            /* discovery done */
            dmDiscoverDone(dmRoot, onePortContext, DM_RC_FAILURE);
          }
          /* If the expander has up stream device */
          else
          {
	    
//qqqqq
            /* If sas address doesn't match */
            if ( (oneExpander->upStreamSASAddressHi != attachedSasHi)
                 || (oneExpander->upStreamSASAddressLo != attachedSasLo) )
            {
              /* TODO: discovery error, callback */
              DM_DBG1(("dmDownStreamDiscover2ExpanderPhy: **** two subtractive phys!!! Allowed in SAS2!!!\n"));
              onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo
                = DEVINFO_GET_SAS_ADDRESSLO(&oneDeviceData->agDeviceInfo);
              onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi
                = DEVINFO_GET_SAS_ADDRESSHI(&oneDeviceData->agDeviceInfo);
              onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier = oneExpander->discoveringPhyId;
	      onePortContext->discovery.DeferredError = agTRUE;
     
            }
          }
        }
        /* If the phy has table routing attribute */
        else if ( SAS2_DISCRSP_GET_ROUTINGATTRIB(pDiscoverResp) == SAS_ROUTING_TABLE)
        {
          /* If the attached device is a fan out expander */
          if ( SAS2_DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) == SAS_FANOUT_EXPANDER_DEVICE)
          {
            /* (2.3.3.2.1.1) TODO: discovery error, callback */
            DM_DBG1(("dmDownStreamDiscover2ExpanderPhy: **** Topology Error fan out expander to routing table phy!!!\n"));
            onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo
              = DEVINFO_GET_SAS_ADDRESSLO(&oneDeviceData->agDeviceInfo);
            onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi
              = DEVINFO_GET_SAS_ADDRESSHI(&oneDeviceData->agDeviceInfo);
            onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier = oneExpander->discoveringPhyId;
            DM_DBG1(("dmDownStreamDiscover2ExpanderPhy: sasAddressHi 0x%08x sasAddressLo 0x%08x phyid 0x%x\n", 
                      onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi, 
                      onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo,
                      onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier));
            /* discovery done */
            dmDiscoverDone(dmRoot, onePortContext, DM_RC_FAILURE);
          }
          /* If the attached device is an edge expander */
          else if ( SAS2_DISCRSP_GET_ATTACHED_DEVTYPE(pDiscoverResp) == SAS_EDGE_EXPANDER_DEVICE) 
          {
            /* Setup up stream inform */
            AttachedExpander = AttachedDevice->dmExpander;
            DM_DBG2(("dmDownStreamDiscover2ExpanderPhy: Found edge expander=%p\n", AttachedExpander));
            //hhhhhh
            /* If the attached expander has up stream device */
            if ( AttachedExpander->hasUpStreamDevice == agTRUE)
            {
              /* compare the sas address */
              if ( (AttachedExpander->upStreamSASAddressHi
                    != DEVINFO_GET_SAS_ADDRESSHI(&oneDeviceData->agDeviceInfo))
                   || (AttachedExpander->upStreamSASAddressLo
                       != DEVINFO_GET_SAS_ADDRESSLO(&oneDeviceData->agDeviceInfo)))
              {
	        if (AttachedExpander->TTTSupported && oneExpander->TTTSupported)
		{
                  /*
		     needs further error checking 
		     UpstreamExpanderOfAttachedExpander = AttachedExpander->UpStreamExpander
		     for (i=0;i<DM_MAX_EXPANDER_PHYS;i++)
		     {
		       if (UpstreamExpanderOfAttachedExpander->downStreamPhys[i] != 0 &&
		     } 
		  */
		  SAS2SAS11Check = dmSAS2SAS11ErrorCheck(dmRoot, onePortContext, AttachedExpander->dmUpStreamExpander, AttachedExpander, oneExpander);                  
		  if (SAS2SAS11Check == agTRUE)
		  {
                    
		    DM_DBG1(("dmDownStreamDiscover2ExpanderPhy: **** Topology Error SAS2 and SAS1.1!!!\n"));                    
		    onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo
                      = DEVINFO_GET_SAS_ADDRESSLO(&oneDeviceData->agDeviceInfo);                    
		    onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi
                      = DEVINFO_GET_SAS_ADDRESSHI(&oneDeviceData->agDeviceInfo);                    
		    onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier = oneExpander->discoveringPhyId;                    
		    DM_DBG1(("dmDownStreamDiscover2ExpanderPhy: sasAddressHi 0x%08x sasAddressLo 0x%08x phyid 0x%x\n", 
                              onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi, 
                              onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo,
                              onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier));                    
		    /* discovery done */                    
		    dmDiscoverDone(dmRoot, onePortContext, DM_RC_FAILURE);
		  }
		  else
		  {
		    DM_DBG1(("dmDownStreamDiscover2ExpanderPhy: Allowed Table to Table (1)\n"));
		    /* move on to the next phys but should be not proceed after oneExpander */
		    oneExpander->UndoDueToTTTSupported = agTRUE;
		    onePortContext->discovery.DeferredError = agFALSE;
		  }
		}
		else
		{
                  /* TODO: discovery error, callback */
                  DM_DBG1(("dmDownStreamDiscover2ExpanderPhy: **** Topology Error two table routing phys connected (1)!!!\n"));
                  onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo
                    = DEVINFO_GET_SAS_ADDRESSLO(&oneDeviceData->agDeviceInfo);
                  onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi
                    = DEVINFO_GET_SAS_ADDRESSHI(&oneDeviceData->agDeviceInfo);
                  onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier = oneExpander->discoveringPhyId;
                  DM_DBG1(("dmDownStreamDiscover2ExpanderPhy: sasAddressHi 0x%08x sasAddressLo 0x%08x phyid 0x%x\n", 
                            onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi, 
                            onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo,
                            onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier));
                  /* discovery done */
                  dmDiscoverDone(dmRoot, onePortContext, DM_RC_FAILURE);
		}
              }
              else
              {
                DM_DBG2(("dmDownStreamDiscover2ExpanderPhy: Add edge expander=%p\n", AttachedExpander));
                /* set up downstream information on configurable expander */
       
                dmExpanderDownStreamPhyAdd(dmRoot, oneExpander, (bit8) oneExpander->discoveringPhyId); 
                /* haha */
                dmExpanderUpStreamPhyAdd(dmRoot, AttachedExpander, (bit8) oneExpander->discoveringPhyId);
                /* Add the pAttachedExpander to discovering list */
                dmDiscoveringExpanderAdd(dmRoot, onePortContext, AttachedExpander);
              }
            }
            /* If the attached expander doesn't have up stream device */
            else
            {
	      if (AttachedExpander->TTTSupported && oneExpander->TTTSupported)
              {
                DM_DBG1(("dmDownStreamDiscover2ExpanderPhy: Allowed Table to Table (2)\n"));
		/* move on to the next phys but should be not proceed after oneExpander */
                oneExpander->UndoDueToTTTSupported = agTRUE;
		onePortContext->discovery.DeferredError = agFALSE;
              }
              else
              {
                /* TODO: discovery error, callback */
                DM_DBG1(("dmDownStreamDiscover2ExpanderPhy: **** Topology Error two table routing phys connected (2)!!!\n"));
                onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo
                  = DEVINFO_GET_SAS_ADDRESSLO(&oneDeviceData->agDeviceInfo);
                onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi
                  = DEVINFO_GET_SAS_ADDRESSHI(&oneDeviceData->agDeviceInfo);
                onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier = oneExpander->discoveringPhyId;
                DM_DBG1(("dmDownStreamDiscover2ExpanderPhy: sasAddressHi 0x%08x sasAddressLo 0x%08x phyid 0x%x\n", 
                          onePortContext->discovery.sasAddressIDDiscoverError.sasAddressHi, 
                          onePortContext->discovery.sasAddressIDDiscoverError.sasAddressLo,
                          onePortContext->discovery.sasAddressIDDiscoverError.phyIdentifier));
                /* discovery done */
                dmDiscoverDone(dmRoot, onePortContext, DM_RC_FAILURE);
	      }
            }
          }  
        } /* for else if (SAS2_DISCRSP_GET_ROUTINGATTRIB(pDiscoverResp) == SAS_ROUTING_TABLE) */
          
        /* do this regradless of sub or table */
        /* If status is still DISCOVERY_DOWN_STREAM */            
        if ( onePortContext->discovery.status == DISCOVERY_DOWN_STREAM &&
             onePortContext->discovery.ConfiguresOthers == agFALSE)
        {
          DM_DBG2(("dmDownStreamDiscover2ExpanderPhy: 2nd before\n"));
          dmDumpAllUpExp(dmRoot, onePortContext, oneExpander); 

          UpStreamExpander = oneExpander->dmUpStreamExpander;
          ConfigurableExpander = dmFindConfigurableExp(dmRoot, onePortContext, oneExpander);
          configSASAddressHi = DEVINFO_GET_SAS_ADDRESSHI(&AttachedDevice->agDeviceInfo);
          configSASAddressLo = DEVINFO_GET_SAS_ADDRESSLO(&AttachedDevice->agDeviceInfo); 
          if (ConfigurableExpander)
          { 
            if ( (ConfigurableExpander->dmDevice->SASAddressID.sasAddressHi 
                 == DEVINFO_GET_SAS_ADDRESSHI(&AttachedDevice->agDeviceInfo)) &&
                 (ConfigurableExpander->dmDevice->SASAddressID.sasAddressLo 
                   == DEVINFO_GET_SAS_ADDRESSLO(&AttachedDevice->agDeviceInfo))
               )
            { /* directly attached between oneExpander and ConfigurableExpander */       
              DM_DBG2(("dmDownStreamDiscover2ExpanderPhy: 2nd before loc 1\n"));
              configSASAddressHi = oneExpander->dmDevice->SASAddressID.sasAddressHi;
              configSASAddressLo = oneExpander->dmDevice->SASAddressID.sasAddressLo; 
            }
            else
            {
              DM_DBG2(("dmDownStreamDiscover2ExpanderPhy: 2nd before loc 2\n"));
              configSASAddressHi = DEVINFO_GET_SAS_ADDRESSHI(&AttachedDevice->agDeviceInfo);
              configSASAddressLo = DEVINFO_GET_SAS_ADDRESSLO(&AttachedDevice->agDeviceInfo); 
            }                                             
          } /* if !ConfigurableExpander */
          dupConfigSASAddr = dmDuplicateConfigSASAddr(dmRoot, 
                                                        ConfigurableExpander,   
                                                        configSASAddressHi,
                                                        configSASAddressLo
                                                        );
            
          if ( ConfigurableExpander && dupConfigSASAddr == agFALSE)
          {
            DM_DBG2(("dmDownStreamDiscover2ExpanderPhy: 2nd q123 \n"));
            UpStreamExpander->dmCurrentDownStreamExpander = oneExpander;
            ConfigurableExpander->currentDownStreamPhyIndex = 
                        dmFindCurrentDownStreamPhyIndex(dmRoot, ConfigurableExpander);
            ConfigurableExpander->dmReturnginExpander = oneExpander;
            dmRoutingEntryAdd(dmRoot,
                              ConfigurableExpander, 
                              ConfigurableExpander->downStreamPhys[ConfigurableExpander->currentDownStreamPhyIndex],
                              configSASAddressHi,
                              configSASAddressLo
                             );
          }                                        
        } /* if (onePortContext->discovery.status == DISCOVERY_DOWN_STREAM) */          
        /* incremental discovery */
        if (onePortContext->discovery.type == DM_DISCOVERY_OPTION_INCREMENTAL_START)
        {
          connectionRate = MIN(onePortContext->LinkRate, SAS2_DISCRSP_GET_LOGICAL_LINKRATE(pDiscoverResp)); 

          if (SAS2_DISCRSP_IS_STP_TARGET(pDiscoverResp) || SAS2_DISCRSP_IS_SATA_DEVICE(pDiscoverResp))    
          {
            DM_DBG2(("dmDownStreamDiscover2ExpanderPhy: incremental SATA_STP\n"));

            dmPortSASDeviceAdd(
                              dmRoot,
                              onePortContext,
                              sasIdentify,
                              agFALSE,
                              connectionRate,
                              dmAllShared->itNexusTimeout,
                              0,
                              STP_DEVICE_TYPE,
                              oneDeviceData,
                              oneExpander,
                              pDiscoverResp->phyIdentifier
                              );
          }
          else
          {
            DM_DBG2(("dmDownStreamDiscover2ExpanderPhy: incremental SAS\n"));

             dmPortSASDeviceAdd(
                               dmRoot,
                               onePortContext,
                               sasIdentify,
                               agFALSE,
                               connectionRate,
                               dmAllShared->itNexusTimeout,
                               0,
                               SAS_DEVICE_TYPE,
                               oneDeviceData,
                               oneExpander,
                               pDiscoverResp->phyIdentifier
                               );
        
          }
        }
        
        
      }/* else; existing devce */
    } /* not attached to myself */
    /* If the attached device is myself */
    else
    {
      DM_DBG2(("dmDownStreamDiscover2ExpanderPhy: Found Self\n"));
      DM_DBG2(("dmDownStreamDiscover2ExpanderPhy: 3rd before\n"));
      dmDumpAllUpExp(dmRoot, onePortContext, oneExpander); 

      if (onePortContext->discovery.ConfiguresOthers == agFALSE)
      {	  
        UpStreamExpander = oneExpander->dmUpStreamExpander;
        ConfigurableExpander = dmFindConfigurableExp(dmRoot, onePortContext, oneExpander);
        dupConfigSASAddr = dmDuplicateConfigSASAddr(dmRoot, 
                                                      ConfigurableExpander,   
                                                      onePortContext->sasLocalAddressHi,
                                                      onePortContext->sasLocalAddressLo
                                                      );
      
        if ( ConfigurableExpander && dupConfigSASAddr == agFALSE)
        {
          DM_DBG2(("dmDownStreamDiscover2ExpanderPhy: 3rd q123 Setup routing table\n"));
          UpStreamExpander->dmCurrentDownStreamExpander = oneExpander;
          ConfigurableExpander->currentDownStreamPhyIndex = 
                          dmFindCurrentDownStreamPhyIndex(dmRoot, ConfigurableExpander);
          ConfigurableExpander->dmReturnginExpander = oneExpander;
          dmRoutingEntryAdd(dmRoot,
                            ConfigurableExpander, 
                            ConfigurableExpander->downStreamPhys[ConfigurableExpander->currentDownStreamPhyIndex],
                            onePortContext->sasLocalAddressHi,
                            onePortContext->sasLocalAddressLo
                           );
        }
      } 
    }
  }
  /* If no device is attached */
  else
  {
  }


  /* Increment the discovering phy id */
  oneExpander->discoveringPhyId ++;
  
  /* If the discovery status is DISCOVERY_DOWN_STREAM */
  if ( onePortContext->discovery.status == DISCOVERY_DOWN_STREAM )
  {
    /* If not the last phy */  
    if ( oneExpander->discoveringPhyId < oneDeviceData->numOfPhys )
    {
      DM_DBG2(("dmDownStreamDiscover2ExpanderPhy: More Phys to discover\n"));
      /* continue discovery for the next phy */
      dmDiscoverSend(dmRoot, oneDeviceData);
    }
    /* If the last phy */
    else
    {
      DM_DBG2(("dmDownStreamDiscover2ExpanderPhy: No More Phys\n"));
     
      /* for MCN */
      dmUpdateAllAdjacent(dmRoot, onePortContext, oneDeviceData);  
      ConfigurableExpander = dmFindConfigurableExp(dmRoot, onePortContext, oneExpander);
      if (oneExpander->UndoDueToTTTSupported == agTRUE && ConfigurableExpander != agNULL)
//      if (oneExpander->UndoDueToTTTSupported == agTRUE)
      {
        DM_DBG2(("dmDownStreamDiscover2ExpanderPhy: Not sure!!!\n"));
        dmDiscoveringUndoAdd(dmRoot, onePortContext, oneExpander);       
        oneExpander->UndoDueToTTTSupported = agFALSE;
      }
      
      /* remove the expander from the discovering list */
      dmDiscoveringExpanderRemove(dmRoot, onePortContext, oneExpander);
      /* continue downstream discovering */
      dmDownStreamDiscovering(dmRoot, onePortContext, oneDeviceData);
    }  
  }
  else
  {
    DM_DBG2(("dmDownStreamDiscover2ExpanderPhy: onePortContext->discovery.status not in DISCOVERY_DOWN_STREAM; status %d\n", onePortContext->discovery.status));  
  }  
  DM_DBG2(("dmDownStreamDiscover2ExpanderPhy: end return phyID#%d\n", oneExpander->discoveringPhyId - 1));
 
  return;
}			     


osGLOBAL void
dmDiscoveringUndoAdd(
                     dmRoot_t                 *dmRoot,
                     dmIntPortContext_t       *onePortContext,
                     dmExpander_t             *oneExpander
                    )
{
  dmIntRoot_t        *dmIntRoot    = (dmIntRoot_t *)dmRoot->dmData;
  dmIntContext_t     *dmAllShared = (dmIntContext_t *)&dmIntRoot->dmAllShared;
  dmList_t           *ExpanderList;
  dmExpander_t       *tempExpander;
  dmIntPortContext_t *tmpOnePortContext = onePortContext;
  
  DM_DBG2(("dmDiscoveringUndoAdd: start\n"));
  if (DMLIST_EMPTY(&(tmpOnePortContext->discovery.discoveringExpanderList)))
  {
    DM_DBG2(("dmDiscoveringUndoAdd: empty discoveringExpanderList\n"));
    return;
  }

//  DM_DBG2(("dmDiscoveringUndoAdd: before\n"));
//  dmDumpAllExp(dmRoot, onePortContext, oneExpander);

  ExpanderList = tmpOnePortContext->discovery.discoveringExpanderList.flink;
  while (ExpanderList != &(tmpOnePortContext->discovery.discoveringExpanderList))
  {
    tempExpander = DMLIST_OBJECT_BASE(dmExpander_t, linkNode, ExpanderList);
    if ( tempExpander == agNULL)
    {
      DM_DBG1(("dmDiscoveringUndoAdd: tempExpander is NULL!!!\n"));    
      return;    
    }
    if (tempExpander->dmUpStreamExpander == oneExpander)
    {
      DM_DBG2(("dmDiscoveringUndoAdd: match!!! expander id %d\n", tempExpander->id));
      DM_DBG2(("dmDiscoveringUndoAdd: exp addrHi 0x%08x\n", tempExpander->dmDevice->SASAddressID.sasAddressHi));
      DM_DBG2(("dmDiscoveringUndoAdd: exp addrLo 0x%08x\n", tempExpander->dmDevice->SASAddressID.sasAddressLo));
      tddmSingleThreadedEnter(dmRoot, DM_EXPANDER_LOCK);
      DMLIST_DEQUEUE_THIS(&(tempExpander->linkNode));
//      DMLIST_ENQUEUE_AT_TAIL(&(tempExpander->linkNode), &(dmAllShared->freeExpanderList));
      DMLIST_ENQUEUE_AT_TAIL(&(tempExpander->linkNode), &(dmAllShared->mainExpanderList));
      tddmSingleThreadedLeave(dmRoot, DM_EXPANDER_LOCK);
      ExpanderList = tmpOnePortContext->discovery.discoveringExpanderList.flink;      
    }
    if (DMLIST_EMPTY(&(tmpOnePortContext->discovery.discoveringExpanderList)))
    {
      DM_DBG2(("dmDiscoveringUndoAdd: hitting break\n"));
      break;
    }
    ExpanderList = ExpanderList->flink;
  }
  
//  DM_DBG2(("dmDiscoveringUndoAdd: after\n"));
//  dmDumpAllExp(dmRoot, onePortContext, oneExpander);
  return;
}			     

osGLOBAL void
dmHandleZoneViolation(
                      dmRoot_t              *dmRoot,
                      agsaRoot_t            *agRoot,
                      agsaIORequest_t       *agIORequest,
                      dmDeviceData_t        *oneDeviceData,
                      dmSMPFrameHeader_t    *frameHeader,
                      agsaFrameHandle_t     frameHandle
                     )
{
  dmIntPortContext_t           *onePortContext = agNULL;
  dmExpander_t                 *oneExpander = agNULL;

  DM_DBG1(("dmHandleZoneViolation: start\n"));  
  DM_DBG1(("dmHandleZoneViolation: sasAddressHi 0x%08x\n", oneDeviceData->SASAddressID.sasAddressHi));
  DM_DBG1(("dmHandleZoneViolation: sasAddressLo 0x%08x\n", oneDeviceData->SASAddressID.sasAddressLo));
  onePortContext = oneDeviceData->dmPortContext;
  oneExpander = oneDeviceData->dmExpander;
  if (dmDiscoverCheck(dmRoot, onePortContext) == agTRUE)
  {
    DM_DBG1(("dmHandleZoneViolation: invalid port or aborted discovery!!!\n"));
    return;
  }
  /* for MCN */
  dmUpdateAllAdjacent(dmRoot, onePortContext, oneDeviceData);
  /* remove the expander from the discovering list */
  dmDiscoveringExpanderRemove(dmRoot, onePortContext, oneExpander);
  if ( onePortContext->discovery.status == DISCOVERY_UP_STREAM)
  {
    /* continue upstream discovering */
    dmUpStreamDiscovering(dmRoot, onePortContext, oneDeviceData);
  }
  else /* DISCOVERY_DOWN_STREAM or DISCOVERY_CONFIG_ROUTING */
  {
    /* continue downstream discovering */
    dmDownStreamDiscovering(dmRoot, onePortContext, oneDeviceData);
  }
  return;
}


osGLOBAL void
dmUpStreamDiscoverExpanderPhySkip(
                                   dmRoot_t              *dmRoot,
                                   dmIntPortContext_t    *onePortContext,
                                   dmExpander_t          *oneExpander
                                   )

{
  dmDeviceData_t          *oneDeviceData;
  DM_DBG3(("dmUpStreamDiscoverExpanderPhySkip: start\n"));
  
  oneDeviceData = oneExpander->dmDevice;
  DM_DBG3(("dmUpStreamDiscoverExpanderPhySkip: sasAddressHi 0x%08x\n", oneDeviceData->SASAddressID.sasAddressHi));
  DM_DBG3(("dmUpStreamDiscoverExpanderPhySkip: sasAddressLo 0x%08x\n", oneDeviceData->SASAddressID.sasAddressLo));
  
  oneExpander->discoveringPhyId++;
  if (onePortContext->discovery.status == DISCOVERY_UP_STREAM)
  {
    if ( oneExpander->discoveringPhyId < oneDeviceData->numOfPhys )
    {
      DM_DBG3(("dmUpStreamDiscoverExpanderPhySkip: More Phys to discover\n"));
      /* continue discovery for the next phy */  
      dmDiscoverSend(dmRoot, oneDeviceData);
    }
    else
    {
      DM_DBG3(("dmUpStreamDiscoverExpanderPhySkip: No More Phys\n"));

      /* for MCN */
      dmUpdateAllAdjacent(dmRoot, onePortContext, oneDeviceData);  
      /* remove the expander from the discovering list */
      dmDiscoveringExpanderRemove(dmRoot, onePortContext, oneExpander);
      /* continue upstream discovering */  
      dmUpStreamDiscovering(dmRoot, onePortContext, oneDeviceData);
    }
  }
  else
  {
    DM_DBG3(("dmUpStreamDiscoverExpanderPhySkip: onePortContext->discovery.status not in DISCOVERY_UP_STREAM; status %d\n", onePortContext->discovery.status));  
   
  }
   
  DM_DBG3(("dmUpStreamDiscoverExpanderPhySkip: end return phyID#%d\n", oneExpander->discoveringPhyId - 1));
  
  return;
}	   				


osGLOBAL void
dmUpStreamDiscover2ExpanderPhySkip(
                                   dmRoot_t              *dmRoot,
                                   dmIntPortContext_t    *onePortContext,
                                   dmExpander_t          *oneExpander
                                   )
{
  dmDeviceData_t          *oneDeviceData;
  
  DM_DBG2(("dmUpStreamDiscover2ExpanderPhySkip: start\n"));
  oneDeviceData = oneExpander->dmDevice;
  
  oneExpander->discoveringPhyId++;
  if (onePortContext->discovery.status == DISCOVERY_UP_STREAM)
  {
    if ( oneExpander->discoveringPhyId < oneDeviceData->numOfPhys )
    {
      DM_DBG2(("dmUpStreamDiscover2ExpanderPhySkip: DISCOVERY_UP_STREAM find more ...\n"));
      /* continue discovery for the next phy */  
      dmDiscoverSend(dmRoot, oneDeviceData);
    }
    else
    {
      DM_DBG2(("dmUpStreamDiscover2ExpanderPhySkip: DISCOVERY_UP_STREAM last phy continue upstream..\n"));

      /* for MCN */
      dmUpdateAllAdjacent(dmRoot, onePortContext, oneDeviceData);  
      /* remove the expander from the discovering list */
      dmDiscoveringExpanderRemove(dmRoot, onePortContext, oneExpander);
      /* continue upstream discovering */  
      dmUpStreamDiscovering(dmRoot, onePortContext, oneDeviceData);
    }
  }
  else
  {
    DM_DBG2(("dmUpStreamDiscover2ExpanderPhySkip: onePortContext->discovery.status not in DISCOVERY_UP_STREAM; status %d\n", onePortContext->discovery.status));     
  }
   
  DM_DBG2(("dmUpStreamDiscover2ExpanderPhySkip: end return phyID#%d\n", oneExpander->discoveringPhyId - 1));
  

  return;
}			     

osGLOBAL void
dmDownStreamDiscoverExpanderPhySkip(
                                     dmRoot_t              *dmRoot,
                                     dmIntPortContext_t    *onePortContext,
                                     dmExpander_t          *oneExpander
                                     )
{
  dmDeviceData_t          *oneDeviceData;
  DM_DBG3(("dmDownStreamDiscoverExpanderPhySkip: start\n"));
  
  oneDeviceData = oneExpander->dmDevice;
  DM_DBG3(("dmDownStreamDiscoverExpanderPhySkip: sasAddressHi 0x%08x\n", oneDeviceData->SASAddressID.sasAddressHi));
  DM_DBG3(("dmDownStreamDiscoverExpanderPhySkip: sasAddressLo 0x%08x\n", oneDeviceData->SASAddressID.sasAddressLo));

  /* Increment the discovering phy id */
  oneExpander->discoveringPhyId ++;
  
  /* If the discovery status is DISCOVERY_DOWN_STREAM */
  if ( onePortContext->discovery.status == DISCOVERY_DOWN_STREAM )
  {
    /* If not the last phy */  
    if ( oneExpander->discoveringPhyId < oneDeviceData->numOfPhys )
    {
      DM_DBG3(("dmDownStreamDiscoverExpanderPhySkip: More Phys to discover\n"));
      /* continue discovery for the next phy */
      dmDiscoverSend(dmRoot, oneDeviceData);
    }
    /* If the last phy */
    else
    {
      DM_DBG3(("dmDownStreamDiscoverExpanderPhySkip: No More Phys\n"));

      /* for MCN */
      dmUpdateAllAdjacent(dmRoot, onePortContext, oneDeviceData);  
      /* remove the expander from the discovering list */
      dmDiscoveringExpanderRemove(dmRoot, onePortContext, oneExpander);
      /* continue downstream discovering */
      dmDownStreamDiscovering(dmRoot, onePortContext, oneDeviceData);
    }  
  }
  else
  {
    DM_DBG3(("dmDownStreamDiscoverExpanderPhySkip: onePortContext->discovery.status not in DISCOVERY_DOWN_STREAM; status %d\n", onePortContext->discovery.status));  
  }  
  DM_DBG3(("dmDownStreamDiscoverExpanderPhySkip: end return phyID#%d\n", oneExpander->discoveringPhyId - 1));
  
  
  return;
}	   				

osGLOBAL void
dmDownStreamDiscover2ExpanderPhySkip(
                                     dmRoot_t              *dmRoot,
                                     dmIntPortContext_t    *onePortContext,
                                     dmExpander_t          *oneExpander
                                     )
{
  dmDeviceData_t          *oneDeviceData;
  
  DM_DBG2(("dmDownStreamDiscover2ExpanderPhySkip: start\n"));
  
  oneDeviceData = oneExpander->dmDevice;
  /* Increment the discovering phy id */
  oneExpander->discoveringPhyId ++;
  
  /* If the discovery status is DISCOVERY_DOWN_STREAM */
  if ( onePortContext->discovery.status == DISCOVERY_DOWN_STREAM )
  {
    /* If not the last phy */  
    if ( oneExpander->discoveringPhyId < oneDeviceData->numOfPhys )
    {
      DM_DBG2(("dmDownStreamDiscover2ExpanderPhySkip: More Phys to discover\n"));
      /* continue discovery for the next phy */
      dmDiscoverSend(dmRoot, oneDeviceData);
    }
    /* If the last phy */
    else
    {
      DM_DBG2(("dmDownStreamDiscover2ExpanderPhySkip: No More Phys\n"));

      /* for MCN */
      dmUpdateAllAdjacent(dmRoot, onePortContext, oneDeviceData);  
      /* remove the expander from the discovering list */
      dmDiscoveringExpanderRemove(dmRoot, onePortContext, oneExpander);
      /* continue downstream discovering */
      dmDownStreamDiscovering(dmRoot, onePortContext, oneDeviceData);
    }  
  }
  else
  {
    DM_DBG2(("dmDownStreamDiscover2ExpanderPhySkip: onePortContext->discovery.status not in DISCOVERY_DOWN_STREAM; status %d\n", onePortContext->discovery.status));  
  }  
  DM_DBG2(("dmDownStreamDiscover2ExpanderPhySkip: end return phyID#%d\n", oneExpander->discoveringPhyId - 1));
  return;
}			     

osGLOBAL void
dmExpanderUpStreamPhyAdd(
                         dmRoot_t              *dmRoot,
                         dmExpander_t          *oneExpander,
                         bit8                  phyId
                         )
{
  bit32   i;
  bit32   hasSet = agFALSE;

  DM_DBG3(("dmExpanderUpStreamPhyAdd: start, phyid %d\n", phyId));
  DM_DBG3(("dmExpanderUpStreamPhyAdd: exp addrHi 0x%08x\n", oneExpander->dmDevice->SASAddressID.sasAddressHi));
  DM_DBG3(("dmExpanderUpStreamPhyAdd: exp addrLo 0x%08x\n", oneExpander->dmDevice->SASAddressID.sasAddressLo));
  DM_DBG3(("dmExpanderUpStreamPhyAdd: phyid %d  numOfUpStreamPhys %d\n", phyId, oneExpander->numOfUpStreamPhys));

  for ( i = 0; i < oneExpander->numOfUpStreamPhys; i ++ )
  {
    if ( oneExpander->upStreamPhys[i] == phyId )
    {
      hasSet = agTRUE;
      break;
    }
  }
  
  if ( hasSet == agFALSE )
  {
    oneExpander->upStreamPhys[oneExpander->numOfUpStreamPhys ++] = phyId;    
  }

  DM_DBG3(("dmExpanderUpStreamPhyAdd: AFTER phyid %d  numOfUpStreamPhys %d\n", phyId, oneExpander->numOfUpStreamPhys));

  /* for debugging */
  for ( i = 0; i < oneExpander->numOfUpStreamPhys; i ++ )
  {
    DM_DBG3(("dmExpanderUpStreamPhyAdd: index %d upstream[index] %d\n", i, oneExpander->upStreamPhys[i]));
  }
  return;
}	   				

osGLOBAL void
dmExpanderDownStreamPhyAdd(
                           dmRoot_t              *dmRoot,
                           dmExpander_t          *oneExpander,
                           bit8                  phyId
                          )
{
  bit32   i;
  bit32   hasSet = agFALSE;

  DM_DBG3(("dmExpanderDownStreamPhyAdd: start, phyid %d\n", phyId));
  DM_DBG3(("dmExpanderDownStreamPhyAdd: exp addrHi 0x%08x\n", oneExpander->dmDevice->SASAddressID.sasAddressHi));
  DM_DBG3(("dmExpanderDownStreamPhyAdd: exp addrLo 0x%08x\n", oneExpander->dmDevice->SASAddressID.sasAddressLo));
  DM_DBG3(("dmExpanderDownStreamPhyAdd: phyid %d  numOfDownStreamPhys %d\n", phyId, oneExpander->numOfDownStreamPhys));

  for ( i = 0; i < oneExpander->numOfDownStreamPhys; i ++ )
  {
    if ( oneExpander->downStreamPhys[i] == phyId )
    {
      hasSet = agTRUE;
      break;
    }
  }
  
  if ( hasSet == agFALSE )
  {
    oneExpander->downStreamPhys[oneExpander->numOfDownStreamPhys ++] = phyId;    
  }

  DM_DBG3(("dmExpanderDownStreamPhyAdd: AFTER phyid %d  numOfDownStreamPhys %d\n", phyId, oneExpander->numOfDownStreamPhys));

  /* for debugging */
  for ( i = 0; i < oneExpander->numOfDownStreamPhys; i ++ )
  {
     DM_DBG3(("dmExpanderDownStreamPhyAdd: index %d downstream[index] %d\n", i, oneExpander->downStreamPhys[i]));
  }
  return;
}	   				

osGLOBAL void
dmDiscoveryReportMCN(
                    dmRoot_t                 *dmRoot,
                    dmIntPortContext_t       *onePortContext
                   )
{
  dmIntRoot_t       *dmIntRoot    = (dmIntRoot_t *)dmRoot->dmData;
  dmIntContext_t    *dmAllShared = (dmIntContext_t *)&dmIntRoot->dmAllShared;
  dmDeviceData_t    *oneDeviceData = agNULL;
  dmList_t          *DeviceListList;
  bit16             extension = 0;
  dmDeviceData_t    *oneAttachedExpDeviceData = agNULL;
    
  DM_DBG2(("dmDiscoveryReportMCN: start\n"));

/*
  if full disocvery, report all devices using MCN
  if incremental discovery, 
  1. compare MCN and PrevMCN
  2. report the changed ones; report MCN
  3. set PrevMCN to MCN
     PrevMCN = MCN
*/

  DeviceListList = dmAllShared->MainDeviceList.flink;
  while (DeviceListList != &(dmAllShared->MainDeviceList))
  {
    oneDeviceData = DMLIST_OBJECT_BASE(dmDeviceData_t, MainLink, DeviceListList);
    if ( oneDeviceData == agNULL)
    {
      DM_DBG1(("dmDiscoveryReportMCN: oneDeviceData is NULL!!!\n"));
      return;
    }        
    DM_DBG3(("dmDiscoveryReportMCN: loop did %d\n", oneDeviceData->id));
    if (oneDeviceData->dmPortContext == onePortContext)
    {
      DM_DBG2(("dmDiscoveryReportMCN: oneDeviceData sasAddressHi 0x%08x sasAddressLo 0x%08x\n", 
      oneDeviceData->SASAddressID.sasAddressHi, oneDeviceData->SASAddressID.sasAddressLo));         
      DM_DBG2(("dmDiscoveryReportMCN: MCN 0x%08x PrevMCN 0x%08x\n", oneDeviceData->MCN, oneDeviceData->PrevMCN));
      
      if (onePortContext->discovery.type == DM_DISCOVERY_OPTION_FULL_START)
      {
        DM_DBG2(("dmDiscoveryReportMCN: FULL_START\n"));
      }
      else
      {
        DM_DBG2(("dmDiscoveryReportMCN: INCREMENTAL_START\n"));
      }
      /*
        if MCN is 0, the device is removed 
      */
      if (oneDeviceData->MCN != oneDeviceData->PrevMCN && oneDeviceData->MCN != 0)
      {
        DM_DBG2(("dmDiscoveryReportMCN: reporting \n"));
        extension = oneDeviceData->dmDeviceInfo.ext;
        /* zero out MCN in extension */
        extension = extension & 0x7FF;
        /* sets MCN in extension */	
        extension = extension | (oneDeviceData->MCN << 11);
        DEVINFO_PUT_EXT(&(oneDeviceData->dmDeviceInfo), extension);
        DM_DBG5(("dmDiscoveryReportMCN: MCN 0x%08x PrevMCN 0x%08x\n", DEVINFO_GET_EXT_MCN(&(oneDeviceData->dmDeviceInfo)), oneDeviceData->PrevMCN));
        if (oneDeviceData->ExpDevice != agNULL)
        {
          DM_DBG2(("dmDiscoveryReportMCN: attached expander case\n"));
          oneAttachedExpDeviceData = oneDeviceData->ExpDevice;
          tddmReportDevice(dmRoot, onePortContext->dmPortContext, &oneDeviceData->dmDeviceInfo, &oneAttachedExpDeviceData->dmDeviceInfo, dmDeviceMCNChange);
        }
	else
	{
          DM_DBG2(("dmDiscoveryReportMCN: No attached expander case\n"));
          tddmReportDevice(dmRoot, onePortContext->dmPortContext, &oneDeviceData->dmDeviceInfo, agNULL, dmDeviceMCNChange);
	}        
        oneDeviceData->PrevMCN = oneDeviceData->MCN;          	
      }
      else
      {
        DM_DBG2(("dmDiscoveryReportMCN: No change; no reporting \n"));
	if (oneDeviceData->MCN == 0)
	{
          oneDeviceData->PrevMCN = oneDeviceData->MCN;          	
	}
      }
      
    }
    DeviceListList = DeviceListList->flink;  
  }
  
  return;
}		   

osGLOBAL void
dmDiscoveryDumpMCN(
                    dmRoot_t                 *dmRoot,
                    dmIntPortContext_t       *onePortContext
                   )
{
  dmIntRoot_t       *dmIntRoot    = (dmIntRoot_t *)dmRoot->dmData;
  dmIntContext_t    *dmAllShared = (dmIntContext_t *)&dmIntRoot->dmAllShared;
  dmDeviceData_t    *oneDeviceData = agNULL;
  dmList_t          *DeviceListList;
  
  DM_DBG3(("dmDiscoveryDumpMCN: start\n"));
  
  DeviceListList = dmAllShared->MainDeviceList.flink;
  while (DeviceListList != &(dmAllShared->MainDeviceList))
  {
    oneDeviceData = DMLIST_OBJECT_BASE(dmDeviceData_t, MainLink, DeviceListList);
    if (oneDeviceData == agNULL)
    {
      DM_DBG1(("dmDiscoveryDumpMCN: oneDeviceData is NULL!!!\n"));
      return;   
    }
    DM_DBG3(("dmDiscoveryDumpMCN: loop did %d\n", oneDeviceData->id));
    if (oneDeviceData->dmPortContext == onePortContext)
    {
      DM_DBG3(("dmDiscoveryDumpMCN: oneDeviceData sasAddressHi 0x%08x sasAddressLo 0x%08x\n", 
      oneDeviceData->SASAddressID.sasAddressHi, oneDeviceData->SASAddressID.sasAddressLo));         
      DM_DBG3(("dmDiscoveryDumpMCN: MCN 0x%08x PrevMCN 0x%08x\n", oneDeviceData->MCN, oneDeviceData->PrevMCN));
    }
    DeviceListList = DeviceListList->flink;  
  }
  
  return;
}		   

osGLOBAL void
dmDiscoveryResetMCN(
                    dmRoot_t                 *dmRoot,
                    dmIntPortContext_t       *onePortContext
                   )
{
  dmIntRoot_t       *dmIntRoot    = (dmIntRoot_t *)dmRoot->dmData;
  dmIntContext_t    *dmAllShared = (dmIntContext_t *)&dmIntRoot->dmAllShared;
  dmDeviceData_t    *oneDeviceData = agNULL;
  dmList_t          *DeviceListList;
  
  DM_DBG2(("dmDiscoveryResetMCN: start\n"));
  
  /* reinitialize the device data belonging to this portcontext */
  DeviceListList = dmAllShared->MainDeviceList.flink;
  while (DeviceListList != &(dmAllShared->MainDeviceList))
  {
    oneDeviceData = DMLIST_OBJECT_BASE(dmDeviceData_t, MainLink, DeviceListList);
    if (oneDeviceData == agNULL)
    {
      DM_DBG1(("dmDiscoveryResetMCN: oneDeviceData is NULL!!!\n"));
      return;   
    }
    DM_DBG3(("dmDiscoveryResetMCN: loop did %d\n", oneDeviceData->id));
    if (oneDeviceData->dmPortContext == onePortContext)
    {
      if (oneDeviceData->ExpDevice != agNULL)
      {
        DM_DBG2(("dmDiscoveryResetMCN: resetting oneDeviceData->ExpDevice\n"));
        oneDeviceData->ExpDevice = agNULL;
      }	
      DM_DBG3(("dmDiscoveryResetMCN: resetting MCN and MCNdone\n"));
      oneDeviceData->MCN = 0;

      oneDeviceData->MCNDone = agFALSE;
      DM_DBG2(("dmDiscoveryResetMCN: oneDeviceData sasAddressHi 0x%08x sasAddressLo 0x%08x\n", 
      oneDeviceData->SASAddressID.sasAddressHi, oneDeviceData->SASAddressID.sasAddressLo));         
    }
    DeviceListList = DeviceListList->flink;  
  }
  
  return;
}		   


/*
do min(oneDeviceData, found-one) in all upstream and downstream
find ajcanent expanders and mark it done; sees only ajcacent targets
*/
osGLOBAL void
dmUpdateAllAdjacent(
                    dmRoot_t            *dmRoot,
                    dmIntPortContext_t  *onePortContext,
                    dmDeviceData_t      *oneDeviceData /* current one */
                   )
{
  dmIntRoot_t       *dmIntRoot    = (dmIntRoot_t *)dmRoot->dmData;
  dmIntContext_t    *dmAllShared = (dmIntContext_t *)&dmIntRoot->dmAllShared;
  dmDeviceData_t    *tmponeDeviceData = agNULL;
  dmList_t          *DeviceListList;
    
  DM_DBG2(("dmUpdateAllAdjacent: start\n"));  
  if (oneDeviceData == agNULL)
  {
    DM_DBG1(("dmUpdateAllAdjacent: oneDeviceData is NULL!!!\n"));
    return;      
  }    
  
  oneDeviceData->MCNDone = agTRUE;
  
  DM_DBG2(("dmUpdateAllAdjacent: oneDeviceData sasAddressHi 0x%08x sasAddressLo 0x%08x\n", 
  oneDeviceData->SASAddressID.sasAddressHi, oneDeviceData->SASAddressID.sasAddressLo));         

 
  DeviceListList = dmAllShared->MainDeviceList.flink;
  while (DeviceListList != &(dmAllShared->MainDeviceList))
  {
    tmponeDeviceData = DMLIST_OBJECT_BASE(dmDeviceData_t, MainLink, DeviceListList);
    if ( tmponeDeviceData == agNULL)
    {
      DM_DBG1(("dmUpdateAllAdjacent: tmponeDeviceData is NULL!!!\n"));
      return;
    }
    DM_DBG3(("dmUpdateAllAdjacent: loop did %d\n", tmponeDeviceData->id));
    if (tmponeDeviceData->dmPortContext == onePortContext && tmponeDeviceData->ExpDevice == oneDeviceData)
    {
      DM_DBG2(("dmUpdateAllAdjacent: setting MCN DONE\n"));
      DM_DBG2(("dmUpdateAllAdjacent: tmponeDeviceData sasAddressHi 0x%08x sasAddressLo 0x%08x\n", 
      tmponeDeviceData->SASAddressID.sasAddressHi, tmponeDeviceData->SASAddressID.sasAddressLo));         
      tmponeDeviceData->MCNDone = agTRUE;
      if (oneDeviceData->directlyAttached == agFALSE)
      {
        DM_DBG2(("dmUpdateAllAdjacent: tmponeDeviceData MCN 0x%x\n", tmponeDeviceData->MCN));
        DM_DBG2(("dmUpdateAllAdjacent: oneDeviceData MCN 0x%x\n", oneDeviceData->MCN));
        tmponeDeviceData->MCN = MIN(oneDeviceData->MCN, tmponeDeviceData->MCN);
      }
    
    }
    DeviceListList = DeviceListList->flink;  
  }
  
  return;

}		   

osGLOBAL void
dmUpdateMCN(
            dmRoot_t            *dmRoot,
            dmIntPortContext_t  *onePortContext,
            dmDeviceData_t      *AdjacentDeviceData, /* adjacent expander */ 		    
            dmDeviceData_t      *oneDeviceData /* current one */
           )
{
  
  DM_DBG2(("dmUpdateMCN: start\n"));  
  
  if (AdjacentDeviceData == agNULL)
  {
    DM_DBG1(("dmUpdateMCN: AdjacentDeviceData is NULL!!!\n"));
    return;      
  }    
  
  if (oneDeviceData == agNULL)
  {
    DM_DBG1(("dmUpdateMCN: oneDeviceData is NULL!!!\n"));
    return;      
  }    
  
  DM_DBG2(("dmUpdateMCN: Current sasAddressHi 0x%08x sasAddressLo 0x%08x\n", 
  oneDeviceData->SASAddressID.sasAddressHi, oneDeviceData->SASAddressID.sasAddressLo));         
  
  DM_DBG2(("dmUpdateMCN: AdjacentDeviceData one sasAddressHi 0x%08x sasAddressLo 0x%08x\n", 
  AdjacentDeviceData->SASAddressID.sasAddressHi, AdjacentDeviceData->SASAddressID.sasAddressLo));         
  
  if (onePortContext->discovery.status == DISCOVERY_UP_STREAM)
  {   
    DM_DBG2(("dmUpdateMCN: DISCOVERY_UP_STREAM\n"));  
  }  
  
  if (onePortContext->discovery.status == DISCOVERY_DOWN_STREAM)
  {   
    DM_DBG2(("dmUpdateMCN: DISCOVERY_DOWN_STREAM\n"));  
  }  
  
  
  /* MCN */

  /* directly attached one does not have MCN 
     update only adjacent device data
  */
  
  if (oneDeviceData->directlyAttached == agTRUE && AdjacentDeviceData->MCNDone == agFALSE)
  {
    AdjacentDeviceData->MCN++;
    DM_DBG2(("dmUpdateMCN: case 1 oneDeviceData MCN 0x%x\n", oneDeviceData->MCN));
    DM_DBG2(("dmUpdateMCN: case 1 AdjacentDeviceData MCN 0x%x\n", AdjacentDeviceData->MCN));
  }
  else if (AdjacentDeviceData->MCNDone == agFALSE)
  {
    AdjacentDeviceData->MCN++;
    AdjacentDeviceData->MCN = MIN(oneDeviceData->MCN, AdjacentDeviceData->MCN);      
    DM_DBG2(("dmUpdateMCN: case 2 oneDeviceData MCN 0x%x\n", oneDeviceData->MCN));
    DM_DBG2(("dmUpdateMCN: case 2 AdjacentDeviceData MCN 0x%x\n", AdjacentDeviceData->MCN));
  }
  
 	
  return;
}
/* go through expander list and device list array ??? */
osGLOBAL dmDeviceData_t *
dmPortSASDeviceFind(
                    dmRoot_t            *dmRoot,
                    dmIntPortContext_t  *onePortContext,
                    bit32               sasAddrLo,
                    bit32               sasAddrHi,
                    dmDeviceData_t      *CurrentDeviceData /* current expander */ 		    
                    )
{
  dmIntRoot_t               *dmIntRoot    = (dmIntRoot_t *)dmRoot->dmData;
  dmIntContext_t            *dmAllShared = (dmIntContext_t *)&dmIntRoot->dmAllShared;
  dmDeviceData_t            *oneDeviceData, *RetDeviceData=agNULL;
  dmList_t                  *DeviceListList;
      
  DM_DBG3(("dmPortSASDeviceFind: start\n"));  
  DM_DBG3(("dmPortSASDeviceFind: sasAddressHi 0x%08x sasAddressLo 0x%08x\n", sasAddrHi, sasAddrLo));         
 
  DM_ASSERT((agNULL != dmRoot), "");
  DM_ASSERT((agNULL != onePortContext), "");

  tddmSingleThreadedEnter(dmRoot, DM_DEVICE_LOCK);
  
  /* find a device's existence */
  DeviceListList = dmAllShared->MainDeviceList.flink;
  if (onePortContext->discovery.type == DM_DISCOVERY_OPTION_FULL_START)
  {
    DM_DBG3(("dmPortSASDeviceFind: Full discovery\n"));
    while (DeviceListList != &(dmAllShared->MainDeviceList))
    {
      oneDeviceData = DMLIST_OBJECT_BASE(dmDeviceData_t, MainLink, DeviceListList);
      if (oneDeviceData == agNULL)
      {
        DM_DBG1(("dmPortSASDeviceFind: oneDeviceData is NULL!!!\n"));  
        return agNULL;
      }      
      if ((oneDeviceData->SASAddressID.sasAddressHi == sasAddrHi) &&
          (oneDeviceData->SASAddressID.sasAddressLo == sasAddrLo) &&
          (oneDeviceData->valid == agTRUE) &&
          (oneDeviceData->dmPortContext == onePortContext)
        )
      {
        DM_DBG3(("dmPortSASDeviceFind: Found pid %d did %d\n", onePortContext->id, oneDeviceData->id));
        DM_DBG3(("dmPortSASDeviceFind: sasAddressHi 0x%08x\n", oneDeviceData->SASAddressID.sasAddressHi));         
        DM_DBG3(("dmPortSASDeviceFind: sasAddressLo 0x%08x\n", oneDeviceData->SASAddressID.sasAddressLo));
        RetDeviceData = oneDeviceData;
        dmUpdateMCN(dmRoot, onePortContext, RetDeviceData, CurrentDeviceData);
       	break;
      }
      DeviceListList = DeviceListList->flink;
    }
  }
  else
  {
    /* incremental discovery */
    DM_DBG3(("dmPortSASDeviceFind: Incremental discovery\n"));
    while (DeviceListList != &(dmAllShared->MainDeviceList))
    {
      oneDeviceData = DMLIST_OBJECT_BASE(dmDeviceData_t, MainLink, DeviceListList);
      if (oneDeviceData == agNULL)
      {
        DM_DBG1(("dmPortSASDeviceFind: oneDeviceData is NULL!!!\n"));  
        return agNULL;
      }      
      if ((oneDeviceData->SASAddressID.sasAddressHi == sasAddrHi) &&
          (oneDeviceData->SASAddressID.sasAddressLo == sasAddrLo) &&
          (oneDeviceData->valid2 == agTRUE) &&
          (oneDeviceData->dmPortContext == onePortContext)
          )
      {
        DM_DBG3(("dmPortSASDeviceFind: Found pid %d did %d\n", onePortContext->id, oneDeviceData->id));
        DM_DBG3(("dmPortSASDeviceFind: sasAddressHi 0x%08x\n", oneDeviceData->SASAddressID.sasAddressHi));         
        DM_DBG3(("dmPortSASDeviceFind: sasAddressLo 0x%08x\n", oneDeviceData->SASAddressID.sasAddressLo));
        RetDeviceData = oneDeviceData;
        dmUpdateMCN(dmRoot, onePortContext, RetDeviceData, CurrentDeviceData);
        break;
      }
      DeviceListList = DeviceListList->flink;
    }
  }
  
  tddmSingleThreadedLeave(dmRoot, DM_DEVICE_LOCK);

  return RetDeviceData;
}		      

bit32
dmNewEXPorNot(
              dmRoot_t              *dmRoot,
              dmIntPortContext_t    *onePortContext,
              dmSASSubID_t          *dmSASSubID
             )
{
//  dmIntRoot_t       *dmIntRoot    = (dmIntRoot_t *)dmRoot->dmData;
//  dmIntContext_t    *dmAllShared = (dmIntContext_t *)&dmIntRoot->dmAllShared;
  dmExpander_t      *oneExpander = agNULL;
  dmList_t          *ExpanderList;
  bit32             ret = agTRUE;
  dmDeviceData_t    *oneDeviceData = agNULL;
  
  DM_DBG3(("dmNewEXPorNot: start\n"));
  
  /* find a device's existence */
  ExpanderList = onePortContext->discovery.discoveringExpanderList.flink;
  while (ExpanderList != &(onePortContext->discovery.discoveringExpanderList))
  {
    oneExpander = DMLIST_OBJECT_BASE(dmExpander_t, linkNode, ExpanderList);
    if ( oneExpander == agNULL)
    {
      DM_DBG1(("dmNewEXPorNot: oneExpander is NULL!!!\n"));    
      return agFALSE;
    }    
    oneDeviceData = oneExpander->dmDevice;
    if ((oneDeviceData->SASAddressID.sasAddressHi == dmSASSubID->sasAddressHi) &&
        (oneDeviceData->SASAddressID.sasAddressLo == dmSASSubID->sasAddressLo) &&
        (oneDeviceData->dmPortContext == onePortContext)
        )
    {
      DM_DBG3(("dmNewEXPorNot: Found pid %d did %d\n", onePortContext->id, oneDeviceData->id));
      ret = agFALSE;
      break;
    }
    ExpanderList = ExpanderList->flink;
  }
    
  return ret;
}


bit32
dmNewSASorNot(
              dmRoot_t              *dmRoot,
              dmIntPortContext_t    *onePortContext,
              dmSASSubID_t          *dmSASSubID
             )
{
  dmIntRoot_t       *dmIntRoot    = (dmIntRoot_t *)dmRoot->dmData;
  dmIntContext_t    *dmAllShared = (dmIntContext_t *)&dmIntRoot->dmAllShared;
  dmDeviceData_t    *oneDeviceData = agNULL;
  dmList_t          *DeviceListList;
  bit32             ret = agTRUE;
  
  DM_DBG3(("dmNewSASorNot: start\n"));
  
  /* find a device's existence */
  DeviceListList = dmAllShared->MainDeviceList.flink;
  while (DeviceListList != &(dmAllShared->MainDeviceList))
  {
    oneDeviceData = DMLIST_OBJECT_BASE(dmDeviceData_t, MainLink, DeviceListList);
    if (oneDeviceData == agNULL)
    {
      DM_DBG1(("dmNewSASorNot: oneDeviceData is NULL!!!\n"));
      return agFALSE;
    }    
    if ((oneDeviceData->SASAddressID.sasAddressHi == dmSASSubID->sasAddressHi) &&
        (oneDeviceData->SASAddressID.sasAddressLo == dmSASSubID->sasAddressLo) &&
        (oneDeviceData->dmPortContext == onePortContext) &&
        (oneDeviceData->registered == agTRUE)	
       )
    {
      DM_DBG3(("dmNewSASorNot: Found pid %d did %d\n", onePortContext->id, oneDeviceData->id));
      ret = agFALSE;
      break;
    }
    DeviceListList = DeviceListList->flink;
  }
    
  return ret;
}
/* 
call
osGLOBAL bit32 
tddmReportDevice(
                 dmRoot_t 		*dmRoot,
                 dmPortContext_t	*dmPortContext,
                 dmDeviceInfo_t		*dmDeviceInfo
                 )
if not reported, report Device to TDM
*/
osGLOBAL dmDeviceData_t *
dmPortSASDeviceAdd(
                   dmRoot_t            *dmRoot,
                   dmIntPortContext_t  *onePortContext,
                   agsaSASIdentify_t   sasIdentify,
                   bit32               sasInitiator,
                   bit8                connectionRate,
                   bit32               itNexusTimeout,
                   bit32               firstBurstSize,
                   bit32               deviceType,
                   dmDeviceData_t      *oneExpDeviceData,
                   dmExpander_t        *dmExpander,
                   bit8                phyID
                  )
{
  dmDeviceData_t    *oneDeviceData = agNULL;
  bit8              dev_s_rate = 0;
  bit8              sasorsata = 1;
  dmSASSubID_t      dmSASSubID;
  bit8              ExpanderConnectionRate = connectionRate;
  dmDeviceData_t    *oneAttachedExpDeviceData = agNULL;
  bit16             extension = 0;
  bit32             current_link_rate = 0;
  
  DM_DBG3(("dmPortSASDeviceAdd: start\n"));
  DM_DBG3(("dmPortSASDeviceAdd: connectionRate %d\n", connectionRate));
  
  dmSASSubID.sasAddressHi = SA_IDFRM_GET_SAS_ADDRESSHI(&sasIdentify);
  dmSASSubID.sasAddressLo = SA_IDFRM_GET_SAS_ADDRESSLO(&sasIdentify);
  dmSASSubID.initiator_ssp_stp_smp = sasIdentify.initiator_ssp_stp_smp;
  dmSASSubID.target_ssp_stp_smp = sasIdentify.target_ssp_stp_smp;
  
  if (oneExpDeviceData != agNULL)
  {
    ExpanderConnectionRate =   DEVINFO_GET_LINKRATE(&oneExpDeviceData->agDeviceInfo);
    DM_DBG3(("dmPortSASDeviceAdd: ExpanderConnectionRate 0x%x\n", ExpanderConnectionRate));
  }
  if (oneExpDeviceData != agNULL)
  {
    if (oneExpDeviceData->SASAddressID.sasAddressHi == 0x0 &&
        oneExpDeviceData->SASAddressID.sasAddressLo == 0x0)
    {
      DM_DBG1(("dmPortSASDeviceAdd: 1st Wrong expander!!!\n"));    
    }    	    
  }
  /* old device and already reported to TDM */
  if ( agFALSE == dmNewSASorNot(
                                 dmRoot,
                                 onePortContext,
                                 &dmSASSubID
                                )
       ) /* old device */
  {
    DM_DBG3(("dmPortSASDeviceAdd: OLD qqqq initiator_ssp_stp_smp %d target_ssp_stp_smp %d\n", dmSASSubID.initiator_ssp_stp_smp, dmSASSubID.target_ssp_stp_smp));
    /* allocate a new device and set the valid bit */ 
    oneDeviceData = dmAddSASToSharedcontext(
                                               dmRoot,
                                               onePortContext,
                                               &dmSASSubID,
                                               oneExpDeviceData,
                                               phyID
                                               );
    if (oneDeviceData == agNULL)
    {
      DM_DBG1(("dmPortSASDeviceAdd: no more device, oneDeviceData is null!!!\n"));
    }
    /* If a device is allocated */
    if ( oneDeviceData != agNULL )
    {


      if (onePortContext->discovery.status == DISCOVERY_UP_STREAM)
      {
        DM_DBG3(("dmPortSASDeviceAdd: OLD, UP_STREAM\n"));
      }    
      if (onePortContext->discovery.status == DISCOVERY_DOWN_STREAM)
      {      
        DM_DBG3(("dmPortSASDeviceAdd: OLD, DOWN_STREAM\n"));
      }
      
      if (onePortContext->discovery.type == DM_DISCOVERY_OPTION_FULL_START)
      {
        DM_DBG3(("dmPortSASDeviceAdd: FULL_START\n"));  
        oneDeviceData->MCN++;
      }
      else
      {
        /* incremental */
        DM_DBG3(("dmPortSASDeviceAdd: INCREMENTAL_START\n"));  
        if (oneDeviceData->MCN == 0 && oneDeviceData->directlyAttached == agFALSE)
        {
          oneDeviceData->MCN++;	  
        }
      }      	
      
      DM_DBG3(("dmPortSASDeviceAdd: oneDeviceData MCN 0x%08x\n", oneDeviceData->MCN));
      DM_DBG3(("dmPortSASDeviceAdd: oneDeviceData sasAddressHi 0x%08x sasAddressLo 0x%08x\n", 
      oneDeviceData->SASAddressID.sasAddressHi, oneDeviceData->SASAddressID.sasAddressLo));         


      DM_DBG3(("dmPortSASDeviceAdd: sasAddressHi 0x%08x\n", SA_IDFRM_GET_SAS_ADDRESSHI(&sasIdentify)));
      DM_DBG3(("dmPortSASDeviceAdd: sasAddressLo 0x%08x\n", SA_IDFRM_GET_SAS_ADDRESSLO(&sasIdentify)));
      
//      oneDeviceData->sasIdentify = sasIdentify;
      dm_memcpy(&(oneDeviceData->sasIdentify), &sasIdentify, sizeof(agsaSASIdentify_t));
      
      DM_DBG3(("dmPortSASDeviceAdd: sasAddressHi 0x%08x\n", SA_IDFRM_GET_SAS_ADDRESSHI(&oneDeviceData->sasIdentify)));
      DM_DBG3(("dmPortSASDeviceAdd: sasAddressLo 0x%08x\n", SA_IDFRM_GET_SAS_ADDRESSLO(&oneDeviceData->sasIdentify)));
      
      /* parse sasIDframe to fill in agDeviceInfo */
      DEVINFO_PUT_SMPTO(&oneDeviceData->agDeviceInfo, DEFAULT_SMP_TIMEOUT);
      DEVINFO_PUT_ITNEXUSTO(&oneDeviceData->agDeviceInfo, (bit16)itNexusTimeout);
      DEVINFO_PUT_FBS(&oneDeviceData->agDeviceInfo, (bit16)firstBurstSize);
      DEVINFO_PUT_FLAG(&oneDeviceData->agDeviceInfo, 1);
      
      oneDeviceData->SASSpecDeviceType = SA_IDFRM_GET_DEVICETTYPE(&sasIdentify);
      
      /* adjusting connectionRate */
      oneAttachedExpDeviceData = oneDeviceData->ExpDevice;
      if (oneAttachedExpDeviceData != agNULL)
      {
        connectionRate = MIN(connectionRate, DEVINFO_GET_LINKRATE(&oneAttachedExpDeviceData->agDeviceInfo));
        DM_DBG3(("dmPortSASDeviceAdd: 1st connectionRate 0x%x  DEVINFO_GET_LINKRATE(&oneAttachedExpDeviceData->agDeviceInfo) 0x%x\n",
	       connectionRate, DEVINFO_GET_LINKRATE(&oneAttachedExpDeviceData->agDeviceInfo)));
      }
      else
      {
       DM_DBG3(("dmPortSASDeviceAdd: 1st oneAttachedExpDeviceData is NULL\n"));
      }
      
      /* Device Type, SAS or SATA, connection rate; bit7 --- bit0 */
      sasorsata = (bit8)deviceType;
      /* sTSDK spec device typ */
      dev_s_rate = dev_s_rate | (sasorsata << 4);
      dev_s_rate = dev_s_rate | MIN(connectionRate, ExpanderConnectionRate);
      /* detect link rate change */
      current_link_rate = DEVINFO_GET_LINKRATE(&oneDeviceData->agDeviceInfo);
      if (current_link_rate != (bit32)MIN(connectionRate, ExpanderConnectionRate))
      {
        DM_DBG1(("dmPortSASDeviceAdd: link rate changed current 0x%x new 0x%x\n", current_link_rate, MIN(connectionRate, ExpanderConnectionRate)));
        DEVINFO_PUT_DEV_S_RATE(&oneDeviceData->dmDeviceInfo, dev_s_rate);
        if (oneDeviceData->ExpDevice != agNULL)
        {
          oneAttachedExpDeviceData = oneDeviceData->ExpDevice;
          tddmReportDevice(dmRoot, onePortContext->dmPortContext, &oneDeviceData->dmDeviceInfo, &oneAttachedExpDeviceData->dmDeviceInfo, dmDeviceRateChange);
        }
        else
        {
          tddmReportDevice(dmRoot, onePortContext->dmPortContext, &oneDeviceData->dmDeviceInfo, agNULL, dmDeviceArrival);
        }	  
      }
      
      DEVINFO_PUT_DEV_S_RATE(&oneDeviceData->agDeviceInfo, dev_s_rate);
      
    
      DEVINFO_PUT_SAS_ADDRESSLO(
                                &oneDeviceData->agDeviceInfo,
                                SA_IDFRM_GET_SAS_ADDRESSLO(&oneDeviceData->sasIdentify)
                                );
      DEVINFO_PUT_SAS_ADDRESSHI(
                                &oneDeviceData->agDeviceInfo,
                                SA_IDFRM_GET_SAS_ADDRESSHI(&oneDeviceData->sasIdentify)
                                );
      oneDeviceData->agContext.osData = oneDeviceData;
      oneDeviceData->agContext.sdkData = agNULL;
   
      
    }	
    return oneDeviceData;		
  }  /* old device */
  
  
  /* new device */
	
  DM_DBG3(("dmPortSASDeviceAdd: NEW qqqq initiator_ssp_stp_smp %d target_ssp_stp_smp %d\n", dmSASSubID.initiator_ssp_stp_smp, dmSASSubID.target_ssp_stp_smp));
  
  /* allocate a new device and set the valid bit */ 
  oneDeviceData = dmAddSASToSharedcontext(
                                               dmRoot,
                                               onePortContext,
                                               &dmSASSubID,
                                               oneExpDeviceData,
                                               phyID
                                               );
  if (oneDeviceData == agNULL)
  {
    DM_DBG1(("dmPortSASDeviceAdd: no more device, oneDeviceData is null !!!\n"));
  }
  
   /* If a device is allocated */
  if ( oneDeviceData != agNULL )
  {

//    DM_DBG3(("dmPortSASDeviceAdd: sasAddressHi 0x%08x\n", SA_IDFRM_GET_SAS_ADDRESSHI(&sasIdentify)));
//    DM_DBG3(("dmPortSASDeviceAdd: sasAddressLo 0x%08x\n", SA_IDFRM_GET_SAS_ADDRESSLO(&sasIdentify)));
  
//    oneDeviceData->sasIdentify = sasIdentify;
    dm_memcpy(&(oneDeviceData->sasIdentify), &sasIdentify, sizeof(agsaSASIdentify_t));
    
    if (onePortContext->discovery.status == DISCOVERY_UP_STREAM)
    {
      DM_DBG3(("dmPortSASDeviceAdd: NEW, UP_STREAM\n"));
    }    
    if (onePortContext->discovery.status == DISCOVERY_DOWN_STREAM)
    {      
      DM_DBG3(("dmPortSASDeviceAdd: NEW, DOWN_STREAM\n"));
    }
        
    if (onePortContext->discovery.type == DM_DISCOVERY_OPTION_FULL_START)
    {
      DM_DBG3(("dmPortSASDeviceAdd: FULL_START\n"));  
      oneDeviceData->MCN++;
    }
    else
    {
      /* incremental */
      DM_DBG3(("dmPortSASDeviceAdd: INCREMENTAL_START\n"));  
      if (oneDeviceData->MCN == 0 && oneDeviceData->directlyAttached == agFALSE)
      {
        oneDeviceData->MCN++;	  
      }
    }      
    DM_DBG3(("dmPortSASDeviceAdd: oneDeviceData MCN 0x%08x\n", oneDeviceData->MCN));
    DM_DBG3(("dmPortSASDeviceAdd: oneDeviceData sasAddressHi 0x%08x sasAddressLo 0x%08x\n", 
    oneDeviceData->SASAddressID.sasAddressHi, oneDeviceData->SASAddressID.sasAddressLo));         
    
    DM_DBG3(("dmPortSASDeviceAdd: sasAddressHi 0x%08x\n", SA_IDFRM_GET_SAS_ADDRESSHI(&oneDeviceData->sasIdentify)));
    DM_DBG3(("dmPortSASDeviceAdd: sasAddressLo 0x%08x\n", SA_IDFRM_GET_SAS_ADDRESSLO(&oneDeviceData->sasIdentify)));

    /* parse sasIDframe to fill in agDeviceInfo */
    DEVINFO_PUT_SMPTO(&oneDeviceData->agDeviceInfo, DEFAULT_SMP_TIMEOUT);
    DEVINFO_PUT_ITNEXUSTO(&oneDeviceData->agDeviceInfo, (bit16)itNexusTimeout);
    DEVINFO_PUT_FBS(&oneDeviceData->agDeviceInfo, (bit16)firstBurstSize);
    DEVINFO_PUT_FLAG(&oneDeviceData->agDeviceInfo, 1);
    
    oneDeviceData->SASSpecDeviceType = SA_IDFRM_GET_DEVICETTYPE(&sasIdentify);
    
    /* adjusting connectionRate */
    oneAttachedExpDeviceData = oneDeviceData->ExpDevice;
    if (oneAttachedExpDeviceData != agNULL)
    {
      connectionRate = MIN(connectionRate, DEVINFO_GET_LINKRATE(&oneAttachedExpDeviceData->agDeviceInfo));
      DM_DBG3(("dmPortSASDeviceAdd: 2nd connectionRate 0x%x  DEVINFO_GET_LINKRATE(&oneAttachedExpDeviceData->agDeviceInfo) 0x%x\n",
                connectionRate, DEVINFO_GET_LINKRATE(&oneAttachedExpDeviceData->agDeviceInfo)));
    }
    else
    {
     DM_DBG3(("dmPortSASDeviceAdd: 2nd oneAttachedExpDeviceData is NULL\n"));
    }
    
    /* Device Type, SAS or SATA, connection rate; bit7 --- bit0 */
    sasorsata = (bit8)deviceType;
    dev_s_rate = dev_s_rate | (sasorsata << 4);
    dev_s_rate = dev_s_rate | MIN(connectionRate, ExpanderConnectionRate);
    DEVINFO_PUT_DEV_S_RATE(&oneDeviceData->agDeviceInfo, dev_s_rate);

    
    DEVINFO_PUT_SAS_ADDRESSLO(
                              &oneDeviceData->agDeviceInfo,
                              SA_IDFRM_GET_SAS_ADDRESSLO(&oneDeviceData->sasIdentify)
                              );
    DEVINFO_PUT_SAS_ADDRESSHI(
                              &oneDeviceData->agDeviceInfo,
                              SA_IDFRM_GET_SAS_ADDRESSHI(&oneDeviceData->sasIdentify)
                              );
    oneDeviceData->agContext.osData = oneDeviceData;
    oneDeviceData->agContext.sdkData = agNULL;
		
    DM_DBG3(("dmPortSASDeviceAdd: did %d\n", oneDeviceData->id));
  
    
    /* reporting to TDM; setting dmDeviceInfo */
    DEVINFO_PUT_SMPTO(&oneDeviceData->dmDeviceInfo, DEFAULT_SMP_TIMEOUT);
    DEVINFO_PUT_ITNEXUSTO(&oneDeviceData->dmDeviceInfo, (bit16)itNexusTimeout);
    DEVINFO_PUT_FBS(&oneDeviceData->dmDeviceInfo, (bit16)firstBurstSize);
    DEVINFO_PUT_FLAG(&oneDeviceData->dmDeviceInfo, 1);
    DEVINFO_PUT_INITIATOR_SSP_STP_SMP(&oneDeviceData->dmDeviceInfo, dmSASSubID.initiator_ssp_stp_smp);
    DEVINFO_PUT_TARGET_SSP_STP_SMP(&oneDeviceData->dmDeviceInfo, dmSASSubID.target_ssp_stp_smp);
    extension = phyID;
      
    /* setting 6th bit of dev_s_rate */
    if (oneDeviceData->SASSpecDeviceType == SAS_EDGE_EXPANDER_DEVICE ||
        oneDeviceData->SASSpecDeviceType == SAS_FANOUT_EXPANDER_DEVICE )
    {
      extension = (bit16)(extension | (1 << 8));
    }
    DEVINFO_PUT_EXT(&oneDeviceData->dmDeviceInfo, extension);
      
    DEVINFO_PUT_DEV_S_RATE(&oneDeviceData->dmDeviceInfo, dev_s_rate);
    
    DEVINFO_PUT_SAS_ADDRESSLO(
                              &oneDeviceData->dmDeviceInfo,
                              SA_IDFRM_GET_SAS_ADDRESSLO(&oneDeviceData->sasIdentify)
                              );
    DEVINFO_PUT_SAS_ADDRESSHI(
                              &oneDeviceData->dmDeviceInfo,
                              SA_IDFRM_GET_SAS_ADDRESSHI(&oneDeviceData->sasIdentify)
                              );
    
    if (oneDeviceData->ExpDevice != agNULL)
    {
      DM_DBG3(("dmPortSASDeviceAdd: attached expander case\n"));
      oneAttachedExpDeviceData = oneDeviceData->ExpDevice;
      /*
        Puts attached expander's SAS address into dmDeviceInfo
      */
      DEVINFO_PUT_SAS_ADDRESSLO(
                                &oneAttachedExpDeviceData->dmDeviceInfo,
                                oneAttachedExpDeviceData->SASAddressID.sasAddressLo
                                );
      DEVINFO_PUT_SAS_ADDRESSHI(
                                &oneAttachedExpDeviceData->dmDeviceInfo,
                                oneAttachedExpDeviceData->SASAddressID.sasAddressHi
                                );
      DM_DBG3(("dmPortSASDeviceAdd: oneAttachedExpDeviceData addrHi 0x%08x addrLo 0x%08x PhyID 0x%x ext 0x%x\n", 
      DM_GET_SAS_ADDRESSHI(oneAttachedExpDeviceData->dmDeviceInfo.sasAddressHi), 
      DM_GET_SAS_ADDRESSLO(oneAttachedExpDeviceData->dmDeviceInfo.sasAddressLo),
      phyID, extension));    
            
      if (oneAttachedExpDeviceData->SASAddressID.sasAddressHi == 0x0 &&
          oneAttachedExpDeviceData->SASAddressID.sasAddressLo == 0x0)
      {
        DM_DBG1(("dmPortSASDeviceAdd: 2nd Wrong expander!!!\n"));    
      }    	    
      if (oneDeviceData->reported == agFALSE)
      {
        oneDeviceData->registered = agTRUE;
        oneDeviceData->reported = agTRUE;
        if (deviceType == STP_DEVICE_TYPE)
        {
            /*STP device, DM need send SMP Report Phy SATA to get the SATA device type */
            oneAttachedExpDeviceData->dmExpander->dmDeviceToProcess = oneDeviceData;
            dmReportPhySataSend(dmRoot, oneAttachedExpDeviceData, phyID);  
        }
        else
        {
            /* SAS or SMP device */
            tddmReportDevice(dmRoot, onePortContext->dmPortContext, &oneDeviceData->dmDeviceInfo, &oneAttachedExpDeviceData->dmDeviceInfo, dmDeviceArrival);
        }
      }      
    }
    else
    {
      DM_DBG3(("dmPortSASDeviceAdd: NO attached expander case\n"));
      if (oneDeviceData->reported == agFALSE)
      {
        oneDeviceData->registered = agTRUE;
        oneDeviceData->reported = agTRUE;
        tddmReportDevice(dmRoot, onePortContext->dmPortContext, &oneDeviceData->dmDeviceInfo, agNULL, dmDeviceArrival);
      }      
    }	
  }  
  
  return oneDeviceData;
}		      

osGLOBAL dmDeviceData_t *
dmFindRegNValid(
                dmRoot_t             *dmRoot,
                dmIntPortContext_t   *onePortContext,
                dmSASSubID_t         *dmSASSubID
               )								
{
  dmIntRoot_t       *dmIntRoot    = (dmIntRoot_t *)dmRoot->dmData;
  dmIntContext_t    *dmAllShared = (dmIntContext_t *)&dmIntRoot->dmAllShared;
  dmDeviceData_t    *oneDeviceData = agNULL;
  dmList_t          *DeviceListList;
  bit32             found = agFALSE;
  DM_DBG3(("dmFindRegNValid: start\n"));
  
  /* find a device's existence */
  DeviceListList = dmAllShared->MainDeviceList.flink;
  if (onePortContext->discovery.type == DM_DISCOVERY_OPTION_FULL_START)
  {
    DM_DBG3(("dmFindRegNValid: Full discovery\n"));
    while (DeviceListList != &(dmAllShared->MainDeviceList))
    {
      oneDeviceData = DMLIST_OBJECT_BASE(dmDeviceData_t, MainLink, DeviceListList);
      if (oneDeviceData == agNULL)
      {
        DM_DBG1(("dmFindRegNValid: oneDeviceData is NULL!!!\n"));
        return agFALSE;
      }    
      if ((oneDeviceData->SASAddressID.sasAddressHi == dmSASSubID->sasAddressHi) &&
          (oneDeviceData->SASAddressID.sasAddressLo == dmSASSubID->sasAddressLo) &&
          (oneDeviceData->valid == agTRUE) &&
          (oneDeviceData->dmPortContext == onePortContext)
          )
      {
        DM_DBG3(("dmFindRegNValid: Found pid %d did %d\n", onePortContext->id, oneDeviceData->id));
        DM_DBG3(("dmFindRegNValid: sasAddressHi 0x%08x\n", oneDeviceData->SASAddressID.sasAddressHi));         
        DM_DBG3(("dmFindRegNValid: sasAddressLo 0x%08x\n", oneDeviceData->SASAddressID.sasAddressLo));
        found = agTRUE;
        break;
      }
      DeviceListList = DeviceListList->flink;
    }
  }
  else
  {
    /* incremental discovery */
    DM_DBG3(("dmFindRegNValid: Incremental discovery\n"));
    while (DeviceListList != &(dmAllShared->MainDeviceList))
    {
      oneDeviceData = DMLIST_OBJECT_BASE(dmDeviceData_t, MainLink, DeviceListList);
      if (oneDeviceData == agNULL)
      {
        DM_DBG1(("dmFindRegNValid: oneDeviceData is NULL!!!\n"));
        return agFALSE;
      }    
      if ((oneDeviceData->SASAddressID.sasAddressHi == dmSASSubID->sasAddressHi) &&
          (oneDeviceData->SASAddressID.sasAddressLo == dmSASSubID->sasAddressLo) &&
          (oneDeviceData->valid2 == agTRUE) &&
          (oneDeviceData->dmPortContext == onePortContext)
          )
      {
        DM_DBG3(("dmFindRegNValid: Found pid %d did %d\n", onePortContext->id, oneDeviceData->id));
        DM_DBG3(("dmFindRegNValid: sasAddressHi 0x%08x\n", oneDeviceData->SASAddressID.sasAddressHi));         
        DM_DBG3(("dmFindRegNValid: sasAddressLo 0x%08x\n", oneDeviceData->SASAddressID.sasAddressLo));
        found = agTRUE;
        break;
      }
      DeviceListList = DeviceListList->flink;
    }
  }
    
        
                
  if (found == agFALSE)
  {
    DM_DBG3(("dmFindRegNValid: end returning NULL\n"));
    return agNULL;
  }
  else
  {
    DM_DBG3(("dmFindRegNValid: end returning NOT NULL\n"));
    return oneDeviceData;
  }
}		      

osGLOBAL void	
dmNotifyBC(
           dmRoot_t			*dmRoot,
           dmPortContext_t		*dmPortContext,
           bit32 			type)
{
  dmIntPortContext_t        *onePortContext = agNULL;
  
  onePortContext = (dmIntPortContext_t *)dmPortContext->dmData;
  
  DM_DBG3(("dmNotifyBC: start\n"));
      
  if (onePortContext == agNULL)
  {
    DM_DBG1(("dmNotifyBC: onePortContext is NULL, wrong!!!\n"));  
    return;
  }
  
  if (type == OSSA_HW_EVENT_BROADCAST_CHANGE)
  {
    if (onePortContext->DiscoveryAbortInProgress == agFALSE)
    {
    if (onePortContext->DiscoveryState == DM_DSTATE_COMPLETED)
    {
      DM_DBG3(("dmNotifyBC: BROADCAST_CHANGE\n"));
      onePortContext->DiscoveryState = DM_DSTATE_NOT_STARTED;
      onePortContext->discoveryOptions = DM_DISCOVERY_OPTION_INCREMENTAL_START;
      /* processed broadcast change */
      onePortContext->discovery.SeenBC = agFALSE;       
    }
    else
    {
      DM_DBG3(("dmNotifyBC: pid %d BROADCAST_CHANGE; updating SeenBC. Do nothing.\n", onePortContext->id));      
      onePortContext->discovery.SeenBC = agTRUE;
    }
    }                 
  }
  else if (type == OSSA_HW_EVENT_BROADCAST_SES)
  {
    DM_DBG3(("dmNotifyBC: OSSA_HW_EVENT_BROADCAST_SES\n"));      
  }
  else if (type == OSSA_HW_EVENT_BROADCAST_EXP)
  {
    DM_DBG3(("dmNotifyBC: OSSA_HW_EVENT_BROADCAST_EXP\n"));      
  }
  else 
  {
    DM_DBG3(("dmNotifyBC: unspecified broadcast type 0x%x\n", type));      
  }
  return;
}	   				


#ifdef WORKED
/* triggers incremental discovery */
osGLOBAL void	
dmNotifyBC(
           dmRoot_t			*dmRoot,
           dmPortContext_t		*dmPortContext,
           bit32 			type)
{
  dmIntPortContext_t        *onePortContext = agNULL;
  
  onePortContext = (dmIntPortContext_t *)dmPortContext->dmData;
  
  DM_DBG3(("dmNotifyBC: start\n"));
      
  
  if (type == OSSA_HW_EVENT_BROADCAST_CHANGE)
  {
    if (onePortContext->DiscoveryState == DM_DSTATE_COMPLETED)
    {
      DM_DBG3(("dmNotifyBC: BROADCAST_CHANGE; does incremental discovery\n"));
      onePortContext->DiscoveryState = DM_DSTATE_NOT_STARTED;
      onePortContext->discoveryOptions = DM_DISCOVERY_OPTION_INCREMENTAL_START;
      /* processed broadcast change */
      onePortContext->discovery.SeenBC = agFALSE;       
      if (onePortContext->discovery.ResetTriggerred == agTRUE)
      {
        DM_DBG3(("dmNotifyBC: tdsaBCTimer\n"));
        dmBCTimer(dmRoot, onePortContext);
      }
      else
      {
        dmDiscover(
                   dmRoot,
                   dmPortContext,
                   DM_DISCOVERY_OPTION_INCREMENTAL_START
                  );
      }
    }
    else
    {
      DM_DBG3(("dmNotifyBC: pid %d BROADCAST_CHANGE; updating SeenBC. Do nothing.\n", onePortContext->id));      
      onePortContext->discovery.SeenBC = agTRUE;
    }                 
  }
  else if (type == OSSA_HW_EVENT_BROADCAST_SES)
  {
    DM_DBG3(("dmNotifyBC: OSSA_HW_EVENT_BROADCAST_SES\n"));      
  }
  else if (type == OSSA_HW_EVENT_BROADCAST_EXP)
  {
    DM_DBG3(("dmNotifyBC: OSSA_HW_EVENT_BROADCAST_EXP\n"));      
  }
  else 
  {
    DM_DBG3(("dmNotifyBC: unspecified broadcast type 0x%x\n", type));      
  }
  return;
}	   				
#endif				
				
osGLOBAL bit32 	
dmResetFailedDiscovery(  
                 dmRoot_t               *dmRoot,
                 dmPortContext_t        *dmPortContext)
{
  dmIntPortContext_t        *onePortContext = agNULL;
  
  DM_DBG1(("dmResetFailedDiscovery: start\n"));
  
  onePortContext = (dmIntPortContext_t *)dmPortContext->dmData;
  
  if (onePortContext == agNULL)
  {
    DM_DBG1(("dmResetFailedDiscovery: onePortContext is NULL, wrong!!!\n"));  
    return DM_RC_FAILURE;
  }
  
  if (onePortContext->DiscoveryState == DM_DSTATE_COMPLETED_WITH_FAILURE)
  {
    onePortContext->DiscoveryState = DM_DSTATE_COMPLETED;
  }
  else
  {
    DM_DBG1(("dmResetFailedDiscovery: discovery is NOT DM_DSTATE_COMPLETED_WITH_FAILURE. It is 0x%x\n", onePortContext->DiscoveryState));  
    return DM_RC_FAILURE;
  }
  
  return DM_RC_SUCCESS;
}	   				

osGLOBAL bit32 	
dmQueryDiscovery(  
                 dmRoot_t 		*dmRoot,
                 dmPortContext_t	*dmPortContext)
{
  dmIntPortContext_t        *onePortContext = agNULL;
  
  DM_DBG3(("dmQueryDiscovery: start\n"));
  
  onePortContext = (dmIntPortContext_t *)dmPortContext->dmData;
  
  if (onePortContext == agNULL)
  {
    DM_DBG1(("dmQueryDiscovery: onePortContext is NULL, wrong!!!\n"));  
    return DM_RC_FAILURE;
  }
  
  /* call tddmQueryDiscoveryCB() */
  if (onePortContext->DiscoveryState == DM_DSTATE_COMPLETED)
  {
    tddmQueryDiscoveryCB(dmRoot, dmPortContext,  onePortContext->discoveryOptions, dmDiscCompleted); 
  }
  else if (onePortContext->DiscoveryState == DM_DSTATE_COMPLETED_WITH_FAILURE)
  {
    tddmQueryDiscoveryCB(dmRoot, dmPortContext,  onePortContext->discoveryOptions, dmDiscFailed); 
  }
  else
  {
    tddmQueryDiscoveryCB(dmRoot, dmPortContext,  onePortContext->discoveryOptions, dmDiscInProgress); 
  }  
  
  return DM_RC_SUCCESS;
}	   				

								
/* 
  should only for an expander
*/
osGLOBAL bit32 	
dmRegisterDevice(  
		 dmRoot_t 		*dmRoot,
		 dmPortContext_t	*dmPortContext,
		 dmDeviceInfo_t		*dmDeviceInfo,
                 agsaDevHandle_t        *agDevHandle
		 )
{

  dmIntPortContext_t        *onePortContext = agNULL;
  dmExpander_t              *oneExpander = agNULL;
  bit32                     sasAddressHi, sasAddressLo;
  dmDeviceData_t            *oneDeviceData = agNULL;
  dmSASSubID_t              dmSASSubID;
  
  DM_DBG3(("dmRegisterDevice: start\n"));
  
  onePortContext = (dmIntPortContext_t *)dmPortContext->dmData;
  if (onePortContext == agNULL)
  {
    DM_DBG1(("dmRegisterDevice: onePortContext is NULL!!!\n"));
    return DM_RC_FAILURE;
  }
  
  if (onePortContext->valid == agFALSE)
  {
    DM_DBG1(("dmRegisterDevice: invalid port!!!\n"));
    return DM_RC_FAILURE;
  }
  
  onePortContext->RegFailed = agFALSE;
  
  /* tdssAddSASToSharedcontext() from ossaHwCB()
osGLOBAL void
tdssAddSASToSharedcontext(
                          tdsaPortContext_t    *tdsaPortContext_Instance,
                          agsaRoot_t           *agRoot,
                          agsaDevHandle_t      *agDevHandle,
                          tdsaSASSubID_t       *agSASSubID,
                          bit32                registered,
                          bit8                 phyID,
                          bit32                flag
                          );
from discovery  
osGLOBAL tdsaDeviceData_t *
tdssNewAddSASToSharedcontext(
                                 agsaRoot_t           *agRoot,
                                 tdsaPortContext_t    *onePortContext,
                                 tdsaSASSubID_t       *agSASSubID,
                                 tdsaDeviceData_t     *oneExpDeviceData,
                                 bit8                 phyID
                                 );
  
  */
  /* start here */
  dmSASSubID.sasAddressHi = DM_GET_SAS_ADDRESSHI(dmDeviceInfo->sasAddressHi);
  dmSASSubID.sasAddressLo = DM_GET_SAS_ADDRESSHI(dmDeviceInfo->sasAddressLo);
  dmSASSubID.initiator_ssp_stp_smp = dmDeviceInfo->initiator_ssp_stp_smp;
  dmSASSubID.target_ssp_stp_smp = dmDeviceInfo->target_ssp_stp_smp;
 
  oneDeviceData = dmAddSASToSharedcontext(dmRoot, onePortContext, &dmSASSubID, agNULL, 0xFF);  
  if (oneDeviceData == agNULL)
  {
    DM_DBG1(("dmRegisterDevice: oneDeviceData is NULL!!!\n"));
    return DM_RC_FAILURE;
  }
  oneDeviceData->agDeviceInfo.devType_S_Rate = dmDeviceInfo->devType_S_Rate;
  dm_memcpy(oneDeviceData->agDeviceInfo.sasAddressHi, dmDeviceInfo->sasAddressHi, 4);
  dm_memcpy(oneDeviceData->agDeviceInfo.sasAddressLo, dmDeviceInfo->sasAddressLo, 4);
  /* finds the type of expanders */
  if (DEVINFO_GET_EXT_SMP(dmDeviceInfo))
  {
    if (DEVINFO_GET_EXT_EXPANDER_TYPE(dmDeviceInfo) == SAS_EDGE_EXPANDER_DEVICE)
    {
      oneDeviceData->SASSpecDeviceType = SAS_EDGE_EXPANDER_DEVICE;
    }
    else if (DEVINFO_GET_EXT_EXPANDER_TYPE(dmDeviceInfo) == SAS_FANOUT_EXPANDER_DEVICE)
    {
      oneDeviceData->SASSpecDeviceType = SAS_FANOUT_EXPANDER_DEVICE;
    }
    else
    {
      /* default */
      DM_DBG4(("dmRegisterDevice: no expander type. default to edge expander\n"));
      oneDeviceData->SASSpecDeviceType = SAS_EDGE_EXPANDER_DEVICE;
    }
  }
  
  if (DEVINFO_GET_EXT_MCN(dmDeviceInfo) == 0xF)
  {
    DM_DBG1(("dmRegisterDevice: directly attached expander\n"));
    oneDeviceData->directlyAttached = agTRUE;
    oneDeviceData->dmDeviceInfo.ext =  (bit16)(oneDeviceData->dmDeviceInfo.ext | (0xF << 11));
  }
  else
  {
    DM_DBG1(("dmRegisterDevice: NOT directly attached expander\n"));
    oneDeviceData->directlyAttached = agFALSE;
  }      
  
  if (onePortContext->DiscoveryState == DM_DSTATE_NOT_STARTED)
  {
    DM_DBG3(("dmRegisterDevice: DM_DSTATE_NOT_STARTED\n"));
    /* before the discovery is started */
    oneExpander = dmDiscoveringExpanderAlloc(dmRoot, onePortContext, oneDeviceData);
    if ( oneExpander != agNULL)
    {
      oneExpander->agDevHandle = agDevHandle;
      /* update SAS address field */
      oneExpander->dmDevice->SASAddressID.sasAddressHi = DM_GET_SAS_ADDRESSHI(dmDeviceInfo->sasAddressHi);
      oneExpander->dmDevice->SASAddressID.sasAddressLo = DM_GET_SAS_ADDRESSLO(dmDeviceInfo->sasAddressLo);
      DM_DBG3(("dmRegisterDevice: AddrHi 0x%08x AddrLo 0x%08x\n", oneExpander->dmDevice->SASAddressID.sasAddressHi, oneExpander->dmDevice->SASAddressID.sasAddressLo));
      dmDiscoveringExpanderAdd(dmRoot, onePortContext, oneExpander);      
    }
    else
    {
      DM_DBG1(("dmRegisterDevice: failed to allocate expander !!!\n"));
      /* remember that the registration failed so that a discovery can't be started */
      onePortContext->RegFailed = agTRUE;
      return DM_RC_FAILURE;
    }
  }
  else
  {
    /*
      the discovery has started. Alloc and add have been done.
      find an expander using dmDeviceInfo, and update the expander's agDevHandle
      call dmExpFind()
    */
    DM_DBG3(("dmRegisterDevice: NOT DM_DSTATE_NOT_STARTED\n"));
    sasAddressHi = DM_GET_SAS_ADDRESSHI(dmDeviceInfo->sasAddressHi);
    sasAddressLo = DM_GET_SAS_ADDRESSLO(dmDeviceInfo->sasAddressLo);
    DM_DBG3(("dmRegisterDevice: AddrHi 0x%08x AddrLo 0x%08x\n", sasAddressHi, sasAddressLo));
    oneExpander = dmExpFind(dmRoot, onePortContext, sasAddressHi, sasAddressLo);
    if ( oneExpander != agNULL)
    {
      oneExpander->agDevHandle = agDevHandle;
    }
    else
    {
      DM_DBG1(("dmRegisterDevice: not allowed case, wrong !!!\n"));
      return DM_RC_FAILURE;
    }
  }

  return DM_RC_SUCCESS;
}	   			 

osGLOBAL dmExpander_t *
dmDiscoveringExpanderAlloc(
                           dmRoot_t                 *dmRoot,
                           dmIntPortContext_t       *onePortContext,
                           dmDeviceData_t           *oneDeviceData
                          )
{
  dmIntRoot_t               *dmIntRoot    = (dmIntRoot_t *)dmRoot->dmData;
  dmIntContext_t            *dmAllShared = (dmIntContext_t *)&dmIntRoot->dmAllShared;
  dmExpander_t              *oneExpander = agNULL;
  dmList_t                  *ExpanderList;
  
  DM_DBG3(("dmDiscoveringExpanderAlloc: start\n"));
  DM_DBG3(("dmDiscoveringExpanderAlloc: did %d\n", oneDeviceData->id));
  DM_DBG3(("dmDiscoveringExpanderAlloc: sasAddressHi 0x%08x\n", oneDeviceData->SASAddressID.sasAddressHi));
  DM_DBG3(("dmDiscoveringExpanderAlloc: sasAddressLo 0x%08x\n", oneDeviceData->SASAddressID.sasAddressLo));

  if (onePortContext->valid == agFALSE)
  {
    DM_DBG1(("dmDiscoveringExpanderAlloc: invalid port!!!\n"));
    return agNULL;
  }
  
 
  /* check exitence in dmAllShared->mainExpanderList */
  oneExpander = dmExpMainListFind(dmRoot, 
                                  onePortContext, 
				  oneDeviceData->SASAddressID.sasAddressHi, 
				  oneDeviceData->SASAddressID.sasAddressLo); 
  
  if (oneExpander == agNULL)
  {
    tddmSingleThreadedEnter(dmRoot, DM_EXPANDER_LOCK);
    if (DMLIST_EMPTY(&(dmAllShared->freeExpanderList)))
    {
      DM_DBG1(("dmDiscoveringExpanderAlloc: no free expanders pid %d!!!\n", onePortContext->id));
      tddmSingleThreadedLeave(dmRoot, DM_EXPANDER_LOCK);
      return agNULL;
    }
    else
    {
      tddmSingleThreadedLeave(dmRoot, DM_EXPANDER_LOCK);
    }
  
    tddmSingleThreadedEnter(dmRoot, DM_EXPANDER_LOCK);
    DMLIST_DEQUEUE_FROM_HEAD(&ExpanderList, &(dmAllShared->freeExpanderList));
    tddmSingleThreadedLeave(dmRoot, DM_EXPANDER_LOCK);
  
    oneExpander = DMLIST_OBJECT_BASE(dmExpander_t, linkNode, ExpanderList);
  }
  
  if (oneExpander != agNULL)
  {
    DM_DBG1(("dmDiscoveringExpanderAlloc: pid %d exp id %d \n", onePortContext->id, oneExpander->id));

    tddmSingleThreadedEnter(dmRoot, DM_EXPANDER_LOCK);
    DMLIST_DEQUEUE_THIS(&(oneExpander->linkNode));
    tddmSingleThreadedLeave(dmRoot, DM_EXPANDER_LOCK);
     
    oneExpander->dmDevice = oneDeviceData;
    oneExpander->dmUpStreamExpander = agNULL;
    oneExpander->dmCurrentDownStreamExpander = agNULL;
    oneExpander->dmReturnginExpander = agNULL;
    oneExpander->hasUpStreamDevice = agFALSE;
    oneExpander->numOfUpStreamPhys = 0;
    oneExpander->currentUpStreamPhyIndex = 0;
    oneExpander->discoveringPhyId = 0;    
    oneExpander->underDiscovering = agFALSE; 
    dm_memset( &(oneExpander->currentIndex), 0, sizeof(oneExpander->currentIndex));
    
    oneDeviceData->dmExpander = oneExpander;
    DM_DBG3(("dmDiscoveringExpanderAlloc: oneDeviceData %p did %d\n", oneDeviceData, oneDeviceData->id));
    DM_DBG3(("dmDiscoveringExpanderAlloc: oneExpander %p did %d\n",  oneDeviceData->dmExpander,  oneDeviceData->dmExpander->id));
    
  }
  
  return oneExpander;
}

osGLOBAL void
dmDiscoveringExpanderAdd(
                         dmRoot_t                 *dmRoot,
                         dmIntPortContext_t       *onePortContext,
                         dmExpander_t             *oneExpander
                        )
{
  DM_DBG3(("dmDiscoveringExpanderAdd: start\n"));
  DM_DBG3(("dmDiscoveringExpanderAdd: expander id %d\n", oneExpander->id));
  DM_DBG3(("dmDiscoveringExpanderAdd: exp addrHi 0x%08x\n", oneExpander->dmDevice->SASAddressID.sasAddressHi));
  DM_DBG3(("dmDiscoveringExpanderAdd: exp addrLo 0x%08x\n", oneExpander->dmDevice->SASAddressID.sasAddressLo));  
  
  if (onePortContext->valid == agFALSE)
  {
    DM_DBG1(("dmDiscoveringExpanderAdd: invalid port!!!\n"));
    return;
  }
  if (onePortContext->discovery.status == DISCOVERY_UP_STREAM)
  {
    DM_DBG3(("dmDiscoveringExpanderAdd: UPSTREAM\n"));
  }
  else if (onePortContext->discovery.status == DISCOVERY_DOWN_STREAM)
  {
    DM_DBG3(("dmDiscoveringExpanderAdd: DOWNSTREAM\n"));
  }
  else
  {
    DM_DBG3(("dmDiscoveringExpanderAdd: status %d\n", onePortContext->discovery.status));
  }

  if ( oneExpander->underDiscovering == agFALSE)
  {
    DM_DBG3(("dmDiscoveringExpanderAdd: ADDED \n"));
  
    oneExpander->underDiscovering = agTRUE;
    tddmSingleThreadedEnter(dmRoot, DM_EXPANDER_LOCK);
    DMLIST_ENQUEUE_AT_TAIL(&(oneExpander->linkNode), &(onePortContext->discovery.discoveringExpanderList));
    tddmSingleThreadedLeave(dmRoot, DM_EXPANDER_LOCK);
  }
  
  return;
}		  

osGLOBAL dmExpander_t *
dmFindConfigurableExp(
                      dmRoot_t                  *dmRoot,
                      dmIntPortContext_t        *onePortContext,
                      dmExpander_t              *oneExpander
                     )
{
  dmExpander_t            *tempExpander;
  dmIntPortContext_t      *tmpOnePortContext = onePortContext;
  dmExpander_t            *ret = agNULL;
  DM_DBG3(("dmFindConfigurableExp: start\n"));
  
  if (oneExpander == agNULL)
  {
    DM_DBG3(("dmFindConfigurableExp: NULL expander\n"));
    return agNULL;
  }
  
  DM_DBG3(("dmFindConfigurableExp: exp addrHi 0x%08x\n", oneExpander->dmDevice->SASAddressID.sasAddressHi));
  DM_DBG3(("dmFindConfigurableExp: exp addrLo 0x%08x\n", oneExpander->dmDevice->SASAddressID.sasAddressLo));	
  
  tddmSingleThreadedEnter(dmRoot, DM_EXPANDER_LOCK);
  if (DMLIST_EMPTY(&(tmpOnePortContext->discovery.discoveringExpanderList)))
  {
    tddmSingleThreadedLeave(dmRoot, DM_EXPANDER_LOCK);
    DM_DBG3(("dmFindConfigurableExp: empty UpdiscoveringExpanderList\n"));
    return agNULL;
  }
  else
  {
    tddmSingleThreadedLeave(dmRoot, DM_EXPANDER_LOCK);
  }
  tempExpander = oneExpander->dmUpStreamExpander;
  while (tempExpander)
  {
    DM_DBG3(("dmFindConfigurableExp: loop exp addrHi 0x%08x\n", tempExpander->dmDevice->SASAddressID.sasAddressHi));
    DM_DBG3(("dmFindConfigurableExp: loop exp addrLo 0x%08x\n", tempExpander->dmDevice->SASAddressID.sasAddressLo));
    if (tempExpander->configRouteTable)
    {
      DM_DBG3(("dmFindConfigurableExp: found configurable expander\n"));
      ret = tempExpander;
      break;
    }
   tempExpander = tempExpander->dmUpStreamExpander;
  }
  
  return ret;
}

osGLOBAL bit32
dmDuplicateConfigSASAddr(
                         dmRoot_t                 *dmRoot,
                         dmExpander_t             *oneExpander,
                         bit32                    configSASAddressHi,
                         bit32                    configSASAddressLo
                        )
{
  bit32 i;
  bit32 ret = agFALSE;
  DM_DBG3(("dmDuplicateConfigSASAddr: start\n"));
  
  if (oneExpander == agNULL)
  {
    DM_DBG3(("dmDuplicateConfigSASAddr: NULL expander\n"));
    return agTRUE;
  }  
  
  if (oneExpander->dmDevice->SASAddressID.sasAddressHi == configSASAddressHi &&
      oneExpander->dmDevice->SASAddressID.sasAddressLo == configSASAddressLo
     )
  {
    DM_DBG3(("dmDuplicateConfigSASAddr: unnecessary\n"));
    return agTRUE;
  }	

  DM_DBG3(("dmDuplicateConfigSASAddr: exp addrHi 0x%08x\n", oneExpander->dmDevice->SASAddressID.sasAddressHi));
  DM_DBG3(("dmDuplicateConfigSASAddr: exp addrLo 0x%08x\n", oneExpander->dmDevice->SASAddressID.sasAddressLo));
  DM_DBG3(("dmDuplicateConfigSASAddr: configsasAddressHi 0x%08x\n", configSASAddressHi));
  DM_DBG3(("dmDuplicateConfigSASAddr: configsasAddressLo 0x%08x\n", configSASAddressLo));
  DM_DBG3(("dmDuplicateConfigSASAddr: configSASAddrTableIndex %d\n", oneExpander->configSASAddrTableIndex));    	
  for(i=0;i<oneExpander->configSASAddrTableIndex;i++)
  {
    if (oneExpander->configSASAddressHiTable[i] == configSASAddressHi &&
        oneExpander->configSASAddressLoTable[i] == configSASAddressLo
        )
    {
      DM_DBG3(("dmDuplicateConfigSASAddr: FOUND\n"));
      ret = agTRUE;
      break;
    }
  }
  /* new one; let's add it */
  if (ret == agFALSE)
  {
    DM_DBG3(("dmDuplicateConfigSASAddr: adding configSAS Addr\n"));
    DM_DBG3(("dmDuplicateConfigSASAddr: configSASAddrTableIndex %d\n", oneExpander->configSASAddrTableIndex));   
    oneExpander->configSASAddressHiTable[oneExpander->configSASAddrTableIndex] = configSASAddressHi;
    oneExpander->configSASAddressLoTable[oneExpander->configSASAddrTableIndex] = configSASAddressLo;
    oneExpander->configSASAddrTableIndex++;
  }
  
  return ret;
}

osGLOBAL bit16
dmFindCurrentDownStreamPhyIndex(
                                dmRoot_t          *dmRoot,
                                dmExpander_t      *oneExpander
                                )
{
  dmExpander_t       *DownStreamExpander;
  bit16              index = 0;
  bit16              i;
  bit8               phyId = 0;
  
  DM_DBG3(("dmFindCurrentDownStreamPhyIndex: start\n"));
  
  if (oneExpander == agNULL)
  {
    DM_DBG1(("dmFindCurrentDownStreamPhyIndex: wrong, oneExpander is NULL!!!\n"));
    return 0;
  }
  
  DownStreamExpander = oneExpander->dmCurrentDownStreamExpander;
  
  if (DownStreamExpander == agNULL)
  {
    DM_DBG1(("dmFindCurrentDownStreamPhyIndex: wrong, DownStreamExpander is NULL!!!\n"));
    return 0;
  }
  
  DM_DBG3(("dmFindCurrentDownStreamPhyIndex: exp addrHi 0x%08x\n", oneExpander->dmDevice->SASAddressID.sasAddressHi));
  DM_DBG3(("dmFindCurrentDownStreamPhyIndex: exp addrLo 0x%08x\n", oneExpander->dmDevice->SASAddressID.sasAddressLo));
  DM_DBG3(("dmFindCurrentDownStreamPhyIndex: downstream exp addrHi 0x%08x\n", DownStreamExpander->dmDevice->SASAddressID.sasAddressHi));
  DM_DBG3(("dmFindCurrentDownStreamPhyIndex: downstream exp addrLo 0x%08x\n", DownStreamExpander->dmDevice->SASAddressID.sasAddressLo));
  DM_DBG3(("dmFindCurrentDownStreamPhyIndex: numOfDownStreamPhys %d\n", oneExpander->numOfDownStreamPhys));
  
  phyId = DownStreamExpander->upStreamPhys[0];
  
  DM_DBG3(("dmFindCurrentDownStreamPhyIndex: phyId %d\n", phyId));
  
  for (i=0; i<oneExpander->numOfDownStreamPhys;i++)
  {
    if (oneExpander->downStreamPhys[i] == phyId)
    {
      index = i;
      break;
    }
  }
  DM_DBG3(("dmFindCurrentDownStreamPhyIndex: index %d\n", index));
  return index;
}

osGLOBAL bit32
dmFindDiscoveringExpander(
                          dmRoot_t                  *dmRoot,
                          dmIntPortContext_t        *onePortContext,
                          dmExpander_t              *oneExpander
                         )
{
  dmList_t                *ExpanderList;
  dmExpander_t            *tempExpander;
  dmIntPortContext_t      *tmpOnePortContext = onePortContext;
  bit32                   ret = agFALSE;
  
  
  DM_DBG3(("dmFindDiscoveringExpander: start\n"));
  
  DM_DBG3(("dmFindDiscoveringExpander: exp addrHi 0x%08x\n", oneExpander->dmDevice->SASAddressID.sasAddressHi));
  DM_DBG3(("dmFindDiscoveringExpander: exp addrLo 0x%08x\n", oneExpander->dmDevice->SASAddressID.sasAddressLo));

  if (DMLIST_EMPTY(&(tmpOnePortContext->discovery.discoveringExpanderList)))
  {
    DM_DBG3(("dmFindDiscoveringExpander: empty discoveringExpanderList\n"));
    return ret;
  }
  ExpanderList = tmpOnePortContext->discovery.discoveringExpanderList.flink;
  while (ExpanderList != &(tmpOnePortContext->discovery.discoveringExpanderList))
  {
    tempExpander = DMLIST_OBJECT_BASE(dmExpander_t, linkNode, ExpanderList);
    if (tempExpander == oneExpander)
    {
      if (tempExpander != agNULL)
      {
        DM_DBG3(("dmFindDiscoveringExpander: match, expander id %d\n", tempExpander->id));
        DM_DBG3(("dmFindDiscoveringExpander: exp addrHi 0x%08x\n", tempExpander->dmDevice->SASAddressID.sasAddressHi));
        DM_DBG3(("dmFindDiscoveringExpander: exp addrLo 0x%08x\n", tempExpander->dmDevice->SASAddressID.sasAddressLo));
      }
      ret = agTRUE;
      break;
    }
    
    ExpanderList = ExpanderList->flink;
  }	
  
  
  return ret;
}			 


osGLOBAL void
dmDiscoveringExpanderRemove(
                            dmRoot_t                 *dmRoot,
                            dmIntPortContext_t       *onePortContext,
                            dmExpander_t             *oneExpander
                           )
{
  dmIntRoot_t       *dmIntRoot    = (dmIntRoot_t *)dmRoot->dmData;
  dmIntContext_t    *dmAllShared = (dmIntContext_t *)&dmIntRoot->dmAllShared;
  
  DM_DBG3(("dmDiscoveringExpanderRemove: start\n"));
  DM_DBG3(("dmDiscoveringExpanderRemove: expander id %d\n", oneExpander->id));
  DM_DBG3(("dmDiscoveringExpanderRemove: exp addrHi 0x%08x\n", oneExpander->dmDevice->SASAddressID.sasAddressHi));
  DM_DBG3(("dmDiscoveringExpanderRemove: exp addrLo 0x%08x\n", oneExpander->dmDevice->SASAddressID.sasAddressLo)); 
  
  DM_DBG3(("dmDiscoveringExpanderRemove: BEFORE\n"));
  dmDumpAllExp(dmRoot, onePortContext, oneExpander);
  dmDumpAllUpExp(dmRoot, onePortContext, oneExpander);
  dmDumpAllFreeExp(dmRoot);
  
  // if is temporary till smp problem is fixed
  if (dmFindDiscoveringExpander(dmRoot, onePortContext, oneExpander) == agTRUE)
  {
    DM_DBG3(("dmDiscoveringExpanderRemove: oneDeviceData %p did %d\n", oneExpander->dmDevice, oneExpander->dmDevice->id));
    DM_DBG3(("dmDiscoveringExpanderRemove: oneExpander %p did %d\n", oneExpander, oneExpander->id));
    
    if (oneExpander != oneExpander->dmDevice->dmExpander)
    {
      DM_DBG3(("dmDiscoveringExpanderRemove: before !!! wrong !!!\n"));  
    }
    oneExpander->underDiscovering = agFALSE;
    oneExpander->discoveringPhyId = 0;
    tddmSingleThreadedEnter(dmRoot, DM_EXPANDER_LOCK);
    DMLIST_DEQUEUE_THIS(&(oneExpander->linkNode));
    tddmSingleThreadedLeave(dmRoot, DM_EXPANDER_LOCK);

    if (onePortContext->discovery.status == DISCOVERY_UP_STREAM)
    {
      DM_DBG3(("dmDiscoveringExpanderRemove: DISCOVERY_UP_STREAM\n"));
      tddmSingleThreadedEnter(dmRoot, DM_EXPANDER_LOCK);
      DMLIST_ENQUEUE_AT_TAIL(&(oneExpander->upNode), &(onePortContext->discovery.UpdiscoveringExpanderList)); 
      tddmSingleThreadedLeave(dmRoot, DM_EXPANDER_LOCK);
      onePortContext->discovery.NumOfUpExp++;
    }
    else
    {
      DM_DBG3(("dmDiscoveringExpanderRemove: Status %d\n", onePortContext->discovery.status));
      tddmSingleThreadedEnter(dmRoot, DM_EXPANDER_LOCK);
      DMLIST_ENQUEUE_AT_TAIL(&(oneExpander->linkNode), &(dmAllShared->mainExpanderList));
//      DMLIST_ENQUEUE_AT_TAIL(&(oneExpander->linkNode), &(dmAllShared->freeExpanderList));
      tddmSingleThreadedLeave(dmRoot, DM_EXPANDER_LOCK);
    }
    // error checking
    if (oneExpander != oneExpander->dmDevice->dmExpander)
    {
      DM_DBG3(("dmDiscoveringExpanderRemove: after !!! wrong !!!\n"));  
    }
      
  } //end temp if
  else
  {
    DM_DBG1(("dmDiscoveringExpanderRemove: !!! problem !!!\n"));
  }

  DM_DBG3(("dmDiscoveringExpanderRemove: AFTER\n"));
  
  dmDumpAllExp(dmRoot, onePortContext, oneExpander);
  dmDumpAllUpExp(dmRoot, onePortContext, oneExpander);
  dmDumpAllFreeExp(dmRoot);
  
  return;
}

/*
  returns an expander with sasAddrLo, sasAddrHi from dmAllShared->mainExpanderList
*/
osGLOBAL dmExpander_t *
dmExpMainListFind(
                  dmRoot_t            *dmRoot,
                  dmIntPortContext_t  *onePortContext,
                  bit32               sasAddrHi,
                  bit32               sasAddrLo
                 )
{
  dmIntRoot_t        *dmIntRoot    = (dmIntRoot_t *)dmRoot->dmData;
  dmIntContext_t     *dmAllShared = (dmIntContext_t *)&dmIntRoot->dmAllShared;
  dmList_t           *ExpanderList;
  dmExpander_t       *tempExpander;

  DM_DBG3(("dmExpMainListFind: start\n"));
  
  tddmSingleThreadedEnter(dmRoot, DM_EXPANDER_LOCK);
  if (DMLIST_EMPTY(&(dmAllShared->mainExpanderList)))
  {
    DM_DBG1(("dmExpMainListFind: empty mainExpanderList\n"));
    tddmSingleThreadedLeave(dmRoot, DM_EXPANDER_LOCK);
    return agNULL;
  }
  else
  {
    tddmSingleThreadedLeave(dmRoot, DM_EXPANDER_LOCK);
  }
  ExpanderList = dmAllShared->mainExpanderList.flink;
  while (ExpanderList != &(dmAllShared->mainExpanderList))
  {
    tempExpander = DMLIST_OBJECT_BASE(dmExpander_t, linkNode, ExpanderList);
    if (tempExpander == agNULL)
    {
      DM_DBG1(("dmExpMainListFind: tempExpander is NULL!!!\n"));
      return agNULL;
    }    
    DM_DBG3(("dmExpMainListFind: expander id %d\n", tempExpander->id));
    DM_DBG3(("dmExpMainListFind: exp addrHi 0x%08x\n", tempExpander->dmDevice->SASAddressID.sasAddressHi));
    DM_DBG3(("dmExpMainListFind: exp addrLo 0x%08x\n", tempExpander->dmDevice->SASAddressID.sasAddressLo));
    if ((tempExpander->dmDevice->SASAddressID.sasAddressHi == sasAddrHi) &&
        (tempExpander->dmDevice->SASAddressID.sasAddressLo == sasAddrLo) &&
        (tempExpander->dmDevice->dmPortContext == onePortContext)
       )
    {
      DM_DBG3(("dmExpMainListFind: found expander id %d\n", tempExpander->id));
      DM_DBG3(("dmExpMainListFind: found exp addrHi 0x%08x\n", tempExpander->dmDevice->SASAddressID.sasAddressHi));
      DM_DBG3(("dmExpMainListFind: found exp addrLo 0x%08x\n", tempExpander->dmDevice->SASAddressID.sasAddressLo));
      return tempExpander;
    }       	
    ExpanderList = ExpanderList->flink;
  }
  return agNULL;

}

/*
  returns an expander with sasAddrLo, sasAddrHi from discoveringExpanderList
*/
osGLOBAL dmExpander_t *
dmExpFind(
          dmRoot_t            *dmRoot,
          dmIntPortContext_t  *onePortContext,
          bit32               sasAddrHi,
          bit32               sasAddrLo
         )
{
  dmList_t           *ExpanderList;
  dmExpander_t       *tempExpander;
  dmIntPortContext_t *tmpOnePortContext = onePortContext;
  DM_DBG3(("dmExpFind: start\n"));

  tddmSingleThreadedEnter(dmRoot, DM_EXPANDER_LOCK);
  if (DMLIST_EMPTY(&(tmpOnePortContext->discovery.discoveringExpanderList)))
  {
    DM_DBG3(("dmExpFind tdsaDumpAllExp: empty discoveringExpanderList\n"));
    tddmSingleThreadedLeave(dmRoot, DM_EXPANDER_LOCK);
    return agNULL;
  }
  else
  {
    tddmSingleThreadedLeave(dmRoot, DM_EXPANDER_LOCK);
  }
  ExpanderList = tmpOnePortContext->discovery.discoveringExpanderList.flink;
  while (ExpanderList != &(tmpOnePortContext->discovery.discoveringExpanderList))
  {
    tempExpander = DMLIST_OBJECT_BASE(dmExpander_t, linkNode, ExpanderList);
    if (tempExpander == agNULL)
    {
      DM_DBG1(("dmExpFind: tempExpander is NULL!!!\n"));
      return agNULL;
    }
    DM_DBG3(("dmExpFind: expander id %d\n", tempExpander->id));
    DM_DBG3(("dmExpFind: exp addrHi 0x%08x\n", tempExpander->dmDevice->SASAddressID.sasAddressHi));
    DM_DBG3(("dmExpFind: exp addrLo 0x%08x\n", tempExpander->dmDevice->SASAddressID.sasAddressLo));
    if ((tempExpander->dmDevice->SASAddressID.sasAddressHi == sasAddrHi) &&
        (tempExpander->dmDevice->SASAddressID.sasAddressLo == sasAddrLo) &&
        (tempExpander->dmDevice->dmPortContext == onePortContext)
       )
    {
      DM_DBG3(("dmExpFind: found\n"));
      return tempExpander;
    }       	
    ExpanderList = ExpanderList->flink;
  }
  return agNULL;
}
			     
osGLOBAL bit32
dmDiscoverCheck(
                dmRoot_t 	    	*dmRoot, 
                dmIntPortContext_t      *onePortContext	
                )
{
  DM_DBG3(("dmDiscoverCheck: start\n"));
  
  if (onePortContext == agNULL)
  {
    DM_DBG1(("dmDiscoverCheck: onePortContext is NULL!!!\n"));
    return agTRUE;
  }
  if (onePortContext->valid == agFALSE)
  {
    DM_DBG1(("dmDiscoverCheck: invalid port!!!\n"));
    return agTRUE;
  }
  if (onePortContext->DiscoveryState == DM_DSTATE_COMPLETED ||
      onePortContext->discovery.status == DISCOVERY_SAS_DONE  
     )
  {
    DM_DBG1(("dmDiscoverCheck: aborted discovery!!!\n"));
    tddmDiscoverCB(
                   dmRoot,
                   onePortContext->dmPortContext,
                   dmDiscAborted
	          );
    return agTRUE;
  }
  
  return agFALSE;
}

/* ??? needs to handle pending SMPs 
   move from dmAllShared->discoveringExpanderList to dmAllShared->mainExpanderList  
*/
osGLOBAL void
dmDiscoverAbort(
                dmRoot_t 	    	*dmRoot, 
                dmIntPortContext_t      *onePortContext	
                )
{
  DM_DBG1(("dmDiscoverAbort: start\n"));
  
  if (onePortContext->DiscoveryState == DM_DSTATE_COMPLETED ||
      onePortContext->discovery.status == DISCOVERY_SAS_DONE)
  {
    DM_DBG1(("dmDiscoverAbort: not allowed case!!! onePortContext->DiscoveryState 0x%x onePortContext->discovery.status 0x%x\n", 
    onePortContext->DiscoveryState, onePortContext->discovery.status));
    return;  
  }      
  
  onePortContext->DiscoveryState = DM_DSTATE_COMPLETED;
  onePortContext->discovery.status = DISCOVERY_SAS_DONE;                
  
  /* move from dmAllShared->discoveringExpanderList to dmAllShared->mainExpanderList */
  dmCleanAllExp(dmRoot, onePortContext);

 
  return;

			  
}						  		  	  

/* move from dmAllShared->discoveringExpanderList to dmAllShared->mainExpanderList */
osGLOBAL void
dmCleanAllExp(
              dmRoot_t                 *dmRoot,
              dmIntPortContext_t       *onePortContext
             )
{
  dmIntRoot_t               *dmIntRoot    = (dmIntRoot_t *)dmRoot->dmData;
  dmIntContext_t            *dmAllShared = (dmIntContext_t *)&dmIntRoot->dmAllShared;
  dmList_t                  *ExpanderList;
  dmExpander_t              *tempExpander;
  dmExpander_t              *oneExpander = agNULL;
  dmIntPortContext_t        *tmpOnePortContext = onePortContext;
  
  DM_DBG3(("dmCleanAllExp: start\n"));
  DM_DBG3(("dmCleanAllExp: pid %d\n", onePortContext->id));
  
  DM_DBG3(("dmCleanAllExp: before all clean up\n")); 
  dmDumpAllFreeExp(dmRoot);
  
  /* clean up UpdiscoveringExpanderList*/
  DM_DBG3(("dmCleanAllExp: clean discoveringExpanderList\n"));
  if (!DMLIST_EMPTY(&(tmpOnePortContext->discovery.discoveringExpanderList)))
  {
    ExpanderList = tmpOnePortContext->discovery.discoveringExpanderList.flink;
    while (ExpanderList != &(tmpOnePortContext->discovery.discoveringExpanderList))
    {
      tempExpander = DMLIST_OBJECT_BASE(dmExpander_t, linkNode, ExpanderList);
      if (tempExpander == agNULL)
      {
        DM_DBG1(("dmCleanAllExp: tempExpander is NULL!!!\n"));
        return;
      }    
      DM_DBG3(("dmCleanAllExp: exp addrHi 0x%08x\n", tempExpander->dmDevice->SASAddressID.sasAddressHi));
      DM_DBG3(("dmCleanAllExp: exp addrLo 0x%08x\n", tempExpander->dmDevice->SASAddressID.sasAddressLo));
      DM_DBG3(("dmCleanAllExp: exp id %d\n", tempExpander->id));
      
      oneExpander = dmExpMainListFind(dmRoot, 
                                      tmpOnePortContext, 
                                      tempExpander->dmDevice->SASAddressID.sasAddressHi, 
                                      tempExpander->dmDevice->SASAddressID.sasAddressLo);      
      if (oneExpander == agNULL)
      {      
        DM_DBG3(("dmCleanAllExp: moving\n"));
        DM_DBG3(("dmCleanAllExp: moving, exp id %d\n", tempExpander->id));
        /* putting back to the free pool */
        tddmSingleThreadedEnter(dmRoot, DM_EXPANDER_LOCK);
        DMLIST_DEQUEUE_THIS(&(tempExpander->linkNode));
//      DMLIST_ENQUEUE_AT_TAIL(&(tempExpander->linkNode), &(dmAllShared->freeExpanderList));
        DMLIST_ENQUEUE_AT_TAIL(&(tempExpander->linkNode), &(dmAllShared->mainExpanderList));

        if (DMLIST_EMPTY(&(tmpOnePortContext->discovery.discoveringExpanderList)))
        {
          tddmSingleThreadedLeave(dmRoot, DM_EXPANDER_LOCK);
          break;
        }
        else
        {
          tddmSingleThreadedLeave(dmRoot, DM_EXPANDER_LOCK);   
        }
        ExpanderList = tmpOnePortContext->discovery.discoveringExpanderList.flink;
      }
      else
      {
        DM_DBG3(("dmCleanAllExp: in mainExpanderList; skippig\n"));              
        ExpanderList =  ExpanderList->flink;    
      }                  
    }
  }
  else
  {
    DM_DBG3(("dmCleanAllExp: empty discoveringExpanderList\n")); 
  }
  
  /* reset discoveringExpanderList */
  DMLIST_INIT_HDR(&(tmpOnePortContext->discovery.discoveringExpanderList));    

  /* clean up UpdiscoveringExpanderList*/
  DM_DBG3(("dmCleanAllExp: clean UpdiscoveringExpanderList\n"));
  if (DMLIST_EMPTY(&(tmpOnePortContext->discovery.UpdiscoveringExpanderList)))
  {
    DM_DBG3(("dmCleanAllExp: empty UpdiscoveringExpanderList\n"));
    return;
  }
  ExpanderList = tmpOnePortContext->discovery.UpdiscoveringExpanderList.flink;
  while (ExpanderList != &(tmpOnePortContext->discovery.UpdiscoveringExpanderList))
  {
    tempExpander = DMLIST_OBJECT_BASE(dmExpander_t, upNode, ExpanderList);
    if (tempExpander == agNULL)
    {
      DM_DBG1(("dmCleanAllExp: tempExpander is NULL!!!\n"));
      return;
    }    
    DM_DBG3(("dmCleanAllExp: exp addrHi 0x%08x\n", tempExpander->dmDevice->SASAddressID.sasAddressHi));
    DM_DBG3(("dmCleanAllExp: exp addrLo 0x%08x\n", tempExpander->dmDevice->SASAddressID.sasAddressLo));
    DM_DBG3(("dmCleanAllExp: exp id %d\n", tempExpander->id));
    oneExpander = dmExpMainListFind(dmRoot, 
                                    tmpOnePortContext, 
                                    tempExpander->dmDevice->SASAddressID.sasAddressHi, 
                                    tempExpander->dmDevice->SASAddressID.sasAddressLo);      
    if (oneExpander == agNULL)
    {      
      DM_DBG3(("dmCleanAllExp: moving\n"));
      DM_DBG3(("dmCleanAllExp: moving exp id %d\n", tempExpander->id));
      tddmSingleThreadedEnter(dmRoot, DM_EXPANDER_LOCK);
      DMLIST_DEQUEUE_THIS(&(tempExpander->upNode));
      DMLIST_ENQUEUE_AT_TAIL(&(tempExpander->linkNode), &(dmAllShared->mainExpanderList));

      if (DMLIST_EMPTY(&(tmpOnePortContext->discovery.UpdiscoveringExpanderList)))
      {
        tddmSingleThreadedLeave(dmRoot, DM_EXPANDER_LOCK);
        break;
      }
      else
      {
        tddmSingleThreadedLeave(dmRoot, DM_EXPANDER_LOCK);   
      }
      ExpanderList = tmpOnePortContext->discovery.UpdiscoveringExpanderList.flink;
    }
    else
    {
      DM_DBG3(("dmCleanAllExp: in mainExpanderList; skippig\n"));              
      ExpanderList =  ExpanderList->flink;    
    }                
  }
  
  /* reset UpdiscoveringExpanderList */
  DMLIST_INIT_HDR(&(tmpOnePortContext->discovery.UpdiscoveringExpanderList));    
  
  DM_DBG3(("dmCleanAllExp: after all clean up\n")); 
  dmDumpAllFreeExp(dmRoot);
  
  return;
}

osGLOBAL void
dmInternalRemovals(
                   dmRoot_t                 *dmRoot,
                   dmIntPortContext_t       *onePortContext
                   )
{
  dmIntRoot_t               *dmIntRoot    = (dmIntRoot_t *)dmRoot->dmData;
  dmIntContext_t            *dmAllShared = (dmIntContext_t *)&dmIntRoot->dmAllShared;
  dmDeviceData_t            *oneDeviceData = agNULL;
  dmList_t                  *DeviceListList;
  
  
  DM_DBG3(("dmInternalRemovals: start\n"));
  tddmSingleThreadedEnter(dmRoot, DM_DEVICE_LOCK);
  if (DMLIST_EMPTY(&(dmAllShared->MainDeviceList)))
  {
    tddmSingleThreadedLeave(dmRoot, DM_DEVICE_LOCK);
    DM_DBG3(("dmInternalRemovals: empty device list\n"));
    return;
  }
  else
  {
    tddmSingleThreadedLeave(dmRoot, DM_DEVICE_LOCK);
  }
  
  DeviceListList = dmAllShared->MainDeviceList.flink;
  while (DeviceListList != &(dmAllShared->MainDeviceList))
  {
    oneDeviceData = DMLIST_OBJECT_BASE(dmDeviceData_t, MainLink, DeviceListList);
    if (oneDeviceData == agNULL)
    {
      DM_DBG1(("dmInternalRemovals: oneDeviceData is NULL!!!\n"));
      return;
    }    
    DM_DBG3(("dmInternalRemovals: loop did %d\n", oneDeviceData->id));
    DM_DBG3(("dmInternalRemovals: sasAddrHi 0x%08x \n", oneDeviceData->SASAddressID.sasAddressHi));
    DM_DBG3(("dmInternalRemovals: sasAddrLo 0x%08x \n", oneDeviceData->SASAddressID.sasAddressLo));
    DM_DBG3(("dmInternalRemovals: valid %d\n", oneDeviceData->valid));    
    DM_DBG3(("dmInternalRemovals: valid2 %d\n", oneDeviceData->valid2));    
    DM_DBG3(("dmInternalRemovals: directlyAttached %d\n", oneDeviceData->directlyAttached));    
    if ( oneDeviceData->dmPortContext == onePortContext)
    {
      DM_DBG3(("dmInternalRemovals: right portcontext pid %d\n", onePortContext->id));
      if (onePortContext->discovery.type == DM_DISCOVERY_OPTION_INCREMENTAL_START)
      {
        DM_DBG3(("dmInternalRemovals: incremental discovery\n"));
        oneDeviceData->valid2 = agFALSE;
      }
      else
      {
        DM_DBG3(("dmInternalRemovals: full discovery\n"));
        oneDeviceData->valid = agFALSE;
      }
      DeviceListList = DeviceListList->flink;
    }    
    else
    {
      if (oneDeviceData->dmPortContext != agNULL)
      {
        DM_DBG3(("dmInternalRemovals: different portcontext; oneDeviceData->dmPortContext pid %d oneportcontext pid %d\n", oneDeviceData->dmPortContext->id, onePortContext->id));
      }
      else
      {
        DM_DBG3(("dmInternalRemovals: different portcontext; oneDeviceData->dmPortContext pid NULL oneportcontext pid %d\n", onePortContext->id));
      }
      DeviceListList = DeviceListList->flink;
    }  
  }
  
  
  return;
}

osGLOBAL void
dmDiscoveryResetProcessed(
                          dmRoot_t                 *dmRoot,
                          dmIntPortContext_t       *onePortContext
                         )
{
  dmIntRoot_t       *dmIntRoot    = (dmIntRoot_t *)dmRoot->dmData;
  dmIntContext_t    *dmAllShared = (dmIntContext_t *)&dmIntRoot->dmAllShared;
  dmDeviceData_t    *oneDeviceData = agNULL;
  dmList_t          *DeviceListList;
  
  DM_DBG3(("dmDiscoveryResetProcessed: start\n"));
  
  /* reinitialize the device data belonging to this portcontext */
  DeviceListList = dmAllShared->MainDeviceList.flink;
  while (DeviceListList != &(dmAllShared->MainDeviceList))
  {
    oneDeviceData = DMLIST_OBJECT_BASE(dmDeviceData_t, MainLink, DeviceListList);
    if (oneDeviceData == agNULL)
    {
      DM_DBG1(("dmDiscoveryResetProcessed: oneDeviceData is NULL!!!\n"));
      return;
    }    
    DM_DBG3(("dmDiscoveryResetProcessed: loop did %d\n", oneDeviceData->id));
    if (oneDeviceData->dmPortContext == onePortContext)
    {
      DM_DBG3(("dmDiscoveryResetProcessed: resetting procssed flag\n"));
      oneDeviceData->processed = agFALSE;
    }
    DeviceListList = DeviceListList->flink;  
  }
  
  return;
}			 

/*
  calls
osGLOBAL void 
tddmDiscoverCB(
               dmRoot_t 		*dmRoot,
               dmPortContext_t		*dmPortContext,
               bit32			eventStatus
              )
  
*/
osGLOBAL void
dmDiscoverDone(
               dmRoot_t                 *dmRoot,
               dmIntPortContext_t       *onePortContext,
               bit32                    flag
              )
{
 
  DM_DBG3(("dmDiscoverDone: start\n"));
  DM_DBG3(("dmDiscoverDone: pid %d\n", onePortContext->id));

  /* Set discovery status */
  onePortContext->discovery.status = DISCOVERY_SAS_DONE;                
  
 
  /* clean up expanders data strucures; move to free exp when device is cleaned */
  dmCleanAllExp(dmRoot, onePortContext);
  
  dmDumpAllMainExp(dmRoot, onePortContext);

  dmDiscoveryResetProcessed(dmRoot, onePortContext);
  
  dmDiscoveryDumpMCN(dmRoot, onePortContext);
  
  if (onePortContext->discovery.SeenBC == agTRUE)
  {
    DM_DBG3(("dmDiscoverDone: broadcast change; discover again\n"));
    dmDiscoveryResetMCN(dmRoot, onePortContext);
    
    dmInternalRemovals(dmRoot, onePortContext);

    /* processed broadcast change */
    onePortContext->discovery.SeenBC = agFALSE;
    if (onePortContext->discovery.ResetTriggerred == agTRUE)
    {
      DM_DBG3(("dmDiscoverDone: dmBCTimer\n"));
      dmBCTimer(dmRoot, onePortContext);
    }
    else
    {

      dmIncrementalDiscover(dmRoot, onePortContext, agTRUE); 		  
    }
  }
  else
  {
    onePortContext->DiscoveryState = DM_DSTATE_COMPLETED;
  
    if (onePortContext->discovery.type == DM_DISCOVERY_OPTION_FULL_START)
    { 
      if (flag == DM_RC_SUCCESS)
      {

       dmResetReported(dmRoot,
                       onePortContext
                      );
		      
       dmDiscoveryReportMCN(dmRoot,
                            onePortContext
                           );
                           		      

       /* call tddmDiscoverCB() */
       tddmDiscoverCB(
                       dmRoot,
                       onePortContext->dmPortContext,
                       dmDiscCompleted
                      );
      }
      else if (flag != DM_RC_SUCCESS || onePortContext->discovery.DeferredError == agTRUE)
      {
        onePortContext->DiscoveryState = DM_DSTATE_COMPLETED_WITH_FAILURE;
        DM_DBG1(("dmDiscoverDone: Error; clean up!!!\n"));
	
        dmDiscoveryInvalidateDevices(dmRoot,
                                     onePortContext
                                    );
			
        tddmDiscoverCB(
                       dmRoot,
                       onePortContext->dmPortContext,
                       dmDiscFailed
                      );
      }
    }
    else
    {
      if (flag == DM_RC_SUCCESS)
      { 
        dmReportChanges(dmRoot,
                        onePortContext
                       );
        dmDiscoveryReportMCN(dmRoot,
                             onePortContext
                            );
        tddmDiscoverCB(
                       dmRoot,
                       onePortContext->dmPortContext,
                       dmDiscCompleted
                      );
      }
      else if (flag != DM_RC_SUCCESS || onePortContext->discovery.DeferredError == agTRUE)
      {
        onePortContext->DiscoveryState = DM_DSTATE_COMPLETED_WITH_FAILURE;
        dmDiscoveryInvalidateDevices(dmRoot,
                                     onePortContext
                                    );
		
        tddmDiscoverCB(
                       dmRoot,
                       onePortContext->dmPortContext,
                       dmDiscFailed
                      );
      }                        
    }
  }
  return;
}

/* called by dmDiscoveryErrorRemovals() or dmReportRemovals() on discovery failure */
osGLOBAL void
dmSubReportRemovals(
                   dmRoot_t                  *dmRoot,
                   dmIntPortContext_t        *onePortContext,
                   dmDeviceData_t            *oneDeviceData,
                   bit32                     flag
                  )
{
  dmDeviceData_t    *oneAttachedExpDeviceData = agNULL;
  DM_DBG3(("dmSubReportRemovals: start\n"));
  
  DM_DBG3(("dmSubReportRemovals: flag 0x%x\n", flag));
  if (flag == dmDeviceRemoval)
  {
    oneDeviceData->registered = agFALSE;
  }
  
  if (oneDeviceData->ExpDevice != agNULL)
  {
    DM_DBG3(("dmSubReportRemovals: attached expander case\n"));
    oneAttachedExpDeviceData = oneDeviceData->ExpDevice;
    tddmReportDevice(dmRoot, onePortContext->dmPortContext, &oneDeviceData->dmDeviceInfo, &oneAttachedExpDeviceData->dmDeviceInfo, flag);
  }
  else
  {
    DM_DBG3(("dmSubReportRemovals: NO attached expander case\n"));
    tddmReportDevice(dmRoot, onePortContext->dmPortContext, &oneDeviceData->dmDeviceInfo, agNULL, flag);
  }
 
  
  /* this function is called at the end of discovery; reinitializes oneDeviceData->reported */
  oneDeviceData->reported = agFALSE;
  return;
}


/* called by dmReportChanges() on discovery success */
osGLOBAL void
dmSubReportChanges(
                   dmRoot_t                  *dmRoot,
                   dmIntPortContext_t        *onePortContext,
		   dmDeviceData_t            *oneDeviceData,
                   bit32                     flag
                  )
{
  dmDeviceData_t    *oneAttachedExpDeviceData = agNULL;
  DM_DBG3(("dmSubReportChanges: start\n"));
  
  DM_DBG3(("dmSubReportChanges: flag 0x%x\n", flag));
  if (flag == dmDeviceRemoval)
  {
    oneDeviceData->registered = agFALSE;
  }
  if (oneDeviceData->reported == agFALSE)
  {
    if (oneDeviceData->ExpDevice != agNULL)
    {
      DM_DBG3(("dmSubReportChanges: attached expander case\n"));
      oneAttachedExpDeviceData = oneDeviceData->ExpDevice;
      tddmReportDevice(dmRoot, onePortContext->dmPortContext, &oneDeviceData->dmDeviceInfo, &oneAttachedExpDeviceData->dmDeviceInfo, flag);
    }
    else
    {
      DM_DBG3(("dmSubReportChanges: NO attached expander case\n"));
      tddmReportDevice(dmRoot, onePortContext->dmPortContext, &oneDeviceData->dmDeviceInfo, agNULL, flag);
    }
  }
  else
  {
    DM_DBG3(("dmSubReportChanges: skip; been reported\n"));  
  }
 
  
  /* this function is called at the end of discovery; reinitializes oneDeviceData->reported */
  oneDeviceData->reported = agFALSE;
  return;
}

/* 
 should add or remove be reported per device???
*/
osGLOBAL void
dmReportChanges(
                dmRoot_t                  *dmRoot,
                dmIntPortContext_t        *onePortContext
               )
{
  dmIntRoot_t       *dmIntRoot    = (dmIntRoot_t *)dmRoot->dmData;
  dmIntContext_t    *dmAllShared = (dmIntContext_t *)&dmIntRoot->dmAllShared;
  dmDeviceData_t    *oneDeviceData = agNULL;
  dmList_t          *DeviceListList;
  bit32             added = agFALSE, removed = agFALSE;
//  dmDeviceData_t    *oneAttachedExpDeviceData = agNULL;
  
  DM_DBG3(("dmReportChanges: start\n"));
  
  tddmSingleThreadedEnter(dmRoot, DM_DEVICE_LOCK);
  if (DMLIST_EMPTY(&(dmAllShared->MainDeviceList)))
  {
    tddmSingleThreadedLeave(dmRoot, DM_DEVICE_LOCK);
    DM_DBG3(("dmReportChanges: empty device list\n"));
    return;
  }
  else
  {
    tddmSingleThreadedLeave(dmRoot, DM_DEVICE_LOCK);
  }
  
  DeviceListList = dmAllShared->MainDeviceList.flink;
  while (DeviceListList != &(dmAllShared->MainDeviceList))
  {
    oneDeviceData = DMLIST_OBJECT_BASE(dmDeviceData_t, MainLink, DeviceListList);
    if (oneDeviceData == agNULL)
    {
      DM_DBG1(("dmReportChanges: oneDeviceData is NULL!!!\n"));
      return;
    }    
    DM_DBG3(("dmReportChanges: sasAddrHi 0x%08x \n", oneDeviceData->SASAddressID.sasAddressHi));
    DM_DBG3(("dmReportChanges: sasAddrLo 0x%08x \n", oneDeviceData->SASAddressID.sasAddressLo));
    if ( oneDeviceData->dmPortContext == onePortContext)
    {
      DM_DBG3(("dmReportChanges: right portcontext\n"));
      if (oneDeviceData->SASAddressID.sasAddressHi == onePortContext->sasRemoteAddressHi &&
          oneDeviceData->SASAddressID.sasAddressLo == onePortContext->sasRemoteAddressLo      
         )
      {
        DM_DBG1(("dmReportChanges: keep, not reporting did 0x%x\n", oneDeviceData->id));
        oneDeviceData->valid = agTRUE;
        oneDeviceData->valid2 = agFALSE;
      }      
      else if ( (oneDeviceData->valid == agTRUE) && (oneDeviceData->valid2 == agTRUE) )
      {
        DM_DBG3(("dmReportChanges: same\n"));
        /* reset valid bit */
        oneDeviceData->valid = oneDeviceData->valid2;
        oneDeviceData->valid2 = agFALSE;      
        dmSubReportChanges(dmRoot, onePortContext, oneDeviceData, dmDeviceNoChange);
      }
      else if ( (oneDeviceData->valid == agTRUE) && (oneDeviceData->valid2 == agFALSE) )
      {
        DM_DBG3(("dmReportChanges: removed\n"));
        removed = agTRUE;
        /* reset valid bit */
        oneDeviceData->valid = oneDeviceData->valid2;
        oneDeviceData->valid2 = agFALSE;
      
        onePortContext->RegisteredDevNums--;
        dmSubReportChanges(dmRoot, onePortContext, oneDeviceData, dmDeviceRemoval);
      }
      else if ( (oneDeviceData->valid == agFALSE) && (oneDeviceData->valid2 == agTRUE) )
      {
        DM_DBG3(("dmReportChanges: added\n"));
        added = agTRUE;
        /* reset valid bit */      
        oneDeviceData->valid = oneDeviceData->valid2;
        oneDeviceData->valid2 = agFALSE;
        dmSubReportChanges(dmRoot, onePortContext, oneDeviceData, dmDeviceArrival);
      }
      else
      {
        DM_DBG3(("dmReportChanges: else\n"));
      }
    }
    else
    {
      DM_DBG3(("dmReportChanges: different portcontext\n"));
    }  
    DeviceListList = DeviceListList->flink;
  }
  /*
  osGLOBAL void 
tddmReportDevice(
                 dmRoot_t 		*dmRoot,
                 dmPortContext_t	*dmPortContext,
                 dmDeviceInfo_t		*dmDeviceInfo,
                 dmDeviceInfo_t		*dmExpDeviceInfo,
		 bit32                   flag
		 
                 )

  */
  
  /* arrival or removal at once */
  if (added == agTRUE)
  {
    DM_DBG3(("dmReportChanges: added at the end\n"));
#if 0  /* TBD */  
    ostiInitiatorEvent(
                         tiRoot,
                         onePortContext->tiPortalContext,
                         agNULL,
                         tiIntrEventTypeDeviceChange,
                         tiDeviceArrival,
                         agNULL
                         );
#endif			 
  
  }
  if (removed == agTRUE)
  {
    DM_DBG3(("dmReportChanges: removed at the end\n"));
#if 0  /* TBD */  
    ostiInitiatorEvent(
                       tiRoot,
                       onePortContext->tiPortalContext,
                       agNULL,
                       tiIntrEventTypeDeviceChange,
                       tiDeviceRemoval,
                       agNULL
                       );
#endif  
  }
  
  if (onePortContext->discovery.forcedOK == agTRUE && added == agFALSE && removed == agFALSE)
  {
    DM_DBG3(("dmReportChanges: missed chance to report. forced to report OK\n"));
    onePortContext->discovery.forcedOK = agFALSE;
#if 0  /* TBD */  
    ostiInitiatorEvent(
                       tiRoot,
                       onePortContext->tiPortalContext,
                       agNULL,
                       tiIntrEventTypeDiscovery, 
                       tiDiscOK, 
                       agNULL
                       );
#endif		           
  }
  
  if (added == agFALSE && removed == agFALSE)
  {
    DM_DBG3(("dmReportChanges: the same\n"));
  }
  
  return;
}

osGLOBAL void
dmReportRemovals(
                 dmRoot_t                  *dmRoot,
                 dmIntPortContext_t        *onePortContext,
                 bit32                     flag
                )
{
  dmIntRoot_t       *dmIntRoot    = (dmIntRoot_t *)dmRoot->dmData;
  dmIntContext_t    *dmAllShared = (dmIntContext_t *)&dmIntRoot->dmAllShared;
  dmDeviceData_t    *oneDeviceData = agNULL;
  dmList_t          *DeviceListList;
  bit32             removed = agFALSE;
  
  DM_DBG1(("dmReportRemovals: start\n"));
  
  tddmSingleThreadedEnter(dmRoot, DM_DEVICE_LOCK);
  if (DMLIST_EMPTY(&(dmAllShared->MainDeviceList)))
  {
    tddmSingleThreadedLeave(dmRoot, DM_DEVICE_LOCK);
    DM_DBG3(("dmReportRemovals: empty device list\n"));
    return;
  }
  else
  {
    tddmSingleThreadedLeave(dmRoot, DM_DEVICE_LOCK);
  }
  
  DeviceListList = dmAllShared->MainDeviceList.flink;
  while (DeviceListList != &(dmAllShared->MainDeviceList))
  {
    oneDeviceData = DMLIST_OBJECT_BASE(dmDeviceData_t, MainLink, DeviceListList);
    if (oneDeviceData == agNULL)
    {
      DM_DBG1(("dmReportRemovals: oneDeviceData is NULL!!!\n"));
      return;
    }    
    DM_DBG3(("dmReportRemovals: loop did %d\n", oneDeviceData->id));
    DM_DBG3(("dmReportRemovals: sasAddrHi 0x%08x \n", oneDeviceData->SASAddressID.sasAddressHi));
    DM_DBG3(("dmReportRemovals: sasAddrLo 0x%08x \n", oneDeviceData->SASAddressID.sasAddressLo));
    DM_DBG3(("dmReportRemovals: valid %d\n", oneDeviceData->valid));    
    DM_DBG3(("dmReportRemovals: valid2 %d\n", oneDeviceData->valid2));    
    DM_DBG3(("dmReportRemovals: directlyAttached %d\n", oneDeviceData->directlyAttached));    
    if ( oneDeviceData->dmPortContext == onePortContext)
    {
      DM_DBG3(("dmReportRemovals: right portcontext pid %d\n", onePortContext->id));
      if (oneDeviceData->SASAddressID.sasAddressHi == onePortContext->sasRemoteAddressHi &&
          oneDeviceData->SASAddressID.sasAddressLo == onePortContext->sasRemoteAddressLo      
         )
      {
        DM_DBG1(("dmReportRemovals: keeping\n"));
        oneDeviceData->valid = agTRUE;
        oneDeviceData->valid2 = agFALSE;
      }
      else if (oneDeviceData->valid == agTRUE)
      {    
        DM_DBG3(("dmReportRemovals: removing\n"));
       
        /* notify only reported devices to OS layer*/
        if ( DEVICE_IS_SSP_TARGET(oneDeviceData) || 
             DEVICE_IS_STP_TARGET(oneDeviceData) ||
             DEVICE_IS_SATA_DEVICE(oneDeviceData)
            )
        {
          removed = agTRUE;
        }

        /* all targets except expanders */
        DM_DBG3(("dmReportRemovals: did %d\n", oneDeviceData->id));
        DM_DBG3(("dmReportRemovals: sasAddrHi 0x%08x \n", oneDeviceData->SASAddressID.sasAddressHi));
        DM_DBG3(("dmReportRemovals: sasAddrLo 0x%08x \n", oneDeviceData->SASAddressID.sasAddressLo));
        onePortContext->RegisteredDevNums--;
        dmSubReportRemovals(dmRoot, onePortContext, oneDeviceData, dmDeviceRemoval);

        
        /* reset valid bit */
        oneDeviceData->valid = agFALSE;
        oneDeviceData->valid2 = agFALSE;
      
       
      }
      /* called by port invalid case */
      if (flag == agTRUE)
      {
        oneDeviceData->dmPortContext = agNULL;
      }
      DeviceListList = DeviceListList->flink;
    }    
    else
    {
      if (oneDeviceData->dmPortContext != agNULL)
      {
        DM_DBG3(("dmReportRemovals: different portcontext; oneDeviceData->dmPortContext pid %d oneportcontext pid %d\n", oneDeviceData->dmPortContext->id, onePortContext->id));
      }
      else
      {
        DM_DBG3(("dmReportRemovals: different portcontext; oneDeviceData->dmPortContext pid NULL oneportcontext pid %d\n", onePortContext->id));
      }
      DeviceListList = DeviceListList->flink;
    }  
  }
  
  if (removed == agTRUE)
  {
    DM_DBG3(("dmReportRemovals: removed at the end\n"));
#if 0 /* TBD */      
      ostiInitiatorEvent(
                         tiRoot,
                         onePortContext->tiPortalContext,
                         agNULL,
                         tiIntrEventTypeDeviceChange,
                         tiDeviceRemoval,
                         agNULL
                         );
#endif    
  }
  
  return;
}

osGLOBAL void
dmResetReported(
                dmRoot_t                  *dmRoot,
                dmIntPortContext_t        *onePortContext
               )
{
  dmIntRoot_t       *dmIntRoot    = (dmIntRoot_t *)dmRoot->dmData;
  dmIntContext_t    *dmAllShared = (dmIntContext_t *)&dmIntRoot->dmAllShared;
  dmDeviceData_t    *oneDeviceData = agNULL;
  dmList_t          *DeviceListList;
  
  DM_DBG3(("dmResetReported: start\n"));

  tddmSingleThreadedEnter(dmRoot, DM_DEVICE_LOCK);
  if (DMLIST_EMPTY(&(dmAllShared->MainDeviceList)))
  {
    tddmSingleThreadedLeave(dmRoot, DM_DEVICE_LOCK);
    DM_DBG3(("dmResetReported: empty device list\n"));
    return;
  }
  else
  {
    tddmSingleThreadedLeave(dmRoot, DM_DEVICE_LOCK);
  }

  DeviceListList = dmAllShared->MainDeviceList.flink;
  while (DeviceListList != &(dmAllShared->MainDeviceList))
  {
    oneDeviceData = DMLIST_OBJECT_BASE(dmDeviceData_t, MainLink, DeviceListList);
    if (oneDeviceData == agNULL)
    {
      DM_DBG1(("dmResetReported: oneDeviceData is NULL!!!\n"));
      return;
    }    
    DM_DBG3(("dmResetReported: loop did %d\n", oneDeviceData->id));
    DM_DBG3(("dmResetReported: sasAddrHi 0x%08x \n", oneDeviceData->SASAddressID.sasAddressHi));
    DM_DBG3(("dmResetReported: sasAddrLo 0x%08x \n", oneDeviceData->SASAddressID.sasAddressLo));
    DM_DBG3(("dmResetReported: valid %d\n", oneDeviceData->valid));    
    DM_DBG3(("dmResetReported: valid2 %d\n", oneDeviceData->valid2));    
    DM_DBG3(("dmResetReported: directlyAttached %d\n", oneDeviceData->directlyAttached));    
    if ( oneDeviceData->dmPortContext == onePortContext)
    {
      DM_DBG3(("dmResetReported: right portcontext pid %d\n", onePortContext->id));
      oneDeviceData->reported = agFALSE;
      DeviceListList = DeviceListList->flink;
    }    
    else
    {
      if (oneDeviceData->dmPortContext != agNULL)
      {
        DM_DBG3(("dmResetReported: different portcontext; oneDeviceData->dmPortContext pid %d oneportcontext pid %d\n", oneDeviceData->dmPortContext->id, onePortContext->id));
      }
      else
      {
        DM_DBG3(("dmResetReported: different portcontext; oneDeviceData->dmPortContext pid NULL oneportcontext pid %d\n", onePortContext->id));
      }
      DeviceListList = DeviceListList->flink;
    }  
  }
  
  return;
}	       

/* called on discover failure */
osGLOBAL void
dmDiscoveryInvalidateDevices(
                             dmRoot_t                  *dmRoot,
                             dmIntPortContext_t        *onePortContext
                            )
{
  dmIntRoot_t       *dmIntRoot    = (dmIntRoot_t *)dmRoot->dmData;
  dmIntContext_t    *dmAllShared = (dmIntContext_t *)&dmIntRoot->dmAllShared;
  dmDeviceData_t    *oneDeviceData = agNULL;
  dmList_t          *DeviceListList;
  
  DM_DBG1(("dmDiscoveryInvalidateDevices: start\n"));
  
  tddmSingleThreadedEnter(dmRoot, DM_DEVICE_LOCK);
  if (DMLIST_EMPTY(&(dmAllShared->MainDeviceList)))
  {
    tddmSingleThreadedLeave(dmRoot, DM_DEVICE_LOCK);
    DM_DBG3(("dmDiscoveryInvalidateDevices: empty device list\n"));
    return;
  }
  else
  {
    tddmSingleThreadedLeave(dmRoot, DM_DEVICE_LOCK);
  }
  DeviceListList = dmAllShared->MainDeviceList.flink;
  while (DeviceListList != &(dmAllShared->MainDeviceList))
  {
    oneDeviceData = DMLIST_OBJECT_BASE(dmDeviceData_t, MainLink, DeviceListList);
    if (oneDeviceData == agNULL)
    {
      DM_DBG1(("dmDiscoveryInvalidateDevices: oneDeviceData is NULL!!!\n"));
      return;
    }    
    DM_DBG3(("dmDiscoveryInvalidateDevices: loop did %d\n", oneDeviceData->id));
    DM_DBG3(("dmDiscoveryInvalidateDevices: sasAddrHi 0x%08x \n", oneDeviceData->SASAddressID.sasAddressHi));
    DM_DBG3(("dmDiscoveryInvalidateDevices: sasAddrLo 0x%08x \n", oneDeviceData->SASAddressID.sasAddressLo));
    DM_DBG3(("dmDiscoveryInvalidateDevices: valid %d\n", oneDeviceData->valid));    
    DM_DBG3(("dmDiscoveryInvalidateDevices: valid2 %d\n", oneDeviceData->valid2));    
    DM_DBG3(("dmDiscoveryInvalidateDevices: directlyAttached %d\n", oneDeviceData->directlyAttached));    
    if ( oneDeviceData->dmPortContext == onePortContext)
    {
      DM_DBG3(("dmDiscoveryInvalidateDevices: right portcontext pid %d\n", onePortContext->id));
      if (oneDeviceData->SASAddressID.sasAddressHi == onePortContext->sasRemoteAddressHi &&
          oneDeviceData->SASAddressID.sasAddressLo == onePortContext->sasRemoteAddressLo      
         )
      {
        DM_DBG1(("dmDiscoveryInvalidateDevices: keeping\n"));
        oneDeviceData->valid = agTRUE;
        oneDeviceData->valid2 = agFALSE;
      }
      else
      {            
        oneDeviceData->valid = agFALSE;
        oneDeviceData->valid2 = agFALSE;
        oneDeviceData->registered = agFALSE;
        oneDeviceData->reported = agFALSE;
        /* all targets other than expanders */
        DM_DBG3(("dmDiscoveryInvalidateDevices: did %d\n", oneDeviceData->id));
        DM_DBG3(("dmDiscoveryInvalidateDevices: sasAddrHi 0x%08x \n", oneDeviceData->SASAddressID.sasAddressHi));
        DM_DBG3(("dmDiscoveryInvalidateDevices: sasAddrLo 0x%08x \n", oneDeviceData->SASAddressID.sasAddressLo));
        onePortContext->RegisteredDevNums--;
      }
      DeviceListList = DeviceListList->flink;
    }    
    else
    {
      if (oneDeviceData->dmPortContext != agNULL)
      {
        DM_DBG3(("dmDiscoveryInvalidateDevices: different portcontext; oneDeviceData->dmPortContext pid %d oneportcontext pid %d\n", oneDeviceData->dmPortContext->id, onePortContext->id));
      }
      else
      {
        DM_DBG3(("dmDiscoveryInvalidateDevices: different portcontext; oneDeviceData->dmPortContext pid NULL oneportcontext pid %d\n", onePortContext->id));
      }
      DeviceListList = DeviceListList->flink;
    }  
  }
  
  return;
}


/* 
 should DM report the device removal to TDM on an error case?
 or
 DM simply removes the devices
 For now, the second option.
*/
osGLOBAL void
dmDiscoveryErrorRemovals(
                         dmRoot_t                  *dmRoot,
                         dmIntPortContext_t        *onePortContext
                        )
{
  dmIntRoot_t       *dmIntRoot    = (dmIntRoot_t *)dmRoot->dmData;
  dmIntContext_t    *dmAllShared = (dmIntContext_t *)&dmIntRoot->dmAllShared;
  dmDeviceData_t    *oneDeviceData = agNULL;
  dmList_t          *DeviceListList;
  
  DM_DBG1(("dmDiscoveryErrorRemovals: start\n"));
  
  tddmSingleThreadedEnter(dmRoot, DM_DEVICE_LOCK);
  if (DMLIST_EMPTY(&(dmAllShared->MainDeviceList)))
  {
    tddmSingleThreadedLeave(dmRoot, DM_DEVICE_LOCK);
    DM_DBG3(("dmDiscoveryErrorRemovals: empty device list\n"));
    return;
  }
  else
  {
    tddmSingleThreadedLeave(dmRoot, DM_DEVICE_LOCK);
  }
  DeviceListList = dmAllShared->MainDeviceList.flink;
  while (DeviceListList != &(dmAllShared->MainDeviceList))
  {
    oneDeviceData = DMLIST_OBJECT_BASE(dmDeviceData_t, MainLink, DeviceListList);
    if (oneDeviceData == agNULL)
    {
      DM_DBG1(("dmDiscoveryErrorRemovals: oneDeviceData is NULL!!!\n"));
      return;
    }    
    DM_DBG3(("dmDiscoveryErrorRemovals: loop did %d\n", oneDeviceData->id));
    DM_DBG3(("dmDiscoveryErrorRemovals: sasAddrHi 0x%08x \n", oneDeviceData->SASAddressID.sasAddressHi));
    DM_DBG3(("dmDiscoveryErrorRemovals: sasAddrLo 0x%08x \n", oneDeviceData->SASAddressID.sasAddressLo));
    DM_DBG3(("dmDiscoveryErrorRemovals: valid %d\n", oneDeviceData->valid));    
    DM_DBG3(("dmDiscoveryErrorRemovals: valid2 %d\n", oneDeviceData->valid2));    
    DM_DBG3(("dmDiscoveryErrorRemovals: directlyAttached %d\n", oneDeviceData->directlyAttached));    
    if ( oneDeviceData->dmPortContext == onePortContext)
    {
      DM_DBG3(("dmDiscoveryErrorRemovals: right portcontext pid %d\n", onePortContext->id));
      if (oneDeviceData->SASAddressID.sasAddressHi == onePortContext->sasRemoteAddressHi &&
          oneDeviceData->SASAddressID.sasAddressLo == onePortContext->sasRemoteAddressLo      
         )
      {
        DM_DBG1(("dmDiscoveryErrorRemovals: keeping\n"));
        oneDeviceData->valid = agTRUE;
        oneDeviceData->valid2 = agFALSE;
      }
      else
      {            
        oneDeviceData->valid = agFALSE;
        oneDeviceData->valid2 = agFALSE;
      
        /* all targets other than expanders */
        DM_DBG3(("dmDiscoveryErrorRemovals: did %d\n", oneDeviceData->id));
        DM_DBG3(("dmDiscoveryErrorRemovals: sasAddrHi 0x%08x \n", oneDeviceData->SASAddressID.sasAddressHi));
        DM_DBG3(("dmDiscoveryErrorRemovals: sasAddrLo 0x%08x \n", oneDeviceData->SASAddressID.sasAddressLo));
        onePortContext->RegisteredDevNums--;
        dmSubReportRemovals(dmRoot, onePortContext, oneDeviceData, dmDeviceRemoval);
     
      }
      DeviceListList = DeviceListList->flink;
    }    
    else
    {
      if (oneDeviceData->dmPortContext != agNULL)
      {
        DM_DBG3(("dmDiscoveryErrorRemovals: different portcontext; oneDeviceData->dmPortContext pid %d oneportcontext pid %d\n", oneDeviceData->dmPortContext->id, onePortContext->id));
      }
      else
      {
        DM_DBG3(("dmDiscoveryErrorRemovals: different portcontext; oneDeviceData->dmPortContext pid NULL oneportcontext pid %d\n", onePortContext->id));
      }
      DeviceListList = DeviceListList->flink;
    }  
  }
  
  return;
}

/* move from dmAllShared->mainExpanderList to dmAllShared->freeExpanderList */
osGLOBAL void
dmDiscoveryExpanderCleanUp(
                           dmRoot_t                  *dmRoot,
                           dmIntPortContext_t        *onePortContext
                          )
{
  dmIntRoot_t       *dmIntRoot    = (dmIntRoot_t *)dmRoot->dmData;
  dmIntContext_t    *dmAllShared = (dmIntContext_t *)&dmIntRoot->dmAllShared;
  dmExpander_t      *oneExpander = agNULL;
  dmList_t          *ExpanderList = agNULL;
  dmDeviceData_t    *oneDeviceData = agNULL;
  
  DM_DBG3(("dmDiscoveryExpanderCleanUp: start\n"));
  /*
    be sure to call
    osGLOBAL void
    dmExpanderDeviceDataReInit(
                           dmRoot_t 	    *dmRoot, 
                           dmExpander_t     *oneExpander
                          );

  */
  
  tddmSingleThreadedEnter(dmRoot, DM_EXPANDER_LOCK);
  if (!DMLIST_EMPTY(&(dmAllShared->mainExpanderList)))
  {
    tddmSingleThreadedLeave(dmRoot, DM_EXPANDER_LOCK);
    ExpanderList = dmAllShared->mainExpanderList.flink;
    while (ExpanderList != &(dmAllShared->mainExpanderList))
    {
      oneExpander = DMLIST_OBJECT_BASE(dmExpander_t, linkNode, ExpanderList);
      if (oneExpander == agNULL)
      {
        DM_DBG1(("dmDiscoveryExpanderCleanUp: oneExpander is NULL!!!\n"));
        return;
      }    
      oneDeviceData = oneExpander->dmDevice;
      DM_DBG3(("dmDiscoveryExpanderCleanUp: sasAddrHi 0x%08x \n", oneDeviceData->SASAddressID.sasAddressHi));
      DM_DBG3(("dmDiscoveryExpanderCleanUp: sasAddrLo 0x%08x \n", oneDeviceData->SASAddressID.sasAddressLo));
      if ( oneDeviceData->dmPortContext == onePortContext)
      {
        dmExpanderDeviceDataReInit(dmRoot, oneExpander);
        tddmSingleThreadedEnter(dmRoot, DM_EXPANDER_LOCK);
        DMLIST_DEQUEUE_THIS(&(oneExpander->linkNode));
        DMLIST_ENQUEUE_AT_TAIL(&(oneExpander->linkNode), &(dmAllShared->freeExpanderList));
        
        if (DMLIST_EMPTY(&(dmAllShared->mainExpanderList)))
        {
          tddmSingleThreadedLeave(dmRoot, DM_EXPANDER_LOCK);
          break;
        }
        else
        {
          tddmSingleThreadedLeave(dmRoot, DM_EXPANDER_LOCK);   
        }
        ExpanderList = dmAllShared->mainExpanderList.flink;
      }
      else
      {
        ExpanderList = ExpanderList->flink;
      }   
    }
  }
  else
  {
    tddmSingleThreadedLeave(dmRoot, DM_EXPANDER_LOCK);
    DM_DBG3(("dmDiscoveryExpanderCleanUp: empty mainExpanderList\n")); 
  }  
  return;
  
}			


/* moves all devices from dmAllShared->MainDeviceList to dmAllShared->FreeDeviceList */
osGLOBAL void
dmDiscoveryDeviceCleanUp(
                         dmRoot_t                  *dmRoot,
                         dmIntPortContext_t        *onePortContext
                        )
{
  dmIntRoot_t       *dmIntRoot    = (dmIntRoot_t *)dmRoot->dmData;
  dmIntContext_t    *dmAllShared = (dmIntContext_t *)&dmIntRoot->dmAllShared;
  dmDeviceData_t    *oneDeviceData = agNULL;
  dmList_t          *DeviceListList;
  
  DM_DBG3(("dmDiscoveryDeviceCleanUp: start\n"));
  
  tddmSingleThreadedEnter(dmRoot, DM_DEVICE_LOCK);
  if (!DMLIST_EMPTY(&(dmAllShared->MainDeviceList)))
  {
    tddmSingleThreadedLeave(dmRoot, DM_DEVICE_LOCK);
    DeviceListList = dmAllShared->MainDeviceList.flink;
    while (DeviceListList != &(dmAllShared->MainDeviceList))
    {
      oneDeviceData = DMLIST_OBJECT_BASE(dmDeviceData_t, MainLink, DeviceListList);
      if (oneDeviceData == agNULL)
      {
        DM_DBG1(("dmDiscoveryDeviceCleanUp: oneDeviceData is NULL!!!\n"));
        return;
      }    
      DM_DBG3(("dmDiscoveryDeviceCleanUp: sasAddrHi 0x%08x \n", oneDeviceData->SASAddressID.sasAddressHi));
      DM_DBG3(("dmDiscoveryDeviceCleanUp: sasAddrLo 0x%08x \n", oneDeviceData->SASAddressID.sasAddressLo));
      if ( oneDeviceData->dmPortContext == onePortContext)
      {
        dmDeviceDataReInit(dmRoot, oneDeviceData);
        tddmSingleThreadedEnter(dmRoot, DM_DEVICE_LOCK);
        DMLIST_DEQUEUE_THIS(&(oneDeviceData->MainLink));
        DMLIST_ENQUEUE_AT_TAIL(&(oneDeviceData->FreeLink), &(dmAllShared->FreeDeviceList));
        
        if (DMLIST_EMPTY(&(dmAllShared->MainDeviceList)))
        {
          tddmSingleThreadedLeave(dmRoot, DM_DEVICE_LOCK);
          break;
        }
        else
        {
          tddmSingleThreadedLeave(dmRoot, DM_DEVICE_LOCK);   
        }
	onePortContext->RegisteredDevNums--;
        DeviceListList = dmAllShared->MainDeviceList.flink;
      }
      else
      {
        DeviceListList = DeviceListList->flink;
      }   
    }
  }
  else
  {
    tddmSingleThreadedLeave(dmRoot, DM_DEVICE_LOCK);
    DM_DBG3(("dmDiscoveryDeviceCleanUp: empty MainDeviceList\n")); 
  }  
  return;
}			
			


osGLOBAL void
dmDumpAllExp(
             dmRoot_t                  *dmRoot,
             dmIntPortContext_t        *onePortContext,
             dmExpander_t              *oneExpander
            )
{
  DM_DBG3(("dmDumpAllExp: start\n"));
  return;
}


osGLOBAL void
dmDumpAllUpExp(
               dmRoot_t                  *dmRoot,
               dmIntPortContext_t        *onePortContext,
               dmExpander_t              *oneExpander
              )
{
  DM_DBG3(("dmDumpAllUpExp: start\n"));
  return;
}
		    		    
osGLOBAL void
dmDumpAllFreeExp(
                 dmRoot_t                  *dmRoot
                )
{
  DM_DBG3(("dmDumpAllFreeExp: start\n"));
  return;
}

osGLOBAL void
dmDumpAllMainExp(
                 dmRoot_t                 *dmRoot,
                 dmIntPortContext_t       *onePortContext
                )
{
  dmIntRoot_t        *dmIntRoot    = (dmIntRoot_t *)dmRoot->dmData;
  dmIntContext_t     *dmAllShared = (dmIntContext_t *)&dmIntRoot->dmAllShared;
  dmList_t           *ExpanderList;
  dmExpander_t       *tempExpander;
  
  DM_DBG3(("dmDumpAllMainExp: start\n"));
  
  tddmSingleThreadedEnter(dmRoot, DM_EXPANDER_LOCK);
  if (DMLIST_EMPTY(&(dmAllShared->mainExpanderList)))
  {
    DM_DBG3(("dmDumpAllMainExp: empty discoveringExpanderList\n"));
    tddmSingleThreadedLeave(dmRoot, DM_EXPANDER_LOCK);
    return;
  }
  else
  {
    tddmSingleThreadedLeave(dmRoot, DM_EXPANDER_LOCK);
  }
  
  ExpanderList = dmAllShared->mainExpanderList.flink;
  while (ExpanderList != &(dmAllShared->mainExpanderList))
  {
    tempExpander = DMLIST_OBJECT_BASE(dmExpander_t, linkNode, ExpanderList);
    if (tempExpander == agNULL)
    {
      DM_DBG1(("dmDumpAllMainExp: tempExpander is NULL!!!\n"));
      return;
    }    
    DM_DBG3(("dmDumpAllMainExp: expander id %d\n", tempExpander->id));
    DM_DBG3(("dmDumpAllMainExp: exp addrHi 0x%08x\n", tempExpander->dmDevice->SASAddressID.sasAddressHi));
    DM_DBG3(("dmDumpAllMainExp: exp addrLo 0x%08x\n", tempExpander->dmDevice->SASAddressID.sasAddressLo));
    if ((tempExpander->dmDevice->dmPortContext == onePortContext)
       )
    {
      DM_DBG3(("dmDumpAllMainExp: found expander id %d\n", tempExpander->id));
      DM_DBG3(("dmDumpAllMainExp: found exp addrHi 0x%08x\n", tempExpander->dmDevice->SASAddressID.sasAddressHi));
      DM_DBG3(("dmDumpAllMainExp: found exp addrLo 0x%08x\n", tempExpander->dmDevice->SASAddressID.sasAddressLo));
    }       	
    ExpanderList = ExpanderList->flink;
  }
  return;
}


osGLOBAL void
dmDumpAllMainDevice(
                 dmRoot_t                 *dmRoot,
                 dmIntPortContext_t       *onePortContext
                )
{
  dmIntRoot_t        *dmIntRoot    = (dmIntRoot_t *)dmRoot->dmData;
  dmIntContext_t     *dmAllShared = (dmIntContext_t *)&dmIntRoot->dmAllShared;
  dmDeviceData_t     *oneDeviceData = agNULL;
  dmList_t           *DeviceListList;
  bit32              total = 0, port_total = 0;
  
  DM_DBG3(("dmDumpAllMainDevice: start\n"));
  
  tddmSingleThreadedEnter(dmRoot, DM_DEVICE_LOCK);
  if (DMLIST_EMPTY(&(dmAllShared->MainDeviceList)))
  {
    DM_DBG3(("dmDumpAllMainDevice: empty discoveringExpanderList\n"));
    tddmSingleThreadedLeave(dmRoot, DM_DEVICE_LOCK);
    return;
  }
  else
  {
    tddmSingleThreadedLeave(dmRoot, DM_DEVICE_LOCK);
  }
  
  DeviceListList = dmAllShared->MainDeviceList.flink;
  while (DeviceListList != &(dmAllShared->MainDeviceList))
  {
    oneDeviceData = DMLIST_OBJECT_BASE(dmDeviceData_t, MainLink, DeviceListList);
    if (oneDeviceData == agNULL)
    {
      DM_DBG3(("dmDumpAllMainDevice: oneDeviceData is NULL!!!\n"));
      return;
    }    
    DM_DBG3(("dmDumpAllMainDevice: oneDeviceData id %d\n", oneDeviceData->id));
    DM_DBG3(("dmDumpAllMainDevice: addrHi 0x%08x\n", oneDeviceData->SASAddressID.sasAddressHi));
    DM_DBG3(("dmDumpAllMainDevice: addrLo 0x%08x\n", oneDeviceData->SASAddressID.sasAddressLo));
    total++;
    if ((oneDeviceData->dmPortContext == onePortContext)
       )
    {
      DM_DBG3(("dmDumpAllMainDevice: found oneDeviceData id %d\n", oneDeviceData->id));
      DM_DBG3(("dmDumpAllMainDevice: found addrHi 0x%08x\n", oneDeviceData->SASAddressID.sasAddressHi));
      DM_DBG3(("dmDumpAllMainDevice: found addrLo 0x%08x\n", oneDeviceData->SASAddressID.sasAddressLo));
      port_total++;
    }       	
    DeviceListList = DeviceListList->flink;
  }
  DM_DBG3(("dmDumpAllMainDevice: total %d port_totaol %d\n", total, port_total));
  
  return;
}



osGLOBAL dmDeviceData_t *
dmAddSASToSharedcontext(
                         dmRoot_t              *dmRoot,
                         dmIntPortContext_t    *onePortContext,
                         dmSASSubID_t          *dmSASSubID,
                         dmDeviceData_t        *oneExpDeviceData,
                         bit8                   phyID
                        )
{
  dmIntRoot_t       *dmIntRoot    = (dmIntRoot_t *)dmRoot->dmData;
  dmIntContext_t    *dmAllShared = (dmIntContext_t *)&dmIntRoot->dmAllShared;
  dmDeviceData_t    *oneDeviceData = agNULL;
  dmList_t          *DeviceListList;
  bit32             new_device = agTRUE;
  
  
  DM_DBG3(("dmAddSASToSharedcontext: start\n"));
  DM_DBG3(("dmAddSASToSharedcontext: oneportContext ID %d\n", onePortContext->id));
  
  if (oneExpDeviceData != agNULL)
  {
    DM_DBG3(("dmAddSASToSharedcontext: oneExpDeviceData sasAddressHi 0x%08x sasAddressLo 0x%08x\n", 
    oneExpDeviceData->SASAddressID.sasAddressHi, oneExpDeviceData->SASAddressID.sasAddressLo));       
  }
  else
  {
    DM_DBG3(("dmAddSASToSharedcontext: oneExpDeviceData is NULL\n"));
  }        
  /* find a device's existence */
  DeviceListList = dmAllShared->MainDeviceList.flink;
  while (DeviceListList != &(dmAllShared->MainDeviceList))
  {
    oneDeviceData = DMLIST_OBJECT_BASE(dmDeviceData_t, MainLink, DeviceListList);
    if (oneDeviceData == agNULL)
    {
      DM_DBG1(("dmAddSASToSharedcontext: oneDeviceData is NULL!!!\n"));
      return agNULL;
    }    
    if ((oneDeviceData->SASAddressID.sasAddressHi == dmSASSubID->sasAddressHi) &&
        (oneDeviceData->SASAddressID.sasAddressLo == dmSASSubID->sasAddressLo) &&
        (oneDeviceData->dmPortContext == onePortContext)
        )
    {
      DM_DBG3(("dmAddSASToSharedcontext: pid %d did %d\n", onePortContext->id, oneDeviceData->id));
      new_device = agFALSE;
      break;
    }
    DeviceListList = DeviceListList->flink;
  }
  
  /* new device */
  if (new_device == agTRUE)
  {
    DM_DBG3(("dmAddSASToSharedcontext: new device\n"));
    DM_DBG3(("dmAddSASToSharedcontext: sasAddressHi 0x%08x sasAddressLo 0x%08x\n", 
    dmSASSubID->sasAddressHi, dmSASSubID->sasAddressLo));         
    tddmSingleThreadedEnter(dmRoot, DM_DEVICE_LOCK);
    if (!DMLIST_NOT_EMPTY(&(dmAllShared->FreeDeviceList)))
    {
      tddmSingleThreadedLeave(dmRoot, DM_DEVICE_LOCK);
      DM_DBG1(("dmAddSASToSharedcontext: empty DeviceData FreeLink\n"));
      dmDumpAllMainDevice(dmRoot, onePortContext); 
      return agNULL;
    }
      
    DMLIST_DEQUEUE_FROM_HEAD(&DeviceListList, &(dmAllShared->FreeDeviceList));
    tddmSingleThreadedLeave(dmRoot, DM_DEVICE_LOCK);
    oneDeviceData = DMLIST_OBJECT_BASE(dmDeviceData_t, FreeLink, DeviceListList);

    if (oneDeviceData != agNULL)
    {
      DM_DBG3(("dmAddSASToSharedcontext: oneDeviceData %p pid %d did %d\n", oneDeviceData, onePortContext->id, oneDeviceData->id));

      onePortContext->Count++;
      oneDeviceData->dmRoot = dmRoot;
      /* saving sas address */
      oneDeviceData->SASAddressID.sasAddressLo = dmSASSubID->sasAddressLo;
      oneDeviceData->SASAddressID.sasAddressHi = dmSASSubID->sasAddressHi;
      oneDeviceData->initiator_ssp_stp_smp = dmSASSubID->initiator_ssp_stp_smp;
      oneDeviceData->target_ssp_stp_smp = dmSASSubID->target_ssp_stp_smp;
      oneDeviceData->dmPortContext = onePortContext;
      /* handles both SAS target and STP-target, SATA-device */
      if (!DEVICE_IS_SATA_DEVICE(oneDeviceData) && !DEVICE_IS_STP_TARGET(oneDeviceData))
      {
        oneDeviceData->DeviceType = DM_SAS_DEVICE;
      }
      else
      {
        oneDeviceData->DeviceType = DM_SATA_DEVICE;
      }

      if (oneExpDeviceData != agNULL)
      {
        oneDeviceData->ExpDevice = oneExpDeviceData;
      }      
    
      /* set phyID only when it has initial value of 0xFF */
      if (oneDeviceData->phyID == 0xFF)
      {
        oneDeviceData->phyID = phyID;
      }
      /* incremental discovery */
      /* add device to incremental-related link. Report using this link 
         when incremental discovery is done */
      if (onePortContext->DiscoveryState == DM_DSTATE_NOT_STARTED)
      {
        DM_DBG3(("dmAddSASToSharedcontext: DM_DSTATE_NOT_STARTED\n"));
        DM_DBG3(("dmAddSASToSharedcontext: sasAddrHi 0x%08x \n", oneDeviceData->SASAddressID.sasAddressHi));
        DM_DBG3(("dmAddSASToSharedcontext: sasAddrLo 0x%08x \n", oneDeviceData->SASAddressID.sasAddressLo));
        oneDeviceData->valid = agTRUE;
      }
      else
      {
        if (onePortContext->discovery.type == DM_DISCOVERY_OPTION_INCREMENTAL_START)
        {
          DM_DBG3(("dmAddSASToSharedcontext: incremental discovery\n"));
          DM_DBG3(("dmAddSASToSharedcontext: sasAddrHi 0x%08x \n", oneDeviceData->SASAddressID.sasAddressHi));
          DM_DBG3(("dmAddSASToSharedcontext: sasAddrLo 0x%08x \n", oneDeviceData->SASAddressID.sasAddressLo));
          oneDeviceData->valid2 = agTRUE;
        }
        else
        {
          DM_DBG3(("dmAddSASToSharedcontext: full discovery\n"));
          DM_DBG3(("dmAddSASToSharedcontext: sasAddrHi 0x%08x \n", oneDeviceData->SASAddressID.sasAddressHi));
          DM_DBG3(("dmAddSASToSharedcontext: sasAddrLo 0x%08x \n", oneDeviceData->SASAddressID.sasAddressLo));
         oneDeviceData->valid = agTRUE;
        }
      }
      /* add the devicedata to the portcontext */    
      tddmSingleThreadedEnter(dmRoot, DM_DEVICE_LOCK);
      DMLIST_ENQUEUE_AT_TAIL(&(oneDeviceData->MainLink), &(dmAllShared->MainDeviceList));
      tddmSingleThreadedLeave(dmRoot, DM_DEVICE_LOCK);
      DM_DBG3(("dmAddSASToSharedcontext: one case pid %d did %d \n", onePortContext->id, oneDeviceData->id));
      DM_DBG3(("dmAddSASToSharedcontext: new case pid %d did %d phyID %d\n", onePortContext->id, oneDeviceData->id, oneDeviceData->phyID));
      }
  }
  else /* old device */
  {
    DM_DBG3(("dmAddSASToSharedcontext: old device\n"));
    DM_DBG3(("dmAddSASToSharedcontext: oneDeviceData %p did %d\n", oneDeviceData, oneDeviceData->id));
    DM_DBG3(("dmAddSASToSharedcontext: sasAddressHi 0x%08x sasAddressLo 0x%08x\n", 
    dmSASSubID->sasAddressHi, dmSASSubID->sasAddressLo));         

    oneDeviceData->dmRoot = dmRoot;
    /* saving sas address */
    oneDeviceData->SASAddressID.sasAddressLo = dmSASSubID->sasAddressLo;
    oneDeviceData->SASAddressID.sasAddressHi = dmSASSubID->sasAddressHi;
    oneDeviceData->initiator_ssp_stp_smp = dmSASSubID->initiator_ssp_stp_smp;
    oneDeviceData->target_ssp_stp_smp = dmSASSubID->target_ssp_stp_smp;
    oneDeviceData->dmPortContext = onePortContext;
    /* handles both SAS target and STP-target, SATA-device */
    if (!DEVICE_IS_SATA_DEVICE(oneDeviceData) && !DEVICE_IS_STP_TARGET(oneDeviceData))
    {
      oneDeviceData->DeviceType = DM_SAS_DEVICE;
    }
    else
    {
      oneDeviceData->DeviceType = DM_SATA_DEVICE;
    }
    
    if (oneExpDeviceData != agNULL)
    {
      oneDeviceData->ExpDevice = oneExpDeviceData;
    }      
    
    /* set phyID only when it has initial value of 0xFF */
    if (oneDeviceData->phyID == 0xFF)
    {
      oneDeviceData->phyID = phyID;
    }
    
    if (onePortContext->DiscoveryState == DM_DSTATE_NOT_STARTED)
    {
      DM_DBG3(("dmAddSASToSharedcontext: DM_DSTATE_NOT_STARTED\n"));
      DM_DBG3(("dmAddSASToSharedcontext: sasAddrHi 0x%08x \n", oneDeviceData->SASAddressID.sasAddressHi));
      DM_DBG3(("dmAddSASToSharedcontext: sasAddrLo 0x%08x \n", oneDeviceData->SASAddressID.sasAddressLo));
      oneDeviceData->valid = agTRUE;
    }
    else
    {
      if (onePortContext->discovery.type == DM_DISCOVERY_OPTION_INCREMENTAL_START)
      {
        DM_DBG3(("dmAddSASToSharedcontext: incremental discovery\n"));
        DM_DBG3(("dmAddSASToSharedcontext: sasAddrHi 0x%08x \n", oneDeviceData->SASAddressID.sasAddressHi));
        DM_DBG3(("dmAddSASToSharedcontext: sasAddrLo 0x%08x \n", oneDeviceData->SASAddressID.sasAddressLo));
        oneDeviceData->valid2 = agTRUE;
      }
      else
      {
        DM_DBG3(("dmAddSASToSharedcontext: full discovery\n"));
        DM_DBG3(("dmAddSASToSharedcontext: sasAddrHi 0x%08x \n", oneDeviceData->SASAddressID.sasAddressHi));
        DM_DBG3(("dmAddSASToSharedcontext: sasAddrLo 0x%08x \n", oneDeviceData->SASAddressID.sasAddressLo));
        oneDeviceData->valid = agTRUE;
      }
    }
    DM_DBG3(("dmAddSASToSharedcontext: old case pid %d did %d phyID %d\n", onePortContext->id, oneDeviceData->id, oneDeviceData->phyID));
     
  }
  return oneDeviceData;
}

/* no checking of valid and valid2 */
osGLOBAL dmDeviceData_t *
dmDeviceFind(
             dmRoot_t            *dmRoot,
             dmIntPortContext_t  *onePortContext,
             bit32               sasAddrHi,
             bit32               sasAddrLo
            )
{
  dmIntRoot_t               *dmIntRoot    = (dmIntRoot_t *)dmRoot->dmData;
  dmIntContext_t            *dmAllShared = (dmIntContext_t *)&dmIntRoot->dmAllShared;
  dmDeviceData_t            *oneDeviceData = agNULL;
  dmList_t                  *DeviceListList;
  bit32                     found = agFALSE;
  
  DM_DBG3(("dmDeviceFind: start\n"));
  /* find a device's existence */
  DeviceListList = dmAllShared->MainDeviceList.flink;
  
  while (DeviceListList != &(dmAllShared->MainDeviceList))
  {
    oneDeviceData = DMLIST_OBJECT_BASE(dmDeviceData_t, MainLink, DeviceListList);
    if (oneDeviceData == agNULL)
    {
      DM_DBG1(("dmDeviceFind: oneDeviceData is NULL!!!\n"));
      return agNULL;
    }    
    if ((oneDeviceData->SASAddressID.sasAddressHi == sasAddrHi) &&
        (oneDeviceData->SASAddressID.sasAddressLo == sasAddrLo) &&
//        (oneDeviceData->valid == agTRUE) &&
        (oneDeviceData->dmPortContext == onePortContext)
        )
    {
      DM_DBG3(("dmDeviceFind: Found pid %d did %d\n", onePortContext->id, oneDeviceData->id));
      DM_DBG3(("dmDeviceFind: sasAddressHi 0x%08x\n", oneDeviceData->SASAddressID.sasAddressHi));         
      DM_DBG3(("dmDeviceFind: sasAddressLo 0x%08x\n", oneDeviceData->SASAddressID.sasAddressLo));
      found = agTRUE;
      break;
    }
    DeviceListList = DeviceListList->flink;
  }
  
  if (found == agFALSE)
  {
    DM_DBG3(("dmDeviceFind: end returning NULL\n"));
    return agNULL;
  }
  else
  {
    DM_DBG3(("dmDeviceFind: end returning NOT NULL\n"));
    return oneDeviceData;
  }
  
}	    


osGLOBAL void                          
dmBCTimer(
          dmRoot_t                 *dmRoot,
          dmIntPortContext_t       *onePortContext
         )
{
  dmIntRoot_t       *dmIntRoot    = (dmIntRoot_t *)dmRoot->dmData;
  dmIntContext_t    *dmAllShared = (dmIntContext_t *)&dmIntRoot->dmAllShared;
  dmDiscovery_t     *discovery;
  
  DM_DBG3(("dmBCTimer: start\n"));
  
  discovery = &(onePortContext->discovery);
  
  tddmSingleThreadedEnter(dmRoot, DM_TIMER_LOCK);
  if (discovery->BCTimer.timerRunning == agTRUE)
  {
    tddmSingleThreadedLeave(dmRoot, DM_TIMER_LOCK);
    dmKillTimer(
                dmRoot,
                &discovery->BCTimer
               );
  }
  else
  {
    tddmSingleThreadedLeave(dmRoot, DM_TIMER_LOCK);
  }
  
  if (onePortContext->valid == agTRUE)
  {
    dmSetTimerRequest(
                      dmRoot,
                      &discovery->BCTimer,
                      BC_TIMER_VALUE/dmAllShared->usecsPerTick,
                      dmBCTimerCB,
                      onePortContext,
                      agNULL,
                      agNULL
                      );
  
    dmAddTimer(
               dmRoot,
               &dmAllShared->timerlist, 
               &discovery->BCTimer
              );
  
  }
  
  
  return;
}	 


osGLOBAL void
dmBCTimerCB(
              dmRoot_t    * dmRoot, 
              void        * timerData1,
              void        * timerData2,
              void        * timerData3
              )
{
  dmIntPortContext_t        *onePortContext;
  dmDiscovery_t             *discovery;
  
  DM_DBG3(("dmBCTimerCB: start\n"));
  
  onePortContext = (dmIntPortContext_t *)timerData1;
  discovery = &(onePortContext->discovery);

  tddmSingleThreadedEnter(dmRoot, DM_TIMER_LOCK);
  if (discovery->BCTimer.timerRunning == agTRUE)
  {
    tddmSingleThreadedLeave(dmRoot, DM_TIMER_LOCK);
    dmKillTimer(
               dmRoot,
               &discovery->BCTimer
               );
  }       
  else
  {
    tddmSingleThreadedLeave(dmRoot, DM_TIMER_LOCK);
  }
  
  discovery->ResetTriggerred = agFALSE;
  
  if (onePortContext->valid == agTRUE)
  {
    dmDiscover(dmRoot,
               onePortContext->dmPortContext,
               DM_DISCOVERY_OPTION_INCREMENTAL_START
               );
  }  
  return;
}	      

/* discovery related SMP timers */
osGLOBAL void
dmDiscoverySMPTimer(dmRoot_t                 *dmRoot,
                    dmIntPortContext_t       *onePortContext,
                    bit32                    functionCode,
                    dmSMPRequestBody_t       *dmSMPRequestBody
                   )
{
  dmIntRoot_t       *dmIntRoot    = (dmIntRoot_t *)dmRoot->dmData;
  dmIntContext_t    *dmAllShared = (dmIntContext_t *)&dmIntRoot->dmAllShared;
  dmDiscovery_t     *discovery;
  
  DM_DBG3(("dmDiscoverySMPTimer: start\n"));
  DM_DBG3(("dmDiscoverySMPTimer: pid %d SMPFn 0x%x\n", onePortContext->id, functionCode));
  
  /* start the SMP timer which works as SMP application timer */
  discovery = &(onePortContext->discovery);
  
  tddmSingleThreadedEnter(dmRoot, DM_TIMER_LOCK);
  if (discovery->DiscoverySMPTimer.timerRunning == agTRUE)
  {
    tddmSingleThreadedLeave(dmRoot, DM_TIMER_LOCK);
    dmKillTimer(
              dmRoot,
              &discovery->DiscoverySMPTimer
              );
  }
  else
  {
    tddmSingleThreadedLeave(dmRoot, DM_TIMER_LOCK);
  }
  
  
  dmSetTimerRequest(
                    dmRoot,
                    &discovery->DiscoverySMPTimer,
                    SMP_TIMER_VALUE/dmAllShared->usecsPerTick,
                    dmDiscoverySMPTimerCB,
                    onePortContext,
                    dmSMPRequestBody,
                    agNULL
                   );
  
  dmAddTimer (
              dmRoot,
              &dmAllShared->timerlist, 
              &discovery->DiscoverySMPTimer
              );
  
  return;
}


osGLOBAL void
dmDiscoverySMPTimerCB(
                        dmRoot_t    * dmRoot, 
                        void        * timerData1,
                        void        * timerData2,
                        void        * timerData3
                       )
{
  agsaRoot_t                  *agRoot;
  dmIntPortContext_t          *onePortContext;
  bit8                        SMPFunction;  
#ifndef DIRECT_SMP
  dmSMPFrameHeader_t          *dmSMPFrameHeader;
  bit8                        smpHeader[4];
#endif  
  dmSMPRequestBody_t          *dmSMPRequestBody;
  dmDiscovery_t               *discovery;
  dmDeviceData_t              *oneDeviceData;
  agsaIORequest_t             *agAbortIORequest = agNULL;  
  agsaIORequest_t             *agToBeAbortIORequest = agNULL;  
  dmIntRoot_t                 *dmIntRoot    = (dmIntRoot_t *)dmRoot->dmData;
  dmIntContext_t              *dmAllShared = (dmIntContext_t *)&dmIntRoot->dmAllShared;
  dmExpander_t                *oneExpander = agNULL;
  dmSMPRequestBody_t          *dmAbortSMPRequestBody = agNULL;
  dmList_t                    *SMPList;
  
  DM_DBG1(("dmDiscoverySMPTimerCB: start!!!\n"));
  
  onePortContext = (dmIntPortContext_t *)timerData1;
  dmSMPRequestBody = (dmSMPRequestBody_t *)timerData2;
  
  discovery = &(onePortContext->discovery);
  oneDeviceData = dmSMPRequestBody->dmDevice;
  agToBeAbortIORequest = &(dmSMPRequestBody->agIORequest);
  agRoot = dmAllShared->agRoot;
  
#ifdef DIRECT_SMP
  SMPFunction = dmSMPRequestBody->smpPayload[1];
#else
  saFrameReadBlock(agRoot, dmSMPRequestBody->IndirectSMP, 0, smpHeader, 4);
  dmSMPFrameHeader = (dmSMPFrameHeader_t *)smpHeader;
  SMPFunction = dmSMPFrameHeader->smpFunction;
#endif
  
  DM_DBG3(("dmDiscoverySMPTimerCB: SMP function 0x%x\n", SMPFunction));
  
  tddmSingleThreadedEnter(dmRoot, DM_TIMER_LOCK);
  if (discovery->DiscoverySMPTimer.timerRunning == agTRUE)
  {
    tddmSingleThreadedLeave(dmRoot, DM_TIMER_LOCK);
    dmKillTimer(
                  dmRoot,
                  &discovery->DiscoverySMPTimer
                 );
  }
  else
  {
    tddmSingleThreadedLeave(dmRoot, DM_TIMER_LOCK);
  }
  
//for debugging
//  saGetPendingPICI(agRoot); 		     
  
  switch (SMPFunction)
  {
  case SMP_REPORT_GENERAL: /* fall through */
  case SMP_DISCOVER:  /* fall through */
  case SMP_CONFIGURE_ROUTING_INFORMATION:  /* fall through */
    DM_DBG1(("dmDiscoverySMPTimerCB: failing discovery, SMP function 0x%x !!!\n", SMPFunction));
    dmDiscoverDone(dmRoot, onePortContext, DM_RC_FAILURE);
    return; /* no more things to do */
  case SMP_REPORT_PHY_SATA:
    DM_DBG1(("dmDiscoverySMPTimerCB: failing discovery, SMP function SMP_REPORT_PHY_SATA !!!\n"));
    dmDiscoverDone(dmRoot, onePortContext, DM_RC_FAILURE);
    break;
  default:
    /* do nothing */
    DM_DBG1(("dmDiscoverySMPTimerCB: Error, not allowed case!!!\n"));
    break;
  }
  
  if (oneDeviceData->registered == agTRUE && (oneDeviceData->valid == agTRUE || oneDeviceData->valid2 == agTRUE) )
  {  
    /* call to saSMPAbort(one) */
    /* get an smp REQUEST from the free list */
    tddmSingleThreadedEnter(dmRoot, DM_SMP_LOCK);
    if (DMLIST_EMPTY(&(dmAllShared->freeSMPList)))
    {
      DM_DBG1(("dmDiscoverySMPTimerCB: no free SMP, can't abort SMP!!!\n"));
      tddmSingleThreadedLeave(dmRoot, DM_SMP_LOCK);
      return;
    }
    else
    {
      DMLIST_DEQUEUE_FROM_HEAD(&SMPList, &(dmAllShared->freeSMPList));
      tddmSingleThreadedLeave(dmRoot, DM_SMP_LOCK);
      dmAbortSMPRequestBody = DMLIST_OBJECT_BASE(dmSMPRequestBody_t, Link, SMPList);
      if (dmAbortSMPRequestBody == agNULL)
      {
        DM_DBG1(("dmDiscoverySMPTimerCB: dmAbortSMPRequestBody is NULL!!!\n"));
        return;
      }    
      DM_DBG5(("dmDiscoverySMPTimerCB: SMP id %d\n", dmAbortSMPRequestBody->id));
    }
    
    dmAbortSMPRequestBody->dmRoot = dmRoot;

    agAbortIORequest = &(dmAbortSMPRequestBody->agIORequest);
    agAbortIORequest->osData = (void *) dmAbortSMPRequestBody;
    agAbortIORequest->sdkData = agNULL; /* SALL takes care of this */
				     
    oneExpander = oneDeviceData->dmExpander;
								     				     
    DM_DBG1(("dmDiscoverySMPTimerCB: calling saSMPAbort!!!\n"));
    saSMPAbort(agRoot, 
               agAbortIORequest,
               0,
               oneExpander->agDevHandle,
               0, /* abort one */
               agToBeAbortIORequest,
               dmSMPAbortCB
              );
  }    
  return;
}
		       



osGLOBAL void                          
dmSMPBusyTimer(dmRoot_t             *dmRoot,
               dmIntPortContext_t   *onePortContext,
               dmDeviceData_t       *oneDeviceData,
               dmSMPRequestBody_t   *dmSMPRequestBody
              )
{
  dmIntRoot_t       *dmIntRoot    = (dmIntRoot_t *)dmRoot->dmData;
  dmIntContext_t    *dmAllShared = (dmIntContext_t *)&dmIntRoot->dmAllShared;
  dmDiscovery_t     *discovery;
  
  DM_DBG3(("dmSMPBusyTimer: start\n"));
  DM_DBG3(("dmSMPBusyTimer: pid %d\n", onePortContext->id));
  
  discovery = &(onePortContext->discovery);
  
  tddmSingleThreadedEnter(dmRoot, DM_TIMER_LOCK);
  if (discovery->SMPBusyTimer.timerRunning == agTRUE)
  {
    tddmSingleThreadedLeave(dmRoot, DM_TIMER_LOCK);
    dmKillTimer(
              dmRoot,
              &discovery->SMPBusyTimer
              );
  }
  else
  {
    tddmSingleThreadedLeave(dmRoot, DM_TIMER_LOCK);
  }
  
  dmSetTimerRequest(
                    dmRoot,
                    &discovery->SMPBusyTimer,
                    SMP_BUSY_TIMER_VALUE/dmAllShared->usecsPerTick,
                    dmSMPBusyTimerCB,
                    onePortContext,
                    oneDeviceData, 
                    dmSMPRequestBody
                    );
  
  dmAddTimer (
              dmRoot,
              &dmAllShared->timerlist, 
              &discovery->SMPBusyTimer
              );
  
  
  return;
}

osGLOBAL void
dmSMPBusyTimerCB(
                 dmRoot_t    * dmRoot, 
                 void        * timerData1,
                 void        * timerData2,
                 void        * timerData3
                )
{
  dmIntRoot_t                 *dmIntRoot    = (dmIntRoot_t *)dmRoot->dmData;
  dmIntContext_t              *dmAllShared = (dmIntContext_t *)&dmIntRoot->dmAllShared;
  agsaRoot_t                  *agRoot;
  dmIntPortContext_t          *onePortContext;
  dmDeviceData_t              *oneDeviceData;
  dmSMPRequestBody_t          *dmSMPRequestBody;
  agsaSASRequestBody_t        *agSASRequestBody;
  agsaIORequest_t             *agIORequest;
  agsaDevHandle_t             *agDevHandle;
  dmDiscovery_t               *discovery;
  bit32                       status = AGSA_RC_FAILURE;
  dmExpander_t                *oneExpander = agNULL;
  
  
  DM_DBG3(("dmSMPBusyTimerCB: start\n"));
  
  onePortContext = (dmIntPortContext_t *)timerData1;
  oneDeviceData = (dmDeviceData_t *)timerData2;
  dmSMPRequestBody = (dmSMPRequestBody_t *)timerData3;
  agRoot = dmAllShared->agRoot;
  agIORequest = &(dmSMPRequestBody->agIORequest);
  oneExpander = oneDeviceData->dmExpander;
  agDevHandle = oneExpander->agDevHandle;
  agSASRequestBody = &(dmSMPRequestBody->agSASRequestBody);
  discovery = &(onePortContext->discovery);

  discovery->SMPRetries++;
  
  if (discovery->SMPRetries < SMP_BUSY_RETRIES)
  {    
    status = saSMPStart(
                         agRoot,
                         agIORequest,
                         0,             
                         agDevHandle,
                         AGSA_SMP_INIT_REQ,
                         agSASRequestBody,
                         &dmsaSMPCompleted
                         );
  }

  if (status == AGSA_RC_SUCCESS)
  {
    discovery->SMPRetries = 0;
    tddmSingleThreadedEnter(dmRoot, DM_TIMER_LOCK);
    if (discovery->SMPBusyTimer.timerRunning == agTRUE)
    {
      tddmSingleThreadedLeave(dmRoot, DM_TIMER_LOCK);
      dmKillTimer(
                    dmRoot,
                    &discovery->SMPBusyTimer
                   );
    }		     
    else
    {
      tddmSingleThreadedLeave(dmRoot, DM_TIMER_LOCK);
    }
  }		       
  else if (status == AGSA_RC_FAILURE)
  {  
    tddmSingleThreadedEnter(dmRoot, DM_TIMER_LOCK);
    if (discovery->SMPBusyTimer.timerRunning == agTRUE)
    {
      tddmSingleThreadedLeave(dmRoot, DM_TIMER_LOCK);
      dmKillTimer(
                    dmRoot,
                    &discovery->SMPBusyTimer
                   );
    }		     
    else
    {
      tddmSingleThreadedLeave(dmRoot, DM_TIMER_LOCK);
    }

    discovery->SMPRetries = 0;
    dmDiscoverDone(dmRoot, onePortContext, DM_RC_FAILURE);
  }
  else /* AGSA_RC_BUSY */
  {
    if (discovery->SMPRetries >= SMP_BUSY_RETRIES)
    {
      /* done with retris; give up */
      DM_DBG3(("dmSMPBusyTimerCB: retries are over\n"));

      tddmSingleThreadedEnter(dmRoot, DM_TIMER_LOCK);
      if (discovery->SMPBusyTimer.timerRunning == agTRUE)
      {
        tddmSingleThreadedLeave(dmRoot, DM_TIMER_LOCK);
        dmKillTimer(
                      dmRoot,
                      &discovery->SMPBusyTimer
                     );
      }		     
      else
      {
        tddmSingleThreadedLeave(dmRoot, DM_TIMER_LOCK);
      }

      discovery->SMPRetries = 0;
      dmDiscoverDone(dmRoot, onePortContext, DM_RC_FAILURE);

    }
    else
    {
      /* keep retrying */
      dmSMPBusyTimer(dmRoot, onePortContext, oneDeviceData, dmSMPRequestBody);
    }
  }
  
  return;
}  


/* expander configuring timer */
osGLOBAL void                          
dmDiscoveryConfiguringTimer(dmRoot_t                 *dmRoot,
                            dmIntPortContext_t       *onePortContext,
                            dmDeviceData_t           *oneDeviceData
                           )
{
  dmIntRoot_t       *dmIntRoot    = (dmIntRoot_t *)dmRoot->dmData;
  dmIntContext_t    *dmAllShared = (dmIntContext_t *)&dmIntRoot->dmAllShared;
  dmDiscovery_t     *discovery;
  
  DM_DBG3(("dmDiscoveryConfiguringTimer: start\n"));
  DM_DBG3(("dmDiscoveryConfiguringTimer: pid %d\n", onePortContext->id));
  
  discovery = &(onePortContext->discovery);
 
  tddmSingleThreadedEnter(dmRoot, DM_TIMER_LOCK);
  if (discovery->discoveryTimer.timerRunning == agTRUE)
  {
    tddmSingleThreadedLeave(dmRoot, DM_TIMER_LOCK);
    dmKillTimer(
              dmRoot,
              &discovery->discoveryTimer
              );
  }
  else
  {
    tddmSingleThreadedLeave(dmRoot, DM_TIMER_LOCK);
  }
  
  DM_DBG3(("dmDiscoveryConfiguringTimer: UsecsPerTick %d\n", dmAllShared->usecsPerTick));
  DM_DBG3(("dmDiscoveryConfiguringTimer: Timervalue %d\n", DISCOVERY_CONFIGURING_TIMER_VALUE/dmAllShared->usecsPerTick));
  
  dmSetTimerRequest(
                    dmRoot,
                    &discovery->discoveryTimer,
                    DISCOVERY_CONFIGURING_TIMER_VALUE/dmAllShared->usecsPerTick,
                    dmDiscoveryConfiguringTimerCB,
                    onePortContext, 
                    oneDeviceData,
                    agNULL
                   );
                   
  dmAddTimer (
              dmRoot,
              &dmAllShared->timerlist, 
              &discovery->discoveryTimer
              );
  
  
  return;
}

		
osGLOBAL void
dmDiscoveryConfiguringTimerCB(
                              dmRoot_t    * dmRoot, 
                              void        * timerData1,
                              void        * timerData2,
                              void        * timerData3
                             )
{
  dmIntPortContext_t     *onePortContext = agNULL;
  dmDiscovery_t          *discovery      = agNULL;
  dmDeviceData_t         *oneDeviceData  = agNULL;

  onePortContext = (dmIntPortContext_t *)timerData1;
  oneDeviceData  = (dmDeviceData_t *)timerData2;
  discovery = &(onePortContext->discovery);

  DM_DBG3(("dmDiscoveryConfiguringTimerCB: start\n"));  

  tddmSingleThreadedEnter(dmRoot, DM_TIMER_LOCK);
  if (discovery->discoveryTimer.timerRunning == agTRUE)
  {
    tddmSingleThreadedLeave(dmRoot, DM_TIMER_LOCK);
    dmKillTimer(
               dmRoot,
               &discovery->discoveryTimer
               );
  }       
  else
  {
    tddmSingleThreadedLeave(dmRoot, DM_TIMER_LOCK);
  }
  
  if (oneDeviceData->valid == agTRUE || oneDeviceData->valid2 == agTRUE)
  {
    dmReportGeneralSend(dmRoot, oneDeviceData);
  }
  return;
}
						
osGLOBAL void                          
dmConfigureRouteTimer(dmRoot_t                 *dmRoot,
                      dmIntPortContext_t       *onePortContext,
                      dmExpander_t             *oneExpander,
                      smpRespDiscover_t        *pdmSMPDiscoverResp,
                      smpRespDiscover2_t       *pdmSMPDiscover2Resp
                     )
{
  dmIntRoot_t       *dmIntRoot    = (dmIntRoot_t *)dmRoot->dmData;
  dmIntContext_t    *dmAllShared = (dmIntContext_t *)&dmIntRoot->dmAllShared;
  dmDiscovery_t     *discovery;
  
  DM_DBG3(("dmConfigureRouteTimer: start\n"));
  
  DM_DBG3(("dmConfigureRouteTimer: pid %d\n", onePortContext->id));
  
  discovery = &(onePortContext->discovery);
 
  DM_DBG3(("dmConfigureRouteTimer: onePortContext %p oneExpander %p pdmSMPDiscoverResp %p\n", onePortContext, oneExpander, pdmSMPDiscoverResp));
  
  DM_DBG3(("dmConfigureRouteTimer: discovery %p \n", discovery));
  
  DM_DBG3(("dmConfigureRouteTimer:  pid %d configureRouteRetries %d\n", onePortContext->id, discovery->configureRouteRetries));
  
  DM_DBG3(("dmConfigureRouteTimer: discovery->status %d\n", discovery->status));
      
  tddmSingleThreadedEnter(dmRoot, DM_TIMER_LOCK);
  if (discovery->configureRouteTimer.timerRunning == agTRUE)
  {
    tddmSingleThreadedLeave(dmRoot, DM_TIMER_LOCK);
    dmKillTimer(
              dmRoot,
              &discovery->configureRouteTimer
              );
  }
  else
  {
    tddmSingleThreadedLeave(dmRoot, DM_TIMER_LOCK);
  }
  
  DM_DBG3(("dmConfigureRouteTimer: UsecsPerTick %d\n", dmAllShared->usecsPerTick));
  DM_DBG3(("dmConfigureRouteTimer: Timervalue %d\n", CONFIGURE_ROUTE_TIMER_VALUE/dmAllShared->usecsPerTick));
  
  if (oneExpander->SAS2 == 0)
  {
    /* SAS 1.1 */
    dmSetTimerRequest(
                      dmRoot,
                      &discovery->configureRouteTimer,
                      CONFIGURE_ROUTE_TIMER_VALUE/dmAllShared->usecsPerTick,
                      dmConfigureRouteTimerCB,
                      (void *)onePortContext, 
                      (void *)oneExpander,
                      (void *)pdmSMPDiscoverResp
                     );
  }                   
  else
  { 
    /* SAS 2 */
    dmSetTimerRequest(
                      dmRoot,
                      &discovery->configureRouteTimer,
                      CONFIGURE_ROUTE_TIMER_VALUE/dmAllShared->usecsPerTick,
                      dmConfigureRouteTimerCB,
                      (void *)onePortContext, 
                      (void *)oneExpander,
                      (void *)pdmSMPDiscover2Resp
                     );
  }		     
  dmAddTimer (
              dmRoot,
              &dmAllShared->timerlist, 
              &discovery->configureRouteTimer
              );
   
  return;
}


osGLOBAL void
dmConfigureRouteTimerCB(
                        dmRoot_t    * dmRoot, 
                        void        * timerData1,
                        void        * timerData2,
                        void        * timerData3
                       )
{
  dmIntRoot_t         *dmIntRoot    = (dmIntRoot_t *)dmRoot->dmData;
  dmIntContext_t      *dmAllShared = (dmIntContext_t *)&dmIntRoot->dmAllShared;
  dmIntPortContext_t  *onePortContext;
  dmExpander_t        *oneExpander;
  smpRespDiscover_t   *pdmSMPDiscoverResp = agNULL;
  smpRespDiscover2_t  *pdmSMPDiscover2Resp = agNULL;
  dmDiscovery_t       *discovery;
  
  
  DM_DBG3(("dmConfigureRouteTimerCB: start\n"));
  
  onePortContext = (dmIntPortContext_t *)timerData1;
  oneExpander = (dmExpander_t *)timerData2;
  if (oneExpander->SAS2 == 0)
  {
    pdmSMPDiscoverResp = (smpRespDiscover_t *)timerData3;
  }
  else
  {
    pdmSMPDiscover2Resp = (smpRespDiscover2_t *)timerData3;
  }
  discovery = &(onePortContext->discovery);
  
  DM_DBG3(("dmConfigureRouteTimerCB: onePortContext %p oneExpander %p pdmSMPDiscoverResp %p\n", onePortContext, oneExpander, pdmSMPDiscoverResp));
  
  DM_DBG3(("dmConfigureRouteTimerCB: discovery %p\n", discovery));

  DM_DBG3(("dmConfigureRouteTimerCB: pid %d configureRouteRetries %d\n", onePortContext->id, discovery->configureRouteRetries));
  
  DM_DBG3(("dmConfigureRouteTimerCB: discovery.status %d\n", discovery->status));
   
  discovery->configureRouteRetries++; 
  if (discovery->configureRouteRetries >= dmAllShared->MaxRetryDiscovery)
  {
    DM_DBG3(("dmConfigureRouteTimerCB: retries are over\n"));

    tddmSingleThreadedEnter(dmRoot, DM_TIMER_LOCK);
    if (discovery->configureRouteTimer.timerRunning == agTRUE)
    {
      tddmSingleThreadedLeave(dmRoot, DM_TIMER_LOCK);
      dmKillTimer(
                  dmRoot,
                  &discovery->configureRouteTimer
                  );
    }
    else
    {
      tddmSingleThreadedLeave(dmRoot, DM_TIMER_LOCK);
    }

    discovery->configureRouteRetries = 0;
    /* failed the discovery */
    dmDiscoverDone(dmRoot, onePortContext, DM_RC_FAILURE);

    return;
  }

  
  if (oneExpander->SAS2 == 0)
  {
    if (onePortContext->discovery.status == DISCOVERY_DOWN_STREAM)
    {
      DM_DBG3(("dmConfigureRouteTimerCB: proceed by calling dmDownStreamDiscoverExpanderPhy\n"));
      dmhexdump("dmConfigureRouteTimerCB", (bit8*)pdmSMPDiscoverResp, sizeof(smpRespDiscover_t));
      discovery->configureRouteRetries = 0;

      dmDownStreamDiscoverExpanderPhy(dmRoot, onePortContext, oneExpander, pdmSMPDiscoverResp);  
    }
    else
    {
      DM_DBG3(("dmConfigureRouteTimerCB: setting timer again\n"));
      /* set the timer again */
      dmSetTimerRequest(
                        dmRoot,
                        &discovery->configureRouteTimer,
                        CONFIGURE_ROUTE_TIMER_VALUE/dmAllShared->usecsPerTick,
                        dmConfigureRouteTimerCB,
                        (void *)onePortContext, 
                        (void *)oneExpander,
                        (void *)pdmSMPDiscoverResp
                       );
                   
      dmAddTimer (
                  dmRoot,
                  &dmAllShared->timerlist, 
                  &discovery->configureRouteTimer
                  );
    }
  } /* SAS 1.1 */
  else
  {
    /* SAS 2 */
    if (onePortContext->discovery.status == DISCOVERY_DOWN_STREAM)
    {
      DM_DBG2(("dmConfigureRouteTimerCB: proceed by calling dmDownStreamDiscover2ExpanderPhy\n"));
      dmhexdump("dmConfigureRouteTimerCB", (bit8*)pdmSMPDiscover2Resp, sizeof(smpRespDiscover2_t));

      dmDownStreamDiscover2ExpanderPhy(dmRoot, onePortContext, oneExpander, pdmSMPDiscover2Resp);  
    }
    else
    {
      DM_DBG2(("dmConfigureRouteTimerCB: setting timer again\n"));
      /* set the timer again */
      dmSetTimerRequest(
                        dmRoot,
                        &discovery->configureRouteTimer,
                        CONFIGURE_ROUTE_TIMER_VALUE/dmAllShared->usecsPerTick,
                        dmConfigureRouteTimerCB,
                        (void *)onePortContext, 
                        (void *)oneExpander,
                        (void *)pdmSMPDiscover2Resp
                       );
                   
      dmAddTimer (
                  dmRoot,
                  &dmAllShared->timerlist, 
                  &discovery->configureRouteTimer
                 );
    }
  }
  
  return;
}		       
#endif /* FDS_ DM */

