📄 mptscsih.c
字号:
if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) { dfailprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n", ioc->name, pReq->CDB[0], SCpnt)); return FAILED; } /* Update the tracking arrays. * If chainSge == NULL, update ReqToChain, else ChainToChain */ if (chainSge) { ioc->ChainToChain[chain_idx] = newIndex; } else { ioc->ReqToChain[req_idx] = newIndex; } chain_idx = newIndex; chain_dma_off = ioc->req_sz * chain_idx; /* Populate the chainSGE for the current buffer. * - Set chain buffer pointer to psge and fill * out the Address and Flags fields. */ chainSge = (char *) psge; dsgprintk((KERN_INFO " Current buff @ %p (index 0x%x)", psge, req_idx)); /* Start the SGE for the next buffer */ psge = (char *) (ioc->ChainBuffer + chain_dma_off); sgeOffset = 0; sg_done = 0; dsgprintk((KERN_INFO " Chain buff @ %p (index 0x%x)\n", psge, chain_idx)); /* Start the SGE for the next buffer */ goto nextSGEset; } return SUCCESS;} /* mptscsih_AddSGE() *//*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* * 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; hd = (MPT_SCSI_HOST *) ioc->sh->hostdata; 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, hd->ScsiLookup[req_idx_MR]); return 0; } sc = hd->ScsiLookup[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; } 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((MYIOC_s_INFO_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((MYIOC_s_INFO_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; status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK; scsi_state = pScsiReply->SCSIState; scsi_status = pScsiReply->SCSIStatus; xfer_cnt = le32_to_cpu(pScsiReply->TransferCount); sc->resid = sc->request_bufflen - xfer_cnt; /* * 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; } dreplyprintk((KERN_NOTICE "Reply ha=%d id=%d lun=%d:\n" "IOCStatus=%04xh SCSIState=%02xh SCSIStatus=%02xh\n" "resid=%d bufflen=%d xfer_cnt=%d\n", ioc->id, sc->device->id, sc->device->lun, status, scsi_state, scsi_status, sc->resid, sc->request_bufflen, xfer_cnt)); 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(KERN_NOTICE "ha=%d id=%d lun=%d: " "FCP_ResponseInfo=%08xh\n", ioc->id, 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]++; break; case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */ case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */ 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 */ sc->resid = sc->request_bufflen - 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((KERN_NOTICE "RESIDUAL_MISMATCH: result=%x on id=%d\n", sc->result, 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((KERN_NOTICE " sc->underflow={report ERR if < %02xh bytes xfer'd}\n", sc->underflow)); dreplyprintk((KERN_NOTICE " ActBytesXferd=%02xh\n", 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 */ sc->resid=0; case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */ case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */ if (scsi_status == MPI_SCSI_STATUS_BUSY) sc->result = (DID_BUS_BUSY << 16) | scsi_status; else 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) { /* Device Inq. data indicates that it supports * QTags, but rejects QTag messages. * This command completed OK. * * Not real sure here either so do nothing... */ } if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL) mptscsih_report_queue_full(sc, pScsiReply, pScsiReq); /* Add handling of: * Reservation Conflict, Busy, * Command Terminated, CHECK */ break; case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */ sc->result = DID_SOFT_ERROR << 16; break; case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */ case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */ case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */ case MPI_IOCSTATUS_RESERVED: /* 0x0005 */ case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */ case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */ case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */ case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */ case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */ default: /* * What to do? */ sc->result = DID_SOFT_ERROR << 16; break; } /* switch(status) */ dreplyprintk((KERN_NOTICE " sc->result is %08xh\n", sc->result)); } /* end of address reply case */ /* Unmap the DMA buffers, if any. */ if (sc->use_sg) { pci_unmap_sg(ioc->pcidev, (struct scatterlist *) sc->request_buffer, sc->use_sg, sc->sc_data_direction); } else if (sc->request_bufflen) { pci_unmap_single(ioc->pcidev, sc->SCp.dma_handle, sc->request_bufflen, sc->sc_data_direction); } hd->ScsiLookup[req_idx] = NULL; sc->scsi_done(sc); /* Issue the command callback */ /* Free Chain buffers */ mptscsih_freeChainBuffers(ioc, req_idx); return 1;}/* * mptscsih_flush_running_cmds - For each command found, search * Scsi_Host instance taskQ and reply to OS. * Called only if recovering from a FW reload. * @hd: Pointer to a SCSI HOST structure * * Returns: None. * * Must be called while new I/Os are being queued. */static voidmptscsih_flush_running_cmds(MPT_SCSI_HOST *hd){ MPT_ADAPTER *ioc = hd->ioc; struct scsi_cmnd *SCpnt; MPT_FRAME_HDR *mf; int ii; int max = ioc->req_depth; dprintk((KERN_INFO MYNAM ": flush_ScsiLookup called\n")); for (ii= 0; ii < max; ii++) { if ((SCpnt = hd->ScsiLookup[ii]) != NULL) { /* Command found. */ /* Null ScsiLookup index */ hd->ScsiLookup[ii] = NULL; mf = MPT_INDEX_2_MFPTR(ioc, ii); dmfprintk(( "flush: ScsiDone (mf=%p,sc=%p)\n", mf, SCpnt)); /* Set status, free OS resources (SG DMA buffers) * Do OS callback * Free driver resources (chain, msg buffers) */ if (SCpnt->use_sg) { pci_unmap_sg(ioc->pcidev, (struct scatterlist *) SCpnt->request_buffer, SCpnt->use_sg, SCpnt->sc_data_direction); } else if (SCpnt->request_bufflen) { pci_unmap_single(ioc->pcidev, SCpnt->SCp.dma_handle, SCpnt->request_bufflen, SCpnt->sc_data_direction); } SCpnt->result = DID_RESET << 16; SCpnt->host_scribble = NULL; /* Free Chain buffers */ mptscsih_freeChainBuffers(ioc, ii); /* Free Message frames */ mpt_free_msg_frame(ioc, mf); SCpnt->scsi_done(SCpnt); /* Issue the command callback */ } } return;}/* * mptscsih_search_running_cmds - Delete any commands associated * with the specified target and lun. Function called only * when a lun is disable by mid-layer. * Do NOT access the referenced scsi_cmnd structure or * members. Will cause either a paging or NULL ptr error. * (BUT, BUT, BUT, the code does reference it! - mdr) * @hd: Pointer to a SCSI HOST structure * @vdevice: per device private data * * Returns: None. * * Called from slave_destroy. */static voidmptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice){ SCSIIORequest_t *mf = NULL; int ii; int max = hd->ioc->req_depth; struct scsi_cmnd *sc; dsprintk((KERN_INFO MYNAM ": search_running target %d lun %d max %d\n", vdevice->vtarget->target_id, vdevice->lun, max)); for (ii=0; ii < max; ii++) { if ((sc = hd->ScsiLookup[ii]) != NULL) { mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(hd->ioc, ii); dsprintk(( "search_running: found (sc=%p, mf = %p) target %d, lun %d \n", hd->ScsiLookup[ii], mf, mf->TargetID, mf->LUN[1])); if ((mf->TargetID != ((u8)vdevice->vtarget->target_id)) || (mf->LUN[1] != ((u8) vdevice->lun))) continue; /* Cleanup */ hd->ScsiLookup[ii] = NULL; mptscsih_freeChainBuffers(hd->ioc, ii); mpt_free_msg_frame(hd->ioc, (MPT_FRAME_HDR *)mf); if (sc->use_sg) { pci_unmap_sg(hd->ioc->pcidev, (struct scatterlist *) sc->request_buffer, sc->use_sg, sc->sc_data_direction); } else if (sc->request_bufflen) { pci_unmap_single(hd->ioc->pcidev, sc->SCp.dma_handle, sc->request_bufflen,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -