📄 mptscsih.c
字号:
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) { 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; hd->numTMrequests = 0; /* 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; */#ifdef MPTSCSIH_DBG_TIMEOUT hd->ioc->timeout_hard = 0; hd->ioc->timeout_delta = 30 * HZ; hd->ioc->timeout_maxcnt = 0; hd->ioc->timeout_cnt = 0; for (ii=0; ii < 8; ii++) foo_to[ii] = NULL;#endif if (hd->is_spi) { /* Update with the driver setup * values. */ if (hd->ioc->spi_data.maxBusWidth > driver_setup.max_width) { hd->ioc->spi_data.maxBusWidth = driver_setup.max_width; } if (hd->ioc->spi_data.minSyncFactor < driver_setup.min_sync_fac) { hd->ioc->spi_data.minSyncFactor = driver_setup.min_sync_fac; } if (hd->ioc->spi_data.minSyncFactor == MPT_ASYNC) { hd->ioc->spi_data.maxSyncOffset = 0; } hd->ioc->spi_data.Saf_Te = driver_setup.saf_te; hd->negoNvram = 0;#ifndef MPTSCSIH_ENABLE_DOMAIN_VALIDATION hd->negoNvram = MPT_SCSICFG_USE_NVRAM;#endif if (driver_setup.dv == 0) { hd->negoNvram = MPT_SCSICFG_USE_NVRAM; } hd->ioc->spi_data.forceDv = 0; for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) { hd->ioc->spi_data.dvStatus[ii] = MPT_SCSICFG_NEGOTIATE; } if (hd->negoNvram == 0) { for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) hd->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", hd->ioc->name, driver_setup.dv, driver_setup.max_width, driver_setup.min_sync_fac, 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, sz2, sz3, sztarget=0; int szr2chain = 0; int szc2chain = 0; int szQ = 0; mptscsih_shutdown(&pdev->dev); sz1 = sz2 = sz3 = 0; if (hd->ScsiLookup != NULL) { sz1 = hd->ioc->req_depth * sizeof(void *); kfree(hd->ScsiLookup); hd->ScsiLookup = NULL; } if (hd->ReqToChain != NULL) { szr2chain = hd->ioc->req_depth * sizeof(int); kfree(hd->ReqToChain); hd->ReqToChain = NULL; } if (hd->ChainToChain != NULL) { szc2chain = hd->num_chain * sizeof(int); kfree(hd->ChainToChain); hd->ChainToChain = 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<256 ? MPT_MAX_FC_DEVICES : 255; } 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) Target (%d+%d) memory\n", hd->ioc->name, sz1, sz3, sztarget)); dprintk(("Free'd done and free Q (%d) memory\n", szQ)); /* NULL the Scsi_Host pointer */ hd->ioc->sh = NULL; } scsi_host_put(host); mpt_scsi_hosts--;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* * mptscsih_shutdown - reboot notifier * */static voidmptscsih_shutdown(struct device * dev){ MPT_ADAPTER *ioc = pci_get_drvdata(to_pci_dev(dev)); struct Scsi_Host *host = ioc->sh; MPT_SCSI_HOST *hd; if(!host) return; hd = (MPT_SCSI_HOST *)host->hostdata; /* Flush the cache of this adapter */ if(hd != NULL) mptscsih_synchronize_cache(hd, 0);}#ifdef CONFIG_PM/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* * mptscsih_suspend - Fusion MPT scsie driver suspend routine. * * */static intmptscsih_suspend(struct pci_dev *pdev, u32 state){ mptscsih_shutdown(&pdev->dev); return 0;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* * mptscsih_resume - Fusion MPT scsi driver resume routine. * * */static intmptscsih_resume(struct pci_dev *pdev){ MPT_ADAPTER *ioc = pci_get_drvdata(pdev); struct Scsi_Host *host = ioc->sh; MPT_SCSI_HOST *hd; if(!host) return 0; hd = (MPT_SCSI_HOST *)host->hostdata; if(!hd) return 0;#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION { unsigned long lflags; spin_lock_irqsave(&dvtaskQ_lock, lflags); if (!dvtaskQ_active) { dvtaskQ_active = 1; spin_unlock_irqrestore(&dvtaskQ_lock, lflags); INIT_WORK(&mptscsih_dvTask, mptscsih_domainValidation, (void *) hd); schedule_work(&mptscsih_dvTask); } else { spin_unlock_irqrestore(&dvtaskQ_lock, lflags); } }#endif return 0;}#endifstatic struct mpt_pci_driver mptscsih_driver = { .probe = mptscsih_probe, .remove = mptscsih_remove, .shutdown = mptscsih_shutdown,#ifdef CONFIG_PM .suspend = mptscsih_suspend, .resume = mptscsih_resume,#endif};/* SCSI host fops start here... *//*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** * mptscsih_init - Register MPT adapter(s) as SCSI host(s) with * linux scsi mid-layer. * * Returns 0 for success, non-zero for failure. */static int __initmptscsih_init(void){ 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); if (mpt_event_register(ScsiDoneCtx, mptscsih_event_process) == 0) { dprintk((KERN_INFO MYNAM ": Registered for IOC event notifications\n")); } if (mpt_reset_register(ScsiDoneCtx, mptscsih_ioc_reset) == 0) { dprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n")); }#ifdef MODULE /* Evaluate the command line arguments, if any */ if (mptscsih) mptscsih_setup(mptscsih);#endif if(mpt_device_driver_register(&mptscsih_driver, MPTSCSIH_DRIVER) != 0 ) { dprintk((KERN_INFO MYNAM ": failed to register dd callbacks\n")); } return 0;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** * mptscsih_exit - Unregisters MPT adapter(s) * */static void __exitmptscsih_exit(void){ mpt_device_driver_deregister(MPTSCSIH_DRIVER); 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);}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** * 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'; if (h) { mpt_print_ioc_summary(h->ioc, info_kbuf, &size, 0, 0); info_kbuf[size-1] = '\0'; } return info_kbuf;}struct info_str { char *buffer; int length; int offset; int pos;};static void copy_mem_info(struct info_str *info, char *data, int len){ if (info->pos + len > info->length) len = info->length - info->pos; if (info->pos + len < info->offset) { info->pos += len; return; } if (info->pos < info->offset) { data += (info->offset - info->pos); len -= (info->offset - info->pos); } if (len > 0) { memcpy(info->buffer + info->pos, data, len); info->pos += len; }}static int copy_info(struct info_str *info, char *fmt, ...){ va_list args; char buf[81]; int len; va_start(args, fmt); len = vsprintf(buf, fmt, args); va_end(args); copy_mem_info(info, buf, len); return len;}static int mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len){ struct info_str info;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -