📄 lpfc_sli.c
字号:
} else { /* Unknown IOCB command */ lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "%d:0321 Unknown IOCB command " "Data: x%x, x%x x%x x%x x%x\n", phba->brd_no, type, irsp->ulpCommand, irsp->ulpStatus, irsp->ulpIoTag, irsp->ulpContext); } break; } /* * The response IOCB has been processed. Update the ring * pointer in SLIM. If the port response put pointer has not * been updated, sync the pgp->rspPutInx and fetch the new port * response put pointer. */ if (++pring->rspidx >= portRspMax) pring->rspidx = 0; to_slim = phba->MBslimaddr + (SLIMOFF + (pring->ringno * 2) + 1) * 4; writel(pring->rspidx, to_slim); if (pring->rspidx == portRspPut) portRspPut = le32_to_cpu(pgp->rspPutInx); } if ((rsp_cmpl > 0) && (mask & HA_R0RE_REQ)) { pring->stats.iocb_rsp_full++; status = ((CA_R0ATT | CA_R0RE_RSP) << (pring->ringno * 4)); writel(status, phba->CAregaddr); readl(phba->CAregaddr); } if ((mask & HA_R0CE_RSP) && (pring->flag & LPFC_CALL_RING_AVAILABLE)) { pring->flag &= ~LPFC_CALL_RING_AVAILABLE; pring->stats.iocb_cmd_empty++; /* Force update of the local copy of cmdGetInx */ pring->local_getidx = le32_to_cpu(pgp->cmdGetInx); lpfc_sli_resume_iocb(phba, pring); if ((pring->lpfc_sli_cmd_available)) (pring->lpfc_sli_cmd_available) (phba, pring); } spin_unlock_irqrestore(phba->host->host_lock, iflag); return rc;}intlpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba, struct lpfc_sli_ring * pring, uint32_t mask){ IOCB_t *entry; IOCB_t *irsp = NULL; struct lpfc_iocbq *rspiocbp = NULL; struct lpfc_iocbq *next_iocb; struct lpfc_iocbq *cmdiocbp; struct lpfc_iocbq *saveq; struct lpfc_pgp *pgp = &phba->slim2p->mbx.us.s2.port[pring->ringno]; uint8_t iocb_cmd_type; lpfc_iocb_type type; uint32_t status, free_saveq; uint32_t portRspPut, portRspMax; int rc = 1; unsigned long iflag; void __iomem *to_slim; spin_lock_irqsave(phba->host->host_lock, iflag); pring->stats.iocb_event++; /* * The next available response entry should never exceed the maximum * entries. If it does, treat it as an adapter hardware error. */ portRspMax = pring->numRiocb; portRspPut = le32_to_cpu(pgp->rspPutInx); if (portRspPut >= portRspMax) { /* * Ring <ringno> handler: portRspPut <portRspPut> is bigger then * rsp ring <portRspMax> */ lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "%d:0312 Ring %d handler: portRspPut %d " "is bigger then rsp ring %d\n", phba->brd_no, pring->ringno, portRspPut, portRspMax); phba->hba_state = LPFC_HBA_ERROR; spin_unlock_irqrestore(phba->host->host_lock, iflag); phba->work_hs = HS_FFER3; lpfc_handle_eratt(phba); return 1; } rmb(); while (pring->rspidx != portRspPut) { /* * Build a completion list and call the appropriate handler. * The process is to get the next available response iocb, get * a free iocb from the list, copy the response data into the * free iocb, insert to the continuation list, and update the * next response index to slim. This process makes response * iocb's in the ring available to DMA as fast as possible but * pays a penalty for a copy operation. Since the iocb is * only 32 bytes, this penalty is considered small relative to * the PCI reads for register values and a slim write. When * the ulpLe field is set, the entire Command has been * received. */ entry = IOCB_ENTRY(pring->rspringaddr, pring->rspidx); rspiocbp = lpfc_sli_get_iocbq(phba); if (rspiocbp == NULL) { printk(KERN_ERR "%s: out of buffers! Failing " "completion.\n", __FUNCTION__); break; } lpfc_sli_pcimem_bcopy(entry, &rspiocbp->iocb, sizeof (IOCB_t)); irsp = &rspiocbp->iocb; if (++pring->rspidx >= portRspMax) pring->rspidx = 0; to_slim = phba->MBslimaddr + (SLIMOFF + (pring->ringno * 2) + 1) * 4; writel(pring->rspidx, to_slim); if (list_empty(&(pring->iocb_continueq))) { list_add(&rspiocbp->list, &(pring->iocb_continueq)); } else { list_add_tail(&rspiocbp->list, &(pring->iocb_continueq)); } pring->iocb_continueq_cnt++; if (irsp->ulpLe) { /* * By default, the driver expects to free all resources * associated with this iocb completion. */ free_saveq = 1; saveq = list_get_first(&pring->iocb_continueq, struct lpfc_iocbq, list); irsp = &(saveq->iocb); list_del_init(&pring->iocb_continueq); pring->iocb_continueq_cnt = 0; pring->stats.iocb_rsp++; if (irsp->ulpStatus) { /* Rsp ring <ringno> error: IOCB */ lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, "%d:0328 Rsp Ring %d error: IOCB Data: " "x%x x%x x%x x%x x%x x%x x%x x%x\n", phba->brd_no, pring->ringno, irsp->un.ulpWord[0], irsp->un.ulpWord[1], irsp->un.ulpWord[2], irsp->un.ulpWord[3], irsp->un.ulpWord[4], irsp->un.ulpWord[5], *(((uint32_t *) irsp) + 6), *(((uint32_t *) irsp) + 7)); } /* * Fetch the IOCB command type and call the correct * completion routine. Solicited and Unsolicited * IOCBs on the ELS ring get freed back to the * lpfc_iocb_list by the discovery kernel thread. */ iocb_cmd_type = irsp->ulpCommand & CMD_IOCB_MASK; type = lpfc_sli_iocb_cmd_type(iocb_cmd_type); if (type == LPFC_SOL_IOCB) { spin_unlock_irqrestore(phba->host->host_lock, iflag); rc = lpfc_sli_process_sol_iocb(phba, pring, saveq); spin_lock_irqsave(phba->host->host_lock, iflag); } else if (type == LPFC_UNSOL_IOCB) { spin_unlock_irqrestore(phba->host->host_lock, iflag); rc = lpfc_sli_process_unsol_iocb(phba, pring, saveq); spin_lock_irqsave(phba->host->host_lock, iflag); } else if (type == LPFC_ABORT_IOCB) { if ((irsp->ulpCommand != CMD_XRI_ABORTED_CX) && ((cmdiocbp = lpfc_sli_iocbq_lookup(phba, pring, saveq)))) { /* Call the specified completion routine */ if (cmdiocbp->iocb_cmpl) { spin_unlock_irqrestore( phba->host->host_lock, iflag); (cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq); spin_lock_irqsave( phba->host->host_lock, iflag); } else lpfc_sli_release_iocbq(phba, cmdiocbp); } } else if (type == LPFC_UNKNOWN_IOCB) { if (irsp->ulpCommand == CMD_ADAPTER_MSG) { char adaptermsg[LPFC_MAX_ADPTMSG]; memset(adaptermsg, 0, LPFC_MAX_ADPTMSG); memcpy(&adaptermsg[0], (uint8_t *) irsp, MAX_MSG_DATA); dev_warn(&((phba->pcidev)->dev), "lpfc%d: %s", phba->brd_no, adaptermsg); } else { /* Unknown IOCB command */ lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "%d:0321 Unknown IOCB command " "Data: x%x x%x x%x x%x\n", phba->brd_no, irsp->ulpCommand, irsp->ulpStatus, irsp->ulpIoTag, irsp->ulpContext); } } if (free_saveq) { if (!list_empty(&saveq->list)) { list_for_each_entry_safe(rspiocbp, next_iocb, &saveq->list, list) { lpfc_sli_release_iocbq(phba, rspiocbp); } } lpfc_sli_release_iocbq(phba, saveq); } } /* * If the port response put pointer has not been updated, sync * the pgp->rspPutInx in the MAILBOX_tand fetch the new port * response put pointer. */ if (pring->rspidx == portRspPut) { portRspPut = le32_to_cpu(pgp->rspPutInx); } } /* while (pring->rspidx != portRspPut) */ if ((rspiocbp != 0) && (mask & HA_R0RE_REQ)) { /* At least one response entry has been freed */ pring->stats.iocb_rsp_full++; /* SET RxRE_RSP in Chip Att register */ status = ((CA_R0ATT | CA_R0RE_RSP) << (pring->ringno * 4)); writel(status, phba->CAregaddr); readl(phba->CAregaddr); /* flush */ } if ((mask & HA_R0CE_RSP) && (pring->flag & LPFC_CALL_RING_AVAILABLE)) { pring->flag &= ~LPFC_CALL_RING_AVAILABLE; pring->stats.iocb_cmd_empty++; /* Force update of the local copy of cmdGetInx */ pring->local_getidx = le32_to_cpu(pgp->cmdGetInx); lpfc_sli_resume_iocb(phba, pring); if ((pring->lpfc_sli_cmd_available)) (pring->lpfc_sli_cmd_available) (phba, pring); } spin_unlock_irqrestore(phba->host->host_lock, iflag); return rc;}intlpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring){ struct lpfc_iocbq *iocb, *next_iocb; IOCB_t *icmd = NULL, *cmd = NULL; int errcnt; errcnt = 0; /* Error everything on txq and txcmplq * First do the txq. */ spin_lock_irq(phba->host->host_lock); list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) { list_del_init(&iocb->list); if (iocb->iocb_cmpl) { icmd = &iocb->iocb; icmd->ulpStatus = IOSTAT_LOCAL_REJECT; icmd->un.ulpWord[4] = IOERR_SLI_ABORTED; spin_unlock_irq(phba->host->host_lock); (iocb->iocb_cmpl) (phba, iocb, iocb); spin_lock_irq(phba->host->host_lock); } else lpfc_sli_release_iocbq(phba, iocb); } pring->txq_cnt = 0; INIT_LIST_HEAD(&(pring->txq)); /* Next issue ABTS for everything on the txcmplq */ list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) { cmd = &iocb->iocb; /* * Imediate abort of IOCB, deque and call compl */ list_del_init(&iocb->list); pring->txcmplq_cnt--; if (iocb->iocb_cmpl) { cmd->ulpStatus = IOSTAT_LOCAL_REJECT; cmd->un.ulpWord[4] = IOERR_SLI_ABORTED; spin_unlock_irq(phba->host->host_lock); (iocb->iocb_cmpl) (phba, iocb, iocb); spin_lock_irq(phba->host->host_lock); } else lpfc_sli_release_iocbq(phba, iocb); } INIT_LIST_HEAD(&pring->txcmplq); pring->txcmplq_cnt = 0; spin_unlock_irq(phba->host->host_lock); return errcnt;}/******************************************************************************* lpfc_sli_send_reset** Note: After returning from this function, the HBA cannot be accessed for* 1 ms. Since we do not wish to delay in interrupt context, it is the* responsibility of the caller to perform the mdelay(1) and flush via readl().******************************************************************************/static intlpfc_sli_send_reset(struct lpfc_hba * phba, uint16_t skip_post){ MAILBOX_t *swpmb; volatile uint32_t word0; void __iomem *to_slim; unsigned long flags = 0; spin_lock_irqsave(phba->host->host_lock, flags); /* A board reset must use REAL SLIM. */ phba->sli.sli_flag &= ~LPFC_SLI2_ACTIVE; word0 = 0; swpmb = (MAILBOX_t *) & word0; swpmb->mbxCommand = MBX_RESTART; swpmb->mbxHc = 1; to_slim = phba->MBslimaddr; writel(*(uint32_t *) swpmb, to_slim); readl(to_slim); /* flush */ /* Only skip post after fc_ffinit is completed */ if (skip_post) { word0 = 1; /* This is really setting up word1 */ } else { word0 = 0; /* This is really setting up word1 */ } to_slim = phba->MBslimaddr + sizeof (uint32_t); writel(*(uint32_t *) swpmb, to_slim); readl(to_slim); /* flush */ /* Turn off parity checking and serr during the physical reset */ pci_read_config_word(phba->pcidev, PCI_COMMAND, &phba->pci_cfg_value); pci_write_config_word(phba->pcidev, PCI_COMMAND, (phba->pci_cfg_value & ~(PCI_COMMAND_PARITY | PCI_COMMAND_SERR))); writel(HC_INITFF, phba->HCregaddr); phba->hba_state = LPFC_INIT_START; spin_unlock_irqrestore(phba->host->host_lock, flags); return 0;}static intlpfc_sli_brdreset(struct lpfc_hba * phba, uint16_t skip_post){ struct lpfc_sli_ring *pring; int i; struct lpfc_dmabuf *mp, *next_mp; unsigned long flags = 0; lpfc_sli_send_reset(phba, skip_post); mdelay(1); spin_lock_irqsave(phba->host->host_lock, flags); /* Risk the write on flush case ie no delay after the readl */ readl(phba->HCregaddr); /* flush */ /* Now toggle INITFF bit set by lpfc_sli_send_reset */ writel(0, phba->HCregaddr); readl(phba->HCregaddr); /* flush */ /* Restore PCI cmd register */ pci_write_config_word(phba->pcidev, PCI_COMMAND, phba->pci_cfg_value); /* perform board reset */ phba->fc_eventTag = 0; phba->fc_myDID = 0; phba->fc_prevDID = Mask_DID; /* Reset HBA */ lpfc_printf_log(phba, KERN_INFO, LOG_SLI, "%d:0325 Reset HBA Data: x%x x%x x%x\n", phba->brd_no, phba->hba_state, phba->sli.sli_flag, skip_post); /* Initialize relevant SLI info */ for (i = 0; i < phba->sli.num_rings; i++) { pring = &phba->sli.ring[i]; pring->flag = 0; pring->rspidx = 0; pring->next_cmdidx = 0; pring->local_getidx = 0; pring->cmdidx = 0; pring->missbufcnt = 0; } spin_unlock_irqrestore(phba->host->host_lock, flags); if (skip_post) { mdelay(100); } else { mdelay(2000); } spin_lock_irqsave(phba->host->host_lock, flags); /* Cleanup preposted buffers on the ELS ring */ pring = &phba->sli.ring[LPFC_ELS_RING]; list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) { list_del(&mp->list); pring->postbufq_cnt--; lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); } spin_unlock_irqrestore(phba->host->host_lock, flags); for (i = 0; i < phba->sli.num_rings; i++) lpfc_sli_abort_iocb_ring(phba, &phba->sli.ring[i]); return 0;}static intlpfc_sli_chipset_init(struct lpfc_hba *phba){ uint32_t status, i = 0; /* Read the HBA Host Status Register */ status = readl(phba->HSregaddr); /* Check status register to see what current state is */ i = 0; while ((status & (HS_FFRDY | HS_MBRDY)) != (HS_FFRDY | HS_MBRDY)) { /* Check every 100ms for 5 retries, then every 500ms for 5, then * every 2.5 sec for 5, then reset board and every 2.5 sec for * 4. */ if (i++ >= 20) { /* Adapter failed to init, timeout, status reg <status> */ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "%d:0436 Adapter failed to init, " "timeout, status reg x%x\n", phba->brd_no, status); phba->hba_state = LPFC_HBA_ERROR; return -ETIMEDOUT;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -