📄 mptscsih.c
字号:
if (hd->resetPending) { dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n", ioc->name, SCpnt)); return SCSI_MLQUEUE_HOST_BUSY; } /* * Put together a MPT SCSI request... */ if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) { dprintk(ioc, printk(MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n", ioc->name)); return SCSI_MLQUEUE_HOST_BUSY; } pScsiReq = (SCSIIORequest_t *) mf; my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); ADD_INDEX_LOG(my_idx); /* TUR's being issued with scsictl=0x02000000 (DATA_IN)! * Seems we may receive a buffer (datalen>0) even when there * will be no data transfer! GRRRRR... */ if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) { datalen = scsi_bufflen(SCpnt); scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */ } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) { datalen = scsi_bufflen(SCpnt); scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */ } else { datalen = 0; scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER; } /* Default to untagged. Once a target structure has been allocated, * use the Inquiry data to determine if device supports tagged. */ if (vdevice && (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES) && (SCpnt->device->tagged_supported)) { scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ; } else { scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED; } /* Use the above information to set up the message frame */ pScsiReq->TargetID = (u8) vdevice->vtarget->id; pScsiReq->Bus = vdevice->vtarget->channel; pScsiReq->ChainOffset = 0; if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH; else pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST; pScsiReq->CDBLength = SCpnt->cmd_len; pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE; pScsiReq->Reserved = 0; pScsiReq->MsgFlags = mpt_msg_flags(); int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN); pScsiReq->Control = cpu_to_le32(scsictl); /* * Write SCSI CDB into the message */ cmd_len = SCpnt->cmd_len; for (ii=0; ii < cmd_len; ii++) pScsiReq->CDB[ii] = SCpnt->cmnd[ii]; for (ii=cmd_len; ii < 16; ii++) pScsiReq->CDB[ii] = 0; /* DataLength */ pScsiReq->DataLength = cpu_to_le32(datalen); /* SenseBuffer low address */ pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma + (my_idx * MPT_SENSE_BUFFER_ALLOC)); /* Now add the SG list * Always have a SGE even if null length. */ if (datalen == 0) { /* Add a NULL SGE */ mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1); } else { /* Add a 32 or 64 bit SGE */ if (mptscsih_AddSGE(ioc, SCpnt, pScsiReq, my_idx) != SUCCESS) goto fail; } SCpnt->host_scribble = (unsigned char *)mf; mptscsih_set_scsi_lookup(ioc, my_idx, SCpnt); mpt_put_msg_frame(ioc->DoneCtx, ioc, mf); dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n", ioc->name, SCpnt, mf, my_idx)); DBG_DUMP_REQUEST_FRAME(ioc, (u32 *)mf); return 0; fail: mptscsih_freeChainBuffers(ioc, my_idx); mpt_free_msg_frame(ioc, mf); return SCSI_MLQUEUE_HOST_BUSY;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* * mptscsih_freeChainBuffers - Function to free chain buffers associated * with a SCSI IO request * @hd: Pointer to the MPT_SCSI_HOST instance * @req_idx: Index of the SCSI IO request frame. * * Called if SG chain buffer allocation fails and mptscsih callbacks. * No return. */static voidmptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx){ MPT_FRAME_HDR *chain; unsigned long flags; int chain_idx; int next; /* Get the first chain index and reset * tracker state. */ chain_idx = ioc->ReqToChain[req_idx]; ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN; while (chain_idx != MPT_HOST_NO_CHAIN) { /* Save the next chain buffer index */ next = ioc->ChainToChain[chain_idx]; /* Free this chain buffer and reset * tracker */ ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN; chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer + (chain_idx * ioc->req_sz)); spin_lock_irqsave(&ioc->FreeQlock, flags); list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ); spin_unlock_irqrestore(&ioc->FreeQlock, flags); dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FreeChainBuffers (index %d)\n", ioc->name, chain_idx)); /* handle next */ chain_idx = next; } return;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* * Reset Handling *//*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** * mptscsih_TMHandler - Generic handler for SCSI Task Management. * @hd: Pointer to MPT SCSI HOST structure * @type: Task Management type * @channel: channel number for task management * @id: Logical Target ID for reset (if appropriate) * @lun: Logical Unit for reset (if appropriate) * @ctx2abort: Context for the task to be aborted (if appropriate) * @timeout: timeout for task management control * * Fall through to mpt_HardResetHandler if: not operational, too many * failed TM requests or handshake failure. * * Remark: Currently invoked from a non-interrupt thread (_bh). * * Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC * will be active. * * Returns 0 for SUCCESS, or %FAILED. **/intmptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout){ MPT_ADAPTER *ioc; int rc = -1; u32 ioc_raw_state; unsigned long flags; ioc = hd->ioc; dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler Entered!\n", ioc->name)); // SJR - CHECKME - Can we avoid this here? // (mpt_HardResetHandler has this check...) spin_lock_irqsave(&ioc->diagLock, flags); if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) { spin_unlock_irqrestore(&ioc->diagLock, flags); return FAILED; } spin_unlock_irqrestore(&ioc->diagLock, flags); /* Wait a fixed amount of time for the TM pending flag to be cleared. * If we time out and not bus reset, then we return a FAILED status * to the caller. * The call to mptscsih_tm_pending_wait() will set the pending flag * if we are * successful. Otherwise, reload the FW. */ if (mptscsih_tm_pending_wait(hd) == FAILED) { if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) { dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler abort: " "Timed out waiting for last TM (%d) to complete! \n", ioc->name, hd->tmPending)); return FAILED; } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) { dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler target " "reset: Timed out waiting for last TM (%d) " "to complete! \n", ioc->name, hd->tmPending)); return FAILED; } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) { dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler bus reset: " "Timed out waiting for last TM (%d) to complete! \n", ioc->name, hd->tmPending)); return FAILED; } } else { spin_lock_irqsave(&ioc->FreeQlock, flags); hd->tmPending |= (1 << type); spin_unlock_irqrestore(&ioc->FreeQlock, flags); } ioc_raw_state = mpt_GetIocState(ioc, 0); if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) { printk(MYIOC_s_WARN_FMT "TM Handler for type=%x: IOC Not operational (0x%x)!\n", ioc->name, type, ioc_raw_state); printk(MYIOC_s_WARN_FMT " Issuing HardReset!!\n", ioc->name); if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0) printk(MYIOC_s_WARN_FMT "TMHandler: HardReset " "FAILED!!\n", ioc->name); return FAILED; } if (ioc_raw_state & MPI_DOORBELL_ACTIVE) { printk(MYIOC_s_WARN_FMT "TM Handler for type=%x: ioc_state: " "DOORBELL_ACTIVE (0x%x)!\n", ioc->name, type, ioc_raw_state); return FAILED; } /* Isse the Task Mgmt request. */ if (hd->hard_resets < -1) hd->hard_resets++; rc = mptscsih_IssueTaskMgmt(hd, type, channel, id, lun, ctx2abort, timeout); if (rc) printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n", ioc->name); else dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issue of TaskMgmt Successful!\n", ioc->name)); dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler rc = %d!\n", ioc->name, rc)); return rc;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** * mptscsih_IssueTaskMgmt - Generic send Task Management function. * @hd: Pointer to MPT_SCSI_HOST structure * @type: Task Management type * @channel: channel number for task management * @id: Logical Target ID for reset (if appropriate) * @lun: Logical Unit for reset (if appropriate) * @ctx2abort: Context for the task to be aborted (if appropriate) * @timeout: timeout for task management control * * Remark: _HardResetHandler can be invoked from an interrupt thread (timer) * or a non-interrupt thread. In the former, must not call schedule(). * * Not all fields are meaningfull for all task types. * * Returns 0 for SUCCESS, or FAILED. * **/static intmptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout){ MPT_FRAME_HDR *mf; SCSITaskMgmt_t *pScsiTm; int ii; int retval; MPT_ADAPTER *ioc = hd->ioc; /* Return Fail to calling function if no message frames available. */ if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) { dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n", ioc->name)); return FAILED; } dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt request @ %p\n", ioc->name, mf)); /* Format the Request */ pScsiTm = (SCSITaskMgmt_t *) mf; pScsiTm->TargetID = id; pScsiTm->Bus = channel; pScsiTm->ChainOffset = 0; pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; pScsiTm->Reserved = 0; pScsiTm->TaskType = type; pScsiTm->Reserved1 = 0; pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0; int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN); for (ii=0; ii < 7; ii++) pScsiTm->Reserved2[ii] = 0; pScsiTm->TaskMsgContext = ctx2abort; dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt: ctx2abort (0x%08x) " "type=%d\n", ioc->name, ctx2abort, type)); DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm); if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) && (ioc->facts.MsgVersion >= MPI_VERSION_01_05)) mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf); else { retval = mpt_send_handshake_request(ioc->TaskCtx, ioc, sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP); if (retval) { dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "send_handshake FAILED!" " (hd %p, ioc %p, mf %p, rc=%d) \n", ioc->name, hd, ioc, mf, retval)); goto fail_out; } } if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) { dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "task management request TIMED OUT!" " (hd %p, ioc %p, mf %p) \n", ioc->name, hd, ioc, mf)); dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n", ioc->name)); retval = mpt_HardResetHandler(ioc, CAN_SLEEP); dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rc=%d \n", ioc->name, retval)); goto fail_out; } /* * Handle success case, see if theres a non-zero ioc_status. */ if (hd->tm_iocstatus == MPI_IOCSTATUS_SUCCESS || hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED || hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED) retval = 0; else retval = FAILED; return retval; fail_out: /* * Free task managment mf, and corresponding tm flags */ mpt_free_msg_frame(ioc, mf); hd->tmPending = 0; hd->tmState = TM_STATE_NONE; return FAILED;}static intmptscsih_get_tm_timeout(MPT_ADAPTER *ioc){ switch (ioc->bus_type) { case FC: return 40; case SAS: return 10; case SPI: default: return 2; }}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** * mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant * @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted * * (linux scsi_host_template.eh_abort_handler routine) * * Returns SUCCESS or FAILED. **/intmptscsih_abort(struct scsi_cmnd * SCpnt){ MPT_SCSI_HOST *hd; MPT_FRAME_HDR *mf; u32 ctx2abort; int scpnt_idx; int retval; VirtDevice *vdevice; ulong sn = SCpnt->serial_number; MPT_ADAPTER *ioc; /* If we can't locate our host adapter structure, return FAILED status. */ if ((hd = shost_priv(SCpnt->device->host)) == NULL) { SCpnt->result = DID_RESET << 16; SCpnt->scsi_done(SCpnt); printk(KERN_ERR MYNAM ": task abort: " "can't locate host! (sc=%p)\n", SCpnt); return FAILED; } ioc = hd->ioc; printk(MYIOC_s_INFO_FMT "attempting task abort! (sc=%p)\n", ioc->name, SCpnt); scsi_print_command(SCpnt); vdevice = SCpnt->device->hostdata; if (!vdevice || !vdevice->vtarget) { dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: device has been deleted (sc=%p)\n", ioc->name, SCpnt)); SCpnt->result = DID_NO_CONNECT << 16; SCpnt->scsi_done(SCpnt); retval = 0; goto out; } /* Task aborts are not supported for hidden raid components.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -