📄 mptscsih.c
字号:
int count = 0; int list_sz; dslprintk((KERN_INFO MYNAM ": spinlock#1\n")); spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags); list_sz = mpt_scsih_taskQ_cnt; if (! Q_IS_EMPTY(&mpt_scsih_taskQ)) { mf = mpt_scsih_taskQ.head; do { count++; if (mf->u.frame.linkage.argp1 == sc && mf->u.frame.linkage.arg1 == task_type) { if (remove) { Q_DEL_ITEM(&mf->u.frame.linkage); mpt_scsih_taskQ_cnt--; } break; } } while ((mf = mf->u.frame.linkage.forw) != (MPT_FRAME_HDR*)&mpt_scsih_taskQ); if (mf == (MPT_FRAME_HDR*)&mpt_scsih_taskQ) { mf = NULL; } } spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); if (list_sz) { dprintk((KERN_INFO MYNAM ": search_taskQ(%d,%p,%d) results=%p (%sFOUND%s)!\n", remove, sc, task_type, mf, mf ? "" : "NOT_", (mf && remove) ? "+REMOVED" : "" )); dprintk((KERN_INFO MYNAM ": (searched thru %d of %d items on taskQ)\n", count, list_sz )); } return mf;}#endif/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* * Hack! I'd like to report if a device is returning QUEUE_FULL * but maybe not each and every time... */static long last_queue_full = 0;/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* * mptscsih_report_queue_full - Report QUEUE_FULL status returned * from a SCSI target device. * @sc: Pointer to Scsi_Cmnd structure * @pScsiReply: Pointer to SCSIIOReply_t * @pScsiReq: Pointer to original SCSI request * * This routine periodically reports QUEUE_FULL status returned from a * SCSI target device. It reports this to the console via kernel * printk() API call, not more than once every 10 seconds. */static voidmptscsih_report_queue_full(Scsi_Cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq){ long time = jiffies; if (time - last_queue_full > 10 * HZ) { printk(KERN_WARNING MYNAM ": Device reported QUEUE_FULL! SCSI bus:target:lun = %d:%d:%d\n", 0, sc->target, sc->lun); last_queue_full = time; }}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/static int BeenHereDoneThat = 0;/* SCSI fops start here... *//*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** * mptscsih_detect - Register MPT adapter(s) as SCSI host(s) with * linux scsi mid-layer. * @tpnt: Pointer to Scsi_Host_Template structure * * (linux Scsi_Host_Template.detect routine) * * Returns number of SCSI host adapters that were successfully * registered with the linux scsi mid-layer via the scsi_register() * API call. */intmptscsih_detect(Scsi_Host_Template *tpnt){ struct Scsi_Host *sh = NULL; MPT_SCSI_HOST *hd = NULL; MPT_ADAPTER *this; unsigned long flags; int sz; u8 *mem; if (! BeenHereDoneThat++) { show_mptmod_ver(my_NAME, my_VERSION); if ((ScsiDoneCtx = mpt_register(mptscsih_io_done, MPTSCSIH_DRIVER)) <= 0) { printk(KERN_ERR MYNAM ": Failed to register callback1 with MPT base driver\n"); return mpt_scsi_hosts; } if ((ScsiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSCSIH_DRIVER)) <= 0) { printk(KERN_ERR MYNAM ": Failed to register callback2 with MPT base driver\n"); return mpt_scsi_hosts; }#ifndef MPT_SCSI_USE_NEW_EH Q_INIT(&mpt_scsih_taskQ, MPT_FRAME_HDR); spin_lock_init(&mpt_scsih_taskQ_lock);#endif if (mpt_event_register(ScsiDoneCtx, mptscsih_event_process) == 0) { dprintk((KERN_INFO MYNAM ": Registered for IOC event notifications\n")); } else { /* FIXME! */ } if (mpt_reset_register(ScsiDoneCtx, mptscsih_ioc_reset) == 0) { dprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n")); } else { /* FIXME! */ } } dprintk((KERN_INFO MYNAM ": mpt_scsih_detect()\n")); this = mpt_adapter_find_first(); while (this != NULL) { /* FIXME! Multi-port (aka FC929) support... * for (i = 0; i < this->facts.NumberOfPorts; i++) */ /* 20010215 -sralston * Added sanity check on SCSI Initiator-mode enabled * for this MPT adapter. */ if (!(this->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR)) { printk(KERN_ERR MYNAM ": Skipping %s because SCSI Initiator mode is NOT enabled!\n", this->name); this = mpt_adapter_find_next(this); continue; } /* 20010202 -sralston * Added sanity check on readiness of the MPT adapter. */ if (this->last_state != MPI_IOC_STATE_OPERATIONAL) { printk(KERN_ERR MYNAM ": ERROR - Skipping %s because it's not operational!\n", this->name); this = mpt_adapter_find_next(this); continue; }#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) tpnt->proc_dir = &proc_mpt_scsihost;#endif sh = scsi_register(tpnt, sizeof(MPT_SCSI_HOST)); if (sh != NULL) { save_flags(flags); cli(); sh->io_port = 0; sh->n_io_port = 0; sh->irq = 0; /* Yikes! This is important! * Otherwise, by default, linux only scans target IDs 0-7! * * BUG FIX! 20010618 -sralston & pdelaney * FC919 testing was encountering "duplicate" FC devices, * as it turns out because the 919 was returning 512 * for PortFacts.MaxDevices, causing a wraparound effect * in SCSI IO requests. So instead of using: * sh->max_id = this->pfacts[0].MaxDevices - 1 * we'll use a definitive max here. */ sh->max_id = MPT_MAX_FC_DEVICES; sh->this_id = this->pfacts[0].PortSCSIID; restore_flags(flags); hd = (MPT_SCSI_HOST *) sh->hostdata; hd->ioc = this; hd->port = 0; /* FIXME! */ /* SCSI needs Scsi_Cmnd lookup table! * (with size equal to req_depth*PtrSz!) */ sz = hd->ioc->req_depth * sizeof(void *); mem = kmalloc(sz, GFP_KERNEL); if (mem == NULL) return mpt_scsi_hosts; memset(mem, 0, sz); hd->ScsiLookup = (struct scsi_cmnd **) mem; dprintk((KERN_INFO MYNAM ": ScsiLookup @ %p, sz=%d\n", hd->ScsiLookup, sz)); /* SCSI also needs SG buckets/hunk management! * (with size equal to N * req_sz * req_depth!) * (where N is number of SG buckets per hunk) */ sz = MPT_SG_BUCKETS_PER_HUNK * hd->ioc->req_sz * hd->ioc->req_depth; mem = pci_alloc_consistent(hd->ioc->pcidev, sz, &hd->SgHunksDMA); if (mem == NULL) return mpt_scsi_hosts; memset(mem, 0, sz); hd->SgHunks = (u8*)mem; dprintk((KERN_INFO MYNAM ": SgHunks @ %p(%08x), sz=%d\n", hd->SgHunks, hd->SgHunksDMA, sz)); hd->qtag_tick = jiffies; this->sh = sh; mpt_scsi_hosts++; } this = mpt_adapter_find_next(this); } return mpt_scsi_hosts;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ static char *info_kbuf = NULL;/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** * mptscsih_release - Unregister SCSI host from linux scsi mid-layer * @host: Pointer to Scsi_Host structure * * (linux Scsi_Host_Template.release routine) * This routine releases all resources associated with the SCSI host * adapter. * * Returns 0 for success. */intmptscsih_release(struct Scsi_Host *host){ MPT_SCSI_HOST *hd;#ifndef MPT_SCSI_USE_NEW_EH unsigned long flags; spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags); if (mpt_scsih_taskQ_bh_active) { int count = 10 * HZ; dprintk((KERN_INFO MYNAM ": Info: Zapping TaskMgmt thread!\n")); /* Zap the taskQ! */ Q_INIT(&mpt_scsih_taskQ, MPT_FRAME_HDR); spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); while(mpt_scsih_taskQ_bh_active && --count) { current->state = TASK_INTERRUPTIBLE; schedule_timeout(1); } if (!count) printk(KERN_ERR MYNAM ": ERROR! TaskMgmt thread still active!\n"); } spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);#endif hd = (MPT_SCSI_HOST *) host->hostdata; if (hd != NULL) { int sz1, sz2; sz1 = sz2 = 0; if (hd->ScsiLookup != NULL) { sz1 = hd->ioc->req_depth * sizeof(void *); kfree(hd->ScsiLookup); hd->ScsiLookup = NULL; } if (hd->SgHunks != NULL) { sz2 = MPT_SG_BUCKETS_PER_HUNK * hd->ioc->req_sz * hd->ioc->req_depth; pci_free_consistent(hd->ioc->pcidev, sz2, hd->SgHunks, hd->SgHunksDMA); hd->SgHunks = NULL; } dprintk((KERN_INFO MYNAM ": Free'd ScsiLookup (%d) and SgHunks (%d) memory\n", sz1, sz2)); } if (mpt_scsi_hosts) { if (--mpt_scsi_hosts == 0) {#if 0 mptscsih_flush_pending();#endif 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(ScsiDoneCtx); mpt_deregister(ScsiTaskCtx); if (info_kbuf != NULL) kfree(info_kbuf); } } return 0;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** * 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;#ifdef MPT_DEBUG static int max_sges = 0; static int max_xfer = 0;#endif#if 0 static int max_num_sges = 0; static int max_sgent_len = 0;#endif#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/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** * 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 *)){ struct Scsi_Host *host; MPT_SCSI_HOST *hd; MPT_FRAME_HDR *mf; SCSIIORequest_t *pScsiReq; int datadir; u32 len; u32 sgdir; u32 scsictl; u32 scsidir; u32 qtag; u32 *mptr; int sge_spill1; int frm_sz; int sges_left; u32 chain_offset; int my_idx; int i; dmfprintk((KERN_INFO MYNAM "_qcmd: SCpnt=%p, done()=%p\n", SCpnt, done)); host = SCpnt->host; hd = (MPT_SCSI_HOST *) host->hostdata; #if 0 if (host->host_busy >= 60) { MPT_ADAPTER *ioc = hd->ioc; u16 pci_command, pci_status; /* The IOC is probably hung, investigate status. */ printk("MPI: IOC probably hung IOCSTAT[%08x] INTSTAT[%08x] REPLYFIFO[%08x]\n", readl(&ioc->chip.fc9xx->DoorbellValue), readl(&ioc->chip.fc9xx->IntStatus), readl(&ioc->chip.fc9xx->ReplyFifo)); pci_read_config_word(ioc->pcidev, PCI_COMMAND, &pci_command); pci_read_config_word(ioc->pcidev, PCI_STATUS, &pci_status); printk("MPI: PCI command[%04x] status[%04x]\n", pci_command, pci_status); { /* DUMP req index logger. */ int begin, end; begin = (index_ent - 65) & (128 - 1); end = index_ent & (128 - 1); printk("MPI: REQ_INDEX_HIST["); while (begin != end) { printk("(%04x)", index_log[begin]); begin = (begin + 1) & (128 - 1); } printk("\n"); } sti(); while(1) barrier(); }#endif SCpnt->scsi_done = 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. */#ifdef MPT_SCSI_CACHE_AUTOSENSE { MPT_SCSI_DEV *mpt_sdev; mpt_sdev = (MPT_SCSI_DEV *) SCpnt->device->hostdata; if (mpt_sdev && SCpnt->cmnd[0] == REQUEST_SENSE) { u8 *dest = NULL; if (!SCpnt->use_sg) dest = SCpnt->request_buffer; else { struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -