lpfc: add Emulex FC driver version 8.0.28

From: 	James.Smart@Emulex.Com

Modified for kernel import and
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
This commit is contained in:
2005-04-17 16:05:31 -05:00 committed by James Bottomley
parent 8e8790415e
commit dea3101e0a
24 changed files with 22885 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,83 @@
LPFC Driver Release Notes:
=============================================================================
IMPORTANT:
Starting in the 8.0.17 release, the driver began to be targeted strictly
toward the upstream kernel. As such, we removed #ifdefs for older kernels
(pre 2.6.10). The 8.0.16 release should be used if the driver is to be
run on one of the older kernels.
The proposed modifications to the transport layer for FC remote ports
and extended attribute support is now part of the upstream kernel
as of 2.6.12. We no longer need to provide patches for this support,
nor a *full* version which has old an new kernel support.
The driver now requires a 2.6.12 (if pre-release, 2.6.12-rc1) or later
kernel.
Please heed these dependencies....
********************************************************************
The following information is provided for additional background on the
history of the driver as we push for upstream acceptance.
Cable pull and temporary device Loss:
In older revisions of the lpfc driver, the driver internally queued i/o
received from the midlayer. In the cases where a cable was pulled, link
jitter, or a device temporarily loses connectivity (due to its cable
being removed, a switch rebooting, or a device reboot), the driver could
hide the disappearance of the device from the midlayer. I/O's issued to
the LLDD would simply be queued for a short duration, allowing the device
to reappear or link come back alive, with no inadvertant side effects
to the system. If the driver did not hide these conditions, i/o would be
errored by the driver, the mid-layer would exhaust its retries, and the
device would be taken offline. Manual intervention would be required to
re-enable the device.
The community supporting kernel.org has driven an effort to remove
internal queuing from all LLDDs. The philosophy is that internal
queuing is unnecessary as the block layer already performs the
queuing. Removing the queues from the LLDD makes a more predictable
and more simple LLDD.
As a potential new addition to kernel.org, the 8.x driver was asked to
have all internal queuing removed. Emulex complied with this request.
In explaining the impacts of this change, Emulex has worked with the
community in modifying the behavior of the SCSI midlayer so that SCSI
devices can be temporarily suspended while transport events (such as
those described) can occur.
The proposed patch was posted to the linux-scsi mailing list. The patch
is contained in the 2.6.10-rc2 (and later) patch kits. As such, this
patch is part of the standard 2.6.10 kernel.
By default, the driver expects the patches for block/unblock interfaces
to be present in the kernel. No #define needs to be set to enable support.
Kernel Support
This source package is targeted for the upstream kernel only. (See notes
at the top of this file). It relies on interfaces that are slowing
migrating into the kernel.org kernel.
At this time, the driver requires the 2.6.12 (if pre-release, 2.6.12-rc1)
kernel.
If a driver is needed for older kernels please utilize the 8.0.16
driver sources.
Patches
Thankfully, at this time, patches are not needed.

View File

@ -1314,6 +1314,14 @@ config SCSI_QLOGICPTI
source "drivers/scsi/qla2xxx/Kconfig"
config SCSI_LPFC
tristate "Emulex LightPulse Fibre Channel Support"
depends on PCI && SCSI
select SCSI_FC_ATTRS
help
This lpfc driver supports the Emulex LightPulse
Family of Fibre Channel PCI host adapters.
config SCSI_SEAGATE
tristate "Seagate ST-02 and Future Domain TMC-8xx SCSI support"
depends on X86 && ISA && SCSI && BROKEN

View File

@ -80,6 +80,7 @@ obj-$(CONFIG_SCSI_QLOGIC_ISP) += qlogicisp.o
obj-$(CONFIG_SCSI_QLOGIC_FC) += qlogicfc.o
obj-$(CONFIG_SCSI_QLOGIC_1280) += qla1280.o
obj-$(CONFIG_SCSI_QLA2XXX) += qla2xxx/
obj-$(CONFIG_SCSI_LPFC) += lpfc/
obj-$(CONFIG_SCSI_PAS16) += pas16.o
obj-$(CONFIG_SCSI_SEAGATE) += seagate.o
obj-$(CONFIG_SCSI_FD_8xx) += seagate.o

View File

@ -0,0 +1,32 @@
#/*******************************************************************
# * This file is part of the Emulex Linux Device Driver for *
# * Enterprise Fibre Channel Host Bus Adapters. *
# * Refer to the README file included with this package for *
# * driver version and adapter support. *
# * Copyright (C) 2004 Emulex Corporation. *
# * www.emulex.com *
# * *
# * This program is free software; you can redistribute it and/or *
# * modify it under the terms of the GNU General Public License *
# * as published by the Free Software Foundation; either version 2 *
# * of the License, or (at your option) any later version. *
# * *
# * This program is distributed in the hope that it will be useful, *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
# * GNU General Public License for more details, a copy of which *
# * can be found in the file COPYING included with this package. *
# *******************************************************************/
######################################################################
#$Id: Makefile 1.58 2005/01/23 19:00:32EST sf_support Exp $
ifneq ($(GCOV),)
EXTRA_CFLAGS += -fprofile-arcs -ftest-coverage
EXTRA_CFLAGS += -O0
endif
obj-$(CONFIG_SCSI_LPFC) := lpfc.o
lpfc-objs := lpfc_mem.o lpfc_sli.o lpfc_ct.o lpfc_els.o lpfc_hbadisc.o \
lpfc_init.o lpfc_mbox.o lpfc_nportdisc.o lpfc_scsi.o lpfc_attr.o

384
drivers/scsi/lpfc/lpfc.h Normal file
View File

@ -0,0 +1,384 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Enterprise Fibre Channel Host Bus Adapters. *
* Refer to the README file included with this package for *
* driver version and adapter support. *
* Copyright (C) 2004 Emulex Corporation. *
* www.emulex.com *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details, a copy of which *
* can be found in the file COPYING included with this package. *
*******************************************************************/
/*
* $Id: lpfc.h 1.167 2005/04/07 08:47:05EDT sf_support Exp $
*/
struct lpfc_sli2_slim;
#define LPFC_MAX_TARGET 256 /* max targets supported */
#define LPFC_MAX_DISC_THREADS 64 /* max outstanding discovery els req */
#define LPFC_MAX_NS_RETRY 3 /* max NameServer retries */
#define LPFC_DFT_HBA_Q_DEPTH 2048 /* max cmds per hba */
#define LPFC_LC_HBA_Q_DEPTH 1024 /* max cmds per low cost hba */
#define LPFC_LP101_HBA_Q_DEPTH 128 /* max cmds per low cost hba */
#define LPFC_CMD_PER_LUN 30 /* max outstanding cmds per lun */
#define LPFC_SG_SEG_CNT 64 /* sg element count per scsi cmnd */
#define LPFC_IOCB_LIST_CNT 2250 /* list of IOCBs for fast-path usage. */
/* Define macros for 64 bit support */
#define putPaddrLow(addr) ((uint32_t) (0xffffffff & (u64)(addr)))
#define putPaddrHigh(addr) ((uint32_t) (0xffffffff & (((u64)(addr))>>32)))
#define getPaddr(high, low) ((dma_addr_t)( \
(( (u64)(high)<<16 ) << 16)|( (u64)(low))))
/* Provide maximum configuration definitions. */
#define LPFC_DRVR_TIMEOUT 16 /* driver iocb timeout value in sec */
#define MAX_FCP_TARGET 256 /* max num of FCP targets supported */
#define FC_MAX_ADPTMSG 64
#define MAX_HBAEVT 32
/* Provide DMA memory definitions the driver uses per port instance. */
struct lpfc_dmabuf {
struct list_head list;
void *virt; /* virtual address ptr */
dma_addr_t phys; /* mapped address */
};
struct lpfc_dma_pool {
struct lpfc_dmabuf *elements;
uint32_t max_count;
uint32_t current_count;
};
/* Priority bit. Set value to exceed low water mark in lpfc_mem. */
#define MEM_PRI 0x100
/****************************************************************************/
/* Device VPD save area */
/****************************************************************************/
typedef struct lpfc_vpd {
uint32_t status; /* vpd status value */
uint32_t length; /* number of bytes actually returned */
struct {
uint32_t rsvd1; /* Revision numbers */
uint32_t biuRev;
uint32_t smRev;
uint32_t smFwRev;
uint32_t endecRev;
uint16_t rBit;
uint8_t fcphHigh;
uint8_t fcphLow;
uint8_t feaLevelHigh;
uint8_t feaLevelLow;
uint32_t postKernRev;
uint32_t opFwRev;
uint8_t opFwName[16];
uint32_t sli1FwRev;
uint8_t sli1FwName[16];
uint32_t sli2FwRev;
uint8_t sli2FwName[16];
} rev;
} lpfc_vpd_t;
struct lpfc_scsi_buf;
/*
* lpfc stat counters
*/
struct lpfc_stats {
/* Statistics for ELS commands */
uint32_t elsLogiCol;
uint32_t elsRetryExceeded;
uint32_t elsXmitRetry;
uint32_t elsDelayRetry;
uint32_t elsRcvDrop;
uint32_t elsRcvFrame;
uint32_t elsRcvRSCN;
uint32_t elsRcvRNID;
uint32_t elsRcvFARP;
uint32_t elsRcvFARPR;
uint32_t elsRcvFLOGI;
uint32_t elsRcvPLOGI;
uint32_t elsRcvADISC;
uint32_t elsRcvPDISC;
uint32_t elsRcvFAN;
uint32_t elsRcvLOGO;
uint32_t elsRcvPRLO;
uint32_t elsRcvPRLI;
uint32_t elsRcvRRQ;
uint32_t elsXmitFLOGI;
uint32_t elsXmitPLOGI;
uint32_t elsXmitPRLI;
uint32_t elsXmitADISC;
uint32_t elsXmitLOGO;
uint32_t elsXmitSCR;
uint32_t elsXmitRNID;
uint32_t elsXmitFARP;
uint32_t elsXmitFARPR;
uint32_t elsXmitACC;
uint32_t elsXmitLSRJT;
uint32_t frameRcvBcast;
uint32_t frameRcvMulti;
uint32_t strayXmitCmpl;
uint32_t frameXmitDelay;
uint32_t xriCmdCmpl;
uint32_t xriStatErr;
uint32_t LinkUp;
uint32_t LinkDown;
uint32_t LinkMultiEvent;
uint32_t NoRcvBuf;
uint32_t fcpCmd;
uint32_t fcpCmpl;
uint32_t fcpRspErr;
uint32_t fcpRemoteStop;
uint32_t fcpPortRjt;
uint32_t fcpPortBusy;
uint32_t fcpError;
uint32_t fcpLocalErr;
};
enum sysfs_mbox_state {
SMBOX_IDLE,
SMBOX_WRITING,
SMBOX_READING
};
struct lpfc_sysfs_mbox {
enum sysfs_mbox_state state;
size_t offset;
struct lpfcMboxq * mbox;
};
struct lpfc_hba {
struct list_head hba_list; /* List of hbas/ports */
struct lpfc_sli sli;
struct lpfc_sli2_slim *slim2p;
dma_addr_t slim2p_mapping;
uint16_t pci_cfg_value;
uint32_t hba_state;
#define LPFC_INIT_START 1 /* Initial state after board reset */
#define LPFC_INIT_MBX_CMDS 2 /* Initialize HBA with mbox commands */
#define LPFC_LINK_DOWN 3 /* HBA initialized, link is down */
#define LPFC_LINK_UP 4 /* Link is up - issue READ_LA */
#define LPFC_LOCAL_CFG_LINK 5 /* local NPORT Id configured */
#define LPFC_FLOGI 6 /* FLOGI sent to Fabric */
#define LPFC_FABRIC_CFG_LINK 7 /* Fabric assigned NPORT Id
configured */
#define LPFC_NS_REG 8 /* Register with NameServer */
#define LPFC_NS_QRY 9 /* Query NameServer for NPort ID list */
#define LPFC_BUILD_DISC_LIST 10 /* Build ADISC and PLOGI lists for
* device authentication / discovery */
#define LPFC_DISC_AUTH 11 /* Processing ADISC list */
#define LPFC_CLEAR_LA 12 /* authentication cmplt - issue
CLEAR_LA */
#define LPFC_HBA_READY 32
#define LPFC_HBA_ERROR 0xff
uint8_t fc_linkspeed; /* Link speed after last READ_LA */
uint32_t fc_eventTag; /* event tag for link attention */
uint32_t fc_prli_sent; /* cntr for outstanding PRLIs */
uint32_t num_disc_nodes; /*in addition to hba_state */
struct timer_list fc_estabtmo; /* link establishment timer */
struct timer_list fc_disctmo; /* Discovery rescue timer */
struct timer_list fc_fdmitmo; /* fdmi timer */
/* These fields used to be binfo */
struct lpfc_name fc_nodename; /* fc nodename */
struct lpfc_name fc_portname; /* fc portname */
uint32_t fc_pref_DID; /* preferred D_ID */
uint8_t fc_pref_ALPA; /* preferred AL_PA */
uint32_t fc_edtov; /* E_D_TOV timer value */
uint32_t fc_arbtov; /* ARB_TOV timer value */
uint32_t fc_ratov; /* R_A_TOV timer value */
uint32_t fc_rttov; /* R_T_TOV timer value */
uint32_t fc_altov; /* AL_TOV timer value */
uint32_t fc_crtov; /* C_R_TOV timer value */
uint32_t fc_citov; /* C_I_TOV timer value */
uint32_t fc_myDID; /* fibre channel S_ID */
uint32_t fc_prevDID; /* previous fibre channel S_ID */
struct serv_parm fc_sparam; /* buffer for our service parameters */
struct serv_parm fc_fabparam; /* fabric service parameters buffer */
uint8_t alpa_map[128]; /* AL_PA map from READ_LA */
uint8_t fc_ns_retry; /* retries for fabric nameserver */
uint32_t fc_nlp_cnt; /* outstanding NODELIST requests */
uint32_t fc_rscn_id_cnt; /* count of RSCNs payloads in list */
struct lpfc_dmabuf *fc_rscn_id_list[FC_MAX_HOLD_RSCN];
uint32_t lmt;
uint32_t fc_flag; /* FC flags */
#define FC_PT2PT 0x1 /* pt2pt with no fabric */
#define FC_PT2PT_PLOGI 0x2 /* pt2pt initiate PLOGI */
#define FC_DISC_TMO 0x4 /* Discovery timer running */
#define FC_PUBLIC_LOOP 0x8 /* Public loop */
#define FC_LBIT 0x10 /* LOGIN bit in loopinit set */
#define FC_RSCN_MODE 0x20 /* RSCN cmd rcv'ed */
#define FC_NLP_MORE 0x40 /* More node to process in node tbl */
#define FC_OFFLINE_MODE 0x80 /* Interface is offline for diag */
#define FC_FABRIC 0x100 /* We are fabric attached */
#define FC_ESTABLISH_LINK 0x200 /* Reestablish Link */
#define FC_RSCN_DISCOVERY 0x400 /* Authenticate all devices after RSCN*/
#define FC_LOADING 0x1000 /* HBA in process of loading drvr */
#define FC_UNLOADING 0x2000 /* HBA in process of unloading drvr */
#define FC_SCSI_SCAN_TMO 0x4000 /* scsi scan timer running */
#define FC_ABORT_DISCOVERY 0x8000 /* we want to abort discovery */
#define FC_NDISC_ACTIVE 0x10000 /* NPort discovery active */
uint32_t fc_topology; /* link topology, from LINK INIT */
struct lpfc_stats fc_stat;
/* These are the head/tail pointers for the bind, plogi, adisc, unmap,
* and map lists. Their counters are immediately following.
*/
struct list_head fc_plogi_list;
struct list_head fc_adisc_list;
struct list_head fc_reglogin_list;
struct list_head fc_prli_list;
struct list_head fc_nlpunmap_list;
struct list_head fc_nlpmap_list;
struct list_head fc_npr_list;
struct list_head fc_unused_list;
/* Keep counters for the number of entries in each list. */
uint16_t fc_plogi_cnt;
uint16_t fc_adisc_cnt;
uint16_t fc_reglogin_cnt;
uint16_t fc_prli_cnt;
uint16_t fc_unmap_cnt;
uint16_t fc_map_cnt;
uint16_t fc_npr_cnt;
uint16_t fc_unused_cnt;
struct lpfc_nodelist fc_fcpnodev; /* nodelist entry for no device */
uint32_t nport_event_cnt; /* timestamp for nlplist entry */
#define LPFC_RPI_HASH_SIZE 64
#define LPFC_RPI_HASH_FUNC(x) ((x) & (0x3f))
/* ptr to active D_ID / RPIs */
struct lpfc_nodelist *fc_nlplookup[LPFC_RPI_HASH_SIZE];
uint32_t wwnn[2];
uint32_t RandomData[7];
uint32_t cfg_log_verbose;
uint32_t cfg_lun_queue_depth;
uint32_t cfg_nodev_tmo;
uint32_t cfg_hba_queue_depth;
uint32_t cfg_fcp_class;
uint32_t cfg_use_adisc;
uint32_t cfg_ack0;
uint32_t cfg_topology;
uint32_t cfg_scan_down;
uint32_t cfg_link_speed;
uint32_t cfg_cr_delay;
uint32_t cfg_cr_count;
uint32_t cfg_fdmi_on;
uint32_t cfg_fcp_bind_method;
uint32_t cfg_discovery_threads;
uint32_t cfg_max_luns;
uint32_t cfg_sg_seg_cnt;
uint32_t cfg_sg_dma_buf_size;
lpfc_vpd_t vpd; /* vital product data */
struct Scsi_Host *host;
struct pci_dev *pcidev;
struct list_head work_list;
uint32_t work_ha; /* Host Attention Bits for WT */
uint32_t work_ha_mask; /* HA Bits owned by WT */
uint32_t work_hs; /* HS stored in case of ERRAT */
uint32_t work_status[2]; /* Extra status from SLIM */
uint32_t work_hba_events; /* Timeout to be handled */
#define WORKER_DISC_TMO 0x1 /* Discovery timeout */
#define WORKER_ELS_TMO 0x2 /* ELS timeout */
#define WORKER_MBOX_TMO 0x4 /* MBOX timeout */
#define WORKER_FDMI_TMO 0x8 /* FDMI timeout */
wait_queue_head_t *work_wait;
struct task_struct *worker_thread;
unsigned long pci_bar0_map; /* Physical address for PCI BAR0 */
unsigned long pci_bar2_map; /* Physical address for PCI BAR2 */
void __iomem *slim_memmap_p; /* Kernel memory mapped address for
PCI BAR0 */
void __iomem *ctrl_regs_memmap_p;/* Kernel memory mapped address for
PCI BAR2 */
void __iomem *MBslimaddr; /* virtual address for mbox cmds */
void __iomem *HAregaddr; /* virtual address for host attn reg */
void __iomem *CAregaddr; /* virtual address for chip attn reg */
void __iomem *HSregaddr; /* virtual address for host status
reg */
void __iomem *HCregaddr; /* virtual address for host ctl reg */
int brd_no; /* FC board number */
char SerialNumber[32]; /* adapter Serial Number */
char OptionROMVersion[32]; /* adapter BIOS / Fcode version */
char ModelDesc[256]; /* Model Description */
char ModelName[80]; /* Model Name */
char ProgramType[256]; /* Program Type */
char Port[20]; /* Port No */
uint8_t vpd_flag; /* VPD data flag */
#define VPD_MODEL_DESC 0x1 /* valid vpd model description */
#define VPD_MODEL_NAME 0x2 /* valid vpd model name */
#define VPD_PROGRAM_TYPE 0x4 /* valid vpd program type */
#define VPD_PORT 0x8 /* valid vpd port data */
#define VPD_MASK 0xf /* mask for any vpd data */
struct timer_list els_tmofunc;
void *link_stats;
/*
* stat counters
*/
uint64_t fc4InputRequests;
uint64_t fc4OutputRequests;
uint64_t fc4ControlRequests;
struct lpfc_sysfs_mbox sysfs_mbox;
/* fastpath list. */
struct list_head lpfc_scsi_buf_list;
uint32_t total_scsi_bufs;
struct list_head lpfc_iocb_list;
uint32_t total_iocbq_bufs;
/* pci_mem_pools */
struct pci_pool *lpfc_scsi_dma_buf_pool;
struct pci_pool *lpfc_mbuf_pool;
struct lpfc_dma_pool lpfc_mbuf_safety_pool;
mempool_t *mbox_mem_pool;
mempool_t *nlp_mem_pool;
struct list_head freebufList;
struct list_head ctrspbuflist;
struct list_head rnidrspbuflist;
};
struct rnidrsp {
void *buf;
uint32_t uniqueid;
struct list_head list;
uint32_t data;
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,97 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Enterprise Fibre Channel Host Bus Adapters. *
* Refer to the README file included with this package for *
* driver version and adapter support. *
* Copyright (C) 2004 Emulex Corporation. *
* www.emulex.com *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details, a copy of which *
* can be found in the file COPYING included with this package. *
*******************************************************************/
/*
* $Id: lpfc_compat.h 1.32 2005/01/25 17:51:45EST sf_support Exp $
*
* This file provides macros to aid compilation in the Linux 2.4 kernel
* over various platform architectures.
*/
/*******************************************************************
Note: HBA's SLI memory contains little-endian LW.
Thus to access it from a little-endian host,
memcpy_toio() and memcpy_fromio() can be used.
However on a big-endian host, copy 4 bytes at a time,
using writel() and readl().
*******************************************************************/
#if __BIG_ENDIAN
static inline void
lpfc_memcpy_to_slim(void __iomem *dest, void *src, unsigned int bytes)
{
uint32_t __iomem *dest32;
uint32_t *src32;
unsigned int four_bytes;
dest32 = (uint32_t __iomem *) dest;
src32 = (uint32_t *) src;
/* write input bytes, 4 bytes at a time */
for (four_bytes = bytes /4; four_bytes > 0; four_bytes--) {
writel( *src32, dest32);
readl(dest32); /* flush */
dest32++;
src32++;
}
return;
}
static inline void
lpfc_memcpy_from_slim( void *dest, void __iomem *src, unsigned int bytes)
{
uint32_t *dest32;
uint32_t __iomem *src32;
unsigned int four_bytes;
dest32 = (uint32_t *) dest;
src32 = (uint32_t __iomem *) src;
/* read input bytes, 4 bytes at a time */
for (four_bytes = bytes /4; four_bytes > 0; four_bytes--) {
*dest32 = readl( src32);
dest32++;
src32++;
}
return;
}
#else
static inline void
lpfc_memcpy_to_slim( void __iomem *dest, void *src, unsigned int bytes)
{
/* actually returns 1 byte past dest */
memcpy_toio( dest, src, bytes);
}
static inline void
lpfc_memcpy_from_slim( void *dest, void __iomem *src, unsigned int bytes)
{
/* actually returns 1 byte past dest */
memcpy_fromio( dest, src, bytes);
}
#endif /* __BIG_ENDIAN */

View File

@ -0,0 +1,216 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Enterprise Fibre Channel Host Bus Adapters. *
* Refer to the README file included with this package for *
* driver version and adapter support. *
* Copyright (C) 2004 Emulex Corporation. *
* www.emulex.com *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details, a copy of which *
* can be found in the file COPYING included with this package. *
*******************************************************************/
/*
* $Id: lpfc_crtn.h 1.166 2005/04/07 08:46:47EDT sf_support Exp $
*/
void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t);
void lpfc_read_nv(struct lpfc_hba *, LPFC_MBOXQ_t *);
int lpfc_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb,
struct lpfc_dmabuf *mp);
void lpfc_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_config_link(struct lpfc_hba *, LPFC_MBOXQ_t *);
int lpfc_read_sparam(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_read_config(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_set_slim(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t);
int lpfc_reg_login(struct lpfc_hba *, uint32_t, uint8_t *, LPFC_MBOXQ_t *,
uint32_t);
void lpfc_unreg_login(struct lpfc_hba *, uint32_t, LPFC_MBOXQ_t *);
void lpfc_unreg_did(struct lpfc_hba *, uint32_t, LPFC_MBOXQ_t *);
void lpfc_init_link(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t);
int lpfc_linkdown(struct lpfc_hba *);
void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
int lpfc_nlp_plogi(struct lpfc_hba *, struct lpfc_nodelist *);
int lpfc_nlp_adisc(struct lpfc_hba *, struct lpfc_nodelist *);
int lpfc_nlp_unmapped(struct lpfc_hba *, struct lpfc_nodelist *);
int lpfc_nlp_list(struct lpfc_hba *, struct lpfc_nodelist *, int);
void lpfc_set_disctmo(struct lpfc_hba *);
int lpfc_can_disctmo(struct lpfc_hba *);
int lpfc_unreg_rpi(struct lpfc_hba *, struct lpfc_nodelist *);
int lpfc_check_sli_ndlp(struct lpfc_hba *, struct lpfc_sli_ring *,
struct lpfc_iocbq *, struct lpfc_nodelist *);
int lpfc_nlp_remove(struct lpfc_hba *, struct lpfc_nodelist *);
void lpfc_nlp_init(struct lpfc_hba *, struct lpfc_nodelist *, uint32_t);
struct lpfc_nodelist *lpfc_setup_disc_node(struct lpfc_hba *, uint32_t);
struct lpfc_nodelist *lpfc_setup_rscn_node(struct lpfc_hba *, uint32_t);
void lpfc_disc_list_loopmap(struct lpfc_hba *);
void lpfc_disc_start(struct lpfc_hba *);
void lpfc_disc_flush_list(struct lpfc_hba *);
void lpfc_disc_timeout(unsigned long);
void lpfc_scan_timeout(unsigned long);
struct lpfc_nodelist *lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi);
struct lpfc_nodelist *lpfc_findnode_remove_rpi(struct lpfc_hba * phba,
uint16_t rpi);
void lpfc_addnode_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
uint16_t rpi);
int lpfc_workq_post_event(struct lpfc_hba *, void *, void *, uint32_t);
int lpfc_do_work(void *);
int lpfc_disc_state_machine(struct lpfc_hba *, struct lpfc_nodelist *, void *,
uint32_t);
uint32_t lpfc_cmpl_prli_reglogin_issue(struct lpfc_hba *,
struct lpfc_nodelist *, void *,
uint32_t);
uint32_t lpfc_cmpl_plogi_prli_issue(struct lpfc_hba *, struct lpfc_nodelist *,
void *, uint32_t);
int lpfc_check_sparm(struct lpfc_hba *, struct lpfc_nodelist *,
struct serv_parm *, uint32_t);
int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist * ndlp,
int);
int lpfc_els_abort_flogi(struct lpfc_hba *);
int lpfc_initial_flogi(struct lpfc_hba *);
int lpfc_issue_els_plogi(struct lpfc_hba *, struct lpfc_nodelist *, uint8_t);
int lpfc_issue_els_prli(struct lpfc_hba *, struct lpfc_nodelist *, uint8_t);
int lpfc_issue_els_adisc(struct lpfc_hba *, struct lpfc_nodelist *, uint8_t);
int lpfc_issue_els_logo(struct lpfc_hba *, struct lpfc_nodelist *, uint8_t);
int lpfc_issue_els_scr(struct lpfc_hba *, uint32_t, uint8_t);
int lpfc_els_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *);
int lpfc_els_rsp_acc(struct lpfc_hba *, uint32_t, struct lpfc_iocbq *,
struct lpfc_nodelist *, LPFC_MBOXQ_t *, uint8_t);
int lpfc_els_rsp_reject(struct lpfc_hba *, uint32_t, struct lpfc_iocbq *,
struct lpfc_nodelist *);
int lpfc_els_rsp_adisc_acc(struct lpfc_hba *, struct lpfc_iocbq *,
struct lpfc_nodelist *);
int lpfc_els_rsp_prli_acc(struct lpfc_hba *, struct lpfc_iocbq *,
struct lpfc_nodelist *);
void lpfc_els_retry_delay(unsigned long);
void lpfc_els_retry_delay_handler(struct lpfc_nodelist *);
void lpfc_els_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
struct lpfc_iocbq *);
int lpfc_els_handle_rscn(struct lpfc_hba *);
int lpfc_els_flush_rscn(struct lpfc_hba *);
int lpfc_rscn_payload_check(struct lpfc_hba *, uint32_t);
void lpfc_els_flush_cmd(struct lpfc_hba *);
int lpfc_els_disc_adisc(struct lpfc_hba *);
int lpfc_els_disc_plogi(struct lpfc_hba *);
void lpfc_els_timeout(unsigned long);
void lpfc_els_timeout_handler(struct lpfc_hba *);
void lpfc_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
struct lpfc_iocbq *);
int lpfc_ns_cmd(struct lpfc_hba *, struct lpfc_nodelist *, int);
int lpfc_fdmi_cmd(struct lpfc_hba *, struct lpfc_nodelist *, int);
void lpfc_fdmi_tmo(unsigned long);
void lpfc_fdmi_tmo_handler(struct lpfc_hba *);
int lpfc_config_port_prep(struct lpfc_hba *);
int lpfc_config_port_post(struct lpfc_hba *);
int lpfc_hba_down_prep(struct lpfc_hba *);
void lpfc_hba_init(struct lpfc_hba *, uint32_t *);
int lpfc_post_buffer(struct lpfc_hba *, struct lpfc_sli_ring *, int, int);
void lpfc_decode_firmware_rev(struct lpfc_hba *, char *, int);
uint8_t *lpfc_get_lpfchba_info(struct lpfc_hba *, uint8_t *);
int lpfc_fcp_abort(struct lpfc_hba *, int, int, int);
int lpfc_online(struct lpfc_hba *);
int lpfc_offline(struct lpfc_hba *);
int lpfc_sli_setup(struct lpfc_hba *);
int lpfc_sli_queue_setup(struct lpfc_hba *);
void lpfc_slim_access(struct lpfc_hba *);
void lpfc_handle_eratt(struct lpfc_hba *);
void lpfc_handle_latt(struct lpfc_hba *);
irqreturn_t lpfc_intr_handler(int, void *, struct pt_regs *);
void lpfc_read_rev(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_config_ring(struct lpfc_hba *, int, LPFC_MBOXQ_t *);
void lpfc_config_port(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbox_put(struct lpfc_hba *, LPFC_MBOXQ_t *);
LPFC_MBOXQ_t *lpfc_mbox_get(struct lpfc_hba *);
int lpfc_mem_alloc(struct lpfc_hba *);
void lpfc_mem_free(struct lpfc_hba *);
int lpfc_sli_hba_setup(struct lpfc_hba *);
int lpfc_sli_hba_down(struct lpfc_hba *);
int lpfc_sli_issue_mbox(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t);
int lpfc_sli_handle_mb_event(struct lpfc_hba *);
int lpfc_sli_handle_slow_ring_event(struct lpfc_hba *,
struct lpfc_sli_ring *, uint32_t);
void lpfc_sli_def_mbox_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *);
int lpfc_sli_issue_iocb(struct lpfc_hba *, struct lpfc_sli_ring *,
struct lpfc_iocbq *, uint32_t);
void lpfc_sli_pcimem_bcopy(void *, void *, uint32_t);
int lpfc_sli_abort_iocb_ring(struct lpfc_hba *, struct lpfc_sli_ring *);
int lpfc_sli_ringpostbuf_put(struct lpfc_hba *, struct lpfc_sli_ring *,
struct lpfc_dmabuf *);
struct lpfc_dmabuf *lpfc_sli_ringpostbuf_get(struct lpfc_hba *,
struct lpfc_sli_ring *,
dma_addr_t);
int lpfc_sli_issue_abort_iotag32(struct lpfc_hba *, struct lpfc_sli_ring *,
struct lpfc_iocbq *);
int lpfc_sli_sum_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, uint16_t,
uint64_t, lpfc_ctx_cmd);
int lpfc_sli_abort_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, uint16_t,
uint64_t, uint32_t, lpfc_ctx_cmd);
void lpfc_mbox_timeout(unsigned long);
void lpfc_mbox_timeout_handler(struct lpfc_hba *);
void lpfc_map_fcp_cmnd_to_bpl(struct lpfc_hba *, struct lpfc_scsi_buf *);
void lpfc_free_scsi_cmd(struct lpfc_scsi_buf *);
uint32_t lpfc_os_timeout_transform(struct lpfc_hba *, uint32_t);
struct lpfc_nodelist *lpfc_findnode_did(struct lpfc_hba * phba, uint32_t order,
uint32_t did);
int lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq,
uint32_t timeout);
int lpfc_sli_issue_iocb_wait_high_priority(struct lpfc_hba * phba,
struct lpfc_sli_ring * pring,
struct lpfc_iocbq * piocb,
uint32_t flag,
struct lpfc_iocbq * prspiocbq,
uint32_t timeout);
void lpfc_sli_wake_iocb_high_priority(struct lpfc_hba * phba,
struct lpfc_iocbq * queue1,
struct lpfc_iocbq * queue2);
void *lpfc_mbuf_alloc(struct lpfc_hba *, int, dma_addr_t *);
void lpfc_mbuf_free(struct lpfc_hba *, void *, dma_addr_t);
/* Function prototypes. */
const char* lpfc_info(struct Scsi_Host *);
void lpfc_get_cfgparam(struct lpfc_hba *);
int lpfc_alloc_sysfs_attr(struct lpfc_hba *);
void lpfc_free_sysfs_attr(struct lpfc_hba *);
extern struct class_device_attribute *lpfc_host_attrs[];
extern struct scsi_host_template lpfc_template;
extern struct fc_function_template lpfc_transport_functions;
void lpfc_get_hba_sym_node_name(struct lpfc_hba * phba, uint8_t * symbp);
#define ScsiResult(host_code, scsi_code) (((host_code) << 16) | scsi_code)
#define HBA_EVENT_RSCN 5
#define HBA_EVENT_LINK_UP 2
#define HBA_EVENT_LINK_DOWN 3

1237
drivers/scsi/lpfc/lpfc_ct.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,206 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Enterprise Fibre Channel Host Bus Adapters. *
* Refer to the README file included with this package for *
* driver version and adapter support. *
* Copyright (C) 2004 Emulex Corporation. *
* www.emulex.com *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details, a copy of which *
* can be found in the file COPYING included with this package. *
*******************************************************************/
/*
* $Id: lpfc_disc.h 1.61 2005/04/07 08:46:52EDT sf_support Exp $
*/
#define FC_MAX_HOLD_RSCN 32 /* max number of deferred RSCNs */
#define FC_MAX_NS_RSP 65536 /* max size NameServer rsp */
#define FC_MAXLOOP 126 /* max devices supported on a fc loop */
#define LPFC_DISC_FLOGI_TMO 10 /* Discovery FLOGI ratov */
/* This is the protocol dependent definition for a Node List Entry.
* This is used by Fibre Channel protocol to support FCP.
*/
/* structure used to queue event to the discovery tasklet */
struct lpfc_work_evt {
struct list_head evt_listp;
void * evt_arg1;
void * evt_arg2;
uint32_t evt;
};
#define LPFC_EVT_NODEV_TMO 0x1
#define LPFC_EVT_ONLINE 0x2
#define LPFC_EVT_OFFLINE 0x3
#define LPFC_EVT_ELS_RETRY 0x4
struct lpfc_nodelist {
struct list_head nlp_listp;
struct lpfc_name nlp_portname; /* port name */
struct lpfc_name nlp_nodename; /* node name */
uint32_t nlp_flag; /* entry flags */
uint32_t nlp_DID; /* FC D_ID of entry */
uint32_t nlp_last_elscmd; /* Last ELS cmd sent */
uint16_t nlp_type;
#define NLP_FC_NODE 0x1 /* entry is an FC node */
#define NLP_FABRIC 0x4 /* entry rep a Fabric entity */
#define NLP_FCP_TARGET 0x8 /* entry is an FCP target */
#define NLP_FCP_INITIATOR 0x10 /* entry is an FCP Initiator */
uint16_t nlp_rpi;
uint16_t nlp_state; /* state transition indicator */
uint16_t nlp_xri; /* output exchange id for RPI */
uint16_t nlp_sid; /* scsi id */
#define NLP_NO_SID 0xffff
uint16_t nlp_maxframe; /* Max RCV frame size */
uint8_t nlp_class_sup; /* Supported Classes */
uint8_t nlp_retry; /* used for ELS retries */
uint8_t nlp_disc_refcnt; /* used for DSM */
uint8_t nlp_fcp_info; /* class info, bits 0-3 */
#define NLP_FCP_2_DEVICE 0x10 /* FCP-2 device */
struct timer_list nlp_delayfunc; /* Used for delayed ELS cmds */
struct timer_list nlp_tmofunc; /* Used for nodev tmo */
struct fc_rport *rport; /* Corresponding FC transport
port structure */
struct lpfc_nodelist *nlp_rpi_hash_next;
struct lpfc_hba *nlp_phba;
struct lpfc_work_evt nodev_timeout_evt;
struct lpfc_work_evt els_retry_evt;
};
/* Defines for nlp_flag (uint32) */
#define NLP_NO_LIST 0x0 /* Indicates immediately free node */
#define NLP_UNUSED_LIST 0x1 /* Flg to indicate node will be freed */
#define NLP_PLOGI_LIST 0x2 /* Flg to indicate sent PLOGI */
#define NLP_ADISC_LIST 0x3 /* Flg to indicate sent ADISC */
#define NLP_REGLOGIN_LIST 0x4 /* Flg to indicate sent REG_LOGIN */
#define NLP_PRLI_LIST 0x5 /* Flg to indicate sent PRLI */
#define NLP_UNMAPPED_LIST 0x6 /* Node is now unmapped */
#define NLP_MAPPED_LIST 0x7 /* Node is now mapped */
#define NLP_NPR_LIST 0x8 /* Node is in NPort Recovery state */
#define NLP_JUST_DQ 0x9 /* just deque ndlp in lpfc_nlp_list */
#define NLP_LIST_MASK 0xf /* mask to see what list node is on */
#define NLP_PLOGI_SND 0x20 /* sent PLOGI request for this entry */
#define NLP_PRLI_SND 0x40 /* sent PRLI request for this entry */
#define NLP_ADISC_SND 0x80 /* sent ADISC request for this entry */
#define NLP_LOGO_SND 0x100 /* sent LOGO request for this entry */
#define NLP_RNID_SND 0x400 /* sent RNID request for this entry */
#define NLP_ELS_SND_MASK 0x7e0 /* sent ELS request for this entry */
#define NLP_NODEV_TMO 0x10000 /* nodev timeout is running for node */
#define NLP_DELAY_TMO 0x20000 /* delay timeout is running for node */
#define NLP_NPR_2B_DISC 0x40000 /* node is included in num_disc_nodes */
#define NLP_RCV_PLOGI 0x80000 /* Rcv'ed PLOGI from remote system */
#define NLP_LOGO_ACC 0x100000 /* Process LOGO after ACC completes */
#define NLP_TGT_NO_SCSIID 0x200000 /* good PRLI but no binding for scsid */
#define NLP_ACC_REGLOGIN 0x1000000 /* Issue Reg Login after successful
ACC */
#define NLP_NPR_ADISC 0x2000000 /* Issue ADISC when dq'ed from
NPR list */
#define NLP_DELAY_REMOVE 0x4000000 /* Defer removal till end of DSM */
/* Defines for list searchs */
#define NLP_SEARCH_MAPPED 0x1 /* search mapped */
#define NLP_SEARCH_UNMAPPED 0x2 /* search unmapped */
#define NLP_SEARCH_PLOGI 0x4 /* search plogi */
#define NLP_SEARCH_ADISC 0x8 /* search adisc */
#define NLP_SEARCH_REGLOGIN 0x10 /* search reglogin */
#define NLP_SEARCH_PRLI 0x20 /* search prli */
#define NLP_SEARCH_NPR 0x40 /* search npr */
#define NLP_SEARCH_UNUSED 0x80 /* search mapped */
#define NLP_SEARCH_ALL 0xff /* search all lists */
/* There are 4 different double linked lists nodelist entries can reside on.
* The Port Login (PLOGI) list and Address Discovery (ADISC) list are used
* when Link Up discovery or Registered State Change Notification (RSCN)
* processing is needed. Each list holds the nodes that require a PLOGI or
* ADISC Extended Link Service (ELS) request. These lists keep track of the
* nodes affected by an RSCN, or a Link Up (Typically, all nodes are effected
* by Link Up) event. The unmapped_list contains all nodes that have
* successfully logged into at the Fibre Channel level. The
* mapped_list will contain all nodes that are mapped FCP targets.
*
* The bind list is a list of undiscovered (potentially non-existent) nodes
* that we have saved binding information on. This information is used when
* nodes transition from the unmapped to the mapped list.
*/
/* Defines for nlp_state */
#define NLP_STE_UNUSED_NODE 0x0 /* node is just allocated */
#define NLP_STE_PLOGI_ISSUE 0x1 /* PLOGI was sent to NL_PORT */
#define NLP_STE_ADISC_ISSUE 0x2 /* ADISC was sent to NL_PORT */
#define NLP_STE_REG_LOGIN_ISSUE 0x3 /* REG_LOGIN was issued for NL_PORT */
#define NLP_STE_PRLI_ISSUE 0x4 /* PRLI was sent to NL_PORT */
#define NLP_STE_UNMAPPED_NODE 0x5 /* PRLI completed from NL_PORT */
#define NLP_STE_MAPPED_NODE 0x6 /* Identified as a FCP Target */
#define NLP_STE_NPR_NODE 0x7 /* NPort disappeared */
#define NLP_STE_MAX_STATE 0x8
#define NLP_STE_FREED_NODE 0xff /* node entry was freed to MEM_NLP */
/* For UNUSED_NODE state, the node has just been allocated.
* For PLOGI_ISSUE and REG_LOGIN_ISSUE, the node is on
* the PLOGI list. For REG_LOGIN_COMPL, the node is taken off the PLOGI list
* and put on the unmapped list. For ADISC processing, the node is taken off
* the ADISC list and placed on either the mapped or unmapped list (depending
* on its previous state). Once on the unmapped list, a PRLI is issued and the
* state changed to PRLI_ISSUE. When the PRLI completion occurs, the state is
* changed to PRLI_COMPL. If the completion indicates a mapped
* node, the node is taken off the unmapped list. The binding list is checked
* for a valid binding, or a binding is automatically assigned. If binding
* assignment is unsuccessful, the node is left on the unmapped list. If
* binding assignment is successful, the associated binding list entry (if
* any) is removed, and the node is placed on the mapped list.
*/
/*
* For a Link Down, all nodes on the ADISC, PLOGI, unmapped or mapped
* lists will receive a DEVICE_RECOVERY event. If the linkdown or nodev timers
* expire, all effected nodes will receive a DEVICE_RM event.
*/
/*
* For a Link Up or RSCN, all nodes will move from the mapped / unmapped lists
* to either the ADISC or PLOGI list. After a Nameserver query or ALPA loopmap
* check, additional nodes may be added (DEVICE_ADD) or removed (DEVICE_RM) to /
* from the PLOGI or ADISC lists. Once the PLOGI and ADISC lists are populated,
* we will first process the ADISC list. 32 entries are processed initially and
* ADISC is initited for each one. Completions / Events for each node are
* funnelled thru the state machine. As each node finishes ADISC processing, it
* starts ADISC for any nodes waiting for ADISC processing. If no nodes are
* waiting, and the ADISC list count is identically 0, then we are done. For
* Link Up discovery, since all nodes on the PLOGI list are UNREG_LOGIN'ed, we
* can issue a CLEAR_LA and reenable Link Events. Next we will process the PLOGI
* list. 32 entries are processed initially and PLOGI is initited for each one.
* Completions / Events for each node are funnelled thru the state machine. As
* each node finishes PLOGI processing, it starts PLOGI for any nodes waiting
* for PLOGI processing. If no nodes are waiting, and the PLOGI list count is
* identically 0, then we are done. We have now completed discovery / RSCN
* handling. Upon completion, ALL nodes should be on either the mapped or
* unmapped lists.
*/
/* Defines for Node List Entry Events that could happen */
#define NLP_EVT_RCV_PLOGI 0x0 /* Rcv'd an ELS PLOGI command */
#define NLP_EVT_RCV_PRLI 0x1 /* Rcv'd an ELS PRLI command */
#define NLP_EVT_RCV_LOGO 0x2 /* Rcv'd an ELS LOGO command */
#define NLP_EVT_RCV_ADISC 0x3 /* Rcv'd an ELS ADISC command */
#define NLP_EVT_RCV_PDISC 0x4 /* Rcv'd an ELS PDISC command */
#define NLP_EVT_RCV_PRLO 0x5 /* Rcv'd an ELS PRLO command */
#define NLP_EVT_CMPL_PLOGI 0x6 /* Sent an ELS PLOGI command */
#define NLP_EVT_CMPL_PRLI 0x7 /* Sent an ELS PRLI command */
#define NLP_EVT_CMPL_LOGO 0x8 /* Sent an ELS LOGO command */
#define NLP_EVT_CMPL_ADISC 0x9 /* Sent an ELS ADISC command */
#define NLP_EVT_CMPL_REG_LOGIN 0xa /* REG_LOGIN mbox cmd completed */
#define NLP_EVT_DEVICE_RM 0xb /* Device not found in NS / ALPAmap */
#define NLP_EVT_DEVICE_RECOVERY 0xc /* Device existence unknown */
#define NLP_EVT_MAX_EVENT 0xd

