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 + -
显示快捷键?