2170 lines
79 KiB
C
2170 lines
79 KiB
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 sassp.c
|
|
* \brief The file implements the functions for SSP request/response
|
|
*
|
|
*/
|
|
/*******************************************************************************/
|
|
#include <sys/cdefs.h>
|
|
__FBSDID("$FreeBSD$");
|
|
#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 'O'
|
|
#endif
|
|
|
|
#ifdef LOOPBACK_MPI
|
|
extern int loopback;
|
|
#endif
|
|
|
|
#ifdef SALLSDK_DEBUG
|
|
LOCAL void siDumpSSPStartIu(
|
|
agsaDevHandle_t *agDevHandle,
|
|
bit32 agRequestType,
|
|
agsaSASRequestBody_t *agRequestBody
|
|
);
|
|
#endif
|
|
|
|
#ifdef FAST_IO_TEST
|
|
LOCAL bit32 saGetIBQPI(agsaRoot_t *agRoot,
|
|
bit32 queueNum)
|
|
{
|
|
bit8 inq;
|
|
mpiICQueue_t *circularQ;
|
|
agsaLLRoot_t *saRoot = (agsaLLRoot_t *)(agRoot->sdkData);
|
|
|
|
inq = INQ(queueNum);
|
|
circularQ = &saRoot->inboundQueue[inq];
|
|
return circularQ->producerIdx;
|
|
}
|
|
|
|
LOCAL void saSetIBQPI(agsaRoot_t *agRoot,
|
|
bit32 queueNum,
|
|
bit32 pi)
|
|
{
|
|
bit8 inq;
|
|
mpiICQueue_t *circularQ;
|
|
agsaLLRoot_t *saRoot = (agsaLLRoot_t *)(agRoot->sdkData);
|
|
|
|
inq = INQ(queueNum);
|
|
circularQ = &saRoot->inboundQueue[inq];
|
|
circularQ->producerIdx = pi;
|
|
}
|
|
|
|
osLOCAL void*
|
|
siFastSSPReqAlloc(agsaRoot_t *agRoot)
|
|
{
|
|
int idx;
|
|
agsaLLRoot_t *saRoot = (agsaLLRoot_t*)(agRoot->sdkData);
|
|
saFastRequest_t *fr;
|
|
|
|
if (!saRoot->freeFastIdx)
|
|
{
|
|
SA_DBG1(("saSuperSSPReqAlloc: no memory ERROR\n"));
|
|
SA_ASSERT((0), "");
|
|
return 0;
|
|
}
|
|
|
|
ossaSingleThreadedEnter(agRoot, LL_FAST_IO_LOCK);
|
|
saRoot->freeFastIdx--;
|
|
idx = saRoot->freeFastIdx;
|
|
ossaSingleThreadedLeave(agRoot, LL_FAST_IO_LOCK);
|
|
|
|
fr = saRoot->freeFastReq[idx];
|
|
SA_ASSERT((fr), "");
|
|
fr->valid = 1;
|
|
|
|
return fr;
|
|
}
|
|
|
|
LOCAL void
|
|
siFastSSPReqFree(
|
|
agsaRoot_t *agRoot,
|
|
void *freq)
|
|
{
|
|
agsaLLRoot_t *saRoot = (agsaLLRoot_t *)(agRoot->sdkData);
|
|
saFastRequest_t *fr = (saFastRequest_t*)freq;
|
|
|
|
SA_DBG2(("siFastSSPReqFree: enter\n"));
|
|
SA_ASSERT((fr->valid), "");
|
|
if (saRoot->freeFastIdx >= sizeof(saRoot->freeFastReq) /
|
|
sizeof(saRoot->freeFastReq[0]))
|
|
{
|
|
SA_DBG1(("siFastSSPReqFree: too many handles %d / %d ERROR\n",
|
|
saRoot->freeFastIdx, (int)(sizeof(saRoot->freeFastReq) /
|
|
sizeof(saRoot->freeFastReq[0]))));
|
|
SA_ASSERT((0), "");
|
|
return;
|
|
}
|
|
ossaSingleThreadedEnter(agRoot, LL_FAST_IO_LOCK);
|
|
/* not need if only one entry */
|
|
/* saRoot->freeFastReq[saRoot->freeFastIdx] = freq; */
|
|
saRoot->freeFastIdx++;
|
|
ossaSingleThreadedLeave(agRoot, LL_FAST_IO_LOCK);
|
|
|
|
fr->valid = 0;
|
|
SA_DBG6(("siFastSSPReqFree: leave\n"));
|
|
}
|
|
|
|
LOCAL bit32 siFastSSPResAlloc(
|
|
agsaRoot_t *agRoot,
|
|
bit32 queueNum,
|
|
bit32 agRequestType,
|
|
agsaDeviceDesc_t *pDevice,
|
|
agsaIORequestDesc_t **pRequest,
|
|
void **pPayload
|
|
)
|
|
{
|
|
agsaLLRoot_t *saRoot = (agsaLLRoot_t*)(agRoot->sdkData);
|
|
mpiICQueue_t *circularQ;
|
|
bit8 inq;
|
|
bit16 size = IOMB_SIZE64;
|
|
bit32 ret = AGSA_RC_SUCCESS, retVal;
|
|
|
|
smTraceFuncEnter(hpDBG_VERY_LOUD,"2D");
|
|
|
|
SA_DBG4(("Entering function siFastSSPResAlloc:\n"));
|
|
|
|
ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
|
|
*pRequest = (agsaIORequestDesc_t*)saLlistIOGetHead(&saRoot->freeIORequests);
|
|
|
|
/* If no LL IO request entry available */
|
|
if (agNULL == *pRequest )
|
|
{
|
|
ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
|
|
SA_DBG1(("siFastSSPResAlloc: No request from free list\n" ));
|
|
smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "2D");
|
|
ret = AGSA_RC_BUSY;
|
|
goto ext;
|
|
}
|
|
|
|
/* Get IO request from free IORequests */
|
|
/* Assign inbound and outbound Buffer */
|
|
inq = INQ(queueNum);
|
|
SA_ASSERT((AGSA_MAX_INBOUND_Q > inq), "The IBQ Number is out of range.");
|
|
|
|
/* SSP_INI_IO_START_EXT IOMB need at least 80 bytes to support 32 CDB */
|
|
if (agRequestType & AGSA_SSP_EXT_BIT)
|
|
{
|
|
size = IOMB_SIZE96;
|
|
}
|
|
/* If LL IO request entry avaliable */
|
|
/* Get a free inbound queue entry */
|
|
circularQ = &saRoot->inboundQueue[inq];
|
|
retVal = mpiMsgFreeGet(circularQ, size, pPayload);
|
|
|
|
/* if message size is too large return failure */
|
|
if (AGSA_RC_SUCCESS != retVal)
|
|
{
|
|
if (AGSA_RC_FAILURE == retVal)
|
|
{
|
|
SA_DBG1(("siFastSSPResAlloc: error when get free IOMB\n"));
|
|
smTraceFuncExit(hpDBG_VERY_LOUD, 'b', "2D");
|
|
}
|
|
|
|
/* return busy if inbound queue is full */
|
|
if (AGSA_RC_BUSY == retVal)
|
|
{
|
|
SA_DBG3(("siFastSSPResAlloc: no more IOMB\n"));
|
|
smTraceFuncExit(hpDBG_VERY_LOUD, 'c', "2D");
|
|
}
|
|
ret = retVal;
|
|
goto ext;
|
|
}
|
|
|
|
/* But add it to the pending queue during FastStart */
|
|
/* If free IOMB avaliable */
|
|
/* Remove the request from free list */
|
|
saLlistIORemove(&saRoot->freeIORequests, &(*pRequest)->linkNode);
|
|
|
|
/* Add the request to the pendingIORequests list of the device */
|
|
saLlistIOAdd(&pDevice->pendingIORequests, &(*pRequest)->linkNode);
|
|
|
|
ext:
|
|
ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
|
|
|
|
if (AGSA_RC_SUCCESS == ret)
|
|
{
|
|
/* save tag and IOrequest pointer to IOMap */
|
|
saRoot->IOMap[(*pRequest)->HTag].Tag = (*pRequest)->HTag;
|
|
saRoot->IOMap[(*pRequest)->HTag].IORequest = (void *)*pRequest;
|
|
}
|
|
|
|
return ret;
|
|
} /* siFastSSPResAlloc */
|
|
|
|
|
|
GLOBAL bit32 saFastSSPCancel(void *ioHandle)
|
|
{
|
|
agsaRoot_t *agRoot;
|
|
agsaLLRoot_t *saRoot;
|
|
saFastRequest_t *fr;
|
|
bit32 i;
|
|
agsaIORequestDesc_t *ior;
|
|
|
|
SA_ASSERT((ioHandle), "");
|
|
fr = (saFastRequest_t*)ioHandle;
|
|
SA_ASSERT((fr->valid), "");
|
|
agRoot = (agsaRoot_t*)fr->agRoot;
|
|
SA_ASSERT((agRoot), "");
|
|
saRoot = (agsaLLRoot_t*)(agRoot->sdkData);
|
|
SA_ASSERT((saRoot), "");
|
|
|
|
smTraceFuncEnter(hpDBG_VERY_LOUD,"2E");
|
|
|
|
/* rollback the previously set IBQ PI */
|
|
for (i = 0; i < fr->inqMax - 1; i++)
|
|
saSetIBQPI(agRoot, fr->inqList[i], fr->beforePI[fr->inqList[i]]);
|
|
|
|
/* free all the previous Fast IO Requests */
|
|
ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
|
|
/* at least one entry, no need to check for NULL saLlistIOGetHead() */
|
|
ior = (agsaIORequestDesc_t*)((char*)saLlistIOGetHead(&fr->requests) -
|
|
OSSA_OFFSET_OF(agsaIORequestDesc_t, fastLink));
|
|
do
|
|
{
|
|
agsaDeviceDesc_t *pDevice;
|
|
void *tmp;
|
|
|
|
pDevice = ior->pDevice;
|
|
saLlistIORemove(&pDevice->pendingIORequests, &ior->linkNode);
|
|
saLlistIOAdd(&saRoot->freeIORequests, &ior->linkNode);
|
|
|
|
tmp = (void*)saLlistGetNext(&fr->requests, &ior->fastLink);
|
|
if (!tmp)
|
|
{
|
|
break; /* end of list */
|
|
}
|
|
ior = (agsaIORequestDesc_t*)((char*)tmp -
|
|
OSSA_OFFSET_OF(agsaIORequestDesc_t, fastLink));
|
|
} while (1);
|
|
|
|
ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
|
|
|
|
/* free the IBQ PI tracking struct */
|
|
siFastSSPReqFree(agRoot, fr);
|
|
|
|
smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "2E");
|
|
return AGSA_RC_SUCCESS;
|
|
} /* saFastSSPCancel */
|
|
|
|
GLOBAL void *saFastSSPPrepare(
|
|
void *ioh,
|
|
agsaFastCommand_t *fc,
|
|
ossaSSPCompletedCB_t cb,
|
|
void *cbArg)
|
|
{
|
|
bit32 ret = AGSA_RC_SUCCESS;
|
|
agsaRoot_t *agRoot;
|
|
agsaLLRoot_t *saRoot;
|
|
mpiICQueue_t *circularQ;
|
|
agsaDeviceDesc_t *pDevice;
|
|
agsaSgl_t *pSgl;
|
|
bit32 Dir = 0;
|
|
bit8 inq, outq;
|
|
saFastRequest_t *fr;
|
|
void *pMessage;
|
|
agsaIORequestDesc_t *pRequest;
|
|
bit16 opCode;
|
|
bitptr offsetTag;
|
|
bitptr offsetDeviceId;
|
|
bitptr offsetDataLen;
|
|
bitptr offsetDir;
|
|
|
|
agRoot = (agsaRoot_t*)fc->agRoot;
|
|
smTraceFuncEnter(hpDBG_VERY_LOUD,"2G");
|
|
|
|
OSSA_INP_ENTER(agRoot);
|
|
|
|
saRoot = (agsaLLRoot_t*)(agRoot->sdkData);
|
|
/* sanity check */
|
|
SA_ASSERT((agNULL != saRoot), "");
|
|
|
|
SA_DBG4(("Entering function saFastSSPPrepare:\n"));
|
|
|
|
fr = (saFastRequest_t*)ioh;
|
|
if (!fr)
|
|
{
|
|
int i;
|
|
fr = siFastSSPReqAlloc(agRoot);
|
|
if (!fr)
|
|
{
|
|
SA_ASSERT((0), "");
|
|
goto ext;
|
|
}
|
|
|
|
saLlistIOInitialize(&fr->requests);
|
|
for (i = 0; i < AGSA_MAX_INBOUND_Q; i++)
|
|
fr->beforePI[i] = (bit32)-1;
|
|
|
|
fr->inqMax = 0;
|
|
fr->agRoot = agRoot;
|
|
ioh = fr;
|
|
}
|
|
|
|
/* Find the outgoing port for the device */
|
|
pDevice = (agsaDeviceDesc_t*)(((agsaDevHandle_t*)fc->devHandle)->sdkData);
|
|
|
|
ret = siFastSSPResAlloc(agRoot, fc->queueNum, fc->agRequestType,
|
|
pDevice, &pRequest, &pMessage);
|
|
if (ret != AGSA_RC_SUCCESS)
|
|
{
|
|
SA_ASSERT((0), "");
|
|
smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "2G");
|
|
goto ext;
|
|
}
|
|
|
|
/* Assign inbound and outbound Buffer */
|
|
inq = INQ(fc->queueNum);
|
|
outq = OUQ(fc->queueNum);
|
|
circularQ = &saRoot->inboundQueue[inq];
|
|
|
|
SA_DBG3(("saFastSSPPrepare: deviceId %d\n", pDevice->DeviceMapIndex));
|
|
|
|
/* set up pRequest */
|
|
pRequest->valid = agTRUE;
|
|
pRequest->pDevice = pDevice;
|
|
pRequest->requestType = fc->agRequestType;
|
|
|
|
pRequest->completionCB = cb;
|
|
pRequest->pIORequestContext = (agsaIORequest_t*)cbArg;
|
|
|
|
pSgl = fc->agSgl;
|
|
|
|
switch (fc->agRequestType)
|
|
{
|
|
/* case AGSA_SSP_INIT_NONDATA: */
|
|
case AGSA_SSP_INIT_READ:
|
|
case AGSA_SSP_INIT_WRITE:
|
|
case AGSA_SSP_INIT_READ_M:
|
|
case AGSA_SSP_INIT_WRITE_M:
|
|
{
|
|
agsaSSPIniIOStartCmd_t *pPayload = (agsaSSPIniIOStartCmd_t *)pMessage;
|
|
agsaSSPCmdInfoUnit_t *piu;
|
|
|
|
/* SSPIU less equal 28 bytes */
|
|
offsetTag = OSSA_OFFSET_OF(agsaSSPIniIOStartCmd_t, tag);
|
|
offsetDeviceId = OSSA_OFFSET_OF(agsaSSPIniIOStartCmd_t, deviceId);
|
|
offsetDataLen = OSSA_OFFSET_OF(agsaSSPIniIOStartCmd_t, dataLen);
|
|
offsetDir = OSSA_OFFSET_OF(agsaSSPIniIOStartCmd_t, dirMTlr);
|
|
|
|
piu = &pPayload->SSPInfoUnit;
|
|
|
|
si_memcpy(piu->lun, fc->lun, sizeof(piu->lun));
|
|
si_memcpy(piu->cdb, fc->cdb, sizeof(piu->cdb));
|
|
piu->efb_tp_taskAttribute = fc->taskAttribute;
|
|
piu->additionalCdbLen = fc->additionalCdbLen;
|
|
|
|
/* Mask DIR for Read/Write command */
|
|
Dir = fc->agRequestType & AGSA_DIR_MASK;
|
|
|
|
/* set TLR */
|
|
Dir |= fc->flag & TLR_MASK;
|
|
if (fc->agRequestType & AGSA_MSG)
|
|
{
|
|
/* set M bit */
|
|
Dir |= AGSA_MSG_BIT;
|
|
}
|
|
|
|
/* Setup SGL */
|
|
if (fc->dataLength)
|
|
{
|
|
SA_DBG5(("saFastSSPPrepare: agSgl %08x:%08x (%x/%x)\n",
|
|
pSgl->sgUpper, pSgl->sgLower, pSgl->len, pSgl->extReserved));
|
|
/*
|
|
pPayload->AddrLow0 = pSgl->sgLower;
|
|
pPayload->AddrHi0 = pSgl->sgUpper;
|
|
pPayload->Len0 = pSgl->len;
|
|
pPayload->E0 = pSgl->extReserved;
|
|
*/
|
|
si_memcpy(&pPayload->AddrLow0, pSgl, sizeof(*pSgl));
|
|
}
|
|
else
|
|
{
|
|
/* no data transfer */
|
|
si_memset(&pPayload->AddrLow0, 0, sizeof(*pSgl));
|
|
}
|
|
|
|
opCode = OPC_INB_SSPINIIOSTART;
|
|
break;
|
|
}
|
|
|
|
case AGSA_SSP_INIT_READ_EXT:
|
|
case AGSA_SSP_INIT_WRITE_EXT:
|
|
case AGSA_SSP_INIT_READ_EXT_M:
|
|
case AGSA_SSP_INIT_WRITE_EXT_M:
|
|
{
|
|
agsaSSPIniExtIOStartCmd_t *pPayload =
|
|
(agsaSSPIniExtIOStartCmd_t *)pMessage;
|
|
agsaSSPCmdInfoUnitExt_t *piu;
|
|
bit32 sspiul;
|
|
|
|
/* CDB > 16 bytes */
|
|
offsetTag = OSSA_OFFSET_OF(agsaSSPIniExtIOStartCmd_t, tag);
|
|
offsetDeviceId = OSSA_OFFSET_OF(agsaSSPIniExtIOStartCmd_t, deviceId);
|
|
offsetDataLen = OSSA_OFFSET_OF(agsaSSPIniExtIOStartCmd_t, dataLen);
|
|
offsetDir = OSSA_OFFSET_OF(agsaSSPIniExtIOStartCmd_t, SSPIuLendirMTlr);
|
|
|
|
/* dword (bit7-bit2) ==> bytes (bit7-bit0) */
|
|
/* setup standard CDB bytes + additional CDB bytes in length field */
|
|
sspiul = sizeof(agsaSSPCmdInfoUnit_t) + (fc->additionalCdbLen & 0xFC);
|
|
|
|
Dir = sspiul << 16;
|
|
piu = (agsaSSPCmdInfoUnitExt_t*)pPayload->SSPIu;
|
|
|
|
si_memcpy(piu->lun, fc->lun, sizeof(piu->lun));
|
|
si_memcpy(piu->cdb, fc->cdb, MIN(sizeof(piu->cdb),
|
|
16 + fc->additionalCdbLen));
|
|
piu->efb_tp_taskAttribute = fc->taskAttribute;
|
|
piu->additionalCdbLen = fc->additionalCdbLen;
|
|
|
|
/* Mask DIR for Read/Write command */
|
|
Dir |= fc->agRequestType & AGSA_DIR_MASK;
|
|
|
|
/* set TLR */
|
|
Dir |= fc->flag & TLR_MASK;
|
|
if (fc->agRequestType & AGSA_MSG)
|
|
{
|
|
/* set M bit */
|
|
Dir |= AGSA_MSG_BIT;
|
|
}
|
|
|
|
/* Setup SGL */
|
|
if (fc->dataLength)
|
|
{
|
|
SA_DBG5(("saSuperSSPSend: Ext mode, agSgl %08x:%08x (%x/%x)\n",
|
|
pSgl->sgUpper, pSgl->sgLower, pSgl->len, pSgl->extReserved));
|
|
|
|
si_memcpy((&(pPayload->SSPIu[0]) + sspiul), pSgl, sizeof(*pSgl));
|
|
}
|
|
else //?
|
|
{
|
|
/* no data transfer */
|
|
//pPayload->dataLen = 0;
|
|
si_memset((&(pPayload->SSPIu[0]) + sspiul), 0, sizeof(*pSgl));
|
|
}
|
|
SA_ASSERT((smIS_SPC(agRoot)), "smIS_SPC");
|
|
opCode = OPC_INB_SSPINIEXTIOSTART;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
SA_DBG1(("saSuperSSPSend: Unsupported Request IOMB\n"));
|
|
ret = AGSA_RC_FAILURE;
|
|
SA_ASSERT((0), "");
|
|
smTraceFuncExit(hpDBG_VERY_LOUD, 'b', "2G");
|
|
goto ext;
|
|
}
|
|
}
|
|
|
|
OSSA_WRITE_LE_32(agRoot, pMessage, offsetTag, pRequest->HTag);
|
|
OSSA_WRITE_LE_32(agRoot, pMessage, offsetDeviceId, pDevice->DeviceMapIndex);
|
|
OSSA_WRITE_LE_32(agRoot, pMessage, offsetDataLen, fc->dataLength);
|
|
OSSA_WRITE_LE_32(agRoot, pMessage, offsetDir, Dir);
|
|
|
|
if (fr->beforePI[inq] == -1)
|
|
{
|
|
/* save the new IBQ' PI */
|
|
fr->beforePI[inq] = saGetIBQPI(agRoot, inq);
|
|
fr->inqList[fr->inqMax++] = inq;
|
|
}
|
|
|
|
/* post the IOMB to SPC */
|
|
ret = mpiMsgPrepare(circularQ, (void *)pMessage, MPI_CATEGORY_SAS_SATA,
|
|
opCode, outq, 0);
|
|
if (AGSA_RC_SUCCESS != ret)
|
|
{
|
|
SA_ASSERT((0), "");
|
|
ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
|
|
/* Remove the request from pendingIORequests list */
|
|
saLlistIORemove(&pDevice->pendingIORequests, &pRequest->linkNode);
|
|
|
|
/* Add the request to the free list of the device */
|
|
saLlistIOAdd(&saRoot->freeIORequests, &pRequest->linkNode);
|
|
ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
|
|
|
|
SA_DBG1(("saFastSSPPrepare: error when post SSP IOMB\n"));
|
|
smTraceFuncExit(hpDBG_VERY_LOUD, 'c', "2G");
|
|
goto ext;
|
|
}
|
|
|
|
/* Add the request to the pendingFastIORequests list of the device */
|
|
saLlistIOAdd(&fr->requests, &pRequest->fastLink);
|
|
smTraceFuncExit(hpDBG_VERY_LOUD, 'd', "2G");
|
|
|
|
ext:
|
|
if (fr && ret != AGSA_RC_SUCCESS)
|
|
{
|
|
saFastSSPCancel(fr);
|
|
ioh = 0;
|
|
}
|
|
OSSA_INP_LEAVE(agRoot);
|
|
return ioh;
|
|
} /* saFastSSPPrepare */
|
|
|
|
GLOBAL bit32 saFastSSPSend(void *ioHandle)
|
|
{
|
|
bit8 inq;
|
|
agsaRoot_t *agRoot;
|
|
agsaLLRoot_t *saRoot;
|
|
saFastRequest_t *fr;
|
|
bit32 i;
|
|
|
|
SA_ASSERT((ioHandle), "");
|
|
fr = (saFastRequest_t*)ioHandle;
|
|
agRoot = (agsaRoot_t*)fr->agRoot;
|
|
SA_ASSERT((agRoot), "");
|
|
saRoot = (agsaLLRoot_t*)agRoot->sdkData;
|
|
SA_ASSERT((saRoot), "");
|
|
|
|
SA_DBG4(("Entering function saFastSSPSend:\n"));
|
|
|
|
for (i = 0; i < fr->inqMax; i++)
|
|
{
|
|
inq = INQ(fr->inqList[i]);
|
|
/* FW interrupt */
|
|
mpiIBQMsgSend(&saRoot->inboundQueue[inq]);
|
|
}
|
|
/* IORequests are freed in siIODone() */
|
|
|
|
siFastSSPReqFree(agRoot, fr);
|
|
return AGSA_RC_SUCCESS;
|
|
} /* saFastSSPSend */
|
|
#endif
|
|
|
|
/******************************************************************************/
|
|
/*! \brief Start SSP request
|
|
*
|
|
* Start SSP request
|
|
*
|
|
* \param agRoot handles for this instance of SAS/SATA LLL
|
|
* \param queueNum
|
|
* \param agIORequest
|
|
* \param agDevHandle
|
|
* \param agRequestType
|
|
* \param agRequestBody
|
|
* \param agTMRequest valid for task management
|
|
* \param agCB
|
|
*
|
|
* \return If request is started successfully
|
|
* - \e AGSA_RC_SUCCESS request is started successfully
|
|
* - \e AGSA_RC_BUSY request is not started successfully
|
|
*/
|
|
/******************************************************************************/
|
|
GLOBAL bit32 saSSPStart(
|
|
agsaRoot_t *agRoot,
|
|
agsaIORequest_t *agIORequest,
|
|
bit32 queueNum,
|
|
agsaDevHandle_t *agDevHandle,
|
|
bit32 agRequestType,
|
|
agsaSASRequestBody_t *agRequestBody,
|
|
agsaIORequest_t *agTMRequest,
|
|
ossaSSPCompletedCB_t agCB)
|
|
{
|
|
agsaLLRoot_t *saRoot = (agsaLLRoot_t *)(agRoot->sdkData);
|
|
#ifdef LOOPBACK_MPI
|
|
mpiOCQueue_t *circularOQ = agNULL;
|
|
#endif
|
|
mpiICQueue_t *circularQ = agNULL;
|
|
agsaDeviceDesc_t *pDevice = agNULL;
|
|
agsaPort_t *pPort = agNULL;
|
|
agsaIORequestDesc_t *pRequest = agNULL;
|
|
agsaSgl_t *pSgl = agNULL;
|
|
void *pMessage = agNULL;
|
|
bit32 ret = AGSA_RC_SUCCESS, retVal = 0;
|
|
bit32 DirDW4 = 0; /* no data and no AutoGR */
|
|
bit32 encryptFlags = 0;
|
|
bit16 size = 0;
|
|
bit16 opCode = 0;
|
|
bit8 inq = 0, outq = 0;
|
|
|
|
|
|
OSSA_INP_ENTER(agRoot);
|
|
smTraceFuncEnter(hpDBG_VERY_LOUD,"Sa");
|
|
|
|
/* sanity check */
|
|
SA_ASSERT((agNULL != agRoot), "");
|
|
SA_ASSERT((agNULL != agIORequest), "");
|
|
SA_ASSERT((agNULL != agDevHandle), "");
|
|
SA_ASSERT((agNULL != agRequestBody), "");
|
|
|
|
DBG_DUMP_SSPSTART_CMDIU(agDevHandle,agRequestType,agRequestBody);
|
|
|
|
/* Find the outgoing port for the device */
|
|
pDevice = (agsaDeviceDesc_t *) (agDevHandle->sdkData);
|
|
|
|
if(pDevice == agNULL )
|
|
{
|
|
SA_ASSERT((pDevice), "pDevice");
|
|
ret = AGSA_RC_FAILURE;
|
|
smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "Sa");
|
|
goto ext;
|
|
}
|
|
|
|
pPort = pDevice->pPort;
|
|
/* Assign inbound and outbound Buffer */
|
|
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_DBG3(("saSSPStart: inq %d outq %d deviceId 0x%x\n", inq,outq,pDevice->DeviceMapIndex));
|
|
|
|
/* Get request from free IORequests */
|
|
ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
|
|
pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeIORequests));
|
|
|
|
/* If no LL IO request entry available */
|
|
if ( agNULL == pRequest )
|
|
{
|
|
ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
|
|
SA_DBG1(("saSSPStart, No request from free list\n" ));
|
|
smTraceFuncExit(hpDBG_VERY_LOUD, 'b', "Sa");
|
|
ret = AGSA_RC_BUSY;
|
|
goto ext;
|
|
}
|
|
/* If LL IO request entry avaliable */
|
|
else
|
|
{
|
|
/* Remove the request from free list */
|
|
saLlistIORemove(&(saRoot->freeIORequests), &(pRequest->linkNode));
|
|
/* Add the request to the pendingIORequests list of the device */
|
|
saLlistIOAdd(&(pDevice->pendingIORequests), &(pRequest->linkNode));
|
|
|
|
ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
|
|
|
|
SA_ASSERT((!pRequest->valid), "The pRequest is in use");
|
|
|
|
SA_DBG3(("saSSPStart, request %p\n", pRequest ));
|
|
|
|
/* Decode the flag settings in the standard I/O requests to decide what size we need. */
|
|
/* All other requests will be fine with only 64 byte messages. */
|
|
switch ( agRequestType )
|
|
{
|
|
case AGSA_SSP_INIT_READ:
|
|
case AGSA_SSP_INIT_WRITE:
|
|
case AGSA_SSP_INIT_NONDATA:
|
|
case AGSA_SSP_INIT_READ_M:
|
|
case AGSA_SSP_INIT_WRITE_M:
|
|
{
|
|
agsaSSPInitiatorRequest_t *pIRequest = &(agRequestBody->sspInitiatorReq);
|
|
|
|
if ((pIRequest->flag & AGSA_SAS_ENABLE_ENCRYPTION) ||
|
|
#ifdef SAFLAG_USE_DIF_ENC_IOMB
|
|
(pIRequest->flag & AGSA_SAS_USE_DIF_ENC_OPSTART) ||
|
|
#endif /* SAFLAG_USE_DIF_ENC_IOMB */
|
|
(pIRequest->flag & AGSA_SAS_ENABLE_DIF) )
|
|
{
|
|
opCode = OPC_INB_SSP_DIF_ENC_OPSTART;
|
|
size = IOMB_SIZE128;
|
|
}
|
|
else
|
|
{
|
|
opCode = OPC_INB_SSPINIIOSTART;
|
|
size = IOMB_SIZE64;
|
|
}
|
|
break;
|
|
}
|
|
case AGSA_SSP_INIT_READ_EXT:
|
|
case AGSA_SSP_INIT_WRITE_EXT:
|
|
case AGSA_SSP_INIT_READ_EXT_M:
|
|
case AGSA_SSP_INIT_WRITE_EXT_M:
|
|
{
|
|
agsaSSPInitiatorRequestExt_t *pIRequest = &(agRequestBody->sspInitiatorReqExt);
|
|
|
|
if ((pIRequest->flag & AGSA_SAS_ENABLE_ENCRYPTION) ||
|
|
(pIRequest->flag & AGSA_SAS_ENABLE_DIF) ||
|
|
#ifdef SAFLAG_USE_DIF_ENC_IOMB
|
|
(pIRequest->flag & AGSA_SAS_USE_DIF_ENC_OPSTART) ||
|
|
#endif /* SAFLAG_USE_DIF_ENC_IOMB */
|
|
(pIRequest->flag & AGSA_SAS_ENABLE_SKIP_MASK))
|
|
{
|
|
opCode = OPC_INB_SSP_DIF_ENC_OPSTART;
|
|
size = IOMB_SIZE128;
|
|
}
|
|
else
|
|
{
|
|
SA_ASSERT((smIS_SPC(agRoot)), "smIS_SPC");
|
|
opCode = OPC_INB_SSPINIEXTIOSTART;
|
|
size = IOMB_SIZE96;
|
|
}
|
|
break;
|
|
}
|
|
case AGSA_SSP_INIT_READ_INDIRECT:
|
|
case AGSA_SSP_INIT_WRITE_INDIRECT:
|
|
case AGSA_SSP_INIT_READ_INDIRECT_M:
|
|
case AGSA_SSP_INIT_WRITE_INDIRECT_M:
|
|
{
|
|
SA_DBG3(("saSSPStart: agRequestType 0x%X INDIRECT\n", agRequestType));
|
|
opCode = OPC_INB_SSP_DIF_ENC_OPSTART;
|
|
size = IOMB_SIZE128;
|
|
break;
|
|
}
|
|
case (AGSA_SSP_REQTYPE | AGSA_SSP_TASK_MGNT):
|
|
case AGSA_SSP_TASK_MGNT_REQ_M:
|
|
case AGSA_SSP_TGT_READ_DATA:
|
|
case AGSA_SSP_TGT_READ_GOOD_RESP:
|
|
case AGSA_SSP_TGT_WRITE_DATA:
|
|
case AGSA_SSP_TGT_WRITE_GOOD_RESP:
|
|
case AGSA_SSP_TGT_CMD_OR_TASK_RSP:
|
|
|
|
SA_DBG3(("saSSPStart: agRequestType 0x%X (was default)\n", agRequestType));
|
|
opCode = OPC_INB_SSPINIIOSTART;
|
|
size = IOMB_SIZE64;
|
|
break;
|
|
default:
|
|
SA_DBG1(("saSSPStart: agRequestType UNKNOWN 0x%X\n", agRequestType));
|
|
/* OpCode is not used in this case, but Linux complains if it is not initialized. */
|
|
opCode = OPC_INB_SSPINIIOSTART;
|
|
size = IOMB_SIZE64;
|
|
break;
|
|
}
|
|
|
|
/* If free IOMB avaliable, set up pRequest*/
|
|
pRequest->valid = agTRUE;
|
|
pRequest->pIORequestContext = agIORequest;
|
|
pRequest->pDevice = pDevice;
|
|
pRequest->requestType = agRequestType;
|
|
pRequest->pPort = pPort;
|
|
pRequest->startTick = saRoot->timeTick;
|
|
pRequest->completionCB = agCB;
|
|
|
|
/* Set request to the sdkData of agIORequest */
|
|
agIORequest->sdkData = pRequest;
|
|
|
|
/* save tag and IOrequest pointer to IOMap */
|
|
saRoot->IOMap[pRequest->HTag].Tag = pRequest->HTag;
|
|
saRoot->IOMap[pRequest->HTag].IORequest = (void *)pRequest;
|
|
|
|
#ifdef SA_LL_IBQ_PROTECT
|
|
ossaSingleThreadedEnter(agRoot, LL_IOREQ_IBQ0_LOCK + inq);
|
|
#endif /* SA_LL_IBQ_PROTECT */
|
|
|
|
/* Get a free inbound queue entry */
|
|
#ifdef LOOPBACK_MPI
|
|
if (loopback)
|
|
{
|
|
SA_DBG2(("saSSPStart: did %d ioq %d / %d tag %d\n", pDevice->DeviceMapIndex, inq, outq, pRequest->HTag));
|
|
circularOQ = &saRoot->outboundQueue[outq];
|
|
retVal = mpiMsgFreeGetOQ(circularOQ, size, &pMessage);
|
|
}
|
|
else
|
|
#endif /* LOOPBACK_MPI */
|
|
{
|
|
circularQ = &saRoot->inboundQueue[inq];
|
|
retVal = mpiMsgFreeGet(circularQ, size, &pMessage);
|
|
}
|
|
|
|
/* if message size is too large return failure */
|
|
if (AGSA_RC_FAILURE == retVal)
|
|
{
|
|
#ifdef SA_LL_IBQ_PROTECT
|
|
ossaSingleThreadedLeave(agRoot, LL_IOREQ_IBQ0_LOCK + inq);
|
|
#endif /* SA_LL_IBQ_PROTECT */
|
|
/* if not sending return to free list rare */
|
|
ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
|
|
saLlistIORemove(&(pDevice->pendingIORequests), &(pRequest->linkNode));
|
|
pRequest->valid = agFALSE;
|
|
saLlistIOAdd(&(saRoot->freeIORequests), &(pRequest->linkNode));
|
|
ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
|
|
|
|
SA_DBG1(("saSSPStart, error when get free IOMB\n"));
|
|
smTraceFuncExit(hpDBG_VERY_LOUD, 'c', "Sa");
|
|
ret = AGSA_RC_FAILURE;
|
|
goto ext;
|
|
}
|
|
|
|
/* return busy if inbound queue is full */
|
|
if (AGSA_RC_BUSY == retVal)
|
|
{
|
|
#ifdef SA_LL_IBQ_PROTECT
|
|
ossaSingleThreadedLeave(agRoot, LL_IOREQ_IBQ0_LOCK + inq);
|
|
#endif /* SA_LL_IBQ_PROTECT */
|
|
/* if not sending return to free list rare */
|
|
ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
|
|
saLlistIORemove(&(pDevice->pendingIORequests), &(pRequest->linkNode));
|
|
pRequest->valid = agFALSE;
|
|
saLlistIOAdd(&(saRoot->freeIORequests), &(pRequest->linkNode));
|
|
ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
|
|
|
|
SA_DBG1(("saSSPStart, no more IOMB\n"));
|
|
smTraceFuncExit(hpDBG_VERY_LOUD, 'd', "Sa");
|
|
ret = AGSA_RC_BUSY;
|
|
goto ext;
|
|
}
|
|
SA_DBG3(("saSSPStart:agRequestType %X\n" ,agRequestType));
|
|
|
|
switch ( agRequestType )
|
|
{
|
|
case AGSA_SSP_INIT_READ:
|
|
case AGSA_SSP_INIT_WRITE:
|
|
case AGSA_SSP_INIT_NONDATA:
|
|
case AGSA_SSP_INIT_READ_EXT:
|
|
case AGSA_SSP_INIT_WRITE_EXT:
|
|
case AGSA_SSP_INIT_READ_M:
|
|
case AGSA_SSP_INIT_WRITE_M:
|
|
case AGSA_SSP_INIT_READ_EXT_M:
|
|
case AGSA_SSP_INIT_WRITE_EXT_M:
|
|
case AGSA_SSP_INIT_READ_INDIRECT:
|
|
case AGSA_SSP_INIT_WRITE_INDIRECT:
|
|
case AGSA_SSP_INIT_READ_INDIRECT_M:
|
|
case AGSA_SSP_INIT_WRITE_INDIRECT_M:
|
|
{
|
|
if (!(agRequestType & AGSA_SSP_EXT_BIT))
|
|
{
|
|
agsaSSPInitiatorRequest_t *pIRequest = &(agRequestBody->sspInitiatorReq);
|
|
agsaSSPIniIOStartCmd_t *pPayload = (agsaSSPIniIOStartCmd_t *)pMessage;
|
|
agsaSSPIniEncryptIOStartCmd_t *pEncryptPayload = (agsaSSPIniEncryptIOStartCmd_t *)pMessage;
|
|
|
|
/* Most fields for the SAS IOMB have the same offset regardless of the actual IOMB used. */
|
|
/* Be careful with the scatter/gather lists, encryption and DIF options. */
|
|
|
|
/* if( pIRequest->sspCmdIU.cdb[ 0] == 0x28 || pIRequest->sspCmdIU.cdb[0]== 0x2A)
|
|
{
|
|
pRequest->requestBlock = ((pIRequest->sspCmdIU.cdb[2] << 24 ) |
|
|
(pIRequest->sspCmdIU.cdb[3] << 16 ) |
|
|
(pIRequest->sspCmdIU.cdb[4] << 8 ) |
|
|
(pIRequest->sspCmdIU.cdb[5] ) );
|
|
}
|
|
*/
|
|
#ifdef LOOPBACK_MPI
|
|
if (loopback)
|
|
{
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPCompletionRsp_t, tag), pRequest->HTag);
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPCompletionRsp_t, status), OSSA_IO_SUCCESS);
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPCompletionRsp_t, param), 0);
|
|
//OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPCompletionRsp_t, SSPTag), 0);
|
|
}
|
|
else
|
|
#endif /* LOOPBACK_MPI */
|
|
{
|
|
/* SSPIU less equal 28 bytes */
|
|
/* Configure DWORD 1 */
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPIniIOStartCmd_t, tag), pRequest->HTag);
|
|
/* Configure DWORD 2 */
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPIniIOStartCmd_t, deviceId), pDevice->DeviceMapIndex);
|
|
/* Configure DWORD 3 */
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPIniIOStartCmd_t, dataLen), pIRequest->dataLength);
|
|
}
|
|
|
|
#ifdef SA_TESTBASE_EXTRA
|
|
/* TestBase - Set the host BST entry */
|
|
DirDW4 |= ((UINT32)pIRequest->bstIndex) << 16;
|
|
#endif /* SA_TESTBASE_EXTRA */
|
|
|
|
if (!(agRequestType & AGSA_SSP_INDIRECT_BIT))
|
|
{
|
|
/* Configure DWORD 5-12 */
|
|
si_memcpy(&pPayload->SSPInfoUnit, &pIRequest->sspCmdIU, sizeof(pPayload->SSPInfoUnit));
|
|
pPayload->dirMTlr = 0;
|
|
/* Mask DIR for Read/Write command */
|
|
/* Configure DWORD 4 bit 8-9 */
|
|
DirDW4 |= agRequestType & AGSA_DIR_MASK;
|
|
}
|
|
else /* AGSA_SSP_INDIRECT_BIT was set */
|
|
{
|
|
|
|
agsaSSPInitiatorRequestIndirect_t *pIndRequest = &(agRequestBody->sspInitiatorReqIndirect);
|
|
|
|
/* Configure DWORD 5 */
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPIniEncryptIOStartCmd_t,sspiu_0_3_indcdbalL ),pIndRequest->sspInitiatorReqAddrLower32);
|
|
/* Configure DWORD 6 */
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPIniEncryptIOStartCmd_t,sspiu_4_7_indcdbalH ),pIndRequest->sspInitiatorReqAddrUpper32 );
|
|
/* Configure DWORD 7 */
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPIniEncryptIOStartCmd_t,sspiu_8_11 ), 0);
|
|
/* Configure DWORD 8 */
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPIniEncryptIOStartCmd_t,sspiu_12_15 ), 0);
|
|
/* Configure DWORD 9 */
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPIniEncryptIOStartCmd_t,sspiu_16_19 ), 0);
|
|
/* Configure DWORD 10 */
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPIniEncryptIOStartCmd_t,sspiu_19_23), 0);
|
|
/* Configure DWORD 11 */
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPIniEncryptIOStartCmd_t,sspiu_24_27 ), 0);
|
|
/* Mask DIR for Read/Write command */
|
|
/* Configure DWORD 4 bit 8-9 */
|
|
DirDW4 |= agRequestType & AGSA_DIR_MASK;
|
|
/* Configure DWORD 4 bit 24-31 */
|
|
DirDW4 |= ((pIndRequest->sspInitiatorReqLen >> 2) & 0xFF) << SHIFT24;
|
|
/* Configure DWORD 4 bit 4 */
|
|
DirDW4 |= 1 << SHIFT3;
|
|
}
|
|
|
|
/* set TLR */
|
|
DirDW4 |= pIRequest->flag & TLR_MASK;
|
|
if (agRequestType & AGSA_MSG)
|
|
{
|
|
/* set M bit */
|
|
DirDW4 |= AGSA_MSG_BIT;
|
|
}
|
|
|
|
/* check for skipmask operation */
|
|
if (pIRequest->flag & AGSA_SAS_ENABLE_SKIP_MASK)
|
|
{
|
|
DirDW4 |= AGSA_SKIP_MASK_BIT;
|
|
/* agsaSSPInitiatorRequestIndirect_t skip mask in flag is offset 5 */
|
|
DirDW4 |= (pIRequest->flag & AGSA_SAS_SKIP_MASK_OFFSET) << SHIFT8;
|
|
}
|
|
|
|
|
|
/* Configure DWORDS 12-14 */
|
|
if( pIRequest->encrypt.enableEncryptionPerLA && pIRequest->dif.enableDIFPerLA)
|
|
{
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, /* DWORD 12 */
|
|
OSSA_OFFSET_OF(agsaSSPIniEncryptIOStartCmd_t,epl_descL ),
|
|
pIRequest->encrypt.EncryptionPerLAAddrLo );
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, /* DWORD 13 */
|
|
OSSA_OFFSET_OF(agsaSSPIniEncryptIOStartCmd_t,dpl_descL ),
|
|
pIRequest->dif.DIFPerLAAddrLo );
|
|
|
|
SA_ASSERT(pIRequest->encrypt.EncryptionPerLAAddrHi == pIRequest->dif.DIFPerLAAddrHi, "EPL DPL hi region must be equal");
|
|
|
|
if( pIRequest->encrypt.EncryptionPerLAAddrHi != pIRequest->dif.DIFPerLAAddrHi )
|
|
{
|
|
|
|
SA_DBG1(("saSSPStart: EPL DPL hi region must be equal AGSA_RC_FAILURE\n" ));
|
|
smTraceFuncExit(hpDBG_VERY_LOUD, 'e', "Sa");
|
|
ret = AGSA_RC_FAILURE;
|
|
goto ext;
|
|
}
|
|
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, /* DWORD 14 */
|
|
OSSA_OFFSET_OF(agsaSSPIniEncryptIOStartCmd_t,edpl_descH ),
|
|
pIRequest->encrypt.EncryptionPerLAAddrHi );
|
|
}
|
|
else if( pIRequest->encrypt.enableEncryptionPerLA)
|
|
{
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, /* DWORD 12 */
|
|
OSSA_OFFSET_OF(agsaSSPIniEncryptIOStartCmd_t,epl_descL ),
|
|
pIRequest->encrypt.EncryptionPerLAAddrLo );
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, /* DWORD 13 */
|
|
OSSA_OFFSET_OF(agsaSSPIniEncryptIOStartCmd_t,dpl_descL ),
|
|
0);
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, /* DWORD 14 */
|
|
OSSA_OFFSET_OF(agsaSSPIniEncryptIOStartCmd_t,edpl_descH ),
|
|
pIRequest->encrypt.EncryptionPerLAAddrHi );
|
|
}
|
|
else if (pIRequest->dif.enableDIFPerLA) /* configure DIF */
|
|
{
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, /* DWORD 12 */
|
|
OSSA_OFFSET_OF(agsaSSPIniEncryptIOStartCmd_t,epl_descL ),
|
|
0);
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, /* DWORD 13 */
|
|
OSSA_OFFSET_OF(agsaSSPIniEncryptIOStartCmd_t,dpl_descL ),
|
|
pIRequest->dif.DIFPerLAAddrLo );
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, /* DWORD 14 */
|
|
OSSA_OFFSET_OF(agsaSSPIniEncryptIOStartCmd_t,edpl_descH ),
|
|
pIRequest->dif.DIFPerLAAddrHi);
|
|
}
|
|
else /* Not EPL or DPL */
|
|
{
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, /* DWORD 12 */
|
|
OSSA_OFFSET_OF(agsaSSPIniEncryptIOStartCmd_t,epl_descL ),
|
|
0);
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, /* DWORD 13 */
|
|
OSSA_OFFSET_OF(agsaSSPIniEncryptIOStartCmd_t,dpl_descL ),
|
|
0);
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, /* DWORD 14 */
|
|
OSSA_OFFSET_OF(agsaSSPIniEncryptIOStartCmd_t,edpl_descH ),
|
|
0);
|
|
}
|
|
|
|
if (pIRequest->flag & AGSA_SAS_ENABLE_DIF)
|
|
{
|
|
bit32 UDTR1_UDTR0_UDT1_UDT0 = 0;
|
|
bit32 UDT5_UDT4_UDT3_UDT2 = 0;
|
|
bit32 UDTR5_UDTR4_UDTR3_UDTR2 = 0;
|
|
|
|
SA_DBG3(("saSSPStart,DIF enableRefBlockCount ref %d enableRefBlockCount %d enableCrc %d enableCrcInversion %d\n",
|
|
pIRequest->dif.flags & DIF_FLAG_BITS_UDTR_REF_BLKCOUNT ? 1 : 0,
|
|
pIRequest->dif.flags & DIF_FLAG_BITS_UDTR_REF_BLKCOUNT ? 1 : 0,
|
|
pIRequest->dif.flags & DIF_FLAG_BITS_CRC_VER ? 1 : 0,
|
|
pIRequest->dif.flags & DIF_FLAG_BITS_CRC_INV ? 1 : 0 ));
|
|
|
|
SA_DBG3(("saSSPStart,DIF initialIOSeed %X lbSize %X difAction %X\n",
|
|
pIRequest->dif.flags & DIF_FLAG_BITS_CRC_SEED ? 1 : 0,
|
|
(pIRequest->dif.flags & DIF_FLAG_BITS_BLOCKSIZE_MASK) >> DIF_FLAG_BITS_BLOCKSIZE_SHIFT,
|
|
pIRequest->dif.flags & DIF_FLAG_BITS_ACTION ));
|
|
|
|
SA_DBG3(("saSSPStart,DIF udtArray %2X %2X %2X %2X %2X %2X\n",
|
|
pIRequest->dif.udtArray[0],
|
|
pIRequest->dif.udtArray[1],
|
|
pIRequest->dif.udtArray[2],
|
|
pIRequest->dif.udtArray[3],
|
|
pIRequest->dif.udtArray[4],
|
|
pIRequest->dif.udtArray[5]));
|
|
|
|
SA_DBG3(("saSSPStart,DIF udrtArray %2X %2X %2X %2X %2X %2X\n",
|
|
pIRequest->dif.udrtArray[0],
|
|
pIRequest->dif.udrtArray[1],
|
|
pIRequest->dif.udrtArray[2],
|
|
pIRequest->dif.udrtArray[3],
|
|
pIRequest->dif.udrtArray[4],
|
|
pIRequest->dif.udrtArray[5]));
|
|
|
|
SA_DBG3(("saSSPStart,DIF tagUpdateMask %X tagVerifyMask %X DIFPerLAAddrLo %X DIFPerLAAddrHi %X\n",
|
|
(pIRequest->dif.flags & DIF_FLAG_BITS_UDTVMASK) >> DIF_FLAG_BITS_UDTV_SHIFT,
|
|
(pIRequest->dif.flags & DIF_FLAG_BITS_UDTUPMASK) >> DIF_FLAG_BITS_UDTUPSHIFT,
|
|
pIRequest->dif.DIFPerLAAddrLo,
|
|
pIRequest->dif.DIFPerLAAddrHi));
|
|
|
|
DirDW4 |= AGSA_DIF_BIT;
|
|
|
|
/* DWORD 15 */
|
|
SA_DBG3(("saSSPStart, DW 15 DIF_flags 0x%08X\n", pIRequest->dif.flags ));
|
|
|
|
OSSA_WRITE_LE_32(agRoot, pPayload,
|
|
OSSA_OFFSET_OF(agsaSSPIniEncryptIOStartCmd_t, DIF_flags),
|
|
pIRequest->dif.flags);
|
|
|
|
/* Populate the UDT and UDTR bytes as necessary. */
|
|
if ((pIRequest->dif.flags & DIF_FLAG_BITS_ACTION) != AGSA_DIF_INSERT)
|
|
{
|
|
UDTR1_UDTR0_UDT1_UDT0 = (pIRequest->dif.udtArray[1] << SHIFT8 |
|
|
pIRequest->dif.udtArray[0]);
|
|
UDT5_UDT4_UDT3_UDT2 = (pIRequest->dif.udtArray[5] << SHIFT24 |
|
|
pIRequest->dif.udtArray[4] << SHIFT16 |
|
|
pIRequest->dif.udtArray[3] << SHIFT8 |
|
|
pIRequest->dif.udtArray[2]);
|
|
}
|
|
|
|
if ((pIRequest->dif.flags & DIF_FLAG_BITS_ACTION) == AGSA_DIF_INSERT ||
|
|
(pIRequest->dif.flags & DIF_FLAG_BITS_ACTION) == AGSA_DIF_VERIFY_REPLACE ||
|
|
(pIRequest->dif.flags & DIF_FLAG_BITS_ACTION) == AGSA_DIF_REPLACE_UDT_REPLACE_CRC)
|
|
{
|
|
UDTR1_UDTR0_UDT1_UDT0 |= (pIRequest->dif.udrtArray[1] << SHIFT24 |
|
|
pIRequest->dif.udrtArray[0] << SHIFT16 );
|
|
UDTR5_UDTR4_UDTR3_UDTR2 = (pIRequest->dif.udrtArray[5] << SHIFT24 |
|
|
pIRequest->dif.udrtArray[4] << SHIFT16 |
|
|
pIRequest->dif.udrtArray[3] << SHIFT8 |
|
|
pIRequest->dif.udrtArray[2]);
|
|
}
|
|
|
|
/* DWORD 16 is UDT3, UDT2, UDT1 and UDT0 */
|
|
OSSA_WRITE_LE_32(agRoot, pPayload,
|
|
OSSA_OFFSET_OF(agsaSSPIniEncryptIOStartCmd_t, udt),
|
|
UDTR1_UDTR0_UDT1_UDT0);
|
|
|
|
/* DWORD 17 is UDT5, UDT4, UDT3 and UDT2 */
|
|
OSSA_WRITE_LE_32(agRoot, pPayload,
|
|
OSSA_OFFSET_OF(agsaSSPIniEncryptIOStartCmd_t, udtReplacementLo),
|
|
UDT5_UDT4_UDT3_UDT2);
|
|
|
|
/* DWORD 18 is UDTR5, UDTR4, UDTR3 and UDTR2 */
|
|
OSSA_WRITE_LE_32(agRoot, pPayload,
|
|
OSSA_OFFSET_OF(agsaSSPIniEncryptIOStartCmd_t, udtReplacementHi),
|
|
UDTR5_UDTR4_UDTR3_UDTR2);
|
|
|
|
/* DWORD 19 */
|
|
/* Get IOS IOSeed enable bit */
|
|
if( pIRequest->dif.enableDIFPerLA ||
|
|
(pIRequest->dif.flags & DIF_FLAG_BITS_CUST_APP_TAG) )
|
|
{
|
|
OSSA_WRITE_LE_32(agRoot, pPayload,
|
|
OSSA_OFFSET_OF(agsaSSPIniEncryptIOStartCmd_t, DIF_seed),
|
|
((pIRequest->dif.DIFPerLARegion0SecCount << SHIFT16) |
|
|
(pIRequest->dif.flags & DIF_FLAG_BITS_CRC_SEED ? pIRequest->dif.initialIOSeed : 0 )));
|
|
}
|
|
else
|
|
{
|
|
if (pIRequest->dif.flags & DIF_FLAG_BITS_CRC_SEED)
|
|
{
|
|
OSSA_WRITE_LE_32(agRoot, pPayload,
|
|
OSSA_OFFSET_OF(agsaSSPIniEncryptIOStartCmd_t, DIF_seed),
|
|
pIRequest->dif.initialIOSeed );
|
|
}
|
|
else
|
|
{
|
|
OSSA_WRITE_LE_32(agRoot, pPayload,
|
|
OSSA_OFFSET_OF(agsaSSPIniEncryptIOStartCmd_t, DIF_seed), 0 );
|
|
}
|
|
}
|
|
}
|
|
|
|
/* configure encryption */
|
|
if (pIRequest->flag & AGSA_SAS_ENABLE_ENCRYPTION)
|
|
{
|
|
|
|
SA_DBG3(("saSSPStart,ENC dekTable 0x%08X dekIndex 0x%08X\n",
|
|
pIRequest->encrypt.dekInfo.dekTable,
|
|
pIRequest->encrypt.dekInfo.dekIndex));
|
|
|
|
SA_DBG3(("saSSPStart,ENC kekIndex 0x%08X sectorSizeIndex 0x%08X cipherMode 0x%08X\n",
|
|
pIRequest->encrypt.kekIndex,
|
|
pIRequest->encrypt.sectorSizeIndex,
|
|
pIRequest->encrypt.cipherMode));
|
|
|
|
SA_DBG3(("saSSPStart,ENC keyTag_W0 0x%08X keyTag_W1 0x%08X\n",
|
|
pIRequest->encrypt.keyTag_W0,
|
|
pIRequest->encrypt.keyTag_W1));
|
|
SA_DBG3(("saSSPStart,ENC tweakVal_W0 0x%08X tweakVal_W1 0x%08X\n",
|
|
pIRequest->encrypt.tweakVal_W0,
|
|
pIRequest->encrypt.tweakVal_W1));
|
|
SA_DBG3(("saSSPStart,ENC tweakVal_W2 0x%08X tweakVal_W3 0x%08X\n",
|
|
pIRequest->encrypt.tweakVal_W2,
|
|
pIRequest->encrypt.tweakVal_W3));
|
|
|
|
DirDW4 |= AGSA_ENCRYPT_BIT;
|
|
|
|
encryptFlags = 0;
|
|
|
|
if (pIRequest->encrypt.keyTagCheck == agTRUE)
|
|
{
|
|
encryptFlags |= AGSA_ENCRYPT_KEY_TAG_BIT;
|
|
}
|
|
|
|
if( pIRequest->encrypt.cipherMode == agsaEncryptCipherModeXTS )
|
|
{
|
|
encryptFlags |= AGSA_ENCRYPT_XTS_Mode << SHIFT4;
|
|
}
|
|
|
|
encryptFlags |= pIRequest->encrypt.dekInfo.dekTable << SHIFT2;
|
|
|
|
/* Always use encryption for DIF fields, skip SKPD */
|
|
|
|
encryptFlags |= (pIRequest->encrypt.dekInfo.dekIndex & 0xFFFFFF) << SHIFT8;
|
|
/* Configure DWORD 20 */
|
|
OSSA_WRITE_LE_32(agRoot, pPayload,
|
|
OSSA_OFFSET_OF(agsaSSPIniEncryptIOStartCmd_t, encryptFlagsLo),
|
|
encryptFlags);
|
|
|
|
encryptFlags = pIRequest->encrypt.sectorSizeIndex;
|
|
|
|
encryptFlags |= (pIRequest->encrypt.kekIndex) << SHIFT5;
|
|
|
|
encryptFlags |= (pIRequest->encrypt.EncryptionPerLRegion0SecCount) << SHIFT16;
|
|
/* Configure DWORD 21 */
|
|
OSSA_WRITE_LE_32(agRoot, pPayload,
|
|
OSSA_OFFSET_OF(agsaSSPIniEncryptIOStartCmd_t, encryptFlagsHi),
|
|
encryptFlags);
|
|
|
|
/* Configure DWORD 22 */
|
|
OSSA_WRITE_LE_32(agRoot, pPayload,
|
|
OSSA_OFFSET_OF(agsaSSPIniEncryptIOStartCmd_t, keyTag_W0),
|
|
pIRequest->encrypt.keyTag_W0);
|
|
/* Configure DWORD 23 */
|
|
OSSA_WRITE_LE_32(agRoot, pPayload,
|
|
OSSA_OFFSET_OF(agsaSSPIniEncryptIOStartCmd_t, keyTag_W1),
|
|
pIRequest->encrypt.keyTag_W1);
|
|
|
|
/* Configure DWORD 24 */
|
|
OSSA_WRITE_LE_32(agRoot, pPayload,
|
|
OSSA_OFFSET_OF(agsaSSPIniEncryptIOStartCmd_t, tweakVal_W0),
|
|
pIRequest->encrypt.tweakVal_W0);
|
|
/* Configure DWORD 25 */
|
|
OSSA_WRITE_LE_32(agRoot, pPayload,
|
|
OSSA_OFFSET_OF(agsaSSPIniEncryptIOStartCmd_t, tweakVal_W1),
|
|
pIRequest->encrypt.tweakVal_W1);
|
|
/* Configure DWORD 26 */
|
|
OSSA_WRITE_LE_32(agRoot, pPayload,
|
|
OSSA_OFFSET_OF(agsaSSPIniEncryptIOStartCmd_t, tweakVal_W2),
|
|
pIRequest->encrypt.tweakVal_W2);
|
|
/* Configure DWORD 27 */
|
|
OSSA_WRITE_LE_32(agRoot, pPayload,
|
|
OSSA_OFFSET_OF(agsaSSPIniEncryptIOStartCmd_t, tweakVal_W3),
|
|
pIRequest->encrypt.tweakVal_W3);
|
|
}
|
|
|
|
/* Setup SGL */
|
|
if (pIRequest->dataLength)
|
|
{
|
|
pSgl = &(pIRequest->agSgl);
|
|
|
|
SA_DBG3(("saSSPStart:opCode %X agSgl %08x:%08x (%x/%x)\n",opCode,
|
|
pSgl->sgUpper, pSgl->sgLower, pSgl->len, pSgl->extReserved));
|
|
|
|
/* Get DIF PER LA flag */
|
|
DirDW4 |= (pIRequest->dif.enableDIFPerLA ? (1 << SHIFT7) : 0);
|
|
DirDW4 |= (pIRequest->encrypt.enableEncryptionPerLA ? ( 1 << SHIFT12 ) : 0);
|
|
/* Configure DWORD 4 */
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPIniIOStartCmd_t, dirMTlr), DirDW4);
|
|
|
|
if (opCode == OPC_INB_SSP_DIF_ENC_OPSTART)
|
|
{
|
|
/* Configure DWORD 28 */
|
|
pEncryptPayload->AddrLow0 = pSgl->sgLower;
|
|
/* Configure DWORD 29 */
|
|
pEncryptPayload->AddrHi0 = pSgl->sgUpper;
|
|
/* Configure DWORD 30 */
|
|
pEncryptPayload->Len0 = pSgl->len;
|
|
/* Configure DWORD 31 */
|
|
pEncryptPayload->E0 = pSgl->extReserved;
|
|
}
|
|
else
|
|
{
|
|
pPayload->AddrLow0 = pSgl->sgLower;
|
|
pPayload->AddrHi0 = pSgl->sgUpper;
|
|
pPayload->Len0 = pSgl->len;
|
|
pPayload->E0 = pSgl->extReserved;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* no data transfer */
|
|
/* Configure DWORD 4 */
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPIniIOStartCmd_t, dirMTlr), DirDW4);
|
|
|
|
if (opCode == OPC_INB_SSP_DIF_ENC_OPSTART)
|
|
{
|
|
pEncryptPayload = (agsaSSPIniEncryptIOStartCmd_t *) pPayload;
|
|
|
|
pEncryptPayload->AddrLow0 = 0;
|
|
pEncryptPayload->AddrHi0 = 0;
|
|
pEncryptPayload->Len0 = 0;
|
|
pEncryptPayload->E0 = 0;
|
|
}
|
|
else
|
|
{
|
|
pPayload->AddrLow0 = 0;
|
|
pPayload->AddrHi0 = 0;
|
|
pPayload->Len0 = 0;
|
|
pPayload->E0 = 0;
|
|
}
|
|
}
|
|
|
|
/* post the IOMB to SPC */
|
|
#ifdef LOOPBACK_MPI
|
|
if (loopback)
|
|
ret = mpiMsgProduceOQ(circularOQ, (void *)pMessage, MPI_CATEGORY_SAS_SATA, OPC_OUB_SSP_COMP, outq, (bit8)circularQ->priority);
|
|
else
|
|
#endif /* LOOPBACK_MPI */
|
|
ret = mpiMsgProduce(circularQ, (void *)pMessage, MPI_CATEGORY_SAS_SATA, opCode, outq, (bit8)circularQ->priority);
|
|
if (AGSA_RC_FAILURE == ret)
|
|
{
|
|
SA_DBG1(("saSSPStart, error when post SSP IOMB\n"));
|
|
ret = AGSA_RC_FAILURE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* additionalCdbLen is not zero and type is Ext - use EXT mode */
|
|
agsaSSPInitiatorRequestExt_t *pIRequest = &(agRequestBody->sspInitiatorReqExt);
|
|
agsaSSPIniExtIOStartCmd_t *pPayload = (agsaSSPIniExtIOStartCmd_t *)pMessage;
|
|
bit32 sspiul;
|
|
|
|
/*
|
|
* Most fields for the SAS IOMB have the same offset regardless of the actual IOMB used.
|
|
* Be careful with the scatter/gather lists, encryption and DIF options.
|
|
*/
|
|
/* CDB > 16 bytes */
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPIniExtIOStartCmd_t, tag), pRequest->HTag);
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPIniExtIOStartCmd_t, deviceId), pDevice->DeviceMapIndex);
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPIniExtIOStartCmd_t, dataLen), pIRequest->dataLength);
|
|
/* dword (bit7-bit2) ==> bytes (bit7-bit0) */
|
|
/* setup standard CDB bytes + additional CDB bytes in length field */
|
|
sspiul = sizeof(agsaSSPCmdInfoUnit_t) +
|
|
(pIRequest->sspCmdIUExt.additionalCdbLen & 0xFC);
|
|
DirDW4 = sspiul << 16;
|
|
si_memcpy(&pPayload->SSPIu[0], &pIRequest->sspCmdIUExt, sspiul);
|
|
pPayload->SSPIuLendirMTlr = 0;
|
|
|
|
/* Mask DIR for Read/Write command */
|
|
DirDW4 |= agRequestType & AGSA_DIR_MASK;
|
|
|
|
/* set TLR */
|
|
DirDW4 |= pIRequest->flag & TLR_MASK;
|
|
if (agRequestType & AGSA_MSG)
|
|
{
|
|
/* set M bit */
|
|
DirDW4 |= AGSA_MSG_BIT;
|
|
}
|
|
|
|
/* check for skipmask operation */
|
|
if (pIRequest->flag & AGSA_SAS_ENABLE_SKIP_MASK)
|
|
{
|
|
SA_ASSERT(0, "Mode not supported");
|
|
}
|
|
|
|
/* configure DIF */
|
|
if (pIRequest->flag & AGSA_SAS_ENABLE_DIF)
|
|
{
|
|
SA_ASSERT(0, "Mode not supported");
|
|
}
|
|
|
|
/* configure encryption */
|
|
if (pIRequest->flag & AGSA_SAS_ENABLE_ENCRYPTION)
|
|
{
|
|
SA_ASSERT(0, "Mode not supported");
|
|
}
|
|
/* Setup SGL */
|
|
if (pIRequest->dataLength)
|
|
{
|
|
pSgl = &(pIRequest->agSgl);
|
|
|
|
SA_DBG3(("saSSPStart: Ext mode, agSgl %08x:%08x (%x/%x)\n",
|
|
pSgl->sgUpper, pSgl->sgLower, pSgl->len, pSgl->extReserved));
|
|
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPIniExtIOStartCmd_t, SSPIuLendirMTlr), DirDW4);
|
|
|
|
if (opCode == OPC_INB_SSP_DIF_ENC_OPSTART)
|
|
{
|
|
si_memcpy((&((agsaSSPIniEncryptIOStartCmd_t *)(pPayload))->AddrLow0), pSgl, sizeof(agsaSgl_t));
|
|
}
|
|
else
|
|
{
|
|
si_memcpy((&(pPayload->SSPIu[0]) + sspiul), pSgl, sizeof(agsaSgl_t));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* no data transfer */
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPIniExtIOStartCmd_t, SSPIuLendirMTlr), DirDW4);
|
|
pPayload->dataLen = 0;
|
|
}
|
|
|
|
/* post the IOMB to SPC */
|
|
if (AGSA_RC_FAILURE == mpiMsgProduce(circularQ, (void *)pMessage, MPI_CATEGORY_SAS_SATA, opCode, outq,(bit8)circularQ->priority ))
|
|
{
|
|
SA_DBG1(("saSSPStart, error when post SSP Ext IOMB\n"));
|
|
ret = AGSA_RC_FAILURE;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case AGSA_SSP_TASK_MGNT_REQ:
|
|
case AGSA_SSP_TASK_MGNT_REQ_M:
|
|
{
|
|
agsaIORequestDesc_t *pTMRequestToAbort = agNULL;
|
|
agsaSSPIniTMStartCmd_t *pPayload = (agsaSSPIniTMStartCmd_t *)pMessage;
|
|
|
|
if (agRequestType & AGSA_MSG)
|
|
{
|
|
/* set M bit */
|
|
DirDW4 = AGSA_MSG_BIT;
|
|
}
|
|
|
|
/* set DS and ADS bit */
|
|
DirDW4 |= (agRequestBody->sspTaskMgntReq.tmOption & 0x3) << 3;
|
|
|
|
/* Prepare the SSP TASK Management payload */
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPIniTMStartCmd_t, tag), pRequest->HTag);
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPIniTMStartCmd_t, deviceId), pDevice->DeviceMapIndex);
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPIniTMStartCmd_t, relatedTag), agRequestBody->sspTaskMgntReq.tagOfTaskToBeManaged);
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPIniTMStartCmd_t, TMfunction), agRequestBody->sspTaskMgntReq.taskMgntFunction);
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPIniTMStartCmd_t, dsAdsMReport), DirDW4);
|
|
pPayload->lun[0] = agRequestBody->sspTaskMgntReq.lun[0];
|
|
pPayload->lun[1] = agRequestBody->sspTaskMgntReq.lun[1];
|
|
pPayload->lun[2] = agRequestBody->sspTaskMgntReq.lun[2];
|
|
pPayload->lun[3] = agRequestBody->sspTaskMgntReq.lun[3];
|
|
pPayload->lun[4] = agRequestBody->sspTaskMgntReq.lun[4];
|
|
pPayload->lun[5] = agRequestBody->sspTaskMgntReq.lun[5];
|
|
pPayload->lun[6] = agRequestBody->sspTaskMgntReq.lun[6];
|
|
pPayload->lun[7] = agRequestBody->sspTaskMgntReq.lun[7];
|
|
|
|
if (agTMRequest)
|
|
{
|
|
pTMRequestToAbort = (agsaIORequestDesc_t *)agTMRequest->sdkData;
|
|
if (pTMRequestToAbort)
|
|
{
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPIniTMStartCmd_t, relatedTag), pTMRequestToAbort->HTag);
|
|
}
|
|
}
|
|
|
|
SA_DBG1(("saSSPStart, HTAG 0x%x TM function 0x%x Tag-to-be-aborted 0x%x deviceId 0x%x\n",
|
|
pPayload->tag, pPayload->TMfunction, pPayload->relatedTag, pPayload->deviceId));
|
|
|
|
siDumpActiveIORequests(agRoot, saRoot->swConfig.maxActiveIOs);
|
|
|
|
/* post the IOMB to SPC */
|
|
if (AGSA_RC_FAILURE == mpiMsgProduce(circularQ, (void *)pMessage, MPI_CATEGORY_SAS_SATA, OPC_INB_SSPINITMSTART, outq, (bit8)circularQ->priority))
|
|
{
|
|
SA_DBG1(("saSSPStart, error when post TM IOMB\n"));
|
|
ret = AGSA_RC_FAILURE;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case AGSA_SSP_TGT_READ_DATA:
|
|
case AGSA_SSP_TGT_READ_GOOD_RESP:
|
|
case AGSA_SSP_TGT_WRITE_DATA:
|
|
case AGSA_SSP_TGT_WRITE_GOOD_RESP:
|
|
{
|
|
agsaSSPTargetRequest_t *pTRequest = &(agRequestBody->sspTargetReq);
|
|
agsaSSPTgtIOStartCmd_t *pPayload = (agsaSSPTgtIOStartCmd_t *)pMessage;
|
|
bit32 DirDW5 = 0;
|
|
/* Prepare the SSP TGT IO Start payload */
|
|
/* Configure DWORD 1 */
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPTgtIOStartCmd_t, tag), pRequest->HTag);
|
|
/* Configure DWORD 2 */
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPTgtIOStartCmd_t, deviceId), pDevice->DeviceMapIndex);
|
|
/* Configure DWORD 3 */
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPTgtIOStartCmd_t, dataLen), pTRequest->dataLength);
|
|
/* Configure DWORD 4 */
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPTgtIOStartCmd_t, dataOffset), pTRequest->offset);
|
|
|
|
SA_DBG3(("saSSPStart, sspOption %08X\n", pTRequest->sspOption ));
|
|
|
|
/* Mask DIR and AutoGR bits for Read/Write command */
|
|
DirDW5 = (agRequestType & (AGSA_DIR_MASK | AGSA_AUTO_MASK)) | (pTRequest->agTag << 16);
|
|
|
|
if (pTRequest->sspOption & SSP_OPTION_DIF )
|
|
{
|
|
bit32 UDTR1_UDTR0_UDT1_UDT0 = 0;
|
|
bit32 UDT5_UDT4_UDT3_UDT2 = 0;
|
|
bit32 UDTR5_UDTR4_UDTR3_UDTR2 = 0;
|
|
SA_DBG3(("saSSPStart,tgt DIF enableRefBlockCount ref %d enableRefBlockCount %d enableCrc %d enableCrcInversion %d\n",
|
|
pTRequest->dif.flags & DIF_FLAG_BITS_UDTR_REF_BLKCOUNT ? 1 : 0,
|
|
pTRequest->dif.flags & DIF_FLAG_BITS_UDTR_REF_BLKCOUNT ? 1 : 0,
|
|
pTRequest->dif.flags & DIF_FLAG_BITS_CRC_VER ? 1 : 0,
|
|
pTRequest->dif.flags & DIF_FLAG_BITS_CRC_INV ? 1 : 0 ));
|
|
|
|
SA_DBG3(("saSSPStart,tgt DIF initialIOSeed %X lbSize %X difAction %X\n",
|
|
pTRequest->dif.flags & DIF_FLAG_BITS_CRC_SEED ? 1 : 0,
|
|
(pTRequest->dif.flags & DIF_FLAG_BITS_BLOCKSIZE_MASK ) >> DIF_FLAG_BITS_BLOCKSIZE_SHIFT,
|
|
pTRequest->dif.flags & DIF_FLAG_BITS_ACTION ));
|
|
|
|
SA_DBG3(("saSSPStart,tgt DIF udtArray %2X %2X %2X %2X %2X %2X\n",
|
|
pTRequest->dif.udtArray[0],
|
|
pTRequest->dif.udtArray[1],
|
|
pTRequest->dif.udtArray[2],
|
|
pTRequest->dif.udtArray[3],
|
|
pTRequest->dif.udtArray[4],
|
|
pTRequest->dif.udtArray[5]));
|
|
|
|
SA_DBG3(("saSSPStart,tgt DIF udrtArray %2X %2X %2X %2X %2X %2X\n",
|
|
pTRequest->dif.udrtArray[0],
|
|
pTRequest->dif.udrtArray[1],
|
|
pTRequest->dif.udrtArray[2],
|
|
pTRequest->dif.udrtArray[3],
|
|
pTRequest->dif.udrtArray[4],
|
|
pTRequest->dif.udrtArray[5]));
|
|
|
|
SA_DBG3(("saSSPStart,tgt DIF tagUpdateMask %X tagVerifyMask %X DIFPerLAAddrLo %X DIFPerLAAddrHi %X\n",
|
|
(pTRequest->dif.flags & DIF_FLAG_BITS_UDTVMASK) >> DIF_FLAG_BITS_UDTV_SHIFT,
|
|
(pTRequest->dif.flags & DIF_FLAG_BITS_UDTUPMASK) >> DIF_FLAG_BITS_UDTUPSHIFT,
|
|
pTRequest->dif.DIFPerLAAddrLo,
|
|
pTRequest->dif.DIFPerLAAddrHi));
|
|
|
|
DirDW5 |= AGSA_SSP_TGT_BITS_DEE_DIF;
|
|
|
|
|
|
SA_DBG3(("saSSPStart,tgt DW 15 DIF_flags 0x%08X\n", pTRequest->dif.flags ));
|
|
|
|
OSSA_WRITE_LE_32(agRoot, pPayload,
|
|
OSSA_OFFSET_OF(agsaSSPTgtIOStartCmd_t, DIF_flags),
|
|
pTRequest->dif.flags);
|
|
|
|
/* Populate the UDT and UDTR bytes as necessary. */
|
|
if ((pTRequest->dif.flags & DIF_FLAG_BITS_ACTION) != AGSA_DIF_INSERT)
|
|
{
|
|
UDTR1_UDTR0_UDT1_UDT0 = (pTRequest->dif.udtArray[1] << SHIFT8 |
|
|
pTRequest->dif.udtArray[0]);
|
|
UDT5_UDT4_UDT3_UDT2 = (pTRequest->dif.udtArray[5] << SHIFT24 |
|
|
pTRequest->dif.udtArray[4] << SHIFT16 |
|
|
pTRequest->dif.udtArray[3] << SHIFT8 |
|
|
pTRequest->dif.udtArray[2]);
|
|
}
|
|
|
|
if ((pTRequest->dif.flags & DIF_FLAG_BITS_ACTION) == AGSA_DIF_INSERT ||
|
|
(pTRequest->dif.flags & DIF_FLAG_BITS_ACTION) == AGSA_DIF_VERIFY_REPLACE ||
|
|
(pTRequest->dif.flags & DIF_FLAG_BITS_ACTION) == AGSA_DIF_REPLACE_UDT_REPLACE_CRC)
|
|
{
|
|
UDTR1_UDTR0_UDT1_UDT0 |= (pTRequest->dif.udrtArray[1] << SHIFT24 |
|
|
pTRequest->dif.udrtArray[0] << SHIFT16 );
|
|
UDTR5_UDTR4_UDTR3_UDTR2 = (pTRequest->dif.udrtArray[5] << SHIFT24 |
|
|
pTRequest->dif.udrtArray[4] << SHIFT16 |
|
|
pTRequest->dif.udrtArray[3] << SHIFT8 |
|
|
pTRequest->dif.udrtArray[2]);
|
|
}
|
|
/* DWORD 8 is UDTR1, UDTR0, UDT1 and UDT0 */
|
|
OSSA_WRITE_LE_32(agRoot, pPayload,
|
|
OSSA_OFFSET_OF(agsaSSPTgtIOStartCmd_t, udt),
|
|
UDTR1_UDTR0_UDT1_UDT0);
|
|
|
|
/* DWORD 9 is UDT5, UDT4, UDT3 and UDT2 */
|
|
OSSA_WRITE_LE_32(agRoot, pPayload,
|
|
OSSA_OFFSET_OF(agsaSSPTgtIOStartCmd_t, udtReplacementLo),
|
|
UDT5_UDT4_UDT3_UDT2);
|
|
|
|
/* DWORD 10 is UDTR5, UDTR4, UDTR3 and UDTR2 */
|
|
OSSA_WRITE_LE_32(agRoot, pPayload,
|
|
OSSA_OFFSET_OF(agsaSSPTgtIOStartCmd_t, udtReplacementHi),
|
|
UDTR5_UDTR4_UDTR3_UDTR2);
|
|
/* DWORD 11 */
|
|
/* Get IOS IOSeed enable bit */
|
|
if( pTRequest->dif.flags & DIF_FLAG_BITS_CUST_APP_TAG)
|
|
{
|
|
OSSA_WRITE_LE_32(agRoot, pPayload,
|
|
OSSA_OFFSET_OF(agsaSSPTgtIOStartCmd_t, DIF_seed),
|
|
((pTRequest->dif.DIFPerLARegion0SecCount << SHIFT16) |
|
|
(pTRequest->dif.flags & DIF_FLAG_BITS_CRC_SEED ? pTRequest->dif.initialIOSeed : 0 )));
|
|
}
|
|
else
|
|
{
|
|
/* Get IOS IOSeed enable bit */
|
|
if (pTRequest->dif.flags & DIF_FLAG_BITS_CRC_SEED)
|
|
{
|
|
OSSA_WRITE_LE_32(agRoot, pPayload,
|
|
OSSA_OFFSET_OF(agsaSSPTgtIOStartCmd_t, DIF_seed),
|
|
pTRequest->dif.initialIOSeed );
|
|
}
|
|
else
|
|
{
|
|
OSSA_WRITE_LE_32(agRoot, pPayload,
|
|
OSSA_OFFSET_OF(agsaSSPTgtIOStartCmd_t, DIF_seed), 0 );
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Mask DIR and AutoGR bits for Read/Write command */
|
|
if(pTRequest->sspOption & SSP_OPTION_AUTO_GOOD_RESPONSE)
|
|
{
|
|
DirDW5 |= AGSA_SSP_TGT_BITS_AGR;
|
|
}
|
|
|
|
/* AN, RTE, RDF bits */
|
|
DirDW5 |= (pTRequest->sspOption & SSP_OPTION_BITS) << 2;
|
|
|
|
/* ODS */
|
|
if(pTRequest->sspOption & SSP_OPTION_ODS)
|
|
{
|
|
DirDW5 |= AGSA_SSP_TGT_BITS_ODS;
|
|
}
|
|
|
|
/* Setup SGL */
|
|
if (pTRequest->dataLength)
|
|
{
|
|
pSgl = &(pTRequest->agSgl);
|
|
|
|
SA_DBG5(("saSSPStart: agSgl %08x:%08x (%x/%x)\n",
|
|
pSgl->sgUpper, pSgl->sgLower, pSgl->len, pSgl->extReserved));
|
|
|
|
/* set up dir on the payload */
|
|
/* Configure DWORD 5 */
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPTgtIOStartCmd_t, INITagAgrDir), DirDW5);
|
|
|
|
pPayload->AddrLow0 = pSgl->sgLower;
|
|
pPayload->AddrHi0 = pSgl->sgUpper;
|
|
pPayload->Len0 = pSgl->len;
|
|
pPayload->E0 = pSgl->extReserved;
|
|
}
|
|
else
|
|
{
|
|
/* no data transfer */
|
|
/* Configure DWORD 5 */
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPTgtIOStartCmd_t, INITagAgrDir), DirDW5);
|
|
pPayload->AddrLow0 = 0;
|
|
pPayload->AddrHi0 = 0;
|
|
pPayload->Len0 = 0;
|
|
}
|
|
/* Configure DWORD 6 */
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPTgtIOStartCmd_t,reserved ), 0);
|
|
|
|
/* Build TGT IO START command and send it to SPC */
|
|
if (AGSA_RC_FAILURE == mpiMsgProduce(circularQ, (void *)pMessage, MPI_CATEGORY_SAS_SATA, OPC_INB_SSPTGTIOSTART, outq, (bit8)circularQ->priority))
|
|
{
|
|
SA_DBG1(("saSSPStart, error when post TGT IOMB\n"));
|
|
ret = AGSA_RC_FAILURE;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case AGSA_SSP_TGT_CMD_OR_TASK_RSP:
|
|
{
|
|
agsaSSPTargetResponse_t *pTResponse = &(agRequestBody->sspTargetResponse);
|
|
agsaSSPTgtRspStartCmd_t *pPayload = (agsaSSPTgtRspStartCmd_t *)pMessage;
|
|
bit32 ip, an, ods;
|
|
|
|
if (pTResponse->frameBuf && (pTResponse->respBufLength <= AGSA_MAX_SSPPAYLOAD_VIA_SFO))
|
|
{
|
|
ip = 1;
|
|
si_memcpy(pPayload->reserved, pTResponse->frameBuf, pTResponse->respBufLength);
|
|
}
|
|
else
|
|
{
|
|
ip = 0;
|
|
/* NOTE:
|
|
* 1. reserved field must be ZEROED out. FW depends on it
|
|
* 2. trusted interface. indirect response buffer must be valid.
|
|
*/
|
|
si_memset(pPayload->reserved, 0, sizeof(pPayload->reserved));
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPTgtRspStartCmd_t, AddrLow0), pTResponse->respBufLower);
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPTgtRspStartCmd_t, AddrHi0), pTResponse->respBufUpper);
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPTgtRspStartCmd_t, Len0), pTResponse->respBufLength);
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPTgtRspStartCmd_t, E0), 0);
|
|
}
|
|
|
|
/* TLR setting */
|
|
an = (pTResponse->respOption & RESP_OPTION_BITS);
|
|
/* ODS */
|
|
ods = (pTResponse->respOption & RESP_OPTION_ODS);
|
|
|
|
/* Prepare the SSP TGT RESPONSE Start payload */
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPTgtRspStartCmd_t, tag), pRequest->HTag);
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPTgtRspStartCmd_t, deviceId), pDevice->DeviceMapIndex);
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPTgtRspStartCmd_t, RspLen), pTResponse->respBufLength);
|
|
OSSA_WRITE_LE_32(agRoot, pPayload, OSSA_OFFSET_OF(agsaSSPTgtRspStartCmd_t, INITag_IP_AN),
|
|
(pTResponse->agTag << SHIFT16) | ods | (ip << SHIFT10) | (an << SHIFT2));
|
|
|
|
/* Build TGT RESPONSE START command and send it to SPC */
|
|
if (AGSA_RC_FAILURE == mpiMsgProduce(circularQ, (void *)pMessage, MPI_CATEGORY_SAS_SATA, OPC_INB_SSPTGTRSPSTART, outq, (bit8)circularQ->priority))
|
|
{
|
|
SA_DBG1(("saSSPStart, error when post TGT RSP IOMB\n"));
|
|
ret = AGSA_RC_FAILURE;
|
|
}
|
|
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
SA_DBG1(("saSSPStart, Unsupported Request IOMB\n"));
|
|
ret = AGSA_RC_FAILURE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
} /* LL IOrequest available */
|
|
|
|
#ifdef SA_LL_IBQ_PROTECT
|
|
ossaSingleThreadedLeave(agRoot, LL_IOREQ_IBQ0_LOCK + inq);
|
|
#endif /* SA_LL_IBQ_PROTECT */
|
|
|
|
#ifdef SALL_API_TEST
|
|
if (ret == AGSA_RC_SUCCESS)
|
|
saRoot->LLCounters.IOCounter.numSSPStarted++;
|
|
#endif /*SALL_API_TEST */
|
|
|
|
#ifdef LOOPBACK_MPI
|
|
if (loopback)
|
|
saRoot->interruptVecIndexBitMap[0] |= (1 << outq);
|
|
#endif /* LOOPBACK_MPI */
|
|
/* goto have leave and trace point info */
|
|
smTraceFuncExit(hpDBG_VERY_LOUD, 'f', "Sa");
|
|
ext:
|
|
|
|
OSSA_INP_LEAVE(agRoot);
|
|
return ret;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/*! \brief Abort SSP request
|
|
*
|
|
* Abort SSP request
|
|
*
|
|
* \param agRoot handles for this instance of SAS/SATA LLL
|
|
* \param queueNum
|
|
* \param agIORequest
|
|
* \param agIOToBeAborted
|
|
*
|
|
* \return If request is aborted successfully
|
|
* - \e AGSA_RC_SUCCESS request is aborted successfully
|
|
* - \e AGSA_RC_FAILURE request is not aborted successfully
|
|
*/
|
|
/*******************************************************************************/
|
|
GLOBAL bit32 saSSPAbort(
|
|
agsaRoot_t *agRoot,
|
|
agsaIORequest_t *agIORequest,
|
|
bit32 queueNum,
|
|
agsaDevHandle_t *agDevHandle,
|
|
bit32 flag,
|
|
void *abortParam,
|
|
ossaGenericAbortCB_t agCB
|
|
)
|
|
{
|
|
bit32 ret = AGSA_RC_SUCCESS, retVal;
|
|
agsaLLRoot_t *saRoot = (agsaLLRoot_t *)(agRoot->sdkData);
|
|
agsaIORequestDesc_t *pRequest;
|
|
agsaIORequestDesc_t *pRequestABT = NULL;
|
|
agsaDeviceDesc_t *pDevice = NULL;
|
|
agsaDeviceDesc_t *pDeviceABT = NULL;
|
|
agsaPort_t *pPort = NULL;
|
|
mpiICQueue_t *circularQ;
|
|
void *pMessage;
|
|
agsaSSPAbortCmd_t *payload;
|
|
agsaIORequest_t *agIOToBeAborted;
|
|
bit8 inq, outq;
|
|
bit32 using_reserved = agFALSE;
|
|
bit32 flag_copy = flag;
|
|
smTraceFuncEnter(hpDBG_VERY_LOUD,"Sb");
|
|
|
|
/* sanity check */
|
|
SA_ASSERT((agNULL != agRoot), "");
|
|
SA_ASSERT((agNULL != agIORequest), "");
|
|
|
|
SA_DBG2(("saSSPAbort: agIORequest %p agDevHandle %p abortParam %p flag 0x%x\n", agIORequest,agDevHandle,abortParam,flag));
|
|
|
|
/* Assign inbound and outbound Buffer */
|
|
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.");
|
|
|
|
#ifdef SA_PRINTOUT_IN_WINDBG
|
|
#ifndef DBG
|
|
DbgPrint("saSSPAbort flag %d\n", flag );
|
|
#endif /* DBG */
|
|
#endif /* SA_PRINTOUT_IN_WINDBG */
|
|
|
|
if( ABORT_SINGLE == (flag & ABORT_MASK) )
|
|
{
|
|
agIOToBeAborted = (agsaIORequest_t *)abortParam;
|
|
/* Get LL IORequest entry for saSSPAbort() */
|
|
pRequest = (agsaIORequestDesc_t *) (agIOToBeAborted->sdkData);
|
|
if (agNULL == pRequest)
|
|
{
|
|
/* no pRequest found - can not Abort */
|
|
SA_DBG1(("saSSPAbort: ABORT_ALL no pRequest\n"));
|
|
smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "Sb");
|
|
return AGSA_RC_FAILURE;
|
|
}
|
|
/* Find the device the request sent to */
|
|
pDevice = pRequest->pDevice;
|
|
/* Get LL IORequest entry for IOToBeAborted */
|
|
pRequestABT = (agsaIORequestDesc_t *) (agIOToBeAborted->sdkData);
|
|
if (agNULL == pRequestABT)
|
|
{
|
|
/* The IO to Be Abort is no longer exist */
|
|
SA_DBG1(("saSSPAbort: ABORT_ALL no pRequestABT\n"));
|
|
smTraceFuncExit(hpDBG_VERY_LOUD, 'b', "Sb");
|
|
return AGSA_RC_FAILURE;
|
|
}
|
|
/* Find the device the request Abort to */
|
|
pDeviceABT = pRequestABT->pDevice;
|
|
|
|
if (agNULL == pDeviceABT)
|
|
{
|
|
/* no deviceID - can not build IOMB */
|
|
SA_DBG1(("saSSPAbort: ABORT_ALL no pRequestABT->deviceID\n"));
|
|
smTraceFuncExit(hpDBG_VERY_LOUD, 'c', "Sb");
|
|
return AGSA_RC_FAILURE;
|
|
}
|
|
|
|
if (agNULL != pDevice)
|
|
{
|
|
/* Find the port the request was sent to */
|
|
pPort = pDevice->pPort;
|
|
}
|
|
else
|
|
{
|
|
/* no deviceID - can not build IOMB */
|
|
SA_DBG1(("saSSPAbort: ABORT_ALL no deviceID\n"));
|
|
smTraceFuncExit(hpDBG_VERY_LOUD, 'd', "Sb");
|
|
return AGSA_RC_FAILURE;
|
|
}
|
|
|
|
/* Get request from free IORequests */
|
|
ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
|
|
pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeIORequests)); /**/
|
|
}
|
|
else
|
|
{
|
|
if (ABORT_ALL == (flag & ABORT_MASK))
|
|
{
|
|
/* abort All with Device or Port */
|
|
/* Find the outgoing port for the device */
|
|
if (agDevHandle == agNULL)
|
|
{
|
|
/* no deviceID - can not build IOMB */
|
|
SA_DBG1(("saSSPAbort: agDevHandle == agNULL!!!\n"));
|
|
return AGSA_RC_FAILURE;
|
|
}
|
|
pDevice = (agsaDeviceDesc_t *) (agDevHandle->sdkData);
|
|
if (agNULL == pDevice)
|
|
{
|
|
/* no deviceID - can not build IOMB */
|
|
SA_DBG1(("saSSPAbort: ABORT_ALL agNULL == pDevice\n"));
|
|
return AGSA_RC_FAILURE;
|
|
}
|
|
pPort = pDevice->pPort;
|
|
ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
|
|
pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeIORequests)); /**/
|
|
}
|
|
else
|
|
{
|
|
/* only support 00, 01 and 02 for flag */
|
|
SA_DBG1(("saSSPAbort: ABORT_ALL type not supported 0x%X\n",flag));
|
|
smTraceFuncExit(hpDBG_VERY_LOUD, 'e', "Sb");
|
|
return AGSA_RC_FAILURE;
|
|
}
|
|
}
|
|
|
|
if ( agNULL == pRequest )
|
|
{
|
|
pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeReservedRequests));
|
|
if(agNULL != pRequest)
|
|
{
|
|
using_reserved = agTRUE;
|
|
SA_DBG2(("saSSPAbort: using saRoot->freeReservedRequests\n"));
|
|
}
|
|
else
|
|
{
|
|
ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
|
|
/* If no LL IO request entry available */
|
|
SA_DBG1(("saSSPAbort: No request from free list Not using saRoot->freeReservedRequests\n"));
|
|
smTraceFuncExit(hpDBG_VERY_LOUD, 'f', "Sb");
|
|
return AGSA_RC_BUSY;
|
|
}
|
|
}
|
|
|
|
/* If free IOMB avaliable */
|
|
/* Remove the request from free list */
|
|
if( using_reserved )
|
|
{
|
|
saLlistIORemove(&(saRoot->freeReservedRequests), &(pRequest->linkNode));
|
|
}
|
|
else
|
|
{
|
|
saLlistIORemove(&(saRoot->freeIORequests), &(pRequest->linkNode));
|
|
}
|
|
|
|
/* Add the request to the pendingIORequests list of the device */
|
|
pRequest->valid = agTRUE;
|
|
saLlistIOAdd(&(pDevice->pendingIORequests), &(pRequest->linkNode));
|
|
|
|
ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK);
|
|
|
|
/* set up pRequest */
|
|
pRequest->pIORequestContext = agIORequest;
|
|
pRequest->requestType = AGSA_SSP_REQTYPE;
|
|
pRequest->pDevice = pDevice;
|
|
pRequest->pPort = pPort;
|
|
pRequest->completionCB = (void*)agCB;
|
|
/* pRequest->abortCompletionCB = agCB;*/
|
|
pRequest->startTick = saRoot->timeTick;
|
|
|
|
/* Set request to the sdkData of agIORequest */
|
|
agIORequest->sdkData = pRequest;
|
|
|
|
/* save tag and IOrequest pointer to IOMap */
|
|
saRoot->IOMap[pRequest->HTag].Tag = pRequest->HTag;
|
|
saRoot->IOMap[pRequest->HTag].IORequest = (void *)pRequest;
|
|
|
|
|
|
#ifdef SA_LL_IBQ_PROTECT
|
|
ossaSingleThreadedEnter(agRoot, LL_IOREQ_IBQ0_LOCK + inq);
|
|
#endif /* SA_LL_IBQ_PROTECT */
|
|
|
|
/* If LL IO request entry avaliable */
|
|
/* Get a free inbound queue entry */
|
|
circularQ = &saRoot->inboundQueue[inq];
|
|
retVal = mpiMsgFreeGet(circularQ, IOMB_SIZE64, &pMessage);
|
|
|
|
/* if message size is too large return failure */
|
|
if (AGSA_RC_FAILURE == retVal)
|
|
{
|
|
#ifdef SA_LL_IBQ_PROTECT
|
|
ossaSingleThreadedLeave(agRoot, LL_IOREQ_IBQ0_LOCK + inq);
|
|
#endif /* SA_LL_IBQ_PROTECT */
|
|
|
|
ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
|
|
saLlistIORemove(&(pDevice->pendingIORequests), &(pRequest->linkNode));
|
|
pRequest->valid = agFALSE;
|
|
if(saLlistIOGetCount(&(saRoot->freeReservedRequests)) < SA_RESERVED_REQUEST_COUNT)
|
|
{
|
|
SA_DBG1(("saSSPAbort: 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(("saSSPAbort: error when get free IOMB\n"));
|
|
|
|
smTraceFuncExit(hpDBG_VERY_LOUD, 'g', "Sb");
|
|
return AGSA_RC_FAILURE;
|
|
}
|
|
|
|
/* return busy if inbound queue is full */
|
|
if (AGSA_RC_BUSY == retVal)
|
|
{
|
|
#ifdef SA_LL_IBQ_PROTECT
|
|
ossaSingleThreadedLeave(agRoot, LL_IOREQ_IBQ0_LOCK + inq);
|
|
#endif /* SA_LL_IBQ_PROTECT */
|
|
|
|
ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK);
|
|
saLlistIORemove(&(pDevice->pendingIORequests), &(pRequest->linkNode));
|
|
pRequest->valid = agFALSE;
|
|
if(saLlistIOGetCount(&(saRoot->freeReservedRequests)) < SA_RESERVED_REQUEST_COUNT)
|
|
{
|
|
SA_DBG1(("saSSPAbort: 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(("saSSPAbort: no more IOMB\n"));
|
|
smTraceFuncExit(hpDBG_VERY_LOUD, 'h', "Sb");
|
|
return AGSA_RC_BUSY;
|
|
}
|
|
|
|
/* setup payload */
|
|
payload = (agsaSSPAbortCmd_t*)pMessage;
|
|
OSSA_WRITE_LE_32(agRoot, payload, OSSA_OFFSET_OF(agsaSSPAbortCmd_t, tag), pRequest->HTag);
|
|
|
|
if( ABORT_SINGLE == (flag & ABORT_MASK) )
|
|
{
|
|
if ( agNULL == pDeviceABT )
|
|
{
|
|
SA_DBG1(("saSSPSAbort: no device\n" ));
|
|
smTraceFuncExit(hpDBG_VERY_LOUD, 'i', "Sb");
|
|
return AGSA_RC_FAILURE;
|
|
}
|
|
OSSA_WRITE_LE_32(agRoot, payload, OSSA_OFFSET_OF(agsaSSPAbortCmd_t, deviceId), pDeviceABT->DeviceMapIndex);
|
|
OSSA_WRITE_LE_32(agRoot, payload, OSSA_OFFSET_OF(agsaSSPAbortCmd_t, HTagAbort), pRequestABT->HTag);
|
|
}
|
|
else
|
|
{
|
|
/* abort all */
|
|
OSSA_WRITE_LE_32(agRoot, payload, OSSA_OFFSET_OF(agsaSSPAbortCmd_t, deviceId), pDevice->DeviceMapIndex);
|
|
OSSA_WRITE_LE_32(agRoot, payload, OSSA_OFFSET_OF(agsaSSPAbortCmd_t, HTagAbort), 0);
|
|
}
|
|
|
|
if(flag & ABORT_TSDK_QUARANTINE)
|
|
{
|
|
if(smIS_SPCV(agRoot))
|
|
{
|
|
flag_copy &= ABORT_SCOPE;
|
|
flag_copy |= ABORT_QUARANTINE_SPCV;
|
|
}
|
|
}
|
|
OSSA_WRITE_LE_32(agRoot, payload, OSSA_OFFSET_OF(agsaSSPAbortCmd_t, abortAll), flag_copy);
|
|
|
|
SA_DBG1(("saSSPAbort: HTag 0x%x HTagABT 0x%x deviceId 0x%x flag 0x%x\n", payload->tag, payload->HTagAbort, payload->deviceId,flag));
|
|
|
|
siCountActiveIORequestsOnDevice( agRoot, payload->deviceId );
|
|
|
|
/* post the IOMB to SPC */
|
|
ret = mpiMsgProduce(circularQ, (void *)pMessage, MPI_CATEGORY_SAS_SATA, OPC_INB_SSP_ABORT, outq, (bit8)circularQ->priority);
|
|
|
|
#ifdef SA_LL_IBQ_PROTECT
|
|
ossaSingleThreadedLeave(agRoot, LL_IOREQ_IBQ0_LOCK + inq);
|
|
#endif /* SA_LL_IBQ_PROTECT */
|
|
|
|
#ifdef SALL_API_TEST
|
|
if (AGSA_RC_SUCCESS == ret)
|
|
{
|
|
saRoot->LLCounters.IOCounter.numSSPAborted++;
|
|
}
|
|
#endif
|
|
|
|
smTraceFuncExit(hpDBG_VERY_LOUD, 'j', "Sb");
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
#if defined(SALLSDK_DEBUG)
|
|
/******************************************************************************/
|
|
/*! \brief
|
|
*
|
|
* Dump StartSSP information
|
|
*
|
|
* Debug helper routine
|
|
*
|
|
* \return -none -
|
|
*/
|
|
/*******************************************************************************/
|
|
LOCAL void siDumpSSPStartIu(
|
|
agsaDevHandle_t *agDevHandle,
|
|
bit32 agRequestType,
|
|
agsaSASRequestBody_t *agRequestBody
|
|
)
|
|
{
|
|
switch ( agRequestType )
|
|
{
|
|
case AGSA_SSP_INIT_READ:
|
|
case AGSA_SSP_INIT_WRITE:
|
|
{
|
|
agsaSSPInitiatorRequest_t *pIRequest = &(agRequestBody->sspInitiatorReq);
|
|
|
|
SA_DBG5(("siDumpSSPStartIu: dev=%p - %s - len=%x - attr=%x - CDB:%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
|
agDevHandle,
|
|
(agRequestType==AGSA_SSP_INIT_READ)? "AGSA_SSP_INIT_READ" : "AGSA_SSP_INIT_WRITE",
|
|
pIRequest->dataLength,
|
|
pIRequest->sspCmdIU.efb_tp_taskAttribute,
|
|
pIRequest->sspCmdIU.cdb[0],
|
|
pIRequest->sspCmdIU.cdb[1],
|
|
pIRequest->sspCmdIU.cdb[2],
|
|
pIRequest->sspCmdIU.cdb[3],
|
|
pIRequest->sspCmdIU.cdb[4],
|
|
pIRequest->sspCmdIU.cdb[5],
|
|
pIRequest->sspCmdIU.cdb[6],
|
|
pIRequest->sspCmdIU.cdb[7],
|
|
pIRequest->sspCmdIU.cdb[8],
|
|
pIRequest->sspCmdIU.cdb[9]
|
|
));
|
|
break;
|
|
}
|
|
|
|
case AGSA_SSP_INIT_READ_EXT:
|
|
case AGSA_SSP_INIT_WRITE_EXT:
|
|
{
|
|
agsaSSPInitiatorRequestExt_t *pIRequest = &(agRequestBody->sspInitiatorReqExt);
|
|
|
|
SA_DBG3(("siDumpSSPStartIu: dev=%p - %s - len=%x - attr=%x - CDB:%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
|
agDevHandle,
|
|
(agRequestType==AGSA_SSP_INIT_READ_EXT)? "AGSA_SSP_INIT_READ_EXT" : "AGSA_SSP_INIT_WRITE_EXT",
|
|
pIRequest->dataLength,
|
|
pIRequest->sspCmdIUExt.efb_tp_taskAttribute,
|
|
pIRequest->sspCmdIUExt.cdb[0],
|
|
pIRequest->sspCmdIUExt.cdb[1],
|
|
pIRequest->sspCmdIUExt.cdb[2],
|
|
pIRequest->sspCmdIUExt.cdb[3],
|
|
pIRequest->sspCmdIUExt.cdb[4],
|
|
pIRequest->sspCmdIUExt.cdb[5],
|
|
pIRequest->sspCmdIUExt.cdb[6],
|
|
pIRequest->sspCmdIUExt.cdb[7],
|
|
pIRequest->sspCmdIUExt.cdb[8],
|
|
pIRequest->sspCmdIUExt.cdb[9]
|
|
));
|
|
break;
|
|
}
|
|
|
|
case AGSA_SSP_INIT_READ_EXT_M:
|
|
case AGSA_SSP_INIT_WRITE_EXT_M:
|
|
{
|
|
agsaSSPInitiatorRequestExt_t *pIRequest = &(agRequestBody->sspInitiatorReqExt);
|
|
|
|
SA_DBG3(("siDumpSSPStartIu: dev=%p - %s - len=%x - attr=%x - CDB:%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
|
agDevHandle,
|
|
(agRequestType==AGSA_SSP_INIT_READ_EXT_M)? "AGSA_SSP_INIT_READ_EXT_M" : "AGSA_SSP_INIT_WRITE_EXT_M",
|
|
pIRequest->dataLength,
|
|
pIRequest->sspCmdIUExt.efb_tp_taskAttribute,
|
|
pIRequest->sspCmdIUExt.cdb[0],
|
|
pIRequest->sspCmdIUExt.cdb[1],
|
|
pIRequest->sspCmdIUExt.cdb[2],
|
|
pIRequest->sspCmdIUExt.cdb[3],
|
|
pIRequest->sspCmdIUExt.cdb[4],
|
|
pIRequest->sspCmdIUExt.cdb[5],
|
|
pIRequest->sspCmdIUExt.cdb[6],
|
|
pIRequest->sspCmdIUExt.cdb[7],
|
|
pIRequest->sspCmdIUExt.cdb[8],
|
|
pIRequest->sspCmdIUExt.cdb[9]
|
|
));
|
|
break;
|
|
}
|
|
|
|
case AGSA_SSP_INIT_READ_INDIRECT:
|
|
case AGSA_SSP_INIT_WRITE_INDIRECT:
|
|
case AGSA_SSP_INIT_READ_INDIRECT_M:
|
|
case AGSA_SSP_INIT_WRITE_INDIRECT_M:
|
|
{
|
|
agsaSSPInitiatorRequestIndirect_t *pIRequest = &(agRequestBody->sspInitiatorReqIndirect);
|
|
|
|
SA_DBG3(("siDumpSSPStartIu: dev=%p - %s - len=%x - cdblen=%d CDB:U %08x L %08x\n",
|
|
agDevHandle,
|
|
(agRequestType==AGSA_SSP_INIT_READ_INDIRECT ||
|
|
agRequestType==AGSA_SSP_INIT_READ_INDIRECT_M) ? "AGSA_SSP_INIT_READ_INDIRECT" : "AGSA_SSP_INIT_WRITE_INDIRECT",
|
|
pIRequest->dataLength,
|
|
pIRequest->sspInitiatorReqLen,
|
|
pIRequest->sspInitiatorReqAddrUpper32,
|
|
pIRequest->sspInitiatorReqAddrLower32 ));
|
|
break;
|
|
}
|
|
|
|
|
|
case AGSA_SSP_TASK_MGNT_REQ:
|
|
{
|
|
agsaSSPScsiTaskMgntReq_t *pTaskCmd =&agRequestBody->sspTaskMgntReq;
|
|
/* copy payload */
|
|
|
|
SA_DBG5(("siDumpSSPStartIu: dev=%p - %s - Task Function=%x - Tag to managed=%x",
|
|
agDevHandle,
|
|
"AGSA_SSP_TASK_MGNT_REQ",
|
|
pTaskCmd->taskMgntFunction,
|
|
pTaskCmd->tagOfTaskToBeManaged
|
|
));
|
|
break;
|
|
}
|
|
case AGSA_SSP_TGT_READ_DATA:
|
|
{
|
|
agsaSSPTargetRequest_t *pTRequest = &(agRequestBody->sspTargetReq);
|
|
|
|
SA_DBG5(("siDumpSSPStartIu: dev=%p - %s - dmaSize=%x dmaOffset=%x\n",
|
|
agDevHandle,
|
|
"AGSA_SSP_TGT_READ_DATA",
|
|
pTRequest->dataLength,
|
|
pTRequest->offset ));
|
|
break;
|
|
}
|
|
case AGSA_SSP_TGT_READ_GOOD_RESP:
|
|
{
|
|
agsaSSPTargetRequest_t *pTRequest = &(agRequestBody->sspTargetReq);
|
|
|
|
SA_DBG5(("siDumpSSPStartIu: dev=%p - %s - dmaSize=%x dmaOffset=%x\n",
|
|
agDevHandle,
|
|
"AGSA_SSP_TGT_READ_GOOD_RESP",
|
|
pTRequest->dataLength,
|
|
pTRequest->offset));
|
|
break;
|
|
}
|
|
case AGSA_SSP_TGT_WRITE_GOOD_RESP:
|
|
{
|
|
agsaSSPTargetRequest_t *pTRequest = &(agRequestBody->sspTargetReq);
|
|
SA_DBG5(("siDumpSSPStartIu: dev=%p - %s - dmaSize=%x dmaOffset=%x\n",
|
|
agDevHandle,
|
|
"AGSA_SSP_TGT_WRITE_GOOD_RESP",
|
|
pTRequest->dataLength,
|
|
pTRequest->offset ));
|
|
|
|
break;
|
|
}
|
|
case AGSA_SSP_TGT_WRITE_DATA:
|
|
{
|
|
agsaSSPTargetRequest_t *pTRequest = &(agRequestBody->sspTargetReq);
|
|
|
|
SA_DBG5(("siDumpSSPStartIu: dev=%p - %s - dmaSize=%x dmaOffset=%x\n",
|
|
agDevHandle,
|
|
"AGSA_SSP_TGT_WRITE_DATA",
|
|
pTRequest->dataLength,
|
|
pTRequest->offset ));
|
|
break;
|
|
}
|
|
case AGSA_SSP_TGT_CMD_OR_TASK_RSP:
|
|
{
|
|
agsaSSPTargetResponse_t *pTResponse = &(agRequestBody->sspTargetResponse);
|
|
|
|
SA_DBG5(("siDumpSSPStartIu: dev=%p - %s - len=%x PAddr=%08x:%08x Tag=%x\n",
|
|
agDevHandle,
|
|
"AGSA_SSP_TGT_CMD_OR_TASK_RSP",
|
|
pTResponse->respBufLength,
|
|
pTResponse->respBufUpper,
|
|
pTResponse->respBufLower,
|
|
pTResponse->agTag ));
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
SA_DBG1(("siDumpSSPStartIu: dev=%p - %s %X\n",
|
|
agDevHandle,
|
|
"Unknown SSP cmd type",
|
|
agRequestType
|
|
));
|
|
break;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
#endif /* SALLSDK_DEBUG */
|