📄 mptscsih.c
字号:
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;#ifdef MPTSCSIH_DISABLE_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++; } }done: if (mpt_scsi_hosts > 0) register_reboot_notifier(&mptscsih_notifier); else { 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 mpt_scsi_hosts;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** * 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; int count; unsigned long flags; hd = (MPT_SCSI_HOST *) host->hostdata;#ifndef MPT_SCSI_USE_NEW_EH#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION spin_lock_irqsave(&dvtaskQ_lock, flags); dvtaskQ_release = 1; spin_unlock_irqrestore(&dvtaskQ_lock, flags);#endif count = 10 * HZ; spin_lock_irqsave(&mytaskQ_lock, flags); if (mytaskQ_bh_active) { spin_unlock_irqrestore(&mytaskQ_lock, flags); dprintk((KERN_INFO MYNAM ": Info: Zapping TaskMgmt thread!\n")); clean_taskQ(hd); while(mytaskQ_bh_active && --count) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); } } else { spin_unlock_irqrestore(&mytaskQ_lock, flags); } if (!count) printk(KERN_ERR MYNAM ": ERROR - TaskMgmt thread still active!\n");#endif#ifndef MPTSCSIH_DISABLE_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 unregister_reboot_notifier(&mptscsih_notifier); if (hd != NULL) { int sz1, sz2, sz3, sztarget=0; int szr2chain = 0; int szc2chain = 0; int szchain = 0; int szQ = 0; /* Synchronize disk caches */ (void) mptscsih_synchronize_cache(hd, 0); 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->ChainBuffer != NULL) { sz2 = hd->num_chain * hd->ioc->req_sz; szchain = szr2chain + szc2chain + 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<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), 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; MPT_SCSI_HOST *hd; /* 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'; 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; info.buffer = pbuf; info.length = len; info.offset = offset; info.pos = 0; copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name); copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word); copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts); copy_info(&info, "MaxQ=%d\n", ioc->req_depth); return ((info.pos > info.offset) ? info.pos - info.offset : 0);}#ifndef MPTSCSIH_DBG_TIMEOUTstatic int mptscsih_user_command(MPT_ADAPTER *ioc, char *pbuf, int len){ /* Not yet implemented */ return len;}#else#define is_digit(c) ((c) >= '0' && (c) <= '9')#define digit_to_bin(c) ((c) - '0')#define is_space(c) ((c) == ' ' || (c) == '\t')#define UC_DBG_TIMEOUT 0x01#define UC_DBG_HARDRESET 0x02static int skip_spaces(char *ptr, int len){ int cnt, c; for (cnt = len; cnt > 0 && (c = *ptr++) && is_space(c); cnt --); return (len - cnt);}static int get_int_arg(char *ptr, int len, ulong *pv){ int cnt, c; ulong v; for (v = 0, cnt = len; cnt > 0 && (c=*ptr++) && is_digit(c); cnt --) { v = (v * 10) + digit_to_bin(c); } if (pv) *pv = v; return (len - cnt);}static int is_keyword(char *ptr, int len, char *verb){ int verb_len = strlen(verb); if (len >= strlen(verb) && !memcmp(verb, ptr, verb_len)) return verb_len; else return 0;}#define SKIP_SPACES(min_spaces) \ if ((arg_len = skip_spaces(ptr,len)) < (min_spaces)) \ return -EINVAL; \ ptr += arg_len; \ len -= arg_len;#define GET_INT_ARG(v) \ if (!(arg_len = get_int_arg(ptr,len, &(v)))) \ return -EINVAL; \ ptr += arg_len; \ len -= arg_len;static int mptscsih_user_command(MPT_ADAPTER *ioc, char *buffer, int length){ char *ptr = buffer; char btmp[24]; /* REMOVE */ int arg_len; int len = length; int cmd; ulong number = 1; ulong delta = 10; if ((len > 0) && (ptr[len -1] == '\n')) --len; if (len < 22) { strncpy(btmp, buffer, len); btmp[len+1]='\0'; } else { strncpy(btmp, buffer, 22); btmp[23]='\0'; } printk("user_command: ioc %d, buffer %s, length %d\n", ioc->id, btmp, length); if ((arg_len = is_keyword(ptr, len, "timeout")) != 0) cmd = UC_DBG_TIMEOUT; else if ((arg_len = is_keyword(ptr, len, "hardreset")) != 0) cmd = UC_DBG_HARDRESET; else return -EINVAL; ptr += arg_len; len -= arg_len; switch(cmd) { case UC_DBG_TIMEOUT: SKIP_SPACES(1); GET_INT_ARG(number); SKIP_SPACES(1); GET_INT_ARG(delta); break; } printk("user_command: cnt=%ld delta=%ld\n", number, delta); if (len) return -EINVAL; else { if (cmd == UC_DBG_HARDRESET) { ioc->timeout_hard = 1; } else if (cmd == UC_DBG_TIMEOUT) { /* process this command ... */ ioc->timeout_maxcnt = 0; ioc->timeou
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -