📄 mptfc.c
字号:
} return rc;}/* * OS entry point to allow host driver to alloc memory * for each scsi device. Called once per device the bus scan. * Return non-zero if allocation fails. * Init memory once per LUN. */intmptfc_slave_alloc(struct scsi_device *sdev){ MPT_SCSI_HOST *hd; VirtTarget *vtarget; VirtDevice *vdev; struct scsi_target *starget; struct fc_rport *rport; unsigned long flags; rport = starget_to_rport(scsi_target(sdev)); if (!rport || fc_remote_port_chkready(rport)) return -ENXIO; hd = (MPT_SCSI_HOST *)sdev->host->hostdata; vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL); if (!vdev) { printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n", hd->ioc->name, sizeof(VirtDevice)); return -ENOMEM; } spin_lock_irqsave(&hd->ioc->fc_rport_lock,flags); sdev->hostdata = vdev; starget = scsi_target(sdev); vtarget = starget->hostdata; if (vtarget->num_luns == 0) { vtarget->ioc_id = hd->ioc->id; vtarget->tflags = MPT_TARGET_FLAGS_Q_YES | MPT_TARGET_FLAGS_VALID_INQUIRY; hd->Targets[sdev->id] = vtarget; } vdev->vtarget = vtarget; vdev->ioc_id = hd->ioc->id; vdev->lun = sdev->lun; vdev->target_id = vtarget->target_id; vdev->bus_id = vtarget->bus_id; spin_unlock_irqrestore(&hd->ioc->fc_rport_lock,flags); vtarget->num_luns++; dfcprintk ((MYIOC_s_INFO_FMT "mptfc_slv_alloc.%d: num_luns %d, sdev.id %d, " "CurrentTargetID %d, %x %llx %llx\n", ioc->name, sdev->host->host_no, vtarget->num_luns, sdev->id, ri->pg0.CurrentTargetID, ri->pg0.PortIdentifier, ri->pg0.WWPN, ri->pg0.WWNN)); return 0;}static intmptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)){ struct mptfc_rport_info *ri; struct fc_rport *rport = starget_to_rport(scsi_target(SCpnt->device)); int err; err = fc_remote_port_chkready(rport); if (unlikely(err)) { SCpnt->result = err; done(SCpnt); return 0; } ri = *((struct mptfc_rport_info **)rport->dd_data); if (unlikely(ri->remap_needed)) return SCSI_MLQUEUE_HOST_BUSY; return mptscsih_qcmd(SCpnt,done);}static voidmptfc_init_host_attr(MPT_ADAPTER *ioc,int portnum){ unsigned class = 0, cos = 0; /* don't know what to do as only one scsi (fc) host was allocated */ if (portnum != 0) return; class = ioc->fc_port_page0[portnum].SupportedServiceClass; if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_1) cos |= FC_COS_CLASS1; if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_2) cos |= FC_COS_CLASS2; if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_3) cos |= FC_COS_CLASS3; fc_host_node_name(ioc->sh) = (u64)ioc->fc_port_page0[portnum].WWNN.High << 32 | (u64)ioc->fc_port_page0[portnum].WWNN.Low; fc_host_port_name(ioc->sh) = (u64)ioc->fc_port_page0[portnum].WWPN.High << 32 | (u64)ioc->fc_port_page0[portnum].WWPN.Low; fc_host_port_id(ioc->sh) = ioc->fc_port_page0[portnum].PortIdentifier; fc_host_supported_classes(ioc->sh) = cos; fc_host_tgtid_bind_type(ioc->sh) = FC_TGTID_BIND_BY_WWPN;}static voidmptfc_rescan_devices(void *arg){ MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg; int ii; int work_to_do; unsigned long flags; struct mptfc_rport_info *ri; do { /* start by tagging all ports as missing */ spin_lock_irqsave(&ioc->fc_rport_lock,flags); list_for_each_entry(ri, &ioc->fc_rports, list) { if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) { ri->flags |= MPT_RPORT_INFO_FLAGS_MISSING; } } spin_unlock_irqrestore(&ioc->fc_rport_lock,flags); /* * now rescan devices known to adapter, * will reregister existing rports */ for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) { (void) mptbase_GetFcPortPage0(ioc, ii); mptfc_init_host_attr(ioc,ii); /* refresh */ mptfc_GetFcDevPage0(ioc,ii,mptfc_register_dev); } /* delete devices still missing */ spin_lock_irqsave(&ioc->fc_rport_lock, flags); list_for_each_entry(ri, &ioc->fc_rports, list) { /* if newly missing, delete it */ if ((ri->flags & (MPT_RPORT_INFO_FLAGS_REGISTERED | MPT_RPORT_INFO_FLAGS_MISSING)) == (MPT_RPORT_INFO_FLAGS_REGISTERED | MPT_RPORT_INFO_FLAGS_MISSING)) { ri->flags &= ~(MPT_RPORT_INFO_FLAGS_REGISTERED| MPT_RPORT_INFO_FLAGS_MISSING); ri->remap_needed = 1; fc_remote_port_delete(ri->rport); /* * remote port not really deleted 'cause * binding is by WWPN and driver only * registers FCP_TARGETs but cannot trust * data structures. */ ri->rport = NULL; dfcprintk ((MYIOC_s_INFO_FMT "mptfc_rescan.%d: %llx deleted\n", ioc->name, ioc->sh->host_no, ri->pg0.WWPN)); } } spin_unlock_irqrestore(&ioc->fc_rport_lock,flags); /* * allow multiple passes as target state * might have changed during scan */ spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags); if (ioc->fc_rescan_work_count > 2) /* only need one more */ ioc->fc_rescan_work_count = 2; work_to_do = --ioc->fc_rescan_work_count; spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags); } while (work_to_do);}static intmptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id){ struct Scsi_Host *sh; MPT_SCSI_HOST *hd; MPT_ADAPTER *ioc; unsigned long flags; int ii; int numSGE = 0; int scale; int ioc_cap; int error=0; int r; if ((r = mpt_attach(pdev,id)) != 0) return r; ioc = pci_get_drvdata(pdev); ioc->DoneCtx = mptfcDoneCtx; ioc->TaskCtx = mptfcTaskCtx; ioc->InternalCtx = mptfcInternalCtx; /* 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); error = -ENODEV; goto out_mptfc_probe; } if (!ioc->active) { printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n", ioc->name); error = -ENODEV; goto out_mptfc_probe; } /* 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(&mptfc_driver_template, sizeof(MPT_SCSI_HOST)); if (!sh) { printk(MYIOC_s_WARN_FMT "Unable to register controller with SCSI subsystem\n", ioc->name); error = -1; goto out_mptfc_probe; } INIT_WORK(&ioc->fc_rescan_work, mptfc_rescan_devices,(void *)ioc); 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; 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; } 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!) */ hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC); if (!hd->ScsiLookup) { error = -ENOMEM; goto out_mptfc_probe; } dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n", ioc->name, hd->ScsiLookup)); /* Allocate memory for the device structures. * A non-Null pointer at an offset * indicates a device exists. * max_id = 1 + maximum id (hosts.h) */ hd->Targets = kcalloc(sh->max_id, sizeof(void *), GFP_ATOMIC); if (!hd->Targets) { error = -ENOMEM; goto out_mptfc_probe; } dprintk((KERN_INFO " vdev @ %p\n", hd->Targets)); /* Clear the TM flags */ hd->tmPending = 0; hd->tmState = TM_STATE_NONE; hd->resetPending = 0; hd->abortSCpnt = 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; hd->mpt_pq_filter = mpt_pq_filter; ddvprintk((MYIOC_s_INFO_FMT "mpt_pq_filter %x\n", ioc->name, mpt_pq_filter)); init_waitqueue_head(&hd->scandv_waitq); hd->scandv_wait_done = 0; hd->last_queue_full = 0; sh->transportt = mptfc_transport_template; error = scsi_add_host (sh, &ioc->pcidev->dev); if(error) { dprintk((KERN_ERR MYNAM "scsi_add_host failed\n")); goto out_mptfc_probe; } for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) { mptfc_init_host_attr(ioc,ii); mptfc_GetFcDevPage0(ioc,ii,mptfc_register_dev); } return 0;out_mptfc_probe: mptscsih_remove(pdev); return error;}static struct pci_driver mptfc_driver = { .name = "mptfc", .id_table = mptfc_pci_table, .probe = mptfc_probe, .remove = __devexit_p(mptfc_remove), .shutdown = mptscsih_shutdown,#ifdef CONFIG_PM .suspend = mptscsih_suspend, .resume = mptscsih_resume,#endif};/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** * mptfc_init - Register MPT adapter(s) as SCSI host(s) with * linux scsi mid-layer. * * Returns 0 for success, non-zero for failure. */static int __initmptfc_init(void){ int error; show_mptmod_ver(my_NAME, my_VERSION); /* sanity check module parameter */ if (mptfc_dev_loss_tmo == 0) mptfc_dev_loss_tmo = MPTFC_DEV_LOSS_TMO; mptfc_transport_template = fc_attach_transport(&mptfc_transport_functions); if (!mptfc_transport_template) return -ENODEV; mptfcDoneCtx = mpt_register(mptscsih_io_done, MPTFC_DRIVER); mptfcTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTFC_DRIVER); mptfcInternalCtx = mpt_register(mptscsih_scandv_complete, MPTFC_DRIVER); if (mpt_event_register(mptfcDoneCtx, mptscsih_event_process) == 0) { devtprintk((KERN_INFO MYNAM ": Registered for IOC event notifications\n")); } if (mpt_reset_register(mptfcDoneCtx, mptscsih_ioc_reset) == 0) { dprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n")); } error = pci_register_driver(&mptfc_driver); if (error) fc_release_transport(mptfc_transport_template); return error;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** * mptfc_remove - Removed fc infrastructure for devices * @pdev: Pointer to pci_dev structure * */static void __devexitmptfc_remove(struct pci_dev *pdev){ MPT_ADAPTER *ioc = pci_get_drvdata(pdev); struct mptfc_rport_info *p, *n; fc_remove_host(ioc->sh); list_for_each_entry_safe(p, n, &ioc->fc_rports, list) { list_del(&p->list); kfree(p); } mptscsih_remove(pdev);}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** * mptfc_exit - Unregisters MPT adapter(s) * */static void __exitmptfc_exit(void){ pci_unregister_driver(&mptfc_driver); fc_release_transport(mptfc_transport_template); mpt_reset_deregister(mptfcDoneCtx); dprintk((KERN_INFO MYNAM ": Deregistered for IOC reset notifications\n")); mpt_event_deregister(mptfcDoneCtx); dprintk((KERN_INFO MYNAM ": Deregistered for IOC event notifications\n")); mpt_deregister(mptfcInternalCtx); mpt_deregister(mptfcTaskCtx); mpt_deregister(mptfcDoneCtx);}module_init(mptfc_init);module_exit(mptfc_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -