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

📄 lpfc_init.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
/******************************************************************* * This file is part of the Emulex Linux Device Driver for         * * Fibre Channel Host Bus Adapters.                                * * Copyright (C) 2004-2005 Emulex.  All rights reserved.           * * EMULEX and SLI are trademarks of Emulex.                        * * www.emulex.com                                                  * * Portions Copyright (C) 2004-2005 Christoph Hellwig              * *                                                                 * * This program is free software; you can redistribute it and/or   * * modify it under the terms of version 2 of the GNU General       * * Public License as published by the Free Software Foundation.    * * This program is distributed in the hope that it will be useful. * * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          * * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  * * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      * * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * * TO BE LEGALLY INVALID.  See the GNU General Public License for  * * more details, a copy of which can be found in the file COPYING  * * included with this package.                                     * *******************************************************************/#include <linux/blkdev.h>#include <linux/delay.h>#include <linux/dma-mapping.h>#include <linux/idr.h>#include <linux/interrupt.h>#include <linux/kthread.h>#include <linux/pci.h>#include <linux/spinlock.h>#include <scsi/scsi.h>#include <scsi/scsi_device.h>#include <scsi/scsi_host.h>#include <scsi/scsi_transport_fc.h>#include "lpfc_hw.h"#include "lpfc_sli.h"#include "lpfc_disc.h"#include "lpfc_scsi.h"#include "lpfc.h"#include "lpfc_logmsg.h"#include "lpfc_crtn.h"#include "lpfc_version.h"static int lpfc_parse_vpd(struct lpfc_hba *, uint8_t *);static void lpfc_get_hba_model_desc(struct lpfc_hba *, uint8_t *, uint8_t *);static int lpfc_post_rcv_buf(struct lpfc_hba *);static struct scsi_transport_template *lpfc_transport_template = NULL;static DEFINE_IDR(lpfc_hba_index);/************************************************************************//*                                                                      *//*    lpfc_config_port_prep                                             *//*    This routine will do LPFC initialization prior to the             *//*    CONFIG_PORT mailbox command. This will be initialized             *//*    as a SLI layer callback routine.                                  *//*    This routine returns 0 on success or -ERESTART if it wants        *//*    the SLI layer to reset the HBA and try again. Any                 *//*    other return value indicates an error.                            *//*                                                                      *//************************************************************************/intlpfc_config_port_prep(struct lpfc_hba * phba){	lpfc_vpd_t *vp = &phba->vpd;	int i = 0, rc;	LPFC_MBOXQ_t *pmb;	MAILBOX_t *mb;	char *lpfc_vpd_data = NULL;	uint16_t offset = 0;	static char licensed[56] =		    "key unlock for use with gnu public licensed code only\0";	pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);	if (!pmb) {		phba->hba_state = LPFC_HBA_ERROR;		return -ENOMEM;	}	mb = &pmb->mb;	phba->hba_state = LPFC_INIT_MBX_CMDS;	if (lpfc_is_LC_HBA(phba->pcidev->device)) {		uint32_t *ptext = (uint32_t *) licensed;		for (i = 0; i < 56; i += sizeof (uint32_t), ptext++)			*ptext = cpu_to_be32(*ptext);		lpfc_read_nv(phba, pmb);		memset((char*)mb->un.varRDnvp.rsvd3, 0,			sizeof (mb->un.varRDnvp.rsvd3));		memcpy((char*)mb->un.varRDnvp.rsvd3, licensed,			 sizeof (licensed));		rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);		if (rc != MBX_SUCCESS) {			lpfc_printf_log(phba,					KERN_ERR,					LOG_MBOX,					"%d:0324 Config Port initialization "					"error, mbxCmd x%x READ_NVPARM, "					"mbxStatus x%x\n",					phba->brd_no,					mb->mbxCommand, mb->mbxStatus);			mempool_free(pmb, phba->mbox_mem_pool);			return -ERESTART;		}		memcpy(phba->wwnn, (char *)mb->un.varRDnvp.nodename,		       sizeof (mb->un.varRDnvp.nodename));	}	/* Setup and issue mailbox READ REV command */	lpfc_read_rev(phba, pmb);	rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);	if (rc != MBX_SUCCESS) {		lpfc_printf_log(phba,				KERN_ERR,				LOG_INIT,				"%d:0439 Adapter failed to init, mbxCmd x%x "				"READ_REV, mbxStatus x%x\n",				phba->brd_no,				mb->mbxCommand, mb->mbxStatus);		mempool_free( pmb, phba->mbox_mem_pool);		return -ERESTART;	}	/* The HBA's current state is provided by the ProgType and rr fields.	 * Read and check the value of these fields before continuing to config	 * this port.	 */	if (mb->un.varRdRev.rr == 0 || mb->un.varRdRev.un.b.ProgType != 2) {		/* Old firmware */		vp->rev.rBit = 0;		lpfc_printf_log(phba,				KERN_ERR,				LOG_INIT,				"%d:0440 Adapter failed to init, mbxCmd x%x "				"READ_REV detected outdated firmware"				"Data: x%x\n",				phba->brd_no,				mb->mbxCommand, 0);		mempool_free(pmb, phba->mbox_mem_pool);		return -ERESTART;	} else {		vp->rev.rBit = 1;		vp->rev.sli1FwRev = mb->un.varRdRev.sli1FwRev;		memcpy(vp->rev.sli1FwName,			(char*)mb->un.varRdRev.sli1FwName, 16);		vp->rev.sli2FwRev = mb->un.varRdRev.sli2FwRev;		memcpy(vp->rev.sli2FwName,					(char *)mb->un.varRdRev.sli2FwName, 16);	}	/* Save information as VPD data */	vp->rev.biuRev = mb->un.varRdRev.biuRev;	vp->rev.smRev = mb->un.varRdRev.smRev;	vp->rev.smFwRev = mb->un.varRdRev.un.smFwRev;	vp->rev.endecRev = mb->un.varRdRev.endecRev;	vp->rev.fcphHigh = mb->un.varRdRev.fcphHigh;	vp->rev.fcphLow = mb->un.varRdRev.fcphLow;	vp->rev.feaLevelHigh = mb->un.varRdRev.feaLevelHigh;	vp->rev.feaLevelLow = mb->un.varRdRev.feaLevelLow;	vp->rev.postKernRev = mb->un.varRdRev.postKernRev;	vp->rev.opFwRev = mb->un.varRdRev.opFwRev;	if (lpfc_is_LC_HBA(phba->pcidev->device))		memcpy(phba->RandomData, (char *)&mb->un.varWords[24],						sizeof (phba->RandomData));	/* Get the default values for Model Name and Description */	lpfc_get_hba_model_desc(phba, phba->ModelName, phba->ModelDesc);	/* Get adapter VPD information */	pmb->context2 = kmalloc(DMP_RSP_SIZE, GFP_KERNEL);	if (!pmb->context2)		goto out_free_mbox;	lpfc_vpd_data = kmalloc(DMP_VPD_SIZE, GFP_KERNEL);	if (!lpfc_vpd_data)		goto out_free_context2;	do {		lpfc_dump_mem(phba, pmb, offset);		rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);		if (rc != MBX_SUCCESS) {			lpfc_printf_log(phba, KERN_INFO, LOG_INIT,					"%d:0441 VPD not present on adapter, "					"mbxCmd x%x DUMP VPD, mbxStatus x%x\n",					phba->brd_no,					mb->mbxCommand, mb->mbxStatus);			kfree(lpfc_vpd_data);			lpfc_vpd_data = NULL;			break;		}		lpfc_sli_pcimem_bcopy(pmb->context2, lpfc_vpd_data + offset,							mb->un.varDmp.word_cnt);		offset += mb->un.varDmp.word_cnt;	} while (mb->un.varDmp.word_cnt);	lpfc_parse_vpd(phba, lpfc_vpd_data);	kfree(lpfc_vpd_data);out_free_context2:	kfree(pmb->context2);out_free_mbox:	mempool_free(pmb, phba->mbox_mem_pool);	return 0;}/************************************************************************//*                                                                      *//*    lpfc_config_port_post                                             *//*    This routine will do LPFC initialization after the                *//*    CONFIG_PORT mailbox command. This will be initialized             *//*    as a SLI layer callback routine.                                  *//*    This routine returns 0 on success. Any other return value         *//*    indicates an error.                                               *//*                                                                      *//************************************************************************/intlpfc_config_port_post(struct lpfc_hba * phba){	LPFC_MBOXQ_t *pmb;	MAILBOX_t *mb;	struct lpfc_dmabuf *mp;	struct lpfc_sli *psli = &phba->sli;	uint32_t status, timeout;	int i, j, rc;	pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);	if (!pmb) {		phba->hba_state = LPFC_HBA_ERROR;		return -ENOMEM;	}	mb = &pmb->mb;	lpfc_config_link(phba, pmb);	rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);	if (rc != MBX_SUCCESS) {		lpfc_printf_log(phba,				KERN_ERR,				LOG_INIT,				"%d:0447 Adapter failed init, mbxCmd x%x "				"CONFIG_LINK mbxStatus x%x\n",				phba->brd_no,				mb->mbxCommand, mb->mbxStatus);		phba->hba_state = LPFC_HBA_ERROR;		mempool_free( pmb, phba->mbox_mem_pool);		return -EIO;	}	/* Get login parameters for NID.  */	lpfc_read_sparam(phba, pmb);	if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) {		lpfc_printf_log(phba,				KERN_ERR,				LOG_INIT,				"%d:0448 Adapter failed init, mbxCmd x%x "				"READ_SPARM mbxStatus x%x\n",				phba->brd_no,				mb->mbxCommand, mb->mbxStatus);		phba->hba_state = LPFC_HBA_ERROR;		mp = (struct lpfc_dmabuf *) pmb->context1;		mempool_free( pmb, phba->mbox_mem_pool);		lpfc_mbuf_free(phba, mp->virt, mp->phys);		kfree(mp);		return -EIO;	}	mp = (struct lpfc_dmabuf *) pmb->context1;	memcpy(&phba->fc_sparam, mp->virt, sizeof (struct serv_parm));	lpfc_mbuf_free(phba, mp->virt, mp->phys);	kfree(mp);	pmb->context1 = NULL;	memcpy(&phba->fc_nodename, &phba->fc_sparam.nodeName,	       sizeof (struct lpfc_name));	memcpy(&phba->fc_portname, &phba->fc_sparam.portName,	       sizeof (struct lpfc_name));	/* If no serial number in VPD data, use low 6 bytes of WWNN */	/* This should be consolidated into parse_vpd ? - mr */	if (phba->SerialNumber[0] == 0) {		uint8_t *outptr;		outptr = &phba->fc_nodename.u.s.IEEE[0];		for (i = 0; i < 12; i++) {			status = *outptr++;			j = ((status & 0xf0) >> 4);			if (j <= 9)				phba->SerialNumber[i] =				    (char)((uint8_t) 0x30 + (uint8_t) j);			else				phba->SerialNumber[i] =				    (char)((uint8_t) 0x61 + (uint8_t) (j - 10));			i++;			j = (status & 0xf);			if (j <= 9)				phba->SerialNumber[i] =				    (char)((uint8_t) 0x30 + (uint8_t) j);			else				phba->SerialNumber[i] =				    (char)((uint8_t) 0x61 + (uint8_t) (j - 10));		}	}	/* This should turn on DELAYED ABTS for ELS timeouts */	lpfc_set_slim(phba, pmb, 0x052198, 0x1);	if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) {		phba->hba_state = LPFC_HBA_ERROR;		mempool_free( pmb, phba->mbox_mem_pool);		return -EIO;	}	lpfc_read_config(phba, pmb);	if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) {		lpfc_printf_log(phba,				KERN_ERR,				LOG_INIT,				"%d:0453 Adapter failed to init, mbxCmd x%x "				"READ_CONFIG, mbxStatus x%x\n",				phba->brd_no,				mb->mbxCommand, mb->mbxStatus);		phba->hba_state = LPFC_HBA_ERROR;		mempool_free( pmb, phba->mbox_mem_pool);		return -EIO;	}	/* Reset the DFT_HBA_Q_DEPTH to the max xri  */	if (phba->cfg_hba_queue_depth > (mb->un.varRdConfig.max_xri+1))		phba->cfg_hba_queue_depth =			mb->un.varRdConfig.max_xri + 1;	phba->lmt = mb->un.varRdConfig.lmt;	/* HBA is not 4GB capable, or HBA is not 2GB capable,	don't let link speed ask for it */	if ((((phba->lmt & LMT_4250_10bit) != LMT_4250_10bit) &&		(phba->cfg_link_speed > LINK_SPEED_2G)) ||		(((phba->lmt & LMT_2125_10bit) != LMT_2125_10bit) &&		(phba->cfg_link_speed > LINK_SPEED_1G))) {		/* Reset link speed to auto. 1G/2GB HBA cfg'd for 4G */		lpfc_printf_log(phba,			KERN_WARNING,			LOG_LINK_EVENT,			"%d:1302 Invalid speed for this board: "			"Reset link speed to auto: x%x\n",			phba->brd_no,			phba->cfg_link_speed);			phba->cfg_link_speed = LINK_SPEED_AUTO;	}	phba->hba_state = LPFC_LINK_DOWN;	/* Only process IOCBs on ring 0 till hba_state is READY */	if (psli->ring[psli->ip_ring].cmdringaddr)		psli->ring[psli->ip_ring].flag |= LPFC_STOP_IOCB_EVENT;	if (psli->ring[psli->fcp_ring].cmdringaddr)		psli->ring[psli->fcp_ring].flag |= LPFC_STOP_IOCB_EVENT;	if (psli->ring[psli->next_ring].cmdringaddr)		psli->ring[psli->next_ring].flag |= LPFC_STOP_IOCB_EVENT;	/* Post receive buffers for desired rings */	lpfc_post_rcv_buf(phba);	/* Enable appropriate host interrupts */	spin_lock_irq(phba->host->host_lock);	status = readl(phba->HCregaddr);	status |= HC_MBINT_ENA | HC_ERINT_ENA | HC_LAINT_ENA;	if (psli->num_rings > 0)		status |= HC_R0INT_ENA;	if (psli->num_rings > 1)		status |= HC_R1INT_ENA;	if (psli->num_rings > 2)		status |= HC_R2INT_ENA;	if (psli->num_rings > 3)		status |= HC_R3INT_ENA;	writel(status, phba->HCregaddr);	readl(phba->HCregaddr); /* flush */	spin_unlock_irq(phba->host->host_lock);	/*	 * Setup the ring 0 (els)  timeout handler	 */	timeout = phba->fc_ratov << 1;	phba->els_tmofunc.expires = jiffies + HZ * timeout;	add_timer(&phba->els_tmofunc);	lpfc_init_link(phba, pmb, phba->cfg_topology, phba->cfg_link_speed);	pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;	if (lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT) != MBX_SUCCESS) {		lpfc_printf_log(phba,				KERN_ERR,				LOG_INIT,				"%d:0454 Adapter failed to init, mbxCmd x%x "				"INIT_LINK, mbxStatus x%x\n",				phba->brd_no,				mb->mbxCommand, mb->mbxStatus);		/* Clear all interrupt enable conditions */		writel(0, phba->HCregaddr);		readl(phba->HCregaddr); /* flush */		/* Clear all pending interrupts */		writel(0xffffffff, phba->HAregaddr);		readl(phba->HAregaddr); /* flush */		phba->hba_state = LPFC_HBA_ERROR;		mempool_free(pmb, phba->mbox_mem_pool);		return -EIO;	}	/* MBOX buffer will be freed in mbox compl */	i = 0;	while ((phba->hba_state != LPFC_HBA_READY) ||	       (phba->num_disc_nodes) || (phba->fc_prli_sent) ||	       ((phba->fc_map_cnt == 0) && (i<2)) ||	       (psli->sli_flag & LPFC_SLI_MBOX_ACTIVE)) {		/* Check every second for 30 retries. */		i++;		if (i > 30) {			break;		}		if ((i >= 15) && (phba->hba_state <= LPFC_LINK_DOWN)) {			/* The link is down.  Set linkdown timeout */			break;		}		/* Delay for 1 second to give discovery time to complete. */		msleep(1000);	}	/* Since num_disc_nodes keys off of PLOGI, delay a bit to let

⌨️ 快捷键说明

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