📄 mptscsih.c
字号:
if (scsi_device_online(SCpnt->device)) { if (SCpnt->use_sg) { pci_unmap_sg(ioc->pcidev, (struct scatterlist *) SCpnt->request_buffer, SCpnt->use_sg, SCpnt->sc_data_direction); } else if (SCpnt->request_bufflen) { pci_unmap_single(ioc->pcidev, SCpnt->SCp.dma_handle, SCpnt->request_bufflen, SCpnt->sc_data_direction); } } SCpnt->result = DID_RESET << 16; SCpnt->host_scribble = NULL; /* Free Chain buffers */ mptscsih_freeChainBuffers(ioc, ii); /* Free Message frames */ mpt_free_msg_frame(ioc, mf); SCpnt->scsi_done(SCpnt); /* Issue the command callback */ } } return;}/* * mptscsih_search_running_cmds - Delete any commands associated * with the specified target and lun. Function called only * when a lun is disable by mid-layer. * Do NOT access the referenced scsi_cmnd structure or * members. Will cause either a paging or NULL ptr error. * @hd: Pointer to a SCSI HOST structure * @target: target id * @lun: lun * * Returns: None. * * Called from slave_destroy. */static voidmptscsih_search_running_cmds(MPT_SCSI_HOST *hd, uint target, uint lun){ SCSIIORequest_t *mf = NULL; int ii; int max = hd->ioc->req_depth; dsprintk((KERN_INFO MYNAM ": search_running target %d lun %d max %d\n", target, lun, max)); for (ii=0; ii < max; ii++) { if (hd->ScsiLookup[ii] != NULL) { mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(hd->ioc, ii); dsprintk(( "search_running: found (sc=%p, mf = %p) target %d, lun %d \n", hd->ScsiLookup[ii], mf, mf->TargetID, mf->LUN[1])); if ((mf->TargetID != ((u8)target)) || (mf->LUN[1] != ((u8) lun))) continue; /* Cleanup */ hd->ScsiLookup[ii] = NULL; mptscsih_freeChainBuffers(hd->ioc, ii); mpt_free_msg_frame(hd->ioc, (MPT_FRAME_HDR *)mf); } } return;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* * 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(struct 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->device && sc->device->host != NULL && sc->device->host->hostdata != NULL) ioc_str = ((MPT_SCSI_HOST *)sc->device->host->hostdata)->ioc->name; dprintk((MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n", ioc_str, 0, sc->device->id, sc->device->lun)); last_queue_full = time; }}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/static char *info_kbuf = NULL;/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* * mptscsih_probe - Installs scsi devices per bus. * @pdev: Pointer to pci_dev structure * * Returns 0 for success, non-zero for failure. * */static intmptscsih_probe(struct pci_dev *pdev, const struct pci_device_id *id){ struct Scsi_Host *sh; MPT_SCSI_HOST *hd; MPT_ADAPTER *ioc = pci_get_drvdata(pdev); unsigned long flags; int sz, ii; int numSGE = 0; int scale; int ioc_cap; u8 *mem; int error=0; /* 20010202 -sralston * Added sanity check on readiness of the MPT adapter. */ if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) { printk(MYIOC_s_WARN_FMT "Skipping because it's not operational!\n", ioc->name); return -ENODEV; } if (!ioc->active) { printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n", ioc->name); return -ENODEV; } /* Sanity check - ensure at least 1 port is INITIATOR capable */ ioc_cap = 0; for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) { if (ioc->pfacts[ii].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) ioc_cap ++; } if (!ioc_cap) { printk(MYIOC_s_WARN_FMT "Skipping ioc=%p because SCSI Initiator mode is NOT enabled!\n", ioc->name, ioc); return -ENODEV; } sh = scsi_host_alloc(&driver_template, sizeof(MPT_SCSI_HOST)); if (!sh) { printk(MYIOC_s_WARN_FMT "Unable to register controller with SCSI subsystem\n", ioc->name); return -1; } spin_lock_irqsave(&ioc->FreeQlock, flags); /* Attach the SCSI Host to the IOC structure */ ioc->sh = sh; sh->io_port = 0; sh->n_io_port = 0; sh->irq = 0; /* set 16 byte cdb's */ sh->max_cmd_len = 16; /* 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 (ioc->bus_type == SCSI) { 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->max_channel = 0; sh->this_id = ioc->pfacts[0].PortSCSIID; /* Required entry. */ sh->unique_id = ioc->id; /* 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 = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32)); if (sizeof(dma_addr_t) == sizeof(u64)) { numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32)); } else { numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale + (ioc->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", ioc->name, numSGE, sh->sg_tablesize)); sh->sg_tablesize = numSGE; } /* Set the pci device pointer in Scsi_Host structure. */ scsi_set_device(sh, &ioc->pcidev->dev); spin_unlock_irqrestore(&ioc->FreeQlock, flags); hd = (MPT_SCSI_HOST *) sh->hostdata; hd->ioc = ioc; /* SCSI needs scsi_cmnd lookup table! * (with size equal to req_depth*PtrSz!) */ sz = ioc->req_depth * sizeof(void *); mem = kmalloc(sz, GFP_ATOMIC); if (mem == NULL) { error = -ENOMEM; goto mptscsih_probe_failed; } memset(mem, 0, sz); hd->ScsiLookup = (struct scsi_cmnd **) mem; dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p, sz=%d\n", ioc->name, hd->ScsiLookup, sz)); /* 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) { error = -ENOMEM; goto mptscsih_probe_failed; } 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; hd->tmState = TM_STATE_NONE; hd->resetPending = 0; hd->abortSCpnt = NULL; hd->tmPtr = NULL; /* Clear the pointer used to store * single-threaded commands, i.e., those * issued during a bus scan, dv and * configuration pages. */ hd->cmdPtr = NULL; /* Initialize this SCSI Hosts' timers * To use, set the timer expires field * and add_timer */ init_timer(&hd->timer); hd->timer.data = (unsigned long) hd; hd->timer.function = mptscsih_timer_expired; init_timer(&hd->TMtimer); hd->TMtimer.data = (unsigned long) hd; hd->TMtimer.function = mptscsih_taskmgmt_timeout; hd->qtag_tick = jiffies; /* Moved Earlier Pam D */ /* ioc->sh = sh; */ if (ioc->bus_type == SCSI) { /* Update with the driver setup * values. */ if (ioc->spi_data.maxBusWidth > driver_setup.max_width) { ioc->spi_data.maxBusWidth = driver_setup.max_width; } if (ioc->spi_data.minSyncFactor < driver_setup.min_sync_factor) { ioc->spi_data.minSyncFactor = driver_setup.min_sync_factor; } if (ioc->spi_data.minSyncFactor == MPT_ASYNC) { ioc->spi_data.maxSyncOffset = 0; } ioc->spi_data.Saf_Te = driver_setup.saf_te; hd->negoNvram = 0;#ifndef MPTSCSIH_ENABLE_DOMAIN_VALIDATION hd->negoNvram = MPT_SCSICFG_USE_NVRAM;#endif ioc->spi_data.forceDv = 0; for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) { ioc->spi_data.dvStatus[ii] = MPT_SCSICFG_NEGOTIATE; } for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) ioc->spi_data.dvStatus[ii] |= MPT_SCSICFG_DV_NOT_DONE; ddvprintk((MYIOC_s_INFO_FMT "dv %x width %x factor %x saf_te %x\n", ioc->name, driver_setup.dv, driver_setup.max_width, driver_setup.min_sync_factor, driver_setup.saf_te)); } mpt_scsi_hosts++; error = scsi_add_host (sh, &ioc->pcidev->dev); if(error) { dprintk((KERN_ERR MYNAM "scsi_add_host failed\n")); goto mptscsih_probe_failed; } scsi_scan_host(sh); return 0;mptscsih_probe_failed: mptscsih_remove(pdev); return error;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* * mptscsih_remove - Removed scsi devices * @pdev: Pointer to pci_dev structure * * */static voidmptscsih_remove(struct pci_dev *pdev){ MPT_ADAPTER *ioc = pci_get_drvdata(pdev); struct Scsi_Host *host = ioc->sh; MPT_SCSI_HOST *hd; int count; unsigned long flags; if(!host) return; scsi_remove_host(host);#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION /* Check DV thread active */ count = 10 * HZ; spin_lock_irqsave(&dvtaskQ_lock, flags); if (dvtaskQ_active) { spin_unlock_irqrestore(&dvtaskQ_lock, flags); while(dvtaskQ_active && --count) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); } } else { 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 hd = (MPT_SCSI_HOST *)host->hostdata; if (hd != NULL) { int sz1; mptscsih_shutdown(&pdev->dev); sz1=0; if (hd->ScsiLookup != NULL) { sz1 = hd->ioc->req_depth * sizeof(void *); kfree(hd->ScsiLookup); hd->ScsiLookup = NULL; } if (hd->Targets != NULL) { /* * Free pointer array. */ kfree(hd->Targets); hd->Targets = NULL; } dprintk((MYIOC_s_INFO_FMT
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -