root/sys/dev/pms/RefTisa/tisa/sassata/sas/ini/itdio.c
/*******************************************************************************
*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
 *
 *
 * This file contains initiator IO related functions in TD layer
 *
 */
#include <sys/cdefs.h>
#include <dev/pms/config.h>

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

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

#include <dev/pms/RefTisa/tisa/api/titypes.h>
#include <dev/pms/RefTisa/tisa/api/ostiapi.h>
#include <dev/pms/RefTisa/tisa/api/tiapi.h>
#include <dev/pms/RefTisa/tisa/api/tiglobal.h>

#ifdef FDS_SM
#include <dev/pms/RefTisa/sat/api/sm.h>
#include <dev/pms/RefTisa/sat/api/smapi.h>
#include <dev/pms/RefTisa/sat/api/tdsmapi.h>
#endif

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

#include <dev/pms/RefTisa/tisa/sassata/sas/common/tdtypes.h>
#include <dev/pms/freebsd/driver/common/osstring.h>
#include <dev/pms/RefTisa/tisa/sassata/common/tdutil.h>

#ifdef INITIATOR_DRIVER
#include <dev/pms/RefTisa/tisa/sassata/sas/ini/itdtypes.h>
#include <dev/pms/RefTisa/tisa/sassata/sas/ini/itddefs.h>
#include <dev/pms/RefTisa/tisa/sassata/sas/ini/itdglobl.h>
#endif

#ifdef TARGET_DRIVER
#include <dev/pms/RefTisa/tisa/sassata/sas/tgt/ttdglobl.h>
#include <dev/pms/RefTisa/tisa/sassata/sas/tgt/ttdxchg.h>
#include <dev/pms/RefTisa/tisa/sassata/sas/tgt/ttdtypes.h>
#endif

#include <dev/pms/RefTisa/tisa/sassata/common/tdsatypes.h>
#include <dev/pms/RefTisa/tisa/sassata/common/tdproto.h>

/*****************************************************************************
*! \brief  tiINIIOStart
*
*   Purpose:  This routine is called to initiate a new SCSI request.
*
*  \param   tiRoot:           Pointer to initiator driver/port instance.
*  \param   tiIORequest:      Pointer to the I/O request context for this I/O.
*  \param   tiDeviceHandle:   Pointer to device handle for this I/O.
*  \param   tiScsiRequest:    Pointer to the SCSI-3 I/O request and SGL list.
*  \param   tiRequestBody:    Pointer to the OS Specific module allocated storage
*                             to be used by the TD layer for executing this I/O.
*  \param   interruptContext: The interrupt context within which this function
*                       is called.
*  \return:
*
*  tiSuccess:     I/O request successfully initiated.
*  tiBusy:        No resources available, try again later.
*  tiIONoDevice:  Invalid device handle.
*  tiError:       Other errors that prevent the I/O request to be started.
*
*
*****************************************************************************/
osGLOBAL bit32
tiINIIOStart(
             tiRoot_t                  *tiRoot,
             tiIORequest_t             *tiIORequest,
             tiDeviceHandle_t          *tiDeviceHandle,
             tiScsiInitiatorRequest_t  *tiScsiRequest,
             void                      *tiRequestBody,
             bit32                     interruptContext
             )
{
  tdsaRoot_t                *tdsaRoot        = (tdsaRoot_t *) tiRoot->tdData;
  tdsaContext_t             *tdsaAllShared = (tdsaContext_t *)&tdsaRoot->tdsaAllShared;
  itdsaIni_t                *Initiator = (itdsaIni_t *)tdsaAllShared->itdsaIni;
  tdsaDeviceData_t          *oneDeviceData;
  agsaRoot_t                *agRoot = agNULL;
  agsaIORequest_t           *agIORequest = agNULL;
  agsaDevHandle_t           *agDevHandle = agNULL;
  bit32                     agRequestType;
  agsaSASRequestBody_t      *agSASRequestBody = agNULL;
  bit32                     tiStatus = tiError;
  bit32                     saStatus = AGSA_RC_FAILURE;

  tdIORequestBody_t         *tdIORequestBody;
  agsaSSPInitiatorRequest_t *agSSPInitiatorRequest;
#ifdef REMOVED
  /* only for debugging */
  bit32                      i;
#endif

#ifdef  SATA_ENABLE
#ifndef FDS_SM
  satIOContext_t            *satIOContext;
#endif
#endif
#ifdef FDS_SM
  smRoot_t                  *smRoot = &(tdsaAllShared->smRoot);
  smIORequest_t             *smIORequest;
  smDeviceHandle_t          *smDeviceHandle;
  smScsiInitiatorRequest_t  *smSCSIRequest;
#endif

  TDSA_INP_ENTER(tiRoot);
  TI_DBG6(("tiINIIOStart: start\n"));
  TI_DBG6(("tiINIIOStart:: ******* tdsaRoot %p tdsaAllShared %p \n", tdsaRoot,tdsaAllShared));

  oneDeviceData = (tdsaDeviceData_t *)tiDeviceHandle->tdData;

  TI_DBG6(("tiINIIOStart: onedevicedata %p\n", oneDeviceData));

  if(oneDeviceData == agNULL)
  {
    TI_DBG1(("tiINIIOStart: tiDeviceHandle=%p DeviceData is NULL\n", tiDeviceHandle ));
    tiStatus = tiIONoDevice;
    goto ext;
  }

  /* for hotplug */
  if (oneDeviceData->valid != agTRUE || oneDeviceData->registered != agTRUE ||
      oneDeviceData->tdPortContext == agNULL )
  {
    TI_DBG1(("tiINIIOStart: tiDeviceHandle=%p did %d DeviceData was removed\n", tiDeviceHandle, oneDeviceData->id));
    TI_DBG6(("tiINIIOStart: device AddrHi 0x%08x AddrLo 0x%08x\n",
    oneDeviceData->SASAddressID.sasAddressHi, oneDeviceData->SASAddressID.sasAddressLo));
    // for debugging
    tdIORequestBody = (tdIORequestBody_t *)tiRequestBody;
    tdIORequestBody->IOCompletionFunc = itdssIOForDebugging1Completed;
    TI_DBG6(("tiINIIOStart: IOCompletionFunc %p\n", tdIORequestBody->IOCompletionFunc));
    tiStatus = tiIONoDevice;
    goto ext;
  }
#if 1
  if (tiIORequest->osData == agNULL)
  {
    TI_DBG1(("tiINIIOStart: tiIORequest->osData is NULL, wrong\n"));
  }
#endif

  /* starting IO with SAS device */
  if (oneDeviceData->DeviceType == TD_SAS_DEVICE)
  {
    TI_DBG6(("tiINIIOStart: calling saSSPStart\n"));

    agRoot = oneDeviceData->agRoot;
    agDevHandle = oneDeviceData->agDevHandle;

    /* OS layer has tdlayer data structure pointer in
       tdIORequestBody_t    tdIOReqBody;
       in ccb_t in agtiapi.h
    */
    tdIORequestBody = (tdIORequestBody_t *)tiRequestBody;

    /* initialize */
    osti_memset(tdIORequestBody, 0, sizeof(tdIORequestBody_t));

    /* let's initialize tdIOrequestBody */
    /* initialize callback */
    tdIORequestBody->IOCompletionFunc = itdssIOCompleted;

    /* initialize tiDevhandle */
    tdIORequestBody->tiDevHandle = tiDeviceHandle;

    /* initialize tiIORequest */
    tdIORequestBody->tiIORequest = tiIORequest;

    /* save context if we need to abort later */
    tiIORequest->tdData = tdIORequestBody;

    /* initialize expDataLength */
    tdIORequestBody->IOType.InitiatorRegIO.expDataLength
      = tiScsiRequest->scsiCmnd.expDataLength;

    tdIORequestBody->IOType.InitiatorRegIO.sglVirtualAddr
      = tiScsiRequest->sglVirtualAddr;

    /* initializes "agsaSgl_t   agSgl" of "agsaDifSSPInitiatorRequest_t" */
    tiStatus = itdssIOPrepareSGL(
                                 tiRoot,
                                 tdIORequestBody,
                                 &tiScsiRequest->agSgl1,
                                 tiScsiRequest->sglVirtualAddr
                                 );

    if (tiStatus != tiSuccess)
    {
      TI_DBG1(("tiINIIOStart: can't get SGL\n"));
      goto ext;
    }


    /* initialize agIORequest */
    agIORequest = &(tdIORequestBody->agIORequest);
    agIORequest->osData = (void *) tdIORequestBody;
    agIORequest->sdkData = agNULL; /* LL takes care of this */


    /*
      initialize
      tdIORequestBody_t tdIORequestBody -> agSASRequestBody
    */
    agSASRequestBody = &(tdIORequestBody->transport.SAS.agSASRequestBody);
    agSSPInitiatorRequest = &(agSASRequestBody->sspInitiatorReq);

    agSSPInitiatorRequest->flag = 0;

    /* copy cdb bytes */
    osti_memcpy(agSSPInitiatorRequest->sspCmdIU.cdb, tiScsiRequest->scsiCmnd.cdb, 16);

    /* copy lun field */
    osti_memcpy(agSSPInitiatorRequest->sspCmdIU.lun,
                tiScsiRequest->scsiCmnd.lun.lun, 8);


    /* setting the data length */
    agSSPInitiatorRequest->dataLength  = tiScsiRequest->scsiCmnd.expDataLength;
    TI_DBG6(("tiINIIOStart: tiScsiRequest->scsiCmnd.expDataLength %d\n", tiScsiRequest->scsiCmnd.expDataLength));

    agSSPInitiatorRequest->firstBurstSize = 0;

    /*
      process taskattribute
    */
    if (tiScsiRequest->scsiCmnd.taskAttribute == TASK_SIMPLE)
    {
      agSSPInitiatorRequest->sspCmdIU.efb_tp_taskAttribute = (bit8)
       agSSPInitiatorRequest->sspCmdIU.efb_tp_taskAttribute | TD_TASK_SIMPLE;
    }
    else if (tiScsiRequest->scsiCmnd.taskAttribute == TASK_ORDERED)
    {
      agSSPInitiatorRequest->sspCmdIU.efb_tp_taskAttribute = (bit8)
       agSSPInitiatorRequest->sspCmdIU.efb_tp_taskAttribute | TD_TASK_ORDERED;
    }
    else if (tiScsiRequest->scsiCmnd.taskAttribute == TASK_HEAD_OF_QUEUE)
    {
      agSSPInitiatorRequest->sspCmdIU.efb_tp_taskAttribute = (bit8)
       agSSPInitiatorRequest->sspCmdIU.efb_tp_taskAttribute | TD_TASK_HEAD_OF_QUEUE;
    }
    else if (tiScsiRequest->scsiCmnd.taskAttribute == TASK_ACA)
    {
      agSSPInitiatorRequest->sspCmdIU.efb_tp_taskAttribute = (bit8)
       agSSPInitiatorRequest->sspCmdIU.efb_tp_taskAttribute | TD_TASK_ACA;
    }

    if (tiScsiRequest->dataDirection == tiDirectionIn)
    {
      agRequestType = AGSA_SSP_INIT_READ;
      TI_DBG6(("tiINIIOStart: READ\n"));
    }
    else if (tiScsiRequest->dataDirection == tiDirectionOut)
    {
      agRequestType = AGSA_SSP_INIT_WRITE;
      TI_DBG6(("tiINIIOStart: WRITE\n"));
    }
    else
    {
      agRequestType = AGSA_REQ_TYPE_UNKNOWN;
      TI_DBG1(("tiINIIOStart: unknown data direction\n"));
    }

    tdIORequestBody->agRequestType = agRequestType;

    TI_DBG6(("tiINIIOStart: device AddrHi 0x%08x\n", oneDeviceData->SASAddressID.sasAddressHi));
    TI_DBG6(("tiINIIOStart: device AddrLo 0x%08x\n", oneDeviceData->SASAddressID.sasAddressLo));

    /* for debugging */
    if (tdIORequestBody->IOCompletionFunc == agNULL)
    {
      TI_DBG1(("tiINIIOStart: Error!!!! IOCompletionFunc is NULL\n"));
    }
    saStatus = saSSPStart(agRoot,
                          agIORequest,
                          tdsaRotateQnumber(tiRoot, oneDeviceData),
                          agDevHandle,
                          agRequestType,
                          agSASRequestBody,
                          agNULL,
                          &ossaSSPCompleted);

    tdIORequestBody->ioStarted = agTRUE;
    tdIORequestBody->ioCompleted = agFALSE;
    tdIORequestBody->reTries = 0;

    if (saStatus == AGSA_RC_SUCCESS)
    {
      Initiator->NumIOsActive++;
      tiStatus = tiSuccess;
    }
    else
    {
      tdIORequestBody->ioStarted = agFALSE;
      tdIORequestBody->ioCompleted = agTRUE;
      if (saStatus == AGSA_RC_BUSY)
      {
        TI_DBG4(("tiINIIOStart: saSSPStart busy\n"));
        tiStatus = tiBusy;
      }
      else
      {
        tiStatus = tiError;
      }
      goto ext;
    }
  }
#ifdef FDS_SM
  else if (oneDeviceData->DeviceType == TD_SATA_DEVICE)
  {
    TI_DBG5(("tiINIIOStart: calling satIOStart\n"));
    TI_DBG5(("tiINIIOStart: onedevicedata did %d\n", oneDeviceData->id));
    tdIORequestBody = (tdIORequestBody_t *)tiRequestBody;
    /* initialize */
    osti_memset(tdIORequestBody, 0, sizeof(tdIORequestBody_t));
    /* initialize tiDevhandle */
    tdIORequestBody->tiDevHandle = tiDeviceHandle;
    tdIORequestBody->superIOFlag = agFALSE;

    tiIORequest->tdData = tdIORequestBody;
    tdIORequestBody->tiIORequest = tiIORequest;
    smIORequest = (smIORequest_t *)&(tdIORequestBody->smIORequest);
    smIORequest->tdData = tdIORequestBody;

    smDeviceHandle = (smDeviceHandle_t *)&(oneDeviceData->smDeviceHandle);
    smDeviceHandle->tdData = oneDeviceData;

    smSCSIRequest = (smScsiInitiatorRequest_t *)&(tdIORequestBody->SM.smSCSIRequest);
    osti_memcpy(smSCSIRequest, tiScsiRequest, sizeof(smScsiInitiatorRequest_t));

    tiStatus = smIOStart(smRoot,
                         smIORequest,
                         smDeviceHandle,
                         smSCSIRequest,
                         interruptContext);
    /*
osGLOBAL bit32
smIOStart(
          smRoot_t          *smRoot,
          smIORequest_t         *smIORequest,
          smDeviceHandle_t      *smDeviceHandle,
          smScsiInitiatorRequest_t  *smSCSIRequest,
          bit32             interruptContext
         )


    */
  }
#else
  else if (oneDeviceData->DeviceType == TD_SATA_DEVICE)
  {
    TI_DBG5(("tiINIIOStart: calling satIOStart\n"));
    TI_DBG5(("tiINIIOStart: onedevicedata did %d\n", oneDeviceData->id));

#ifdef  SATA_ENABLE
    tdIORequestBody = (tdIORequestBody_t *)tiRequestBody;

    /* initialize */
    osti_memset(tdIORequestBody, 0, sizeof(tdIORequestBody_t));

    /* initialize tiDevhandle */
    tdIORequestBody->tiDevHandle = tiDeviceHandle;

    /* initialize tiIORequest */
    tdIORequestBody->tiIORequest = tiIORequest;
    tdIORequestBody->IOCompletionFunc = itdssIOForDebugging2Completed;

    satIOContext = &(tdIORequestBody->transport.SATA.satIOContext);

    /*
     * Need to initialize all the fields within satIOContext except
     * reqType and satCompleteCB which will be set in sat.c depending on cmd.
     */
    tdIORequestBody->transport.SATA.tiSenseData.senseData = agNULL;
    tdIORequestBody->transport.SATA.tiSenseData.senseLen = 0;
    satIOContext->pSatDevData   = &oneDeviceData->satDevData;
    satIOContext->pFis          =
      &tdIORequestBody->transport.SATA.agSATARequestBody.fis.fisRegHostToDev;
    satIOContext->pScsiCmnd     = &tiScsiRequest->scsiCmnd;
    satIOContext->pSense        = &tdIORequestBody->transport.SATA.sensePayload;
    satIOContext->pTiSenseData  = &tdIORequestBody->transport.SATA.tiSenseData;
    satIOContext->pTiSenseData->senseData = satIOContext->pSense;
    /*    satIOContext->pSense = (scsiRspSense_t *)satIOContext->pTiSenseData->senseData; */
    satIOContext->tiRequestBody = tiRequestBody;
    satIOContext->interruptContext = interruptContext;
    satIOContext->ptiDeviceHandle = tiDeviceHandle;
    satIOContext->tiScsiXchg = tiScsiRequest;
    satIOContext->satIntIoContext  = agNULL;
    satIOContext->satOrgIOContext  = agNULL;
    /*    satIOContext->tiIORequest      = tiIORequest; */

    /* save context if we need to abort later */
    tiIORequest->tdData = tdIORequestBody;

    /* followings are used only for internal IO */
    satIOContext->currentLBA = 0;
    satIOContext->OrgTL = 0;

    TI_DBG5(("tiINIIOStart: pSatDevData=%p\n", satIOContext->pSatDevData ));

    tiStatus = satIOStart( tiRoot,
                           tiIORequest,
                           tiDeviceHandle,
                           tiScsiRequest,
                           satIOContext);
    goto ext;
#endif
  }
#endif /* else of FDS_SM */
  else
  {

    tdIORequestBody = (tdIORequestBody_t *)tiRequestBody;
    tdIORequestBody->IOCompletionFunc = itdssIOForDebugging3Completed;
    TI_DBG1(("tiINIIOStart: wrong unspported Device %d\n", oneDeviceData->DeviceType));
    /*
      error. unsupported IO
     */
  }
ext:
  TDSA_INP_LEAVE(tiRoot);
  return tiStatus;
}

#ifdef FAST_IO_TEST
osGLOBAL bit32
tiINIFastIOSend(void *ioh)
{
  bit32 saStatus, tiStatus;

  saStatus = saFastSSPSend(ioh);
  if (saStatus == AGSA_RC_SUCCESS)
    tiStatus = tiSuccess;
  else
    tiStatus = tiError;
  return tiStatus;
}

osGLOBAL bit32
tiINIFastIOCancel(void *ioh)
{
  bit32 saStatus, tiStatus;

  saStatus = saFastSSPCancel(ioh);
  if (saStatus == AGSA_RC_SUCCESS)
    tiStatus = tiSuccess;
  else
    tiStatus = tiError;
  return tiStatus;
}

osGLOBAL void*
tiINIFastIOPrepare(
            tiRoot_t          *tiRoot,
            void              *ioHandle,
            agsaFastCommand_t *fc)
{
  tdsaDeviceData_t *oneDeviceData;
  tiDeviceHandle_t *tiDeviceHandle = fc->devHandle;
  bit32            taskAttribute = fc->taskAttribute;
  void             *ioh = ioHandle;

  TDSA_INP_ENTER(tiRoot);
  TI_DBG6(("tiINIFastIOPrepare: enter\n"));

  oneDeviceData = (tdsaDeviceData_t *)tiDeviceHandle->tdData;
  if(oneDeviceData == agNULL)
  {
    TI_DBG1(("tiINIFastIOPrepare: tiDeviceHandle=%p DeviceData is NULL\n",
             tiDeviceHandle));
    ioHandle = 0;
    TD_ASSERT((0), "");
    goto ext;
  }
  TI_DBG6(("tiINIFastIOPrepare: onedevicedata %p\n", oneDeviceData));

  /* starting IO with SAS device */
  if (oneDeviceData->DeviceType != TD_SAS_DEVICE)
  {
    TI_DBG1(("tiINISuperIOSend: wrong Device %d\n", oneDeviceData->DeviceType));
    /* error: unsupported IO */
    ioHandle = 0;
    TD_ASSERT((0), "");
    goto ext;
  }

  fc->agRoot = oneDeviceData->agRoot;
  TD_ASSERT((NULL != fc->agRoot), "");

  fc->devHandle = oneDeviceData->agDevHandle;
  TD_ASSERT((NULL != fc->devHandle), "");
  fc->safb->oneDeviceData = oneDeviceData;

  /*
    process taskattribute
  */
  switch (taskAttribute)
  {
    case TASK_SIMPLE:
      fc->taskAttribute = TD_TASK_SIMPLE;
      break;
    case TASK_ORDERED:
      fc->taskAttribute = TD_TASK_ORDERED;
      break;
    case TASK_HEAD_OF_QUEUE:
      fc->taskAttribute = TD_TASK_HEAD_OF_QUEUE;
      break;
    case TASK_ACA:
      fc->taskAttribute = TD_TASK_ACA;
      break;
      /* compile out for "iniload" */
  }


  TI_DBG3(("tiINIFastIOPrepare: data direction: %x\n", fc->agRequestType));
  TI_DBG6(("tiINIFastIOPrepare: device AddrHi/Lo 0x%08x / 0x%08x\n",
           oneDeviceData->SASAddressID.sasAddressHi,
           oneDeviceData->SASAddressID.sasAddressLo));

  fc->queueNum = tdsaRotateQnumber(tiRoot, oneDeviceData);

  ioHandle = saFastSSPPrepare(ioHandle, fc, ossaFastSSPCompleted, fc->safb);
  if (!ioHandle)
  {
    TI_DBG1(("tiINIFastIOPrepare: saSuperSSPSend error\n"));
    TD_ASSERT((0), "");
    //goto ext;
  }

ext:
  if (ioh && !ioHandle)
  {
    saFastSSPCancel(ioh);
  }

  TI_DBG6(("tiINIFastIOPrepare: leave\n"));

  TDSA_INP_LEAVE(tiRoot);
  return ioHandle;
} /* tiINIFastIOPrepare */
#endif

/*****************************************************************************
*
*   tiINIIOStartDif
*
*   Purpose:  This routine is called to initiate a new SCSI request with
*             DIF enable.
*
*   Parameters:
*     tiRoot:           Pointer to initiator driver/port instance.
*     tiIORequest:      Pointer to the I/O request context for this I/O.
*     tiDeviceHandle:   Pointer to device handle for this I/O.
*     tiScsiRequest:    Pointer to the SCSI-3 I/O request and SGL list.
*     tiRequestBody:    Pointer to the OS Specific module allocated storage
*                       to be used by the TD layer for executing this I/O.
*     interruptContext: The interrupt context within which this function
*                       is called.
*     difOption:        DIF option.
*
*  Return:
*
*  tiSuccess:     I/O request successfully initiated.
*  tiBusy:        No resources available, try again later.
*  tiIONoDevice:  Invalid device handle.
*  tiError:       Other errors that prevent the I/O request to be started.
*
*
*****************************************************************************/
osGLOBAL bit32 tiINIIOStartDif(
                        tiRoot_t                    *tiRoot,
                        tiIORequest_t               *tiIORequest,
                        tiDeviceHandle_t            *tiDeviceHandle,
                        tiScsiInitiatorRequest_t   *tiScsiRequest,
                        void                      *tiRequestBody,
                        bit32                       interruptContext,
                        tiDif_t                     *difOption
                        )
{

  /* This function was never used by SAS/SATA. Use tiINISuperIOStart() instead. */
  return tiBusy;
}


/*****************************************************************************
*
*   tiINISuperIOStart
*
*   Purpose:  This routine is called to initiate a new SCSI request.
*
*   Parameters:
*     tiRoot:           Pointer to initiator driver/port instance.
*     tiIORequest:      Pointer to the I/O request context for this I/O.
*     tiDeviceHandle:   Pointer to device handle for this I/O.
*     tiScsiRequest:    Pointer to the SCSI-3 I/O request and SGL list.
*     tiRequestBody:    Pointer to the OS Specific module allocated storage
*                       to be used by the TD layer for executing this I/O.
*     interruptContext: The interrupt context within which this function
*                       is called.
*  Return:
*
*  tiSuccess:     I/O request successfully initiated.
*  tiBusy:        No resources available, try again later.
*  tiIONoDevice:  Invalid device handle.
*  tiError:       Other errors that prevent the I/O request to be started.
*
*
*****************************************************************************/
osGLOBAL bit32
tiINISuperIOStart(
             tiRoot_t                       *tiRoot,
             tiIORequest_t                  *tiIORequest,
             tiDeviceHandle_t               *tiDeviceHandle,
             tiSuperScsiInitiatorRequest_t  *tiScsiRequest,
             void                           *tiRequestBody,
             bit32                          interruptContext
             )
{
  tdsaRoot_t                *tdsaRoot = agNULL;
  tdsaContext_t             *tdsaAllShared = agNULL;
  itdsaIni_t                *Initiator = agNULL;
  tdsaDeviceData_t          *oneDeviceData = agNULL;
  tdIORequestBody_t         *tdIORequestBody = agNULL;
  agsaSSPInitiatorRequest_t *agSSPInitiatorRequest = agNULL;
  agsaRoot_t                *agRoot = agNULL;
  agsaIORequest_t           *agIORequest = agNULL;
  agsaDevHandle_t           *agDevHandle = agNULL;
  agsaSASRequestBody_t      *agSASRequestBody = agNULL;
  bit32                     tiStatus = tiError;
  bit32                     saStatus = AGSA_RC_FAILURE;
  bit32                     adjusted_length = 0;
  bit32                     agRequestType   = 0;
  agBOOLEAN                 needPlusDataLenAdjustment = agFALSE;
  agBOOLEAN                 needMinusDataLenAdjustment = agFALSE;

#ifdef  SATA_ENABLE
#ifndef FDS_SM
  satIOContext_t            *satIOContext;
#endif
#endif
#ifdef FDS_SM
  smRoot_t                  *smRoot;
  smIORequest_t             *smIORequest;
  smDeviceHandle_t          *smDeviceHandle;
  smSuperScsiInitiatorRequest_t  *smSuperSCSIRequest;
#endif
#ifdef CCBUILD_INDIRECT_CDB
  agsaSSPInitiatorRequestIndirect_t *agSSPInitiatorIndRequest = agNULL;
#endif
  TD_ASSERT(tiRoot , "tiRoot");
  TD_ASSERT(tiIORequest, "tiIORequest");
  TD_ASSERT(tiDeviceHandle, "tiDeviceHandle");
  TD_ASSERT(tiRequestBody, "tiRequestBody");
  TD_ASSERT(tiRoot->tdData, "tiRoot->tdData");
  TD_ASSERT(tiDeviceHandle, "tiDeviceHandle");

  tdsaRoot        = (tdsaRoot_t *) tiRoot->tdData;
  TD_ASSERT(tdsaRoot, "tdsaRoot");

  tdsaAllShared = (tdsaContext_t *)&tdsaRoot->tdsaAllShared;
  TD_ASSERT(tdsaAllShared, "tdsaAllShared");

  Initiator = (itdsaIni_t *)tdsaAllShared->itdsaIni;
  TD_ASSERT(Initiator, "Initiator");

  oneDeviceData = (tdsaDeviceData_t *)tiDeviceHandle->tdData;
  TD_ASSERT(oneDeviceData, "oneDeviceData");


#ifdef FDS_SM
  smRoot = &(tdsaAllShared->smRoot);
  TD_ASSERT(smRoot , "smRoot");
#endif


  TI_DBG6(("tiINISuperIOStart: start\n"));
  TI_DBG6(("tiINISuperIOStart:: ******* tdsaRoot %p tdsaAllShared %p \n", tdsaRoot,tdsaAllShared));

  TI_DBG6(("tiINISuperIOStart: onedevicedata %p\n", oneDeviceData));

  if (oneDeviceData == agNULL)
  {
    TI_DBG1(("tiINISuperIOStart: tiDeviceHandle=%p DeviceData is NULL\n", tiDeviceHandle ));
    return tiIONoDevice;
  }

  /* for hotplug */
  if (oneDeviceData->valid != agTRUE || oneDeviceData->registered != agTRUE ||
      oneDeviceData->tdPortContext == agNULL )
  {
    TI_DBG1(("tiINISuperIOStart: tiDeviceHandle=%p did %d DeviceData was removed\n", tiDeviceHandle, oneDeviceData->id));
    TI_DBG6(("tiINISuperIOStart: device AddrHi 0x%08x AddrLo 0x%08x\n",
    oneDeviceData->SASAddressID.sasAddressHi, oneDeviceData->SASAddressID.sasAddressLo));
    // for debugging
    tdIORequestBody = (tdIORequestBody_t *)tiRequestBody;
    tdIORequestBody->IOCompletionFunc = itdssIOForDebugging1Completed;
    TI_DBG6(("tiINISuperIOStart: IOCompletionFunc %p\n", tdIORequestBody->IOCompletionFunc));
    return tiIONoDevice;
  }

#ifdef DBG
  if (tiIORequest->osData == agNULL)
  {
    TI_DBG1(("tiINISuperIOStart: tiIORequest->osData is NULL, wrong\n"));
    return tiError;
  }
#endif
  /* starting IO with SAS device */
  if (oneDeviceData->DeviceType == TD_SAS_DEVICE)
  {
    TI_DBG3(("tiINISuperIOStart: calling saSSPStart\n"));

    agRoot = oneDeviceData->agRoot;
    agDevHandle = oneDeviceData->agDevHandle;

    /* OS layer has tdlayer data structure pointer in tdIORequestBody_t  tdIOReqBody; in ccb_t in agtiapi.h */
    tdIORequestBody = (tdIORequestBody_t *)tiRequestBody;

    /* initialize */
    /*the tdIORequestBody has been initialized in HwBuildIo routine */
    /*osti_memset(tdIORequestBody, 0, sizeof(tdIORequestBody_t));*/

    /* let's initialize tdIOrequestBody */
    /* initialize callback */
    tdIORequestBody->IOCompletionFunc = itdssIOCompleted;

    /* initialize tiDevhandle */
    tdIORequestBody->tiDevHandle = tiDeviceHandle;

    /* initialize tiIORequest */
    tdIORequestBody->tiIORequest = tiIORequest;

    /* save context if we need to abort later */
    tiIORequest->tdData = tdIORequestBody;

    /* initialize expDataLength */
    tdIORequestBody->IOType.InitiatorRegIO.expDataLength
      = tiScsiRequest->scsiCmnd.expDataLength;

    tdIORequestBody->IOType.InitiatorRegIO.sglVirtualAddr
      = tiScsiRequest->sglVirtualAddr;

    /* initialize agIORequest */
    agIORequest = &(tdIORequestBody->agIORequest);
    agIORequest->osData = (void *) tdIORequestBody;

    /* initialize tdIORequestBody_t tdIORequestBody -> agSASRequestBody */
    agSASRequestBody = &(tdIORequestBody->transport.SAS.agSASRequestBody);
    agSSPInitiatorRequest = &(agSASRequestBody->sspInitiatorReq);

    agSSPInitiatorRequest->flag = 0;
    if (tiScsiRequest->flags & TI_SCSI_INITIATOR_ENCRYPT)
    {
      TI_DBG3(("tiINISuperIOStart: TI_SCSI_INITIATOR_ENCRYPT\n"));

      /*  Copy all of the relevant encrypt information */
      agSSPInitiatorRequest->flag |= AGSA_SAS_ENABLE_ENCRYPTION;
      TD_ASSERT( sizeof(tiEncrypt_t) == sizeof(agsaEncrypt_t) , "sizeof(tiEncrypt_t) == sizeof(agsaEncrypt_t)");
      osti_memcpy(&agSSPInitiatorRequest->encrypt, &tiScsiRequest->Encrypt, sizeof(agsaEncrypt_t));
    }

    if ((tiScsiRequest->flags & TI_SCSI_INITIATOR_DIF) &&
         (tiScsiRequest->scsiCmnd.cdb[0] == SCSIOPC_READ_10 ||
          tiScsiRequest->scsiCmnd.cdb[0] == SCSIOPC_WRITE_10 ||
          tiScsiRequest->scsiCmnd.cdb[0] == SCSIOPC_WRITE_6 ||
          tiScsiRequest->scsiCmnd.cdb[0] == SCSIOPC_READ_6 ||
          tiScsiRequest->scsiCmnd.cdb[0] == SCSIOPC_READ_12 ||
          tiScsiRequest->scsiCmnd.cdb[0] == SCSIOPC_WRITE_12 ||
          tiScsiRequest->scsiCmnd.cdb[0] == SCSIOPC_WRITE_16 ||
          tiScsiRequest->scsiCmnd.cdb[0] == SCSIOPC_READ_16 ))
    {
      TI_DBG3(("tiINISuperIOStart: TI_SCSI_INITIATOR_DIF\n"));
      /* Copy all of the relevant DIF information */
      agSSPInitiatorRequest->flag |= AGSA_SAS_ENABLE_DIF;
      osti_memcpy(&agSSPInitiatorRequest->dif, &tiScsiRequest->Dif, sizeof(agsaDif_t));

      /* Check if need to adjust dataLength. */
      switch (tiScsiRequest->dataDirection)
      {
      case tiDirectionOut: /* Write/Outbound */
          break;

      case tiDirectionIn:  /* Read/Inbound */
          if ((agSSPInitiatorRequest->dif.flags & DIF_ACTION_FLAG_MASK) == DIF_INSERT)
          {
              needPlusDataLenAdjustment = agTRUE;
          }
          break;
      }

      /* Set SGL data len XXX This code needs to support more sector sizes */
      /* Length adjustment for PCIe DMA only not SAS */
      if (needPlusDataLenAdjustment == agTRUE)
      {
        adjusted_length = tiScsiRequest->scsiCmnd.expDataLength;
        adjusted_length += (adjusted_length/512) * 8;
        agSSPInitiatorRequest->dataLength = adjusted_length;
      }
      else if (needMinusDataLenAdjustment == agTRUE)
      {
        adjusted_length = tiScsiRequest->scsiCmnd.expDataLength;
        adjusted_length -= (adjusted_length/520) * 8;
        agSSPInitiatorRequest->dataLength = adjusted_length;
      }
      else
      {
        /* setting the data length */
        agSSPInitiatorRequest->dataLength  = tiScsiRequest->scsiCmnd.expDataLength;
      }

      /* initializes "agsaSgl_t   agSgl" of "agsaDifSSPInitiatorRequest_t" */
      tiStatus = itdssIOPrepareSGL(
                                   tiRoot,
                                   tdIORequestBody,
                                   &tiScsiRequest->agSgl1,
                                   tiScsiRequest->sglVirtualAddr
                                   );
      TI_DBG2(("tiINISuperIOStart:TI_SCSI_INITIATOR_DIF needMinusDataLenAdjustment %d needPlusDataLenAdjustment %d difAction %X\n",
                   needMinusDataLenAdjustment,
                   needPlusDataLenAdjustment,
                   agSSPInitiatorRequest->dif.flags & DIF_ACTION_FLAG_MASK));

    }
    else
    {
      /* setting the data length */
      agSSPInitiatorRequest->dataLength  = tiScsiRequest->scsiCmnd.expDataLength;

      /* initializes "agsaSgl_t   agSgl" of "agsaSSPInitiatorRequest_t" */
      tiStatus = itdssIOPrepareSGL(
                                   tiRoot,
                                   tdIORequestBody,
                                   &tiScsiRequest->agSgl1,
                                   tiScsiRequest->sglVirtualAddr
                                   );
    }

    if (tiStatus != tiSuccess)
    {
      TI_DBG1(("tiINISuperIOStart: can't get SGL\n"));
      return tiStatus;
    }

    TI_DBG6(("tiINISuperIOStart: tiScsiRequest->scsiCmnd.expDataLength %d\n", tiScsiRequest->scsiCmnd.expDataLength));

    /* process taskattribute */
    if (tiScsiRequest->scsiCmnd.taskAttribute == TASK_SIMPLE)
    {
      agSSPInitiatorRequest->sspCmdIU.efb_tp_taskAttribute = (bit8)
       agSSPInitiatorRequest->sspCmdIU.efb_tp_taskAttribute | TD_TASK_SIMPLE;
    }
    else if (tiScsiRequest->scsiCmnd.taskAttribute == TASK_ORDERED)
    {
      agSSPInitiatorRequest->sspCmdIU.efb_tp_taskAttribute = (bit8)
       agSSPInitiatorRequest->sspCmdIU.efb_tp_taskAttribute | TD_TASK_ORDERED;
    }
    else if (tiScsiRequest->scsiCmnd.taskAttribute == TASK_HEAD_OF_QUEUE)
    {
      agSSPInitiatorRequest->sspCmdIU.efb_tp_taskAttribute = (bit8)
       agSSPInitiatorRequest->sspCmdIU.efb_tp_taskAttribute | TD_TASK_HEAD_OF_QUEUE;
    }
    else if (tiScsiRequest->scsiCmnd.taskAttribute == TASK_ACA)
    {
      agSSPInitiatorRequest->sspCmdIU.efb_tp_taskAttribute = (bit8)
       agSSPInitiatorRequest->sspCmdIU.efb_tp_taskAttribute | TD_TASK_ACA;
    }

    /* copy cdb bytes */
    osti_memcpy(agSSPInitiatorRequest->sspCmdIU.cdb, tiScsiRequest->scsiCmnd.cdb, 16);
    /* copy lun field */
    osti_memcpy(agSSPInitiatorRequest->sspCmdIU.lun, tiScsiRequest->scsiCmnd.lun.lun, 8);
#ifdef CCBUILD_INDIRECT_CDB
    /* check the Indirect CDB flag */
    if (tiScsiRequest->flags & TI_SCSI_INITIATOR_INDIRECT_CDB)
    {
      /* Indirect CDB */
      if (tiScsiRequest->dataDirection == tiDirectionIn)
      {
        agRequestType = AGSA_SSP_INIT_READ_INDIRECT;
        TI_DBG6(("tiINISuperIOStart: Indirect READ\n"));
      }
      else if (tiScsiRequest->dataDirection == tiDirectionOut)
      {
        agRequestType = AGSA_SSP_INIT_WRITE_INDIRECT;
        TI_DBG6(("tiINISuperIOStart: Indirect WRITE\n"));
      }
      else
      {
        agRequestType = AGSA_REQ_TYPE_UNKNOWN;
        TI_DBG1(("tiINISuperIOStart: unknown data direction\n"));
      }
      agSSPInitiatorIndRequest = &(agSASRequestBody->sspInitiatorReqIndirect);
      /* copy the constructed SSPIU info to indirect SSPIU buffer */
      osti_memcpy(tiScsiRequest->IndCDBBuffer, &agSSPInitiatorRequest->sspCmdIU, sizeof(agsaSSPCmdInfoUnit_t));
      /* initialize the indirect CDB buffer address and length */
      agSSPInitiatorIndRequest->sspInitiatorReqAddrLower32 = tiScsiRequest->IndCDBLowAddr;
      agSSPInitiatorIndRequest->sspInitiatorReqAddrUpper32 = tiScsiRequest->IndCDBHighAddr;
      agSSPInitiatorIndRequest->sspInitiatorReqLen         = sizeof(agsaSSPCmdInfoUnit_t);
    }
    else
#endif //CCBUILD_INDIRECT_CDB
    {
      /* Direct CDB */
      if (tiScsiRequest->dataDirection == tiDirectionIn)
      {
        agRequestType = AGSA_SSP_INIT_READ;
        TI_DBG6(("tiINISuperIOStart: READ\n"));
      }
      else if (tiScsiRequest->dataDirection == tiDirectionOut)
      {
        agRequestType = AGSA_SSP_INIT_WRITE;
        TI_DBG6(("tiINISuperIOStart: WRITE\n"));
      }
      else
      {
        agRequestType = AGSA_REQ_TYPE_UNKNOWN;
        TI_DBG1(("tiINISuperIOStart: unknown data direction\n"));
      }
    }

    tdIORequestBody->agRequestType = agRequestType;
   
    TI_DBG6(("tiINISuperIOStart: device AddrHi 0x%08x\n", oneDeviceData->SASAddressID.sasAddressHi));
    TI_DBG6(("tiINISuperIOStart: device AddrLo 0x%08x\n", oneDeviceData->SASAddressID.sasAddressLo));

#ifdef DBG
    /* for debugging */
    if (tdIORequestBody->IOCompletionFunc == agNULL)
    {
      TI_DBG1(("tiINISuperIOStart: Error!!!! IOCompletionFunc is NULL\n"));
      return tiError;
    }
#endif
    saStatus = saSSPStart(agRoot,
                          agIORequest,
                          tdsaRotateQnumber(tiRoot, oneDeviceData),
                          agDevHandle,
                          agRequestType,
                          agSASRequestBody,
                          agNULL,
                          &ossaSSPCompleted);

    if (saStatus == AGSA_RC_SUCCESS)
    {
      Initiator->NumIOsActive++;
      tdIORequestBody->ioStarted = agTRUE;
      tdIORequestBody->ioCompleted = agFALSE;
      tiStatus = tiSuccess;
    }
    else
    {
      tdIORequestBody->ioStarted = agFALSE;
      tdIORequestBody->ioCompleted = agTRUE;
      if (saStatus == AGSA_RC_BUSY)
      {
        TI_DBG4(("tiINISuperIOStart: saSSPStart busy\n"));
        tiStatus = tiBusy;
      }
      else
      {
        tiStatus = tiError;
      }
      return tiStatus;
    }
  }
#ifdef FDS_SM
  else if (oneDeviceData->DeviceType == TD_SATA_DEVICE)
  {
    TI_DBG5(("tiINISuperIOStart: calling satIOStart\n"));
    TI_DBG5(("tiINISuperIOStart: onedevicedata did %d\n", oneDeviceData->id));
    TI_DBG5(("tiINISuperIOStart: SATA sasAddressHi 0x%08x\n", oneDeviceData->SASAddressID.sasAddressHi));
    TI_DBG5(("tiINISuperIOStart: SATA sasAddressLo 0x%08x\n", oneDeviceData->SASAddressID.sasAddressLo));
    
    tdIORequestBody = (tdIORequestBody_t *)tiRequestBody;
    /* initialize */
    /* the tdIORequestBody has been initialized by Storport in SRB Extension */
    /*osti_memset(tdIORequestBody, 0, sizeof(tdIORequestBody_t));*/
    /* initialize tiDevhandle */
    tdIORequestBody->tiDevHandle = tiDeviceHandle;
    tdIORequestBody->superIOFlag = agTRUE;

    tiIORequest->tdData = tdIORequestBody;
    tdIORequestBody->tiIORequest = tiIORequest;
    smIORequest = (smIORequest_t *)&(tdIORequestBody->smIORequest);
    smIORequest->tdData = tdIORequestBody;
    smIORequest->smData = &tdIORequestBody->smIORequestBody;

    smDeviceHandle = (smDeviceHandle_t *)&(oneDeviceData->smDeviceHandle);
    smDeviceHandle->tdData = oneDeviceData;

    smSuperSCSIRequest = (smSuperScsiInitiatorRequest_t *)&(tdIORequestBody->SM.smSuperSCSIRequest);
    osti_memcpy(smSuperSCSIRequest, tiScsiRequest, sizeof(smSuperScsiInitiatorRequest_t));

    tiStatus = smSuperIOStart(smRoot,
                              smIORequest,
                              smDeviceHandle,
                              smSuperSCSIRequest,
                              oneDeviceData->SASAddressID.sasAddressHi,                       
                              oneDeviceData->SASAddressID.sasAddressLo,
                              interruptContext);

  }
#else
  else if (oneDeviceData->DeviceType == TD_SATA_DEVICE)
  {

    TI_DBG5(("tiINISuperIOStart: calling satIOStart\n"));
    TI_DBG5(("tiINISuperIOStart: onedevicedata did %d\n", oneDeviceData->id));

#ifdef  SATA_ENABLE
    tdIORequestBody = (tdIORequestBody_t *)tiRequestBody;

    /* initialize */
    osti_memset(tdIORequestBody, 0, sizeof(tdIORequestBody_t));

    /* initialize tiDevhandle */
    tdIORequestBody->tiDevHandle = tiDeviceHandle;

    /* initialize tiIORequest */
    tdIORequestBody->tiIORequest = tiIORequest;
    tdIORequestBody->IOCompletionFunc = itdssIOForDebugging2Completed;

    satIOContext = &(tdIORequestBody->transport.SATA.satIOContext);

    /*
     * Need to initialize all the fields within satIOContext except
     * reqType and satCompleteCB which will be set in sat.c depending on cmd.
     */
    tdIORequestBody->transport.SATA.tiSenseData.senseData = agNULL;
    tdIORequestBody->transport.SATA.tiSenseData.senseLen = 0;
    satIOContext->pSatDevData   = &oneDeviceData->satDevData;
    satIOContext->pFis          =
      &tdIORequestBody->transport.SATA.agSATARequestBody.fis.fisRegHostToDev;
    satIOContext->pScsiCmnd     = &tiScsiRequest->scsiCmnd;
    satIOContext->pSense        = &tdIORequestBody->transport.SATA.sensePayload;
    satIOContext->pTiSenseData  = &tdIORequestBody->transport.SATA.tiSenseData;
    satIOContext->pTiSenseData->senseData = satIOContext->pSense;
    /*    satIOContext->pSense = (scsiRspSense_t *)satIOContext->pTiSenseData->senseData; */
    satIOContext->tiRequestBody = tiRequestBody;
    satIOContext->interruptContext = interruptContext;
    satIOContext->ptiDeviceHandle = tiDeviceHandle;
    /*
     This code uses a kludge for the tiScsiXchg. Many subroutines in the SATA code
     require a tiScsiInitiatorRequest. Since it would be a lot of work to replicate
     those functions for a tiSuperScsiInitiatorRequest, we will use a short cut.
     The standard pointer will be passed, but the superIOFlag marks the real type of the structure.
    */
    satIOContext->tiScsiXchg = tiScsiRequest;
    satIOContext->superIOFlag = agTRUE;

    satIOContext->satIntIoContext  = agNULL;
    satIOContext->satOrgIOContext  = agNULL;
    /*    satIOContext->tiIORequest      = tiIORequest; */

    /* save context if we need to abort later */
    tiIORequest->tdData = tdIORequestBody;

    /* followings are used only for internal IO */
    satIOContext->currentLBA = 0;
    satIOContext->OrgTL = 0;

    TI_DBG5(("tiINISuperIOStart: pSatDevData=%p\n", satIOContext->pSatDevData ));

    tiStatus = satIOStart( tiRoot,
                           tiIORequest,
                           tiDeviceHandle,
                           satIOContext->tiScsiXchg,
                           satIOContext);

    return tiStatus;
#endif
  }
#endif /* else of FDS_SM */

  else
  {

    tdIORequestBody = (tdIORequestBody_t *)tiRequestBody;
    tdIORequestBody->IOCompletionFunc = itdssIOForDebugging3Completed;
    TI_DBG1(("tiINISuperIOStart: wrong unspported Device %d\n", oneDeviceData->DeviceType));
    /*
      error. unsupported IO
     */
  }
  return tiStatus;
}

osGLOBAL bit32
tiINISMPStart(
       tiRoot_t                  *tiRoot,
       tiIORequest_t             *tiIORequest,
       tiDeviceHandle_t          *tiDeviceHandle,
       tiSMPFrame_t              *tiSMPFrame,
       void                      *tiSMPBody,
       bit32                     interruptContext
       )
{
  tdsaDeviceData_t          *oneDeviceData;
  agsaIORequest_t           *agIORequest = agNULL;
  tdIORequestBody_t         *tdSMPRequestBody = agNULL;
  agsaRoot_t                *agRoot = agNULL;
  agsaDevHandle_t           *agDevHandle = agNULL;
  agsaSASRequestBody_t      *agRequestBody = agNULL;
  agsaSMPFrame_t            *agSMPFrame = agNULL;
  bit32                     agRequestType;
  bit32                     tiStatus = tiError;
  bit32                     saStatus = AGSA_RC_FAILURE;
  bit32                     queueNum;
  TDSA_INP_ENTER(tiRoot);
    TI_DBG6(("tiINISMPStart: start\n"));
    oneDeviceData = (tdsaDeviceData_t *)tiDeviceHandle->tdData;
  TI_DBG6(("tiINISMPStart: onedevicedata %p\n", oneDeviceData));
    TI_DBG6(("tiINISMPStart: tiDeviceHandle %p\n", tiDeviceHandle));
  if (oneDeviceData == agNULL)
  {
    TI_DBG1(("tiINISMPStart: tiDeviceHandle=%p Expander DeviceData is NULL\n", tiDeviceHandle ));
    return tiError;
  }
  if (tiIORequest->osData == agNULL)
  {
    TI_DBG1(("tiINISMPStart: tiIORequest->osData is NULL, wrong\n"));
    return tiError;
  }
  agRoot = oneDeviceData->agRoot;
  agDevHandle = oneDeviceData->agDevHandle;
  tdSMPRequestBody = (tdIORequestBody_t *)tiSMPBody;
  tdSMPRequestBody->tiIORequest = tiIORequest;
  tiIORequest->tdData = tdSMPRequestBody;
  agIORequest = &(tdSMPRequestBody->agIORequest);
  agIORequest->osData = (void *) tdSMPRequestBody;
  agRequestBody = &(tdSMPRequestBody->transport.SAS.agSASRequestBody);
  agSMPFrame = &(agRequestBody->smpFrame);
  if (!DEVICE_IS_SMP_TARGET(oneDeviceData))
  {
    TI_DBG1(("tiINISMPStart: Target Device is not SMP device\n"));
    return tiError;
  }
  if (tiSMPFrame->flag == 0) // define DIRECT SMP at td layer?
  {
    TI_DBG6(("tiINISMPStart: Direct SMP\n"));
    agSMPFrame->outFrameBuf = tiSMPFrame->outFrameBuf;
    agSMPFrame->outFrameLen = tiSMPFrame->outFrameLen;
    tdhexdump("tiINISMPStart agSMPFrame", (bit8 *)agSMPFrame->outFrameBuf, agSMPFrame->outFrameLen);
    agSMPFrame->expectedRespLen = tiSMPFrame->expectedRespLen;
    agSMPFrame->inFrameLen = 0;
    agSMPFrame->flag = tiSMPFrame->flag;
    agRequestType = AGSA_SMP_INIT_REQ;
    queueNum = 0;
    saStatus = saSMPStart(agRoot,
                agIORequest,
                queueNum,
                agDevHandle,
                agRequestType,
                agRequestBody,
                &ossaSMPCAMCompleted
               );
    if (saStatus == AGSA_RC_SUCCESS)
    {
      tiStatus = tiSuccess;
    }
    else
    {
      if (saStatus == AGSA_RC_BUSY)
      {
        TI_DBG1(("tiINISMPStart: saSSPStart busy\n"));
        tiStatus = tiBusy;
      }
      else
      {
        TI_DBG1(("tiINISMPStart: saSSPStart error\n"));
        tiStatus = tiError;
      }
      return tiStatus;
    }
  }
  else
  {
    TI_DBG1(("tiINISMPStart: Indirect SMP! Not supported yet\n"));
    tiStatus = tiError;
  }
  return tiStatus;
}
#ifdef TD_INT_COALESCE
osGLOBAL bit32
tiINIIOStartIntCoalesce(
             tiRoot_t                  *tiRoot,
             tiIORequest_t             *tiIORequest,
             tiDeviceHandle_t          *tiDeviceHandle,
             tiScsiInitiatorRequest_t *tiScsiRequest,
             void                      *tiRequestBody,
             bit32                     interruptContext,
             tiIntCoalesceContext_t    *tiIntCoalesceCxt
             )
{
  tdsaRoot_t                *tdsaRoot        = (tdsaRoot_t *) tiRoot->tdData;
  tdsaContext_t             *tdsaAllShared = (tdsaContext_t *)&tdsaRoot->tdsaAllShared;
  itdsaIni_t                *Initiator = (itdsaIni_t *)tdsaAllShared->itdsaIni;
  tdsaDeviceData_t          *oneDeviceData;
  agsaRoot_t                *agRoot = agNULL;
  agsaIORequest_t           *agIORequest = agNULL;
  agsaDevHandle_t           *agDevHandle = agNULL;
  bit32                     agRequestType;
  agsaSASRequestBody_t      *agSASRequestBody = agNULL;
  bit32                     tiStatus = tiError;
  bit32                     saStatus = AGSA_RC_FAILURE;

  tdIORequestBody_t         *tdIORequestBody;
  agsaSSPInitiatorRequest_t *agSSPInitiatorRequest;
  tdsaIntCoalesceContext_t  *tdsaIntCoalCxt;
  agsaIntCoalesceContext_t  *agIntCoalCxt;

  TI_DBG1(("tiINIIOStartIntCoalesce: start\n"));
  oneDeviceData = (tdsaDeviceData_t *)tiDeviceHandle->tdData;

  TI_DBG6(("tiINIIOStartIntCoalesce: onedevicedata %p\n", oneDeviceData));

  if(oneDeviceData == agNULL)
  {
    TI_DBG1(("tiINIIOStartIntCoalesce: tiDeviceHandle=%p DeviceData is NULL\n", tiDeviceHandle ));
    return tiIONoDevice;
  }

  /* starting IO with SAS device */
  if (oneDeviceData->DeviceType == TD_SAS_DEVICE)
  {
    TI_DBG6(("tiINIIOStartIntCoalesce: calling saSSPStart\n"));

    agRoot = oneDeviceData->agRoot;
    agDevHandle = oneDeviceData->agDevHandle;

    /* OS layer has tdlayer data structure pointer in
       tdIORequestBody_t    tdIOReqBody;
       in ccb_t in agtiapi.h
    */
    tdIORequestBody = (tdIORequestBody_t *)tiRequestBody;

    /* let's initialize tdIOrequestBody */
    /* initialize callback */
    tdIORequestBody->IOCompletionFunc = itdssIOCompleted;

    /* initialize tiDevhandle */
    tdIORequestBody->tiDevHandle = tiDeviceHandle;

    /* initialize tiIORequest */
    tdIORequestBody->tiIORequest = tiIORequest;

    /* save context if we need to abort later */
    tiIORequest->tdData = tdIORequestBody;

    /* initialize expDataLength */
    tdIORequestBody->IOType.InitiatorRegIO.expDataLength
      = tiScsiRequest->scsiCmnd.expDataLength;

    /* initializes "agsaSgl_t   agSgl" of "agsaDifSSPInitiatorRequest_t" */
    tiStatus = itdssIOPrepareSGL(
                                 tiRoot,
                                 tdIORequestBody,
                                 &tiScsiRequest->agSgl1,
                                 tiScsiRequest->sglVirtualAddr
                                 );

    if (tiStatus != tiSuccess)
    {
      TI_DBG1(("tiINIIOStartIntCoalesce: can't get SGL\n"));
      return tiStatus;
    }


    /* initialize agIORequest */
    agIORequest = &(tdIORequestBody->agIORequest);
    agIORequest->osData = (void *) tdIORequestBody;
    agIORequest->sdkData = agNULL; /* LL takes care of this */


    /*
      initialize
      tdIORequestBody_t tdIORequestBody -> agSASRequestBody
    */
    agSASRequestBody = &(tdIORequestBody->transport.SAS.agSASRequestBody);
    agSSPInitiatorRequest = &(agSASRequestBody->sspInitiatorReq);


    /* copy cdb bytes */
    osti_memcpy(agSSPInitiatorRequest->sspCmdIU.cdb, tiScsiRequest->scsiCmnd.cdb, 16);

    /* copy lun field */
    osti_memcpy(agSSPInitiatorRequest->sspCmdIU.lun,
                tiScsiRequest->scsiCmnd.lun.lun, 8);

    /* setting the data length */
    agSSPInitiatorRequest->dataLength  = tiScsiRequest->scsiCmnd.expDataLength;
    TI_DBG6(("tiINIIOStartIntCoalesce: tiScsiRequest->scsiCmnd.expDataLength %d\n", tiScsiRequest->scsiCmnd.expDataLength));

    agSSPInitiatorRequest->firstBurstSize = 0;

    if (tiScsiRequest->dataDirection == tiDirectionIn)
    {
      agRequestType = AGSA_SSP_INIT_READ;
      TI_DBG6(("tiINIIOStartIntCoalesce: READ\n"));
    }
    else if (tiScsiRequest->dataDirection == tiDirectionOut)
    {
      agRequestType = AGSA_SSP_INIT_WRITE;
      TI_DBG6(("tiINIIOStartIntCoalesce: WRITE\n"));
    }
    else
    {
      agRequestType = AGSA_REQ_TYPE_UNKNOWN;
      TI_DBG1(("tiINIIOStartIntCoalesce: unknown data direction\n"));
    }

    tdIORequestBody->agRequestType = agRequestType;

    tdsaIntCoalCxt = (tdsaIntCoalesceContext_t *)tiIntCoalesceCxt->tdData;
    agIntCoalCxt = &(tdsaIntCoalCxt->agIntCoalCxt);


   
#ifdef LL_INT_COALESCE
    saStatus = saSSPStartIntCoalesce(agRoot,
                                     agIORequest,
                                     agIntCoalCxt,
                                     agDevHandle,
                                     agRequestType,
                                     agSASRequestBody,
                                     &ossaSSPCompleted);
#endif

    tdIORequestBody->ioStarted = agTRUE;
    tdIORequestBody->ioCompleted = agFALSE;

    if (saStatus == AGSA_RC_SUCCESS)
    {
      Initiator->NumIOsActive++;
      tiStatus = tiSuccess;
    }
    else
    {
      TI_DBG1(("tiINIIOStartIntCoalesce: saSSPStart failed\n"));
      tdIORequestBody->ioStarted = agFALSE;
      tdIORequestBody->ioCompleted = agTRUE;
      if (saStatus == AGSA_RC_BUSY)
      {
        tiStatus = tiBusy;
      }
      else
      {
        tiStatus = tiError;
      }
      return tiStatus;
    }
  }

  else if (oneDeviceData->DeviceType == TD_SATA_DEVICE)
  {
    /*
      satIOStart() -> saSATAStartIntCoalesce()
    */
    TI_DBG1(("tiINIIOStartIntCoalesce: SATA not supported yet\n"));
    return tiStatus;
  }
  else
  {
    TI_DBG1(("tiINIIOStartIntCoalesce: wrong unspported Device %d\n", oneDeviceData->DeviceType));
    /*
      error. unsupported IO
     */
  }
  return tiStatus;


}

osGLOBAL bit32
tiINIIOStartIntCoalesceDif(
                           tiRoot_t                  *tiRoot,
                           tiIORequest_t             *tiIORequest,
                           tiDeviceHandle_t          *tiDeviceHandle,
                           tiScsiInitiatorRequest_t *tiScsiRequest,
                           void                      *tiRequestBody,
                           bit32                     interruptContext,
                           tiIntCoalesceContext_t    *tiIntCoalesceCxt,
                           tiDif_t                   *difOption
                           )
{
  tdsaRoot_t                   *tdsaRoot        = (tdsaRoot_t *) tiRoot->tdData;
  tdsaContext_t                *tdsaAllShared = (tdsaContext_t *)&tdsaRoot->tdsaAllShared;
  itdsaIni_t                   *Initiator = (itdsaIni_t *)tdsaAllShared->itdsaIni;
  tdsaDeviceData_t             *oneDeviceData;
  agsaRoot_t                   *agRoot = agNULL;
  agsaIORequest_t              *agIORequest = agNULL;
  agsaDevHandle_t              *agDevHandle = agNULL;
  bit32                        agRequestType;
  agsaDifSSPRequestBody_t      *agEdcSSPRequestBody = agNULL;
  bit32                        tiStatus = tiError;
  bit32                        saStatus = AGSA_RC_FAILURE;

  tdIORequestBody_t            *tdIORequestBody;
  agsaDifSSPInitiatorRequest_t *agEdcSSPInitiatorRequest;
  agsaDif_t                    *agEdc;
  bit32                        agUpdateMask = 0;
  bit32                        agVerifyMask = 0;
  tdsaIntCoalesceContext_t     *tdsaIntCoalCxt;
  agsaIntCoalesceContext_t     *agIntCoalCxt;

  TI_DBG1(("tiINIIOStartIntCoalesceDif: start\n"));
  oneDeviceData = (tdsaDeviceData_t *)tiDeviceHandle->tdData;

  TI_DBG6(("tiINIIOStartIntCoalesceDif: onedevicedata %p\n", oneDeviceData));

  if(oneDeviceData == agNULL)
  {
    TI_DBG1(("tiINIIOStartIntCoalesceDif: tiDeviceHandle=%p DeviceData is NULL\n", tiDeviceHandle ));
    return tiIONoDevice;
  }

  /* starting IO with SAS device */
  if (oneDeviceData->DeviceType == TD_SAS_DEVICE)
  {
    TI_DBG6(("tiINIIOStartIntCoalesceDif: calling saSSPStart\n"));

    agRoot = oneDeviceData->agRoot;
    agDevHandle = oneDeviceData->agDevHandle;

    /* OS layer has tdlayer data structure pointer in
       tdIORequestBody_t    tdIOReqBody;
       in ccb_t in agtiapi.h
    */
    tdIORequestBody = (tdIORequestBody_t *)tiRequestBody;

    /* let's initialize tdIOrequestBody */
    /* initialize callback */
    tdIORequestBody->IOCompletionFunc = itdssIOCompleted;

    /* initialize tiDevhandle */
    tdIORequestBody->tiDevHandle = tiDeviceHandle;

    /* initialize tiIORequest */
    tdIORequestBody->tiIORequest = tiIORequest;

    /* save context if we need to abort later */
    tiIORequest->tdData = tdIORequestBody;

    /* initialize expDataLength */
    tdIORequestBody->IOType.InitiatorRegIO.expDataLength
      = tiScsiRequest->scsiCmnd.expDataLength;

    /* initializes "agsaSgl_t   agSgl" of "agsaDifSSPInitiatorRequest_t" */
    tiStatus = itdssIOPrepareSGL(
                                 tiRoot,
                                 tdIORequestBody,
                                 &tiScsiRequest->agSgl1,
                                 tiScsiRequest->sglVirtualAddr
                                 );

    if (tiStatus != tiSuccess)
    {
      TI_DBG1(("tiINIIOStartIntCoalesceDif: can't get SGL\n"));
      return tiStatus;
    }


    /* initialize agIORequest */
    agIORequest = &(tdIORequestBody->agIORequest);
    agIORequest->osData = (void *) tdIORequestBody;
    agIORequest->sdkData = agNULL; /* LL takes care of this */


    /*
      initialize
      tdIORequestBody_t tdIORequestBody -> agSASRequestBody
    */
    agEdcSSPRequestBody = &(tdIORequestBody->transport.SAS.agEdcSSPRequestBody);
    agEdcSSPInitiatorRequest = &(agEdcSSPRequestBody->edcSSPInitiatorReq);


    /* copy cdb bytes */
    osti_memcpy(agEdcSSPInitiatorRequest->sspCmdIU.cdb, tiScsiRequest->scsiCmnd.cdb, 16);

    /* copy lun field */
    osti_memcpy(agEdcSSPInitiatorRequest->sspCmdIU.lun,
                tiScsiRequest->scsiCmnd.lun.lun, 8);


    /* setting the data length */
    agEdcSSPInitiatorRequest->dataLength  = tiScsiRequest->scsiCmnd.expDataLength;
    TI_DBG6(("tiINIIOStartIntCoalesceDif: tiScsiRequest->scsiCmnd.expDataLength %d\n", tiScsiRequest->scsiCmnd.expDataLength));

    agEdcSSPInitiatorRequest->firstBurstSize = 0;


    if (tiScsiRequest->dataDirection == tiDirectionIn)
    {
      agRequestType = AGSA_SSP_INIT_READ;
      TI_DBG1(("tiINIIOStartIntCoalesceDif: READ difAction %X\n",difOption->difAction));
    }
    else if (tiScsiRequest->dataDirection == tiDirectionOut)
    {
      agRequestType = AGSA_SSP_INIT_WRITE;
      TI_DBG1(("tiINIIOStartIntCoalesceDif: WRITE difAction %X\n",difOption->difAction));
    }
    else
    {
      agRequestType = AGSA_REQ_TYPE_UNKNOWN;
      TI_DBG1(("tiINIIOStartIntCoalesceDif: unknown data direction\n"));
    }

    tdIORequestBody->agRequestType = agRequestType;

    /* process interrupt coalesce context */
    tdsaIntCoalCxt = (tdsaIntCoalesceContext_t *)tiIntCoalesceCxt->tdData;
    agIntCoalCxt = &(tdsaIntCoalCxt->agIntCoalCxt);

    /* process DIF */

    agEdc = &(agEdcSSPInitiatorRequest->edc);

    osti_memset(agEdc, 0, sizeof(agsaDif_t));

    /* setting edcFlag */
    if (difOption->enableBlockCount)
    {
      /* enables block count; bit5 */
      agEdc->edcFlag = agEdc->edcFlag | 0x20; /* 0010 0000 */
    }

    if (difOption->enableCrc)
    {
      /* enables CRC verification; bit6 */
      agEdc->edcFlag = agEdc->edcFlag | 0x40; /* 0100 0000 */
    }

    if (difOption->enableIOSeed)
    {
      
    }
    if (difOption->difAction == DIF_INSERT)
    {
      /* bit 0 - 2; 000 */
      agEdc->edcFlag = agEdc->edcFlag & 0xFFFFFFF8;
    }
    else if (difOption->difAction == DIF_VERIFY_FORWARD)
    {
      /* bit 0 - 2; 001 */
      agEdc->edcFlag = agEdc->edcFlag | 0x01;
    }
    else if (difOption->difAction == DIF_VERIFY_DELETE)
    {
      /* bit 0 - 2; 010 */
      agEdc->edcFlag = agEdc->edcFlag | 0x02;
    }
    else
    {
      /* DIF_VERIFY_REPLACE */
      /* bit 0 - 2; 011 */
      agEdc->edcFlag = agEdc->edcFlag | 0x04;
    }

    /* set Update Mask; bit 16-21 */
    agUpdateMask = (difOption->tagUpdateMask) & 0x3F; /* 0011 1111 */
    agUpdateMask = agUpdateMask << 16;
    agEdc->edcFlag = agEdc->edcFlag | agUpdateMask;

    /* set Verify Mask bit 24-29 */
    agVerifyMask = (difOption->tagVerifyMask) & 0x3F; /* 0011 1111 */
    agVerifyMask = agVerifyMask << 24;
    agEdc->edcFlag = agEdc->edcFlag | agVerifyMask;

    agEdc->appTag = difOption->udtArray[0];
    agEdc->appTag = (agEdc->appTag << 8) | difOption->udtArray[1];

    agEdc->lbaReferenceTag =  difOption->udtArray[2];
    agEdc->lbaReferenceTag = (agEdc->lbaReferenceTag << 8) | difOption->udtArray[3];
    agEdc->lbaReferenceTag = (agEdc->lbaReferenceTag << 8) | difOption->udtArray[4];
    agEdc->lbaReferenceTag = (agEdc->lbaReferenceTag << 8) | difOption->udtArray[5];

    /* currently TISA supports only 512 logical block size */
    agEdc->lbSize = 512;


#ifdef LL_INT_COALESCE
    saStatus = saSSPStartIntCoalesceEdc(agRoot,
                                        agIORequest,
                                        agIntCoalCxt,
                                        agDevHandle,
                                        agRequestType,
                                        agEdcSSPRequestBody,
                                        &ossaSSPCompleted);
#endif

    tdIORequestBody->ioStarted = agTRUE;
    tdIORequestBody->ioCompleted = agFALSE;

    if (saStatus == AGSA_RC_SUCCESS)
    {
      Initiator->NumIOsActive++;
      tiStatus = tiSuccess;
    }
    else
    {
      TI_DBG1(("tiINIIOStartIntCoalesceDif: saSSPStart failed\n"));
      tdIORequestBody->ioStarted = agFALSE;
      tdIORequestBody->ioCompleted = agTRUE;
      if (saStatus == AGSA_RC_BUSY)
      {
        tiStatus = tiBusy;
      }
      else
      {
        tiStatus = tiError;
      }
      return tiStatus;
    }
  }
  else if (oneDeviceData->DeviceType == TD_SATA_DEVICE)
  {
    /*
      satIOStart() -> saSATAStartIntCoalesceEdc()
    */
    TI_DBG1(("tiINIIOStartIntCoalesceDif: SATA not supported yet\n"));
    return tiStatus;
  }
  else
  {
    TI_DBG1(("tiINIIOStartIntCoalesceDif: wrong unspported Device %d\n", oneDeviceData->DeviceType));
    /*
      error. unsupported IO
     */
  }
  return tiStatus;
}


osGLOBAL bit32
tiINIIntCoalesceInit(
                     tiRoot_t                  *tiRoot,
                     tiIntCoalesceContext_t    *tiIntCoalesceCxt,
                     bit32                     count
                     )
{

  tdsaRoot_t                *tdsaRoot        = (tdsaRoot_t *) tiRoot->tdData;
  tdsaContext_t             *tdsaAllShared = (tdsaContext_t *)&tdsaRoot->tdsaAllShared;
  agsaRoot_t                *agRoot = agNULL;
  tdsaIntCoalesceContext_t  *tdsaIntCoalCxtHead
    = (tdsaIntCoalesceContext_t *)tdsaAllShared->IntCoalesce;
  tdsaIntCoalesceContext_t  *tdsaIntCoalCxt;
  agsaIntCoalesceContext_t  *agIntCoalCxt;
  tdList_t                  *tdsaIntCoalCxtList = agNULL;

  bit32                     tiStatus = tiError;

  TI_DBG1(("tiINIIntCoalesceInit: start\n"));

  tdsaSingleThreadedEnter(tiRoot, TD_INTCOAL_LOCK);
  if (TDLIST_NOT_EMPTY(&(tdsaIntCoalCxtHead->FreeLink)))
  {
    TDLIST_DEQUEUE_FROM_HEAD(&tdsaIntCoalCxtList, &(tdsaIntCoalCxtHead->FreeLink));
    tdsaSingleThreadedLeave(tiRoot, TD_INTCOAL_LOCK);
    tdsaIntCoalCxt
      = TDLIST_OBJECT_BASE(tdsaIntCoalesceContext_t, FreeLink, tdsaIntCoalCxtList);

    TI_DBG1(("tiINIIntCoalesceInit: id %d\n", tdsaIntCoalCxt->id));

    agRoot = &(tdsaAllShared->agRootNonInt);

    agIntCoalCxt = &(tdsaIntCoalCxt->agIntCoalCxt);
    tdsaIntCoalCxt->tiIntCoalesceCxt = tiIntCoalesceCxt;
    tiIntCoalesceCxt->tdData = tdsaIntCoalCxt;
    agIntCoalCxt->osData = tdsaIntCoalCxt;

    tdsaSingleThreadedEnter(tiRoot, TD_INTCOAL_LOCK);
    TDLIST_ENQUEUE_AT_TAIL(&(tdsaIntCoalCxt->MainLink), &(tdsaIntCoalCxtHead->MainLink));
    tdsaSingleThreadedLeave(tiRoot, TD_INTCOAL_LOCK);

    /*
      note: currently asynchronously call is assumed. In other words,
      "ossaIntCoalesceInitCB()" -> "ostiInitiatorCoalesceInitCB()" are used
    */
#ifdef LL_INT_COALESCE
    tiStatus = saIntCoalesceInit(agRoot, agIntCoalCxt, count);
#endif

    TI_DBG6(("tiINIIntCoalesceInit: status %d\n", tiStatus));
    return tiStatus;
  }
  else
  {
    tdsaSingleThreadedLeave(tiRoot, TD_INTCOAL_LOCK);
    TI_DBG1(("tiINIIntCoalesceInit: no more interrupt coalesce context; return fail\n"));
    return tiStatus;
  }
}
#endif /* TD_INT_COALESCE */

/*****************************************************************************
*! \brief itdssIOPrepareSGL
*
*  Purpose:  This function is called to translate TISA SGL information to the
*            LL layer SGL.
*
*  \param    tiRoot:         Pointer to initiator driver/port instance.
*  \param    IORequestBody:  TD layer request body for the I/O.
*  \param    tiSgl1:         First TISA SGL info.
*  \param    sglVirtualAddr: The virtual address of the first element in
*                            tiSgl1 when tiSgl1 is used with the type tiSglList.
*
*  \return:
*
*  tiSuccess:     SGL initialized successfully.
*  tiError:       Failed to initialize SGL.
*
*
*****************************************************************************/
osGLOBAL FORCEINLINE bit32
itdssIOPrepareSGL(
                  tiRoot_t                 *tiRoot,
                  tdIORequestBody_t        *tdIORequestBody,
                  tiSgl_t                  *tiSgl1,
                  void                     *sglVirtualAddr
                  )
{
  agsaSgl_t                 *agSgl;

  TI_DBG6(("itdssIOPrepareSGL: start\n"));

  agSgl = &(tdIORequestBody->transport.SAS.agSASRequestBody.sspInitiatorReq.agSgl);

  agSgl->len = 0;

  if (tiSgl1 == agNULL)
  {
    TI_DBG1(("itdssIOPrepareSGL: Error tiSgl1 is NULL\n"));
    return tiError;
  }

  if (tdIORequestBody->IOType.InitiatorRegIO.expDataLength == 0)
  {
    TI_DBG6(("itdssIOPrepareSGL: expDataLength is 0\n"));
    agSgl->sgUpper = 0;
    agSgl->sgLower = 0;
    agSgl->len = 0;
    CLEAR_ESGL_EXTEND(agSgl->extReserved);
    return tiSuccess;
  }

  agSgl->sgUpper = tiSgl1->upper;
  agSgl->sgLower = tiSgl1->lower;
  agSgl->len = tiSgl1->len;
  agSgl->extReserved = tiSgl1->type;

  return tiSuccess;
}

osGLOBAL bit32
tiNumOfLunIOCTLreq(
             tiRoot_t                       *tiRoot, 
             tiIORequest_t                  *tiIORequest,
             tiDeviceHandle_t               *tiDeviceHandle,
             void                           *tiRequestBody,
             tiIOCTLPayload_t               *agIOCTLPayload,
             void                           *agParam1,
             void                           *agParam2
             )
{
  tdsaRoot_t                        *tdsaRoot = (tdsaRoot_t *) tiRoot->tdData;
  tdsaContext_t                     *tdsaAllShared = (tdsaContext_t *)&tdsaRoot->tdsaAllShared;
  agsaRoot_t                        *agRoot = &(tdsaAllShared->agRootInt);
  void                                      *respBuffer = agNULL;
  void                                      *osMemHandle = agNULL;
  bit32                                     ostiMemoryStatus = 0;
  tdsaDeviceData_t                  *oneDeviceData = agNULL;
  agsaSSPInitiatorRequest_t *agSSPFrame = agNULL;
  bit32                                     status = IOCTL_CALL_SUCCESS;        
  bit32                                     agRequestType = 0;
  agsaDevHandle_t                   *agDevHandle = agNULL;
  agsaIORequest_t                   *agIORequest = agNULL;
  tdIORequestBody_t                 *tdIORequestBody = agNULL;
  agsaSASRequestBody_t      *agSASRequestBody = agNULL;

  do
  {
    if((tiIORequest == agNULL) || (tiRequestBody == agNULL))
    {
      status = IOCTL_CALL_FAIL;
      break;
    }
    tdIORequestBody = (tdIORequestBody_t *)tiRequestBody;
    tdIORequestBody->tiIORequest = tiIORequest;
    
    /* save context if we need to abort later */
    tiIORequest->tdData = tdIORequestBody; 
    
    agIORequest = &(tdIORequestBody->agIORequest);
    agIORequest->osData = (void *) tdIORequestBody;
    agSASRequestBody = &(tdIORequestBody->transport.SAS.agSASRequestBody);
    agSSPFrame = &(agSASRequestBody->sspInitiatorReq);
    
    ostiMemoryStatus = ostiAllocMemory( tiRoot,
                                                                          &osMemHandle,
                                                                          (void **)&respBuffer,
                                                                          &(agSSPFrame->agSgl.sgUpper),
                                                                          &(agSSPFrame->agSgl.sgLower),
                                                                          8,
                                                                          REPORT_LUN_LEN,
                                                                          agFALSE);
    if((ostiMemoryStatus != tiSuccess) && (respBuffer == agNULL  ))
    {
      status = IOCTL_CALL_FAIL;
      break;
    }
        
    osti_memset((void *)respBuffer, 0, REPORT_LUN_LEN);
    
        // use FW control place in shared structure to keep the neccesary information
    tdsaAllShared->tdFWControlEx.virtAddr = respBuffer;
    tdsaAllShared->tdFWControlEx.len = REPORT_LUN_LEN;
    tdsaAllShared->tdFWControlEx.param1 = agParam1;
    tdsaAllShared->tdFWControlEx.param2 = agParam2;
    tdsaAllShared->tdFWControlEx.payload = agIOCTLPayload;
    tdsaAllShared->tdFWControlEx.inProgress = 1;
    agRequestType = AGSA_SSP_INIT_READ;
    
    status = IOCTL_CALL_PENDING;
    oneDeviceData = (tdsaDeviceData_t *)(tiDeviceHandle->tdData);
    agDevHandle = oneDeviceData->agDevHandle;
    
    agSSPFrame->sspCmdIU.cdb[0] = REPORT_LUN_OPCODE;
    agSSPFrame->sspCmdIU.cdb[1] = 0x0;
    agSSPFrame->sspCmdIU.cdb[2] = 0x0; 
    agSSPFrame->sspCmdIU.cdb[3] = 0x0;
    agSSPFrame->sspCmdIU.cdb[4] = 0x0;
    agSSPFrame->sspCmdIU.cdb[5] = 0x0;
    agSSPFrame->sspCmdIU.cdb[6] = 0x0;
    agSSPFrame->sspCmdIU.cdb[7] = 0x0;
    agSSPFrame->sspCmdIU.cdb[8] = 0x0;
    agSSPFrame->sspCmdIU.cdb[9] = REPORT_LUN_LEN;
    agSSPFrame->sspCmdIU.cdb[10] = 0x0;
    agSSPFrame->sspCmdIU.cdb[11] = 0x0;
      
    agSSPFrame->dataLength = REPORT_LUN_LEN;
    agSSPFrame->agSgl.len =     sizeof(agsaSSPCmdInfoUnit_t);
    agSSPFrame->agSgl.extReserved = 0;
    CLEAR_ESGL_EXTEND(agSSPFrame->agSgl.extReserved);

    status = saSSPStart(agRoot, agIORequest, 0, agDevHandle, agRequestType,agSASRequestBody,agNULL,
                                                                                   &ossaSSPIoctlCompleted);
    if(status != AGSA_RC_SUCCESS)
        {
      ostiFreeMemory(tiRoot,
                                 tdsaAllShared->tdFWControlEx.virtAddr,
                                 tdsaAllShared->tdFWControlEx.len); 
      tdsaAllShared->tdFWControlEx.payload = NULL; 
      tdsaAllShared->tdFWControlEx.inProgress = 0;
      status = IOCTL_CALL_FAIL;
    }
  }while(0);
  return status;
}