lpfc_sli.c
来自「linux2.6.16版本」· C语言 代码 · 共 2,499 行 · 第 1/5 页
C
2,499 行
} break; default: 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 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. */ to_slim = phba->MBslimaddr + (SLIMOFF + (pring->ringno * 2) + 1) * 4; writeb(pring->rspidx, to_slim); if (pring->rspidx == portRspPut) portRspPut = le32_to_cpu(pgp->rspPutInx); } ha_copy = readl(phba->HAregaddr); ha_copy >>= (LPFC_FCP_RING * 4); if ((rsp_cmpl > 0) && (ha_copy & HA_R0RE_REQ)) { pring->stats.iocb_rsp_full++; status = ((CA_R0ATT | CA_R0RE_RSP) << (LPFC_FCP_RING * 4)); writel(status, phba->CAregaddr); readl(phba->CAregaddr); } if ((ha_copy & 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); } return;}/* * This routine presumes LPFC_FCP_RING handling and doesn't bother * to check it explicitly. */static intlpfc_sli_handle_fast_ring_event(struct lpfc_hba * phba, struct lpfc_sli_ring * pring, uint32_t mask){ struct lpfc_pgp *pgp = &phba->slim2p->mbx.us.s2.port[pring->ringno]; IOCB_t *irsp = NULL; IOCB_t *entry = NULL; struct lpfc_iocbq *cmdiocbq = NULL; struct lpfc_iocbq rspiocbq; uint32_t status; uint32_t portRspPut, portRspMax; int rc = 1; lpfc_iocb_type type; unsigned long iflag; uint32_t rsp_cmpl = 0; 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 (unlikely(portRspPut >= portRspMax)) { lpfc_sli_rsp_pointers_error(phba, pring); spin_unlock_irqrestore(phba->host->host_lock, iflag); return 1; } rmb(); while (pring->rspidx != portRspPut) { /* * Fetch an entry off the ring and copy it into a local data * structure. The copy involves a byte-swap since the * network byte order and pci byte orders are different. */ entry = IOCB_ENTRY(pring->rspringaddr, pring->rspidx); if (++pring->rspidx >= portRspMax) pring->rspidx = 0; lpfc_sli_pcimem_bcopy((uint32_t *) entry, (uint32_t *) &rspiocbq.iocb, sizeof (IOCB_t)); irsp = &rspiocbq.iocb; type = lpfc_sli_iocb_cmd_type(irsp->ulpCommand & CMD_IOCB_MASK); pring->stats.iocb_rsp++; rsp_cmpl++; if (unlikely(irsp->ulpStatus)) { /* Rsp ring <ringno> error: IOCB */ lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, "%d:0326 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)); } switch (type) { case LPFC_ABORT_IOCB: case LPFC_SOL_IOCB: /* * Idle exchange closed via ABTS from port. No iocb * resources need to be recovered. */ if (unlikely(irsp->ulpCommand == CMD_XRI_ABORTED_CX)) { printk(KERN_INFO "%s: IOCB cmd 0x%x processed. " "Skipping completion\n", __FUNCTION__, irsp->ulpCommand); break; } cmdiocbq = lpfc_sli_iocbq_lookup(phba, pring, &rspiocbq); if ((cmdiocbq) && (cmdiocbq->iocb_cmpl)) { spin_unlock_irqrestore( phba->host->host_lock, iflag); (cmdiocbq->iocb_cmpl)(phba, cmdiocbq, &rspiocbq); spin_lock_irqsave(phba->host->host_lock, iflag); } break; default: 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 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. */ 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;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?