3258
drivers/scsi/lpfc/lpfc_els.c Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

2687
drivers/scsi/lpfc/lpfc_hw.h Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,41 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Enterprise Fibre Channel Host Bus Adapters. *
* Refer to the README file included with this package for *
* driver version and adapter support. *
* Copyright (C) 2004 Emulex Corporation. *
* www.emulex.com *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details, a copy of which *
* can be found in the file COPYING included with this package. *
*******************************************************************/
/*
* $Id: lpfc_logmsg.h 1.32 2005/01/25 17:52:01EST sf_support Exp $
*/
#define LOG_ELS 0x1 /* ELS events */
#define LOG_DISCOVERY 0x2 /* Link discovery events */
#define LOG_MBOX 0x4 /* Mailbox events */
#define LOG_INIT 0x8 /* Initialization events */
#define LOG_LINK_EVENT 0x10 /* Link events */
#define LOG_IP 0x20 /* IP traffic history */
#define LOG_FCP 0x40 /* FCP traffic history */
#define LOG_NODE 0x80 /* Node table events */
#define LOG_MISC 0x400 /* Miscellaneous events */
#define LOG_SLI 0x800 /* SLI events */
#define LOG_CHK_COND 0x1000 /* FCP Check condition flag */
#define LOG_LIBDFC 0x2000 /* Libdfc events */
#define LOG_ALL_MSG 0xffff /* LOG all messages */
#define lpfc_printf_log(phba, level, mask, fmt, arg...) \
{ if (((mask) &(phba)->cfg_log_verbose) || (level[1] <= '3')) \
dev_printk(level, &((phba)->pcidev)->dev, fmt, ##arg); }

View File

@ -0,0 +1,646 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Enterprise Fibre Channel Host Bus Adapters. *
* Refer to the README file included with this package for *
* driver version and adapter support. *
* Copyright (C) 2004 Emulex Corporation. *
* www.emulex.com *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details, a copy of which *
* can be found in the file COPYING included with this package. *
*******************************************************************/
/*
* $Id: lpfc_mbox.c 1.85 2005/04/13 11:59:11EDT sf_support Exp $
*/
#include <linux/blkdev.h>
#include <linux/pci.h>
#include <linux/interrupt.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_compat.h"
/**********************************************/
/* mailbox command */
/**********************************************/
void
lpfc_dump_mem(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, uint16_t offset)
{
MAILBOX_t *mb;
void *ctx;
mb = &pmb->mb;
ctx = pmb->context2;
/* Setup to dump VPD region */
memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
mb->mbxCommand = MBX_DUMP_MEMORY;
mb->un.varDmp.cv = 1;
mb->un.varDmp.type = DMP_NV_PARAMS;
mb->un.varDmp.entry_index = offset;
mb->un.varDmp.region_id = DMP_REGION_VPD;
mb->un.varDmp.word_cnt = (DMP_RSP_SIZE / sizeof (uint32_t));
mb->un.varDmp.co = 0;
mb->un.varDmp.resp_offset = 0;
pmb->context2 = ctx;
mb->mbxOwner = OWN_HOST;
return;
}
/**********************************************/
/* lpfc_read_nv Issue a READ NVPARAM */
/* mailbox command */
/**********************************************/
void
lpfc_read_nv(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
{
MAILBOX_t *mb;
mb = &pmb->mb;
memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
mb->mbxCommand = MBX_READ_NV;
mb->mbxOwner = OWN_HOST;
return;
}
/**********************************************/
/* lpfc_read_la Issue a READ LA */
/* mailbox command */
/**********************************************/
int
lpfc_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, struct lpfc_dmabuf *mp)
{
MAILBOX_t *mb;
struct lpfc_sli *psli;
psli = &phba->sli;
mb = &pmb->mb;
memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
INIT_LIST_HEAD(&mp->list);
mb->mbxCommand = MBX_READ_LA64;
mb->un.varReadLA.un.lilpBde64.tus.f.bdeSize = 128;
mb->un.varReadLA.un.lilpBde64.addrHigh = putPaddrHigh(mp->phys);
mb->un.varReadLA.un.lilpBde64.addrLow = putPaddrLow(mp->phys);
/* Save address for later completion and set the owner to host so that
* the FW knows this mailbox is available for processing.
*/
pmb->context1 = (uint8_t *) mp;
mb->mbxOwner = OWN_HOST;
return (0);
}
/**********************************************/
/* lpfc_clear_la Issue a CLEAR LA */
/* mailbox command */
/**********************************************/
void
lpfc_clear_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
{
MAILBOX_t *mb;
mb = &pmb->mb;
memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
mb->un.varClearLA.eventTag = phba->fc_eventTag;
mb->mbxCommand = MBX_CLEAR_LA;
mb->mbxOwner = OWN_HOST;
return;
}
/**************************************************/
/* lpfc_config_link Issue a CONFIG LINK */
/* mailbox command */
/**************************************************/
void
lpfc_config_link(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
{
MAILBOX_t *mb = &pmb->mb;
memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
/* NEW_FEATURE
* SLI-2, Coalescing Response Feature.
*/
if (phba->cfg_cr_delay) {
mb->un.varCfgLnk.cr = 1;
mb->un.varCfgLnk.ci = 1;
mb->un.varCfgLnk.cr_delay = phba->cfg_cr_delay;
mb->un.varCfgLnk.cr_count = phba->cfg_cr_count;
}
mb->un.varCfgLnk.myId = phba->fc_myDID;
mb->un.varCfgLnk.edtov = phba->fc_edtov;
mb->un.varCfgLnk.arbtov = phba->fc_arbtov;
mb->un.varCfgLnk.ratov = phba->fc_ratov;
mb->un.varCfgLnk.rttov = phba->fc_rttov;
mb->un.varCfgLnk.altov = phba->fc_altov;
mb->un.varCfgLnk.crtov = phba->fc_crtov;
mb->un.varCfgLnk.citov = phba->fc_citov;
if (phba->cfg_ack0)
mb->un.varCfgLnk.ack0_enable = 1;
mb->mbxCommand = MBX_CONFIG_LINK;
mb->mbxOwner = OWN_HOST;
return;
}
/**********************************************/
/* lpfc_init_link Issue an INIT LINK */
/* mailbox command */
/**********************************************/
void
lpfc_init_link(struct lpfc_hba * phba,
LPFC_MBOXQ_t * pmb, uint32_t topology, uint32_t linkspeed)
{
lpfc_vpd_t *vpd;
struct lpfc_sli *psli;
MAILBOX_t *mb;
mb = &pmb->mb;
memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
psli = &phba->sli;
switch (topology) {
case FLAGS_TOPOLOGY_MODE_LOOP_PT:
mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_LOOP;
mb->un.varInitLnk.link_flags |= FLAGS_TOPOLOGY_FAILOVER;
break;
case FLAGS_TOPOLOGY_MODE_PT_PT:
mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_PT_PT;
break;
case FLAGS_TOPOLOGY_MODE_LOOP:
mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_LOOP;
break;
case FLAGS_TOPOLOGY_MODE_PT_LOOP:
mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_PT_PT;
mb->un.varInitLnk.link_flags |= FLAGS_TOPOLOGY_FAILOVER;
break;
}
/* NEW_FEATURE
* Setting up the link speed
*/
vpd = &phba->vpd;
if (vpd->rev.feaLevelHigh >= 0x02){
switch(linkspeed){
case LINK_SPEED_1G:
case LINK_SPEED_2G:
case LINK_SPEED_4G:
mb->un.varInitLnk.link_flags |=
FLAGS_LINK_SPEED;
mb->un.varInitLnk.link_speed = linkspeed;
break;
case LINK_SPEED_AUTO:
default:
mb->un.varInitLnk.link_speed =
LINK_SPEED_AUTO;
break;
}
}
else
mb->un.varInitLnk.link_speed = LINK_SPEED_AUTO;
mb->mbxCommand = (volatile uint8_t)MBX_INIT_LINK;
mb->mbxOwner = OWN_HOST;
mb->un.varInitLnk.fabric_AL_PA = phba->fc_pref_ALPA;
return;
}
/**********************************************/
/* lpfc_read_sparam Issue a READ SPARAM */
/* mailbox command */
/**********************************************/
int
lpfc_read_sparam(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
{
struct lpfc_dmabuf *mp;
MAILBOX_t *mb;
struct lpfc_sli *psli;
psli = &phba->sli;
mb = &pmb->mb;
memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
mb->mbxOwner = OWN_HOST;
/* Get a buffer to hold the HBAs Service Parameters */
if (((mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL)) == 0) ||
((mp->virt = lpfc_mbuf_alloc(phba, 0, &(mp->phys))) == 0)) {
if (mp)
kfree(mp);
mb->mbxCommand = MBX_READ_SPARM64;
/* READ_SPARAM: no buffers */
lpfc_printf_log(phba,
KERN_WARNING,
LOG_MBOX,
"%d:0301 READ_SPARAM: no buffers\n",
phba->brd_no);
return (1);
}
INIT_LIST_HEAD(&mp->list);
mb->mbxCommand = MBX_READ_SPARM64;
mb->un.varRdSparm.un.sp64.tus.f.bdeSize = sizeof (struct serv_parm);
mb->un.varRdSparm.un.sp64.addrHigh = putPaddrHigh(mp->phys);
mb->un.varRdSparm.un.sp64.addrLow = putPaddrLow(mp->phys);
/* save address for completion */
pmb->context1 = mp;
return (0);
}
/********************************************/
/* lpfc_unreg_did Issue a UNREG_DID */
/* mailbox command */
/********************************************/
void
lpfc_unreg_did(struct lpfc_hba * phba, uint32_t did, LPFC_MBOXQ_t * pmb)
{
MAILBOX_t *mb;
mb = &pmb->mb;
memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
mb->un.varUnregDID.did = did;
mb->mbxCommand = MBX_UNREG_D_ID;
mb->mbxOwner = OWN_HOST;
return;
}
/***********************************************/
/* command to write slim */
/***********************************************/
void
lpfc_set_slim(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, uint32_t addr,
uint32_t value)
{
MAILBOX_t *mb;
mb = &pmb->mb;
memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
/* addr = 0x090597 is AUTO ABTS disable for ELS commands */
/* addr = 0x052198 is DELAYED ABTS enable for ELS commands */
/*
* Always turn on DELAYED ABTS for ELS timeouts
*/
if ((addr == 0x052198) && (value == 0))
value = 1;
mb->un.varWords[0] = addr;
mb->un.varWords[1] = value;
mb->mbxCommand = MBX_SET_SLIM;
mb->mbxOwner = OWN_HOST;
return;
}
/**********************************************/
/* lpfc_read_nv Issue a READ CONFIG */
/* mailbox command */
/**********************************************/
void
lpfc_read_config(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
{
MAILBOX_t *mb;
mb = &pmb->mb;
memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
mb->mbxCommand = MBX_READ_CONFIG;
mb->mbxOwner = OWN_HOST;
return;
}
/********************************************/
/* lpfc_reg_login Issue a REG_LOGIN */
/* mailbox command */
/********************************************/
int
lpfc_reg_login(struct lpfc_hba * phba,
uint32_t did, uint8_t * param, LPFC_MBOXQ_t * pmb, uint32_t flag)
{
uint8_t *sparam;
struct lpfc_dmabuf *mp;
MAILBOX_t *mb;
struct lpfc_sli *psli;
psli = &phba->sli;
mb = &pmb->mb;
memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
mb->un.varRegLogin.rpi = 0;
mb->un.varRegLogin.did = did;
mb->un.varWords[30] = flag; /* Set flag to issue action on cmpl */
mb->mbxOwner = OWN_HOST;
/* Get a buffer to hold NPorts Service Parameters */
if (((mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL)) == NULL) ||
((mp->virt = lpfc_mbuf_alloc(phba, 0, &(mp->phys))) == 0)) {
if (mp)
kfree(mp);
mb->mbxCommand = MBX_REG_LOGIN64;
/* REG_LOGIN: no buffers */
lpfc_printf_log(phba,
KERN_WARNING,
LOG_MBOX,
"%d:0302 REG_LOGIN: no buffers Data x%x x%x\n",
phba->brd_no,
(uint32_t) did, (uint32_t) flag);
return (1);
}
INIT_LIST_HEAD(&mp->list);
sparam = mp->virt;
/* Copy param's into a new buffer */
memcpy(sparam, param, sizeof (struct serv_parm));
/* save address for completion */
pmb->context1 = (uint8_t *) mp;
mb->mbxCommand = MBX_REG_LOGIN64;
mb->un.varRegLogin.un.sp64.tus.f.bdeSize = sizeof (struct serv_parm);
mb->un.varRegLogin.un.sp64.addrHigh = putPaddrHigh(mp->phys);
mb->un.varRegLogin.un.sp64.addrLow = putPaddrLow(mp->phys);
return (0);
}
/**********************************************/
/* lpfc_unreg_login Issue a UNREG_LOGIN */
/* mailbox command */
/**********************************************/
void
lpfc_unreg_login(struct lpfc_hba * phba, uint32_t rpi, LPFC_MBOXQ_t * pmb)
{
MAILBOX_t *mb;
mb = &pmb->mb;
memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
mb->un.varUnregLogin.rpi = (uint16_t) rpi;
mb->un.varUnregLogin.rsvd1 = 0;
mb->mbxCommand = MBX_UNREG_LOGIN;
mb->mbxOwner = OWN_HOST;
return;
}
static void
lpfc_config_pcb_setup(struct lpfc_hba * phba)
{
struct lpfc_sli *psli = &phba->sli;
struct lpfc_sli_ring *pring;
PCB_t *pcbp = &phba->slim2p->pcb;
dma_addr_t pdma_addr;
uint32_t offset;
uint32_t iocbCnt;
int i;
psli->MBhostaddr = (uint32_t *)&phba->slim2p->mbx;
pcbp->maxRing = (psli->num_rings - 1);
iocbCnt = 0;
for (i = 0; i < psli->num_rings; i++) {
pring = &psli->ring[i];
/* A ring MUST have both cmd and rsp entries defined to be
valid */
if ((pring->numCiocb == 0) || (pring->numRiocb == 0)) {
pcbp->rdsc[i].cmdEntries = 0;
pcbp->rdsc[i].rspEntries = 0;
pcbp->rdsc[i].cmdAddrHigh = 0;
pcbp->rdsc[i].rspAddrHigh = 0;
pcbp->rdsc[i].cmdAddrLow = 0;
pcbp->rdsc[i].rspAddrLow = 0;
pring->cmdringaddr = NULL;
pring->rspringaddr = NULL;
continue;
}
/* Command ring setup for ring */
pring->cmdringaddr =
(void *)&phba->slim2p->IOCBs[iocbCnt];
pcbp->rdsc[i].cmdEntries = pring->numCiocb;
offset = (uint8_t *)&phba->slim2p->IOCBs[iocbCnt] -
(uint8_t *)phba->slim2p;
pdma_addr = phba->slim2p_mapping + offset;
pcbp->rdsc[i].cmdAddrHigh = putPaddrHigh(pdma_addr);
pcbp->rdsc[i].cmdAddrLow = putPaddrLow(pdma_addr);
iocbCnt += pring->numCiocb;
/* Response ring setup for ring */
pring->rspringaddr =
(void *)&phba->slim2p->IOCBs[iocbCnt];
pcbp->rdsc[i].rspEntries = pring->numRiocb;
offset = (uint8_t *)&phba->slim2p->IOCBs[iocbCnt] -
(uint8_t *)phba->slim2p;
pdma_addr = phba->slim2p_mapping + offset;
pcbp->rdsc[i].rspAddrHigh = putPaddrHigh(pdma_addr);
pcbp->rdsc[i].rspAddrLow = putPaddrLow(pdma_addr);
iocbCnt += pring->numRiocb;
}
}
void
lpfc_read_rev(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
{
MAILBOX_t *mb;
mb = &pmb->mb;
memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
mb->un.varRdRev.cv = 1;
mb->mbxCommand = MBX_READ_REV;
mb->mbxOwner = OWN_HOST;
return;
}
void
lpfc_config_ring(struct lpfc_hba * phba, int ring, LPFC_MBOXQ_t * pmb)
{
int i;
MAILBOX_t *mb = &pmb->mb;
struct lpfc_sli *psli;
struct lpfc_sli_ring *pring;
memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
mb->un.varCfgRing.ring = ring;
mb->un.varCfgRing.maxOrigXchg = 0;
mb->un.varCfgRing.maxRespXchg = 0;
mb->un.varCfgRing.recvNotify = 1;
psli = &phba->sli;
pring = &psli->ring[ring];
mb->un.varCfgRing.numMask = pring->num_mask;
mb->mbxCommand = MBX_CONFIG_RING;
mb->mbxOwner = OWN_HOST;
/* Is this ring configured for a specific profile */
if (pring->prt[0].profile) {
mb->un.varCfgRing.profile = pring->prt[0].profile;
return;
}
/* Otherwise we setup specific rctl / type masks for this ring */
for (i = 0; i < pring->num_mask; i++) {
mb->un.varCfgRing.rrRegs[i].rval = pring->prt[i].rctl;
if (mb->un.varCfgRing.rrRegs[i].rval != FC_ELS_REQ)
mb->un.varCfgRing.rrRegs[i].rmask = 0xff;
else
mb->un.varCfgRing.rrRegs[i].rmask = 0xfe;
mb->un.varCfgRing.rrRegs[i].tval = pring->prt[i].type;
mb->un.varCfgRing.rrRegs[i].tmask = 0xff;
}
return;
}
void
lpfc_config_port(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
{
MAILBOX_t *mb = &pmb->mb;
dma_addr_t pdma_addr;
uint32_t bar_low, bar_high;
size_t offset;
HGP hgp;
void __iomem *to_slim;
memset(pmb, 0, sizeof(LPFC_MBOXQ_t));
mb->mbxCommand = MBX_CONFIG_PORT;
mb->mbxOwner = OWN_HOST;
mb->un.varCfgPort.pcbLen = sizeof(PCB_t);
offset = (uint8_t *)&phba->slim2p->pcb - (uint8_t *)phba->slim2p;
pdma_addr = phba->slim2p_mapping + offset;
mb->un.varCfgPort.pcbLow = putPaddrLow(pdma_addr);
mb->un.varCfgPort.pcbHigh = putPaddrHigh(pdma_addr);
/* Now setup pcb */
phba->slim2p->pcb.type = TYPE_NATIVE_SLI2;
phba->slim2p->pcb.feature = FEATURE_INITIAL_SLI2;
/* Setup Mailbox pointers */
phba->slim2p->pcb.mailBoxSize = sizeof(MAILBOX_t);
offset = (uint8_t *)&phba->slim2p->mbx - (uint8_t *)phba->slim2p;
pdma_addr = phba->slim2p_mapping + offset;
phba->slim2p->pcb.mbAddrHigh = putPaddrHigh(pdma_addr);
phba->slim2p->pcb.mbAddrLow = putPaddrLow(pdma_addr);
/*
* Setup Host Group ring pointer.
*
* For efficiency reasons, the ring get/put pointers can be
* placed in adapter memory (SLIM) rather than in host memory.
* This allows firmware to avoid PCI reads/writes when updating
* and checking pointers.
*
* The firmware recognizes the use of SLIM memory by comparing
* the address of the get/put pointers structure with that of
* the SLIM BAR (BAR0).
*
* Caution: be sure to use the PCI config space value of BAR0/BAR1
* (the hardware's view of the base address), not the OS's
* value of pci_resource_start() as the OS value may be a cookie
* for ioremap/iomap.
*/
pci_read_config_dword(phba->pcidev, PCI_BASE_ADDRESS_0, &bar_low);
pci_read_config_dword(phba->pcidev, PCI_BASE_ADDRESS_1, &bar_high);
/* mask off BAR0's flag bits 0 - 3 */
phba->slim2p->pcb.hgpAddrLow = (bar_low & PCI_BASE_ADDRESS_MEM_MASK) +
(SLIMOFF*sizeof(uint32_t));
if (bar_low & PCI_BASE_ADDRESS_MEM_TYPE_64)
phba->slim2p->pcb.hgpAddrHigh = bar_high;
else
phba->slim2p->pcb.hgpAddrHigh = 0;
/* write HGP data to SLIM at the required longword offset */
memset(&hgp, 0, sizeof(HGP));
to_slim = phba->MBslimaddr + (SLIMOFF*sizeof (uint32_t));
lpfc_memcpy_to_slim(to_slim, &hgp, sizeof (HGP));
/* Setup Port Group ring pointer */
offset = (uint8_t *)&phba->slim2p->mbx.us.s2.port -
(uint8_t *)phba->slim2p;
pdma_addr = phba->slim2p_mapping + offset;
phba->slim2p->pcb.pgpAddrHigh = putPaddrHigh(pdma_addr);
phba->slim2p->pcb.pgpAddrLow = putPaddrLow(pdma_addr);
/* Use callback routine to setp rings in the pcb */
lpfc_config_pcb_setup(phba);
/* special handling for LC HBAs */
if (lpfc_is_LC_HBA(phba->pcidev->device)) {
uint32_t hbainit[5];
lpfc_hba_init(phba, hbainit);
memcpy(&mb->un.varCfgPort.hbainit, hbainit, 20);
}
/* Swap PCB if needed */
lpfc_sli_pcimem_bcopy(&phba->slim2p->pcb, &phba->slim2p->pcb,
sizeof (PCB_t));
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
"%d:0405 Service Level Interface (SLI) 2 selected\n",
phba->brd_no);
}
void
lpfc_mbox_put(struct lpfc_hba * phba, LPFC_MBOXQ_t * mbq)
{
struct lpfc_sli *psli;
psli = &phba->sli;
list_add_tail(&mbq->list, &psli->mboxq);
psli->mboxq_cnt++;
return;
}
LPFC_MBOXQ_t *
lpfc_mbox_get(struct lpfc_hba * phba)
{
LPFC_MBOXQ_t *mbq = NULL;
struct lpfc_sli *psli = &phba->sli;
list_remove_head((&psli->mboxq), mbq, LPFC_MBOXQ_t,
list);
if (mbq) {
psli->mboxq_cnt--;
}
return mbq;
}

View File

@ -0,0 +1,179 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Enterprise Fibre Channel Host Bus Adapters. *
* Refer to the README file included with this package for *
* driver version and adapter support. *
* Copyright (C) 2004 Emulex Corporation. *
* www.emulex.com *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details, a copy of which *
* can be found in the file COPYING included with this package. *
*******************************************************************/
/*
* $Id: lpfc_mem.c 1.79 2005/04/13 14:25:50EDT sf_support Exp $
*/
#include <linux/mempool.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
#include "lpfc_hw.h"
#include "lpfc_sli.h"
#include "lpfc_disc.h"
#include "lpfc_scsi.h"
#include "lpfc.h"
#include "lpfc_crtn.h"
#define LPFC_MBUF_POOL_SIZE 64 /* max elements in MBUF safety pool */
#define LPFC_MEM_POOL_SIZE 64 /* max elem in non-DMA safety pool */
static void *
lpfc_pool_kmalloc(unsigned int gfp_flags, void *data)
{
return kmalloc((unsigned long)data, gfp_flags);
}
static void
lpfc_pool_kfree(void *obj, void *data)
{
kfree(obj);
}
int
lpfc_mem_alloc(struct lpfc_hba * phba)
{
struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool;
int i;
phba->lpfc_scsi_dma_buf_pool = pci_pool_create("lpfc_scsi_dma_buf_pool",
phba->pcidev, phba->cfg_sg_dma_buf_size, 8, 0);
if (!phba->lpfc_scsi_dma_buf_pool)
goto fail;
phba->lpfc_mbuf_pool = pci_pool_create("lpfc_mbuf_pool", phba->pcidev,
LPFC_BPL_SIZE, 8,0);
if (!phba->lpfc_mbuf_pool)
goto fail_free_dma_buf_pool;
pool->elements = kmalloc(sizeof(struct lpfc_dmabuf) *
LPFC_MBUF_POOL_SIZE, GFP_KERNEL);
pool->max_count = 0;
pool->current_count = 0;
for ( i = 0; i < LPFC_MBUF_POOL_SIZE; i++) {
pool->elements[i].virt = pci_pool_alloc(phba->lpfc_mbuf_pool,
GFP_KERNEL, &pool->elements[i].phys);
if (!pool->elements[i].virt)
goto fail_free_mbuf_pool;
pool->max_count++;
pool->current_count++;
}
phba->mbox_mem_pool = mempool_create(LPFC_MEM_POOL_SIZE,
lpfc_pool_kmalloc, lpfc_pool_kfree,
(void *)(unsigned long)sizeof(LPFC_MBOXQ_t));
if (!phba->mbox_mem_pool)
goto fail_free_mbuf_pool;
phba->nlp_mem_pool = mempool_create(LPFC_MEM_POOL_SIZE,
lpfc_pool_kmalloc, lpfc_pool_kfree,
(void *)(unsigned long)sizeof(struct lpfc_nodelist));
if (!phba->nlp_mem_pool)
goto fail_free_mbox_pool;
return 0;
fail_free_mbox_pool:
mempool_destroy(phba->mbox_mem_pool);
fail_free_mbuf_pool:
while (--i)
pci_pool_free(phba->lpfc_mbuf_pool, pool->elements[i].virt,
pool->elements[i].phys);
kfree(pool->elements);
pci_pool_destroy(phba->lpfc_mbuf_pool);
fail_free_dma_buf_pool:
pci_pool_destroy(phba->lpfc_scsi_dma_buf_pool);
fail:
return -ENOMEM;
}
void
lpfc_mem_free(struct lpfc_hba * phba)
{
struct lpfc_sli *psli = &phba->sli;
struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool;
LPFC_MBOXQ_t *mbox, *next_mbox;
struct lpfc_dmabuf *mp;
int i;
list_for_each_entry_safe(mbox, next_mbox, &psli->mboxq, list) {
mp = (struct lpfc_dmabuf *) (mbox->context1);
if (mp) {
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
}
list_del(&mbox->list);
mempool_free(mbox, phba->mbox_mem_pool);
}
psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
if (psli->mbox_active) {
mbox = psli->mbox_active;
mp = (struct lpfc_dmabuf *) (mbox->context1);
if (mp) {
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
}
mempool_free(mbox, phba->mbox_mem_pool);
psli->mbox_active = NULL;
}
for (i = 0; i < pool->current_count; i++)
pci_pool_free(phba->lpfc_mbuf_pool, pool->elements[i].virt,
pool->elements[i].phys);
kfree(pool->elements);
mempool_destroy(phba->nlp_mem_pool);
mempool_destroy(phba->mbox_mem_pool);
pci_pool_destroy(phba->lpfc_scsi_dma_buf_pool);
pci_pool_destroy(phba->lpfc_mbuf_pool);
}
void *
lpfc_mbuf_alloc(struct lpfc_hba *phba, int mem_flags, dma_addr_t *handle)
{
struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool;
void *ret;
ret = pci_pool_alloc(phba->lpfc_mbuf_pool, GFP_KERNEL, handle);
if (!ret && ( mem_flags & MEM_PRI) && pool->current_count) {
pool->current_count--;
ret = pool->elements[pool->current_count].virt;
*handle = pool->elements[pool->current_count].phys;
}
return ret;
}
void
lpfc_mbuf_free(struct lpfc_hba * phba, void *virt, dma_addr_t dma)
{
struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool;
if (pool->current_count < pool->max_count) {
pool->elements[pool->current_count].virt = virt;
pool->elements[pool->current_count].phys = dma;
pool->current_count++;
} else {
pci_pool_free(phba->lpfc_mbuf_pool, virt, dma);
}
return;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,157 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Enterprise Fibre Channel Host Bus Adapters. *
* Refer to the README file included with this package for *
* driver version and adapter support. *
* Copyright (C) 2004 Emulex Corporation. *
* www.emulex.com *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details, a copy of which *
* can be found in the file COPYING included with this package. *
*******************************************************************/
/*
* $Id: lpfc_scsi.h 1.83 2005/04/07 08:47:43EDT sf_support Exp $
*/
struct lpfc_hba;
#define list_remove_head(list, entry, type, member) \
if (!list_empty(list)) { \
entry = list_entry((list)->next, type, member); \
list_del_init(&entry->member); \
}
#define list_get_first(list, type, member) \
(list_empty(list)) ? NULL : \
list_entry((list)->next, type, member)
/* per-port data that is allocated in the FC transport for us */
struct lpfc_rport_data {
struct lpfc_nodelist *pnode; /* Pointer to the node structure. */
};
struct fcp_rsp {
uint32_t rspRsvd1; /* FC Word 0, byte 0:3 */
uint32_t rspRsvd2; /* FC Word 1, byte 0:3 */
uint8_t rspStatus0; /* FCP_STATUS byte 0 (reserved) */
uint8_t rspStatus1; /* FCP_STATUS byte 1 (reserved) */
uint8_t rspStatus2; /* FCP_STATUS byte 2 field validity */
#define RSP_LEN_VALID 0x01 /* bit 0 */
#define SNS_LEN_VALID 0x02 /* bit 1 */
#define RESID_OVER 0x04 /* bit 2 */
#define RESID_UNDER 0x08 /* bit 3 */
uint8_t rspStatus3; /* FCP_STATUS byte 3 SCSI status byte */
uint32_t rspResId; /* Residual xfer if residual count field set in
fcpStatus2 */
/* Received in Big Endian format */
uint32_t rspSnsLen; /* Length of sense data in fcpSnsInfo */
/* Received in Big Endian format */
uint32_t rspRspLen; /* Length of FCP response data in fcpRspInfo */
/* Received in Big Endian format */
uint8_t rspInfo0; /* FCP_RSP_INFO byte 0 (reserved) */
uint8_t rspInfo1; /* FCP_RSP_INFO byte 1 (reserved) */
uint8_t rspInfo2; /* FCP_RSP_INFO byte 2 (reserved) */
uint8_t rspInfo3; /* FCP_RSP_INFO RSP_CODE byte 3 */
#define RSP_NO_FAILURE 0x00
#define RSP_DATA_BURST_ERR 0x01
#define RSP_CMD_FIELD_ERR 0x02
#define RSP_RO_MISMATCH_ERR 0x03
#define RSP_TM_NOT_SUPPORTED 0x04 /* Task mgmt function not supported */
#define RSP_TM_NOT_COMPLETED 0x05 /* Task mgmt function not performed */
uint32_t rspInfoRsvd; /* FCP_RSP_INFO bytes 4-7 (reserved) */
uint8_t rspSnsInfo[128];
#define SNS_ILLEGAL_REQ 0x05 /* sense key is byte 3 ([2]) */
#define SNSCOD_BADCMD 0x20 /* sense code is byte 13 ([12]) */
};
struct fcp_cmnd {
uint32_t fcpLunMsl; /* most significant lun word (32 bits) */
uint32_t fcpLunLsl; /* least significant lun word (32 bits) */
/* # of bits to shift lun id to end up in right
* payload word, little endian = 8, big = 16.
*/
#if __BIG_ENDIAN
#define FC_LUN_SHIFT 16
#define FC_ADDR_MODE_SHIFT 24
#else /* __LITTLE_ENDIAN */
#define FC_LUN_SHIFT 8
#define FC_ADDR_MODE_SHIFT 0
#endif
uint8_t fcpCntl0; /* FCP_CNTL byte 0 (reserved) */
uint8_t fcpCntl1; /* FCP_CNTL byte 1 task codes */
#define SIMPLE_Q 0x00
#define HEAD_OF_Q 0x01
#define ORDERED_Q 0x02
#define ACA_Q 0x04
#define UNTAGGED 0x05
uint8_t fcpCntl2; /* FCP_CTL byte 2 task management codes */
#define FCP_ABORT_TASK_SET 0x02 /* Bit 1 */
#define FCP_CLEAR_TASK_SET 0x04 /* bit 2 */
#define FCP_BUS_RESET 0x08 /* bit 3 */
#define FCP_LUN_RESET 0x10 /* bit 4 */
#define FCP_TARGET_RESET 0x20 /* bit 5 */
#define FCP_CLEAR_ACA 0x40 /* bit 6 */
#define FCP_TERMINATE_TASK 0x80 /* bit 7 */
uint8_t fcpCntl3;
#define WRITE_DATA 0x01 /* Bit 0 */
#define READ_DATA 0x02 /* Bit 1 */
uint8_t fcpCdb[16]; /* SRB cdb field is copied here */
uint32_t fcpDl; /* Total transfer length */
};
struct lpfc_scsi_buf {
struct list_head list;
struct scsi_cmnd *pCmd;
struct lpfc_hba *scsi_hba;
struct lpfc_rport_data *rdata;
uint32_t timeout;
uint16_t status; /* From IOCB Word 7- ulpStatus */
uint32_t result; /* From IOCB Word 4. */
uint32_t seg_cnt; /* Number of scatter-gather segments returned by
* dma_map_sg. The driver needs this for calls
* to dma_unmap_sg. */
dma_addr_t nonsg_phys; /* Non scatter-gather physical address. */
/*
* data and dma_handle are the kernel virutal and bus address of the
* dma-able buffer containing the fcp_cmd, fcp_rsp and a scatter
* gather bde list that supports the sg_tablesize value.
*/
void *data;
dma_addr_t dma_handle;
struct fcp_cmnd *fcp_cmnd;
struct fcp_rsp *fcp_rsp;
struct ulp_bde64 *fcp_bpl;
/* cur_iocbq has phys of the dma-able buffer.
* Iotag is in here
*/
struct lpfc_iocbq cur_iocbq;
};
#define LPFC_SCSI_DMA_EXT_SIZE 264
#define LPFC_BPL_SIZE 1024
#define MDAC_DIRECT_CMD 0x22

2885
drivers/scsi/lpfc/lpfc_sli.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,216 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Enterprise Fibre Channel Host Bus Adapters. *
* Refer to the README file included with this package for *
* driver version and adapter support. *
* Copyright (C) 2004 Emulex Corporation. *
* www.emulex.com *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details, a copy of which *
* can be found in the file COPYING included with this package. *
*******************************************************************/
/*
* $Id: lpfc_sli.h 1.42 2005/03/21 02:01:28EST sf_support Exp $
*/
/* forward declaration for LPFC_IOCB_t's use */
struct lpfc_hba;
/* Define the context types that SLI handles for abort and sums. */
typedef enum _lpfc_ctx_cmd {
LPFC_CTX_LUN,
LPFC_CTX_TGT,
LPFC_CTX_CTX,
LPFC_CTX_HOST
} lpfc_ctx_cmd;
/* This structure is used to handle IOCB requests / responses */
struct lpfc_iocbq {
/* lpfc_iocbqs are used in double linked lists */
struct list_head list;
IOCB_t iocb; /* IOCB cmd */
uint8_t retry; /* retry counter for IOCB cmd - if needed */
uint8_t iocb_flag;
#define LPFC_IO_POLL 1 /* Polling mode iocb */
#define LPFC_IO_LIBDFC 2 /* libdfc iocb */
#define LPFC_IO_WAIT 4
#define LPFC_IO_HIPRI 8 /* High Priority Queue signal flag */
uint8_t abort_count;
uint8_t rsvd2;
uint32_t drvrTimeout; /* driver timeout in seconds */
void *context1; /* caller context information */
void *context2; /* caller context information */
void *context3; /* caller context information */
union {
wait_queue_head_t *hipri_wait_queue; /* High Priority Queue wait
queue */
struct lpfc_iocbq *rsp_iocb;
struct lpfcMboxq *mbox;
} context_un;
void (*iocb_cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
struct lpfc_iocbq *);
};
#define SLI_IOCB_RET_IOCB 1 /* Return IOCB if cmd ring full */
#define SLI_IOCB_HIGH_PRIORITY 2 /* High priority command */
#define IOCB_SUCCESS 0
#define IOCB_BUSY 1
#define IOCB_ERROR 2
#define IOCB_TIMEDOUT 3
typedef struct lpfcMboxq {
/* MBOXQs are used in single linked lists */
struct list_head list; /* ptr to next mailbox command */
MAILBOX_t mb; /* Mailbox cmd */
void *context1; /* caller context information */
void *context2; /* caller context information */
void (*mbox_cmpl) (struct lpfc_hba *, struct lpfcMboxq *);
} LPFC_MBOXQ_t;
#define MBX_POLL 1 /* poll mailbox till command done, then
return */
#define MBX_NOWAIT 2 /* issue command then return immediately */
#define MBX_STOP_IOCB 4 /* Stop iocb processing till mbox cmds
complete */
#define LPFC_MAX_RING_MASK 4 /* max num of rctl/type masks allowed per
ring */
#define LPFC_MAX_RING 4 /* max num of SLI rings used by driver */
struct lpfc_sli_ring;
struct lpfc_sli_ring_mask {
uint8_t profile; /* profile associated with ring */
uint8_t rctl; /* rctl / type pair configured for ring */
uint8_t type; /* rctl / type pair configured for ring */
uint8_t rsvd;
/* rcv'd unsol event */
void (*lpfc_sli_rcv_unsol_event) (struct lpfc_hba *,
struct lpfc_sli_ring *,
struct lpfc_iocbq *);
};
/* Structure used to hold SLI statistical counters and info */
struct lpfc_sli_ring_stat {
uint64_t iocb_event; /* IOCB event counters */
uint64_t iocb_cmd; /* IOCB cmd issued */
uint64_t iocb_rsp; /* IOCB rsp received */
uint64_t iocb_cmd_delay; /* IOCB cmd ring delay */
uint64_t iocb_cmd_full; /* IOCB cmd ring full */
uint64_t iocb_cmd_empty; /* IOCB cmd ring is now empty */
uint64_t iocb_rsp_full; /* IOCB rsp ring full */
};
/* Structure used to hold SLI ring information */
struct lpfc_sli_ring {
uint16_t flag; /* ring flags */
#define LPFC_DEFERRED_RING_EVENT 0x001 /* Deferred processing a ring event */
#define LPFC_CALL_RING_AVAILABLE 0x002 /* indicates cmd was full */
#define LPFC_STOP_IOCB_MBX 0x010 /* Stop processing IOCB cmds mbox */
#define LPFC_STOP_IOCB_EVENT 0x020 /* Stop processing IOCB cmds event */
#define LPFC_STOP_IOCB_MASK 0x030 /* Stop processing IOCB cmds mask */
uint16_t abtsiotag; /* tracks next iotag to use for ABTS */
uint32_t local_getidx; /* last available cmd index (from cmdGetInx) */
uint32_t next_cmdidx; /* next_cmd index */
uint8_t rsvd;
uint8_t ringno; /* ring number */
uint8_t rspidx; /* current index in response ring */
uint8_t cmdidx; /* current index in command ring */
uint16_t numCiocb; /* number of command iocb's per ring */
uint16_t numRiocb; /* number of rsp iocb's per ring */
uint32_t fast_iotag; /* max fastlookup based iotag */
uint32_t iotag_ctr; /* keeps track of the next iotag to use */
uint32_t iotag_max; /* max iotag value to use */
struct lpfc_iocbq ** fast_lookup; /* array of IOCB ptrs indexed by
iotag */
struct list_head txq;
uint16_t txq_cnt; /* current length of queue */
uint16_t txq_max; /* max length */
struct list_head txcmplq;
uint16_t txcmplq_cnt; /* current length of queue */
uint16_t txcmplq_max; /* max length */
uint32_t *cmdringaddr; /* virtual address for cmd rings */
uint32_t *rspringaddr; /* virtual address for rsp rings */
uint32_t missbufcnt; /* keep track of buffers to post */
struct list_head postbufq;
uint16_t postbufq_cnt; /* current length of queue */
uint16_t postbufq_max; /* max length */
struct list_head iocb_continueq;
uint16_t iocb_continueq_cnt; /* current length of queue */
uint16_t iocb_continueq_max; /* max length */
struct lpfc_sli_ring_mask prt[LPFC_MAX_RING_MASK];
uint32_t num_mask; /* number of mask entries in prt array */
struct lpfc_sli_ring_stat stats; /* SLI statistical info */
/* cmd ring available */
void (*lpfc_sli_cmd_available) (struct lpfc_hba *,
struct lpfc_sli_ring *);
};
/* Structure used to hold SLI statistical counters and info */
struct lpfc_sli_stat {
uint64_t mbox_stat_err; /* Mbox cmds completed status error */
uint64_t mbox_cmd; /* Mailbox commands issued */
uint64_t sli_intr; /* Count of Host Attention interrupts */
uint32_t err_attn_event; /* Error Attn event counters */
uint32_t link_event; /* Link event counters */
uint32_t mbox_event; /* Mailbox event counters */
uint32_t mbox_busy; /* Mailbox cmd busy */
};
/* Structure used to hold SLI information */
struct lpfc_sli {
uint32_t num_rings;
uint32_t sli_flag;
/* Additional sli_flags */
#define LPFC_SLI_MBOX_ACTIVE 0x100 /* HBA mailbox is currently active */
#define LPFC_SLI2_ACTIVE 0x200 /* SLI2 overlay in firmware is active */
#define LPFC_PROCESS_LA 0x400 /* Able to process link attention */
struct lpfc_sli_ring ring[LPFC_MAX_RING];
int fcp_ring; /* ring used for FCP initiator commands */
int next_ring;
int ip_ring; /* ring used for IP network drv cmds */
struct lpfc_sli_stat slistat; /* SLI statistical info */
struct list_head mboxq;
uint16_t mboxq_cnt; /* current length of queue */
uint16_t mboxq_max; /* max length */
LPFC_MBOXQ_t *mbox_active; /* active mboxq information */
struct timer_list mbox_tmo; /* Hold clk to timeout active mbox
cmd */
uint32_t *MBhostaddr; /* virtual address for mbox cmds */
};
/* Given a pointer to the start of the ring, and the slot number of
* the desired iocb entry, calc a pointer to that entry.
* (assume iocb entry size is 32 bytes, or 8 words)
*/
#define IOCB_ENTRY(ring,slot) ((IOCB_t *)(((char *)(ring)) + ((slot) * 32)))
#define LPFC_MBOX_TMO 30 /* Sec tmo for outstanding mbox
command */

View File

@ -0,0 +1,32 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Enterprise Fibre Channel Host Bus Adapters. *
* Refer to the README file included with this package for *
* driver version and adapter support. *
* Copyright (C) 2004 Emulex Corporation. *
* www.emulex.com *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details, a copy of which *
* can be found in the file COPYING included with this package. *
*******************************************************************/
/*
* $Id: lpfc_version.h 1.49 2005/04/13 15:07:19EDT sf_support Exp $
*/
#define LPFC_DRIVER_VERSION "8.0.28"
#define LPFC_DRIVER_NAME "lpfc"
#define LPFC_MODULE_DESC "Emulex LightPulse Fibre Channel SCSI driver " \
LPFC_DRIVER_VERSION
#define DFC_API_VERSION "0.0.0"