/******************************************************************************* *Copyright (c) 2014 PMC-Sierra, Inc. All rights reserved. * *Redistribution and use in source and binary forms, with or without modification, are permitted provided *that the following conditions are met: *1. Redistributions of source code must retain the above copyright notice, this list of conditions and the *following disclaimer. *2. Redistributions in binary form must reproduce the above copyright notice, *this list of conditions and the following disclaimer in the documentation and/or other materials provided *with the distribution. * *THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED *WARRANTIES,INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE *FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT *NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR *BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE ********************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * This table is used to map LL Layer saSATAStart() status to TISA status. */ FORCEINLINE bit32 smsataLLIOStart( smRoot_t *smRoot, smIORequest_t *smIORequest, smDeviceHandle_t *smDeviceHandle, smScsiInitiatorRequest_t *smScsiRequest, smSatIOContext_t *satIOContext ) { smDeviceData_t *oneDeviceData = (smDeviceData_t *)smDeviceHandle->smData; smIntRoot_t *smIntRoot = (smIntRoot_t *) smRoot->smData; smIntContext_t *smAllShared = (smIntContext_t *)&(smIntRoot->smAllShared); smIORequestBody_t *smIORequestBody = (smIORequestBody_t *)satIOContext->smRequestBody; smDeviceData_t *pSatDevData = satIOContext->pSatDevData; smSatInternalIo_t *satIntIo = satIOContext->satIntIoContext; agsaRoot_t *agRoot = smAllShared->agRoot; agsaIORequest_t *agIORequest = &(smIORequestBody->agIORequest); agsaDevHandle_t *agDevHandle = oneDeviceData->agDevHandle; agsaSATAInitiatorRequest_t *agSATAReq = &(smIORequestBody->transport.SATA.agSATARequestBody); bit32 RLERecovery = agFALSE; bit32 status = SM_RC_FAILURE; bit32 nQNumber = 0; /* * If this is a super I/O request, check for optional settings. * Be careful. Use the superRequest pointer for all references * in this block of code. */ agSATAReq->option = 0; if (satIOContext->superIOFlag) { smSuperScsiInitiatorRequest_t *superRequest = (smSuperScsiInitiatorRequest_t *) smScsiRequest; if (superRequest->flags & SM_SCSI_INITIATOR_ENCRYPT) { /* Copy all of the relevant encrypt information */ agSATAReq->option |= AGSA_SATA_ENABLE_ENCRYPTION; sm_memcpy(&agSATAReq->encrypt, &superRequest->Encrypt, sizeof(agsaEncrypt_t)); } { /* initialize expDataLength */ if (satIOContext->reqType == AGSA_SATA_PROTOCOL_NON_DATA || satIOContext->reqType == AGSA_SATA_PROTOCOL_SRST_ASSERT || satIOContext->reqType == AGSA_SATA_PROTOCOL_SRST_DEASSERT ) { smIORequestBody->IOType.InitiatorRegIO.expDataLength = 0; } else { smIORequestBody->IOType.InitiatorRegIO.expDataLength = smScsiRequest->scsiCmnd.expDataLength; } agSATAReq->dataLength = smIORequestBody->IOType.InitiatorRegIO.expDataLength; } } else { /* initialize expDataLength */ if (satIOContext->reqType == AGSA_SATA_PROTOCOL_NON_DATA || satIOContext->reqType == AGSA_SATA_PROTOCOL_SRST_ASSERT || satIOContext->reqType == AGSA_SATA_PROTOCOL_SRST_DEASSERT ) { smIORequestBody->IOType.InitiatorRegIO.expDataLength = 0; } else { smIORequestBody->IOType.InitiatorRegIO.expDataLength = smScsiRequest->scsiCmnd.expDataLength; } agSATAReq->dataLength = smIORequestBody->IOType.InitiatorRegIO.expDataLength; } if ( (pSatDevData->satDriveState == SAT_DEV_STATE_IN_RECOVERY) && (satIOContext->pFis->h.command == SAT_READ_LOG_EXT) ) { RLERecovery = agTRUE; } /* check max io, be sure to free */ if ( (pSatDevData->satDriveState != SAT_DEV_STATE_IN_RECOVERY) || (RLERecovery == agTRUE) ) { if (RLERecovery == agFALSE) /* RLE is not checked against pending IO's */ { #ifdef CCFLAG_OPTIMIZE_SAT_LOCK bit32 volatile satPendingNCQIO = 0; bit32 volatile satPendingNONNCQIO = 0; bit32 volatile satPendingIO = 0; tdsmInterlockedExchange(smRoot, &satPendingNCQIO, pSatDevData->satPendingNCQIO); tdsmInterlockedExchange(smRoot, &satPendingNONNCQIO, pSatDevData->satPendingNONNCQIO); tdsmInterlockedExchange(smRoot, &satPendingIO, pSatDevData->satPendingIO); #endif if ( (satIOContext->reqType == AGSA_SATA_PROTOCOL_FPDMA_WRITE) || (satIOContext->reqType == AGSA_SATA_PROTOCOL_FPDMA_READ) ) { #ifdef CCFLAG_OPTIMIZE_SAT_LOCK if ( satPendingNCQIO >= pSatDevData->satNCQMaxIO || satPendingNONNCQIO != 0) { SM_DBG1(("smsataLLIOStart: 1st busy did %d!!!\n", pSatDevData->id)); SM_DBG1(("smsataLLIOStart: 1st busy NCQ. NCQ Pending 0x%x NONNCQ Pending 0x%x All Pending 0x%x!!!\n", satPendingNCQIO, satPendingNONNCQIO, satPendingIO)); /* free resource */ smsatFreeIntIoResource( smRoot, pSatDevData, satIntIo); return SM_RC_DEVICE_BUSY; } #else tdsmSingleThreadedEnter(smRoot, SM_EXTERNAL_IO_LOCK); if (pSatDevData->satPendingNCQIO >= pSatDevData->satNCQMaxIO || pSatDevData->satPendingNONNCQIO != 0) { SM_DBG1(("smsataLLIOStart: 1st busy did %d!!!\n", pSatDevData->id)); SM_DBG1(("smsataLLIOStart: 1st busy NCQ. NCQ Pending 0x%x NONNCQ Pending 0x%x All Pending 0x%x!!!\n", pSatDevData->satPendingNCQIO, pSatDevData->satPendingNONNCQIO, pSatDevData->satPendingIO)); tdsmSingleThreadedLeave(smRoot, SM_EXTERNAL_IO_LOCK); /* free resource */ smsatFreeIntIoResource( smRoot, pSatDevData, satIntIo); return SM_RC_DEVICE_BUSY; } tdsmSingleThreadedLeave(smRoot, SM_EXTERNAL_IO_LOCK); #endif } else if ( (satIOContext->reqType == AGSA_SATA_PROTOCOL_D2H_PKT) || (satIOContext->reqType == AGSA_SATA_PROTOCOL_H2D_PKT) || (satIOContext->reqType == AGSA_SATA_PROTOCOL_NON_PKT) ) { sm_memcpy(agSATAReq->scsiCDB, smScsiRequest->scsiCmnd.cdb, 16); #ifdef CCFLAG_OPTIMIZE_SAT_LOCK if ( satPendingNONNCQIO >= SAT_APAPI_CMDQ_MAX || satPendingNCQIO != 0) { SM_DBG1(("smsataLLIOStart: ATAPI busy did %d!!!\n", pSatDevData->id)); SM_DBG1(("smsataLLIOStart: ATAPI busy NON-NCQ. NCQ Pending 0x%x NON-NCQ Pending 0x%x All Pending 0x%x!!!\n", satPendingNCQIO, satPendingNONNCQIO, satPendingIO)); /* free resource */ smsatFreeIntIoResource( smRoot, pSatDevData, satIntIo); return SM_RC_DEVICE_BUSY; } #else tdsmSingleThreadedEnter(smRoot, SM_EXTERNAL_IO_LOCK); if ( pSatDevData->satPendingNONNCQIO >= SAT_APAPI_CMDQ_MAX || pSatDevData->satPendingNCQIO != 0) { SM_DBG1(("smsataLLIOStart: ATAPI busy did %d!!!\n", pSatDevData->id)); SM_DBG1(("smsataLLIOStart: ATAPI busy NON-NCQ. NCQ Pending 0x%x NON-NCQ Pending 0x%x All Pending 0x%x!!!\n", pSatDevData->satPendingNCQIO, pSatDevData->satPendingNONNCQIO, pSatDevData->satPendingIO)); tdsmSingleThreadedLeave(smRoot, SM_EXTERNAL_IO_LOCK); /* free resource */ smsatFreeIntIoResource( smRoot, pSatDevData, satIntIo); return SM_RC_DEVICE_BUSY; } tdsmSingleThreadedLeave(smRoot, SM_EXTERNAL_IO_LOCK); #endif } else { #ifdef CCFLAG_OPTIMIZE_SAT_LOCK if ( satPendingNONNCQIO >= SAT_NONNCQ_MAX || satPendingNCQIO != 0) { SM_DBG1(("smsataLLIOStart: 2nd busy did %d!!!\n", pSatDevData->id)); SM_DBG1(("smsataLLIOStart: 2nd busy NCQ. NCQ Pending 0x%x NONNCQ Pending 0x%x All Pending 0x%x!!!\n", satPendingNCQIO, satPendingNONNCQIO, satPendingIO)); /* free resource */ smsatFreeIntIoResource( smRoot, pSatDevData, satIntIo); return SM_RC_DEVICE_BUSY; } #else tdsmSingleThreadedEnter(smRoot, SM_EXTERNAL_IO_LOCK); if (pSatDevData->satPendingNONNCQIO >= SAT_NONNCQ_MAX || pSatDevData->satPendingNCQIO != 0) { SM_DBG1(("smsataLLIOStart: 2nd busy did %d!!!\n", pSatDevData->id)); SM_DBG1(("smsataLLIOStart: 2nd busy NCQ. NCQ Pending 0x%x NONNCQ Pending 0x%x All Pending 0x%x!!!\n", pSatDevData->satPendingNCQIO, pSatDevData->satPendingNONNCQIO, pSatDevData->satPendingIO)); tdsmSingleThreadedLeave(smRoot, SM_EXTERNAL_IO_LOCK); /* free resource */ smsatFreeIntIoResource( smRoot, pSatDevData, satIntIo); return SM_RC_DEVICE_BUSY; } tdsmSingleThreadedLeave(smRoot, SM_EXTERNAL_IO_LOCK); #endif } } /* RLE */ /* for internal SATA command only */ if (satIOContext->satOrgIOContext != agNULL) { /* Initialize tiIORequest */ smIORequestBody->smIORequest = smIORequest; if (smIORequest == agNULL) { SM_DBG1(("smsataLLIOStart: 1 check!!!\n")); } } /* Initialize tiDevhandle */ smIORequestBody->smDevHandle = smDeviceHandle; /* Initializes Scatter Gather and ESGL */ status = smsatIOPrepareSGL( smRoot, smIORequestBody, &smScsiRequest->smSgl1, smScsiRequest->sglVirtualAddr ); if (status != SM_RC_SUCCESS) { SM_DBG1(("smsataLLIOStart: can't get SGL!!!\n")); /* free resource */ smsatFreeIntIoResource( smRoot, pSatDevData, satIntIo); return status; } /* Initialize LL Layer agIORequest */ agIORequest->osData = (void *) smIORequestBody; agIORequest->sdkData = agNULL; /* SA takes care of this */ smIORequestBody->ioStarted = agTRUE; smIORequestBody->ioCompleted = agFALSE; /* assign tag value for SATA */ if ( (satIOContext->reqType == AGSA_SATA_PROTOCOL_FPDMA_WRITE) || (satIOContext->reqType == AGSA_SATA_PROTOCOL_FPDMA_READ) ) { if (agFALSE == smsatTagAlloc(smRoot, pSatDevData, &satIOContext->sataTag)) { SM_DBG1(("smsataLLIOStart: No more NCQ tag!!!\n")); smIORequestBody->ioStarted = agFALSE; smIORequestBody->ioCompleted = agTRUE; return SM_RC_DEVICE_BUSY; } SM_DBG3(("smsataLLIOStart: ncq tag 0x%x\n",satIOContext->sataTag)); } else { satIOContext->sataTag = 0xFF; } } else /* AGSA_SATA_PROTOCOL_SRST_ASSERT or AGSA_SATA_PROTOCOL_SRST_DEASSERT or SAT_CHECK_POWER_MODE as ABORT */ { agsaSgl_t *agSgl; /* for internal SATA command only */ if (satIOContext->satOrgIOContext != agNULL) { /* Initialize tiIORequest */ smIORequestBody->smIORequest = smIORequest; if (smIORequest == agNULL) { SM_DBG1(("smsataLLIOStart: 2 check!!!\n")); } } /* Initialize tiDevhandle */ smIORequestBody->smDevHandle = smDeviceHandle; smIORequestBody->IOType.InitiatorRegIO.expDataLength = 0; /* SGL for SATA request */ agSgl = &(smIORequestBody->transport.SATA.agSATARequestBody.agSgl); agSgl->len = 0; agSgl->sgUpper = 0; agSgl->sgLower = 0; agSgl->len = 0; SM_CLEAR_ESGL_EXTEND(agSgl->extReserved); /* Initialize LL Layer agIORequest */ agIORequest = &(smIORequestBody->agIORequest); agIORequest->osData = (void *) smIORequestBody; agIORequest->sdkData = agNULL; /* SA takes care of this */ smIORequestBody->ioStarted = agTRUE; smIORequestBody->ioCompleted = agFALSE; /* setting the data length */ agSATAReq->dataLength = 0; } smIORequestBody->reTries = 0; #ifdef TD_INTERNAL_DEBUG smhexdump("smsataLLIOStart", (bit8 *)satIOContext->pFis, sizeof(agsaFisRegHostToDevice_t)); smhexdump("smsataLLIOStart LL", (bit8 *)&agSATAReq->fis.fisRegHostToDev, sizeof(agsaFisRegHostToDevice_t)); #endif SM_DBG6(("smsataLLIOStart: agDevHandle %p\n", agDevHandle)); /* to get better IO performance, rotate the OBQ number on main IO path */ if (smScsiRequest == agNULL) { nQNumber = 0; } else { switch (smScsiRequest->scsiCmnd.cdb[0]) { case SCSIOPC_READ_10: case SCSIOPC_WRITE_10: case SCSIOPC_READ_6: case SCSIOPC_WRITE_6: case SCSIOPC_READ_12: case SCSIOPC_WRITE_12: case SCSIOPC_READ_16: case SCSIOPC_WRITE_16: nQNumber = tdsmRotateQnumber(smRoot, smDeviceHandle); break; default: nQNumber = 0; break; } } SM_DBG3(("sataLLIOStart: Lock in\n")); #ifdef CCFLAG_OPTIMIZE_SAT_LOCK if ( (satIOContext->reqType == AGSA_SATA_PROTOCOL_FPDMA_WRITE) || (satIOContext->reqType == AGSA_SATA_PROTOCOL_FPDMA_READ) ) { tdsmInterlockedIncrement(smRoot,&pSatDevData->satPendingNCQIO); } else { tdsmInterlockedIncrement(smRoot,&pSatDevData->satPendingNONNCQIO); } tdsmInterlockedIncrement(smRoot,&pSatDevData->satPendingIO); #else tdsmSingleThreadedEnter(smRoot, SM_EXTERNAL_IO_LOCK); if ( (satIOContext->reqType == AGSA_SATA_PROTOCOL_FPDMA_WRITE) || (satIOContext->reqType == AGSA_SATA_PROTOCOL_FPDMA_READ) ) { pSatDevData->satPendingNCQIO++; } else { pSatDevData->satPendingNONNCQIO++; } pSatDevData->satPendingIO++; SMLIST_INIT_ELEMENT (&satIOContext->satIoContextLink); SMLIST_ENQUEUE_AT_TAIL (&satIOContext->satIoContextLink, &pSatDevData->satIoLinkList); tdsmSingleThreadedLeave(smRoot, SM_EXTERNAL_IO_LOCK); #endif /* post SATA command to low level MPI */ status = saSATAStart( agRoot, agIORequest, nQNumber, agDevHandle, satIOContext->reqType, agSATAReq, satIOContext->sataTag, smllSATACompleted ); if (status != AGSA_RC_SUCCESS) { if (status == AGSA_RC_BUSY) { SM_DBG1(("smsataLLIOStart: saSATAStart busy!!!\n")); status = SM_RC_BUSY; } else { SM_DBG1(("smsataLLIOStart: saSATAStart failed!!!\n")); status = SM_RC_FAILURE; } if ( (satIOContext->reqType == AGSA_SATA_PROTOCOL_FPDMA_WRITE) || (satIOContext->reqType == AGSA_SATA_PROTOCOL_FPDMA_READ) ) { smsatTagRelease(smRoot, pSatDevData, satIOContext->sataTag); } #ifdef CCFLAG_OPTIMIZE_SAT_LOCK if ( (satIOContext->reqType == AGSA_SATA_PROTOCOL_FPDMA_WRITE) || (satIOContext->reqType == AGSA_SATA_PROTOCOL_FPDMA_READ) ) { tdsmInterlockedDecrement(smRoot,&oneDeviceData->satPendingNCQIO); } else { tdsmInterlockedDecrement(smRoot,&oneDeviceData->satPendingNONNCQIO); } tdsmInterlockedDecrement(smRoot,&oneDeviceData->satPendingIO); #else if ( (satIOContext->reqType == AGSA_SATA_PROTOCOL_FPDMA_WRITE) || (satIOContext->reqType == AGSA_SATA_PROTOCOL_FPDMA_READ) ) { tdsmSingleThreadedEnter(smRoot, SM_EXTERNAL_IO_LOCK); oneDeviceData->satPendingNCQIO--; oneDeviceData->satPendingIO--; SMLIST_DEQUEUE_THIS (&satIOContext->satIoContextLink); tdsmSingleThreadedLeave(smRoot, SM_EXTERNAL_IO_LOCK); } else { tdsmSingleThreadedEnter(smRoot, SM_EXTERNAL_IO_LOCK); oneDeviceData->satPendingNONNCQIO--; oneDeviceData->satPendingIO--; SMLIST_DEQUEUE_THIS (&satIOContext->satIoContextLink); tdsmSingleThreadedLeave(smRoot, SM_EXTERNAL_IO_LOCK); } #endif /* CCFLAG_OPTIMIZE_SAT_LOCK */ /* Free the ESGL pages associated with this I/O */ smIORequestBody->ioStarted = agFALSE; smIORequestBody->ioCompleted = agTRUE; return (status); } return SM_RC_SUCCESS; } osGLOBAL FORCEINLINE bit32 smsatIOPrepareSGL( smRoot_t *smRoot, smIORequestBody_t *smIORequestBody, smSgl_t *smSgl1, void *sglVirtualAddr ) { agsaSgl_t *agSgl; /* Uppper should be zero-out */ SM_DBG5(("smsatIOPrepareSGL: start\n")); SM_DBG5(("smsatIOPrepareSGL: smSgl1->upper %d smSgl1->lower %d smSgl1->len %d\n", smSgl1->upper, smSgl1->lower, smSgl1->len)); SM_DBG5(("smsatIOPrepareSGL: smSgl1->type %d\n", smSgl1->type)); /* SGL for SATA request */ agSgl = &(smIORequestBody->transport.SATA.agSATARequestBody.agSgl); agSgl->len = 0; if (smSgl1 == agNULL) { SM_DBG1(("smsatIOPrepareSGL: Error smSgl1 is NULL!!!\n")); return tiError; } if (smIORequestBody->IOType.InitiatorRegIO.expDataLength == 0) { SM_DBG3(("smsatIOPrepareSGL: expDataLength is 0\n")); agSgl->sgUpper = 0; agSgl->sgLower = 0; agSgl->len = 0; SM_CLEAR_ESGL_EXTEND(agSgl->extReserved); return SM_RC_SUCCESS; } agSgl->sgUpper = smSgl1->upper; agSgl->sgLower = smSgl1->lower; agSgl->len = smSgl1->len; agSgl->extReserved = smSgl1->type; return SM_RC_SUCCESS; }