⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lpfc_sli.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
			} 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 + -