lpfc_sli.c

来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 2,535 行 · 第 1/5 页

C
2,535
字号
	return errcnt;}intlpfc_sli_brdready(struct lpfc_hba * phba, uint32_t mask){	uint32_t status;	int i = 0;	int retval = 0;	/* Read the HBA Host Status Register */	status = readl(phba->HSregaddr);	/*	 * Check status register 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.	 * Break our of the loop if errors occurred during init.	 */	while (((status & mask) != mask) &&	       !(status & HS_FFERM) &&	       i++ < 20) {		if (i <= 5)			msleep(10);		else if (i <= 10)			msleep(500);		else			msleep(2500);		if (i == 15) {			phba->hba_state = LPFC_STATE_UNKNOWN; /* Do post */			lpfc_sli_brdrestart(phba);		}		/* Read the HBA Host Status Register */		status = readl(phba->HSregaddr);	}	/* Check to see if any errors occurred during init */	if ((status & HS_FFERM) || (i >= 20)) {		phba->hba_state = LPFC_HBA_ERROR;		retval = 1;	}	return retval;}#define BARRIER_TEST_PATTERN (0xdeadbeef)void lpfc_reset_barrier(struct lpfc_hba * phba){	uint32_t * resp_buf;	uint32_t * mbox_buf;	volatile uint32_t mbox;	uint32_t hc_copy;	int  i;	uint8_t hdrtype;	pci_read_config_byte(phba->pcidev, PCI_HEADER_TYPE, &hdrtype);	if (hdrtype != 0x80 ||	    (FC_JEDEC_ID(phba->vpd.rev.biuRev) != HELIOS_JEDEC_ID &&	     FC_JEDEC_ID(phba->vpd.rev.biuRev) != THOR_JEDEC_ID))		return;	/*	 * Tell the other part of the chip to suspend temporarily all	 * its DMA activity.	 */	resp_buf =  (uint32_t *)phba->MBslimaddr;	/* Disable the error attention */	hc_copy = readl(phba->HCregaddr);	writel((hc_copy & ~HC_ERINT_ENA), phba->HCregaddr);	readl(phba->HCregaddr); /* flush */	if (readl(phba->HAregaddr) & HA_ERATT) {		/* Clear Chip error bit */		writel(HA_ERATT, phba->HAregaddr);		phba->stopped = 1;	}	mbox = 0;	((MAILBOX_t *)&mbox)->mbxCommand = MBX_KILL_BOARD;	((MAILBOX_t *)&mbox)->mbxOwner = OWN_CHIP;	writel(BARRIER_TEST_PATTERN, (resp_buf + 1));	mbox_buf = (uint32_t *)phba->MBslimaddr;	writel(mbox, mbox_buf);	for (i = 0;	     readl(resp_buf + 1) != ~(BARRIER_TEST_PATTERN) && i < 50; i++)		mdelay(1);	if (readl(resp_buf + 1) != ~(BARRIER_TEST_PATTERN)) {		if (phba->sli.sli_flag & LPFC_SLI2_ACTIVE ||		    phba->stopped)			goto restore_hc;		else			goto clear_errat;	}	((MAILBOX_t *)&mbox)->mbxOwner = OWN_HOST;	for (i = 0; readl(resp_buf) != mbox &&  i < 500; i++)		mdelay(1);clear_errat:	while (!(readl(phba->HAregaddr) & HA_ERATT) && ++i < 500)		mdelay(1);	if (readl(phba->HAregaddr) & HA_ERATT) {		writel(HA_ERATT, phba->HAregaddr);		phba->stopped = 1;	}restore_hc:	writel(hc_copy, phba->HCregaddr);	readl(phba->HCregaddr); /* flush */}intlpfc_sli_brdkill(struct lpfc_hba * phba){	struct lpfc_sli *psli;	LPFC_MBOXQ_t *pmb;	uint32_t status;	uint32_t ha_copy;	int retval;	int i = 0;	psli = &phba->sli;	/* Kill HBA */	lpfc_printf_log(phba,		KERN_INFO,		LOG_SLI,		"%d:0329 Kill HBA Data: x%x x%x\n",		phba->brd_no,		phba->hba_state,		psli->sli_flag);	if ((pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool,						  GFP_KERNEL)) == 0)		return 1;	/* Disable the error attention */	spin_lock_irq(phba->host->host_lock);	status = readl(phba->HCregaddr);	status &= ~HC_ERINT_ENA;	writel(status, phba->HCregaddr);	readl(phba->HCregaddr); /* flush */	spin_unlock_irq(phba->host->host_lock);	lpfc_kill_board(phba, pmb);	pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;	retval = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);	if (retval != MBX_SUCCESS) {		if (retval != MBX_BUSY)			mempool_free(pmb, phba->mbox_mem_pool);		return 1;	}	psli->sli_flag &= ~LPFC_SLI2_ACTIVE;	mempool_free(pmb, phba->mbox_mem_pool);	/* There is no completion for a KILL_BOARD mbox cmd. Check for an error	 * attention every 100ms for 3 seconds. If we don't get ERATT after	 * 3 seconds we still set HBA_ERROR state because the status of the	 * board is now undefined.	 */	ha_copy = readl(phba->HAregaddr);	while ((i++ < 30) && !(ha_copy & HA_ERATT)) {		mdelay(100);		ha_copy = readl(phba->HAregaddr);	}	del_timer_sync(&psli->mbox_tmo);	if (ha_copy & HA_ERATT) {		writel(HA_ERATT, phba->HAregaddr);		phba->stopped = 1;	}	spin_lock_irq(phba->host->host_lock);	psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;	spin_unlock_irq(phba->host->host_lock);	psli->mbox_active = NULL;	lpfc_hba_down_post(phba);	phba->hba_state = LPFC_HBA_ERROR;	return (ha_copy & HA_ERATT ? 0 : 1);}intlpfc_sli_brdreset(struct lpfc_hba * phba){	struct lpfc_sli *psli;	struct lpfc_sli_ring *pring;	uint16_t cfg_value;	int i;	psli = &phba->sli;	/* Reset HBA */	lpfc_printf_log(phba, KERN_INFO, LOG_SLI,			"%d:0325 Reset HBA Data: x%x x%x\n", phba->brd_no,			phba->hba_state, psli->sli_flag);	/* perform board reset */	phba->fc_eventTag = 0;	phba->fc_myDID = 0;	phba->fc_prevDID = 0;	psli->sli_flag = 0;	/* Turn off parity checking and serr during the physical reset */	pci_read_config_word(phba->pcidev, PCI_COMMAND, &cfg_value);	pci_write_config_word(phba->pcidev, PCI_COMMAND,			      (cfg_value &			       ~(PCI_COMMAND_PARITY | PCI_COMMAND_SERR)));	psli->sli_flag &= ~LPFC_SLI2_ACTIVE;	/* Now toggle INITFF bit in the Host Control Register */	writel(HC_INITFF, phba->HCregaddr);	mdelay(1);	readl(phba->HCregaddr); /* flush */	writel(0, phba->HCregaddr);	readl(phba->HCregaddr); /* flush */	/* Restore PCI cmd register */	pci_write_config_word(phba->pcidev, PCI_COMMAND, cfg_value);	/* Initialize relevant SLI info */	for (i = 0; i < psli->num_rings; i++) {		pring = &psli->ring[i];		pring->flag = 0;		pring->rspidx = 0;		pring->next_cmdidx  = 0;		pring->local_getidx = 0;		pring->cmdidx = 0;		pring->missbufcnt = 0;	}	phba->hba_state = LPFC_WARM_START;	return 0;}intlpfc_sli_brdrestart(struct lpfc_hba * phba){	MAILBOX_t *mb;	struct lpfc_sli *psli;	uint16_t skip_post;	volatile uint32_t word0;	void __iomem *to_slim;	spin_lock_irq(phba->host->host_lock);	psli = &phba->sli;	/* Restart HBA */	lpfc_printf_log(phba, KERN_INFO, LOG_SLI,			"%d:0328 Restart HBA Data: x%x x%x\n", phba->brd_no,			phba->hba_state, psli->sli_flag);	word0 = 0;	mb = (MAILBOX_t *) &word0;	mb->mbxCommand = MBX_RESTART;	mb->mbxHc = 1;	lpfc_reset_barrier(phba);	to_slim = phba->MBslimaddr;	writel(*(uint32_t *) mb, to_slim);	readl(to_slim); /* flush */	/* Only skip post after fc_ffinit is completed */	if (phba->hba_state) {		skip_post = 1;		word0 = 1;	/* This is really setting up word1 */	} else {		skip_post = 0;		word0 = 0;	/* This is really setting up word1 */	}	to_slim = (uint8_t *) phba->MBslimaddr + sizeof (uint32_t);	writel(*(uint32_t *) mb, to_slim);	readl(to_slim); /* flush */	lpfc_sli_brdreset(phba);	phba->stopped = 0;	phba->hba_state = LPFC_INIT_START;	spin_unlock_irq(phba->host->host_lock);	if (skip_post)		mdelay(100);	else		mdelay(2000);	lpfc_hba_down_post(phba);	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;		}		/* Check to see if any errors occurred during init */		if (status & HS_FFERM) {			/* ERROR: During chipset initialization */			/* Adapter failed to init, chipset, status reg			   <status> */			lpfc_printf_log(phba,					KERN_ERR,					LOG_INIT,					"%d:0437 Adapter failed to init, "					"chipset, status reg x%x\n",					phba->brd_no,					status);			phba->hba_state = LPFC_HBA_ERROR;			return -EIO;		}		if (i <= 5) {			msleep(10);		} else if (i <= 10) {			msleep(500);		} else {			msleep(2500);		}		if (i == 15) {			phba->hba_state = LPFC_STATE_UNKNOWN; /* Do post */			lpfc_sli_brdrestart(phba);		}		/* Read the HBA Host Status Register */		status = readl(phba->HSregaddr);	}	/* Check to see if any errors occurred during init */	if (status & HS_FFERM) {		/* ERROR: During chipset initialization */		/* Adapter failed to init, chipset, status reg <status> */		lpfc_printf_log(phba,				KERN_ERR,				LOG_INIT,				"%d:0438 Adapter failed to init, chipset, "				"status reg x%x\n",				phba->brd_no,				status);		phba->hba_state = LPFC_HBA_ERROR;		return -EIO;	}	/* Clear all interrupt enable conditions */	writel(0, phba->HCregaddr);	readl(phba->HCregaddr); /* flush */	/* setup host attn register */	writel(0xffffffff, phba->HAregaddr);	readl(phba->HAregaddr); /* flush */	return 0;}intlpfc_sli_hba_setup(struct lpfc_hba * phba){	LPFC_MBOXQ_t *pmb;	uint32_t resetcount = 0, rc = 0, done = 0;	pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);	if (!pmb) {		phba->hba_state = LPFC_HBA_ERROR;		return -ENOMEM;	}	while (resetcount < 2 && !done) {		phba->hba_state = LPFC_STATE_UNKNOWN;		lpfc_sli_brdrestart(phba);		msleep(2500);		rc = lpfc_sli_chipset_init(phba);		if (rc)			break;		resetcount++;	/* Call pre CONFIG_PORT mailbox command initialization.  A value of 0	 * means the call was successful.  Any other nonzero value is a failure,	 * but if ERESTART is returned, the driver may reset the HBA and try	 * again.	 */		rc = lpfc_config_port_prep(phba);		if (rc == -ERESTART) {			phba->hba_state = 0;			continue;		} else if (rc) {			break;		}		phba->hba_state = LPFC_INIT_MBX_CMDS;		lpfc_config_port(phba, pmb);		rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);		if (rc == MBX_SUCCESS)			done = 1;		else {			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,				"%d:0442 Adapter failed to init, mbxCmd x%x "				"CONFIG_PORT, mbxStatus x%x Data: x%x\n",				phba->brd_no, pmb->mb.mbxCommand,				pmb->mb.mbxStatus, 0);			phba->sli.sli_flag &= ~LPFC_SLI2_ACTIVE;		}	}	if (!done)		goto lpfc_sli_hba_setup_error;	rc = lpfc_sli_ring_map(phba, pmb);	if (rc)		goto lpfc_sli_hba_setup_error;	phba->sli.sli_flag |= LPFC_PROCESS_LA;	rc = lpfc_config_port_post(phba);	if (rc)		goto lpfc_sli_hba_setup_error;	goto lpfc_sli_hba_setup_exit;lpfc_sli_hba_setup_error:	phba->hba_state = LPFC_HBA_ERROR;lpfc_sli_hba_setup_exit:	mempool_free(pmb, phba->mbox_mem_pool);	return rc;}static voidlpfc_mbox_abort(struct lpfc_hba * phba){	LPFC_MBOXQ_t *pmbox;	MAILBOX_t *mb;	if (phba->sli.mbox_active) {		del_timer_sync(&phba->sli.mbox_tmo);		phba->work_hba_events &= ~WORKER_MBOX_TMO;		pmbox = phba->sli.mbox_active;		mb = &pmbox->mb;		phba->sli.mbox_active = NULL;		if (pmbox->mbox_cmpl) {			mb->mbxStatus = MBX_NOT_FINISHED;			(pmbox->mbox_cmpl) (phba, pmbox);		}		phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;	}	/* Abort all the non active mailbox commands. */	spin_lock_irq(phba->host->host_lock);	pmbox = lpfc_mbox_get(phba);	while (pmbox) {		mb = &pmbox->mb;		if (pmbox->mbox_cmpl) {			mb->mbxStatus = MBX_NOT_FINISHED;			spin_unlock_irq(phba->host->host_lock);			(pmbox->mbox_cmpl) (phba, pmbox);			spin_lock_irq(phba->host->host_lock);		}		pmbox = lpfc_mbox_get(phba);	}	spin_unlock_irq(phba->host->host_lock);	return;}/*! lpfc_mbox_timeout * * \pre * \post * \param hba Pointer to per struct lpfc_hba structure * \param l1  Pointer to the driver's mailbox queue. * \return

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?