📄 mptscsih.c
字号:
SCpnt->use_sg, scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); } else if (SCpnt->request_bufflen) { scPrivate *my_priv; my_priv = (scPrivate *) &SCpnt->SCp; pci_unmap_single(hd->ioc->pcidev, (dma_addr_t)(ulong)my_priv->p1, SCpnt->request_bufflen, scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); } SCpnt->result = DID_RESET << 16; SCpnt->host_scribble = NULL; MPT_HOST_LOCK(flags); SCpnt->scsi_done(SCpnt); /* Issue the command callback */ MPT_HOST_UNLOCK(flags); /* Free Chain buffers */ mptscsih_freeChainBuffers(hd, ii); /* Free Message frames */ mpt_free_msg_frame(ScsiDoneCtx, hd->ioc->id, mf); } }#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION /* Clear untagged counting array */ for (ii= 0; ii < MPT_MAX_SCSI_DEVICES; ii++) hd->ioc->spi_data.iocntr[ii] = 0;#endif return;}#ifdef DROP_TEST/* mptscsih_flush_drop_test - Free resources and do callback if * DROP_TEST enabled. * * @hd: Pointer to a SCSI HOST structure * * Returns: None. * * Must be called while new I/Os are being queued. */static voidmptscsih_flush_drop_test (MPT_SCSI_HOST *hd){ Scsi_Cmnd *sc; unsigned long flags; u16 req_idx; /* Free resources for the drop test MF * and chain buffers. */ if (dropMfPtr) { req_idx = le16_to_cpu(dropMfPtr->u.frame.hwhdr.msgctxu.fld.req_idx); sc = hd->ScsiLookup[req_idx]; if (sc == NULL) { printk(MYIOC_s_ERR_FMT "Drop Test: NULL ScsiCmd ptr!\n", ioc->name); } else { /* unmap OS resources, set status, do callback * free driver resources */ if (sc->use_sg) { pci_unmap_sg(ioc->pcidev, (struct scatterlist *) sc->request_buffer, sc->use_sg, scsi_to_pci_dma_dir(sc->sc_data_direction)); } else if (sc->request_bufflen) { scPrivate *my_priv; my_priv = (scPrivate *) &sc->SCp; pci_unmap_single(ioc->pcidev, (dma_addr_t)(ulong)my_priv->p1, sc->request_bufflen, scsi_to_pci_dma_dir(sc->sc_data_direction)); } sc->host_scribble = NULL; sc->result = DID_RESET << 16; hd->ScsiLookup[req_idx] = NULL; atomic_dec(&queue_depth); MPT_HOST_LOCK(flags); sc->scsi_done(sc); /* Issue callback */ MPT_HOST_UNLOCK(flags); } mptscsih_freeChainBuffers(hd, req_idx); mpt_free_msg_frame(ScsiDoneCtx, ioc->id, dropMfPtr); printk(MYIOC_s_INFO_FMT "Free'd Dropped cmd (%p)\n", hd->ioc->name, sc); printk(MYIOC_s_INFO_FMT "mf (%p) reqidx (%4x)\n", hd->ioc->name, dropMfPtr, req_idx); printk(MYIOC_s_INFO_FMT "Num Tot (%d) Good (%d) Bad (%d) \n", hd->ioc->name, dropTestNum, dropTestOK, dropTestBad); } dropMfPtr = NULL; return;}#endif/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* * mptscsih_initChainBuffers - Allocate memory for and initialize * chain buffers, chain buffer control arrays and spinlock. * @hd: Pointer to MPT_SCSI_HOST structure * @init: If set, initialize the spin lock. */static intmptscsih_initChainBuffers (MPT_SCSI_HOST *hd, int init){ MPT_FRAME_HDR *chain; u8 *mem; unsigned long flags; int sz, ii, numChain; /* Chain buffer allocations * Allocate and initialize tracker structures */ if (hd->ioc->req_sz <= 64) numChain = MPT_SG_REQ_64_SCALE * hd->ioc->req_depth; else if (hd->ioc->req_sz <= 96) numChain = MPT_SG_REQ_96_SCALE * hd->ioc->req_depth; else numChain = MPT_SG_REQ_128_SCALE * hd->ioc->req_depth; sz = numChain * sizeof(int); if (hd->ReqToChain == NULL) { mem = kmalloc(sz, GFP_ATOMIC); if (mem == NULL) return -1; hd->ReqToChain = (int *) mem; } else { mem = (u8 *) hd->ReqToChain; } memset(mem, 0xFF, sz); if (hd->ChainToChain == NULL) { mem = kmalloc(sz, GFP_ATOMIC); if (mem == NULL) return -1; hd->ChainToChain = (int *) mem; } else { mem = (u8 *) hd->ChainToChain; } memset(mem, 0xFF, sz); if (hd->ChainBuffer == NULL) { /* Allocate free chain buffer pool */ sz = numChain * hd->ioc->req_sz; mem = pci_alloc_consistent(hd->ioc->pcidev, sz, &hd->ChainBufferDMA); if (mem == NULL) return -1; hd->ChainBuffer = (u8*)mem; } else { mem = (u8 *) hd->ChainBuffer; } memset(mem, 0, sz); dprintk((KERN_INFO " ChainBuffer @ %p(%p), sz=%d\n", hd->ChainBuffer, (void *)(ulong)hd->ChainBufferDMA, sz)); /* Initialize the free chain Q. */ if (init) { spin_lock_init(&hd->FreeChainQlock); } spin_lock_irqsave (&hd->FreeChainQlock, flags); Q_INIT(&hd->FreeChainQ, MPT_FRAME_HDR); /* Post the chain buffers to the FreeChainQ. */ mem = (u8 *)hd->ChainBuffer; for (ii=0; ii < numChain; ii++) { chain = (MPT_FRAME_HDR *) mem; Q_ADD_TAIL(&hd->FreeChainQ.head, &chain->u.frame.linkage, MPT_FRAME_HDR); mem += hd->ioc->req_sz; } spin_unlock_irqrestore(&hd->FreeChainQlock, flags); return 0;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* * Hack! It might be nice 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) { char *ioc_str = "ioc?"; if (sc->host != NULL && sc->host->hostdata != NULL) ioc_str = ((MPT_SCSI_HOST *)sc->host->hostdata)->ioc->name; printk(MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n", ioc_str, 0, sc->target, sc->lun); last_queue_full = time; }}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/static int BeenHereDoneThat = 0;/* SCSI host 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; MPT_DONE_Q *freedoneQ; unsigned long flags; int sz, ii; int numSGE = 0; int scale; u8 *mem; if (! BeenHereDoneThat++) { show_mptmod_ver(my_NAME, my_VERSION); ScsiDoneCtx = mpt_register(mptscsih_io_done, MPTSCSIH_DRIVER); ScsiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSCSIH_DRIVER); ScsiScanDvCtx = mpt_register(mptscsih_scandv_complete, MPTSCSIH_DRIVER);#ifndef MPT_SCSI_USE_NEW_EH spin_lock_init(&mytaskQ_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"));#ifdef MODULE /* Evaluate the command line arguments, if any */ if (mptscsih) mptscsih_setup(mptscsih);#endif#ifndef MPT_SCSI_USE_NEW_EH atomic_set(&mpt_taskQdepth, 0);#endif this = mpt_adapter_find_first(); while (this != NULL) { int portnum; for (portnum=0; portnum < this->facts.NumberOfPorts; portnum++) { /* 20010215 -sralston * Added sanity check on SCSI Initiator-mode enabled * for this MPT adapter. */ if (!(this->pfacts[portnum].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR)) { printk(MYIOC_s_WARN_FMT "Skipping because SCSI Initiator mode is NOT enabled!\n", this->name); continue; } /* 20010202 -sralston * Added sanity check on readiness of the MPT adapter. */ if (this->last_state != MPI_IOC_STATE_OPERATIONAL) { printk(MYIOC_s_WARN_FMT "Skipping because it's not operational!\n", this->name); 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! * pfactsN->MaxDevices unreliable * (not supported in early * versions of the FW). * max_id = 1 + actual max id, * max_lun = 1 + actual last lun, * see hosts.h :o( */ if ((int)this->chip_type > (int)FC929) sh->max_id = MPT_MAX_SCSI_DEVICES; else { /* For FC, increase the queue depth * from MPT_SCSI_CAN_QUEUE (31) * to MPT_FC_CAN_QUEUE (63). */ sh->can_queue = MPT_FC_CAN_QUEUE; sh->max_id = MPT_MAX_FC_DEVICES<256 ? MPT_MAX_FC_DEVICES : 255; } sh->max_lun = MPT_LAST_LUN + 1; sh->this_id = this->pfacts[portnum].PortSCSIID; /* OS entry to allow host drivers to force * a queue depth on a per device basis. */ sh->select_queue_depths = mptscsih_select_queue_depths; /* Verify that we won't exceed the maximum * number of chain buffers * We can optimize: ZZ = req_sz/sizeof(SGE) * For 32bit SGE's: * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ * + (req_sz - 64)/sizeof(SGE) * A slightly different algorithm is required for * 64bit SGEs. */ scale = this->req_sz/(sizeof(dma_addr_t) + sizeof(u32)); if (sizeof(dma_addr_t) == sizeof(u64)) { numSGE = (scale - 1) * (this->facts.MaxChainDepth-1) + scale + (this->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32)); } else { numSGE = 1 + (scale - 1) * (this->facts.MaxChainDepth-1) + scale + (this->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32)); } if (numSGE < sh->sg_tablesize) { /* Reset this value */ dprintk((MYIOC_s_INFO_FMT "Resetting sg_tablesize to %d from %d\n", this->name, numSGE, sh->sg_tablesize)); sh->sg_tablesize = numSGE; } /* Set the pci device pointer in Scsi_Host structure. */ scsi_set_pci_device(sh, this->pcidev); restore_flags(flags); hd = (MPT_SCSI_HOST *) sh->hostdata; hd->ioc = this; if ((int)this->chip_type > (int)FC929) hd->is_spi = 1; if (DmpService && (this->chip_type == FC919 || this->chip_type == FC929)) hd->is_multipath = 1; 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_ATOMIC); if (mem == NULL) goto done; memset(mem, 0, sz); hd->ScsiLookup = (struct scsi_cmnd **) mem; dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p, sz=%d\n", this->name, hd->ScsiLookup, sz)); if (mptscsih_initChainBuffers(hd, 1) < 0) goto done; /* Allocate memory for free and doneQ's */ sz = sh->can_queue * sizeof(MPT_DONE_Q); mem = kmalloc(sz, GFP_ATOMIC); if (mem == NULL) goto done; memset(mem, 0xFF, sz); hd->memQ = mem; /* Initialize the free, done and pending Qs. */ Q_INIT(&hd->freeQ, MPT_DONE_Q); Q_INIT(&hd->doneQ, MPT_DONE_Q); Q_INIT(&hd->pendingQ, MPT_DONE_Q); spin_lock_init(&hd->freedoneQlock); mem = hd->memQ; for (ii=0; ii < sh->can_queue; ii++) { freedoneQ = (MPT_DONE_Q *) mem; Q_ADD_TAIL(&hd->freeQ.head, freedoneQ, MPT_DONE_Q); mem += sizeof(MPT_DONE_Q); } /* Initialize this Scsi_Host * internal task Q. */ Q_INIT(&hd->taskQ, MPT_FRAME_HDR); hd->taskQcnt = 0; /* Allocate memory for the device structures. * A non-Null pointer at an offset * indicates a device exists. * max_id = 1 + maximum id (hosts.h) */ sz = sh->max_id * sizeof(void *); mem = kmalloc(sz, GFP_ATOMIC); if (mem == NULL) goto done; memset(mem, 0, sz); hd->Targets = (VirtDevice **) mem; dprintk((KERN_INFO " Targets @ %p, sz=%d\n", hd->Targets, sz)); /* Clear the TM flags */ hd->tmPending = 0;#ifdef MPT_SCSI_USE_NEW_EH hd->tmState = TM_STATE_NONE;#endif hd->resetPending = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -