📄 mptfc.c
字号:
if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_4GBIT_SPEED) speed |= FC_PORTSPEED_4GBIT; if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_10GBIT_SPEED) speed |= FC_PORTSPEED_10GBIT; fc_host_supported_speeds(sh) = speed; port_state = FC_PORTSTATE_UNKNOWN; if (pp0->PortState == MPI_FCPORTPAGE0_PORTSTATE_ONLINE) port_state = FC_PORTSTATE_ONLINE; else if (pp0->PortState == MPI_FCPORTPAGE0_PORTSTATE_OFFLINE) port_state = FC_PORTSTATE_LINKDOWN; fc_host_port_state(sh) = port_state; port_type = FC_PORTTYPE_UNKNOWN; if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_POINT_TO_POINT) port_type = FC_PORTTYPE_PTP; else if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_PRIVATE_LOOP) port_type = FC_PORTTYPE_LPORT; else if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_PUBLIC_LOOP) port_type = FC_PORTTYPE_NLPORT; else if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_FABRIC_DIRECT) port_type = FC_PORTTYPE_NPORT; fc_host_port_type(sh) = port_type; fc_host_fabric_name(sh) = (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_FABRIC_WWN_VALID) ? (u64) pp0->FabricWWNN.High << 32 | (u64) pp0->FabricWWPN.Low : (u64)pp0->WWNN.High << 32 | (u64)pp0->WWNN.Low;}static voidmptfc_link_status_change(struct work_struct *work){ MPT_ADAPTER *ioc = container_of(work, MPT_ADAPTER, fc_rescan_work); int ii; for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) (void) mptfc_GetFcPortPage0(ioc, ii);}static voidmptfc_setup_reset(struct work_struct *work){ MPT_ADAPTER *ioc = container_of(work, MPT_ADAPTER, fc_setup_reset_work); u64 pn; struct mptfc_rport_info *ri; /* reset about to happen, delete (block) all rports */ list_for_each_entry(ri, &ioc->fc_rports, list) { if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) { ri->flags &= ~MPT_RPORT_INFO_FLAGS_REGISTERED; fc_remote_port_delete(ri->rport); /* won't sleep */ ri->rport = NULL; pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low; dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT "mptfc_setup_reset.%d: %llx deleted\n", ioc->name, ioc->sh->host_no, (unsigned long long)pn)); } }}static voidmptfc_rescan_devices(struct work_struct *work){ MPT_ADAPTER *ioc = container_of(work, MPT_ADAPTER, fc_rescan_work); int ii; u64 pn; struct mptfc_rport_info *ri; /* start by tagging all ports as missing */ list_for_each_entry(ri, &ioc->fc_rports, list) { if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) { ri->flags |= MPT_RPORT_INFO_FLAGS_MISSING; } } /* * now rescan devices known to adapter, * will reregister existing rports */ for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) { (void) mptfc_GetFcPortPage0(ioc, ii); mptfc_init_host_attr(ioc, ii); /* refresh */ mptfc_GetFcDevPage0(ioc, ii, mptfc_register_dev); } /* delete devices still missing */ list_for_each_entry(ri, &ioc->fc_rports, list) { /* if newly missing, delete it */ if (ri->flags & MPT_RPORT_INFO_FLAGS_MISSING) { ri->flags &= ~(MPT_RPORT_INFO_FLAGS_REGISTERED| MPT_RPORT_INFO_FLAGS_MISSING); fc_remote_port_delete(ri->rport); /* won't sleep */ ri->rport = NULL; pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low; dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT "mptfc_rescan.%d: %llx deleted\n", ioc->name, ioc->sh->host_no, (unsigned long long)pn)); } }}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 0; } 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; } spin_lock_init(&ioc->fc_rescan_work_lock); INIT_WORK(&ioc->fc_rescan_work, mptfc_rescan_devices); INIT_WORK(&ioc->fc_setup_reset_work, mptfc_setup_reset); INIT_WORK(&ioc->fc_lsc_work, mptfc_link_status_change); 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 = ioc->pfacts->MaxDevices; sh->max_lun = max_lun; 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(ioc, printk(MYIOC_s_DEBUG_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 = shost_priv(sh); hd->ioc = ioc; /* SCSI needs scsi_cmnd lookup table! * (with size equal to req_depth*PtrSz!) */ ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC); if (!ioc->ScsiLookup) { error = -ENOMEM; goto out_mptfc_probe; } spin_lock_init(&ioc->scsi_lookup_lock); dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n", ioc->name, ioc->ScsiLookup)); /* 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; 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(ioc, printk(MYIOC_s_ERR_FMT "scsi_add_host failed\n", ioc->name)); goto out_mptfc_probe; } /* initialize workqueue */ snprintf(ioc->fc_rescan_work_q_name, KOBJ_NAME_LEN, "mptfc_wq_%d", sh->host_no); ioc->fc_rescan_work_q = create_singlethread_workqueue(ioc->fc_rescan_work_q_name); if (!ioc->fc_rescan_work_q) goto out_mptfc_probe; /* * Pre-fetch FC port WWN and stuff... * (FCPortPage0_t stuff) */ for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) { (void) mptfc_GetFcPortPage0(ioc, ii); } mptfc_SetFcPortPage1_defaults(ioc); /* * scan for rports - * by doing it via the workqueue, some locking is eliminated */ queue_work(ioc->fc_rescan_work_q, &ioc->fc_rescan_work); flush_workqueue(ioc->fc_rescan_work_q); 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};static intmptfc_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply){ MPT_SCSI_HOST *hd; u8 event = le32_to_cpu(pEvReply->Event) & 0xFF; unsigned long flags; int rc=1; devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n", ioc->name, event)); if (ioc->sh == NULL || ((hd = shost_priv(ioc->sh)) == NULL)) return 1; switch (event) { case MPI_EVENT_RESCAN: spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags); if (ioc->fc_rescan_work_q) { queue_work(ioc->fc_rescan_work_q, &ioc->fc_rescan_work); } spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags); break; case MPI_EVENT_LINK_STATUS_CHANGE: spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags); if (ioc->fc_rescan_work_q) { queue_work(ioc->fc_rescan_work_q, &ioc->fc_lsc_work); } spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags); break; default: rc = mptscsih_event_process(ioc,pEvReply); break; } return rc;}static intmptfc_ioc_reset(MPT_ADAPTER *ioc, int reset_phase){ int rc; unsigned long flags; rc = mptscsih_ioc_reset(ioc,reset_phase); if (rc == 0) return rc; dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": IOC %s_reset routed to FC host driver!\n",ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : ( reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"))); if (reset_phase == MPT_IOC_SETUP_RESET) { spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags); if (ioc->fc_rescan_work_q) { queue_work(ioc->fc_rescan_work_q, &ioc->fc_setup_reset_work); } spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags); } else if (reset_phase == MPT_IOC_PRE_RESET) { } else { /* MPT_IOC_POST_RESET */ mptfc_SetFcPortPage1_defaults(ioc); spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags); if (ioc->fc_rescan_work_q) { queue_work(ioc->fc_rescan_work_q, &ioc->fc_rescan_work); } spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags); } return 1;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** * mptfc_init - Register MPT adapter(s) as SCSI host(s) with 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 parameters */ 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); mpt_event_register(mptfcDoneCtx, mptfc_event_process); mpt_reset_register(mptfcDoneCtx, mptfc_ioc_reset); error = pci_register_driver(&mptfc_driver); if (error) fc_release_transport(mptfc_transport_template); return error;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** * mptfc_remove - Remove 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; struct workqueue_struct *work_q; unsigned long flags; int ii; /* destroy workqueue */ if ((work_q=ioc->fc_rescan_work_q)) { spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags); ioc->fc_rescan_work_q = NULL; spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags); destroy_workqueue(work_q); } fc_remove_host(ioc->sh); list_for_each_entry_safe(p, n, &ioc->fc_rports, list) { list_del(&p->list); kfree(p); } for (ii=0; ii<ioc->facts.NumberOfPorts; ii++) { if (ioc->fc_data.fc_port_page1[ii].data) { pci_free_consistent(ioc->pcidev, ioc->fc_data.fc_port_page1[ii].pg_sz, (u8 *) ioc->fc_data.fc_port_page1[ii].data, ioc->fc_data.fc_port_page1[ii].dma); ioc->fc_data.fc_port_page1[ii].data = NULL; } } 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); mpt_event_deregister(mptfcDoneCtx); 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 + -