/*******************************************************************************
*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

********************************************************************************/
/*******************************************************************************/
/*! \file sampicmd.c
 *  \brief The file implements the functions of MPI Inbound IOMB/Command to SPC
 *
 */
/******************************************************************************/
#include <sys/cdefs.h>
__BSDSUXID("$BSDSUniX $");
#include <dev/pms/config.h>

#include <dev/pms/RefTisa/sallsdk/spc/saglobal.h>
#ifdef SA_ENABLE_TRACE_FUNCTIONS
#ifdef siTraceFileID
#undef siTraceFileID
#endif
#define siTraceFileID 'I'
#endif

/******************************************************************************/
/*! \brief SAS/SATA LL API ECHO Command
 *
 *  This command used to test that MPI between host and SPC IOP is operational.
 *
 *  \param agRoot       Handles for this instance of SAS/SATA hardware
 *  \param agContext    Context of SPC FW Flash Update Command
 *  \param queueNum     Inbound/outbound queue number
 *  \param echoPayload  Pointer of Echo payload of IOMB
 *
 *  \return If the MPI command is sent to SPC successfully
 *          - \e AGSA_RC_SUCCESS the MPI command is successfully
 *          - \e AGSA_RC_BUSY the SPC is no resource, cannot send now
 *          - \e AGSA_RC_FAILURE the MPI command is failure
 *
 */
/*******************************************************************************/
GLOBAL bit32 saEchoCommand(
  agsaRoot_t            *agRoot,
  agsaContext_t         *agContext,
  bit32                 queueNum,
  void                  *echoPayload
)
{
  bit32 ret = AGSA_RC_SUCCESS;

  smTraceFuncEnter(hpDBG_VERY_LOUD, "xa");

  /* setup IOMB payload */
  ret = mpiEchoCmd(agRoot, queueNum, agContext, echoPayload);

  smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "xa");

  return ret;
}

/******************************************************************************/
/*! \brief Build a IOMB command and send to SPC
 *
 *  Build an IOMB if there is a free message buffer and Send it to SPC
 *
 *  \param agRoot       Handles for this instance of SAS/SATA hardware
 *  \param payload      Pointer of payload in the IOMB
 *  \param category     Category of IOMB
 *  \param opcode       Opcode of IOMB
 *  \param size         Size of IOMB
 *  \param queueNum     Inbound/outbound queue number
 *
 *  \return If the MPI command is sent to SPC successfully
 *          - \e AGSA_RC_SUCCESS the MPI command is successfully
 *          - \e AGSA_RC_BUSY the SPC is no resource, cannot send now
 *          - \e AGSA_RC_FAILURE the MPI command is failure
 */
/*******************************************************************************/
GLOBAL bit32 mpiBuildCmd(
  agsaRoot_t        *agRoot,
  bit32             *payload,
  mpiMsgCategory_t  category,
  bit16             opcode,
  bit16             size,
  bit32             queueNum
  )
{
  agsaLLRoot_t      *saRoot = (agsaLLRoot_t *) (agRoot->sdkData);
  mpiICQueue_t      *circularQ;
  void              *pMessage;
  bit32             ret = AGSA_RC_SUCCESS;
  bit32             retVal;
  bit8              inq, outq;

  smTraceFuncEnter(hpDBG_VERY_LOUD, "xb");

  inq = (bit8)(queueNum & MPI_IB_NUM_MASK);
  outq = (bit8)((queueNum & MPI_OB_NUM_MASK) >> MPI_OB_SHIFT);
  SA_ASSERT((AGSA_MAX_INBOUND_Q > inq), "The IBQ Number is out of range.");
  SA_ASSERT((AGSA_MAX_OUTBOUND_Q > outq), "The OBQ Number is out of range.");

#ifdef SA_USE_MAX_Q
  outq = saRoot->QueueConfig.numOutboundQueues -1;
  SA_DBG1(("mpiBuildCmd, set OBQ to  %d\n",outq));
#endif /* SA_USE_MAX_Q */
  /* get a free inbound queue entry */

#ifdef SA_LL_IBQ_PROTECT
  ossaSingleThreadedEnter(agRoot, LL_IOREQ_IBQ0_LOCK + inq);
#endif /* SA_LL_IBQ_PROTECT */

  circularQ = &saRoot->inboundQueue[inq];
  retVal    = mpiMsgFreeGet(circularQ, size, &pMessage);

  /* return FAILURE if error happened */
  if (AGSA_RC_FAILURE == retVal)
  {
#ifdef SA_LL_IBQ_PROTECT
    ossaSingleThreadedLeave(agRoot, LL_IOREQ_IBQ0_LOCK + inq);
#endif /* SA_LL_IBQ_PROTECT */
    /* the message size exceeds the inbound queue message size */
    SA_DBG1(("mpiBuildCmd, failure\n"));
    ret = AGSA_RC_FAILURE;
    smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "xb");
    return ret;
  }

  /* return BUSY if no more inbound queue entry available */
  if (AGSA_RC_BUSY == retVal)
  {
    SA_DBG1(("mpiBuildCmd, no more IOMB\n"));
    ret = AGSA_RC_BUSY;
  }
  else
  {
    /* copy payload if it is necessary */
    if (agNULL != payload)
    {
      si_memcpy(pMessage, payload, (size - sizeof(mpiMsgHeader_t)));
    }

    /* post the message to SPC */
    if (AGSA_RC_FAILURE == mpiMsgProduce(circularQ, (void *)pMessage, category, opcode, outq, (bit8)circularQ->priority))
    {
      ret = AGSA_RC_FAILURE;
    }
  }

#ifdef SA_LL_IBQ_PROTECT
  ossaSingleThreadedLeave(agRoot, LL_IOREQ_IBQ0_LOCK + inq);
#endif /* SA_LL_IBQ_PROTECT */

  smTraceFuncExit(hpDBG_VERY_LOUD, 'b', "xb");
  return ret;
}

/******************************************************************************/
/*! \brief SPC MPI ECHO Command
 *
 *  This command used to test that MPI between host and SPC IOP is operational.
 *
 *  \param agRoot       Handles for this instance of SAS/SATA LLL
 *  \param queueNum     Inbound/outbound queue number
 *  \param tag          Tag of this IOMB
 *  \param echoPayload  Pointer to the ECHO payload of inbound IOMB
 *
 *  \return If the MPI command is sent to SPC successfully
 *          - \e AGSA_RC_SUCCESS the MPI command is successfully
 *          - \e AGSA_RC_BUSY the SPC is no resource, cannot send now
 *          - \e AGSA_RC_FAILURE the MPI command is failure
 *
 */
/*******************************************************************************/
GLOBAL bit32 mpiEchoCmd(
  agsaRoot_t          *agRoot,
  bit32               queueNum,
  agsaContext_t       *agContext,
  void                *echoPayload
  )
{
  bit32               ret = AGSA_RC_SUCCESS;
  agsaLLRoot_t        *saRoot = (agsaLLRoot_t *) (agRoot->sdkData);
  agsaIORequestDesc_t *pRequest;
  agsaEchoCmd_t       payload;

  smTraceFuncEnter(hpDBG_VERY_LOUD, "xc");

  ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
  /* Get request from free IORequests */
  pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeIORequests));

  /* If no LL Control request entry available */
  if ( agNULL == pRequest )
  {
    ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
    SA_DBG1(("mpiEchoCmd, No request from free list\n" ));
    smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "xc");
    return AGSA_RC_BUSY;
  }
  /* If LL Control request entry avaliable */
  else
  {
    /* Remove the request from free list */
    SA_ASSERT((!pRequest->valid), "The pRequest is in use");
    saLlistIORemove(&(saRoot->freeIORequests), &(pRequest->linkNode));
    saRoot->IOMap[pRequest->HTag].Tag = pRequest->HTag;
    saRoot->IOMap[pRequest->HTag].IORequest = (void *)pRequest;
    saRoot->IOMap[pRequest->HTag].agContext = agContext;
    pRequest->valid = agTRUE;

    ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);


    /* build IOMB command and send to SPC */
    OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaEchoCmd_t, tag), pRequest->HTag);
    /* copy Echo payload */
    si_memcpy(&payload.payload[0], echoPayload, (sizeof(agsaEchoCmd_t) - 4));
    /* build IOMB command and send to SPC */
    ret = mpiBuildCmd(agRoot, (bit32 *)&payload, MPI_CATEGORY_SAS_SATA, OPC_INB_ECHO, IOMB_SIZE64, queueNum);
    SA_DBG3(("mpiEchoCmd, return value = %d\n", ret));
    if (AGSA_RC_SUCCESS != ret)
    {
      ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
      /* remove the request from IOMap */
      saRoot->IOMap[pRequest->HTag].Tag = MARK_OFF;
      saRoot->IOMap[pRequest->HTag].IORequest = agNULL;
      saRoot->IOMap[pRequest->HTag].agContext = agNULL;
      pRequest->valid = agFALSE;
      /* return the request to free pool */
      saLlistIOAdd(&(saRoot->freeIORequests), &(pRequest->linkNode));

      ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);

      SA_DBG1(("mpiEchoCmd, sending IOMB failed\n" ));
    }
#ifdef SALL_API_TEST
    else
    {
      saRoot->LLCounters.IOCounter.numEchoSent++;
    }
#endif

  }

  /* return value */
  smTraceFuncExit(hpDBG_VERY_LOUD, 'b', "xc");
  return ret;
}


/******************************************************************************/
/*! \brief Get Phy Profile Command SPCv
 *
 *  This command is get # of phys and support speeds from SPCV.
 *
 *  \param agRoot       Handles for this instance of SAS/SATA LLL
 *  \param agDevHandle  Handle of device
 *
 *  \return If the MPI command is sent to SPC successfully
 *          - \e AGSA_RC_SUCCESS the MPI command is successfully
 *          - \e AGSA_RC_BUSY the SPC is no resource, cannot send now
 *          - \e AGSA_RC_FAILURE the MPI command is failure
 *
 */
/*******************************************************************************/


GLOBAL bit32 mpiGetPhyProfileCmd(
  agsaRoot_t          *agRoot,
  agsaContext_t       *agContext,
  bit32                Operation,
  bit32                PhyId,
  void                *agCB
  )
{
  agsaLLRoot_t            *saRoot = (agsaLLRoot_t *) (agRoot->sdkData);
  agsaIORequestDesc_t     *pRequest;
  bit32                   ret = AGSA_RC_SUCCESS;
  agsaGetPhyProfileCmd_V_t   payload;

  smTraceFuncEnter(hpDBG_VERY_LOUD, "xd");

  ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
  /* Get request from free IORequests */
  pRequest = (agsaIORequestDesc_t *)saLlistGetHead(&(saRoot->freeIORequests));

  SA_DBG1(("mpiGetPhyProfileCmd, Operation 0x%x PhyId %d \n",Operation ,PhyId ));

  /* If no LL Control request entry avalibale */
  if ( agNULL == pRequest )
  {
    ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
    SA_DBG1(("mpiGetPhyProfileCmd, No request from free list\n" ));
    return AGSA_RC_BUSY;
  }
  /* If LL Control request entry avaliable */
  else
  {
    SA_ASSERT((!pRequest->valid), "The pRequest is in use");

    /* Remove the request from free list */
    saLlistRemove(&(saRoot->freeIORequests), &(pRequest->linkNode));
    saRoot->IOMap[pRequest->HTag].Tag = pRequest->HTag;
    saRoot->IOMap[pRequest->HTag].IORequest = (void *)pRequest;
    saRoot->IOMap[pRequest->HTag].agContext = agContext;

    pRequest->valid = agTRUE;
    pRequest->completionCB  = agCB;
    ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);


    /* set payload to zeros */
    si_memset(&payload, 0, sizeof(agsaGetPhyProfileCmd_V_t));

    /* set tag field */
    OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaGetPhyProfileCmd_V_t, tag), pRequest->HTag);
    OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaGetPhyProfileCmd_V_t, Reserved_Ppc_SOP_PHYID), (((Operation & 0xF) << SHIFT8 ) | (PhyId  & 0xFF) ) );
    /* build IOMB command and send to SPC */
    ret = mpiBuildCmd(agRoot, (bit32 *)&payload, MPI_CATEGORY_SAS_SATA, OPC_INB_GET_PHY_PROFILE, IOMB_SIZE128, 0);
    if (AGSA_RC_SUCCESS != ret)
    {
      ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
      pRequest->valid = agFALSE;
      /* return the request to free pool */
      saLlistAdd(&(saRoot->freeIORequests), &(pRequest->linkNode));
      /* remove the request from IOMap */
      saRoot->IOMap[pRequest->HTag].Tag = MARK_OFF;
      saRoot->IOMap[pRequest->HTag].IORequest = agNULL;
      saRoot->IOMap[pRequest->HTag].agContext = agNULL;
      ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);

      SA_DBG1(("mpiGetPhyProfileCmd, sending IOMB failed\n" ));
    }
    SA_DBG3(("mpiGetPhyProfileCmd, return value = %d\n", ret));
  }

  smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "xd");
  /* return value */
  return ret;
}


GLOBAL bit32 mpiVHistCapCmd(
                          agsaRoot_t    *agRoot,
                          agsaContext_t *agContext,
                          bit32         queueNum,
                          bit32         Channel,
                          bit32         NumBitLo,
                          bit32         NumBitHi,
                          bit32         PcieAddrLo,
                          bit32         PcieAddrHi,
                          bit32         ByteCount )
{
  agsaLLRoot_t            *saRoot = (agsaLLRoot_t *) (agRoot->sdkData);
  agsaIORequestDesc_t     *pRequest= agNULL;
  bit32                   ret = AGSA_RC_SUCCESS;
  agsaGetVHistCap_V_t payload;

  smTraceFuncEnter(hpDBG_VERY_LOUD,"3C");
  SA_DBG1(("mpiVHistCapCmd\n"));

  ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
  /* Get request from free IORequests */
  pRequest = (agsaIORequestDesc_t *)saLlistGetHead(&(saRoot->freeIORequests));
  /* If no LL Control request entry avalibale */
  if ( agNULL == pRequest )
  {
    ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
    SA_DBG1((", No request from free list\n" ));
    smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "3C");
    return AGSA_RC_BUSY;
  }
  /* If LL Control request entry avaliable */
  else
  {
    SA_ASSERT((!pRequest->valid), "The pRequest is in use");
    /* Remove the request from free list */
    saLlistRemove(&(saRoot->freeIORequests), &(pRequest->linkNode));
    saRoot->IOMap[pRequest->HTag].Tag = pRequest->HTag;
    saRoot->IOMap[pRequest->HTag].IORequest = (void *)pRequest;
    saRoot->IOMap[pRequest->HTag].agContext = agContext;

    pRequest->valid = agTRUE;
    pRequest->completionCB  = (void *)ossaGetPhyProfileCB;
    ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);

    /* set payload to zeros */
    si_memset(&payload, 0, sizeof(agsaGetVHistCap_V_t));

    /* set tag field */
    OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaGetVHistCap_V_t, tag),       pRequest->HTag);
    OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaGetVHistCap_V_t, Channel),   Channel );
    OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaGetVHistCap_V_t, NumBitLo),  NumBitLo);
    OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaGetVHistCap_V_t, NumBitHi),  NumBitHi);
    OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaGetVHistCap_V_t, PcieAddrLo),PcieAddrLo);
    OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaGetVHistCap_V_t, PcieAddrHi),PcieAddrHi);
    OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaGetVHistCap_V_t, ByteCount), ByteCount );


    /* build IOMB command and send to SPC */
    ret = mpiBuildCmd(agRoot, (bit32 *)&payload, MPI_CATEGORY_SAS_SATA, OPC_INB_GET_VHIST_CAP, IOMB_SIZE128,queueNum );
    if (AGSA_RC_SUCCESS != ret)
    {
      ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
      pRequest->valid = agFALSE;
      /* return the request to free pool */
      saLlistAdd(&(saRoot->freeIORequests), &(pRequest->linkNode));
      /* remove the request from IOMap */
      saRoot->IOMap[pRequest->HTag].Tag = MARK_OFF;
      saRoot->IOMap[pRequest->HTag].IORequest = agNULL;
      saRoot->IOMap[pRequest->HTag].agContext = agNULL;
      ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);

      SA_DBG1(("mpiVHistCapCmd, sending IOMB failed\n" ));
    }
    SA_DBG3(("mpiVHistCapCmd, return value = %d\n", ret));
  }

  smTraceFuncExit(hpDBG_VERY_LOUD, 'b', "3C");
  /* return value */

  return(ret);
}

GLOBAL bit32 mpiSetPhyProfileCmd(
  agsaRoot_t    *agRoot,
  agsaContext_t *agContext,
  bit32         Operation,
  bit32         PhyId,
  bit32         length,
  void *        buffer
  )
{
  agsaLLRoot_t            *saRoot = (agsaLLRoot_t *) (agRoot->sdkData);
  agsaIORequestDesc_t     *pRequest;
  bit32                   ret = AGSA_RC_SUCCESS;
  bit32                   i;
  agsaSetPhyProfileCmd_V_t     payload;
  bit32               * PageData =(bit32 * )buffer;

  smTraceFuncEnter(hpDBG_VERY_LOUD,"2P");

  ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
  /* Get request from free IORequests */
  pRequest = (agsaIORequestDesc_t *)saLlistGetHead(&(saRoot->freeIORequests));

  SA_DBG1(("mpiSetPhyProfileCmd, Operation 0x%x PhyId %d \n",Operation ,PhyId ));

  /* If no LL Control request entry avalibale */
  if ( agNULL == pRequest )
  {
    ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
    SA_DBG1(("mpiSetPhyProfileCmd, No request from free list\n" ));
    return AGSA_RC_BUSY;
  }
  /* If LL Control request entry avaliable */
  else
  {
    SA_ASSERT((!pRequest->valid), "The pRequest is in use");
    /* Remove the request from free list */
    saLlistRemove(&(saRoot->freeIORequests), &(pRequest->linkNode));
    saRoot->IOMap[pRequest->HTag].Tag = pRequest->HTag;
    saRoot->IOMap[pRequest->HTag].IORequest = (void *)pRequest;
    saRoot->IOMap[pRequest->HTag].agContext = agContext;

    pRequest->valid = agTRUE;
    pRequest->SOP = (bit16) Operation;
    pRequest->completionCB  = (void *)ossaGetPhyProfileCB;
    ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);


    /* set payload to zeros */
    si_memset(&payload, 0, sizeof(agsaSetPhyProfileCmd_V_t));

    /* set tag field */
    OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSetPhyProfileCmd_V_t, tag), pRequest->HTag);
    OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSetPhyProfileCmd_V_t, Reserved_Ppc_SOP_PHYID), (((Operation & 0xF) << SHIFT8 ) | (PhyId  & 0xFF) ) );

    for(i=0; i < (length / sizeof(bit32)); i++)
    {
      OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSetPhyProfileCmd_V_t, PageSpecificArea[i]),* (PageData+i)  );
    }

    /* build IOMB command and send to SPC */
    ret = mpiBuildCmd(agRoot, (bit32 *)&payload, MPI_CATEGORY_SAS_SATA, OPC_INB_SET_PHY_PROFILE, IOMB_SIZE128, 0);
    if (AGSA_RC_SUCCESS != ret)
    {
      ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
      pRequest->valid = agFALSE;
      /* return the request to free pool */
      saLlistAdd(&(saRoot->freeIORequests), &(pRequest->linkNode));
      /* remove the request from IOMap */
      saRoot->IOMap[pRequest->HTag].Tag = MARK_OFF;
      saRoot->IOMap[pRequest->HTag].IORequest = agNULL;
      saRoot->IOMap[pRequest->HTag].agContext = agNULL;
      ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);

      SA_DBG1(("mpiSetPhyProfileCmd, sending IOMB failed\n" ));
    }
    SA_DBG3(("mpiGetPhyProfileCmd, return value = %d\n", ret));
  }

  smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "2P");
  /* return value */
  return ret;
}


/******************************************************************************/
/*! \brief Get Device Information Command
 *
 *  This command is get # of phys and support speeds from SPC.
 *
 *  \param agRoot       Handles for this instance of SAS/SATA LLL
 *  \param agDevHandle  Handle of device
 *  \param deviceid     Device Id
 *  \param opton        oprion
 *
 *  \return If the MPI command is sent to SPC successfully
 *          - \e AGSA_RC_SUCCESS the MPI command is successfully
 *          - \e AGSA_RC_BUSY the SPC is no resource, cannot send now
 *          - \e AGSA_RC_FAILURE the MPI command is failure
 *
 */
/*******************************************************************************/
GLOBAL bit32 mpiGetDeviceInfoCmd(
  agsaRoot_t          *agRoot,
  agsaContext_t       *agContext,
  bit32               deviceid,
  bit32               option,
  bit32               queueNum
  )
{
  agsaLLRoot_t            *saRoot = (agsaLLRoot_t *) (agRoot->sdkData);
  agsaIORequestDesc_t     *pRequest;
  bit32                   ret = AGSA_RC_SUCCESS;
  agsaGetDevInfoCmd_t     payload;

  SA_ASSERT((agNULL !=saRoot ), "");
  if(saRoot == agNULL)
  {
    SA_DBG1(("mpiGetDeviceInfoCmd: saRoot == agNULL\n"));
    return(AGSA_RC_FAILURE);
  }
  smTraceFuncEnter(hpDBG_VERY_LOUD,"2K");

  ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
  /* Get request from free IORequests */
  pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeIORequests));

  /* If no LL Control request entry available */
  if ( agNULL == pRequest )
  {
    SA_DBG1(("mpiGetDeviceInfoCmd, No request from free list\n" ));
    smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "2K");
    ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
    return AGSA_RC_BUSY;
  }
  /* If LL Control request entry avaliable */
  else
  {
    /* Remove the request from free list */
    SA_ASSERT((!pRequest->valid), "The pRequest is in use");
    saLlistIORemove(&(saRoot->freeIORequests), &(pRequest->linkNode));
    saRoot->IOMap[pRequest->HTag].Tag = pRequest->HTag;
    saRoot->IOMap[pRequest->HTag].IORequest = (void *)pRequest;
    saRoot->IOMap[pRequest->HTag].agContext = agContext;
    pRequest->valid = agTRUE;
    pRequest->DeviceInfoCmdOption = (bit8)option;
    ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);


    /* set payload to zeros */
    si_memset(&payload, 0, sizeof(agsaGetDevInfoCmd_t));

    /* set tag field */
    OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaGetDevInfoCmd_t, tag), pRequest->HTag);
    OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaGetDevInfoCmd_t, DeviceId), deviceid);
    /* build IOMB command and send to SPC */
    if( smIS_SPC(agRoot))
    {
      ret = mpiBuildCmd(agRoot, (bit32 *)&payload, MPI_CATEGORY_SAS_SATA, OPC_INB_SPC_GET_DEV_INFO, IOMB_SIZE64, queueNum);
    }
    else
    {
      ret = mpiBuildCmd(agRoot, (bit32 *)&payload, MPI_CATEGORY_SAS_SATA, OPC_INB_GET_DEV_INFO, IOMB_SIZE64, queueNum);
    }
    if (AGSA_RC_SUCCESS != ret)
    {
      ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
      /* remove the request from IOMap */
      saRoot->IOMap[pRequest->HTag].Tag = MARK_OFF;
      saRoot->IOMap[pRequest->HTag].IORequest = agNULL;
      saRoot->IOMap[pRequest->HTag].agContext = agNULL;
      pRequest->valid = agFALSE;
      /* return the request to free pool */
      saLlistIOAdd(&(saRoot->freeIORequests), &(pRequest->linkNode));
      ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);

      SA_DBG1(("mpiGetDeviceInfoCmd, sending IOMB failed\n" ));
    }
    SA_DBG3(("mpiGetDeviceInfoCmd, return value = %d\n", ret));
  }

  smTraceFuncExit(hpDBG_VERY_LOUD, 'b', "2K");
  /* return value */
  return ret;
}

/******************************************************************************/
/*! \brief Set Device Information Command
 *
 *  This command is Set Device Information to SPC.
 *
 *  \param agRoot       Handles for this instance of SAS/SATA LLL
 *  \param agDevHandle  Handle of device
 *  \param deviceid     Device Id
 *  \param opton        oprion
 *
 *  \return If the MPI command is sent to SPC successfully
 *          - \e AGSA_RC_SUCCESS the MPI command is successfully
 *          - \e AGSA_RC_BUSY the SPC is no resource, cannot send now
 *          - \e AGSA_RC_FAILURE the MPI command is failure
 *
 */
/*******************************************************************************/
GLOBAL bit32 mpiSetDeviceInfoCmd(
  agsaRoot_t          *agRoot,
  agsaContext_t       *agContext,
  bit32               deviceid,
  bit32               option,
  bit32               queueNum,
  bit32               param,
  ossaSetDeviceInfoCB_t   agCB
  )
{
  agsaLLRoot_t            *saRoot = agNULL;
  agsaIORequestDesc_t     *pRequest = agNULL;
  bit32                   ret = AGSA_RC_SUCCESS;
  agsaSetDevInfoCmd_t     payload;

  smTraceFuncEnter(hpDBG_VERY_LOUD,"xe");

  /* sanity check */
  SA_ASSERT((agNULL != agRoot), "");
  saRoot = (agsaLLRoot_t *) (agRoot->sdkData);
  SA_ASSERT((agNULL != saRoot), "");

  /* Get request from free IORequests */
  ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
  pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeIORequests));

  SA_DBG2(("mpiSetDeviceInfoCmd, param 0x%08X option 0x%08X\n",param,option ));

  /* If no LL Control request entry available */
  if ( agNULL == pRequest )
  {
    SA_DBG1(("mpiSetDeviceInfoCmd, No request from free list\n" ));
    smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "xe");
    ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
    return AGSA_RC_BUSY;
  }
  /* If LL Control request entry avaliable */
  else
  {
    /* Remove the request from free list */
    saLlistIORemove(&(saRoot->freeIORequests), &(pRequest->linkNode));
    saRoot->IOMap[pRequest->HTag].Tag = pRequest->HTag;
    saRoot->IOMap[pRequest->HTag].IORequest = (void *)pRequest;
    saRoot->IOMap[pRequest->HTag].agContext = agContext;
    pRequest->valid = agTRUE;
    pRequest->completionCB = (ossaSSPCompletedCB_t)agCB;
    ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);

    /* set payload to zeros */
    si_memset(&payload, 0, sizeof(agsaSetDevInfoCmd_t));

    /* set tag field */

    if(smIS_SPC(agRoot))
    {
      option &= SET_DEV_INFO_SPC_DW3_MASK;
      param  &= SET_DEV_INFO_SPC_DW4_MASK;
    }
    else
    {
      option &= SET_DEV_INFO_V_DW3_MASK;
      param  &= SET_DEV_INFO_V_DW4_MASK;
    }

    OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSetDevInfoCmd_t, tag), pRequest->HTag);
    OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSetDevInfoCmd_t, deviceId), deviceid);
    OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSetDevInfoCmd_t, SA_SR_SI), option);
    OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSetDevInfoCmd_t, DEVA_MCN_R_ITNT), param );

    /* build IOMB command and send to SPC */
    ret = mpiBuildCmd(agRoot, (bit32 *)&payload, MPI_CATEGORY_SAS_SATA, OPC_INB_SET_DEV_INFO, IOMB_SIZE64, queueNum);
    if (AGSA_RC_SUCCESS != ret)
    {
      ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
      /* remove the request from IOMap */
      saRoot->IOMap[pRequest->HTag].Tag = MARK_OFF;
      saRoot->IOMap[pRequest->HTag].IORequest = agNULL;
      saRoot->IOMap[pRequest->HTag].agContext = agNULL;
      pRequest->valid = agFALSE;

      /* return the request to free pool */
      saLlistIOAdd(&(saRoot->freeIORequests), &(pRequest->linkNode));
      ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);

      SA_DBG1(("mpiSetDeviceInfoCmd, sending IOMB failed\n" ));
    }
    SA_DBG3(("mpiSetDeviceInfoCmd, return value = %d\n", ret));
  }

  smTraceFuncExit(hpDBG_VERY_LOUD, 'b', "xe");
  /* return value */

  return ret;
}

/******************************************************************************/
/*! \brief SPC MPI Phy Start Command
 *
 *  This command sends to SPC for the I/O.
 *
 *  \param agRoot        Handles for this instance of SAS/SATA LLL
 *  \param tag           tage for IOMB
 *  \param phyId         the phy id of the link will be started
 *  \param agPhyConfig   the phy properity
 *  \param agSASIdentify the SAS identify frame will be sent by the phy
 *
 *  \return If the MPI command is sent to SPC successfully
 *          - \e AGSA_RC_SUCCESS the MPI command is successfully
 *          - \e AGSA_RC_BUSY the SPC is no resource, cannot send now
 *          - \e AGSA_RC_FAILURE the MPI command is failure
 *
 */
/*******************************************************************************/
GLOBAL bit32 mpiPhyStartCmd(
  agsaRoot_t          *agRoot,
  bit32               tag,
  bit32               phyId,
  agsaPhyConfig_t     *agPhyConfig,
  agsaSASIdentify_t   *agSASIdentify,
  bit32               queueNum
  )
{
  bit32               ret = AGSA_RC_SUCCESS;
  agsaPhyStartCmd_t   payload;
  bit32               *pValue;
  bit32               *ptemp;
  bit32               index;
  bit32               dw2 = 0;

#if defined(SALLSDK_DEBUG)
  bit32               Sscd;
#endif  /* SALLSDK_DEBUG */
  smTraceFuncEnter(hpDBG_VERY_LOUD,"xg");

  /* set payload to zeros */
  si_memset(&payload, 0, sizeof(agsaPhyStartCmd_t));

  pValue = (bit32 *)agSASIdentify;
  ptemp = (bit32 *)&payload.sasIdentify;
  index = (agPhyConfig->phyProperties & 0x0ff00) >> SHIFT8;

#if defined(SALLSDK_DEBUG)
  Sscd =  (agPhyConfig->phyProperties & 0xf0000) >> SHIFT16;
#endif  /* SALLSDK_DEBUG */

  SA_DBG1(("mpiPhyStartCmd,phyId = %d dw 2 0x%08X\n",phyId ,((phyId & SM_PHYID_MASK) | ((agPhyConfig->phyProperties & 0xfff) << SHIFT8) | (agPhyConfig->phyProperties & 0xf0000) )));


  SA_DBG2(("mpiPhyStartCmd,phyId 0x%x phyProperties 0x%x index 0x%x Sscd 0x%x\n",phyId, agPhyConfig->phyProperties,index,Sscd));

  dw2 = ((phyId & SM_PHYID_MASK)                             | /* PHY id */
        ((agPhyConfig->phyProperties & 0x000000FF) << SHIFT8)| /* SLR Mode */
         (agPhyConfig->phyProperties & 0x000f0000)           | /* SSCD */
         (agPhyConfig->phyProperties & 0x00700000)           | /* setting bit20, bit21 and bit22 for optical mode */
         (agPhyConfig->phyProperties & 0x00800000) );          /* bit23 active cable mode BCT Disable 12g only*/

  /* Haileah Phy analogsetting bit enable*/
  if(smIS_SPC(agRoot))
  {
    if( smIS_spc8081(agRoot))
    {
       dw2 = dw2 | 0x08000;
     }
  }

  SA_DBG1(("mpiPhyStartCmd,dw2 0x%08x\n",dw2));
  SA_ASSERT(((agSASIdentify->sasAddressHi[0] || agSASIdentify->sasAddressHi[1] ||
  agSASIdentify->sasAddressHi[2] || agSASIdentify->sasAddressHi[3] ||
  agSASIdentify->sasAddressLo[0] || agSASIdentify->sasAddressLo[1] ||
  agSASIdentify->sasAddressLo[2] || agSASIdentify->sasAddressLo[3])), "SAS Address Zero");

  SA_DBG1(("mpiPhyStartCmd,SAS addr Hi 0x%02X%02X%02X%02X Lo 0x%02X%02X%02X%02X\n",
                                                              agSASIdentify->sasAddressHi[0],agSASIdentify->sasAddressHi[1],
                                                              agSASIdentify->sasAddressHi[2],agSASIdentify->sasAddressHi[3],
                                                              agSASIdentify->sasAddressLo[0],agSASIdentify->sasAddressLo[1],
                                                              agSASIdentify->sasAddressLo[2],agSASIdentify->sasAddressLo[3]));

  /* setup phy ID field */
  OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaPhyStartCmd_t, SscdAseSHLmMlrPhyId),dw2);

  OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaPhyStartCmd_t, tag), tag);

  /* setup analog setting index field */
  OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaPhyStartCmd_t, analogSetupIdx), index);
  /* copy SASIdentify to payload of IOMB */
  si_memcpy(ptemp, pValue, sizeof(agsaSASIdentify_t));

  /* build IOMB command and send to SPC */
  ret = mpiBuildCmd(agRoot, (bit32 *)&payload, MPI_CATEGORY_SAS_SATA, OPC_INB_PHYSTART, IOMB_SIZE64, queueNum);

  SA_DBG3(("mpiPhyStartCmd, return value = %d\n", ret));

  smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "xg");
  return ret;
}

/******************************************************************************/
/*! \brief SPC MPI Phy Stop Command
 *
 *  This command sends to SPC for the I/O.
 *
 *  \param agRoot       Handles for this instance of SAS/SATA LLL
 *  \param tag          tag of IOMB
 *  \param phyId        To stop the phyId
 *
 *  \return If the MPI command is sent to SPC successfully
 *          - \e AGSA_RC_SUCCESS the MPI command is successfully
 *          - \e AGSA_RC_BUSY the SPC is no resource, cannot send now
 *          - \e AGSA_RC_FAILURE the MPI command is failure
 *
 */
/*******************************************************************************/
GLOBAL bit32 mpiPhyStopCmd(
  agsaRoot_t          *agRoot,
  bit32               tag,
  bit32               phyId,
  bit32               queueNum
  )
{
  bit32 ret = AGSA_RC_SUCCESS;
  agsaPhyStopCmd_t    payload;

  smTraceFuncEnter(hpDBG_VERY_LOUD,"xh");

  /* set payload to zeros */
  si_memset(&payload, 0, sizeof(agsaPhyStopCmd_t));

  /* set tag */
  OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaPhyStopCmd_t, tag), tag);
  OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaPhyStopCmd_t, phyId), (phyId & SM_PHYID_MASK ));
  /* build IOMB command and send to SPC */
  ret = mpiBuildCmd(agRoot, (bit32 *)&payload, MPI_CATEGORY_SAS_SATA, OPC_INB_PHYSTOP, IOMB_SIZE64, queueNum);

  SA_DBG3(("mpiPhyStopCmd, return value = %d\n", ret));

  smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "xh");

  return ret;
}

/******************************************************************************/
/*! \brief SPC MPI SMP Request Command
 *
 *  This command sends to SPC for the SMP.
 *
 *  \param agRoot       Handles for this instance of SAS/SATA LLL
 *  \param pIomb        pointer of IOMB
 *  \param opcode       opcode of IOMB
 *  \param payload      pointer of payload
 *  \param inq          inbound queue number
 *  \param outq         outbound queue number
 *
 *  \return If the MPI command is sent to SPC successfully
 *          - \e AGSA_RC_SUCCESS the MPI command is successfully
 *          - \e AGSA_RC_BUSY the SPC is no resource, cannot send now
 *          - \e AGSA_RC_FAILURE the MPI command is failure
 *
 */
/*******************************************************************************/
GLOBAL bit32 mpiSMPCmd(
  agsaRoot_t             *agRoot,
  void                   *pIomb,
  bit16                  opcode,
  agsaSMPCmd_t           *payload,
  bit8                   inq,
  bit8                   outq
  )
{
  agsaLLRoot_t   *saRoot = (agsaLLRoot_t *) (agRoot->sdkData);
  mpiICQueue_t   *circularQ;
  bit32          ret = AGSA_RC_SUCCESS;
#if defined(SALLSDK_DEBUG)
 mpiMsgHeader_t *msgHeader;
  bit32                bc;
#endif /* SALLSDK_DEBUG */
  smTraceFuncEnter(hpDBG_VERY_LOUD,"xi");

  SA_DBG6(("mpiSMPCmd: start\n"));

#if defined(SALLSDK_DEBUG)
  msgHeader = (mpiMsgHeader_t*)(((bit8*)pIomb) - sizeof(mpiMsgHeader_t));
  bc = (((msgHeader->Header) >> SHIFT24) & BC_MASK);
#endif /* SALLSDK_DEBUG */
  SA_DBG6(("mpiSMPCmd: before msgHeader bc %d\n", bc));

  /* copy payload if it is necessary */
  if (agNULL != payload)
  {
    si_memcpy(pIomb, payload, sizeof(agsaSMPCmd_t));
  }

  SA_DBG6(("mpiSMPCmd: after msgHeader bc %d\n", bc));

  /* post the IOMB to SPC */
  circularQ = &saRoot->inboundQueue[inq];
  if (AGSA_RC_FAILURE == mpiMsgProduce(circularQ, (void *)pIomb, MPI_CATEGORY_SAS_SATA, opcode, outq, (bit8)circularQ->priority))
    ret = AGSA_RC_FAILURE;

  SA_DBG3(("mpiSMPCmd, return value = %d\n", ret));

  /* return value */
  smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "xi");
  return ret;
}

/******************************************************************************/
/*! \brief SPC MPI Deregister Device Handle Command
 *
 *  This command used to deregister(remove) the device handle.
 *
 *  \param agRoot       Handles for this instance of SAS/SATA LLL
 *  \param agDevHandle  Device Handle
 *  \param deviceId     index of device
 *  \param portId       index of port
 *  \param queueNum     IQ/OQ number
 *
 *  \return If the MPI command is sent to SPC successfully
 *          - \e AGSA_RC_SUCCESS the MPI command is successfully
 *          - \e AGSA_RC_BUSY the SPC is no resource, cannot send now
 *          - \e AGSA_RC_FAILURE the MPI command is failure
 *
 */
/*******************************************************************************/
GLOBAL bit32 mpiDeregDevHandleCmd(
  agsaRoot_t          *agRoot,
  agsaContext_t       *agContext,
  agsaDeviceDesc_t    *pDevice,
  bit32               deviceId,
  bit32               portId,
  bit32               queueNum
  )
{
  bit32                   ret = AGSA_RC_SUCCESS;
  agsaLLRoot_t            *saRoot = (agsaLLRoot_t *) (agRoot->sdkData);
  agsaIORequestDesc_t     *pRequest;
  agsaDeregDevHandleCmd_t payload;

  smTraceFuncEnter(hpDBG_VERY_LOUD,"xp");

  /* Get request from free IORequests */
  ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
  pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeIORequests));

  /* If no LL Control request entry available */
  if ( agNULL == pRequest )
  {
    SA_DBG1(("mpiDeregDevHandleCmd, No request from free list\n" ));
    smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "xp");
    ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
    return AGSA_RC_BUSY;
  }
  /* If LL Control request entry avaliable */
  else
  {
    pRequest->pDevice = pDevice;
    /* Remove the request from free list */
    SA_ASSERT((!pRequest->valid), "The pRequest is in use");
    pRequest->valid = agTRUE;
    saRoot->IOMap[pRequest->HTag].Tag = pRequest->HTag;
    saRoot->IOMap[pRequest->HTag].IORequest = (void *)pRequest;
    saRoot->IOMap[pRequest->HTag].agContext = agContext;
    saLlistIORemove(&(saRoot->freeIORequests), &(pRequest->linkNode));
    ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);

    /* clean the payload to zeros */
    si_memset(&payload, 0, sizeof(agsaDeregDevHandleCmd_t));

    OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaDeregDevHandleCmd_t, tag), pRequest->HTag);
    OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaDeregDevHandleCmd_t, deviceId), deviceId);

    /* build IOMB command and send it to SPC */
    ret = mpiBuildCmd(agRoot, (bit32 *)&payload, MPI_CATEGORY_SAS_SATA, OPC_INB_DEREG_DEV_HANDLE, IOMB_SIZE64, queueNum);
    if (AGSA_RC_SUCCESS != ret)
    {
      ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
      /* remove the request from IOMap */
      saRoot->IOMap[pRequest->HTag].Tag = MARK_OFF;
      saRoot->IOMap[pRequest->HTag].IORequest = agNULL;
      saRoot->IOMap[pRequest->HTag].agContext = agNULL;
      pRequest->valid = agFALSE;

      /* return the request to free pool */
      saLlistIOAdd(&(saRoot->freeIORequests), &(pRequest->linkNode));

      ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
      SA_DBG1(("mpiSetVPDCmd, sending IOMB failed\n" ));
    }
    SA_DBG3(("mpiDeregDevHandleCmd, return value = %d\n", ret));
  }

  smTraceFuncExit(hpDBG_VERY_LOUD, 'b', "xp");

  /* return value */
  return ret;
}

/******************************************************************************/
/*! \brief SPC MPI Get Device Handle Command
 *
 *  This command used to get device handle.
 *
 *  \param agRoot       Handles for this instance of SAS/SATA LLL
 *  \param agContext    Context of Device Handle Command
 *  \param portId       index of port
 *  \param flags        flags
 *  \param maxDevs      Maximum Device Handles
 *  \param queueNum     IQ/OQ number
 *  \param skipCount    skip device entry count
 *
 *  \return If the MPI command is sent to SPC successfully
 *          - \e AGSA_RC_SUCCESS the MPI command is successfully
 *          - \e AGSA_RC_BUSY the SPC is no resource, cannot send now
 *          - \e AGSA_RC_FAILURE the MPI command is failure
 *
 */
/*******************************************************************************/
GLOBAL bit32 mpiGetDeviceHandleCmd(
  agsaRoot_t          *agRoot,
  agsaContext_t       *agContext,
  bit32               portId,
  bit32               flags,
  bit32               maxDevs,
  bit32               queueNum,
  bit32               skipCount
  )
{
  bit32                 ret = AGSA_RC_SUCCESS;
  agsaLLRoot_t          *saRoot = (agsaLLRoot_t *) (agRoot->sdkData);
  agsaIORequestDesc_t   *pRequest;
  agsaGetDevHandleCmd_t payload;
  bit32               using_reserved = agFALSE;

  smTraceFuncEnter(hpDBG_VERY_LOUD,"xj");

  /* Get request from free CntrlRequests */
  ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
  pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeIORequests));

  /* If no LL Control request entry available */
  if ( agNULL == pRequest )
  {
    pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeReservedRequests)); /**/
    if(agNULL != pRequest)
    {
      using_reserved = agTRUE;
      SA_DBG1(("mpiGetDeviceHandleCmd, using saRoot->freeReservedRequests\n"));
    }
    else
    {
      SA_DBG1(("mpiGetDeviceHandleCmd, No request from free list Not using saRoot->freeReservedRequests\n"));
      smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "xj");
      ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
      return AGSA_RC_BUSY;
    }
  }

  /* Remove the request from free list */
  if( using_reserved )
  {
    saLlistIORemove(&(saRoot->freeReservedRequests), &(pRequest->linkNode));
  }
  else
  {
    saLlistIORemove(&(saRoot->freeIORequests), &(pRequest->linkNode));
  }
  SA_ASSERT((!pRequest->valid), "The pRequest is in use");
  saRoot->IOMap[pRequest->HTag].Tag = pRequest->HTag;
  saRoot->IOMap[pRequest->HTag].IORequest = (void *)pRequest;
  saRoot->IOMap[pRequest->HTag].agContext = agContext;
  pRequest->valid = agTRUE;
  ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);


  /* clean the payload to zeros */
  si_memset(&payload, 0, sizeof(agsaGetDevHandleCmd_t));
  OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaGetDevHandleCmd_t, tag), pRequest->HTag);
  OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaGetDevHandleCmd_t, DevADevTMaxDIDportId),
                   ((portId & PORTID_MASK) | (maxDevs << SHIFT8) | (flags << SHIFT24)));
    /* set starting Number */
  OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaGetDevHandleCmd_t, skipCount), skipCount);

  /* build IOMB command and send it to SPC */
  ret = mpiBuildCmd(agRoot, (bit32 *)&payload, MPI_CATEGORY_SAS_SATA, OPC_INB_GET_DEV_HANDLE, IOMB_SIZE64, queueNum);
  if (AGSA_RC_SUCCESS != ret)
  {
    ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
    /* remove the request from IOMap */
    saRoot->IOMap[pRequest->HTag].Tag = MARK_OFF;
    saRoot->IOMap[pRequest->HTag].IORequest = agNULL;
    saRoot->IOMap[pRequest->HTag].agContext = agNULL;
    pRequest->valid = agFALSE;
    /* return the request to free pool */
    if(saLlistIOGetCount(&(saRoot->freeReservedRequests)) < SA_RESERVED_REQUEST_COUNT)
    {
      SA_DBG1(("mpiGetDeviceHandleCmd: saving pRequest (%p) for later use\n", pRequest));
      saLlistIOAdd(&(saRoot->freeReservedRequests), &(pRequest->linkNode));
    }
    else
    {
      /* return the request to free pool */
      saLlistIOAdd(&(saRoot->freeIORequests), &(pRequest->linkNode));
    }
    ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);

    SA_DBG1(("mpiGetDeviceHandleCmd, sending IOMB failed\n" ));
  }
  SA_DBG3(("mpiGetDeviceHandleCmd, return value = %d\n", ret));

  smTraceFuncExit(hpDBG_VERY_LOUD, 'b', "xj");

  return ret;
}

/******************************************************************************/
/*! \brief SPC MPI LOCAL PHY CONTROL Command
 *
 *  This command used to do the SPC Phy operation.
 *
 *  \param agRoot       Handles for this instance of SAS/SATA LLL
 *  \param tag          tag of IOMB
 *  \param phyId        PHY Id
 *  \param operation    operation of PHY control
 *  \param queueNum     IQ/OQ number
 *
 *  \return If the MPI command is sent to SPC successfully
 *          - \e AGSA_RC_SUCCESS the MPI command is successfully
 *          - \e AGSA_RC_BUSY the SPC is no resource, cannot send now
 *          - \e AGSA_RC_FAILURE the MPI command is failure
 *
 */
/*******************************************************************************/
GLOBAL bit32 mpiLocalPhyControlCmd(
  agsaRoot_t          *agRoot,
  bit32               tag,
  bit32               phyId,
  bit32               operation,
  bit32               queueNum
  )
{
  bit32                   ret = AGSA_RC_SUCCESS;
  agsaLocalPhyCntrlCmd_t  payload;
  smTraceFuncEnter(hpDBG_VERY_LOUD,"xl");

  SA_DBG3(("mpiLocalPhyControlCmd, phyId 0x%X operation 0x%x dw2 0x%x\n",phyId, operation,(((operation & BYTE_MASK) << SHIFT8) | (phyId & SM_PHYID_MASK))));

  /* clean the payload field */
  si_memset(&payload, 0, sizeof(agsaLocalPhyCntrlCmd_t));

  OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaLocalPhyCntrlCmd_t, phyOpPhyId),
    (((operation & BYTE_MASK) << SHIFT8) | (phyId & SM_PHYID_MASK)));
  OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaLocalPhyCntrlCmd_t, tag), tag);
  /* build IOMB command and send to SPC */
  ret = mpiBuildCmd(agRoot, (bit32 *)&payload, MPI_CATEGORY_SAS_SATA, OPC_INB_LOCAL_PHY_CONTROL, IOMB_SIZE64, queueNum);

  SA_DBG3(("mpiLocalPhyControlCmd, return value = %d\n", ret));

  /* return value */
  smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "xl");
  return ret;
}

/******************************************************************************/
/*! \brief Device Handle Accept Command
 *
 *  This command is Device Handle Accept IOMB to SPC.
 *
 *  \param agRoot       Handles for this instance of SAS/SATA LLL
 *  \param agContext    Context for the set VPD command
 *  \param ctag         controller tag
 *  \param deviceId     device Id
 *  \param action       action
 *  \param queueNum     queue Number
 *
 *  \return If the MPI command is sent to SPC successfully
 *          - \e AGSA_RC_SUCCESS the MPI command is successfully
 *          - \e AGSA_RC_BUSY the SPC is no resource, cannot send now
 *          - \e AGSA_RC_FAILURE the MPI command is failure
 *
 */
/*******************************************************************************/
GLOBAL bit32 mpiDevHandleAcceptCmd(
  agsaRoot_t          *agRoot,
  agsaContext_t       *agContext,
  bit32               ctag,
  bit32               deviceId,
  bit32               action,
  bit32               flag,
  bit32               itlnx,
  bit32               queueNum
  )
{
  bit32                    ret = AGSA_RC_SUCCESS;
  agsaLLRoot_t             *saRoot = (agsaLLRoot_t *) (agRoot->sdkData);
  agsaIORequestDesc_t      *pRequest;
  agsaDevHandleAcceptCmd_t payload;
  bit32                    DW4 =0;
  bit32                    mcn =0;
  bit32                    awt =0;
  bit32                    ha =0;

  smTraceFuncEnter(hpDBG_VERY_LOUD,"xt");

  if(deviceId & 0xFFFF0000)
  {
    ha = 1;
  }
  /* Get request from free IORequests */
  ossaSingleThreadedEnter(agRoot,LL_IOREQ_LOCKEQ_LOCK );
  pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeIORequests));

  SA_DBG2(("mpiDevHandleAcceptCmd, deviceId 0x%x action 0x%x flag 0x%x itlnx 0x%x\n",deviceId,action,flag,itlnx ));

  /* If no LL Control request entry available */
  if ( agNULL == pRequest )
  {
    ossaSingleThreadedLeave(agRoot,LL_IOREQ_LOCKEQ_LOCK );
    SA_DBG1(("mpiDevHandleAcceptCmd, No request from free list\n" ));
    smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "xt");
    return AGSA_RC_BUSY;
  }
  /* If LL Control request entry avaliable */
  else
  {
    /* Remove the request from free list */
    SA_ASSERT((!pRequest->valid), "The pRequest is in use");
    saLlistIORemove(&(saRoot->freeIORequests), &(pRequest->linkNode));
    saRoot->IOMap[pRequest->HTag].Tag = pRequest->HTag;
    saRoot->IOMap[pRequest->HTag].IORequest = (void *)pRequest;
    saRoot->IOMap[pRequest->HTag].agContext = agContext;
    ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);

    /* Do not mark as valid at this IOMB does not complete in OBQ */

    /* set payload to zeros */
    si_memset(&payload, 0, sizeof(agsaDevHandleAcceptCmd_t));

    /* set tag field */
    OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaDevHandleAcceptCmd_t, tag), pRequest->HTag);
    OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaDevHandleAcceptCmd_t, deviceId), deviceId);
    OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaDevHandleAcceptCmd_t, Ctag), ctag);
    mcn = (flag & 0xF0000) >>SHIFT16;
    awt = (flag & 2)>>SHIFT1;
    DW4 = (action << SHIFT24) | \
             mcn << SHIFT20   | \
             awt << SHIFT17   | \
             ha  << SHIFT16   | \
                     itlnx;
    SA_DBG2(("mpiDevHandleAcceptCmd,DW4 0x%x\n",DW4 ));
    OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaDevHandleAcceptCmd_t, DevA_MCN_R_R_HA_ITNT),DW4);
  }

  /* build IOMB command and send to SPC */
  ret = mpiBuildCmd(agRoot, (bit32 *)&payload, MPI_CATEGORY_SAS_SATA, OPC_INB_DEV_HANDLE_ACCEPT, IOMB_SIZE64, queueNum);
  if (AGSA_RC_SUCCESS != ret)
  {
    SA_DBG1(("mpiDevHandleAcceptCmd, sending IOMB failed\n" ));
  }
  else
  {
    SA_DBG1(("mpiDevHandleAcceptCmd, sending IOMB succeeded\n" ));
  }

  ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
  /* remove the request from IOMap */
  saRoot->IOMap[pRequest->HTag].Tag = MARK_OFF;
  saRoot->IOMap[pRequest->HTag].IORequest = agNULL;
  saRoot->IOMap[pRequest->HTag].agContext = agNULL;
  pRequest->valid = agFALSE;
  /* return the request to free pool */
  if(saLlistIOGetCount(&(saRoot->freeReservedRequests)) < SA_RESERVED_REQUEST_COUNT)
  {
    SA_DBG1(("mpiDevHandleAcceptCmd: saving pRequest (%p) for later use\n", pRequest));
    saLlistIOAdd(&(saRoot->freeReservedRequests), &(pRequest->linkNode));
  }
  else
  {
    /* return the request to free pool */
    saLlistIOAdd(&(saRoot->freeIORequests), &(pRequest->linkNode));
  }

  /* return value */
  ossaSingleThreadedLeave(agRoot,LL_IOREQ_LOCKEQ_LOCK );
  smTraceFuncExit(hpDBG_VERY_LOUD, 'b', "xt");
  return ret;
}

/******************************************************************************/
/*! \brief SPC READ REGISTER DUMP Command
 *
 *  This command used to do the SPC Read Register Dump command.
 *
 *  \param agRoot       Handles for this instance of SAS/SATA LLL
 *  \param tag          tag of IOMB
 *  \param cpuId        CPU Id
 *  \param queueNum     IQ/OQ number
 *  \param cpuId        AAP1 or IOP
 *  \param cOffset      offset of the register dump data
 *  \param addrHi       Hi address if Register Dump data
 *  \param addrHi       Low address if Register Dump data
 *  \param len          the length of for read
 *
 *  \return If the MPI command is sent to SPC successfully
 *          - \e AGSA_RC_SUCCESS the MPI command is successfully
 *          - \e AGSA_RC_BUSY the SPC is no resource, cannot send now
 *          - \e AGSA_RC_FAILURE the MPI command is failure
 *
 */
/*******************************************************************************/
GLOBAL bit32 mpiNVMReadRegDumpCmd(
  agsaRoot_t          *agRoot,
  agsaContext_t       *agContext,
  bit32               queueNum,
  bit32               cpuId,
  bit32               cOffset,
  bit32               addrHi,
  bit32               addrLo,
  bit32               len
  )
{
  bit32                 ret = AGSA_RC_SUCCESS;
  agsaLLRoot_t          *saRoot = (agsaLLRoot_t *) (agRoot->sdkData);
  agsaIORequestDesc_t   *pRequest;
  agsaGetNVMDataCmd_t   payload;
  bit32 nvmd = 0;

  smTraceFuncEnter(hpDBG_VERY_LOUD,"xk");

  /* Get request from free IORequests */
  ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
  pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeIORequests));

  /* If no LL Control request entry available */
  if ( agNULL == pRequest )
  {
    SA_DBG1(("mpiNVMReadRegDumpCmd, No request from free list\n" ));
    smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "xk");
    ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
    return AGSA_RC_BUSY;
  }
  /* If LL Control request entry avaliable */
  else
  {
    /* Remove the request from free list */
    SA_ASSERT((!pRequest->valid), "The pRequest is in use");
    saLlistIORemove(&(saRoot->freeIORequests), &(pRequest->linkNode));
    saRoot->IOMap[pRequest->HTag].Tag = pRequest->HTag;
    saRoot->IOMap[pRequest->HTag].IORequest = (void *)pRequest;
    saRoot->IOMap[pRequest->HTag].agContext = agContext;
    pRequest->valid = agTRUE;
    ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);

    /* clean the payload field */
    si_memset(&payload, 0, sizeof(agsaGetNVMDataCmd_t));

    /* only indirect mode */
    if (cpuId <= 1)
    {
      if (cpuId == 0)
        nvmd = AAP1_RDUMP | IRMode;
      else
        nvmd = IOP_RDUMP | IRMode;

      /* setup IOMB */
      OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaGetNVMDataCmd_t, tag), pRequest->HTag);
      OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaGetNVMDataCmd_t, LEN_IR_VPDD), nvmd);
      OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaGetNVMDataCmd_t, VPDOffset), cOffset);
      OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaGetNVMDataCmd_t, respAddrLo), addrLo);
      OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaGetNVMDataCmd_t, respAddrHi), addrHi);
      OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaGetNVMDataCmd_t, respLen), len);

      /* build IOMB command and send to SPC */
      ret = mpiBuildCmd(agRoot, (bit32 *)&payload, MPI_CATEGORY_SAS_SATA, OPC_INB_GET_NVMD_DATA, IOMB_SIZE64, queueNum);
    }
    else
    {
      SA_DBG1(("mpiNVMReadRegDumpCmd, Wrong device type\n" ));
      ret = AGSA_RC_FAILURE;
    }

    if (AGSA_RC_SUCCESS != ret)
    {
      ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
      /* remove the request from IOMap */
      saRoot->IOMap[pRequest->HTag].Tag = MARK_OFF;
      saRoot->IOMap[pRequest->HTag].IORequest = agNULL;
      saRoot->IOMap[pRequest->HTag].agContext = agNULL;
      pRequest->valid = agFALSE;
      /* return the request to free pool */
      saLlistIOAdd(&(saRoot->freeIORequests), &(pRequest->linkNode));

      ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
      SA_DBG1(("mpiNVMReadRegDumpCmd, sending IOMB failed\n" ));
    }
  }

  SA_DBG3(("mpiNVMReadRegDumpCmd, return value = %d\n", ret));

  /* return value */
  smTraceFuncExit(hpDBG_VERY_LOUD, 'b', "xk");

  return ret;
}

/******************************************************************************/
/*! \brief Get NVM Data command
 *
 *  This command is get NVM Data from SPC.
 *
 *  \param agRoot       Handles for this instance of SAS/SATA LLL
 *  \param agContext    Context for the VPD command
 *  \param VPDInfo      Pointer of VPD Information
 *  \param queueNum     Queue Number of inbound/outbound queue
 *
 *  \return If the MPI command is sent to SPC successfully
 *          - \e AGSA_RC_SUCCESS the MPI command is successfully
 *          - \e AGSA_RC_BUSY the SPC is no resource, cannot send now
 *          - \e AGSA_RC_FAILURE the MPI command is failure
 *
 */
/*******************************************************************************/
GLOBAL bit32 mpiGetNVMDCmd(
  agsaRoot_t          *agRoot,
  agsaContext_t       *agContext,
  agsaNVMDData_t      *NVMDInfo,
  bit32               queueNum
  )
{
  bit32                 ret = AGSA_RC_FAILURE;
  agsaLLRoot_t          *saRoot = (agsaLLRoot_t *) (agRoot->sdkData);
  agsaIORequestDesc_t   *pRequest;
  agsaGetNVMDataCmd_t   payload;

  smTraceFuncEnter(hpDBG_VERY_LOUD,"xr");

  /* Get request from free IORequests */
  ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
  pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeIORequests));

  /* If no LL Control request entry available */
  if ( agNULL == pRequest )
  {
    SA_DBG1(("mpiGetNVMDCmd, No request from free list\n" ));
    smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "xr");
    ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
    return AGSA_RC_BUSY;
  }
  /* If LL Control request entry avaliable */
  else
  {
    SA_DBG3(("mpiGetNVMDCmd, Build IOMB NVMDDevice= 0x%x\n", NVMDInfo->NVMDevice));
    /* Remove the request from free list */
    SA_ASSERT((!pRequest->valid), "The pRequest is in use");
    saLlistIORemove(&(saRoot->freeIORequests), &(pRequest->linkNode));
    saRoot->IOMap[pRequest->HTag].Tag = pRequest->HTag;
    saRoot->IOMap[pRequest->HTag].IORequest = (void *)pRequest;
    saRoot->IOMap[pRequest->HTag].agContext = agContext;
    pRequest->valid = agTRUE;
    ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);

    /* set payload to zeros */
    si_memset(&payload, 0, sizeof(agsaGetNVMDataCmd_t));
    /* set tag field */
    OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaGetNVMDataCmd_t, tag), pRequest->HTag);

    if (NVMDInfo->indirectPayload)
    {
      /* indirect payload IP = 1 */
      switch (NVMDInfo->NVMDevice)
      {
      case AGSA_NVMD_TWI_DEVICES:
        /* NVMD = 0 */
        /* indirect payload IP = 1 and 0x0 (TWI) */
        OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaGetNVMDataCmd_t, LEN_IR_VPDD),
          (NVMDInfo->TWIDeviceAddress << 16) | (NVMDInfo->TWIBusNumber << 12) |
          (NVMDInfo->TWIDevicePageSize << 8) | (NVMDInfo->TWIDeviceAddressSize << 4) |
          (NVMDInfo->indirectPayload << 31) | NVMDInfo->NVMDevice);
            OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaGetNVMDataCmd_t, VPDOffset),
          NVMDInfo->dataOffsetAddress);
        break;
      case AGSA_NVMD_CONFIG_SEEPROM:
        /* NVMD = 1 */
        /* Data Offset should be 0 */
        if (NVMDInfo->dataOffsetAddress != 0)
        {
          /* Error for Offset */
          SA_DBG1(("mpiGetNVMDCmd, (IP=1)wrong offset = 0x%x\n", NVMDInfo->dataOffsetAddress));
        }
        /* indirect payload IP = 1, NVMD = 0x1 (SEEPROM0) */
        OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaGetNVMDataCmd_t, LEN_IR_VPDD),
          (NVMDInfo->indirectPayload << SHIFT31) | (NVMDInfo->NVMDevice));
        break;
      case AGSA_NVMD_VPD_FLASH:
        /* indirect payload IP = 1 and 0x4 (FLASH) */
        OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaGetNVMDataCmd_t, LEN_IR_VPDD),
          (NVMDInfo->indirectPayload << SHIFT31) | NVMDInfo->NVMDevice);
        OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaGetNVMDataCmd_t, VPDOffset),
          NVMDInfo->dataOffsetAddress);
        break;
      case AGSA_NVMD_EXPANSION_ROM:
        /* indirect payload IP = 1 and 0x7 (EXPANSION ROM PARTITION) */
        OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaGetNVMDataCmd_t, LEN_IR_VPDD),
          (NVMDInfo->indirectPayload << SHIFT31) | NVMDInfo->NVMDevice);
        OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaGetNVMDataCmd_t, VPDOffset),
          NVMDInfo->dataOffsetAddress);
        break;
      case  AGSA_NVMD_AAP1_REG_FLASH: /* AGSA_NVMD_REG_FLASH  SPCv uses 5 as well */
        /* indirect payload IP = 1 and 0x5 (AGSA_NVMD_AAP1_REG_FLASH ) */
        OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaGetNVMDataCmd_t, LEN_IR_VPDD),
          (NVMDInfo->indirectPayload << SHIFT31) | NVMDInfo->NVMDevice);
        OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaGetNVMDataCmd_t, VPDOffset),
          NVMDInfo->dataOffsetAddress);
        break;
      case  AGSA_NVMD_IOP_REG_FLASH:
        /* indirect payload IP = 1 and 0x6 ( AGSA_NVMD_IOP_REG_FLASH ) */
        OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaGetNVMDataCmd_t, LEN_IR_VPDD),
          (NVMDInfo->indirectPayload << SHIFT31) | NVMDInfo->NVMDevice);
        OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaGetNVMDataCmd_t, VPDOffset),
          NVMDInfo->dataOffsetAddress);
        break;

      default:
        SA_DBG1(("mpiGetNVMDCmd, (IP=1)wrong device type = 0x%x\n", NVMDInfo->NVMDevice));
        break;
      }

      OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaGetNVMDataCmd_t, respAddrLo), NVMDInfo->indirectAddrLower32);
      OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaGetNVMDataCmd_t, respAddrHi), NVMDInfo->indirectAddrUpper32);
      OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaGetNVMDataCmd_t, respLen), NVMDInfo->indirectLen);
      /* build IOMB command and send to SPC */
      ret = mpiBuildCmd(agRoot, (bit32 *)&payload, MPI_CATEGORY_SAS_SATA, OPC_INB_GET_NVMD_DATA, IOMB_SIZE64, queueNum);
    }
    else
    {
      /* direct payload IP = 0 only for TWI device */
      if (AGSA_NVMD_TWI_DEVICES == NVMDInfo->NVMDevice)
      {
        /* NVMD = 0 */
        /* indirect payload IP = 0 and 0x0 (TWI) */
        OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaGetNVMDataCmd_t, LEN_IR_VPDD),
          (NVMDInfo->TWIDeviceAddress << SHIFT16) | (NVMDInfo->TWIBusNumber << SHIFT12) |
          (NVMDInfo->TWIDevicePageSize << SHIFT8) | (NVMDInfo->TWIDeviceAddressSize << SHIFT4) |
          NVMDInfo->NVMDevice);
            OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaGetNVMDataCmd_t, VPDOffset),
          NVMDInfo->dataOffsetAddress | (NVMDInfo->directLen << SHIFT24));
        /* build IOMB command and send to SPC */
        ret = mpiBuildCmd(agRoot, (bit32 *)&payload, MPI_CATEGORY_SAS_SATA, OPC_INB_GET_NVMD_DATA, IOMB_SIZE64, queueNum);
      }
      else
      {
        SA_DBG1(("mpiGetNVMDCmd, (IP=0)wrong device type = 0x%x\n", NVMDInfo->NVMDevice));
        ret = AGSA_RC_FAILURE;
        /* CB for NVMD with error */
        ossaGetNVMDResponseCB(agRoot, agContext, OSSA_NVMD_MODE_ERROR, 0, NVMDInfo->directLen, agNULL);
      }
    }

    if (AGSA_RC_SUCCESS != ret)
    {
      ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
      /* remove the request from IOMap */
      saRoot->IOMap[pRequest->HTag].Tag = MARK_OFF;
      saRoot->IOMap[pRequest->HTag].IORequest = agNULL;
      saRoot->IOMap[pRequest->HTag].agContext = agNULL;
      pRequest->valid = agFALSE;

      /* return the request to free pool */
      saLlistIOAdd(&(saRoot->freeIORequests), &(pRequest->linkNode));

      ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
      SA_DBG1(("mpiGetNVMDCmd, sending IOMB failed\n" ));
    }
    SA_DBG3(("mpiGetNVMDCmd, return value = %d\n", ret));
  }

  smTraceFuncExit(hpDBG_VERY_LOUD, 'b', "xr");

  /* return value */
  return ret;
}

/******************************************************************************/
/*! \brief Set NVM Data Command
 *
 *  This command is set NVM Data to SPC.
 *
 *  \param agRoot       Handles for this instance of SAS/SATA LLL
 *  \param agContext    Context for the set VPD command
 *  \param NVMDInfo      pointer of VPD information
 *  \param queueNum     queue Number
 *
 *  \return If the MPI command is sent to SPC successfully
 *          - \e AGSA_RC_SUCCESS the MPI command is successfully
 *          - \e AGSA_RC_BUSY the SPC is no resource, cannot send now
 *          - \e AGSA_RC_FAILURE the MPI command is failure
 *
 */
/*******************************************************************************/
GLOBAL bit32 mpiSetNVMDCmd(
  agsaRoot_t          *agRoot,
  agsaContext_t       *agContext,
  agsaNVMDData_t      *NVMDInfo,
  bit32               queueNum
  )
{
  bit32               ret = AGSA_RC_FAILURE;
  agsaLLRoot_t        *saRoot = (agsaLLRoot_t *) (agRoot->sdkData);
  agsaIORequestDesc_t *pRequest;
  agsaSetNVMDataCmd_t payload;

  smTraceFuncEnter(hpDBG_VERY_LOUD,"xm");


  /* Get request from free IORequests */
  ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
  pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeIORequests));

  /* If no LL Control request entry available */
  if ( agNULL == pRequest )
  {
    SA_DBG1(("mpiSetNVMDCmd, No request from free list\n" ));
    smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "xm");
    ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
    return AGSA_RC_BUSY;
  }
  /* If LL Control request entry avaliable */
  else
  {
    SA_DBG3(("mpiSetNVMDCmd, Build IOMB NVMDDevice= 0x%x\n", NVMDInfo->NVMDevice));
    /* Remove the request from free list */
    SA_ASSERT((!pRequest->valid), "The pRequest is in use");
    saLlistIORemove(&(saRoot->freeIORequests), &(pRequest->linkNode));
    saRoot->IOMap[pRequest->HTag].Tag = pRequest->HTag;
    saRoot->IOMap[pRequest->HTag].IORequest = (void *)pRequest;
    saRoot->IOMap[pRequest->HTag].agContext = agContext;
    pRequest->valid = agTRUE;
    ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);

    /* set payload to zeros */
    si_memset(&payload, 0, sizeof(agsaSetNVMDataCmd_t));

    /* set tag field */
    OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSetNVMDataCmd_t, tag), pRequest->HTag);

    if (NVMDInfo->indirectPayload)
    {
      /* indirect payload IP = 1 */
      switch (NVMDInfo->NVMDevice)
      {
      case AGSA_NVMD_TWI_DEVICES:
        /* NVMD = 0 */
        /* indirect payload IP = 1 and 0x0 (TWI) */
        /* set up signature */
        OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSetNVMDataCmd_t, Data.indirectData.signature), NVMDInfo->signature);
        OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSetNVMDataCmd_t, LEN_IR_VPDD),
          (NVMDInfo->TWIDeviceAddress << SHIFT16) | (NVMDInfo->TWIBusNumber << SHIFT12) |
          (NVMDInfo->TWIDevicePageSize << SHIFT8) | (NVMDInfo->TWIDeviceAddressSize << SHIFT4) |
          (NVMDInfo->indirectPayload << SHIFT31) | NVMDInfo->NVMDevice);
        OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSetNVMDataCmd_t, VPDOffset),
          NVMDInfo->dataOffsetAddress);
        break;
      /* 0x01:SEEPROM-0 and 0x04:FLASH only in indirect mode */
      case AGSA_NVMD_CONFIG_SEEPROM:
        /* NVMD=1 */
        /* Data Offset should be 0 */
        /* set up signature */
        OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSetNVMDataCmd_t, Data.indirectData.signature), NVMDInfo->signature);
        /* indirect payload IP = 1, NVMD = 0x1 (SEEPROM0) */
        OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSetNVMDataCmd_t, LEN_IR_VPDD),
          (NVMDInfo->indirectPayload << SHIFT31) | NVMDInfo->NVMDevice);
        break;
      case AGSA_NVMD_VPD_FLASH:
        /* indirect payload IP = 1, NVMD=0x4 (FLASH) */
        OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSetNVMDataCmd_t, LEN_IR_VPDD),
          (NVMDInfo->indirectPayload << SHIFT31) | NVMDInfo->NVMDevice);
        /* set up Offset */
            OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSetNVMDataCmd_t, VPDOffset),
          NVMDInfo->dataOffsetAddress);
        break;
      default:
        SA_DBG1(("mpiSetNVMDCmd, (IP=1)wrong device type = 0x%x\n", NVMDInfo->NVMDevice));
        ret = AGSA_RC_FAILURE;
        ossaSetNVMDResponseCB(agRoot, agContext, OSSA_NVMD_MODE_ERROR);
        break;
      }

      /* set up SGL field */
      OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSetNVMDataCmd_t, Data.indirectData.ISglAL), (NVMDInfo->indirectAddrLower32));
      OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSetNVMDataCmd_t, Data.indirectData.ISglAH), (NVMDInfo->indirectAddrUpper32));
      OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSetNVMDataCmd_t, Data.indirectData.ILen), (NVMDInfo->indirectLen));
      /* build IOMB command and send to SPC */
      ret = mpiBuildCmd(agRoot, (bit32 *)&payload, MPI_CATEGORY_SAS_SATA, OPC_INB_SET_NVMD_DATA, IOMB_SIZE64, queueNum);
    }
    else
    {
      /* direct payload IP = 0 */
      if (AGSA_NVMD_TWI_DEVICES == NVMDInfo->NVMDevice)
      {
        /* NVMD = 0 */
        /* indirect payload IP = 0 and 0x0 (TWI) */
        /* not allow write to Config SEEPROM for direct mode, so don't set singature */
        OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSetNVMDataCmd_t, LEN_IR_VPDD),
          (NVMDInfo->TWIDeviceAddress << SHIFT16) | (NVMDInfo->TWIBusNumber << SHIFT12) |
          (NVMDInfo->TWIDevicePageSize << SHIFT8) | (NVMDInfo->TWIDeviceAddressSize << SHIFT4) |
          NVMDInfo->NVMDevice);
        OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSetNVMDataCmd_t, VPDOffset),
          NVMDInfo->dataOffsetAddress | (NVMDInfo->directLen << SHIFT24));
        si_memcpy(&payload.Data.NVMData[0], NVMDInfo->directData, NVMDInfo->directLen);
        /* build IOMB command and send to SPC */
        ret = mpiBuildCmd(agRoot, (bit32 *)&payload, MPI_CATEGORY_SAS_SATA, OPC_INB_SET_NVMD_DATA, IOMB_SIZE64, queueNum);
      }
      else
      {
        SA_DBG1(("mpiSetNVMDCmd, (IP=0)wrong device type = 0x%x\n", NVMDInfo->NVMDevice));
        ret = AGSA_RC_FAILURE;
        ossaSetNVMDResponseCB(agRoot, agContext, OSSA_NVMD_MODE_ERROR);
      }
    }

    if (AGSA_RC_SUCCESS != ret)
    {
      ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
      /* remove the request from IOMap */
      saRoot->IOMap[pRequest->HTag].Tag = MARK_OFF;
      saRoot->IOMap[pRequest->HTag].IORequest = agNULL;
      saRoot->IOMap[pRequest->HTag].agContext = agNULL;
      pRequest->valid = agFALSE;

      /* return the request to free pool */
      saLlistIOAdd(&(saRoot->freeIORequests), &(pRequest->linkNode));
      ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
      SA_DBG1(("mpiSetVPDCmd, sending IOMB failed\n" ));
    }
    SA_DBG3(("mpiSetNVMDCmd, return value = %d\n", ret));
  }


  /* return value */
  smTraceFuncExit(hpDBG_VERY_LOUD, 'b', "xm");
  return ret;
}

/******************************************************************************/
/*! \brief Set Device State command
 *
 *  This command is set Device State to SPC.
 *
 *  \param agRoot       Handles for this instance of SAS/SATA LLL
 *  \param agContext    Context for the Set Nexus State command
 *  \param deviceId     DeviceId
 *  \param queueNum     Queue Number of inbound/outbound queue
 *
 *  \return If the MPI command is sent to SPC successfully
 *          - \e AGSA_RC_SUCCESS the MPI command is successfully
 *          - \e AGSA_RC_BUSY the SPC is no resource, cannot send now
 *          - \e AGSA_RC_FAILURE the MPI command is failure
 *
 */
/*******************************************************************************/
GLOBAL bit32 mpiSetDeviceStateCmd(
  agsaRoot_t          *agRoot,
  agsaContext_t       *agContext,
  bit32               deviceId,
  bit32               nds,
  bit32               queueNum
  )
{
  bit32                  ret = AGSA_RC_SUCCESS;
  agsaLLRoot_t           *saRoot = (agsaLLRoot_t *) (agRoot->sdkData);
  agsaIORequestDesc_t    *pRequest;
  agsaSetDeviceStateCmd_t payload;

  smTraceFuncEnter(hpDBG_VERY_LOUD,"xn");

  /* Get request from free IORequests */
  ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
  pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeIORequests));

  /* If no LL Control request entry available */
  if ( agNULL == pRequest )
  {
    SA_DBG1(("mpiSetDeviceStateCmd, No request from free list\n" ));
    smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "xn");
    ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
    return AGSA_RC_BUSY;
  }
  /* If LL Control request entry avaliable */
  else
  {
    SA_DBG3(("mpiSetDeviceStateCmd, Build IOMB DeviceId= 0x%x\n", deviceId));
    /* Remove the request from free list */
    saLlistIORemove(&(saRoot->freeIORequests), &(pRequest->linkNode));
    saRoot->IOMap[pRequest->HTag].Tag = pRequest->HTag;
    saRoot->IOMap[pRequest->HTag].IORequest = (void *)pRequest;
    saRoot->IOMap[pRequest->HTag].agContext = agContext;
    pRequest->valid = agTRUE;
    ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);

    /* set payload to zeros */
    si_memset(&payload, 0, sizeof(agsaSetDeviceStateCmd_t));
    /* set tag field */
    OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSetDeviceStateCmd_t, tag), pRequest->HTag);
    OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSetDeviceStateCmd_t, deviceId), deviceId);
    OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSetDeviceStateCmd_t, NDS), nds);

    /* build IOMB command and send to SPC */
    ret = mpiBuildCmd(agRoot, (bit32 *)&payload, MPI_CATEGORY_SAS_SATA, OPC_INB_SET_DEVICE_STATE, IOMB_SIZE64, queueNum);
    if (AGSA_RC_SUCCESS != ret)
    {
      ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
      /* remove the request from IOMap */
      saRoot->IOMap[pRequest->HTag].Tag = MARK_OFF;
      saRoot->IOMap[pRequest->HTag].IORequest = agNULL;
      saRoot->IOMap[pRequest->HTag].agContext = agNULL;
      pRequest->valid = agFALSE;

      /* return the request to free pool */
      saLlistIOAdd(&(saRoot->freeIORequests), &(pRequest->linkNode));

      ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);

      SA_DBG1(("mpiSetNexusStateCmd, sending IOMB failed\n" ));
    }
   SA_DBG3(("mpiSetDeviceStateCmd, return value = %d\n", ret));
  }

  /* return value */
  smTraceFuncExit(hpDBG_VERY_LOUD, 'b', "xn");

  return ret;
}

/******************************************************************************/
/*! \brief Get Device State command
 *
 *  This command is get device State to SPC.
 *
 *  \param agRoot       Handles for this instance of SAS/SATA LLL
 *  \param agContext    Context for the Get Nexus State command
 *  \param deviceId     DeviceId
 *  \param queueNum     Queue Number of inbound/outbound queue
 *
 *  \return If the MPI command is sent to SPC successfully
 *          - \e AGSA_RC_SUCCESS the MPI command is successfully
 *          - \e AGSA_RC_BUSY the SPC is no resource, cannot send now
 *          - \e AGSA_RC_FAILURE the MPI command is failure
 *
 */
/*******************************************************************************/
GLOBAL bit32 mpiGetDeviceStateCmd(
  agsaRoot_t          *agRoot,
  agsaContext_t       *agContext,
  bit32               deviceId,
  bit32               queueNum
  )
{
  bit32                  ret = AGSA_RC_SUCCESS;
  agsaLLRoot_t           *saRoot = (agsaLLRoot_t *) (agRoot->sdkData);
  agsaIORequestDesc_t    *pRequest;
  agsaGetDeviceStateCmd_t payload;
  bit32               using_reserved = agFALSE;

  smTraceFuncEnter(hpDBG_VERY_LOUD,"xf");

  /* Get request from free IORequests */
  ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
  pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeIORequests));

  /* If no LL Control request entry available */
  if ( agNULL == pRequest )
  {
    pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeReservedRequests)); /**/
    /* If no LL Control request entry available */
    if(agNULL != pRequest)
    {
      using_reserved = agTRUE;
      SA_DBG1(("mpiGetDeviceStateCmd, using saRoot->freeReservedRequests\n"));
    }
    else
    {
      SA_DBG1(("mpiGetDeviceStateCmd, No request from free list Not using saRoot->freeReservedRequests\n"));
      smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "xf");
      ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
      return AGSA_RC_BUSY;
    }

  }
  /* If LL Control request entry avaliable */
  SA_DBG3(("mpiGetDeviceStateCmd, Build IOMB DeviceId= 0x%x\n", deviceId));
  /* Remove the request from free list */
  if( using_reserved )
  {
    saLlistIORemove(&(saRoot->freeReservedRequests), &(pRequest->linkNode));
  }
  else
  {
    saLlistIORemove(&(saRoot->freeIORequests), &(pRequest->linkNode));
  }
  saRoot->IOMap[pRequest->HTag].Tag = pRequest->HTag;
  saRoot->IOMap[pRequest->HTag].IORequest = (void *)pRequest;
  saRoot->IOMap[pRequest->HTag].agContext = agContext;
  pRequest->valid = agTRUE;

  ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);

  /* set payload to zeros */
  si_memset(&payload, 0, sizeof(agsaGetDeviceStateCmd_t));
  /* set tag field */
  OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaGetDeviceStateCmd_t, tag), pRequest->HTag);
  OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaGetDeviceStateCmd_t, deviceId), deviceId);

  /* build IOMB command and send to SPC */
  ret = mpiBuildCmd(agRoot, (bit32 *)&payload, MPI_CATEGORY_SAS_SATA, OPC_INB_GET_DEVICE_STATE, IOMB_SIZE64, queueNum);
  if (AGSA_RC_SUCCESS != ret)
  {
    ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
    /* remove the request from IOMap */
    SA_ASSERT((!pRequest->valid), "The pRequest is in use");
    saRoot->IOMap[pRequest->HTag].Tag = MARK_OFF;
    saRoot->IOMap[pRequest->HTag].IORequest = agNULL;
    saRoot->IOMap[pRequest->HTag].agContext = agNULL;
    pRequest->valid = agFALSE;
    /* return the request to free pool */
    if(saLlistIOGetCount(&(saRoot->freeReservedRequests)) < SA_RESERVED_REQUEST_COUNT)
    {
      SA_DBG1(("mpiGetDeviceStateCmd: saving pRequest (%p) for later use\n", pRequest));
      saLlistIOAdd(&(saRoot->freeReservedRequests), &(pRequest->linkNode));
    }
    else
    {
      /* return the request to free pool */
      saLlistIOAdd(&(saRoot->freeIORequests), &(pRequest->linkNode));
    }
    ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);

    SA_DBG1(("mpiGetDeviceStateCmd, sending IOMB failed\n" ));
  }
  SA_DBG3(("mpiGetDeviceStateCmd, return value = %d\n", ret));

  /* return value */
  smTraceFuncExit(hpDBG_VERY_LOUD, 'b', "xf");

  return ret;
}

/******************************************************************************/
/*! \brief SAS ReInitialize command
 *
 *  This command is Reinitialize SAS paremeters to SPC.
 *
 *  \param agRoot       Handles for this instance of SAS/SATA LLL
 *  \param agContext    Context for the Get Nexus State command
 *  \param agSASConfig  SAS Configuration Parameters
 *  \param queueNum     Queue Number of inbound/outbound queue
 *
 *  \return If the MPI command is sent to SPC successfully
 *          - \e AGSA_RC_SUCCESS the MPI command is successfully
 *          - \e AGSA_RC_BUSY the SPC is no resource, cannot send now
 *          - \e AGSA_RC_FAILURE the MPI command is failure
 *
 */
/*******************************************************************************/
GLOBAL bit32 mpiSasReinitializeCmd(
   agsaRoot_t        *agRoot,
   agsaContext_t     *agContext,
   agsaSASReconfig_t *agSASConfig,
   bit32             queueNum
   )
{
  bit32                    ret = AGSA_RC_SUCCESS;
  agsaLLRoot_t             *saRoot = (agsaLLRoot_t *) (agRoot->sdkData);
  agsaIORequestDesc_t      *pRequest;
  agsaSasReInitializeCmd_t payload;

  smTraceFuncEnter(hpDBG_VERY_LOUD,"xo");

  /* Get request from free IORequests */
  ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
  pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeIORequests));

  /* If no LL Control request entry available */
  if ( agNULL == pRequest )
  {
    SA_DBG1(("mpiSasReinitializeCmd, No request from free list\n" ));
    smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "xo");
    ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
    return AGSA_RC_BUSY;
  }
  /* If LL Control request entry avaliable */
  else
  {
    SA_DBG3(("mpiSasReinitializeCmd, Build IOMB SAS_RE_INITIALIZE\n"));
    /* Remove the request from free list */
    saLlistIORemove(&(saRoot->freeIORequests), &(pRequest->linkNode));
    saRoot->IOMap[pRequest->HTag].Tag = pRequest->HTag;
    saRoot->IOMap[pRequest->HTag].IORequest = (void *)pRequest;
    saRoot->IOMap[pRequest->HTag].agContext = agContext;
    pRequest->valid = agTRUE;
    ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);

    /* set payload to zeros */
    si_memset(&payload, 0, sizeof(agsaSasReInitializeCmd_t));

    /* set tag field */
    OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSasReInitializeCmd_t, tag), pRequest->HTag);
    OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSasReInitializeCmd_t, setFlags), agSASConfig->flags);
    OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSasReInitializeCmd_t, MaxPorts), agSASConfig->maxPorts);
    OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSasReInitializeCmd_t, openRejReCmdData),
                    (agSASConfig->openRejectRetriesCmd << SHIFT16) | agSASConfig->openRejectRetriesData);
    OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSasReInitializeCmd_t, sataHOLTMO), agSASConfig->sataHolTmo);


    /* build IOMB command and send to SPC */
    ret = mpiBuildCmd(agRoot, (bit32 *)&payload, MPI_CATEGORY_SAS_SATA, OPC_INB_SAS_RE_INITIALIZE, IOMB_SIZE64, queueNum);
    if (AGSA_RC_SUCCESS != ret)
    {
      ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
      /* remove the request from IOMap */
      SA_ASSERT((!pRequest->valid), "The pRequest is in use");
      saRoot->IOMap[pRequest->HTag].Tag = MARK_OFF;
      saRoot->IOMap[pRequest->HTag].IORequest = agNULL;
      saRoot->IOMap[pRequest->HTag].agContext = agNULL;
      pRequest->valid = agFALSE;

      /* return the request to free pool */
      saLlistIOAdd(&(saRoot->freeIORequests), &(pRequest->linkNode));

      ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);

      SA_DBG1(("mpiSasReinitializeCmd, sending IOMB failed\n" ));
    }
    SA_DBG3(("mpiSasReinitializeCmd, return value = %d\n", ret));
  }

  /* return value */
  smTraceFuncExit(hpDBG_VERY_LOUD, 'b', "xo");

  return ret;
}

/******************************************************************************/
/*! \brief SAS Set Controller Configuration Command
 *
 *  This command updates the contents of a controller mode page.
 *
 *  \param agRoot               Handles for this instance of SAS/SATA LLL
 *  \param agContext            Context for the Get Nexus State command
 *  \param agControllerConfig   Mode page being sent to the controller
 *  \param queueNum             Queue Number of inbound/outbound queue
 *
 *  \return If the MPI command is sent to SPC successfully
 *          - \e AGSA_RC_SUCCESS the MPI command is successfully
 *          - \e AGSA_RC_BUSY the SPC is no resource, cannot send now
 *          - \e AGSA_RC_FAILURE the MPI command is failure
 *
 */
/*******************************************************************************/
GLOBAL bit32
mpiSetControllerConfigCmd(
   agsaRoot_t                   *agRoot,
   agsaContext_t                *agContext,
   agsaSetControllerConfigCmd_t *agControllerConfig,
   bit32                         queueNum,
   bit8                          modePageContext
   )
{
    bit32                    ret = AGSA_RC_SUCCESS;
    agsaLLRoot_t             *saRoot = (agsaLLRoot_t *) (agRoot->sdkData);
    agsaIORequestDesc_t      *pRequest;

    smTraceFuncEnter(hpDBG_VERY_LOUD,"x1");

    SA_DBG2(("mpiSetControllerConfigCmd: agControllerConfig 0x%08x 0x%08x 0x%08x 0x%08x\n",
                                     agControllerConfig->pageCode,agControllerConfig->configPage[0],
                                     agControllerConfig->configPage[1], agControllerConfig->configPage[2]));
    SA_DBG2(("mpiSetControllerConfigCmd: agControllerConfig 0x%08x 0x%08x 0x%08x 0x%08x\n",
                                     agControllerConfig->configPage[3],agControllerConfig->configPage[4],
                                     agControllerConfig->configPage[5], agControllerConfig->configPage[6]));
    SA_DBG2(("mpiSetControllerConfigCmd: agControllerConfig 0x%08x 0x%08x 0x%08x 0x%08x\n",
                                     agControllerConfig->configPage[7],agControllerConfig->configPage[8],
                                     agControllerConfig->configPage[9], agControllerConfig->configPage[10]));
    SA_DBG2(("mpiSetControllerConfigCmd: agControllerConfig 0x%08x 0x%08x\n",
                                     agControllerConfig->configPage[11],agControllerConfig->configPage[12]));

    ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
    /* Get request from free IORequests */
    pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeIORequests));

    /* If no LL Control request entry available */
    if ( agNULL == pRequest )
    {
      SA_DBG1(("mpiSetControllerConfigCmd, No request from free list\n" ));
      smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "x1");
      ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
      return AGSA_RC_BUSY;
    }
    /* If LL Control request entry avaliable */
    else
    {
      SA_DBG2(("mpiSetControllerConfigCmd, Build IOMB pageCode 0x%x configPage[0] 0x%x\n",agControllerConfig->pageCode,agControllerConfig->configPage[0]));
      /* Remove the request from free list */
      SA_ASSERT((!pRequest->valid), "The pRequest is in use");
      saLlistIORemove(&(saRoot->freeIORequests), &(pRequest->linkNode));
      saRoot->IOMap[pRequest->HTag].Tag = pRequest->HTag;
      saRoot->IOMap[pRequest->HTag].IORequest = (void *)pRequest;
      saRoot->IOMap[pRequest->HTag].agContext = agContext;
      pRequest->valid = agTRUE;
      pRequest->modePageContext = modePageContext;
      ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);

      /* set tag field */
      agControllerConfig->tag =  pRequest->HTag;
      ret = mpiBuildCmd(agRoot, (bit32 *)agControllerConfig,
                        MPI_CATEGORY_SAS_SATA, OPC_INB_SET_CONTROLLER_CONFIG, IOMB_SIZE64, 0);

      if (AGSA_RC_SUCCESS != ret)
      {
          ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
          /* remove the request from IOMap */
          saRoot->IOMap[pRequest->HTag].Tag = MARK_OFF;
          saRoot->IOMap[pRequest->HTag].IORequest = agNULL;
          saRoot->IOMap[pRequest->HTag].agContext = agNULL;
          pRequest->valid = agFALSE;

          /* return the request to free pool */
          saLlistIOAdd(&(saRoot->freeIORequests), &(pRequest->linkNode));

          ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);

          SA_DBG1(("mpiSetControllerConfigCmd, sending IOMB failed\n" ));
      }
      SA_DBG3(("mpiSetControllerConfigCmd, return value = %d\n", ret));
    }

    /* return value */
    smTraceFuncExit(hpDBG_VERY_LOUD, 'b', "x1");

    return ret;
}

/******************************************************************************/
/*! \brief SAS Get Controller Configuration Command
 *
 *  This command retrieves the contents of a controller mode page.
 *
 *  \param agRoot               Handles for this instance of SAS/SATA LLL
 *  \param agContext            Context for the Get Nexus State command
 *  \param agControllerConfig   Mode page to retrieve from the controller
 *  \param queueNum             Queue Number of inbound/outbound queue
 *
 *  \return If the MPI command is sent to SPC successfully
 *          - \e AGSA_RC_SUCCESS the MPI command is successfully
 *          - \e AGSA_RC_BUSY the SPC is no resource, cannot send now
 *          - \e AGSA_RC_FAILURE the MPI command is failure
 *
 */
