diff options
author | <jejb@titanic.il.steeleye.com> | 2005-04-17 16:05:31 -0500 |
---|---|---|
committer | James Bottomley <jejb@titanic> | 2005-04-18 13:50:53 -0500 |
commit | dea3101e0a5c897d2c9351a7444e139db9f40247 (patch) | |
tree | 61de19e98eed08bb760703b362eab2038c34f261 /drivers/scsi/lpfc | |
parent | 8e8790415e91964096f862a58cacb55d2bc9a817 (diff) |
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>
Diffstat (limited to 'drivers/scsi/lpfc')
-rw-r--r-- | drivers/scsi/lpfc/Makefile | 32 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc.h | 384 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_attr.c | 1291 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_compat.h | 97 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_crtn.h | 216 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_ct.c | 1237 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_disc.h | 206 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_els.c | 3258 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hbadisc.c | 2537 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hw.h | 2687 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 1739 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_logmsg.h | 41 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_mbox.c | 646 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_mem.c | 179 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_nportdisc.c | 1842 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_scsi.c | 1246 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_scsi.h | 157 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 2885 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.h | 216 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_version.h | 32 |
20 files changed, 20928 insertions, 0 deletions
diff --git a/drivers/scsi/lpfc/Makefile b/drivers/scsi/lpfc/Makefile new file mode 100644 index 00000000000..2b3098591c4 --- /dev/null +++ b/drivers/scsi/lpfc/Makefile @@ -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 diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h new file mode 100644 index 00000000000..d78247c63d0 --- /dev/null +++ b/drivers/scsi/lpfc/lpfc.h @@ -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; +}; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c new file mode 100644 index 00000000000..1276bd77b99 --- /dev/null +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -0,0 +1,1291 @@ +/******************************************************************* + * 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_attr.c 1.24 2005/04/13 11:58:55EDT sf_support Exp $ + */ + +#include <linux/ctype.h> +#include <linux/pci.h> +#include <linux/interrupt.h> + +#include <scsi/scsi_device.h> +#include <scsi/scsi_host.h> +#include <scsi/scsi_tcq.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_version.h" +#include "lpfc_compat.h" +#include "lpfc_crtn.h" + + +static void +lpfc_jedec_to_ascii(int incr, char hdw[]) +{ + int i, j; + for (i = 0; i < 8; i++) { + j = (incr & 0xf); + if (j <= 9) + hdw[7 - i] = 0x30 + j; + else + hdw[7 - i] = 0x61 + j - 10; + incr = (incr >> 4); + } + hdw[8] = 0; + return; +} + +static ssize_t +lpfc_drvr_version_show(struct class_device *cdev, char *buf) +{ + return snprintf(buf, PAGE_SIZE, LPFC_MODULE_DESC "\n"); +} + +static ssize_t +management_version_show(struct class_device *cdev, char *buf) +{ + return snprintf(buf, PAGE_SIZE, DFC_API_VERSION "\n"); +} + +static ssize_t +lpfc_info_show(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *host = class_to_shost(cdev); + return snprintf(buf, PAGE_SIZE, "%s\n",lpfc_info(host)); +} + +static ssize_t +lpfc_serialnum_show(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *host = class_to_shost(cdev); + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; + return snprintf(buf, PAGE_SIZE, "%s\n",phba->SerialNumber); +} + +static ssize_t +lpfc_modeldesc_show(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *host = class_to_shost(cdev); + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; + return snprintf(buf, PAGE_SIZE, "%s\n",phba->ModelDesc); +} + +static ssize_t +lpfc_modelname_show(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *host = class_to_shost(cdev); + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; + return snprintf(buf, PAGE_SIZE, "%s\n",phba->ModelName); +} + +static ssize_t +lpfc_programtype_show(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *host = class_to_shost(cdev); + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; + return snprintf(buf, PAGE_SIZE, "%s\n",phba->ProgramType); +} + +static ssize_t +lpfc_portnum_show(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *host = class_to_shost(cdev); + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; + return snprintf(buf, PAGE_SIZE, "%s\n",phba->Port); +} + +static ssize_t +lpfc_fwrev_show(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *host = class_to_shost(cdev); + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; + char fwrev[32]; + lpfc_decode_firmware_rev(phba, fwrev, 1); + return snprintf(buf, PAGE_SIZE, "%s\n",fwrev); +} + +static ssize_t +lpfc_hdw_show(struct class_device *cdev, char *buf) +{ + char hdw[9]; + struct Scsi_Host *host = class_to_shost(cdev); + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; + lpfc_vpd_t *vp = &phba->vpd; + lpfc_jedec_to_ascii(vp->rev.biuRev, hdw); + return snprintf(buf, PAGE_SIZE, "%s\n", hdw); +} +static ssize_t +lpfc_option_rom_version_show(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *host = class_to_shost(cdev); + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; + return snprintf(buf, PAGE_SIZE, "%s\n", phba->OptionROMVersion); +} +static ssize_t +lpfc_state_show(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *host = class_to_shost(cdev); + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; + int len = 0; + switch (phba->hba_state) { + case LPFC_INIT_START: + case LPFC_INIT_MBX_CMDS: + case LPFC_LINK_DOWN: + len += snprintf(buf + len, PAGE_SIZE-len, "Link Down\n"); + break; + case LPFC_LINK_UP: + case LPFC_LOCAL_CFG_LINK: + len += snprintf(buf + len, PAGE_SIZE-len, "Link Up\n"); + break; + case LPFC_FLOGI: + case LPFC_FABRIC_CFG_LINK: + case LPFC_NS_REG: + case LPFC_NS_QRY: + case LPFC_BUILD_DISC_LIST: + case LPFC_DISC_AUTH: + case LPFC_CLEAR_LA: + len += snprintf(buf + len, PAGE_SIZE-len, + "Link Up - Discovery\n"); + break; + case LPFC_HBA_READY: + len += snprintf(buf + len, PAGE_SIZE-len, + "Link Up - Ready:\n"); + if (phba->fc_topology == TOPOLOGY_LOOP) { + if (phba->fc_flag & FC_PUBLIC_LOOP) + len += snprintf(buf + len, PAGE_SIZE-len, + " Public Loop\n"); + else + len += snprintf(buf + len, PAGE_SIZE-len, + " Private Loop\n"); + } else { + if (phba->fc_flag & FC_FABRIC) + len += snprintf(buf + len, PAGE_SIZE-len, + " Fabric\n"); + else + len += snprintf(buf + len, PAGE_SIZE-len, + " Point-2-Point\n"); + } + } + return len; +} + +static ssize_t +lpfc_num_discovered_ports_show(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *host = class_to_shost(cdev); + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; + return snprintf(buf, PAGE_SIZE, "%d\n", phba->fc_map_cnt + + phba->fc_unmap_cnt); +} + + +static ssize_t +lpfc_issue_lip (struct class_device *cdev, const char *buf, size_t count) +{ + struct Scsi_Host *host = class_to_shost(cdev); + struct lpfc_hba *phba = (struct lpfc_hba *) host->hostdata[0]; + int val = 0; + LPFC_MBOXQ_t *pmboxq; + int mbxstatus = MBXERR_ERROR; + + if ((sscanf(buf, "%d", &val) != 1) || + (val != 1)) + return -EINVAL; + + if ((phba->fc_flag & FC_OFFLINE_MODE) || + (phba->hba_state != LPFC_HBA_READY)) + return -EPERM; + + pmboxq = mempool_alloc(phba->mbox_mem_pool,GFP_KERNEL); + + if (!pmboxq) + return -ENOMEM; + + memset((void *)pmboxq, 0, sizeof (LPFC_MBOXQ_t)); + lpfc_init_link(phba, pmboxq, phba->cfg_topology, phba->cfg_link_speed); + mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); + + if (mbxstatus == MBX_TIMEOUT) + pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + else + mempool_free( pmboxq, phba->mbox_mem_pool); + + if (mbxstatus == MBXERR_ERROR) + return -EIO; + + return strlen(buf); +} + +static ssize_t +lpfc_nport_evt_cnt_show(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *host = class_to_shost(cdev); + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; + return snprintf(buf, PAGE_SIZE, "%d\n", phba->nport_event_cnt); +} + +static ssize_t +lpfc_board_online_show(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *host = class_to_shost(cdev); + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; + + if (!phba) return 0; + + if (phba->fc_flag & FC_OFFLINE_MODE) + return snprintf(buf, PAGE_SIZE, "0\n"); + else + return snprintf(buf, PAGE_SIZE, "1\n"); +} + +static ssize_t +lpfc_board_online_store(struct class_device *cdev, const char *buf, + size_t count) +{ + struct Scsi_Host *host = class_to_shost(cdev); + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; + struct completion online_compl; + int val=0, status=0; + + if (sscanf(buf, "%d", &val) != 1) + return 0; + + init_completion(&online_compl); + + if (val) + lpfc_workq_post_event(phba, &status, &online_compl, + LPFC_EVT_ONLINE); + else + lpfc_workq_post_event(phba, &status, &online_compl, + LPFC_EVT_OFFLINE); + wait_for_completion(&online_compl); + if (!status) + return strlen(buf); + else + return 0; +} + + +#define lpfc_param_show(attr) \ +static ssize_t \ +lpfc_##attr##_show(struct class_device *cdev, char *buf) \ +{ \ + struct Scsi_Host *host = class_to_shost(cdev);\ + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];\ + int val = 0;\ + if (phba){\ + val = phba->cfg_##attr;\ + return snprintf(buf, PAGE_SIZE, "%d\n",\ + phba->cfg_##attr);\ + }\ + return 0;\ +} + +#define lpfc_param_store(attr, minval, maxval) \ +static ssize_t \ +lpfc_##attr##_store(struct class_device *cdev, const char *buf, size_t count) \ +{ \ + struct Scsi_Host *host = class_to_shost(cdev);\ + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];\ + int val = 0;\ + if (!isdigit(buf[0]))\ + return -EINVAL;\ + if (sscanf(buf, "0x%x", &val) != 1)\ + if (sscanf(buf, "%d", &val) != 1)\ + return -EINVAL;\ + if (phba){\ + if (val >= minval && val <= maxval) {\ + phba->cfg_##attr = val;\ + return strlen(buf);\ + }\ + }\ + return 0;\ +} + +#define LPFC_ATTR_R_NOINIT(name, desc) \ +extern int lpfc_##name;\ +module_param(lpfc_##name, int, 0);\ +MODULE_PARM_DESC(lpfc_##name, desc);\ +lpfc_param_show(name)\ +static CLASS_DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL) + +#define LPFC_ATTR_R(name, defval, minval, maxval, desc) \ +static int lpfc_##name = defval;\ +module_param(lpfc_##name, int, 0);\ +MODULE_PARM_DESC(lpfc_##name, desc);\ +lpfc_param_show(name)\ +static CLASS_DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL) + +#define LPFC_ATTR_RW(name, defval, minval, maxval, desc) \ +static int lpfc_##name = defval;\ +module_param(lpfc_##name, int, 0);\ +MODULE_PARM_DESC(lpfc_##name, desc);\ +lpfc_param_show(name)\ +lpfc_param_store(name, minval, maxval)\ +static CLASS_DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\ + lpfc_##name##_show, lpfc_##name##_store) + +static CLASS_DEVICE_ATTR(info, S_IRUGO, lpfc_info_show, NULL); +static CLASS_DEVICE_ATTR(serialnum, S_IRUGO, lpfc_serialnum_show, NULL); +static CLASS_DEVICE_ATTR(modeldesc, S_IRUGO, lpfc_modeldesc_show, NULL); +static CLASS_DEVICE_ATTR(modelname, S_IRUGO, lpfc_modelname_show, NULL); +static CLASS_DEVICE_ATTR(programtype, S_IRUGO, lpfc_programtype_show, NULL); +static CLASS_DEVICE_ATTR(portnum, S_IRUGO, lpfc_portnum_show, NULL); +static CLASS_DEVICE_ATTR(fwrev, S_IRUGO, lpfc_fwrev_show, NULL); +static CLASS_DEVICE_ATTR(hdw, S_IRUGO, lpfc_hdw_show, NULL); +static CLASS_DEVICE_ATTR(state, S_IRUGO, lpfc_state_show, NULL); +static CLASS_DEVICE_ATTR(option_rom_version, S_IRUGO, + lpfc_option_rom_version_show, NULL); +static CLASS_DEVICE_ATTR(num_discovered_ports, S_IRUGO, + lpfc_num_discovered_ports_show, NULL); +static CLASS_DEVICE_ATTR(nport_evt_cnt, S_IRUGO, lpfc_nport_evt_cnt_show, NULL); +static CLASS_DEVICE_ATTR(lpfc_drvr_version, S_IRUGO, lpfc_drvr_version_show, + NULL); +static CLASS_DEVICE_ATTR(management_version, S_IRUGO, management_version_show, + NULL); +static CLASS_DEVICE_ATTR(issue_lip, S_IWUSR, NULL, lpfc_issue_lip); +static CLASS_DEVICE_ATTR(board_online, S_IRUGO | S_IWUSR, + lpfc_board_online_show, lpfc_board_online_store); + + +/* +# lpfc_log_verbose: Only turn this flag on if you are willing to risk being +# deluged with LOTS of information. +# You can set a bit mask to record specific types of verbose messages: +# +# LOG_ELS 0x1 ELS events +# LOG_DISCOVERY 0x2 Link discovery events +# LOG_MBOX 0x4 Mailbox events +# LOG_INIT 0x8 Initialization events +# LOG_LINK_EVENT 0x10 Link events +# LOG_IP 0x20 IP traffic history +# LOG_FCP 0x40 FCP traffic history +# LOG_NODE 0x80 Node table events +# LOG_MISC 0x400 Miscellaneous events +# LOG_SLI 0x800 SLI events +# LOG_CHK_COND 0x1000 FCP Check condition flag +# LOG_LIBDFC 0x2000 LIBDFC events +# LOG_ALL_MSG 0xffff LOG all messages +*/ +LPFC_ATTR_RW(log_verbose, 0x0, 0x0, 0xffff, "Verbose logging bit-mask"); + +/* +# lun_queue_depth: This parameter is used to limit the number of outstanding +# commands per FCP LUN. Value range is [1,128]. Default value is 30. +*/ +LPFC_ATTR_R(lun_queue_depth, 30, 1, 128, + "Max number of FCP commands we can queue to a specific LUN"); + +/* +# Some disk devices have a "select ID" or "select Target" capability. +# From a protocol standpoint "select ID" usually means select the +# Fibre channel "ALPA". In the FC-AL Profile there is an "informative +# annex" which contains a table that maps a "select ID" (a number +# between 0 and 7F) to an ALPA. By default, for compatibility with +# older drivers, the lpfc driver scans this table from low ALPA to high +# ALPA. +# +# Turning on the scan-down variable (on = 1, off = 0) will +# cause the lpfc driver to use an inverted table, effectively +# scanning ALPAs from high to low. Value range is [0,1]. Default value is 1. +# +# (Note: This "select ID" functionality is a LOOP ONLY characteristic +# and will not work across a fabric. Also this parameter will take +# effect only in the case when ALPA map is not available.) +*/ +LPFC_ATTR_R(scan_down, 1, 0, 1, + "Start scanning for devices from highest ALPA to lowest"); + +/* +# lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear +# until the timer expires. Value range is [0,255]. Default value is 20. +# NOTE: this MUST be less then the SCSI Layer command timeout - 1. +*/ +LPFC_ATTR_RW(nodev_tmo, 30, 0, 255, + "Seconds driver will hold I/O waiting for a device to come back"); + +/* +# lpfc_topology: link topology for init link +# 0x0 = attempt loop mode then point-to-point +# 0x02 = attempt point-to-point mode only +# 0x04 = attempt loop mode only +# 0x06 = attempt point-to-point mode then loop +# Set point-to-point mode if you want to run as an N_Port. +# Set loop mode if you want to run as an NL_Port. Value range is [0,0x6]. +# Default value is 0. +*/ +LPFC_ATTR_R(topology, 0, 0, 6, "Select Fibre Channel topology"); + |