📄 mptscsih.c
字号:
if (ioc->bus_type != SAS) return; /* Not supported for hidden raid components */ if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) return; if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) { dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: no msg frames!!\n", ioc->name,__FUNCTION__)); return; } SEPMsg = (SEPRequest_t *)mf; SEPMsg->Function = MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR; SEPMsg->Bus = vtarget->channel; SEPMsg->TargetID = vtarget->id; SEPMsg->Action = MPI_SEP_REQ_ACTION_WRITE_STATUS; SEPMsg->SlotStatus = SlotStatus; devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending SEP cmd=%x channel=%d id=%d\n", ioc->name, SlotStatus, SEPMsg->Bus, SEPMsg->TargetID)); mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);}#ifdef CONFIG_FUSION_LOGGING/** * mptscsih_info_scsiio - debug print info on reply frame * @ioc: Pointer to MPT_ADAPTER structure * @sc: original scsi cmnd pointer * @pScsiReply: Pointer to MPT reply frame * * MPT_DEBUG_REPLY needs to be enabled to obtain this info * * Refer to lsi/mpi.h. **/static voidmptscsih_info_scsiio(MPT_ADAPTER *ioc, struct scsi_cmnd *sc, SCSIIOReply_t * pScsiReply){ char *desc = NULL; char *desc1 = NULL; u16 ioc_status; u8 skey, asc, ascq; ioc_status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK; switch (ioc_status) { case MPI_IOCSTATUS_SUCCESS: desc = "success"; break; case MPI_IOCSTATUS_SCSI_INVALID_BUS: desc = "invalid bus"; break; case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: desc = "invalid target_id"; break; case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: desc = "device not there"; break; case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: desc = "data overrun"; break; case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: desc = "data underrun"; break; case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: desc = "I/O data error"; break; case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: desc = "protocol error"; break; case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: desc = "task terminated"; break; case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: desc = "residual mismatch"; break; case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: desc = "task management failed"; break; case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: desc = "IOC terminated"; break; case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: desc = "ext terminated"; break; default: desc = ""; break; } switch (pScsiReply->SCSIStatus) { case MPI_SCSI_STATUS_SUCCESS: desc1 = "success"; break; case MPI_SCSI_STATUS_CHECK_CONDITION: desc1 = "check condition"; break; case MPI_SCSI_STATUS_CONDITION_MET: desc1 = "condition met"; break; case MPI_SCSI_STATUS_BUSY: desc1 = "busy"; break; case MPI_SCSI_STATUS_INTERMEDIATE: desc1 = "intermediate"; break; case MPI_SCSI_STATUS_INTERMEDIATE_CONDMET: desc1 = "intermediate condmet"; break; case MPI_SCSI_STATUS_RESERVATION_CONFLICT: desc1 = "reservation conflict"; break; case MPI_SCSI_STATUS_COMMAND_TERMINATED: desc1 = "command terminated"; break; case MPI_SCSI_STATUS_TASK_SET_FULL: desc1 = "task set full"; break; case MPI_SCSI_STATUS_ACA_ACTIVE: desc1 = "aca active"; break; case MPI_SCSI_STATUS_FCPEXT_DEVICE_LOGGED_OUT: desc1 = "fcpext device logged out"; break; case MPI_SCSI_STATUS_FCPEXT_NO_LINK: desc1 = "fcpext no link"; break; case MPI_SCSI_STATUS_FCPEXT_UNASSIGNED: desc1 = "fcpext unassigned"; break; default: desc1 = ""; break; } scsi_print_command(sc); printk(MYIOC_s_DEBUG_FMT "\tfw_channel = %d, fw_id = %d\n", ioc->name, pScsiReply->Bus, pScsiReply->TargetID); printk(MYIOC_s_DEBUG_FMT "\trequest_len = %d, underflow = %d, " "resid = %d\n", ioc->name, scsi_bufflen(sc), sc->underflow, scsi_get_resid(sc)); printk(MYIOC_s_DEBUG_FMT "\ttag = %d, transfer_count = %d, " "sc->result = %08X\n", ioc->name, le16_to_cpu(pScsiReply->TaskTag), le32_to_cpu(pScsiReply->TransferCount), sc->result); printk(MYIOC_s_DEBUG_FMT "\tiocstatus = %s (0x%04x), " "scsi_status = %s (0x%02x), scsi_state = (0x%02x)\n", ioc->name, desc, ioc_status, desc1, pScsiReply->SCSIStatus, pScsiReply->SCSIState); if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) { skey = sc->sense_buffer[2] & 0x0F; asc = sc->sense_buffer[12]; ascq = sc->sense_buffer[13]; printk(MYIOC_s_DEBUG_FMT "\t[sense_key,asc,ascq]: " "[0x%02x,0x%02x,0x%02x]\n", ioc->name, skey, asc, ascq); } /* * Look for + dump FCP ResponseInfo[]! */ if (pScsiReply->SCSIState & MPI_SCSI_STATE_RESPONSE_INFO_VALID && pScsiReply->ResponseInfo) printk(MYIOC_s_DEBUG_FMT "response_info = %08xh\n", ioc->name, le32_to_cpu(pScsiReply->ResponseInfo));}#endif/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* * mptscsih_io_done - Main SCSI IO callback routine registered to * Fusion MPT (base) driver * @ioc: Pointer to MPT_ADAPTER structure * @mf: Pointer to original MPT request frame * @r: Pointer to MPT reply frame (NULL if TurboReply) * * This routine is called from mpt.c::mpt_interrupt() at the completion * of any SCSI IO request. * This routine is registered with the Fusion MPT (base) driver at driver * load/init time via the mpt_register() API call. * * Returns 1 indicating alloc'd request frame ptr should be freed. */intmptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr){ struct scsi_cmnd *sc; MPT_SCSI_HOST *hd; SCSIIORequest_t *pScsiReq; SCSIIOReply_t *pScsiReply; u16 req_idx, req_idx_MR; VirtDevice *vdevice; VirtTarget *vtarget; hd = shost_priv(ioc->sh); req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); req_idx_MR = (mr != NULL) ? le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx; if ((req_idx != req_idx_MR) || (mf->u.frame.linkage.arg1 == 0xdeadbeaf)) { printk(MYIOC_s_ERR_FMT "Received a mf that was already freed\n", ioc->name); printk (MYIOC_s_ERR_FMT "req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n", ioc->name, req_idx, req_idx_MR, mf, mr, mptscsih_get_scsi_lookup(ioc, req_idx_MR)); return 0; } sc = mptscsih_getclear_scsi_lookup(ioc, req_idx); if (sc == NULL) { MPIHeader_t *hdr = (MPIHeader_t *)mf; /* Remark: writeSDP1 will use the ScsiDoneCtx * If a SCSI I/O cmd, device disabled by OS and * completion done. Cannot touch sc struct. Just free mem. */ if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST) printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n", ioc->name); mptscsih_freeChainBuffers(ioc, req_idx); return 1; } if ((unsigned char *)mf != sc->host_scribble) { mptscsih_freeChainBuffers(ioc, req_idx); return 1; } sc->host_scribble = NULL; sc->result = DID_OK << 16; /* Set default reply as OK */ pScsiReq = (SCSIIORequest_t *) mf; pScsiReply = (SCSIIOReply_t *) mr; if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){ dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n", ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag)); }else{ dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n", ioc->name, mf, mr, sc, req_idx)); } if (pScsiReply == NULL) { /* special context reply handling */ ; } else { u32 xfer_cnt; u16 status; u8 scsi_state, scsi_status; u32 log_info; status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK; scsi_state = pScsiReply->SCSIState; scsi_status = pScsiReply->SCSIStatus; xfer_cnt = le32_to_cpu(pScsiReply->TransferCount); scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt); log_info = le32_to_cpu(pScsiReply->IOCLogInfo); /* * if we get a data underrun indication, yet no data was * transferred and the SCSI status indicates that the * command was never started, change the data underrun * to success */ if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 && (scsi_status == MPI_SCSI_STATUS_BUSY || scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT || scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) { status = MPI_IOCSTATUS_SUCCESS; } if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) mptscsih_copy_sense_data(sc, hd, mf, pScsiReply); /* * Look for + dump FCP ResponseInfo[]! */ if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID && pScsiReply->ResponseInfo) { printk(MYIOC_s_NOTE_FMT "[%d:%d:%d:%d] " "FCP_ResponseInfo=%08xh\n", ioc->name, sc->device->host->host_no, sc->device->channel, sc->device->id, sc->device->lun, le32_to_cpu(pScsiReply->ResponseInfo)); } switch(status) { case MPI_IOCSTATUS_BUSY: /* 0x0002 */ /* CHECKME! * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry) * But not: DID_BUS_BUSY lest one risk * killing interrupt handler:-( */ sc->result = SAM_STAT_BUSY; break; case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */ case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */ sc->result = DID_BAD_TARGET << 16; break; case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */ /* Spoof to SCSI Selection Timeout! */ if (ioc->bus_type != FC) sc->result = DID_NO_CONNECT << 16; /* else fibre, just stall until rescan event */ else sc->result = DID_REQUEUE << 16; if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF) hd->sel_timeout[pScsiReq->TargetID]++; vdevice = sc->device->hostdata; if (!vdevice) break; vtarget = vdevice->vtarget; if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) { mptscsih_issue_sep_command(ioc, vtarget, MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED); vtarget->tflags &= ~MPT_TARGET_FLAGS_LED_ON; } break; case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */ if ( ioc->bus_type == SAS ) { u16 ioc_status = le16_to_cpu(pScsiReply->IOCStatus); if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) { if ((log_info & SAS_LOGINFO_MASK) == SAS_LOGINFO_NEXUS_LOSS) { sc->result = (DID_BUS_BUSY << 16); break; } } } else if (ioc->bus_type == FC) { /* * The FC IOC may kill a request for variety of * reasons, some of which may be recovered by a * retry, some which are unlikely to be * recovered. Return DID_ERROR instead of * DID_RESET to permit retry of the command, * just not an infinite number of them */ sc->result = DID_ERROR << 16; break; } /* * Allow non-SAS & non-NEXUS_LOSS to drop into below code */ case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */ case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */ /* Linux handles an unsolicited DID_RESET better * than an unsolicited DID_ABORT. */ sc->result = DID_RESET << 16; break; case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */ scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt); if((xfer_cnt==0)||(sc->underflow > xfer_cnt)) sc->result=DID_SOFT_ERROR << 16; else /* Sufficient data transfer occurred */ sc->result = (DID_OK << 16) | scsi_status; dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n", ioc->name, sc->result, sc->device->channel, sc->device->id)); break; case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */ /* * Do upfront check for valid SenseData and give it * precedence! */ sc->result = (DID_OK << 16) | scsi_status; if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) { /* Have already saved the status and sense data */ ; } else { if (xfer_cnt < sc->underflow) { if (scsi_status == SAM_STAT_BUSY) sc->result = SAM_STAT_BUSY; else sc->result = DID_SOFT_ERROR << 16; } if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) { /* What to do? */ sc->result = DID_SOFT_ERROR << 16; } else if (scsi_state & MPI_SCSI_STATE_TERMINATED) { /* Not real sure here either... */ sc->result = DID_RESET << 16; } } dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT " sc->underflow={report ERR if < %02xh bytes xfer'd}\n", ioc->name, sc->underflow)); dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT " ActBytesXferd=%02xh\n", ioc->name, xfer_cnt)); /* Report Queue Full */ if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL) mptscsih_report_queue_full(sc, pScsiReply, pScsiReq); break; case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */ scsi_set_resid(sc, 0); case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */ case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */ sc->result = (DID_OK << 16) | scsi_status; if (scsi_state == 0) { ; } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) { /* * If running against circa 200003dd 909 MPT f/w, * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL * (QUEUE_FULL) returned from device! --> get 0x0000?128 * and with SenseBytes set to 0. */ if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL) mptscsih_report_queue_full(sc, pScsiReply, pScsiReq); } else if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS) ) { /* * What to do? */ sc->result = DID_SOFT_ERROR << 16; } else if (scsi_state & MPI_SCSI_STATE_TERMINATED) { /* Not real sure here either... */ sc->result = DID_RESET << 16; } else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -