/******************************************************************************* *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 * * $RCSfile: ttdio.c,v $ * * Copyright 2006 PMC-Sierra, Inc. * * * This file contains initiator IO related functions in TD layer * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef INITIATOR_DRIVER #include #include #include #endif #ifdef TARGET_DRIVER #include #include #include #endif #include #include /* Start For trace only */ #ifdef REMOVED unsigned __int64 GetHiResTimeStamp(void); #endif #undef TD_DEBUG_TRACE_ENABLE #define TD_DEBUG_IO_TRACE_BUFFER_MAX 1024 typedef struct TDDebugTraceEntry_s { bit64 Time; ttdsaXchg_t ttdsaXchg; tdsaDeviceData_t oneDeviceData; } TDDebugTraceEntry_t; typedef struct TDDebugTrace_s { bit32 Idx; bit32 pad; TDDebugTraceEntry_t Data[TD_DEBUG_IO_TRACE_BUFFER_MAX]; } TDDebugTrace_t; void TDTraceInit(void); void TDTraceAdd(ttdsaXchg_t *ttdsaXchg, tdsaDeviceData_t *oneDeviceData); #ifdef TD_DEBUG_TRACE_ENABLE #define TD_DEBUG_TRACE(ttdsaXchg, oneDeviceData) TDTraceAdd(ttdsaXchg, oneDeviceData) #else #define TD_DEBUG_TRACE(ttdsaXchg, oneDeviceData) #endif TDDebugTrace_t TraceData; void TDTraceInit(void) { osti_memset(&TraceData, 0, sizeof(TraceData)); } void TDTraceAdd(ttdsaXchg_t *ttdsaXchg, tdsaDeviceData_t *oneDeviceData) { static bit32 TraceIdx = 0; TraceData.Idx = TraceIdx; #ifdef REMOVED TraceData.Data[TraceIdx].Time = GetHiResTimeStamp(); #endif osti_memcpy((bit8 *)&(TraceData.Data[TraceIdx].ttdsaXchg), (bit8 *)ttdsaXchg, sizeof(ttdsaXchg_t)); osti_memcpy((bit8 *)&(TraceData.Data[TraceIdx].oneDeviceData), (bit8 *)oneDeviceData, sizeof(tdsaDeviceData_t)); #ifdef REMOVED TraceData.Data[TraceIdx].ttdsaXchg = ttdsaXchg; TraceData.Data[TraceIdx].oneDeviceData = oneDeviceData; #endif TraceIdx++; if (TraceIdx >= TD_DEBUG_IO_TRACE_BUFFER_MAX) { TraceIdx = 0; } return; } /* End For trace only */ osGLOBAL void ttdsaSSPReqReceived( agsaRoot_t *agRoot, agsaDevHandle_t *agDevHandle, agsaFrameHandle_t agFrameHandle, bit32 agInitiatorTag, bit32 parameter, bit32 agFrameLen ) { tdsaRootOsData_t *osData = (tdsaRootOsData_t *)agRoot->osData; tiRoot_t *tiRoot = (tiRoot_t *)osData->tiRoot; ttdsaXchg_t *ttdsaXchg; /* agsaSSPCmdInfoUnit_t cmdIU; */ tdsaDeviceData_t *oneDeviceData = agNULL; bit32 agFrameType, TLR; TD_XCHG_CONTEXT_NO_CMD_RCVD(tiRoot) = TD_XCHG_CONTEXT_NO_CMD_RCVD(tiRoot)+1; TI_DBG4(("ttdsaSSPReqReceived: start\n")); agFrameType = TD_GET_FRAME_TYPE(parameter); TLR = TD_GET_TLR(parameter); /*note: in ini, agDevHandle->osData = tdsaDeviceData_t is set in tdssAddDevicedataToSharedcontext() in tdsaDeviceDataInit() oneDeviceData->tiDeviceHandle.tdData has been initialized */ oneDeviceData = (tdsaDeviceData_t *)agDevHandle->osData; if (oneDeviceData == agNULL) { TI_DBG1(("ttdsaSSPReqReceived: no device data\n")); return; } ttdsaXchg = ttdsaXchgGetStruct(agRoot); if (ttdsaXchg == agNULL) { TI_DBG1(("ttdsaSSPReqReceived: no free xchg structures\n")); // ttdsaDumpallXchg(tiRoot); return; } if (ttdsaXchg->IORequestBody.tiIORequest == agNULL) { TI_DBG1(("ttdsaSSPReqReceived: tiIORequest is NULL\n")); // ttdsaDumpallXchg(tiRoot); return; } oneDeviceData->agDevHandle = agDevHandle; oneDeviceData->agRoot = agRoot; /* saving the device */ ttdsaXchg->DeviceData = oneDeviceData; ttdsaXchg->agRoot = agRoot; ttdsaXchg->tiRoot = tiRoot; ttdsaXchg->IORequestBody.agIORequest.sdkData = agNULL; /* initiator tag */ ttdsaXchg->tag = (bit16)agInitiatorTag; ttdsaXchg->IORequestBody.transport.SAS.agSASRequestBody.sspTargetReq.agTag = ttdsaXchg->tag; ttdsaXchg->IORequestBody.transport.SAS.agSASRequestBody.sspTargetResponse.agTag = ttdsaXchg->tag; TI_DBG6(("ttdsaSSPReqReceived: initiator tag 0x%x\n", agInitiatorTag)); if (agFrameType == OSSA_FRAME_TYPE_SSP_CMD) { TI_DBG4(("ttdsaSSPReqReceived: CMD frame type\n")); /* reads agsaSSPResponseInfoUnit_t */ saFrameReadBlock( agRoot, agFrameHandle, 0, &ttdsaXchg->agSSPCmndIU, agFrameLen ); tdsaProcessCDB(&ttdsaXchg->agSSPCmndIU, ttdsaXchg); ttdsaXchg->FrameType = SAS_CMND; /* ** As the last thing we call the disk module to handle the SCSI CDB. ** The disk module will call tiTGTIOStart to start a data phase. */ /* typedef struct { bit8 *reqCDB; bit8 *scsiLun, bit32 taskAttribute; bi32 taskId; bit32 crn; } tiTargetScsiCmnd_t; */ /* what about reqCDB and scsiLun */ /* coverting task attributes from SAS TISA */ switch (SA_SSPCMD_GET_TASKATTRIB(&ttdsaXchg->agSSPCmndIU)) { case 0: ttdsaXchg->tiTgtScsiCmnd.taskAttribute = TASK_SIMPLE; break; case 1: ttdsaXchg->tiTgtScsiCmnd.taskAttribute = TASK_HEAD_OF_QUEUE; break; case 2: ttdsaXchg->tiTgtScsiCmnd.taskAttribute = TASK_ORDERED; break; case 3: TI_DBG1(("ttdsaSSPReqReceived: reserved taskAttribute 0x%x\n",ttdsaXchg->agSSPCmndIU.efb_tp_taskAttribute)); ttdsaXchg->tiTgtScsiCmnd.taskAttribute = TASK_SIMPLE; break; case 4: ttdsaXchg->tiTgtScsiCmnd.taskAttribute = TASK_ACA; break; default: TI_DBG1(("ttdsaSSPReqReceived: unknown taskAttribute 0x%x\n",ttdsaXchg->agSSPCmndIU.efb_tp_taskAttribute)); ttdsaXchg->agSSPCmndIU.efb_tp_taskAttribute = TASK_SIMPLE; break; } ttdsaXchg->tiTgtScsiCmnd.taskId = agInitiatorTag; ttdsaXchg->tiTgtScsiCmnd.crn = 0; ttdsaXchg->TLR = TLR; /* call ostiProcessScsiReq */ ostiProcessScsiReq( tiRoot, &ttdsaXchg->tiTgtScsiCmnd, agFrameHandle, 0, ttdsaXchg->IORequestBody.tiIORequest, &ttdsaXchg->DeviceData->tiDeviceHandle); } else if (agFrameType == OSSA_FRAME_TYPE_SSP_TASK) { TI_DBG4(("ttdsaSSPReqReceived: TM frame type\n")); /* reads aagsaSSPScsiTaskMgntReq_t including lun */ saFrameReadBlock( agRoot, agFrameHandle, 0, &ttdsaXchg->agTMIU, agFrameLen ); ttdsaXchg->FrameType = SAS_TM; /* call task process mangement fn */ ttdsaTMProcess(tiRoot, ttdsaXchg); return; } else { TI_DBG1(("ttdsaSSPReqReceived: unknown frame type\n")); return; } return; } void dumpCDB(bit8 *cdb) { bit32 i; for(i=0;i<10;i++) { TI_DBG4(("cdb[%d] 0x%x\n", i, cdb[i])); } return; } osGLOBAL void tdsaProcessCDB( agsaSSPCmdInfoUnit_t *cmdIU, ttdsaXchg_t *ttdsaXchg ) { tdsaRoot_t *tdsaRoot = (tdsaRoot_t *) ttdsaXchg->tiRoot->tdData; tdsaContext_t *tdsaAllShared = (tdsaContext_t *) &tdsaRoot->tdsaAllShared; ttdsaTgt_t *Target = (ttdsaTgt_t *) tdsaAllShared->ttdsaTgt; bit8 group; #ifdef TD_DEBUG_ENABLE CDB6_t *cdb6; #endif CDB10_t *cdb10; CDB12_t *cdb12; CDB16_t *cdb16; bit32 unknown = agFALSE; bit32 len=0; group = cmdIU->cdb[0] & CDB_GRP_MASK; TI_DBG4(("tdsaProcessCDB: start\n")); switch (cmdIU->cdb[0]) { case SCSIOPC_REPORT_LUN: TI_DBG4(("tdsaProcessCDB: REPORT_LUN\n")); ttdsaXchg->XchType = AGSA_SSP_TGT_READ_DATA; break; case SCSIOPC_INQUIRY: TI_DBG4(("tdsaProcessCDB: INQUIRY\n")); ttdsaXchg->XchType = AGSA_SSP_TGT_READ_DATA; break; case SCSIOPC_TEST_UNIT_READY: TI_DBG4(("tdsaProcessCDB: TEST_UNIT_READY\n")); ttdsaXchg->XchType = AGSA_SSP_TGT_READ_DATA; break; case SCSIOPC_READ_CAPACITY_10: case SCSIOPC_READ_CAPACITY_16: TI_DBG4(("tdsaProcessCDB: READ CAPACITY\n")); ttdsaXchg->XchType = AGSA_SSP_TGT_READ_DATA; break; case SCSIOPC_READ_6: /* fall through */ case SCSIOPC_READ_10: TI_DBG4(("tdsaProcessCDB: READ\n")); ttdsaXchg->XchType = AGSA_SSP_TGT_READ_DATA; break; case SCSIOPC_WRITE_6: /* fall through */ case SCSIOPC_WRITE_10: TI_DBG4(("tdsaProcessCDB: WRITE\n")); ttdsaXchg->XchType = AGSA_SSP_TGT_WRITE_DATA; break; case SCSIOPC_MODE_SENSE_6: /* fall through */ case SCSIOPC_MODE_SENSE_10: TI_DBG4(("tdsaProcessCDB: MODE SENSE\n")); ttdsaXchg->XchType = AGSA_SSP_TGT_READ_DATA; break; case SCSIOPC_SYNCHRONIZE_CACHE_10: TI_DBG4(("tdsaProcessCDB: SCSIOPC_SYNCHRONIZE_CACHE_10\n")); ttdsaXchg->XchType = AGSA_SSP_TGT_CMD_OR_TASK_RSP; break; case SCSIOPC_REQUEST_SENSE: TI_DBG2(("tdsaProcessCDB: SCSIOPC_REQUEST_SENSE\n")); ttdsaXchg->XchType = AGSA_SSP_TGT_READ_DATA; break; default: TI_DBG4(("tdsaProcessCDB: UNKNOWN, cbd %d 0x%x\n", cmdIU->cdb[0], cmdIU->cdb[0])); ttdsaXchg->XchType = TargetUnknown; break; } /* parse datalen */ switch (group) { case CDB_6BYTE: TI_DBG4(("tdsaProcessCDB: CDB 6 byte, not yet\n")); #ifdef TD_DEBUG_ENABLE cdb6 = (CDB6_t *)(cmdIU->cdb); #endif TI_DBG4(("tdsaProcessCDB: CDB len 0x%x\n", cdb6->len)); break; case CDB_10BYTE1: /* fall through */ case CDB_10BYTE2: TI_DBG4(("tdsaProcessCDB: CDB 10 byte\n")); cdb10 = (CDB10_t *)(cmdIU->cdb); OSSA_READ_BE_16(AGROOT, &len, cdb10->len, 0); TI_DBG4(("tdsaProcessCDB: CDB len 0x%x\n", len)); dumpCDB(cmdIU->cdb); break; case CDB_12BYTE: TI_DBG4(("tdsaProcessCDB: CDB 12 byte, not yet\n")); cdb12 = (CDB12_t *)(cmdIU->cdb); OSSA_READ_BE_32(AGROOT, &len, cdb12->len, 0); TI_DBG4(("tdsaProcessCDB: CDB len 0x%x\n", len)); break; case CDB_16BYTE: TI_DBG4(("tdsaProcessCDB: CDB 16 byte, not yet\n")); cdb16 = (CDB16_t *)(cmdIU->cdb); OSSA_READ_BE_32(AGROOT, &len, cdb16->len, 0); TI_DBG4(("tdsaProcessCDB: CDB len 0x%x\n", len)); break; default: TI_DBG4(("tdsaProcessCDB: unknow CDB, group %d 0x%x\n", group, group)); len = 0; unknown = agTRUE; break; } if (cmdIU->cdb[0] == SCSIOPC_READ_6 || cmdIU->cdb[0] == SCSIOPC_READ_10 || cmdIU->cdb[0] == SCSIOPC_WRITE_6 || cmdIU->cdb[0] == SCSIOPC_WRITE_10 ) { ttdsaXchg->dataLen = len * Target->OperatingOption.BlockSize; } else { ttdsaXchg->dataLen = len; } if (ttdsaXchg->dataLen == 0 && unknown == agFALSE) { /* this is needed because of min operation in tiTGTIOstart() */ ttdsaXchg->dataLen = 0xffffffff; } /* TI_DBG4(("tdsaProcessCDB: datalen 0x%x %d\n", ttdsaXchg->dataLen, ttdsaXchg->dataLen)); */ return; } /***************************************************************************** * * tiTGTIOStart * * Purpose: This function is called by the target OS Specific Module to start * the next phase of a SCSI Request. * * Parameters: * tiRoot: Pointer to driver Instance. * tiIORequest: Pointer to the I/O request context for this I/O. * This context was initially passed to the OS Specific Module * in ostiProcessScsiReq(). * dataOffset: Offset into the buffer space for this phase. * dataLength: Length of data to move for this phase. * dataSGL: Length/Address pair of where the data is. The SGL list is * allocated and initialized by the OS Specific module. * sglVirtualAddr: The virtual address of the first element in agSgl1 when * agSgl1 is used with the type tiSglList. * This field is needed for the TD Layer. * * Return: * tiSuccess: I/O request successfully initiated. * tiBusy: No resources available, try again later. * tiError: Other errors that prevent the I/O request to be started. * * Note: * *****************************************************************************/ osGLOBAL bit32 tiTGTIOStart( tiRoot_t *tiRoot, tiIORequest_t *tiIORequest, bit32 dataOffset, bit32 dataLength, tiSgl_t *dataSGL, void *sglVirtualAddr ) { ttdsaXchg_t *ttdsaXchg; agsaSSPTargetRequest_t *agSSPTargetReq; bit32 tiStatus; bit32 saStatus; bit32 tdStatus; tdsaPortContext_t *onePortContext = agNULL; tdsaDeviceData_t *oneDeviceData = agNULL; TI_DBG4(("tiTGTIOStart: start\n")); TI_DBG4(("tiTGTIOStart: dataLength 0x%x %d\n", dataLength, dataLength)); TI_DBG4(("tiTGTIOStart: dataOffset 0x%x %d\n", dataOffset, dataOffset)); /* save infor in ttdsaXchg */ ttdsaXchg = (ttdsaXchg_t *)tiIORequest->tdData; /* check the state of port */ oneDeviceData = ttdsaXchg->DeviceData; onePortContext= oneDeviceData->tdPortContext; if (onePortContext->valid == agFALSE) { TI_DBG1(("tiTGTIOStart: portcontext pid %d is invalid\n", onePortContext->id)); return tiError; } agSSPTargetReq = &(ttdsaXchg->IORequestBody.transport.SAS.agSASRequestBody.sspTargetReq); /* fills in agsaSASRequestBody_t.agsaSSPTargetRequest_t */ agSSPTargetReq->dataLength = (bit32) MIN(dataLength, ttdsaXchg->dataLen); agSSPTargetReq->offset = dataOffset; agSSPTargetReq->agTag = ttdsaXchg->tag; /* SSPTargetReq->agTag has been set in ttdsaSSPReqReceived() */ /* Process TLR */ if (ttdsaXchg->TLR == 2) { /* diable TLR */ agSSPTargetReq->sspOption = 0; } else { /* enable TLR */ /* bit5: 0 1 11 11 :bit0 */ agSSPTargetReq->sspOption = 0x1F; } ttdsaXchg->IORequestBody.IOType.TargetIO.TargetIOType.RegIO.sglVirtualAddr = sglVirtualAddr; if (agSSPTargetReq->dataLength != 0) { TI_DBG6(("tiTGTIOStart: pos 1\n")); ttdsaXchg->IORequestBody.IOType.TargetIO.TargetIOType.RegIO.tiSgl1 = *dataSGL; } else { TI_DBG6(("tiTGTIOStart: pos 2\n")); ttdsaXchg->IORequestBody.IOType.TargetIO.TargetIOType.RegIO.tiSgl1.len = 0; ttdsaXchg->IORequestBody.IOType.TargetIO.TargetIOType.RegIO.tiSgl1.type = tiSgl; /* let's send response frame */ if (ttdsaXchg->resp.length != 0) { /* senselen != 0, send respsonse */ TI_DBG4(("tiTGTIOStart: send respsonse\n")); TI_DBG4(("tiTGTIOStart: resp.length 0x%x\n", ttdsaXchg->resp.length)); ttdsaXchg->responseSent = agTRUE; ttdsaXchg->DeviceData->IOResponse++; TD_DEBUG_TRACE(ttdsaXchg, ttdsaXchg->DeviceData); tdStatus = ttdsaSendResp(ttdsaXchg->agRoot, ttdsaXchg); if (tdStatus == AGSA_RC_SUCCESS) { return tiSuccess; } else if (tdStatus == AGSA_RC_FAILURE) { TI_DBG1(("tiTGTIOStart: (ttdsaSendResp) sending not successful\n")); return tiError; } else { TI_DBG1(("tiTGTIOStart: (ttdsaSendResp) sending busy\n")); return tiBusy; } } } /* sets SSPTargetReq->agSgl */ tiStatus = ttdssIOPrepareSGL(tiRoot, &ttdsaXchg->IORequestBody, dataSGL, NULL, sglVirtualAddr); if (tiStatus != tiSuccess) { TI_DBG1(("tiTGTIOStart: ttdIOPrepareSGL did not return success\n")); return tiStatus; } TI_DBG4(("tiTGTIOStart: agroot %p ttdsaXchg %p\n", ttdsaXchg->agRoot, ttdsaXchg)); TI_DBG4(("tiTGTIOStart: agDevHanlde %p\n", ttdsaXchg->DeviceData->agDevHandle)); if ( (ttdsaXchg->readRspCollapsed == agTRUE) || (ttdsaXchg->wrtRspCollapsed == agTRUE) ) { /* collapse good response with read */ TI_DBG4(("tiTGTIOStart: read rsp collapse\n")); TI_DBG4(("tiTGTIOStart: initiator tag 0x%x\n", ttdsaXchg->tag)); TD_XCHG_CONTEXT_NO_START_IO(tiRoot) = TD_XCHG_CONTEXT_NO_START_IO(tiRoot)+1; ttdsaXchg->DeviceData->IOStart++; TD_DEBUG_TRACE(ttdsaXchg, ttdsaXchg->DeviceData); saStatus = saSSPStart( ttdsaXchg->agRoot, &ttdsaXchg->IORequestBody.agIORequest, tdsaRotateQnumber(tiRoot, oneDeviceData), ttdsaXchg->DeviceData->agDevHandle, ttdsaXchg->readRspCollapsed ? AGSA_SSP_TGT_READ_GOOD_RESP : AGSA_SSP_TGT_WRITE_GOOD_RESP, &ttdsaXchg->IORequestBody.transport.SAS.agSASRequestBody, agNULL, &ossaSSPCompleted ); } else { TI_DBG4(("tiTGTIOStart: normal\n")); TI_DBG4(("tiTGTIOStart: initiator tag 0x%x\n", ttdsaXchg->tag)); TD_XCHG_CONTEXT_NO_START_IO(tiRoot) = TD_XCHG_CONTEXT_NO_START_IO(tiRoot)+1; ttdsaXchg->DeviceData->IOStart++; TD_DEBUG_TRACE(ttdsaXchg, ttdsaXchg->DeviceData); saStatus = saSSPStart( ttdsaXchg->agRoot, /* agRoot, */ &ttdsaXchg->IORequestBody.agIORequest, tdsaRotateQnumber(tiRoot, oneDeviceData), ttdsaXchg->DeviceData->agDevHandle, ttdsaXchg->XchType, &ttdsaXchg->IORequestBody.transport.SAS.agSASRequestBody, agNULL, &ossaSSPCompleted ); } if (saStatus == AGSA_RC_SUCCESS) { return tiSuccess; } else if (saStatus == AGSA_RC_FAILURE) { TI_DBG1(("tiTGTIOStart: sending not successful\n")); return tiError; } else { TI_DBG1(("tiTGTIOStart: sending busy\n")); return tiBusy; } } #ifdef EDC_ENABLE /***************************************************************************** * * tiTGTIOStart * * Purpose: This function is called by the target OS Specific Module to start * the next phase of a SCSI Request. * * Parameters: * tiRoot: Pointer to driver Instance. * tiIORequest: Pointer to the I/O request context for this I/O. * This context was initially passed to the OS Specific Module * in ostiProcessScsiReq(). * dataOffset: Offset into the buffer space for this phase. * dataLength: Length of data to move for this phase. * dataSGL: Length/Address pair of where the data is. The SGL list is * allocated and initialized by the OS Specific module. * sglVirtualAddr: The virtual address of the first element in agSgl1 when * agSgl1 is used with the type tiSglList. * This field is needed for the TD Layer. * difOption: DIF option. * * Return: * tiSuccess: I/O request successfully initiated. * tiBusy: No resources available, try again later. * tiError: Other errors that prevent the I/O request to be started. * * Note: * *****************************************************************************/ osGLOBAL bit32 tiTGTIOStartDif( tiRoot_t *tiRoot, tiIORequest_t *tiIORequest, bit32 dataOffset, bit32 dataLength, tiSgl_t *dataSGL, void *sglVirtualAddr, tiDif_t *difOption ) { /* This function was never used by SAS/SATA. Use tiTGTSuperIOStart() instead. */ return tiBusy; } #endif osGLOBAL bit32 ttdssIOPrepareSGL( tiRoot_t *tiRoot, tdIORequestBody_t *tdIORequestBody, tiSgl_t *tiSgl1, tiSgl_t *tiSgl2, void *sglVirtualAddr ) { agsaSgl_t *agSgl; TI_DBG6(("ttdssIOPrepareSGL: start\n")); agSgl = &(tdIORequestBody->transport.SAS.agSASRequestBody.sspTargetReq.agSgl); agSgl->len = 0; if (tiSgl1 == agNULL) { TI_DBG1(("ttdssIOPrepareSGL: Error tiSgl1 is NULL\n")); return tiError; } agSgl->sgUpper = tiSgl1->upper; agSgl->sgLower = tiSgl1->lower; agSgl->len = tiSgl1->len; agSgl->extReserved = tiSgl1->type; return tiSuccess; } /* temp for debugging */ void dumpresp(bit8 *resp, bit32 len) { bit32 i; for(i=0;iosData; tiRoot_t *tiRoot = (tiRoot_t *)osData->tiRoot; tdsaDeviceData_t *oneDeviceData = agNULL; bit32 agRequestType; bit32 saStatus; agsaSSPTargetResponse_t *agSSPTargetResp; agRequestType = AGSA_SSP_TGT_CMD_OR_TASK_RSP; TI_DBG4(("ttdsaSendResp: start\n")); TI_DBG4(("ttdsaSendResp: agroot %p ttdsaXchg %p\n", ttdsaXchg->agRoot, ttdsaXchg)); TI_DBG4(("ttdsaSendResp:: agDevHanlde %p\n", ttdsaXchg->DeviceData->agDevHandle)); /* sas response */ TI_DBG4(("ttdsaSendResp: len 0x%x \n", ttdsaXchg->resp.length)); TI_DBG4(("ttdsaSendResp: upper 0x%x \n", ttdsaXchg->resp.phyAddrUpper)); TI_DBG4(("ttdsaSendResp: lower 0x%x \n", ttdsaXchg->resp.phyAddrLower)); TI_DBG4(("ttdsaSendResp: initiator tag 0x%x\n", ttdsaXchg->tag)); agSSPTargetResp = &(ttdsaXchg->IORequestBody.transport.SAS.agSASRequestBody.sspTargetResponse); agSSPTargetResp->agTag = ttdsaXchg->tag; agSSPTargetResp->respBufLength = ttdsaXchg->resp.length; agSSPTargetResp->respBufUpper = ttdsaXchg->resp.phyAddrUpper; agSSPTargetResp->respBufLower = ttdsaXchg->resp.phyAddrLower; agSSPTargetResp->respOption = 3; /* Retry on both ACK/NAK timeout and NAK received */ /* temporary solution for T2D Combo*/ #if defined (INITIATOR_DRIVER) && defined (TARGET_DRIVER) /* nothing */ #else if (agSSPTargetResp->respBufLength <= AGSA_MAX_SSPPAYLOAD_VIA_SFO) agSSPTargetResp->frameBuf = ttdsaXchg->resp.virtAddr; else agSSPTargetResp->frameBuf = NULL; #endif dumpresp((bit8 *)ttdsaXchg->resp.virtAddr, ttdsaXchg->resp.length); TD_XCHG_CONTEXT_NO_SEND_RSP(TD_GET_TIROOT(agRoot)) = TD_XCHG_CONTEXT_NO_SEND_RSP(TD_GET_TIROOT(agRoot))+1; oneDeviceData = ttdsaXchg->DeviceData; saStatus = saSSPStart( ttdsaXchg->agRoot, /* agRoot,*/ &ttdsaXchg->IORequestBody.agIORequest, tdsaRotateQnumber(tiRoot, oneDeviceData), ttdsaXchg->DeviceData->agDevHandle, /* agDevHandle, */ agRequestType, &ttdsaXchg->IORequestBody.transport.SAS.agSASRequestBody, agNULL, &ossaSSPCompleted ); if (saStatus == AGSA_RC_SUCCESS) { TI_DBG4(("ttdsaSendResp: sending successful\n")); return AGSA_RC_SUCCESS; } else if (saStatus == AGSA_RC_FAILURE) { TI_DBG1(("ttdsaSendResp: sending not successful\n")); return AGSA_RC_FAILURE; } else { TI_DBG1(("ttdsaSendResp: sending busy\n")); return AGSA_RC_BUSY; } } osGLOBAL void ttdsaIOCompleted( agsaRoot_t *agRoot, agsaIORequest_t *agIORequest, bit32 agIOStatus, bit32 agIOInfoLen, agsaFrameHandle_t agFrameHandle, bit32 agOtherInfo ) { ttdsaXchg_t *ttdsaXchg = (ttdsaXchg_t *)agIORequest->osData; /* done in ttdsaXchgInit() */ bit32 IOFailed = agFALSE; bit32 status; bit32 statusDetail = 0; tiRoot_t *tiRoot; #ifdef REMOVED tdsaRoot_t *tdsaRoot; tdsaContext_t *tdsaAllShared; #endif bit32 tdStatus; bit32 saStatus = AGSA_RC_FAILURE; #ifdef TD_DEBUG_ENABLE agsaDifDetails_t *DifDetail; #endif TI_DBG4(("ttdsaIOCompleted: start\n")); tiRoot = ((tdsaRootOsData_t *)agRoot->osData)->tiRoot; #ifdef REMOVED tdsaRoot = (tdsaRoot_t *) tiRoot->tdData; tdsaAllShared = (tdsaContext_t *)&tdsaRoot->tdsaAllShared; #endif #ifdef TD_DEBUG_ENABLE DifDetail = (agsaDifDetails_t *)agFrameHandle; #endif if (tiRoot == agNULL) { TI_DBG1(("ttdsaIOCompleted: tiRoot is NULL\n")); return; } TD_XCHG_CONTEXT_NO_IO_COMPLETED(tiRoot) = TD_XCHG_CONTEXT_NO_IO_COMPLETED(tiRoot)+1; if(TD_XCHG_GET_STATE(ttdsaXchg) != TD_XCHG_STATE_ACTIVE) { TI_DBG1(("ttdsaIOCompleted: XCHG is not active *****************\n")); return; } if (ttdsaXchg->isTMRequest != agTRUE) { TI_DBG6(("ttdsaIOCompleted: COMMAND \n")); TI_DBG6(("ttdsaIOCompleted: ttdsaXchg %p\n", ttdsaXchg)); TI_DBG6(("ttdsaIOCompleted: ttdsaXchg->IORequestBody.EsglPageList %p\n", &ttdsaXchg->IORequestBody.EsglPageList)); TI_DBG6(("ttdsaIOCompleted: command initiator tag 0x%x\n", ttdsaXchg->tag)); #ifdef REMOVED /* call tdsafreeesglpages only for xchg that used eslg */ if (ttdsaXchg->usedEsgl == agTRUE) { tdsaFreeEsglPages(tiRoot, &ttdsaXchg->IORequestBody.EsglPageList); ttdsaXchg->usedEsgl = agFALSE; } #endif /* successful case */ if (agIOStatus == OSSA_IO_SUCCESS) { TI_DBG6(("ttdsaIOCompleted: osIOSuccess\n")); if ( (ttdsaXchg->readRspCollapsed == agTRUE) || (ttdsaXchg->wrtRspCollapsed == agTRUE) ) { ttdsaXchg->responseSent = agTRUE; TI_DBG4(("ttdsaIOCompleted: read rsp collapse\n")); } if (ttdsaXchg->statusSent == agTRUE) { /* the response has already been set and ready but has NOT been sent */ if (ttdsaXchg->responseSent == agFALSE) { /* let's send the response for IO */ TI_DBG6(("ttdsaIOCompleted: sending response\n")); TD_DEBUG_TRACE(ttdsaXchg, ttdsaXchg->DeviceData); tdStatus = ttdsaSendResp(agRoot, ttdsaXchg); if (tdStatus != AGSA_RC_SUCCESS) { TI_DBG1(("ttdsaIOCompleted: attention needed\n")); return; } ttdsaXchg->responseSent = agTRUE; } else { TI_DBG4(("ttdsaIOCompleted: read rsp collapse and complete \n")); /* the response has been sent */ TI_DBG6(("ttdsaIOCompleted: already sent response, notify OS\n")); if (TD_XCHG_GET_STATE(ttdsaXchg) == TD_XCHG_STATE_INACTIVE) { TI_DBG1(("ttdsaIOCompleted: wrong DEQUEUE_THIS\n")); } /* * Notify the OS Specific Module, so it can free its resource. */ TI_DBG4(("ttdsaIOCompleted: calling ostiTargetIOCompleted\n")); ostiTargetIOCompleted( tiRoot, ttdsaXchg->IORequestBody.tiIORequest, tiIOSuccess ); /* clean up resources */ ttdsaXchgFreeStruct(tiRoot,ttdsaXchg); } } /* sent */ else { TI_DBG4(("ttdsaIOCompleted: osIOSuccess: nextphase\n")); /* the response has not been set; still in data phase */ /* we need to tell the disk module to start the next phase */ ostiNextDataPhase(ttdsaXchg->tiRoot, ttdsaXchg->IORequestBody.tiIORequest ); } return; } /* success */ /* handle error cases */ if (agIOStatus == OSSA_IO_XFR_ERROR_DIF_APPLICATION_TAG_MISMATCH || agIOStatus == OSSA_IO_XFR_ERROR_DIF_REFERENCE_TAG_MISMATCH || agIOStatus == OSSA_IO_XFR_ERROR_DIF_CRC_MISMATCH) { TI_DBG1(("ttdsaIOCompleted: DIF detail UpperLBA 0x%08x LowerLBA 0x%08x\n", DifDetail->UpperLBA, DifDetail->LowerLBA)); } switch (agIOStatus) { case OSSA_IO_ABORTED: TI_DBG1(("ttdsaIOCompleted: ABORTED\n")); status = tiIOFailed; statusDetail = tiDetailAborted; IOFailed = agTRUE; break; #ifdef REMOVED case OSSA_IO_OVERFLOW: TI_DBG1(("ttdsaIOCompleted: OVERFLOW\n")); status = tiIOOverRun; IOFailed = agTRUE; break; #endif case OSSA_IO_UNDERFLOW: TI_DBG1(("ttdsaIOCompleted: UNDERFLOW\n")); status = tiIOUnderRun; IOFailed = agTRUE; break; case OSSA_IO_ABORT_RESET: TI_DBG1(("ttdsaIOCompleted: ABORT_RESET\n")); status = tiIOFailed; statusDetail = tiDetailAbortReset; IOFailed = agTRUE; break; case OSSA_IO_XFR_ERROR_DEK_KEY_CACHE_MISS: TI_DBG1(("ttdsaIOCompleted: OSSA_IO_XFR_ERROR_DEK_KEY_CACHE_MISS\n")); status = tiIOEncryptError; statusDetail = tiDetailDekKeyCacheMiss; IOFailed = agTRUE; break; case OSSA_IO_XFR_ERROR_DEK_KEY_TAG_MISMATCH: TI_DBG1(("ttdsaIOCompleted: OSSA_IO_XFR_ERROR_DEK_KEY_TAG_MISMATCH\n")); status = tiIOEncryptError; statusDetail = tiDetailDekKeyCacheMiss; IOFailed = agTRUE; break; case OSSA_IO_XFR_ERROR_DIF_APPLICATION_TAG_MISMATCH: TI_DBG1(("ttdsaIOCompleted: OSSA_IO_XFR_ERROR_DIF_APPLICATION_TAG_MISMATCH\n")); status = tiIODifError; statusDetail = tiDetailDifAppTagMismatch; IOFailed = agTRUE; break; case OSSA_IO_XFR_ERROR_DIF_REFERENCE_TAG_MISMATCH: TI_DBG1(("ttdsaIOCompleted: OSSA_IO_XFR_ERROR_DIF_REFERENCE_TAG_MISMATCH\n")); status = tiIODifError; statusDetail = tiDetailDifRefTagMismatch; IOFailed = agTRUE; break; case OSSA_IO_XFR_ERROR_DIF_CRC_MISMATCH: TI_DBG1(("ttdsaIOCompleted: OSSA_IO_XFR_ERROR_DIF_CRC_MISMATCH\n")); status = tiIODifError; statusDetail = tiDetailDifCrcMismatch; IOFailed = agTRUE; break; case OSSA_IO_FAILED: /* fall through */ case OSSA_IO_NO_DEVICE: /* fall through */ //case OSSA_IO_NO_SUPPORT: /* fall through */ /*added to compile tgt_drv (TP)*/ case OSSA_IO_LINK_FAILURE: /* fall through */ case OSSA_IO_PROG_ERROR: /* fall through */ case OSSA_IO_DS_NON_OPERATIONAL: /* fall through */ case OSSA_IO_DS_IN_RECOVERY: /* fall through */ case OSSA_IO_TM_TAG_NOT_FOUND: /* fall through */ case OSSA_MPI_ERR_IO_RESOURCE_UNAVAILABLE: /* fall through */ default: status = tiIOFailed; statusDetail = tiDetailOtherError; IOFailed = agTRUE; TI_DBG1(("ttdsaIOCompleted: Fail!!!!!!! agIOStatus=0x%x agIOInfoLen=0x%x agOtherInfo=0x%x\n", agIOStatus, agIOInfoLen, agOtherInfo)); // ttdsaDumpallXchg(tiRoot); if (agIOStatus == OSSA_IO_XFER_OPEN_RETRY_TIMEOUT) { TI_DBG1(("ttdsaIOCompleted: OSSA_IO_XFER_OPEN_RETRY_TIMEOUT ttdsaXchg->id 0x%x datalen 0x%x offset 0x%x agTag 0x%x\n", ttdsaXchg->id, ttdsaXchg->IORequestBody.transport.SAS.agSASRequestBody.sspTargetReq.dataLength, ttdsaXchg->IORequestBody.transport.SAS.agSASRequestBody.sspTargetReq.offset, ttdsaXchg->IORequestBody.transport.SAS.agSASRequestBody.sspTargetReq.agTag)); TI_DBG1(("ttdsaIOCompleted: statusSent %d responseSent %d\n", ttdsaXchg->statusSent, ttdsaXchg->responseSent)); } break; } /* switch */ if (IOFailed == agTRUE) { if (agIORequest->sdkData == agNULL) { tiIORequest_t tiIORequest; TI_DBG1(("ttdsaIOCompleted: ERROR ttdsaXchg=%p agIOStatus= 0x%x\n", ttdsaXchg, agIOStatus )); TI_DBG1(("CDB= 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", ttdsaXchg->agSSPCmndIU.cdb[0], ttdsaXchg->agSSPCmndIU.cdb[1], ttdsaXchg->agSSPCmndIU.cdb[2], ttdsaXchg->agSSPCmndIU.cdb[3], ttdsaXchg->agSSPCmndIU.cdb[4], ttdsaXchg->agSSPCmndIU.cdb[5], ttdsaXchg->agSSPCmndIU.cdb[6], ttdsaXchg->agSSPCmndIU.cdb[7], ttdsaXchg->agSSPCmndIU.cdb[8], ttdsaXchg->agSSPCmndIU.cdb[9], ttdsaXchg->agSSPCmndIU.cdb[10], ttdsaXchg->agSSPCmndIU.cdb[11], ttdsaXchg->agSSPCmndIU.cdb[12], ttdsaXchg->agSSPCmndIU.cdb[13], ttdsaXchg->agSSPCmndIU.cdb[14], ttdsaXchg->agSSPCmndIU.cdb[15] )); if (TD_XCHG_GET_STATE(ttdsaXchg) == TD_XCHG_STATE_INACTIVE) { TI_DBG1(("ttdsaIOCompleted: wrong DEQUEUE_THIS 1\n")); } if (ttdsaXchg->retries <= OPEN_RETRY_RETRIES && agIOStatus == OSSA_IO_XFER_OPEN_RETRY_TIMEOUT) { TI_DBG2(("ttdsaIOCompleted: 1 loc retries on OSSA_IO_XFER_OPEN_RETRY_TIMEOUT\n")); if ( (agOtherInfo & 0x1) == 1) { /* repsonse phase */ TI_DBG2(("ttdsaIOCompleted: 0 loc response retry\n")); /* repsonse retry */ saStatus = ttdsaSendResp(ttdsaXchg->agRoot, ttdsaXchg); if (saStatus == AGSA_RC_SUCCESS) { TI_DBG2(("ttdsaIOCompleted: 0 loc retried\n")); ttdsaXchg->retries++; } else { TI_DBG1(("ttdsaIOCompleted: 0 loc retry failed\n")); ttdsaXchg->retries = 0; /* * because we are freeing up the exchange * we must let the oslayer know that * we are releasing the resources by * setting the tdData to NULL */ tiIORequest = ttdsaXchg->IORequestBody.IOType.TargetIO.tiIORequest; tiIORequest.tdData = agNULL; ostiTargetIOError( tiRoot, &tiIORequest, status, statusDetail ); /* clean up resources */ ttdsaXchgFreeStruct(tiRoot,ttdsaXchg); } } else if ( (ttdsaXchg->readRspCollapsed == agTRUE) || (ttdsaXchg->wrtRspCollapsed == agTRUE) ) { saStatus = saSSPStart( ttdsaXchg->agRoot, /* agRoot, */ &ttdsaXchg->IORequestBody.agIORequest, 0, ttdsaXchg->DeviceData->agDevHandle, /* agDevHandle, */ ttdsaXchg->readRspCollapsed ? AGSA_SSP_TGT_READ_GOOD_RESP : AGSA_SSP_TGT_WRITE_GOOD_RESP, &ttdsaXchg->IORequestBody.transport.SAS.agSASRequestBody, agNULL, &ossaSSPCompleted ); if (saStatus == AGSA_RC_SUCCESS) { TI_DBG1(("ttdsaIOCompleted: 1 loc retried\n")); ttdsaXchg->retries++; } else { TI_DBG1(("ttdsaIOCompleted: 1 loc retry failed\n")); ttdsaXchg->retries = 0; /* * because we are freeing up the exchange * we must let the oslayer know that * we are releasing the resources by * setting the tdData to NULL */ tiIORequest = ttdsaXchg->IORequestBody.IOType.TargetIO.tiIORequest; tiIORequest.tdData = agNULL; ostiTargetIOError( tiRoot, &tiIORequest, status, statusDetail ); /* clean up resources */ ttdsaXchgFreeStruct(tiRoot,ttdsaXchg); } } else { if (ttdsaXchg->responseSent == agFALSE) { saStatus = saSSPStart( ttdsaXchg->agRoot, /* agRoot, */ &ttdsaXchg->IORequestBody.agIORequest, /*agIORequest, */ 0, /* queue number */ ttdsaXchg->DeviceData->agDevHandle, /* agDevHandle, */ ttdsaXchg->XchType, &ttdsaXchg->IORequestBody.transport.SAS.agSASRequestBody, agNULL, &ossaSSPCompleted ); } else { /* repsonse retry */ TI_DBG1(("ttdsaIOCompleted: 2 loc reponse retry\n")); saStatus = ttdsaSendResp(ttdsaXchg->agRoot, ttdsaXchg); } if (saStatus == AGSA_RC_SUCCESS) { TI_DBG1(("ttdsaIOCompleted: 2 loc retried\n")); ttdsaXchg->retries++; } else { TI_DBG1(("ttdsaIOCompleted: 2 loc retry failed\n")); ttdsaXchg->retries = 0; /* * because we are freeing up the exchange * we must let the oslayer know that * we are releasing the resources by * setting the tdData to NULL */ tiIORequest = ttdsaXchg->IORequestBody.IOType.TargetIO.tiIORequest; tiIORequest.tdData = agNULL; ostiTargetIOError( tiRoot, &tiIORequest, status, statusDetail ); /* clean up resources */ ttdsaXchgFreeStruct(tiRoot,ttdsaXchg); } } } else { ttdsaXchg->retries = 0; /* * because we are freeing up the exchange * we must let the oslayer know that * we are releasing the resources by * setting the tdData to NULL */ tiIORequest = ttdsaXchg->IORequestBody.IOType.TargetIO.tiIORequest; tiIORequest.tdData = agNULL; ostiTargetIOError( tiRoot, &tiIORequest, status, statusDetail ); /* clean up resources */ ttdsaXchgFreeStruct(tiRoot,ttdsaXchg); } } /* saData == agNULL */ else { tiIORequest_t tiIORequest; TI_DBG1(("ttdsaIOCompleted: 2\n")); if (TD_XCHG_GET_STATE(ttdsaXchg) == TD_XCHG_STATE_INACTIVE) { TI_DBG1(("ttdsaIOCompleted: wrong DEQUEUE_THIS 2\n")); } if (ttdsaXchg->retries <= OPEN_RETRY_RETRIES && agIOStatus == OSSA_IO_XFER_OPEN_RETRY_TIMEOUT) { TI_DBG1(("ttdsaIOCompleted: 2 loc retries on OSSA_IO_XFER_OPEN_RETRY_TIMEOUT\n")); if ( (agOtherInfo & 0x1) == 1) { /* repsonse phase */ TI_DBG2(("ttdsaIOCompleted: 0 loc response retry\n")); /* repsonse retry */ saStatus = ttdsaSendResp(ttdsaXchg->agRoot, ttdsaXchg); if (saStatus == AGSA_RC_SUCCESS) { TI_DBG2(("ttdsaIOCompleted: 0 loc retried\n")); ttdsaXchg->retries++; } else { TI_DBG1(("ttdsaIOCompleted: 0 loc retry failed\n")); ttdsaXchg->retries = 0; /* * because we are freeing up the exchange * we must let the oslayer know that * we are releasing the resources by * setting the tdData to NULL */ tiIORequest = ttdsaXchg->IORequestBody.IOType.TargetIO.tiIORequest; tiIORequest.tdData = agNULL; ostiTargetIOError( tiRoot, &tiIORequest, status, statusDetail ); /* clean up resources */ ttdsaXchgFreeStruct(tiRoot,ttdsaXchg); } } else if ( (ttdsaXchg->readRspCollapsed == agTRUE) || (ttdsaXchg->wrtRspCollapsed == agTRUE) ) { saStatus = saSSPStart( ttdsaXchg->agRoot, /* agRoot, */ &ttdsaXchg->IORequestBody.agIORequest, /* agIORequest, */ 0, /* queue number */ ttdsaXchg->DeviceData->agDevHandle, /* agDevHandle, */ ttdsaXchg->readRspCollapsed ? AGSA_SSP_TGT_READ_GOOD_RESP : AGSA_SSP_TGT_WRITE_GOOD_RESP, &ttdsaXchg->IORequestBody.transport.SAS.agSASRequestBody, agNULL, &ossaSSPCompleted ); if (saStatus == AGSA_RC_SUCCESS) { TI_DBG1(("ttdsaIOCompleted: 1 loc retried\n")); ttdsaXchg->retries++; } else { TI_DBG1(("ttdsaIOCompleted: 1 loc retry failed\n")); ttdsaXchg->retries = 0; /* * because we are freeing up the exchange * we must let the oslayer know that * we are releasing the resources by * setting the tdData to NULL */ tiIORequest = ttdsaXchg->IORequestBody.IOType.TargetIO.tiIORequest; tiIORequest.tdData = agNULL; ostiTargetIOError( tiRoot, &tiIORequest, status, statusDetail ); /* clean up resources */ ttdsaXchgFreeStruct(tiRoot,ttdsaXchg); } } else { TI_DBG1(("ttdsaIOCompleted: 2 loc ttdsaXchg->id 0x%x datalen 0x%x offset 0x%x agTag 0x%x\n", ttdsaXchg->id, ttdsaXchg->IORequestBody.transport.SAS.agSASRequestBody.sspTargetReq.dataLength, ttdsaXchg->IORequestBody.transport.SAS.agSASRequestBody.sspTargetReq.offset, ttdsaXchg->IORequestBody.transport.SAS.agSASRequestBody.sspTargetReq.agTag)); if (ttdsaXchg->responseSent == agFALSE) { saStatus = saSSPStart( ttdsaXchg->agRoot, /* agRoot, */ &ttdsaXchg->IORequestBody.agIORequest, /* agIORequest, */ 0, /* queue number */ ttdsaXchg->DeviceData->agDevHandle, /* agDevHandle, */ ttdsaXchg->XchType, &ttdsaXchg->IORequestBody.transport.SAS.agSASRequestBody, agNULL, &ossaSSPCompleted ); } else { TI_DBG1(("ttdsaIOCompleted: 2 loc response retry\n")); /* repsonse retry */ saStatus = ttdsaSendResp(ttdsaXchg->agRoot, ttdsaXchg); } if (saStatus == AGSA_RC_SUCCESS) { TI_DBG1(("ttdsaIOCompleted: 2 loc retried\n")); ttdsaXchg->retries++; } else { TI_DBG1(("ttdsaIOCompleted: 2 loc retry failed\n")); ttdsaXchg->retries = 0; /* * because we are freeing up the exchange * we must let the oslayer know that * we are releasing the resources by * setting the tdData to NULL */ tiIORequest = ttdsaXchg->IORequestBody.IOType.TargetIO.tiIORequest; tiIORequest.tdData = agNULL; ostiTargetIOError( tiRoot, &tiIORequest, status, statusDetail ); /* clean up resources */ ttdsaXchgFreeStruct(tiRoot,ttdsaXchg); } } } else { TI_DBG1(("ttdsaIOCompleted: retry is over\n")); ttdsaXchg->retries = 0; tiIORequest = ttdsaXchg->IORequestBody.IOType.TargetIO.tiIORequest; tiIORequest.tdData = agNULL; ostiTargetIOError( tiRoot, &tiIORequest, status, statusDetail ); /* clean up resources */ ttdsaXchgFreeStruct(tiRoot,ttdsaXchg); } } /* saData != agNULL */ }/* if (IOFailed == agTRUE) */ } /* not TMrequest */ else /* TMrequest */ { TI_DBG1(("ttdsaIOCompleted: TM request\n")); TI_DBG1(("ttdsaIOCompleted: TM initiator tag 0x%x\n", ttdsaXchg->tag)); switch(agIOStatus) { case OSSA_IO_SUCCESS: TI_DBG1(("ttdsaIOCompleted: success\n")); status = tiIOSuccess; break; case OSSA_IO_ABORTED: TI_DBG1(("ttdsaIOCompleted: ABORTED\n")); status = tiIOFailed; statusDetail = tiDetailAborted; IOFailed = agTRUE; break; case OSSA_IO_ABORT_RESET: TI_DBG1(("ttdsaIOCompleted: ABORT_RESET\n")); status = tiIOFailed; statusDetail = tiDetailAbortReset; IOFailed = agTRUE; break; #ifdef REMOVED case OSSA_IO_OVERFLOW: /* fall through */ #endif case OSSA_IO_UNDERFLOW: /* fall through */ case OSSA_IO_FAILED: /* fall through */ #ifdef REMOVED case OSSA_IO_NOT_VALID: /* fall through */ #endif case OSSA_IO_NO_DEVICE: /* fall through */ //case OSSA_IO_NO_SUPPORT: /* fall through */ /*added to compile tgt_drv (TP)*/ case OSSA_IO_LINK_FAILURE: /* fall through */ case OSSA_IO_PROG_ERROR: /* fall through */ case OSSA_IO_DS_NON_OPERATIONAL: /* fall through */ case OSSA_IO_DS_IN_RECOVERY: /* fall through */ case OSSA_IO_TM_TAG_NOT_FOUND: /* fall through */ case OSSA_MPI_ERR_IO_RESOURCE_UNAVAILABLE: /* fall through */ default: status = tiIOFailed; statusDetail = tiDetailOtherError; IOFailed = agTRUE; break; } /* switch */ /* for not found IO, we don't call OS */ if (ttdsaXchg->io_found == agTRUE) { ostiTargetTmCompleted( tiRoot, ttdsaXchg->IORequestBody.tiIORequest, status, statusDetail ); } /* clean up resources */ ttdsaXchgFreeStruct(tiRoot, ttdsaXchg); } /* TM Request */ return; } osGLOBAL void ttdsaTMProcess( tiRoot_t *tiRoot, ttdsaXchg_t *ttdsaXchg ) { tdsaRoot_t *tdsaRoot = (tdsaRoot_t *) tiRoot->tdData; tdsaContext_t *tdsaAllShared = (tdsaContext_t *)&tdsaRoot->tdsaAllShared; ttdsaTgt_t *Target = (ttdsaTgt_t *)tdsaAllShared->ttdsaTgt; agsaSSPScsiTaskMgntReq_t *agTMIU; bit8 TMFun; bit32 tiTMFun; tiIORequest_t *reftiIORequest = agNULL; tdList_t *IOList; bit32 IOFound = agFALSE; ttdsaXchg_t *tmp_ttdsaXchg = agNULL; agsaRoot_t *agRoot = (agsaRoot_t *)&(tdsaAllShared->agRootNonInt); agsaIORequest_t *agIORequest = agNULL; agsaIORequest_t *agIOAbortRequest = agNULL; tdsaDeviceData_t *oneDeviceData = agNULL; agsaDevHandle_t *agDevHandle = agNULL; TI_DBG1(("ttdsaTMProcess: start\n")); ttdsaXchg->isTMRequest = agTRUE; agTMIU = (agsaSSPScsiTaskMgntReq_t *)&(ttdsaXchg->agTMIU); TMFun = agTMIU->taskMgntFunction; switch (TMFun) { case AGSA_ABORT_TASK: TI_DBG1(("ttdsaTMProcess: ABORT_TASK\n")); tiTMFun = AG_ABORT_TASK; break; case AGSA_ABORT_TASK_SET: TI_DBG1(("ttdsaTMProcess: ABORT_TASK_SET\n")); tiTMFun = AG_ABORT_TASK_SET; break; case AGSA_CLEAR_TASK_SET: TI_DBG1(("ttdsaTMProcess: CLEAR_TASK_SET\n")); tiTMFun = AG_CLEAR_TASK_SET; break; case AGSA_LOGICAL_UNIT_RESET: TI_DBG1(("ttdsaTMProcess: LOGICAL_UNIT_RESET\n")); tiTMFun = AG_LOGICAL_UNIT_RESET; break; case AGSA_CLEAR_ACA: TI_DBG1(("ttdsaTMProcess: CLEAR_ACA\n")); tiTMFun = AG_CLEAR_ACA; break; case AGSA_QUERY_TASK: TI_DBG1(("ttdsaTMProcess: QUERY_TASK\n")); tiTMFun = AG_QUERY_TASK; break; default: TI_DBG1(("ttdsaTMProcess: RESERVED TM 0x%x %d\n", TMFun, TMFun)); tiTMFun = 0xff; /* unknown task management request */ break; } /* * Give the OS Specific module to apply it's Task management policy. */ /* osGLOBAL void ostiTaskManagement ( tiRoot_t *tiRoot, bit32 task, bit8 *scsiLun, tiIORequest_t *refTiIORequest, tiIORequest_t *tiTMRequest, tiDeviceHandle_t *tiDeviceHandle); */ if (TMFun == AGSA_ABORT_TASK) { TI_DBG1(("ttdsaTMProcess: if abort task; to be tested \n")); /* needs to find a reftIIORequest and set it */ IOList = Target->ttdsaXchgData.xchgBusyList.flink; IOFound = agFALSE; /* search through the current IOList */ while (IOList != &Target->ttdsaXchgData.xchgBusyList) { tmp_ttdsaXchg = TDLIST_OBJECT_BASE(ttdsaXchg_t, XchgLinks, IOList); if (tmp_ttdsaXchg->tag == agTMIU->tagOfTaskToBeManaged) { TI_DBG1(("ttdsaTMProcess: tag 0x%x\n",tmp_ttdsaXchg->tag)); IOFound = agTRUE; break; } IOList = IOList->flink; } /* while */ if (IOFound == agTRUE) { TI_DBG1(("ttdsaTMProcess: found \n")); /* call saSSPAbort() */ TI_DBG1(("ttdsaTMProcess: loc 1\n")); /* abort taskmanagement itself */ agIOAbortRequest = (agsaIORequest_t *)&(ttdsaXchg->IORequestBody.agIORequest); /* IO to be aborted */ agIORequest = (agsaIORequest_t *)&(tmp_ttdsaXchg->IORequestBody.agIORequest); oneDeviceData = tmp_ttdsaXchg->DeviceData; agDevHandle = oneDeviceData->agDevHandle; if (agIORequest == agNULL) { TI_DBG1(("ttdsaTMProcess: agIORequest is NULL\n")); } else { TI_DBG1(("ttdsaTMProcess: agIORequest is NOT NULL\n")); if (agIORequest->sdkData == agNULL) { TI_DBG1(("ttdsaTMProcess: agIORequest->saData is NULL\n")); } else { TI_DBG1(("ttdsaTMProcess: agIORequest->saData is NOT NULL\n")); #ifdef RPM_SOC saSSPAbort(agRoot, agIORequest); #else saSSPAbort(agRoot, agIOAbortRequest,0,agDevHandle,0,agIORequest, agNULL); #endif } } } /* FOUND */ else { ttdsaXchg->io_found = agFALSE; tiTGTSendTmResp(tiRoot, ttdsaXchg->IORequestBody.tiIORequest, tiError /* this is FUNCTION_FAILED */ ); TI_DBG1(("ttdsaTMProcess: ABORT_TASK not found\n")); return; } } /* ABORT_TASK */ /* reftiIORequest: referred IO request. If found, not null. But not used in ramdisk */ TI_DBG1(("ttdsaTMProcess: calling ostiTaskManagement\n")); ostiTaskManagement( tiRoot, tiTMFun, ttdsaXchg->agTMIU.lun, reftiIORequest, ttdsaXchg->IORequestBody.tiIORequest, &ttdsaXchg->DeviceData->tiDeviceHandle ); return; } /***************************************************************************** * * tiTGTIOAbort * * Purpose: This function is called to abort an IO previously reported * to oslayer through ostiProcessRequest() function. * * Parameters: * tiRoot: Pointer to driver Instance. * tiIORequest: Pointer to the I/O request context for this I/O. * This context was initially passed to the OS Specific * Module in ostiProcessScsiReq(). * Return: * tiSuccess: Abort request was successfully initiated * tiBusy: No resources available, try again later * tiError: Other errors that prevent the abort request from being * started * Note: * *****************************************************************************/ osGLOBAL bit32 tiTGTIOAbort ( tiRoot_t *tiRoot, tiIORequest_t *taskTag ) { ttdsaXchg_t *ttdsaXchg; ttdsaXchg_t *ttdsaIOAbortXchg; tdsaRoot_t *tdsaRoot = (tdsaRoot_t *) tiRoot->tdData; tdsaContext_t *tdsaAllShared = (tdsaContext_t *)&tdsaRoot->tdsaAllShared; agsaRoot_t *agRoot = (agsaRoot_t *)&(tdsaAllShared->agRootNonInt); agsaIORequest_t *agIORequest = agNULL; agsaIORequest_t *agIOAbortRequest = agNULL; tdsaDeviceData_t *oneDeviceData = agNULL; agsaDevHandle_t *agDevHandle = agNULL; TI_DBG1(("tiTGTIOAbort: start\n")); ttdsaXchg = (ttdsaXchg_t *)taskTag->tdData; if (ttdsaXchg == agNULL) { TI_DBG1(("tiTGTIOAbort: IOError 1 \n")); /* * this exchange has already been freed. * No need to free it */ ostiTargetIOError( tiRoot, taskTag, tiIOFailed, tiDetailAborted ); } else if (ttdsaXchg->IORequestBody.agIORequest.sdkData == agNULL) { TI_DBG1(("tiTGTIOAbort: IOError 2 \n")); /* We have not issued this IO to the salayer. * Abort it right here. */ if (TD_XCHG_GET_STATE(ttdsaXchg) == TD_XCHG_STATE_INACTIVE) { TI_DBG1(("tiTGTIOAbort: wrong DEQUEUE_THIS\n")); } TI_DBG1(("tiTGTIOAbort: IOError 3\n")); ostiTargetIOError( tiRoot, taskTag, tiIOFailed, tiDetailAborted ); TI_DBG1(("tiTGTIOAbort: IOError 4\n")); ttdsaXchgFreeStruct( ttdsaXchg->tiRoot, ttdsaXchg ); TI_DBG1(("tiTGTIOAbort: IOError 5\n")); } else /* to be tested */ { TI_DBG1(("tiTGTIOAbort: aborting; to be tested \n")); /* abort io request itself */ ttdsaIOAbortXchg = ttdsaXchgGetStruct(agRoot); if (ttdsaIOAbortXchg == agNULL) { TI_DBG1(("tiTGTIOAbort: no free xchg structures\n")); // ttdsaDumpallXchg(tiRoot); return tiError; } ttdsaIOAbortXchg->agRoot = agRoot; ttdsaIOAbortXchg->tiRoot = tiRoot; agIOAbortRequest= &(ttdsaXchg->IORequestBody.agIORequest); /* remember IO to be aborted */ ttdsaIOAbortXchg->tiIOToBeAbortedRequest = taskTag; ttdsaIOAbortXchg->XchgToBeAborted = ttdsaXchg; // ttdsaIOAbortXchg->FrameType = SAS_TM; /* io is being aborted */ ttdsaXchg->oslayerAborting = agTRUE; agIORequest = (agsaIORequest_t *)&(ttdsaXchg->IORequestBody.agIORequest); oneDeviceData = ttdsaXchg->DeviceData; if (oneDeviceData == agNULL) { TI_DBG1(("tiTGTIOAbort: oneDeviceData is null; wrong\n")); } else { agDevHandle = oneDeviceData->agDevHandle; ttdsaIOAbortXchg->DeviceData = oneDeviceData; } #ifdef RPM_SOC saSSPAbort(agRoot, agIORequest); #else saSSPAbort(agRoot, agIOAbortRequest,0,agDevHandle,0,agIORequest, agNULL); } return tiSuccess; } osGLOBAL bit32 tiTGTIOAbortAll( tiRoot_t *tiRoot, tiDeviceHandle_t *tiDeviceHandle ) { agsaRoot_t *agRoot = agNULL; tdsaDeviceData_t *oneDeviceData = agNULL; bit32 status = tiError; TI_DBG3(("tiTGTIOAbortAll: start\n")); oneDeviceData = (tdsaDeviceData_t *)tiDeviceHandle->tdData; if (oneDeviceData == agNULL) { TI_DBG1(("tiTGTIOAbortAll: oneDeviceData is NULL!!!\n")); return tiError; } /* for hotplug */ if (oneDeviceData->valid != agTRUE || oneDeviceData->registered != agTRUE || oneDeviceData->tdPortContext == agNULL ) { TI_DBG1(("tiTGTIOAbortAll: NO Device did %d\n", oneDeviceData->id )); TI_DBG1(("tiTGTIOAbortAll: device AddrHi 0x%08x\n", oneDeviceData->SASAddressID.sasAddressHi)); TI_DBG1(("tiTGTIOAbortAll: device AddrLo 0x%08x\n", oneDeviceData->SASAddressID.sasAddressLo)); return tiError; } agRoot = oneDeviceData->agRoot; if (agRoot == agNULL) { TI_DBG1(("tiTGTIOAbortAll: agRoot is NULL!!!\n")); return tiError; } /* this is processed in ossaSSPAbortCB, ossaSATAAbortCB, ossaSMPAbortCB */ oneDeviceData->OSAbortAll = agTRUE; status = tdsaAbortAll(tiRoot, agRoot, oneDeviceData); return status; } /***************************************************************************** * * tiTGTSendTmResp * * Purpose: This function is called to abort an IO previously reported * to oslayer through ostiProcessRequest() function. * * Parameters: * tiRoot: Pointer to driver Instance. * tiIORequest: Pointer to the I/O request context for this I/O. * This context was initially passed to the OS Specific * Module in ostiProcessScsiReq(). * Return: * tiSuccess: Abort request was successfully initiated * tiBusy: No resources available, try again later * tiError: Other errors that prevent the abort request from being * started * Note: * *****************************************************************************/ osGLOBAL bit32 tiTGTSendTmResp( tiRoot_t *tiRoot, tiIORequest_t *tiTMRequest, bit32 status ) { ttdsaXchg_t *ttdsaXchg; sas_resp_t *SASResp; bit32 tdStatus; TI_DBG1(("tiTGTSendTmResp: start 1\n")); ttdsaXchg = (ttdsaXchg_t *)tiTMRequest->tdData; /* set the response and send it */ /* response status is 0 */ /* status is TM status */ TI_DBG1(("tiTGTSendTmResp: start 2\n")); SASResp = (sas_resp_t *)ttdsaXchg->resp.virtAddr; TI_DBG1(("tiTGTSendTmResp: start 3\n")); if (ttdsaXchg->FrameType == SAS_TM) { SASResp->agResp.status = 0; SASResp->agResp.dataPres = RESPONSE_DATA; OSSA_WRITE_BE_32(agRoot, SASResp->agResp.responsedataLen, 0, RESPONSE_DATA_LEN); OSSA_WRITE_BE_32(agRoot, SASResp->agResp.senseDataLen, 0, 0); switch (status) { case tiSuccess: TI_DBG2(("tiTGTSendTmResp: tiSuccess\n")); SASResp->RespData[3] = AGSA_TASK_MANAGEMENT_FUNCTION_SUCCEEDED; break; case tiError: TI_DBG1(("tiTGTSendTmResp: tiError\n")); SASResp->RespData[3] = AGSA_TASK_MANAGEMENT_FUNCTION_FAILED; break; case tiBusy: TI_DBG1(("tiTGTSendTmResp: tibusy\n")); SASResp->RespData[3] = AGSA_TASK_MANAGEMENT_FUNCTION_FAILED; break; case tiIONoDevice: TI_DBG1(("tiTGTSendTmResp: tiionodevicee\n")); SASResp->RespData[3] = AGSA_TASK_MANAGEMENT_FUNCTION_FAILED; break; case tiMemoryTooLarge: TI_DBG1(("tiTGTSendTmResp: timemorytoolarge\n")); SASResp->RespData[3] = AGSA_TASK_MANAGEMENT_FUNCTION_FAILED; break; case tiMemoryNotAvail: TI_DBG1(("tiTGTSendTmResp: timemorynotavail\n")); SASResp->RespData[3] = AGSA_TASK_MANAGEMENT_FUNCTION_FAILED; break; case tiInvalidHandle: TI_DBG1(("tiTGTSendTmResp: tiinvalidhandle\n")); SASResp->RespData[3] = AGSA_TASK_MANAGEMENT_FUNCTION_FAILED; break; case tiNotSupported: TI_DBG1(("tiTGTSendTmResp: tiNotsupported\n")); SASResp->RespData[3] = AGSA_TASK_MANAGEMENT_FUNCTION_NOT_SUPPORTED; break; case tiReject: TI_DBG1(("tiTGTSendTmResp: tireject\n")); SASResp->RespData[3] = AGSA_TASK_MANAGEMENT_FUNCTION_FAILED; break; case tiIncorrectLun: TI_DBG1(("tiTGTSendTmResp: tiincorrectlun\n")); SASResp->RespData[3] = AGSA_INCORRECT_LOGICAL_UNIT_NUMBER; break; default: TI_DBG1(("tiTGTSendTmResp: default\n")); SASResp->RespData[3] = AGSA_TASK_MANAGEMENT_FUNCTION_FAILED; break; } ttdsaXchg->resp.length = sizeof(agsaSSPResponseInfoUnit_t) + RESPONSE_DATA_LEN; ttdsaXchg->statusSent = agTRUE; } else { TI_DBG1(("tiTGTSendTmResp: not TM frame\n")); return tiError; } tdStatus = ttdsaSendResp(ttdsaXchg->agRoot, ttdsaXchg); if (tdStatus == AGSA_RC_SUCCESS) { TI_DBG1(("tiTGTSendTmResp: send success\n")); return tiSuccess; } else if (tdStatus == AGSA_RC_FAILURE) { TI_DBG1(("tiTGTSendTmResp: sending not successful\n")); return tiError; } else { TI_DBG1(("tiTGTSendTmResp: send busy\n")); return tiBusy; } #ifdef REMOVED tiTGTSetResp(tiRoot, tiTMRequest, 0, 0, 0); #endif #ifdef REMOVED if (ttdsaXchg->resp.length != 0) { TI_DBG1(("tiTGTSendTmResp: respsonse is set \n")); TI_DBG1(("tiTGTSendTmResp: resp.length 0x%x\n", ttdsaXchg->resp.length)); ttdsaXchg->responseSent = agTRUE; ttdsaSendResp(ttdsaXchg->agRoot, ttdsaXchg); } else { /* no respsonse is set, direct call */ TI_DBG1(("tiTGTSendTmResp: direct call\n")); tiTGTSetResp(tiRoot, tiTMRequest, 0, 0, 0); ttdsaXchg->responseSent = agTRUE; ttdsaSendResp(ttdsaXchg->agRoot, ttdsaXchg); } #define TASK_MANAGEMENT_FUNCTION_COMPLETE 0x0 #define INVALID_FRAME 0x2 #define TASK_MANAGEMENT_FUNCTION_NOT_SUPPORTED 0x4 #define TASK_MANAGEMENT_FUNCTION_FAILED 0x5 #define TASK_MANAGEMENT_FUNCTION_SUCCEEDED 0x8 #define INVALID_LOGICAL_UNIT_NUMBER 0x9 #endif } /***************************************************************************** * * tiTGTSenseBufferGet * * Purpose: This function is called to get the address of sense buffer from * the target specific Transport Dependent Layer. * * Parameters: * tiRoot: Pointer to driver/port instance. * tiIORequest: I/O request context. * length: Lenght in bytes of the sense buffer. * * Return: none * * Note: * *****************************************************************************/ osGLOBAL void *tiTGTSenseBufferGet( tiRoot_t *tiRoot, tiIORequest_t *tiIORequest, bit32 length ) { ttdsaXchg_t *ttdsaXchg; ttdsaXchg = (ttdsaXchg_t *)tiIORequest->tdData; TI_DBG4(("tiTGTSenseBufferGet: start\n")); OS_ASSERT((length <= 64), "length too big in tiTGTSenseBufferGet"); return &ttdsaXchg->resp.virtAddr[sizeof(agsaSSPResponseInfoUnit_t)]; } /***************************************************************************** * * tiTGTSetResp * * Purpose: This function is called when the target OS Specific Module is ready * to send a response with the next tiTGTIOStart() * function call. This function allows the TD Layer to setup its * portion of the status and mark it to be sent on the next * tiTGTIOStart() function call. * * Parameters: * tiRoot: Pointer to driver Instance. * tiIORequest: Pointer to the I/O request context for this I/O. * This context was initially passed to the OS Specific Module * in ostiProcessScsiReq(). * dataSentLength: How much data sent or received for this Request. * ScsiStatus: Status for this SCSI command. * senseLength: Length of sense data if any. * * Return: none * * Note: * *****************************************************************************/ osGLOBAL void tiTGTSetResp( tiRoot_t *tiRoot, tiIORequest_t *tiIORequest, bit32 dataSentLength, bit8 ScsiStatus, bit32 senseLength ) { /* no call to saSSPStart() in this function */ /* response is normally for task management sense is for command with error need to know this is for TM or cmd */ /* tiTGTSetResp(rdRoot->pTiRoot, rdIORequest->tiIORequest, dataSentLength, ScsiStatus, senseLength); */ ttdsaXchg_t *ttdsaXchg; tdsaRoot_t *tdsaRoot = (tdsaRoot_t *)tiRoot->tdData; #ifdef REMOVED agsaSSPTargetResponse_t *agSSPTargetResp; #endif sas_resp_t *SASResp; bit32 TotalRespLen = 0; TI_DBG4 (("tiTGTSetResp: start\n")); TI_DBG4 (("tiTGTSetResp: datelen %d senselen %d\n", dataSentLength, senseLength)); ttdsaXchg = (ttdsaXchg_t *)tiIORequest->tdData; SASResp = (sas_resp_t *)ttdsaXchg->resp.virtAddr; SASResp->agResp.status = ScsiStatus; if (ttdsaXchg->FrameType == SAS_TM) { TI_DBG1(("tiTGTSetResp: TM\n")); if (senseLength != 0) { TI_DBG1 (("tiTGTSetResp: non-zero sensedatalen for TM\n")); return; } SASResp->agResp.dataPres = RESPONSE_DATA; OSSA_WRITE_BE_32(agRoot, SASResp->agResp.responsedataLen, 0, RESPONSE_DATA_LEN); OSSA_WRITE_BE_32(agRoot, SASResp->agResp.senseDataLen, 0, 0); SASResp->RespData[3] = AGSA_TASK_MANAGEMENT_FUNCTION_NOT_SUPPORTED; TotalRespLen = sizeof(agsaSSPResponseInfoUnit_t) + RESPONSE_DATA_LEN; } else { if (senseLength == 0) { TI_DBG4 (("tiTGTSetResp: CMND, no data\n")); /* good and no data present */ SASResp->agResp.dataPres = NO_DATA; OSSA_WRITE_BE_32(agRoot, SASResp->agResp.responsedataLen, 0, 0); OSSA_WRITE_BE_32(agRoot, SASResp->agResp.senseDataLen, 0, 0); TotalRespLen = sizeof(agsaSSPResponseInfoUnit_t); /* collapse good response with READ */ if (ttdsaXchg->XchType == AGSA_SSP_TGT_READ_DATA) { TI_DBG4(("tiTGTSetResp: read rsp collapse\n")); if (tdsaRoot->autoGoodRSP & READ_GOOD_RESPONSE) ttdsaXchg->readRspCollapsed = agTRUE; } /* collapse good response with WRITE */ if (ttdsaXchg->XchType == AGSA_SSP_TGT_WRITE_DATA) { TI_DBG4(("tiTGTSetResp: write rsp collapse\n")); if (tdsaRoot->autoGoodRSP & WRITE_GOOD_RESPONSE) { if (tiIS_SPC(TI_TIROOT_TO_AGROOT(tiRoot))) { ttdsaXchg->wrtRspCollapsed = agFALSE; } else { ttdsaXchg->wrtRspCollapsed = agTRUE; } } } } else { TI_DBG4 (("tiTGTSetResp: CMND, sense data\n")); /* bad and sense data */ SASResp->agResp.dataPres = SENSE_DATA; OSSA_WRITE_BE_32(agRoot, SASResp->agResp.responsedataLen, 0, 0); OSSA_WRITE_BE_32(agRoot, SASResp->agResp.senseDataLen, 0, senseLength); TotalRespLen = sizeof(agsaSSPResponseInfoUnit_t) + senseLength; } } ttdsaXchg->statusSent = agTRUE; TI_DBG4(("tiTGTSetResp: ttdsaXchg %p\n", ttdsaXchg)); TI_DBG4(("tiTGTSetResp: TotalRespLen 0x%x \n", TotalRespLen)); TI_DBG4(("tiTGTSetResp: upper 0x%x \n", ttdsaXchg->resp.phyAddrUpper)); TI_DBG4(("tiTGTSetResp: lower 0x%x \n", ttdsaXchg->resp.phyAddrLower)); /* set the correct response length */ ttdsaXchg->resp.length = TotalRespLen; dumpresp((bit8 *)ttdsaXchg->resp.virtAddr, ttdsaXchg->resp.length); #ifdef REMOVED /* send TM reponse (which has only response data not sense data here since ramdisk does not call IOstart for this */ if (ttdsaXchg->FrameType == SAS_TM) { TI_DBG1(("tiTGTSetResp: respsonse is set \n")); TI_DBG1(("tiTGTSetResp: resp.length 0x%x\n", ttdsaXchg->resp.length)); ttdsaSendResp(ttdsaXchg->agRoot, ttdsaXchg); } #endif #ifdef REMOVED /* sas response */ agSSPTargetResp = &(ttdsaXchg->IORequestBody.transport.SAS.agSASRequestBody.sspTargetResponse); agSSPTargetResp->agTag = ttdsaXchg->tag; agSSPTargetResp->respBufLength = TotalRespLen; agSSPTargetResp->respBufUpper = ttdsaXchg->IORequestBody.transport.SAS.agSASRequestBody.sspTargetResponse.respBufUpper; agSSPTargetResp->respBufLower = ttdsaXchg->IORequestBody.transport.SAS.agSASRequestBody.sspTargetResponse.respBufLower; TI_DBG4(("tiTGTSetResp: len 0x%x \n", ttdsaXchg->IORequestBody.transport.SAS.agSASRequestBody.sspTargetResponse.respBufLength)); TI_DBG4(("tiTGTSetResp: upper 0x%x \n", ttdsaXchg->IORequestBody.transport.SAS.agSASRequestBody.sspTargetResponse.respBufUpper)); TI_DBG4(("tiTGTSetResp: lower 0x%x \n", ttdsaXchg->IORequestBody.transport.SAS.agSASRequestBody.sspTargetResponse.respBufLower)); #endif return; } /****************************************************************************** * * tiTGTGetDeviceHandles * * Purpose: This routine is called to to return the device handles for each * device currently available. * * Parameters: * tiRoot: Pointer to driver Instance. * agDev[]: Array to receive pointers to the device handles. * maxDevs: Number of device handles which will fit in array pointed * by agDev. * Return: * Number of device handle slots present (however, only maxDevs * are copied into tiDev[]) which may be greater than the number of * handles actually present. * * Note: * ******************************************************************************/ osGLOBAL bit32 tiTGTGetDeviceHandles( tiRoot_t *tiRoot, tiPortalContext_t *tiPortalContext, tiDeviceHandle_t *tiDev[], bit32 maxDevs ) { tdsaRoot_t *tdsaRoot = (tdsaRoot_t *) tiRoot->tdData; tdsaContext_t *tdsaAllShared = (tdsaContext_t *)&tdsaRoot->tdsaAllShared; ttdsaTgt_t *Target = (ttdsaTgt_t *)tdsaAllShared->ttdsaTgt; bit32 deviceToReturn; bit32 devicePresent=0; bit32 deviceIndex=0; tdList_t *PortContextList; tdsaPortContext_t *onePortContext = agNULL; tdList_t *DeviceListList; tdsaDeviceData_t *oneDeviceData = agNULL; bit32 found = agFALSE; TI_DBG4 (("tiTGTGetDeviceHandles: start\n")); /* Check boundary condition */ if (maxDevs > Target->OperatingOption.MaxTargets) { deviceToReturn = Target->OperatingOption.MaxTargets; } else { deviceToReturn = maxDevs; } /* make sure tiPortalContext is valid */ PortContextList = tdsaAllShared->MainPortContextList.flink; while (PortContextList != &(tdsaAllShared->MainPortContextList)) { onePortContext = TDLIST_OBJECT_BASE(tdsaPortContext_t, MainLink, PortContextList); if (onePortContext->tiPortalContext == tiPortalContext) { TI_DBG4(("tiTGTGetDeviceHandles: found; oneportContext ID %d\n", onePortContext->id)); found = agTRUE; break; } PortContextList = PortContextList->flink; } if (found == agFALSE) { TI_DBG4(("tiTGTGetDeviceHandles: No corressponding tdsaPortContext\n")); return 0; } /* go through device list and returns them */ DeviceListList = tdsaAllShared->MainDeviceList.flink; while (DeviceListList != &(tdsaAllShared->MainDeviceList)) { oneDeviceData = TDLIST_OBJECT_BASE(tdsaDeviceData_t, MainLink, DeviceListList); TI_DBG4(("tiTGTGetDeviceHandles: pid %d did %d\n", onePortContext->id, oneDeviceData->id)); TI_DBG4(("tiTGTGetDeviceHandles: device AddrHi 0x%08x\n", oneDeviceData->SASAddressID.sasAddressHi)); TI_DBG4(("tiTGTGetDeviceHandles: device AddrLo 0x%08x\n", oneDeviceData->SASAddressID.sasAddressLo)); TI_DBG4(("tiTGTGetDeviceHandles: handle %p\n", &(oneDeviceData->tiDeviceHandle))); if (oneDeviceData->valid == agTRUE) { TI_DBG4(("tiTGTGetDeviceHandles: valid deviceindex %d devicePresent %d\n", deviceIndex, devicePresent)); tiDev[deviceIndex] = &(oneDeviceData->tiDeviceHandle); devicePresent++; } else { tiDev[deviceIndex] = agNULL; TI_DBG4(("tiTGTGetDeviceHandles: not valid deviceindex %d devicePresent %d\n", deviceIndex, devicePresent)); } deviceIndex++; if (devicePresent >= deviceToReturn ) { break; } DeviceListList = DeviceListList->flink; } return devicePresent; } /****************************************************************************** * * tiTGTGetDeviceInfo * * Purpose: This routine is called to to return the device information for * specified device handle. * * Parameters: * tiRoot: Pointer to driver Instance. * tiDeviceHandle: device handle associated with the device for which * information is queried * tiDeviceInfo: device information structure containing address and name. * * Return: * tiSuccess: if the device handle is valid. * tiError : if the device handle is not valid. * * Note: * ******************************************************************************/ osGLOBAL bit32 tiTGTGetDeviceInfo( tiRoot_t *tiRoot, tiDeviceHandle_t *tiDeviceHandle, tiDeviceInfo_t *tiDeviceInfo) { tdsaDeviceData_t *oneDeviceData = agNULL; TI_DBG4 (("tiTGTGetDeviceInfo: start\n")); if (tiDeviceHandle == agNULL) { TI_DBG4 (("tiTGTGetDeviceInfo: tiDeviceHandle is NULL\n")); return tiError; } oneDeviceData = (tdsaDeviceData_t *)tiDeviceHandle->tdData; if (oneDeviceData == agNULL) { TI_DBG4 (("tiTGTGetDeviceInfo: oneDeviceData is NULL\n")); return tiError; } /* filling in the link rate */ if (oneDeviceData->registered == agTRUE) { tiDeviceInfo->info.devType_S_Rate = oneDeviceData->agDeviceInfo.devType_S_Rate; } else { tiDeviceInfo->info.devType_S_Rate = oneDeviceData->agDeviceInfo.devType_S_Rate & 0x0f; } /* temp just returning local and remote SAS address; doesn't have a name */ tiDeviceInfo->remoteName = (char *)&(oneDeviceData->tdPortContext->sasRemoteAddressHi); tiDeviceInfo->remoteAddress = (char *)&(oneDeviceData->tdPortContext->sasRemoteAddressLo); tiDeviceInfo->localName = (char *)&(oneDeviceData->tdPortContext->sasLocalAddressHi); tiDeviceInfo->localAddress = (char *)&(oneDeviceData->tdPortContext->sasLocalAddressLo); return tiSuccess; } /***************************************************************************** *! \brief ttdssIOAbortedHandler * * Purpose: This function processes I/Os completed and returned by SAS/SATA lower * layer with agIOStatus = OSSA_IO_ABORTED * * \param agRoot: pointer to port instance * \param agIORequest: pointer to I/O request * \param agIOStatus: I/O status given by LL layer * \param agIOInfoLen: lenth of complete SAS RESP frame * \param agParam A Handle used to refer to the response frame or handle * of abort request * \param agOtherInfo Residual count * \return: None * * *****************************************************************************/ /* see itdosIOCompleted() and itdinit.c and itdIoAbortedHandler in itdio.c*/ osGLOBAL void ttdssIOAbortedHandler ( agsaRoot_t *agRoot, agsaIORequest_t *agIORequest, bit32 agIOStatus, bit32 agIOInfoLen, void *agParam, bit32 agOtherInfo ) { tdsaRootOsData_t *osData = (tdsaRootOsData_t *)agRoot->osData; tiRoot_t *tiRoot = (tiRoot_t *)osData->tiRoot; tdIORequestBody_t *tdIORequestBody; TI_DBG1(("itdssIOAbortedHandler: start\n")); tdIORequestBody = (tdIORequestBody_t *)agIORequest->osData; if (agIOStatus != OSSA_IO_ABORTED) { TI_DBG1(("itdssIOAbortedHandler: incorrect agIOStatus 0x%x\n", agIOStatus)); } ostiTargetIOError( tiRoot, tdIORequestBody->tiIORequest, tiIOFailed, tiDetailAborted ); return; }