/*******************************************************************************/
GLOBAL bit32 mpiGetControllerConfigCmd(
   agsaRoot_t        *agRoot,
   agsaContext_t     *agContext,
   agsaGetControllerConfigCmd_t *agControllerConfig,
   bit32             queueNum
   )
{
    bit32                    ret = AGSA_RC_SUCCESS;
    agsaLLRoot_t             *saRoot = (agsaLLRoot_t *) (agRoot->sdkData);
    agsaIORequestDesc_t      *pRequest;

    smTraceFuncEnter(hpDBG_VERY_LOUD,"xq");

    SA_DBG1(("mpiGetControllerConfigCmd: Tag 0x%0X Page Code %0X\n",agControllerConfig->tag,agControllerConfig->pageCode ));
    /* Get request from free IORequests */
    ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
    pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeIORequests));

    /* If no LL Control request entry available */
    if ( agNULL == pRequest )
    {
      SA_DBG1(("mpiGetControllerConfigCmd, No request from free list\n" ));
      smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "xq");
      ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
      return AGSA_RC_BUSY;
    }
    /* If LL Control request entry avaliable */
    else
    {
      SA_DBG3(("mpiGetControllerConfig, Build IOMB mpiGetControllerConfigCmd\n"));
      /* Remove the request from free list */
      SA_ASSERT((!pRequest->valid), "The pRequest is in use");
      saLlistIORemove(&(saRoot->freeIORequests), &(pRequest->linkNode));
      saRoot->IOMap[pRequest->HTag].Tag = pRequest->HTag;
      saRoot->IOMap[pRequest->HTag].IORequest = (void *)pRequest;
      saRoot->IOMap[pRequest->HTag].agContext = agContext;
      pRequest->valid = agTRUE;
      ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);

      /* set tag field */
      agControllerConfig->tag =  pRequest->HTag;

      ret = mpiBuildCmd(agRoot, (bit32 *) agControllerConfig,
                        MPI_CATEGORY_SAS_SATA, OPC_INB_GET_CONTROLLER_CONFIG, IOMB_SIZE64, 0);

      if (AGSA_RC_SUCCESS != ret)
      {
          ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
          /* remove the request from IOMap */
          saRoot->IOMap[pRequest->HTag].Tag = MARK_OFF;
          saRoot->IOMap[pRequest->HTag].IORequest = agNULL;
          saRoot->IOMap[pRequest->HTag].agContext = agNULL;
          pRequest->valid = agFALSE;

          /* return the request to free pool */
          saLlistIOAdd(&(saRoot->freeIORequests), &(pRequest->linkNode));

          ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);

          SA_DBG1(("mpiGetControllerConfigCmd, sending IOMB failed\n" ));
      }
      else
      {
        SA_DBG3(("mpiGetControllerConfigCmd, set OK\n"));
      }
      SA_DBG3(("mpiGetControllerConfigCmd, return value = %d\n", ret));
    }

    /* return value */
    smTraceFuncExit(hpDBG_VERY_LOUD, 'b', "xq");

    return ret;
}

/******************************************************************************/
/*! \brief SAS Encryption KEK command
 *
 *  This command updates one or more KEK in a controller that supports encryption.
 *
 *  \param agRoot      Handles for this instance of SAS/SATA LLL
 *  \param agContext   Context for the Get Nexus State command
 *  \param agKekMgmt   Kek information that will be sent to the controller
 *  \param queueNum    Queue Number of inbound/outbound queue
 *
 *  \return If the MPI command is sent to SPC successfully
 *          - \e AGSA_RC_SUCCESS the MPI command is successfully
 *          - \e AGSA_RC_BUSY the SPC is no resource, cannot send now
 *          - \e AGSA_RC_FAILURE the MPI command is failure
 *
 */
/*******************************************************************************/
GLOBAL bit32 mpiKekManagementCmd(
   agsaRoot_t        *agRoot,
   agsaContext_t     *agContext,
   agsaKekManagementCmd_t *agKekMgmt,
   bit32             queueNum
   )
{
    bit32                    ret = AGSA_RC_SUCCESS;
    agsaLLRoot_t             *saRoot = (agsaLLRoot_t *) (agRoot->sdkData);
    agsaIORequestDesc_t      *pRequest;

    smTraceFuncEnter(hpDBG_VERY_LOUD,"x2");

    /* Get request from free IORequests */
    ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
    pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeIORequests));

    /* If no LL Control request entry available */
    if ( agNULL == pRequest )
    {
      SA_DBG1(("mpiKekManagementCmd, No request from free list\n" ));
      smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "x2");
      ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
      return AGSA_RC_BUSY;
    }
    /* If LL Control request entry avaliable */
    else
    {
      SA_DBG3(("mpiKekManagementCmd, Build OPC_INB_KEK_MANAGEMENT\n"));
      /* Remove the request from free list */
      SA_ASSERT((!pRequest->valid), "The pRequest is in use");
      saLlistIORemove(&(saRoot->freeIORequests), &(pRequest->linkNode));
      saRoot->IOMap[pRequest->HTag].Tag = pRequest->HTag;
      saRoot->IOMap[pRequest->HTag].IORequest = (void *)pRequest;
      saRoot->IOMap[pRequest->HTag].agContext = agContext;
      pRequest->valid = agTRUE;
      agKekMgmt->tag = pRequest->HTag;
      ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);

      SA_DBG1(("mpiKekManagementCmd, 0x%X 0x%X 0x%X\n", agKekMgmt->tag,agKekMgmt->NEWKIDX_CURKIDX_KBF_Reserved_SKNV_KSOP, agKekMgmt->reserved ));

      ret = mpiBuildCmd(agRoot, (bit32 *)agKekMgmt, MPI_CATEGORY_SAS_SATA, OPC_INB_KEK_MANAGEMENT, IOMB_SIZE64, 0);

      if (AGSA_RC_SUCCESS != ret)
      {
          ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
          /* remove the request from IOMap */
          saRoot->IOMap[pRequest->HTag].Tag = MARK_OFF;
          saRoot->IOMap[pRequest->HTag].IORequest = agNULL;
          saRoot->IOMap[pRequest->HTag].agContext = agNULL;
          pRequest->valid = agFALSE;
          /* return the request to free pool */
          saLlistIOAdd(&(saRoot->freeIORequests), &(pRequest->linkNode));

          ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
          SA_DBG1(("mpiKekManagementCmd, sending IOMB failed\n" ));
      }
      SA_DBG3(("mpiKekManagementCmd, return value = %d\n", ret));
    }

    /* return value */
    smTraceFuncExit(hpDBG_VERY_LOUD, 'b', "x2");

    return ret;
}

/******************************************************************************/
/*! \brief SAS Encryption DEK management command
 *
 *  This command updates one or more DEK in a controller that supports encryption.
 *
 *  \param agRoot      Handles for this instance of SAS/SATA LLL
 *  \param agContext   Context for the Get Nexus State command
 *  \param agDekMgmt   DEK information that will be sent to the controller
 *  \param queueNum    Queue Number of inbound/outbound queue
 *
 *  \return If the MPI command is sent to SPC successfully
 *          - \e AGSA_RC_SUCCESS the MPI command is successfully
 *          - \e AGSA_RC_BUSY the SPC is no resource, cannot send now
 *          - \e AGSA_RC_FAILURE the MPI command is failure
 *
 */
/*******************************************************************************/
GLOBAL bit32 mpiDekManagementCmd(
   agsaRoot_t                *agRoot,
   agsaContext_t             *agContext,
   agsaDekManagementCmd_t    *agDekMgmt,
   bit32                     queueNum
   )
{
     bit32                    ret = AGSA_RC_SUCCESS;
    agsaLLRoot_t             *saRoot = (agsaLLRoot_t *) (agRoot->sdkData);
    agsaIORequestDesc_t      *pRequest;

    smTraceFuncEnter(hpDBG_VERY_LOUD,"xs");

    /* Get request from free IORequests */
    ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
    pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeIORequests));

    /* If no LL Control request entry available */
    if ( agNULL == pRequest )
    {
      SA_DBG1(("mpiDekManagementCmd, No request from free list\n" ));
      smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "xs");
      ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
      return AGSA_RC_BUSY;
    }
    /* If LL Control request entry avaliable */
    else
    {
      SA_DBG1(("mpiDekManagementCmd, Build OPC_INB_DEK_MANAGEMENT pRequest %p\n",pRequest));
      /* Remove the request from free list */
      SA_ASSERT((!pRequest->valid), "The pRequest is in use");
      saLlistIORemove(&(saRoot->freeIORequests), &(pRequest->linkNode));
      saRoot->IOMap[pRequest->HTag].Tag = pRequest->HTag;
      saRoot->IOMap[pRequest->HTag].IORequest = (void *)pRequest;
      saRoot->IOMap[pRequest->HTag].agContext = agContext;
      pRequest->valid = agTRUE;
      agDekMgmt->tag = pRequest->HTag;
      ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);

      SA_DBG1(("mpiDekManagementCmd: 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X\n",
                                    agDekMgmt->tag,
                                    agDekMgmt->KEKIDX_Reserved_TBLS_DSOP,
                                    agDekMgmt->dekIndex,
                                    agDekMgmt->tableAddrLo,
                                    agDekMgmt->tableAddrHi,
                                    agDekMgmt->tableEntries,
                                    agDekMgmt->Reserved_DBF_TBL_SIZE ));
      ret = mpiBuildCmd(agRoot, (bit32 *) agDekMgmt, MPI_CATEGORY_SAS_SATA, OPC_INB_DEK_MANAGEMENT, IOMB_SIZE64, 0);

      if (AGSA_RC_SUCCESS != ret)
      {
        ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
        /* remove the request from IOMap */
        saRoot->IOMap[pRequest->HTag].Tag = MARK_OFF;
        saRoot->IOMap[pRequest->HTag].IORequest = agNULL;
        saRoot->IOMap[pRequest->HTag].agContext = agNULL;
        pRequest->valid = agFALSE;

        /* return the request to free pool */
        saLlistIOAdd(&(saRoot->freeIORequests), &(pRequest->linkNode));

        ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);

        SA_DBG1(("mpiDekManagementCmd, sending IOMB failed\n" ));
      }
      SA_DBG3(("mpiDekManagementCmd, return value = %d\n", ret));
    }

    /* return value */
    smTraceFuncExit(hpDBG_VERY_LOUD, 'b', "xs");

    return ret;
}

/******************************************************************************/
/*! \brief
 *
 *  This command sends operator management command.
 *
 *  \param agRoot      Handles for this instance of SAS/SATA LLL
 *  \param agContext   Context
 *  \param queueNum    Queue Number of inbound/outbound queue
 *
 *  \return If the MPI command is sent to SPC successfully
 *          - \e AGSA_RC_SUCCESS the MPI command is successfully
 *          - \e AGSA_RC_BUSY the SPC is no resource, cannot send now
 *          - \e AGSA_RC_FAILURE the MPI command is failure
 *
 */
/*******************************************************************************/
GLOBAL bit32 mpiOperatorManagementCmd(
  agsaRoot_t                *agRoot,
  bit32                     queueNum,
  agsaContext_t             *agContext,
  agsaOperatorMangmentCmd_t *operatorcode )
{
   bit32                    ret = AGSA_RC_SUCCESS;
  agsaLLRoot_t             *saRoot = (agsaLLRoot_t *) (agRoot->sdkData);
  agsaIORequestDesc_t      *pRequest;

  smTraceFuncEnter(hpDBG_VERY_LOUD,"2q");

  SA_DBG1(("mpiOperatorManagementCmd, enter\n" ));

  /* Get request from free IORequests */
  ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
  pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeIORequests));

  /* If no LL Control request entry available */
  if ( agNULL == pRequest )
  {
    SA_DBG1(("mpiOperatorManagementCmd, No request from free list\n" ));
    smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "2q");
    ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
    return AGSA_RC_BUSY;
  }
  /* If LL Control request entry avaliable */
  else
  {
    SA_DBG1(("mpiOperatorManagementCmd, Build OPC_INB_OPR_MGMT\n"));
    /* Remove the request from free list */
    SA_ASSERT((!pRequest->valid), "The pRequest is in use");
    saLlistIORemove(&(saRoot->freeIORequests), &(pRequest->linkNode));
    saRoot->IOMap[pRequest->HTag].Tag = pRequest->HTag;
    saRoot->IOMap[pRequest->HTag].IORequest = (void *)pRequest;
    saRoot->IOMap[pRequest->HTag].agContext = agContext;
    pRequest->valid = agTRUE;
    operatorcode->tag = pRequest->HTag;
    ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);

    ret = mpiBuildCmd(agRoot, (bit32 *)operatorcode , MPI_CATEGORY_SAS_SATA, OPC_INB_OPR_MGMT, IOMB_SIZE128, 0);

    if (AGSA_RC_SUCCESS != ret)
    {
      ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
      /* remove the request from IOMap */
      saRoot->IOMap[pRequest->HTag].Tag = MARK_OFF;
      saRoot->IOMap[pRequest->HTag].IORequest = agNULL;
      saRoot->IOMap[pRequest->HTag].agContext = agNULL;
      pRequest->valid = agFALSE;

      /* return the request to free pool */
      saLlistIOAdd(&(saRoot->freeIORequests), &(pRequest->linkNode));

      ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);

      SA_DBG1(("mpiOperatorManagementCmd, sending IOMB failed\n" ));
    }
    SA_DBG1(("mpiOperatorManagementCmd, return value = %d\n", ret));
  }

  /* return value */
  smTraceFuncExit(hpDBG_VERY_LOUD, 'b', "2q");

  return ret;
}

/******************************************************************************/
/*! \brief
 *
 *  This command sends encrypt self test command.
 *
 *  \param agRoot      Handles for this instance of SAS/SATA LLL
 *  \param agContext   Context
 *  \param queueNum    Queue Number of inbound/outbound queue
 *
 *  \return If the MPI command is sent to SPC successfully
 *          - \e AGSA_RC_SUCCESS the MPI command is successfully
 *          - \e AGSA_RC_BUSY the SPC is no resource, cannot send now
 *          - \e AGSA_RC_FAILURE the MPI command is failure
 *
 */
/*******************************************************************************/
GLOBAL bit32 mpiEncryptBistCmd(
  agsaRoot_t        *agRoot,
  bit32              queueNum,
  agsaContext_t     *agContext,
  agsaEncryptBist_t *bist )
{
   bit32                    ret = AGSA_RC_SUCCESS;
  agsaLLRoot_t             *saRoot = (agsaLLRoot_t *) (agRoot->sdkData);
  agsaIORequestDesc_t      *pRequest;

  smTraceFuncEnter(hpDBG_VERY_LOUD,"2z");

  SA_DBG1(("mpiEncryptBistCmd, enter\n" ));

  /* Get request from free IORequests */
  ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
  pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeIORequests));

  /* If no LL Control request entry available */
  if ( agNULL == pRequest )
  {
    SA_DBG1(("mpiEncryptBistCmd, No request from free list\n" ));
    smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "2z");
    ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
    return AGSA_RC_BUSY;
  }
  /* If LL Control request entry avaliable */
  else
  {
    SA_DBG1(("mpiEncryptBistCmd, Build OPC_INB_ENC_TEST_EXECUTE\n"));
    /* Remove the request from free list */
    SA_ASSERT((!pRequest->valid), "The pRequest is in use");
    saLlistIORemove(&(saRoot->freeIORequests), &(pRequest->linkNode));
    saRoot->IOMap[pRequest->HTag].Tag = pRequest->HTag;
    saRoot->IOMap[pRequest->HTag].IORequest = (void *)pRequest;
    saRoot->IOMap[pRequest->HTag].agContext = agContext;
    pRequest->valid = agTRUE;
    bist->tag = pRequest->HTag;
    ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);

    SA_DBG1(("mpiEncryptBistCmd: 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X\n",
                                  bist->tag,
                                  bist->r_subop,
                                  bist->testDiscption[0],
                                  bist->testDiscption[1],
                                  bist->testDiscption[2],
                                  bist->testDiscption[3],
                                  bist->testDiscption[4] ));
    ret = mpiBuildCmd(agRoot, (bit32 *)bist , MPI_CATEGORY_SAS_SATA, OPC_INB_ENC_TEST_EXECUTE, IOMB_SIZE64, 0);

    if (AGSA_RC_SUCCESS != ret)
    {
      ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
      /* remove the request from IOMap */
      saRoot->IOMap[pRequest->HTag].Tag = MARK_OFF;
      saRoot->IOMap[pRequest->HTag].IORequest = agNULL;
      saRoot->IOMap[pRequest->HTag].agContext = agNULL;
      pRequest->valid = agFALSE;

      /* return the request to free pool */
      saLlistIOAdd(&(saRoot->freeIORequests), &(pRequest->linkNode));

      ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);

      SA_DBG1(("mpiEncryptBistCmd, sending IOMB failed\n" ));
    }
    SA_DBG1(("mpiEncryptBistCmd, return value = %d\n", ret));
  }

  /* return value */
  smTraceFuncExit(hpDBG_VERY_LOUD, 'b', "2z");

  return ret;
}

/******************************************************************************/
/*! \brief
 *
 *  This command sends set operator command.
 *
 *  \param agRoot      Handles for this instance of SAS/SATA LLL
 *  \param agContext   Context
 *  \param queueNum    Queue Number of inbound/outbound queue
 *
 *  \return If the MPI command is sent to SPC successfully
 *          - \e AGSA_RC_SUCCESS the MPI command is successfully
 *          - \e AGSA_RC_BUSY the SPC is no resource, cannot send now
 *          - \e AGSA_RC_FAILURE the MPI command is failure
 *
 */
/*******************************************************************************/
GLOBAL bit32
mpiSetOperatorCmd(
  agsaRoot_t                *agRoot,
  bit32                      queueNum,
  agsaContext_t             *agContext,
  agsaSetOperatorCmd_t      *operatorcode
  )
{
   bit32                    ret = AGSA_RC_SUCCESS;
  agsaLLRoot_t             *saRoot = (agsaLLRoot_t *) (agRoot->sdkData);
  agsaIORequestDesc_t      *pRequest;

  smTraceFuncEnter(hpDBG_VERY_LOUD,"39");

  SA_DBG1(("mpiSetOperatorCmd, enter\n" ));

  /* Get request from free IORequests */
  ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
  pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeIORequests));

  /* If no LL Control request entry available */
  if ( agNULL == pRequest )
  {
    SA_DBG1(("mpiSetOperatorCmd, No request from free list\n" ));
    smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "39");
    ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
    return AGSA_RC_BUSY;
  }
  /* If LL Control request entry avaliable */
  else
  {
    SA_DBG1(("mpiSetOperatorCmd, Build OPC_INB_SET_OPERATOR\n"));
    /* Remove the request from free list */
    SA_ASSERT((!pRequest->valid), "The pRequest is in use");
    saLlistIORemove(&(saRoot->freeIORequests), &(pRequest->linkNode));
    saRoot->IOMap[pRequest->HTag].Tag = pRequest->HTag;
    saRoot->IOMap[pRequest->HTag].IORequest = (void *)pRequest;
    saRoot->IOMap[pRequest->HTag].agContext = agContext;
    pRequest->valid = agTRUE;
    operatorcode->tag = pRequest->HTag;
    ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);

    ret = mpiBuildCmd(agRoot, (bit32 *)operatorcode, MPI_CATEGORY_SAS_SATA, OPC_INB_SET_OPERATOR, IOMB_SIZE64, 0);

    if (AGSA_RC_SUCCESS != ret)
    {
      ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
      /* remove the request from IOMap */
      saRoot->IOMap[pRequest->HTag].Tag = MARK_OFF;
      saRoot->IOMap[pRequest->HTag].IORequest = agNULL;
      saRoot->IOMap[pRequest->HTag].agContext = agNULL;
      pRequest->valid = agFALSE;

      /* return the request to free pool */
      saLlistIOAdd(&(saRoot->freeIORequests), &(pRequest->linkNode));

      ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);

      SA_DBG1(("mpiSetOperatorCmd, sending IOMB failed\n" ));
    }
    SA_DBG1(("mpiSetOperatorCmd, return value = %d\n", ret));
  }

  /* return value */
  smTraceFuncExit(hpDBG_VERY_LOUD, 'b', "39");

  return ret;
}

/******************************************************************************/
/*! \brief
 *
 *  This command sends get operator command.
 *
 *  \param agRoot      Handles for this instance of SAS/SATA LLL
 *  \param agContext   Context
 *  \param queueNum    Queue Number of inbound/outbound queue
 *
 *  \return If the MPI command is sent to SPC successfully
 *          - \e AGSA_RC_SUCCESS the MPI command is successfully
 *          - \e AGSA_RC_BUSY the SPC is no resource, cannot send now
 *          - \e AGSA_RC_FAILURE the MPI command is failure
 *
 */
/*******************************************************************************/
GLOBAL bit32
mpiGetOperatorCmd(
  agsaRoot_t                *agRoot,
  bit32                      queueNum,
  agsaContext_t             *agContext,
  agsaGetOperatorCmd_t      *operatorcode
  )
{
   bit32                    ret = AGSA_RC_SUCCESS;
  agsaLLRoot_t             *saRoot = (agsaLLRoot_t *) (agRoot->sdkData);
  agsaIORequestDesc_t      *pRequest;

  smTraceFuncEnter(hpDBG_VERY_LOUD,"3e");

  SA_DBG1(("mpiGetOperatorCmd, enter\n" ));

  /* Get request from free IORequests */
  ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
  pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeIORequests));

  /* If no LL Control request entry available */
  if ( agNULL == pRequest )
  {
    SA_DBG1(("mpiGetOperatorCmd, No request from free list\n" ));
    smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "3e");
    ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
    return AGSA_RC_BUSY;
  }
  /* If LL Control request entry avaliable */
  else
  {
    SA_DBG1(("mpiGetOperatorCmd, Build OPC_INB_GET_OPERATOR\n"));
    /* Remove the request from free list */
    SA_ASSERT((!pRequest->valid), "The pRequest is in use");
    saLlistIORemove(&(saRoot->freeIORequests), &(pRequest->linkNode));
    saRoot->IOMap[pRequest->HTag].Tag = pRequest->HTag;
    saRoot->IOMap[pRequest->HTag].IORequest = (void *)pRequest;
    saRoot->IOMap[pRequest->HTag].agContext = agContext;
    pRequest->valid = agTRUE;
    operatorcode->tag = pRequest->HTag;
    ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);

    ret = mpiBuildCmd(agRoot, (bit32 *)operatorcode, MPI_CATEGORY_SAS_SATA, OPC_INB_GET_OPERATOR, IOMB_SIZE64, 0);

    if (AGSA_RC_SUCCESS != ret)
    {
      ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
      /* remove the request from IOMap */
      saRoot->IOMap[pRequest->HTag].Tag = MARK_OFF;
      saRoot->IOMap[pRequest->HTag].IORequest = agNULL;
      saRoot->IOMap[pRequest->HTag].agContext = agNULL;
      pRequest->valid = agFALSE;

      /* return the request to free pool */
      saLlistIOAdd(&(saRoot->freeIORequests), &(pRequest->linkNode));

      ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);

      SA_DBG1(("mpiGetOperatorCmd, sending IOMB failed\n" ));
    }
    SA_DBG1(("mpiGetOperatorCmd, return value = %d\n", ret));
  }

  /* return value */
  smTraceFuncExit(hpDBG_VERY_LOUD, 'b', "3e");

  return ret;
}

GLOBAL bit32 mpiDIFEncryptionOffloadCmd(
   agsaRoot_t                      *agRoot,
   agsaContext_t                   *agContext,
   bit32                            queueNum,
   bit32                            op,
   agsaDifEncPayload_t             *agDifEncOffload,
   ossaDIFEncryptionOffloadStartCB_t agCB
   )
{
  bit32 ret = AGSA_RC_SUCCESS;
  bit32 dw8=0;
  bit32 dw9=0;
  bit32 dw10=0;
  bit32 dw14=0;
  bit32 dw15=0;
  agsaLLRoot_t             *saRoot = (agsaLLRoot_t *) (agRoot->sdkData);
  agsaIORequestDesc_t      *pRequest;
  agsaDifEncOffloadCmd_t   payload;
  smTraceFuncEnter(hpDBG_VERY_LOUD,"2b");

  /* Get request from free IORequests */
  ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
  pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeIORequests));

  /* If no LL Control request entry available */
  if ( agNULL == pRequest )
  {
    SA_DBG1(("mpiDIFEncryptionOffloadCmd: No request from free list\n" ));
    smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "2b");
    ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
    return AGSA_RC_BUSY;
  }
  /* If LL Control request entry avaliable */
  else
  {
    SA_DBG1(("mpiDIFEncryptionOffloadCmd: Build OPC_INB_DIF_ENC_OFFLOAD_CMD pRequest %p\n",pRequest));
    /* Remove the request from free list */
    SA_ASSERT((!pRequest->valid), "The pRequest is in use");
    saLlistIORemove(&(saRoot->freeIORequests), &(pRequest->linkNode));
    saRoot->IOMap[pRequest->HTag].Tag = pRequest->HTag;
    saRoot->IOMap[pRequest->HTag].IORequest = (void *)pRequest;
    saRoot->IOMap[pRequest->HTag].agContext = agContext;
    pRequest->valid = agTRUE;
    pRequest->completionCB = (ossaSSPCompletedCB_t)agCB;
    ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);

    si_memset(&payload, 0, sizeof(agsaDifEncOffloadCmd_t));
    SA_DBG1(("mpiDIFEncryptionOffloadCmd: op %d\n",op));

    if(smIS_SPCV(agRoot))
    {
      OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaDifEncOffloadCmd_t, tag),            pRequest->HTag);
      OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaDifEncOffloadCmd_t, option),         op);
      OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaDifEncOffloadCmd_t, Src_Data_Len),   agDifEncOffload->SrcDL);
      OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaDifEncOffloadCmd_t, Dst_Data_Len),   agDifEncOffload->DstDL);
      OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaDifEncOffloadCmd_t, flags),          agDifEncOffload->dif.flags);

      dw8 = agDifEncOffload->dif.udrtArray[1] << SHIFT24 | 
            agDifEncOffload->dif.udrtArray[0] << SHIFT16 | 
            agDifEncOffload->dif.udtArray[1]  << SHIFT8  | 
            agDifEncOffload->dif.udtArray[0];
      OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaDifEncOffloadCmd_t, UDTR01UDT01), dw8);

      dw9 = agDifEncOffload->dif.udtArray[5]  << SHIFT24 |
            agDifEncOffload->dif.udtArray[4] << SHIFT16  |
            agDifEncOffload->dif.udtArray[3] << SHIFT8   | 
            agDifEncOffload->dif.udtArray[2];
      OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaDifEncOffloadCmd_t, UDT2345), dw9);
      dw10 = agDifEncOffload->dif.udrtArray[5] << SHIFT24 |
             agDifEncOffload->dif.udrtArray[4] << SHIFT16 |
             agDifEncOffload->dif.udrtArray[3] << SHIFT8  |
             agDifEncOffload->dif.udrtArray[2];

      OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaDifEncOffloadCmd_t, UDTR2345), dw10);

      OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaDifEncOffloadCmd_t, DPLR0SecCnt_IOSeed), 
               agDifEncOffload->dif.DIFPerLARegion0SecCount << SHIFT16 | 
               agDifEncOffload->dif.initialIOSeed);
      
      OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaDifEncOffloadCmd_t, DPL_Addr_Lo)        , agDifEncOffload->dif.DIFPerLAAddrLo);
      OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaDifEncOffloadCmd_t, DPL_Addr_Hi)        , agDifEncOffload->dif.DIFPerLAAddrHi);

      dw14 =  agDifEncOffload->encrypt.dekInfo.dekIndex          << SHIFT8 |
             (agDifEncOffload->encrypt.dekInfo.dekTable & 0x3)   << SHIFT2 | 
             (agDifEncOffload->encrypt.keyTagCheck & 0x1)        << SHIFT1;

      if (agDifEncOffload->encrypt.cipherMode == agsaEncryptCipherModeXTS)
      {
        dw14 |= AGSA_ENCRYPT_XTS_Mode << SHIFT4;
      }
      else
      {
        dw14 |= (agDifEncOffload->encrypt.cipherMode & 0xF) << SHIFT4;
      }

      OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaDifEncOffloadCmd_t, KeyIndex_CMode_KTS_ENT_R), dw14);
      
      dw15 = agDifEncOffload->encrypt.EncryptionPerLRegion0SecCount << SHIFT16 | 
                           (agDifEncOffload->encrypt.kekIndex & 0xF) << SHIFT5 | 
                           (agDifEncOffload->encrypt.sectorSizeIndex & 0x1F);

      OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaDifEncOffloadCmd_t, EPLR0SecCnt_KS_ENSS), dw15);
      
      OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaDifEncOffloadCmd_t, keyTag_W0),   agDifEncOffload->encrypt.keyTag_W0);
      OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaDifEncOffloadCmd_t, keyTag_W1),   agDifEncOffload->encrypt.keyTag_W1);
      OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaDifEncOffloadCmd_t, tweakVal_W0), agDifEncOffload->encrypt.tweakVal_W0);
      OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaDifEncOffloadCmd_t, tweakVal_W1), agDifEncOffload->encrypt.tweakVal_W1);
      OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaDifEncOffloadCmd_t, tweakVal_W2), agDifEncOffload->encrypt.tweakVal_W2);
      OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaDifEncOffloadCmd_t, tweakVal_W3), agDifEncOffload->encrypt.tweakVal_W3);
      OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaDifEncOffloadCmd_t, EPL_Addr_Lo), agDifEncOffload->encrypt.EncryptionPerLAAddrLo);
      OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaDifEncOffloadCmd_t, EPL_Addr_Hi), agDifEncOffload->encrypt.EncryptionPerLAAddrHi);
      
      si_memcpy((bit32 *) &(payload.SrcSgl), (bit32 *) &(agDifEncOffload->SrcSgl), sizeof(agsaSgl_t));
      si_memcpy((bit32 *) &(payload.DstSgl), (bit32 *) &(agDifEncOffload->DstSgl), sizeof(agsaSgl_t));

      ret = mpiBuildCmd(agRoot, (bit32 *)&payload, MPI_CATEGORY_SAS_SATA, OPC_INB_DIF_ENC_OFFLOAD_CMD, IOMB_SIZE128, queueNum);

    }
    else
    {
      /* SPC does not support this command */
      ret = AGSA_RC_FAILURE;
    }

    if (AGSA_RC_SUCCESS != ret)
    {
      ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
      /* remove the request from IOMap */
      saRoot->IOMap[pRequest->HTag].Tag = MARK_OFF;
      saRoot->IOMap[pRequest->HTag].IORequest = agNULL;
      saRoot->IOMap[pRequest->HTag].agContext = agNULL;
      pRequest->valid = agFALSE;

      /* return the request to free pool */
      saLlistIOAdd(&(saRoot->freeIORequests), &(pRequest->linkNode));

      ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);

      SA_DBG1(("mpiDIFEncryptionOffloadCmd: sending IOMB failed\n" ));
    }
    SA_DBG3(("mpiDIFEncryptionOffloadCmd: return value = %d\n", ret));
  }

  /* return value */
  smTraceFuncExit(hpDBG_VERY_LOUD, 'b', "2b");

  return ret;
}