📄 mptscsih.c
字号:
pScsiReq->LUN[1] = lun; pScsiReq->LUN[2] = 0; pScsiReq->LUN[3] = 0; pScsiReq->LUN[4] = 0; pScsiReq->LUN[5] = 0; pScsiReq->LUN[6] = 0; pScsiReq->LUN[7] = 0; 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(hd->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(hd->ioc, SCpnt, pScsiReq, my_idx) != SUCCESS) goto fail; } hd->ScsiLookup[my_idx] = SCpnt; SCpnt->host_scribble = NULL;#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION if (hd->ioc->bus_type == SCSI) { int dvStatus = hd->ioc->spi_data.dvStatus[pTarget->target_id]; int issueCmd = 1; if (dvStatus || hd->ioc->spi_data.forceDv) { if ((dvStatus & MPT_SCSICFG_NEED_DV) || (hd->ioc->spi_data.forceDv & MPT_SCSICFG_NEED_DV)) { unsigned long lflags; /* Schedule DV if necessary */ spin_lock_irqsave(&dvtaskQ_lock, lflags); if (!dvtaskQ_active) { dvtaskQ_active = 1; spin_unlock_irqrestore(&dvtaskQ_lock, lflags); INIT_WORK(&dvTaskQ_task, mptscsih_domainValidation, (void *) hd); schedule_work(&dvTaskQ_task); } else { spin_unlock_irqrestore(&dvtaskQ_lock, lflags); } hd->ioc->spi_data.forceDv &= ~MPT_SCSICFG_NEED_DV; } /* Trying to do DV to this target, extend timeout. * Wait to issue until flag is clear */ if (dvStatus & MPT_SCSICFG_DV_PENDING) { mod_timer(&SCpnt->eh_timeout, jiffies + 40 * HZ); issueCmd = 0; } /* Set the DV flags. */ if (dvStatus & MPT_SCSICFG_DV_NOT_DONE) mptscsih_set_dvflags(hd, pScsiReq); if (!issueCmd) goto fail; } }#endif mpt_put_msg_frame(hd->ioc->DoneCtx, hd->ioc, mf); dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n", hd->ioc->name, SCpnt, mf, my_idx)); DBG_DUMP_REQUEST_FRAME(mf) return 0; fail: hd->ScsiLookup[my_idx] = NULL; mptscsih_freeChainBuffers(hd->ioc, my_idx); mpt_free_msg_frame(hd->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((MYIOC_s_INFO_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. * Fall through to mpt_HardResetHandler if: not operational, too many * failed TM requests or handshake failure. * * @ioc: Pointer to MPT_ADAPTER structure * @type: Task Management type * @target: Logical Target ID for reset (if appropriate) * @lun: Logical Unit for reset (if appropriate) * @ctx2abort: Context for the task to be aborted (if appropriate) * * 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 -1 if FAILED. */static intmptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout){ MPT_ADAPTER *ioc; int rc = -1; int doTask = 1; u32 ioc_raw_state; unsigned long flags; /* If FW is being reloaded currently, return success to * the calling function. */ if (hd == NULL) return 0; ioc = hd->ioc; if (ioc == NULL) { printk(KERN_ERR MYNAM " TMHandler" " NULL ioc!\n"); return FAILED; } dtmprintk((MYIOC_s_INFO_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((KERN_INFO MYNAM ": %s: TMHandler abort: " "Timed out waiting for last TM (%d) to complete! \n", hd->ioc->name, hd->tmPending)); return FAILED; } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) { dtmprintk((KERN_INFO MYNAM ": %s: TMHandler target reset: " "Timed out waiting for last TM (%d) to complete! \n", hd->ioc->name, hd->tmPending)); return FAILED; } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) { dtmprintk((KERN_INFO MYNAM ": %s: TMHandler bus reset: " "Timed out waiting for last TM (%d) to complete! \n", hd->ioc->name, hd->tmPending)); if (hd->tmPending & (1 << MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)) return FAILED; doTask = 0; } } else { spin_lock_irqsave(&hd->ioc->FreeQlock, flags); hd->tmPending |= (1 << type); spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); } /* Is operational? */ ioc_raw_state = mpt_GetIocState(hd->ioc, 0);#ifdef MPT_DEBUG_RESET if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) { printk(MYIOC_s_WARN_FMT "TM Handler: IOC Not operational(0x%x)!\n", hd->ioc->name, ioc_raw_state); }#endif if (doTask && ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) && !(ioc_raw_state & MPI_DOORBELL_ACTIVE)) { /* Isse the Task Mgmt request. */ if (hd->hard_resets < -1) hd->hard_resets++; rc = mptscsih_IssueTaskMgmt(hd, type, channel, target, lun, ctx2abort, timeout); if (rc) { printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n", hd->ioc->name); } else { dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n", hd->ioc->name)); } } /* Only fall through to the HRH if this is a bus reset */ if ((type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) && (rc || ioc->reload_fw || (ioc->alt_ioc && ioc->alt_ioc->reload_fw))) { dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n", hd->ioc->name)); rc = mpt_HardResetHandler(hd->ioc, CAN_SLEEP); } dtmprintk((MYIOC_s_INFO_FMT "TMHandler rc = %d!\n", hd->ioc->name, rc)); return rc;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* * mptscsih_IssueTaskMgmt - Generic send Task Management function. * @hd: Pointer to MPT_SCSI_HOST structure * @type: Task Management type * @target: Logical Target ID for reset (if appropriate) * @lun: Logical Unit for reset (if appropriate) * @ctx2abort: Context for the task to be aborted (if appropriate) * * 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, -999 for "no msg frames", * else other non-zero value returned. */static intmptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout){ MPT_FRAME_HDR *mf; SCSITaskMgmt_t *pScsiTm; int ii; int retval; /* Return Fail to calling function if no message frames available. */ if ((mf = mpt_get_msg_frame(hd->ioc->TaskCtx, hd->ioc)) == NULL) { dfailprintk((MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n", hd->ioc->name)); return FAILED; } dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n", hd->ioc->name, mf)); /* Format the Request */ pScsiTm = (SCSITaskMgmt_t *) mf; pScsiTm->TargetID = target; 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; for (ii= 0; ii < 8; ii++) { pScsiTm->LUN[ii] = 0; } pScsiTm->LUN[1] = lun; for (ii=0; ii < 7; ii++) pScsiTm->Reserved2[ii] = 0; pScsiTm->TaskMsgContext = ctx2abort; dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt: ctx2abort (0x%08x) type=%d\n", hd->ioc->name, ctx2abort, type)); DBG_DUMP_TM_REQUEST_FRAME((u32 *)pScsiTm); if ((retval = mpt_send_handshake_request(hd->ioc->TaskCtx, hd->ioc, sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP)) != 0) { dfailprintk((MYIOC_s_ERR_FMT "_send_handshake FAILED!" " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd, hd->ioc, mf)); mpt_free_msg_frame(hd->ioc, mf); return retval; } if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) { dfailprintk((MYIOC_s_ERR_FMT "_wait_for_completion FAILED!" " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd, hd->ioc, mf)); mpt_free_msg_frame(hd->ioc, mf); dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n", hd->ioc->name)); retval = mpt_HardResetHandler(hd->ioc, CAN_SLEEP); } return retval;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** * 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_ADAPTER *ioc; MPT_FRAME_HDR *mf; u32 ctx2abort; int scpnt_idx; int retval; /* If we can't locate our host adapter structure, return FAILED status. */ if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) { SCpnt->result = DID_RESET << 16; SCpnt->scsi_done(SCpnt); dfailprintk((KERN_INFO MYNAM ": mptscsih_abort: " "Can't locate host! (sc=%p)\n", SCpnt)); return FAILED; } ioc = hd->ioc; if (hd->resetPending) { return FAILED; } if (hd->timeouts < -1) hd->timeouts++; /* Find this command */ if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) { /* Cmd not found in ScsiLookup. * Do OS callback. */ SCpnt->result = DID_RESET << 16; dtmprintk((KERN_INFO MYNAM ": %s: mptscsih_abort: " "Command not in the active list! (sc=%p)\n", hd->ioc->name, SCpnt)); return SUCCESS; } printk(KERN_WARNING MYNAM ": %s: attempting task abort! (sc=%p)\n", hd->ioc->name, SCpnt); scsi_print_command(SCpnt); /* Most important! Set TaskMsgContext to SCpnt's MsgContext! * (the IO to be ABORT'd) * * NOTE: Since we do not byteswap MsgContext, we do not * swap it here either. It is an opaque cookie to * the controller, so it does not matter. -DaveM */ mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx); ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext; hd->abortSCpnt = SCpnt; retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK, SCpnt->device->channel, SCpnt->device->id, SCpnt->device->lun, ctx2abort, 2 /* 2 second timeout */); printk (KERN_WARNING MYNAM ": %s: task abort: %s (sc=%p)\n", hd->ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt); if (retval == 0) return SUCCESS; if(retval != FAILED ) { hd->tmPending = 0; hd->tmState = TM_STATE_NONE; } return FAILED;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to * * (linux scsi_host_template.eh_dev_reset_handler routine)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -