📄 mptscsih.c
字号:
if (!count) printk(KERN_ERR MYNAM ": ERROR - TaskMgmt thread still active!\n"); } spin_unlock_irqrestore(&mytaskQ_lock, flags);#endif#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION /* Check DV thread active */ count = 10 * HZ; spin_lock_irqsave(&dvtaskQ_lock, flags); while(dvtaskQ_active && --count) { spin_unlock_irqrestore(&dvtaskQ_lock, flags); set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); spin_lock_irqsave(&dvtaskQ_lock, flags); } spin_unlock_irqrestore(&dvtaskQ_lock, flags); if (!count) printk(KERN_ERR MYNAM ": ERROR - DV thread still active!\n");#if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY) else printk(KERN_ERR MYNAM ": DV thread orig %d, count %d\n", 10 * HZ, count);#endif#endif unregister_reboot_notifier(&mptscsih_notifier); if (hd != NULL) { int sz1, sz2, sz3, sztarget=0; int szchain = 0; int szQ = 0; int scale; /* Synchronize disk caches */ (void) mptscsih_synchronize_cache(hd, 0); sz1 = sz2 = sz3 = 0; if (hd->ioc->req_sz <= 64) scale = MPT_SG_REQ_64_SCALE; else if (hd->ioc->req_sz <= 96) scale = MPT_SG_REQ_96_SCALE; else scale = MPT_SG_REQ_128_SCALE; if (hd->ScsiLookup != NULL) { sz1 = hd->ioc->req_depth * sizeof(void *); kfree(hd->ScsiLookup); hd->ScsiLookup = NULL; } if (hd->ReqToChain != NULL) { szchain += scale * hd->ioc->req_depth * sizeof(int); kfree(hd->ReqToChain); hd->ReqToChain = NULL; } if (hd->ChainToChain != NULL) { szchain += scale * hd->ioc->req_depth * sizeof(int); kfree(hd->ChainToChain); hd->ChainToChain = NULL; } if (hd->ChainBuffer != NULL) { sz2 = scale * hd->ioc->req_depth * hd->ioc->req_sz; szchain += sz2; pci_free_consistent(hd->ioc->pcidev, sz2, hd->ChainBuffer, hd->ChainBufferDMA); hd->ChainBuffer = NULL; } if (hd->memQ != NULL) { szQ = host->can_queue * sizeof(MPT_DONE_Q); kfree(hd->memQ); hd->memQ = NULL; } if (hd->Targets != NULL) { int max, ii; /* * Free any target structures that were allocated. */ if (hd->is_spi) { max = MPT_MAX_SCSI_DEVICES; } else { max = MPT_MAX_FC_DEVICES; } for (ii=0; ii < max; ii++) { if (hd->Targets[ii]) { kfree(hd->Targets[ii]); hd->Targets[ii] = NULL; sztarget += sizeof(VirtDevice); } } /* * Free pointer array. */ sz3 = max * sizeof(void *); kfree(hd->Targets); hd->Targets = NULL; } dprintk((MYIOC_s_INFO_FMT "Free'd ScsiLookup (%d), chain (%d) and Target (%d+%d) memory\n", hd->ioc->name, sz1, szchain, sz3, sztarget)); dprintk(("Free'd done and free Q (%d) memory\n", szQ)); } /* NULL the Scsi_Host pointer */ hd->ioc->sh = NULL; scsi_unregister(host); if (mpt_scsi_hosts) { if (--mpt_scsi_hosts == 0) { mpt_reset_deregister(ScsiDoneCtx); dprintk((KERN_INFO MYNAM ": Deregistered for IOC reset notifications\n")); mpt_event_deregister(ScsiDoneCtx); dprintk((KERN_INFO MYNAM ": Deregistered for IOC event notifications\n")); mpt_deregister(ScsiScanDvCtx); mpt_deregister(ScsiTaskCtx); mpt_deregister(ScsiDoneCtx); if (info_kbuf != NULL) kfree(info_kbuf); } } return 0;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** * mptscsih_halt - Process the reboot notification * @nb: Pointer to a struct notifier_block (ignored) * @event: event (SYS_HALT, SYS_RESTART, SYS_POWER_OFF) * @buf: Pointer to a data buffer (ignored) * * This routine called if a system shutdown or reboot is to occur. * * Return NOTIFY_DONE if this is something other than a reboot message. * NOTIFY_OK if this is a reboot message. */static intmptscsih_halt(struct notifier_block *nb, ulong event, void *buf){ MPT_ADAPTER *ioc = NULL; MPT_SCSI_HOST *hd = NULL; /* Ignore all messages other than reboot message */ if ((event != SYS_RESTART) && (event != SYS_HALT) && (event != SYS_POWER_OFF)) return (NOTIFY_DONE); for (ioc = mpt_adapter_find_first(); ioc != NULL; ioc = mpt_adapter_find_next(ioc)) { /* Flush the cache of this adapter */ if (ioc->sh) { hd = (MPT_SCSI_HOST *) ioc->sh->hostdata; if (hd) { mptscsih_synchronize_cache(hd, 0); } } } unregister_reboot_notifier(&mptscsih_notifier); return NOTIFY_OK;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** * mptscsih_info - Return information about MPT adapter * @SChost: Pointer to Scsi_Host structure * * (linux Scsi_Host_Template.info routine) * * Returns pointer to buffer where information was written. */const char *mptscsih_info(struct Scsi_Host *SChost){ MPT_SCSI_HOST *h; int size = 0; if (info_kbuf == NULL) if ((info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL) return info_kbuf; h = (MPT_SCSI_HOST *)SChost->hostdata; info_kbuf[0] = '\0'; mpt_print_ioc_summary(h->ioc, info_kbuf, &size, 0, 0); info_kbuf[size-1] = '\0'; return info_kbuf;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ static int max_qd = 1;#if 0static int index_log[128];static int index_ent = 0;static __inline__ void ADD_INDEX_LOG(int req_ent){ int i = index_ent++; index_log[i & (128 - 1)] = req_ent;}#else#define ADD_INDEX_LOG(req_ent) do { } while(0)#endif#ifdef DROP_TEST#define DROP_IOC 1 /* IOC to force failures */#define DROP_TARGET 3 /* Target ID to force failures */#define DROP_THIS_CMD 10000 /* iteration to drop command */static int dropCounter = 0;static int dropTestOK = 0; /* num did good */static int dropTestBad = 0; /* num did bad */static int dropTestNum = 0; /* total = good + bad + incomplete */static int numTotCmds = 0;static MPT_FRAME_HDR *dropMfPtr = NULL;static int numTMrequested = 0;#endif/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* * mptscsih_put_msgframe - Wrapper routine to post message frame to F/W. * @context: Call back context (ScsiDoneCtx, ScsiScanDvCtx) * @id: IOC id number * @mf: Pointer to message frame * * Handles the call to mptbase for posting request and queue depth * tracking. * * Returns none. */static voidmptscsih_put_msgframe(int context, int id, MPT_FRAME_HDR *mf){ /* Main banana... */ atomic_inc(&queue_depth); if (atomic_read(&queue_depth) > max_qd) { max_qd = atomic_read(&queue_depth); dprintk((KERN_INFO MYNAM ": Queue depth now %d.\n", max_qd)); } mpt_put_msg_frame(context, id, mf); return;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine. * @SCpnt: Pointer to Scsi_Cmnd structure * @done: Pointer SCSI mid-layer IO completion function * * (linux Scsi_Host_Template.queuecommand routine) * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest * from a linux Scsi_Cmnd request and send it to the IOC. * * Returns 0. (rtn value discarded by linux scsi mid-layer) */intmptscsih_qcmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)){ MPT_SCSI_HOST *hd; MPT_FRAME_HDR *mf; SCSIIORequest_t *pScsiReq; VirtDevice *pTarget; MPT_DONE_Q *buffer = NULL; unsigned long flags; int target; int lun; int datadir; u32 datalen; u32 scsictl; u32 scsidir; u32 qtag; u32 cmd_len; int my_idx; int ii; int rc; int did_errcode; int issueCmd; did_errcode = 0; hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata; target = SCpnt->target; lun = SCpnt->lun; SCpnt->scsi_done = done; pTarget = hd->Targets[target]; dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n", (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done)); /* 20000617 -sralston * GRRRRR... Shouldn't have to do this but... * Do explicit check for REQUEST_SENSE and cached SenseData. * If yes, return cached SenseData. */ if (SCpnt->cmnd[0] == REQUEST_SENSE) { u8 *dest = NULL; int sz; if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_VALID_SENSE)) { pTarget->tflags &= ~MPT_TARGET_FLAGS_VALID_SENSE; //sjr-moved-here if (!SCpnt->use_sg) { dest = SCpnt->request_buffer; } else { struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer; if (sg) dest = (u8 *)(ulong)sg_dma_address(sg); } if (dest) { sz = MIN (SCSI_STD_SENSE_BYTES, SCpnt->request_bufflen); memcpy(dest, pTarget->sense, sz);#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) SCpnt->resid = SCpnt->request_bufflen - sz;#endif SCpnt->result = 0; SCpnt->scsi_done(SCpnt); //sjr-moved-up//pTarget->tflags &= ~MPT_TARGET_FLAGS_VALID_SENSE; return 0; } } } if (hd->resetPending) { /* Prevent new commands from being issued * while reloading the FW. */ did_errcode = 1; goto did_error; } /* * Put together a MPT SCSI request... */ if ((mf = mpt_get_msg_frame(ScsiDoneCtx, hd->ioc->id)) == NULL) { dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n", hd->ioc->name)); did_errcode = 2; goto did_error; } pScsiReq = (SCSIIORequest_t *) mf; my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); ADD_INDEX_LOG(my_idx); /* * The scsi layer should be handling this stuff * (In 2.3.x it does -DaveM) */ /* BUG FIX! 19991030 -sralston * 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... */ datadir = mptscsih_io_direction(SCpnt); if (datadir < 0) { datalen = SCpnt->request_bufflen; scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */ } else if (datadir > 0) { datalen = SCpnt->request_bufflen; 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. */ qtag = MPI_SCSIIO_CONTROL_UNTAGGED; if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES) && (SCpnt->device->tagged_supported)) { /* * Some drives are too stupid to handle fairness issues * with tagged queueing. We throw in the odd ordered * tag to stop them starving themselves. */ if ((jiffies - hd->qtag_tick) > (5*HZ)) { qtag = MPI_SCSIIO_CONTROL_ORDEREDQ; hd->qtag_tick = jiffies; } else qtag = MPI_SCSIIO_CONTROL_SIMPLEQ; } scsictl = scsidir | qtag; /* Use the above information to set up the message frame */ pScsiReq->TargetID = target; pScsiReq->Bus = hd->port; pScsiReq->ChainOffset = 0; pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST; pScsiReq->CDBLength = SCpnt->cmd_len; pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE; pScsiReq->Reserved = 0; pScsiReq->MsgFlags = MPT_SCSIIO_MSG_FLAGS; pScsiReq->LUN[0] = 0; 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. */ rc = SUCCESS; if (datalen == 0) { /* Add a NULL SGE */ mptscsih_AddNullSGE(pScsiReq); } else { /* Add a 32 or 64 bit SGE */ rc = mptscsih_Add32BitSGE(hd, SCpnt, pScsiReq, my_idx); } if (rc == SUCCESS) { hd->ScsiLookup[my_idx] = SCpnt; SCpnt->host_scribble = NULL;#ifdef DROP_TEST numTotCmds++; /* If the IOC number and target match, increment * counter. If counter matches DROP_THIS, do not * issue command to FW to force a reset. * Save the MF pointer so we can free resources * when task mgmt completes. */ if ((hd->ioc->id == DROP_IOC) && (target == DROP_TARGET)) { dropCounter++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -