mptbase.c
来自「linux 内核源代码」· C语言 代码 · 共 2,293 行 · 第 1/5 页
C
2,293 行
ioc->name, recovery_state); } else { printk(MYIOC_s_INFO_FMT "pci-resume: success\n", ioc->name); } return 0;}#endifstatic intmpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase){ if ((MptDriverClass[index] == MPTSPI_DRIVER && ioc->bus_type != SPI) || (MptDriverClass[index] == MPTFC_DRIVER && ioc->bus_type != FC) || (MptDriverClass[index] == MPTSAS_DRIVER && ioc->bus_type != SAS)) /* make sure we only call the relevant reset handler * for the bus */ return 0; return (MptResetHandlers[index])(ioc, reset_phase);}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** * mpt_do_ioc_recovery - Initialize or recover MPT adapter. * @ioc: Pointer to MPT adapter structure * @reason: Event word / reason * @sleepFlag: Use schedule if CAN_SLEEP else use udelay. * * This routine performs all the steps necessary to bring the IOC * to a OPERATIONAL state. * * This routine also pre-fetches the LAN MAC address of a Fibre Channel * MPT adapter. * * Returns: * 0 for success * -1 if failed to get board READY * -2 if READY but IOCFacts Failed * -3 if READY but PrimeIOCFifos Failed * -4 if READY but IOCInit Failed */static intmpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag){ int hard_reset_done = 0; int alt_ioc_ready = 0; int hard; int rc=0; int ii; u8 cb_idx; int handlers; int ret = 0; int reset_alt_ioc_active = 0; int irq_allocated = 0; u8 *a; printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name, reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery"); /* Disable reply interrupts (also blocks FreeQ) */ CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); ioc->active = 0; if (ioc->alt_ioc) { if (ioc->alt_ioc->active) reset_alt_ioc_active = 1; /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */ CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF); ioc->alt_ioc->active = 0; } hard = 1; if (reason == MPT_HOSTEVENT_IOC_BRINGUP) hard = 0; if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) { if (hard_reset_done == -4) { printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n", ioc->name); if (reset_alt_ioc_active && ioc->alt_ioc) { /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */ dprintk(ioc, printk(MYIOC_s_INFO_FMT "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name)); CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM); ioc->alt_ioc->active = 1; } } else { printk(MYIOC_s_WARN_FMT "NOT READY!\n", ioc->name); } return -1; } /* hard_reset_done = 0 if a soft reset was performed * and 1 if a hard reset was performed. */ if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) { if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0) alt_ioc_ready = 1; else printk(MYIOC_s_WARN_FMT "alt_ioc not ready!\n", ioc->alt_ioc->name); } for (ii=0; ii<5; ii++) { /* Get IOC facts! Allow 5 retries */ if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0) break; } if (ii == 5) { dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Retry IocFacts failed rc=%x\n", ioc->name, rc)); ret = -2; } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { MptDisplayIocCapabilities(ioc); } if (alt_ioc_ready) { if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) { dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc)); /* Retry - alt IOC was initialized once */ rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason); } if (rc) { dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc)); alt_ioc_ready = 0; reset_alt_ioc_active = 0; } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { MptDisplayIocCapabilities(ioc->alt_ioc); } } /* * Device is reset now. It must have de-asserted the interrupt line * (if it was asserted) and it should be safe to register for the * interrupt now. */ if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) { ioc->pci_irq = -1; if (ioc->pcidev->irq) { if (mpt_msi_enable && !pci_enable_msi(ioc->pcidev)) printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n", ioc->name); rc = request_irq(ioc->pcidev->irq, mpt_interrupt, IRQF_SHARED, ioc->name, ioc); if (rc < 0) { printk(MYIOC_s_ERR_FMT "Unable to allocate " "interrupt %d!\n", ioc->name, ioc->pcidev->irq); if (mpt_msi_enable) pci_disable_msi(ioc->pcidev); return -EBUSY; } irq_allocated = 1; ioc->pci_irq = ioc->pcidev->irq; pci_set_master(ioc->pcidev); /* ?? */ pci_set_drvdata(ioc->pcidev, ioc); dprintk(ioc, printk(MYIOC_s_INFO_FMT "installed at interrupt " "%d\n", ioc->name, ioc->pcidev->irq)); } } /* Prime reply & request queues! * (mucho alloc's) Must be done prior to * init as upper addresses are needed for init. * If fails, continue with alt-ioc processing */ if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0)) ret = -3; /* May need to check/upload firmware & data here! * If fails, continue with alt-ioc processing */ if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0)) ret = -4;// NEW! if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) { printk(MYIOC_s_WARN_FMT ": alt_ioc (%d) FIFO mgmt alloc!\n", ioc->alt_ioc->name, rc); alt_ioc_ready = 0; reset_alt_ioc_active = 0; } if (alt_ioc_ready) { if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) { alt_ioc_ready = 0; reset_alt_ioc_active = 0; printk(MYIOC_s_WARN_FMT "alt_ioc (%d) init failure!\n", ioc->alt_ioc->name, rc); } } if (reason == MPT_HOSTEVENT_IOC_BRINGUP){ if (ioc->upload_fw) { ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "firmware upload required!\n", ioc->name)); /* Controller is not operational, cannot do upload */ if (ret == 0) { rc = mpt_do_upload(ioc, sleepFlag); if (rc == 0) { if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) { /* * Maintain only one pointer to FW memory * so there will not be two attempt to * downloadboot onboard dual function * chips (mpt_adapter_disable, * mpt_diag_reset) */ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_upload: alt_%s has cached_fw=%p \n", ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw)); ioc->alt_ioc->cached_fw = NULL; } } else { printk(MYIOC_s_WARN_FMT "firmware upload failure!\n", ioc->name); ret = -5; } } } } if (ret == 0) { /* Enable! (reply interrupt) */ CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM); ioc->active = 1; } if (reset_alt_ioc_active && ioc->alt_ioc) { /* (re)Enable alt-IOC! (reply interrupt) */ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name)); CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM); ioc->alt_ioc->active = 1; } /* Enable MPT base driver management of EventNotification * and EventAck handling. */ if ((ret == 0) && (!ioc->facts.EventState)) (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */ if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState) (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */ /* Add additional "reason" check before call to GetLanConfigPages * (combined with GetIoUnitPage2 call). This prevents a somewhat * recursive scenario; GetLanConfigPages times out, timer expired * routine calls HardResetHandler, which calls into here again, * and we try GetLanConfigPages again... */ if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) { /* * Initalize link list for inactive raid volumes. */ init_MUTEX(&ioc->raid_data.inactive_list_mutex); INIT_LIST_HEAD(&ioc->raid_data.inactive_list); if (ioc->bus_type == SAS) { /* clear persistency table */ if(ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) { ret = mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT); if(ret != 0) goto out; } /* Find IM volumes */ mpt_findImVolumes(ioc); } else if (ioc->bus_type == FC) { if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) && (ioc->lan_cnfg_page0.Header.PageLength == 0)) { /* * Pre-fetch the ports LAN MAC address! * (LANPage1_t stuff) */ (void) GetLanConfigPages(ioc); a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow; dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n", ioc->name, a[5], a[4], a[3], a[2], a[1], a[0])); } } else { /* Get NVRAM and adapter maximums from SPP 0 and 2 */ mpt_GetScsiPortSettings(ioc, 0); /* Get version and length of SDP 1 */ mpt_readScsiDevicePageHeaders(ioc, 0); /* Find IM volumes */ if (ioc->facts.MsgVersion >= MPI_VERSION_01_02) mpt_findImVolumes(ioc); /* Check, and possibly reset, the coalescing value */ mpt_read_ioc_pg_1(ioc); mpt_read_ioc_pg_4(ioc); } GetIoUnitPage2(ioc); mpt_get_manufacturing_pg_0(ioc); } /* * Call each currently registered protocol IOC reset handler * with post-reset indication. * NOTE: If we're doing _IOC_BRINGUP, there can be no * MptResetHandlers[] registered yet. */ if (hard_reset_done) { rc = handlers = 0; for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { if ((ret == 0) && MptResetHandlers[cb_idx]) { dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC post_reset handler #%d\n", ioc->name, cb_idx)); rc += mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET); handlers++; } if (alt_ioc_ready && MptResetHandlers[cb_idx]) { drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC post_reset handler #%d\n", ioc->alt_ioc->name, cb_idx)); rc += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET); handlers++; } } /* FIXME? Examine results here? */ } out: if ((ret != 0) && irq_allocated) { free_irq(ioc->pci_irq, ioc); if (mpt_msi_enable) pci_disable_msi(ioc->pcidev); } return ret;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** * mpt_detect_bound_ports - Search for matching PCI bus/dev_function * @ioc: Pointer to MPT adapter structure * @pdev: Pointer to (struct pci_dev) structure * * Search for PCI bus/dev_function which matches * PCI bus/dev_function (+/-1) for newly discovered 929, * 929X, 1030 or 1035. * * If match on PCI dev_function +/-1 is found, bind the two MPT adapters * using alt_ioc pointer fields in their %MPT_ADAPTER structures. */static voidmpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev){ struct pci_dev *peer=NULL; unsigned int slot = PCI_SLOT(pdev->devfn); unsigned int func = PCI_FUNC(pdev->devfn); MPT_ADAPTER *ioc_srch; dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x," " searching for devfn match on %x or %x\n", ioc->name, pci_name(pdev), pdev->bus->number, pdev->devfn, func-1, func+1)); peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1)); if (!peer) { peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1)); if (!peer) return; } list_for_each_entry(ioc_srch, &ioc_list, list) { struct pci_dev *_pcidev = ioc_srch->pcidev; if (_pcidev == peer) { /* Paranoia checks */ if (ioc->alt_ioc != NULL) { printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n", ioc->name, ioc->alt_ioc->name); break; } else if (ioc_srch->alt_ioc != NULL) { printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n", ioc_srch->name, ioc_srch->alt_ioc->name); break; } dprintk(ioc, printk(MYIOC_s_INFO_FMT "FOUND! binding to %s\n", ioc->name, ioc_srch->name)); ioc_srch->alt_ioc = ioc; ioc->alt_ioc = ioc_srch; } } pci_dev_put(peer);}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** * mpt_adapter_disable - Disable misbehaving MPT adapter. * @ioc: Pointer to MPT adapter structure */static voidmpt_adapter_disable(MPT_ADAPTER *ioc){ int sz; int ret; if (ioc->cached_fw != NULL) { ddlprintk(ioc, printk(MYIOC_s_INFO_FMT "mpt_adapter_disable: Pushing FW onto adapter\n", ioc->name)); if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) { printk(MYIOC_s_WARN_FMT "firmware downloadboot failure (%d)!\n", ioc->name, ret); } } /* Disable adapter interrupts! */ CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); ioc->active = 0; /* Clear any lingering interrupt */ CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); if (ioc->alloc != NULL) { sz = ioc->alloc_sz; dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n", ioc->name, ioc->alloc, ioc->alloc_sz)); pci_free_consistent(ioc->pcidev, sz, ioc->alloc, ioc->alloc_dma); ioc->reply_frames = NULL; ioc->req_frames = NULL; ioc->alloc = NULL; ioc->alloc_total -= sz; } if (ioc->sense_buf_pool != NULL) { sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC); pci_free_consiste
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?