From 92d7f7b0cde3ad2260e7462b40867b57efd49851 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sun, 17 Jun 2007 19:56:38 -0500 Subject: [SCSI] lpfc: NPIV: add NPIV support on top of SLI-3 NPIV support is added to the driver. It utilizes the interfaces of the fc transport for the creation and deletion of vports. Within the driver, a new Scsi_Host is created for each NPIV instance, and is paired with a new instance of a FC port. This allows N FC Port elements to share a single Adapter. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/Makefile | 5 +- drivers/scsi/lpfc/lpfc.h | 156 +++- drivers/scsi/lpfc/lpfc_attr.c | 308 ++++++- drivers/scsi/lpfc/lpfc_crtn.h | 71 +- drivers/scsi/lpfc/lpfc_ct.c | 520 ++++++++--- drivers/scsi/lpfc/lpfc_disc.h | 8 +- drivers/scsi/lpfc/lpfc_els.c | 1661 ++++++++++++++++++++++++++++-------- drivers/scsi/lpfc/lpfc_hbadisc.c | 1140 ++++++++++++++++--------- drivers/scsi/lpfc/lpfc_hw.h | 125 ++- drivers/scsi/lpfc/lpfc_init.c | 285 ++++--- drivers/scsi/lpfc/lpfc_logmsg.h | 1 + drivers/scsi/lpfc/lpfc_mbox.c | 131 ++- drivers/scsi/lpfc/lpfc_mem.c | 46 +- drivers/scsi/lpfc/lpfc_nportdisc.c | 298 +++++-- drivers/scsi/lpfc/lpfc_scsi.c | 355 ++++++-- drivers/scsi/lpfc/lpfc_sli.c | 1034 ++++++++++++---------- drivers/scsi/lpfc/lpfc_sli.h | 17 +- drivers/scsi/lpfc/lpfc_version.h | 2 +- drivers/scsi/lpfc/lpfc_vport.c | 508 +++++++++++ drivers/scsi/lpfc/lpfc_vport.h | 113 +++ 20 files changed, 5021 insertions(+), 1763 deletions(-) create mode 100644 drivers/scsi/lpfc/lpfc_vport.c create mode 100644 drivers/scsi/lpfc/lpfc_vport.h diff --git a/drivers/scsi/lpfc/Makefile b/drivers/scsi/lpfc/Makefile index d1be465d5f5..d94c9e0212a 100644 --- a/drivers/scsi/lpfc/Makefile +++ b/drivers/scsi/lpfc/Makefile @@ -1,7 +1,7 @@ #/******************************************************************* # * This file is part of the Emulex Linux Device Driver for * # * Fibre Channel Host Bus Adapters. * -# * Copyright (C) 2004-2005 Emulex. All rights reserved. * +# * Copyright (C) 2004-2006 Emulex. All rights reserved. * # * EMULEX and SLI are trademarks of Emulex. * # * www.emulex.com * # * * @@ -27,4 +27,5 @@ 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 + lpfc_init.o lpfc_mbox.o lpfc_nportdisc.o lpfc_scsi.o lpfc_attr.o \ + lpfc_vport.o diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 74f4d18842c..4b9019d7d50 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -34,6 +34,17 @@ struct lpfc_sli2_slim; #define LPFC_IOCB_LIST_CNT 2250 /* list of IOCBs for fast-path usage. */ #define LPFC_Q_RAMP_UP_INTERVAL 120 /* lun q_depth ramp up interval */ +/* + * Following time intervals are used of adjusting SCSI device + * queue depths when there are driver resource error or Firmware + * resource error. + */ +#define QUEUE_RAMP_DOWN_INTERVAL (1 * HZ) /* 1 Second */ +#define QUEUE_RAMP_UP_INTERVAL (300 * HZ) /* 5 minutes */ + +/* Number of exchanges reserved for discovery to complete */ +#define LPFC_DISC_IOCB_BUFF_COUNT 20 + /* Define macros for 64 bit support */ #define putPaddrLow(addr) ((uint32_t) (0xffffffff & (u64)(addr))) #define putPaddrHigh(addr) ((uint32_t) (0xffffffff & (((u64)(addr))>>32))) @@ -97,6 +108,29 @@ typedef struct lpfc_vpd { uint32_t sli2FwRev; uint8_t sli2FwName[16]; } rev; + struct { +#ifdef __BIG_ENDIAN_BITFIELD + uint32_t rsvd2 :24; /* Reserved */ + uint32_t cmv : 1; /* Configure Max VPIs */ + uint32_t ccrp : 1; /* Config Command Ring Polling */ + uint32_t csah : 1; /* Configure Synchronous Abort Handling */ + uint32_t chbs : 1; /* Cofigure Host Backing store */ + uint32_t cinb : 1; /* Enable Interrupt Notification Block */ + uint32_t cerbm : 1; /* Configure Enhanced Receive Buf Mgmt */ + uint32_t cmx : 1; /* Configure Max XRIs */ + uint32_t cmr : 1; /* Configure Max RPIs */ +#else /* __LITTLE_ENDIAN */ + uint32_t cmr : 1; /* Configure Max RPIs */ + uint32_t cmx : 1; /* Configure Max XRIs */ + uint32_t cerbm : 1; /* Configure Enhanced Receive Buf Mgmt */ + uint32_t cinb : 1; /* Enable Interrupt Notification Block */ + uint32_t chbs : 1; /* Cofigure Host Backing store */ + uint32_t csah : 1; /* Configure Synchronous Abort Handling */ + uint32_t ccrp : 1; /* Config Command Ring Polling */ + uint32_t cmv : 1; /* Configure Max VPIs */ + uint32_t rsvd2 :24; /* Reserved */ +#endif + } sli3Feat; } lpfc_vpd_t; struct lpfc_scsi_buf; @@ -129,6 +163,7 @@ struct lpfc_stats { uint32_t elsRcvRPS; uint32_t elsRcvRPL; uint32_t elsXmitFLOGI; + uint32_t elsXmitFDISC; uint32_t elsXmitPLOGI; uint32_t elsXmitPRLI; uint32_t elsXmitADISC; @@ -174,18 +209,21 @@ struct lpfc_sysfs_mbox { struct lpfc_hba; + enum discovery_state { - LPFC_STATE_UNKNOWN = 0, /* HBA state is unknown */ - LPFC_LOCAL_CFG_LINK = 6, /* local NPORT Id configured */ - LPFC_FLOGI = 7, /* FLOGI sent to Fabric */ - LPFC_FABRIC_CFG_LINK = 8, /* Fabric assigned NPORT Id - * configured */ - LPFC_NS_REG = 9, /* Register with NameServer */ - LPFC_NS_QRY = 10, /* Query NameServer for NPort ID list */ - LPFC_BUILD_DISC_LIST = 11, /* Build ADISC and PLOGI lists for - * device authentication / discovery */ - LPFC_DISC_AUTH = 12, /* Processing ADISC list */ - LPFC_VPORT_READY = 32, + LPFC_VPORT_UNKNOWN = 0, /* vport state is unknown */ + LPFC_VPORT_FAILED = 1, /* vport has failed */ + LPFC_LOCAL_CFG_LINK = 6, /* local NPORT Id configured */ + LPFC_FLOGI = 7, /* FLOGI sent to Fabric */ + LPFC_FDISC = 8, /* FDISC sent for vport */ + LPFC_FABRIC_CFG_LINK = 9, /* Fabric assigned NPORT Id + * configured */ + LPFC_NS_REG = 10, /* Register with NameServer */ + LPFC_NS_QRY = 11, /* Query NameServer for NPort ID list */ + LPFC_BUILD_DISC_LIST = 12, /* Build ADISC and PLOGI lists for + * device authentication / discovery */ + LPFC_DISC_AUTH = 13, /* Processing ADISC list */ + LPFC_VPORT_READY = 32, }; enum hba_state { @@ -195,8 +233,9 @@ enum hba_state { LPFC_INIT_MBX_CMDS = 3, /* Initialize HBA with mbox commands */ LPFC_LINK_DOWN = 4, /* HBA initialized, link is down */ LPFC_LINK_UP = 5, /* Link is up - issue READ_LA */ - LPFC_CLEAR_LA = 13, /* authentication cmplt - issue + LPFC_CLEAR_LA = 6, /* authentication cmplt - issue * CLEAR_LA */ + LPFC_HBA_READY = 32, LPFC_HBA_ERROR = -1 }; @@ -209,26 +248,30 @@ struct lpfc_vport { #define LPFC_FABRIC_PORT 3 enum discovery_state port_state; + uint16_t vpi; uint32_t fc_flag; /* FC flags */ /* Several of these flags are HBA centric and should be moved to * phba->link_flag (e.g. FC_PTP, FC_PUBLIC_LOOP) */ -#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_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 */ -#define FC_BYPASSED_MODE 0x20000 /* NPort is in bypassed mode */ +#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 /* Auth all devices after RSCN */ +#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 */ +#define FC_BYPASSED_MODE 0x20000 /* NPort is in bypassed mode */ +#define FC_RFF_NOT_SUPPORTED 0x40000 /* RFF_ID was rejected by switch */ +#define FC_VPORT_NEEDS_REG_VPI 0x80000 /* Needs to have its vpi registered */ +#define FC_RSCN_DEFERRED 0x100000 /* A deferred RSCN being processed */ struct list_head fc_nodes; @@ -269,6 +312,9 @@ struct lpfc_vport { #define WORKER_ELS_TMO 0x2 /* ELS timeout */ #define WORKER_MBOX_TMO 0x4 /* MBOX timeout */ #define WORKER_FDMI_TMO 0x8 /* FDMI timeout */ +#define WORKER_FABRIC_BLOCK_TMO 0x10 /* fabric block timout */ +#define WORKER_RAMP_DOWN_QUEUE 0x20 /* Decrease Q depth */ +#define WORKER_RAMP_UP_QUEUE 0x40 /* Increase Q depth */ struct timer_list fc_fdmitmo; struct timer_list els_tmofunc; @@ -278,10 +324,10 @@ struct lpfc_vport { uint8_t load_flag; #define FC_LOADING 0x1 /* HBA in process of loading drvr */ #define FC_UNLOADING 0x2 /* HBA in process of unloading drvr */ - + char *vname; /* Application assigned name */ + struct fc_vport *fc_vport; }; - struct hbq_s { uint16_t entry_count; /* Current number of HBQ slots */ uint32_t next_hbqPutIdx; /* Index to next HBQ slot to use */ @@ -289,33 +335,38 @@ struct hbq_s { uint32_t local_hbqGetIdx; /* Local copy of Get index from Port */ }; -#define MAX_HBQS 16 +#define LPFC_MAX_HBQS 16 +/* this matches the possition in the lpfc_hbq_defs array */ +#define LPFC_ELS_HBQ 0 struct lpfc_hba { struct lpfc_sli sli; uint32_t sli_rev; /* SLI2 or SLI3 */ uint32_t sli3_options; /* Mask of enabled SLI3 options */ -#define LPFC_SLI3_ENABLED 0x01 -#define LPFC_SLI3_HBQ_ENABLED 0x02 -#define LPFC_SLI3_INB_ENABLED 0x04 +#define LPFC_SLI3_ENABLED 0x01 +#define LPFC_SLI3_HBQ_ENABLED 0x02 +#define LPFC_SLI3_NPIV_ENABLED 0x04 +#define LPFC_SLI3_VPORT_TEARDOWN 0x08 uint32_t iocb_cmd_size; uint32_t iocb_rsp_size; enum hba_state link_state; uint32_t link_flag; /* link state flags */ -#define LS_LOOPBACK_MODE 0x40000 /* NPort is in Loopback mode */ +#define LS_LOOPBACK_MODE 0x1 /* NPort is in Loopback mode */ /* This flag is set while issuing */ /* INIT_LINK mailbox command */ -#define LS_IGNORE_ERATT 0x80000 /* intr handler should ignore ERATT */ +#define LS_NPIV_FAB_SUPPORTED 0x2 /* Fabric supports NPIV */ +#define LS_IGNORE_ERATT 0x3 /* intr handler should ignore ERATT */ struct lpfc_sli2_slim *slim2p; struct lpfc_dmabuf hbqslimp; dma_addr_t slim2p_mapping; - uint16_t pci_cfg_value; + uint8_t work_found; +#define LPFC_MAX_WORKER_ITERATION 4 uint8_t fc_linkspeed; /* Link speed after last READ_LA */ @@ -325,7 +376,7 @@ struct lpfc_hba { struct timer_list fc_estabtmo; /* link establishment timer */ /* These fields used to be binfo */ uint32_t fc_pref_DID; /* preferred D_ID */ - uint8_t fc_pref_ALPA; /* preferred AL_PA */ + 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 */ @@ -355,6 +406,8 @@ struct lpfc_hba { uint32_t cfg_nodev_tmo; uint32_t cfg_devloss_tmo; uint32_t cfg_hba_queue_depth; + uint32_t cfg_peer_port_login; + uint32_t cfg_vport_restrict_login; uint32_t cfg_fcp_class; uint32_t cfg_use_adisc; uint32_t cfg_ack0; @@ -391,11 +444,9 @@ struct lpfc_hba { wait_queue_head_t *work_wait; struct task_struct *worker_thread; - struct hbq_dmabuf *hbq_buffer_pool; - uint32_t hbq_buffer_count; - uint32_t hbq_buff_count; /* Current hbq buffers */ + struct list_head hbq_buffer_list; uint32_t hbq_count; /* Count of configured HBQs */ - struct hbq_s hbqs[MAX_HBQS]; /* local copy of hbq indicies */ + struct hbq_s hbqs[LPFC_MAX_HBQS]; /* local copy of hbq indicies */ unsigned long pci_bar0_map; /* Physical address for PCI BAR0 */ unsigned long pci_bar2_map; /* Physical address for PCI BAR2 */ @@ -413,7 +464,7 @@ struct lpfc_hba { struct lpfc_hgp __iomem *host_gp; /* Host side get/put pointers */ uint32_t __iomem *hbq_put; /* Address in SLIM to HBQ put ptrs */ - uint32_t __iomem *hbq_get; /* Address in SLIM to HBQ get ptrs */ + uint32_t *hbq_get; /* Host mem address of HBQ get ptrs */ int brd_no; /* FC board number */ @@ -464,6 +515,22 @@ struct lpfc_hba { struct fc_host_statistics link_stats; struct list_head port_list; struct lpfc_vport *pport; /* physical lpfc_vport pointer */ + uint16_t max_vpi; /* Maximum virtual nports */ + uint16_t vpi_cnt; /* Nport count */ +#define LPFC_MAX_VPI 100 /* Max number of VPorts supported */ + unsigned long *vpi_bmask; /* vpi allocation table */ + + /* Data structure used by fabric iocb scheduler */ + struct list_head fabric_iocb_list; + atomic_t fabric_iocb_count; + struct timer_list fabric_block_timer; + unsigned long bit_flags; +#define FABRIC_COMANDS_BLOCKED 0 + atomic_t num_rsrc_err; + atomic_t num_cmd_success; + unsigned long last_rsrc_error_time; + unsigned long last_ramp_down_time; + unsigned long last_ramp_up_time; }; static inline struct Scsi_Host * @@ -485,10 +552,9 @@ static inline int lpfc_is_link_up(struct lpfc_hba *phba) { return phba->link_state == LPFC_LINK_UP || - phba->link_state == LPFC_CLEAR_LA; + phba->link_state == LPFC_CLEAR_LA || + phba->link_state == LPFC_HBA_READY; } - - #define FC_REG_DUMP_EVENT 0x10 /* Register for Dump events */ diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index b8adff8cea6..5cb7924fe3d 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -39,6 +39,7 @@ #include "lpfc_version.h" #include "lpfc_compat.h" #include "lpfc_crtn.h" +#include "lpfc_vport.h" #define LPFC_DEF_DEVLOSS_TMO 30 #define LPFC_MIN_DEVLOSS_TMO 1 @@ -139,7 +140,7 @@ lpfc_fwrev_show(struct class_device *cdev, char *buf) char fwrev[32]; lpfc_decode_firmware_rev(phba, fwrev, 1); - return snprintf(buf, PAGE_SIZE, "%s\n",fwrev); + return snprintf(buf, PAGE_SIZE, "%s, sli-%d\n", fwrev, phba->sli_rev); } static ssize_t @@ -178,10 +179,11 @@ lpfc_state_show(struct class_device *cdev, char *buf) case LPFC_INIT_MBX_CMDS: case LPFC_LINK_DOWN: case LPFC_HBA_ERROR: - len += snprintf(buf + len, PAGE_SIZE-len, "Link Down"); + len += snprintf(buf + len, PAGE_SIZE-len, "Link Down\n"); break; case LPFC_LINK_UP: case LPFC_CLEAR_LA: + case LPFC_HBA_READY: len += snprintf(buf + len, PAGE_SIZE-len, "Link Up - \n"); switch (vport->port_state) { @@ -190,8 +192,9 @@ lpfc_state_show(struct class_device *cdev, char *buf) break; case LPFC_LOCAL_CFG_LINK: len += snprintf(buf + len, PAGE_SIZE-len, - "configuring\n"); + "Configuring Link\n"); break; + case LPFC_FDISC: case LPFC_FLOGI: case LPFC_FABRIC_CFG_LINK: case LPFC_NS_REG: @@ -205,7 +208,11 @@ lpfc_state_show(struct class_device *cdev, char *buf) len += snprintf(buf + len, PAGE_SIZE - len, "Ready\n"); break; - case LPFC_STATE_UNKNOWN: + case LPFC_VPORT_FAILED: + len += snprintf(buf + len, PAGE_SIZE - len, "Failed\n"); + break; + + case LPFC_VPORT_UNKNOWN: len += snprintf(buf + len, PAGE_SIZE - len, "Unknown\n"); break; @@ -432,6 +439,151 @@ lpfc_board_mode_store(struct class_device *cdev, const char *buf, size_t count) return -EIO; } +static ssize_t +lpfc_max_vpi_show(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; + struct lpfc_hba *phba = vport->phba; + + return snprintf(buf, PAGE_SIZE, "%d\n", phba->max_vpi); +} + +static ssize_t +lpfc_used_vpi_show(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; + struct lpfc_hba *phba = vport->phba; + + /* Don't count the physical port */ + return snprintf(buf, PAGE_SIZE, "%d\n", phba->vpi_cnt-1); +} + +int +lpfc_get_hba_info(struct lpfc_hba *phba, uint32_t *mxri, + uint32_t *axri, uint32_t *mrpi, uint32_t *arpi) +{ + struct lpfc_sli *psli = &phba->sli; + LPFC_MBOXQ_t *pmboxq; + MAILBOX_t *pmb; + int rc = 0; + + /* + * prevent udev from issuing mailbox commands until the port is + * configured. + */ + if (phba->link_state < LPFC_LINK_DOWN || + !phba->mbox_mem_pool || + (phba->sli.sli_flag & LPFC_SLI2_ACTIVE) == 0) + return 0; + + if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) + return 0; + + pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!pmboxq) + return 0; + memset(pmboxq, 0, sizeof (LPFC_MBOXQ_t)); + + pmb = &pmboxq->mb; + pmb->mbxCommand = MBX_READ_CONFIG; + pmb->mbxOwner = OWN_HOST; + pmboxq->context1 = NULL; + + if ((phba->pport->fc_flag & FC_OFFLINE_MODE) || + (!(psli->sli_flag & LPFC_SLI2_ACTIVE))) + rc = MBX_NOT_FINISHED; + else + rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); + + if (rc != MBX_SUCCESS) { + if (rc == MBX_TIMEOUT) + pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + else + mempool_free(pmboxq, phba->mbox_mem_pool); + return 0; + } + + if (mrpi) + *mrpi = pmb->un.varRdConfig.max_rpi; + if (arpi) + *arpi = pmb->un.varRdConfig.avail_rpi; + if (mxri) + *mxri = pmb->un.varRdConfig.max_xri; + if (axri) + *axri = pmb->un.varRdConfig.avail_xri; + + mempool_free(pmboxq, phba->mbox_mem_pool); + return 1; +} + +static ssize_t +lpfc_max_rpi_show(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; + struct lpfc_hba *phba = vport->phba; + uint32_t cnt; + + if (lpfc_get_hba_info(phba, NULL, NULL, &cnt, NULL)) + return snprintf(buf, PAGE_SIZE, "%d\n", cnt); + return snprintf(buf, PAGE_SIZE, "Unknown\n"); +} + +static ssize_t +lpfc_used_rpi_show(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; + struct lpfc_hba *phba = vport->phba; + uint32_t cnt, acnt; + + if (lpfc_get_hba_info(phba, NULL, NULL, &cnt, &acnt)) + return snprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt)); + return snprintf(buf, PAGE_SIZE, "Unknown\n"); +} + +static ssize_t +lpfc_max_xri_show(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; + struct lpfc_hba *phba = vport->phba; + uint32_t cnt; + + if (lpfc_get_hba_info(phba, &cnt, NULL, NULL, NULL)) + return snprintf(buf, PAGE_SIZE, "%d\n", cnt); + return snprintf(buf, PAGE_SIZE, "Unknown\n"); +} + +static ssize_t +lpfc_used_xri_show(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; + struct lpfc_hba *phba = vport->phba; + uint32_t cnt, acnt; + + if (lpfc_get_hba_info(phba, &cnt, &acnt, NULL, NULL)) + return snprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt)); + return snprintf(buf, PAGE_SIZE, "Unknown\n"); +} + +static ssize_t +lpfc_npiv_info_show(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; + struct lpfc_hba *phba = vport->phba; + + if (!(phba->max_vpi)) + return snprintf(buf, PAGE_SIZE, "NPIV Not Supported\n"); + if (vport->port_type == LPFC_PHYSICAL_PORT) + return snprintf(buf, PAGE_SIZE, "NPIV Physical\n"); + return snprintf(buf, PAGE_SIZE, "NPIV Virtual (VPI %d)\n", vport->vpi); +} + static ssize_t lpfc_poll_show(struct class_device *cdev, char *buf) { @@ -640,6 +792,13 @@ static CLASS_DEVICE_ATTR(management_version, S_IRUGO, management_version_show, static CLASS_DEVICE_ATTR(board_mode, S_IRUGO | S_IWUSR, lpfc_board_mode_show, lpfc_board_mode_store); static CLASS_DEVICE_ATTR(issue_reset, S_IWUSR, NULL, lpfc_issue_reset); +static CLASS_DEVICE_ATTR(max_vpi, S_IRUGO, lpfc_max_vpi_show, NULL); +static CLASS_DEVICE_ATTR(used_vpi, S_IRUGO, lpfc_used_vpi_show, NULL); +static CLASS_DEVICE_ATTR(max_rpi, S_IRUGO, lpfc_max_rpi_show, NULL); +static CLASS_DEVICE_ATTR(used_rpi, S_IRUGO, lpfc_used_rpi_show, NULL); +static CLASS_DEVICE_ATTR(max_xri, S_IRUGO, lpfc_max_xri_show, NULL); +static CLASS_DEVICE_ATTR(used_xri, S_IRUGO, lpfc_used_xri_show, NULL); +static CLASS_DEVICE_ATTR(npiv_info, S_IRUGO, lpfc_npiv_info_show, NULL); static char *lpfc_soft_wwn_key = "C99G71SL8032A"; @@ -829,6 +988,17 @@ MODULE_PARM_DESC(lpfc_poll, "FCP ring polling mode control:" static CLASS_DEVICE_ATTR(lpfc_poll, S_IRUGO | S_IWUSR, lpfc_poll_show, lpfc_poll_store); +int lpfc_sli_mode = 0; +module_param(lpfc_sli_mode, int, 0); +MODULE_PARM_DESC(lpfc_sli_mode, "SLI mode selector:" + " 0 - auto (SLI-3 if supported)," + " 2 - select SLI-2 even on SLI-3 capable HBAs," + " 3 - select SLI-3"); + +int lpfc_npiv_enable = 0; +module_param(lpfc_npiv_enable, int, 0); +MODULE_PARM_DESC(lpfc_npiv_enable, "Enable NPIV functionality"); + /* # 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 30. @@ -984,6 +1154,33 @@ LPFC_ATTR_R(lun_queue_depth, 30, 1, 128, LPFC_ATTR_R(hba_queue_depth, 8192, 32, 8192, "Max number of FCP commands we can queue to a lpfc HBA"); +/* +# peer_port_login: This parameter allows/prevents logins +# between peer ports hosted on the same physical port. +# When this parameter is set 0 peer ports of same physical port +# are not allowed to login to each other. +# When this parameter is set 1 peer ports of same physical port +# are allowed to login to each other. +# Default value of this parameter is 0. +*/ +LPFC_ATTR_R(peer_port_login, 0, 0, 1, + "Allow peer ports on the same physical port to login to each " + "other."); + +/* +# vport_restrict_login: This parameter allows/prevents logins +# between Virtual Ports and remote initiators. +# When this parameter is not set (0) Virtual Ports will accept PLOGIs from +# other initiators and will attempt to PLOGI all remote ports. +# When this parameter is set (1) Virtual Ports will reject PLOGIs from +# remote ports and will not attempt to PLOGI to other initiators. +# This parameter does not restrict to the physical port. +# This parameter does not restrict logins to Fabric resident remote ports. +# Default value of this parameter is 1. +*/ +LPFC_ATTR_RW(vport_restrict_login, 1, 0, 1, + "Restrict virtual ports login to remote initiators."); + /* # Some disk devices have a "select ID" or "select Target" capability. # From a protocol standpoint "select ID" usually means select the @@ -1127,6 +1324,7 @@ LPFC_ATTR_RW(poll_tmo, 10, 1, 255, LPFC_ATTR_R(use_msi, 0, 0, 1, "Use Message Signaled Interrupts, if possible"); + struct class_device_attribute *lpfc_hba_attrs[] = { &class_device_attr_info, &class_device_attr_serialnum, @@ -1143,6 +1341,8 @@ struct class_device_attribute *lpfc_hba_attrs[] = { &class_device_attr_lpfc_log_verbose, &class_device_attr_lpfc_lun_queue_depth, &class_device_attr_lpfc_hba_queue_depth, + &class_device_attr_lpfc_peer_port_login, + &class_device_attr_lpfc_vport_restrict_login, &class_device_attr_lpfc_nodev_tmo, &class_device_attr_lpfc_devloss_tmo, &class_device_attr_lpfc_fcp_class, @@ -1161,6 +1361,13 @@ struct class_device_attribute *lpfc_hba_attrs[] = { &class_device_attr_nport_evt_cnt, &class_device_attr_management_version, &class_device_attr_board_mode, + &class_device_attr_max_vpi, + &class_device_attr_used_vpi, + &class_device_attr_max_rpi, + &class_device_attr_used_rpi, + &class_device_attr_max_xri, + &class_device_attr_used_xri, + &class_device_attr_npiv_info, &class_device_attr_issue_reset, &class_device_attr_lpfc_poll, &class_device_attr_lpfc_poll_tmo, @@ -1299,7 +1506,7 @@ sysfs_mbox_write(struct kobject *kobj, char *buf, loff_t off, size_t count) } else { if (phba->sysfs_mbox.state != SMBOX_WRITING || phba->sysfs_mbox.offset != off || - phba->sysfs_mbox.mbox == NULL ) { + phba->sysfs_mbox.mbox == NULL) { sysfs_mbox_idle(phba); spin_unlock_irq(&phba->hbalock); return -EAGAIN; @@ -1406,6 +1613,8 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count) return -EPERM; } + phba->sysfs_mbox.mbox->vport = vport; + if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) { sysfs_mbox_idle(phba); spin_unlock_irq(&phba->hbalock); @@ -1480,12 +1689,12 @@ lpfc_alloc_sysfs_attr(struct lpfc_vport *vport) int error; error = sysfs_create_bin_file(&shost->shost_classdev.kobj, - &sysfs_ctlreg_attr); + &sysfs_ctlreg_attr); if (error) goto out; error = sysfs_create_bin_file(&shost->shost_classdev.kobj, - &sysfs_mbox_attr); + &sysfs_mbox_attr); if (error) goto out_remove_ctlreg_attr; @@ -1527,7 +1736,9 @@ lpfc_get_host_port_type(struct Scsi_Host *shost) spin_lock_irq(shost->host_lock); - if (lpfc_is_link_up(phba)) { + if (vport->port_type == LPFC_NPIV_PORT) { + fc_host_port_type(shost) = FC_PORTTYPE_NPIV; + } else if (lpfc_is_link_up(phba)) { if (phba->fc_topology == TOPOLOGY_LOOP) { if (vport->fc_flag & FC_PUBLIC_LOOP) fc_host_port_type(shost) = FC_PORTTYPE_NLPORT; @@ -1563,6 +1774,7 @@ lpfc_get_host_port_state(struct Scsi_Host *shost) break; case LPFC_LINK_UP: case LPFC_CLEAR_LA: + case LPFC_HBA_READY: /* Links up, beyond this port_type reports state */ fc_host_port_state(shost) = FC_PORTSTATE_ONLINE; break; @@ -1644,13 +1856,14 @@ lpfc_get_stats(struct Scsi_Host *shost) unsigned long seconds; int rc = 0; - /* prevent udev from issuing mailbox commands - * until the port is configured. - */ + /* + * prevent udev from issuing mailbox commands until the port is + * configured. + */ if (phba->link_state < LPFC_LINK_DOWN || !phba->mbox_mem_pool || (phba->sli.sli_flag & LPFC_SLI2_ACTIVE) == 0) - return NULL; + return NULL; if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) return NULL; @@ -1664,6 +1877,7 @@ lpfc_get_stats(struct Scsi_Host *shost) pmb->mbxCommand = MBX_READ_STATUS; pmb->mbxOwner = OWN_HOST; pmboxq->context1 = NULL; + pmboxq->vport = vport; if ((vport->fc_flag & FC_OFFLINE_MODE) || (!(psli->sli_flag & LPFC_SLI2_ACTIVE))) @@ -1690,6 +1904,7 @@ lpfc_get_stats(struct Scsi_Host *shost) pmb->mbxCommand = MBX_READ_LNK_STAT; pmb->mbxOwner = OWN_HOST; pmboxq->context1 = NULL; + pmboxq->vport = vport; if ((vport->fc_flag & FC_OFFLINE_MODE) || (!(psli->sli_flag & LPFC_SLI2_ACTIVE))) @@ -1701,7 +1916,7 @@ lpfc_get_stats(struct Scsi_Host *shost) if (rc == MBX_TIMEOUT) pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl; else - mempool_free( pmboxq, phba->mbox_mem_pool); + mempool_free(pmboxq, phba->mbox_mem_pool); return NULL; } @@ -1769,6 +1984,7 @@ lpfc_reset_stats(struct Scsi_Host *shost) pmb->mbxOwner = OWN_HOST; pmb->un.varWords[0] = 0x1; /* reset request */ pmboxq->context1 = NULL; + pmboxq->vport = vport; if ((vport->fc_flag & FC_OFFLINE_MODE) || (!(psli->sli_flag & LPFC_SLI2_ACTIVE))) @@ -1788,6 +2004,7 @@ lpfc_reset_stats(struct Scsi_Host *shost) pmb->mbxCommand = MBX_READ_LNK_STAT; pmb->mbxOwner = OWN_HOST; pmboxq->context1 = NULL; + pmboxq->vport = vport; if ((vport->fc_flag & FC_OFFLINE_MODE) || (!(psli->sli_flag & LPFC_SLI2_ACTIVE))) @@ -1950,6 +2167,69 @@ struct fc_function_template lpfc_transport_functions = { .issue_fc_host_lip = lpfc_issue_lip, .dev_loss_tmo_callbk = lpfc_dev_loss_tmo_callbk, .terminate_rport_io = lpfc_terminate_rport_io, + + .vport_create = lpfc_vport_create, + .vport_delete = lpfc_vport_delete, + .dd_fcvport_size = sizeof(struct lpfc_vport *), +}; + +struct fc_function_template lpfc_vport_transport_functions = { + /* fixed attributes the driver supports */ + .show_host_node_name = 1, + .show_host_port_name = 1, + .show_host_supported_classes = 1, + .show_host_supported_fc4s = 1, + .show_host_supported_speeds = 1, + .show_host_maxframe_size = 1, + + /* dynamic attributes the driver supports */ + .get_host_port_id = lpfc_get_host_port_id, + .show_host_port_id = 1, + + .get_host_port_type = lpfc_get_host_port_type, + .show_host_port_type = 1, + + .get_host_port_state = lpfc_get_host_port_state, + .show_host_port_state = 1, + + /* active_fc4s is shown but doesn't change (thus no get function) */ + .show_host_active_fc4s = 1, + + .get_host_speed = lpfc_get_host_speed, + .show_host_speed = 1, + + .get_host_fabric_name = lpfc_get_host_fabric_name, + .show_host_fabric_name = 1, + + /* + * The LPFC driver treats linkdown handling as target loss events + * so there are no sysfs handlers for link_down_tmo. + */ + + .get_fc_host_stats = lpfc_get_stats, + .reset_fc_host_stats = lpfc_reset_stats, + + .dd_fcrport_size = sizeof(struct lpfc_rport_data), + .show_rport_maxframe_size = 1, + .show_rport_supported_classes = 1, + + .set_rport_dev_loss_tmo = lpfc_set_rport_loss_tmo, + .show_rport_dev_loss_tmo = 1, + + .get_starget_port_id = lpfc_get_starget_port_id, + .show_starget_port_id = 1, + + .get_starget_node_name = lpfc_get_starget_node_name, + .show_starget_node_name = 1, + + .get_starget_port_name = lpfc_get_starget_port_name, + .show_starget_port_name = 1, + + .issue_fc_host_lip = lpfc_issue_lip, + .dev_loss_tmo_callbk = lpfc_dev_loss_tmo_callbk, + .terminate_rport_io = lpfc_terminate_rport_io, + + .vport_disable = lpfc_vport_disable, }; void @@ -1972,6 +2252,8 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) lpfc_discovery_threads_init(phba, lpfc_discovery_threads); lpfc_max_luns_init(phba, lpfc_max_luns); lpfc_poll_tmo_init(phba, lpfc_poll_tmo); + lpfc_peer_port_login_init(phba, lpfc_peer_port_login); + lpfc_vport_restrict_login_init(phba, lpfc_vport_restrict_login); lpfc_use_msi_init(phba, lpfc_use_msi); lpfc_devloss_tmo_init(phba, lpfc_devloss_tmo); lpfc_nodev_tmo_init(phba, lpfc_nodev_tmo); diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 77693072705..94e78819956 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -28,15 +28,18 @@ int lpfc_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, void lpfc_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_issue_clear_la(struct lpfc_hba *phba, struct lpfc_vport *vport); void lpfc_config_link(struct lpfc_hba *, LPFC_MBOXQ_t *); -int lpfc_read_sparam(struct lpfc_hba *, LPFC_MBOXQ_t *); +int lpfc_read_sparam(struct lpfc_hba *, LPFC_MBOXQ_t *, int); void lpfc_read_config(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_read_lnk_stat(struct lpfc_hba *, LPFC_MBOXQ_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 *); +int lpfc_reg_login(struct lpfc_hba *, uint16_t, uint32_t, uint8_t *, + LPFC_MBOXQ_t *, uint32_t); +void lpfc_unreg_login(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *); +void lpfc_unreg_did(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *); +void lpfc_reg_vpi(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *); +void lpfc_unreg_vpi(struct lpfc_hba *, uint16_t, LPFC_MBOXQ_t *); void lpfc_init_link(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t); +void lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove); int lpfc_linkdown(struct lpfc_hba *); void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *); @@ -51,6 +54,10 @@ void lpfc_drop_node(struct lpfc_vport *, struct lpfc_nodelist *); void lpfc_set_disctmo(struct lpfc_vport *); int lpfc_can_disctmo(struct lpfc_vport *); int lpfc_unreg_rpi(struct lpfc_vport *, struct lpfc_nodelist *); +void lpfc_unreg_all_rpis(struct lpfc_vport *); +void lpfc_unreg_default_rpis(struct lpfc_vport *); +void lpfc_issue_reg_vpi(struct lpfc_hba *, struct lpfc_vport *); + int lpfc_check_sli_ndlp(struct lpfc_hba *, struct lpfc_sli_ring *, struct lpfc_iocbq *, struct lpfc_nodelist *); void lpfc_nlp_init(struct lpfc_vport *, struct lpfc_nodelist *, uint32_t); @@ -60,25 +67,33 @@ struct lpfc_nodelist *lpfc_setup_disc_node(struct lpfc_vport *, uint32_t); void lpfc_disc_list_loopmap(struct lpfc_vport *); void lpfc_disc_start(struct lpfc_vport *); void lpfc_disc_flush_list(struct lpfc_vport *); +void lpfc_cleanup_discovery_resources(struct lpfc_vport *); void lpfc_disc_timeout(unsigned long); struct lpfc_nodelist *__lpfc_findnode_rpi(struct lpfc_vport *, uint16_t); struct lpfc_nodelist *lpfc_findnode_rpi(struct lpfc_vport *, uint16_t); +void lpfc_worker_wake_up(struct lpfc_hba *); int lpfc_workq_post_event(struct lpfc_hba *, void *, void *, uint32_t); int lpfc_do_work(void *); int lpfc_disc_state_machine(struct lpfc_vport *, struct lpfc_nodelist *, void *, uint32_t); +void lpfc_register_new_vport(struct lpfc_hba *, struct lpfc_vport *, + struct lpfc_nodelist *); +void lpfc_do_scr_ns_plogi(struct lpfc_hba *, struct lpfc_vport *); int lpfc_check_sparm(struct lpfc_vport *, struct lpfc_nodelist *, struct serv_parm *, uint32_t); -int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist * ndlp); +int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist *); int lpfc_els_abort_flogi(struct lpfc_hba *); int lpfc_initial_flogi(struct lpfc_vport *); +int lpfc_initial_fdisc(struct lpfc_vport *); +int lpfc_issue_els_fdisc(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t); int lpfc_issue_els_plogi(struct lpfc_vport *, uint32_t, uint8_t); int lpfc_issue_els_prli(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t); int lpfc_issue_els_adisc(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t); int lpfc_issue_els_logo(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t); +int lpfc_issue_els_npiv_logo(struct lpfc_vport *, struct lpfc_nodelist *); int lpfc_issue_els_scr(struct lpfc_vport *, uint32_t, uint8_t); int lpfc_els_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *); int lpfc_els_rsp_acc(struct lpfc_vport *, uint32_t, struct lpfc_iocbq *, @@ -95,7 +110,7 @@ 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_vport *); -int lpfc_els_flush_rscn(struct lpfc_vport *); +void lpfc_els_flush_rscn(struct lpfc_vport *); int lpfc_rscn_payload_check(struct lpfc_vport *, uint32_t); void lpfc_els_flush_cmd(struct lpfc_vport *); int lpfc_els_disc_adisc(struct lpfc_vport *); @@ -105,7 +120,7 @@ void lpfc_els_timeout_handler(struct lpfc_vport *); void lpfc_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *, struct lpfc_iocbq *); -int lpfc_ns_cmd(struct lpfc_vport *, struct lpfc_nodelist *, int); +int lpfc_ns_cmd(struct lpfc_vport *, int, uint8_t, uint32_t); int lpfc_fdmi_cmd(struct lpfc_vport *, struct lpfc_nodelist *, int); void lpfc_fdmi_tmo(unsigned long); void lpfc_fdmi_timeout_handler(struct lpfc_vport *vport); @@ -136,6 +151,7 @@ void lpfc_config_port(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_kill_board(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 *); +void lpfc_mbox_cmpl_put(struct lpfc_hba *, LPFC_MBOXQ_t *); int lpfc_mbox_tmo_val(struct lpfc_hba *, int); void lpfc_config_hbq(struct lpfc_hba *, struct lpfc_hbq_init *, uint32_t , @@ -144,6 +160,7 @@ struct lpfc_hbq_entry * lpfc_sli_next_hbq_slot(struct lpfc_hba *, uint32_t); int lpfc_mem_alloc(struct lpfc_hba *); void lpfc_mem_free(struct lpfc_hba *); +void lpfc_stop_vport_timers(struct lpfc_vport *); void lpfc_poll_timeout(unsigned long ptr); void lpfc_poll_start_timer(struct lpfc_hba * phba); @@ -176,11 +193,10 @@ int lpfc_sli_ringpostbuf_put(struct lpfc_hba *, struct lpfc_sli_ring *, struct lpfc_dmabuf *lpfc_sli_ringpostbuf_get(struct lpfc_hba *, struct lpfc_sli_ring *, dma_addr_t); -int lpfc_sli_hbqbuf_fill_hbq(struct lpfc_hba *); -void lpfc_sli_hbqbuf_free(struct lpfc_hba *, void *, dma_addr_t); +int lpfc_sli_hbqbuf_init_hbqs(struct lpfc_hba *, uint32_t); +int lpfc_sli_hbqbuf_add_hbqs(struct lpfc_hba *, uint32_t); void lpfc_sli_hbqbuf_free_all(struct lpfc_hba *); struct hbq_dmabuf *lpfc_sli_hbqbuf_find(struct lpfc_hba *, uint32_t); -void lpfc_sli_free_hbq(struct lpfc_hba *, struct hbq_dmabuf *); int lpfc_sli_hbq_size(void); int lpfc_sli_issue_abort_iotag(struct lpfc_hba *, struct lpfc_sli_ring *, struct lpfc_iocbq *); @@ -192,12 +208,15 @@ int lpfc_sli_abort_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, uint16_t, void lpfc_mbox_timeout(unsigned long); void lpfc_mbox_timeout_handler(struct lpfc_hba *); +struct lpfc_nodelist *__lpfc_find_node(struct lpfc_vport *, node_filter, + void *); +struct lpfc_nodelist *lpfc_find_node(struct lpfc_vport *, node_filter, void *); struct lpfc_nodelist *lpfc_findnode_did(struct lpfc_vport *, uint32_t); struct lpfc_nodelist *lpfc_findnode_wwpn(struct lpfc_vport *, struct lpfc_name *); int lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq, - uint32_t timeout); + uint32_t timeout); int lpfc_sli_issue_iocb_wait(struct lpfc_hba * phba, struct lpfc_sli_ring * pring, @@ -210,11 +229,13 @@ void lpfc_sli_abort_fcp_cmpl(struct lpfc_hba * phba, void *lpfc_hbq_alloc(struct lpfc_hba *, int, dma_addr_t *); void lpfc_hbq_free(struct lpfc_hba *, void *, dma_addr_t); +void lpfc_sli_free_hbq(struct lpfc_hba *, struct hbq_dmabuf *); void *lpfc_mbuf_alloc(struct lpfc_hba *, int, dma_addr_t *); void __lpfc_mbuf_free(struct lpfc_hba *, void *, dma_addr_t); void lpfc_mbuf_free(struct lpfc_hba *, void *, dma_addr_t); +void lpfc_in_buf_free(struct lpfc_hba *, struct lpfc_dmabuf *); /* Function prototypes. */ const char* lpfc_info(struct Scsi_Host *); void lpfc_scan_start(struct Scsi_Host *); @@ -226,14 +247,34 @@ void lpfc_free_sysfs_attr(struct lpfc_vport *); extern struct class_device_attribute *lpfc_hba_attrs[]; extern struct scsi_host_template lpfc_template; extern struct fc_function_template lpfc_transport_functions; +extern struct fc_function_template lpfc_vport_transport_functions; extern int lpfc_sli_mode; +extern int lpfc_npiv_enable; -void lpfc_get_hba_sym_node_name(struct lpfc_hba *phba, uint8_t *symbp); +int lpfc_vport_symbolic_node_name(struct lpfc_vport *, char *, size_t); void lpfc_terminate_rport_io(struct fc_rport *); void lpfc_dev_loss_tmo_callbk(struct fc_rport *rport); -struct lpfc_vport *lpfc_create_port(struct lpfc_hba *, int); -void lpfc_post_hba_setup_vport_init(struct lpfc_vport *); +struct lpfc_vport *lpfc_create_port(struct lpfc_hba *, int, struct fc_vport *); +int lpfc_vport_disable(struct fc_vport *fc_vport, bool disable); +void lpfc_mbx_unreg_vpi(struct lpfc_vport *); void destroy_port(struct lpfc_vport *); +int lpfc_get_instance(void); +void lpfc_host_attrib_init(struct Scsi_Host *); + +/* Interface exported by fabric iocb scheduler */ +int lpfc_issue_fabric_iocb(struct lpfc_hba *, struct lpfc_iocbq *); +void lpfc_fabric_abort_vport(struct lpfc_vport *); +void lpfc_fabric_abort_nport(struct lpfc_nodelist *); +void lpfc_fabric_abort_hba(struct lpfc_hba *); +void lpfc_fabric_abort_flogi(struct lpfc_hba *); +void lpfc_fabric_block_timeout(unsigned long); +void lpfc_unblock_fabric_iocbs(struct lpfc_hba *); +void lpfc_adjust_queue_depth(struct lpfc_hba *); +void lpfc_ramp_down_queue_handler(struct lpfc_hba *); +void lpfc_ramp_up_queue_handler(struct lpfc_hba *); #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 diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index e8ed5d7ccf9..5584f395314 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -40,6 +40,7 @@ #include "lpfc_logmsg.h" #include "lpfc_crtn.h" #include "lpfc_version.h" +#include "lpfc_vport.h" #define HBA_PORTSPEED_UNKNOWN 0 /* Unknown - transceiver * incapable of reporting */ @@ -74,15 +75,13 @@ lpfc_ct_unsol_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, __FUNCTION__, __LINE__, piocbq, mp, size, piocbq->iocb.ulpStatus); + } static void lpfc_ct_ignore_hbq_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, - struct hbq_dmabuf *sp, uint32_t size) + struct lpfc_dmabuf *mp, uint32_t size) { - struct lpfc_dmabuf *mp = NULL; - - mp = sp ? &sp->dbuf : NULL; if (!mp) { printk(KERN_ERR "%s (%d): Unsolited CT, no " "HBQ buffer, piocbq = %p, status = x%x\n", @@ -102,21 +101,26 @@ void lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_iocbq *piocbq) { + struct lpfc_dmabuf *mp = NULL; - struct hbq_dmabuf *sp = NULL; IOCB_t *icmd = &piocbq->iocb; int i; struct lpfc_iocbq *iocbq; dma_addr_t paddr; uint32_t size; + struct lpfc_dmabuf *bdeBuf1 = piocbq->context2; + struct lpfc_dmabuf *bdeBuf2 = piocbq->context3; + + piocbq->context2 = NULL; + piocbq->context3 = NULL; - if ((icmd->ulpStatus == IOSTAT_LOCAL_REJECT) && - ((icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING)) { + if (unlikely(icmd->ulpStatus == IOSTAT_NEED_BUFFER)) { + lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ); + } else if ((icmd->ulpStatus == IOSTAT_LOCAL_REJECT) && + ((icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING)) { /* Not enough posted buffers; Try posting more buffers */ phba->fc_stat.NoRcvBuf++; - if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) - lpfc_sli_hbqbuf_fill_hbq(phba); - else + if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) lpfc_post_buffer(phba, pring, 0, 1); return; } @@ -139,23 +143,14 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, } size = icmd->un.cont64[0].tus.f.bdeSize; - sp = lpfc_sli_hbqbuf_find(phba, icmd->un.ulpWord[3]); - if (sp) - phba->hbq_buff_count--; - lpfc_ct_ignore_hbq_buffer(phba, iocbq, sp, size); - lpfc_sli_free_hbq(phba, sp); + lpfc_ct_ignore_hbq_buffer(phba, piocbq, bdeBuf1, size); + lpfc_in_buf_free(phba, bdeBuf1); if (icmd->ulpBdeCount == 2) { - sp = lpfc_sli_hbqbuf_find(phba, - icmd->un.ulpWord[15]); - if (sp) - phba->hbq_buff_count--; - lpfc_ct_ignore_hbq_buffer(phba, iocbq, sp, + lpfc_ct_ignore_hbq_buffer(phba, piocbq, bdeBuf2, size); - lpfc_sli_free_hbq(phba, sp); + lpfc_in_buf_free(phba, bdeBuf2); } - } - lpfc_sli_hbqbuf_fill_hbq(phba); } else { struct lpfc_iocbq *next; @@ -176,8 +171,7 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, paddr); size = icmd->un.cont64[i].tus.f.bdeSize; lpfc_ct_unsol_buffer(phba, piocbq, mp, size); - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); + lpfc_in_buf_free(phba, mp); } list_del(&iocbq->list); lpfc_sli_release_iocbq(phba, iocbq); @@ -222,7 +216,8 @@ lpfc_alloc_ct_rsp(struct lpfc_hba *phba, int cmdcode, struct ulp_bde64 *bpl, INIT_LIST_HEAD(&mp->list); - if (cmdcode == be16_to_cpu(SLI_CTNS_GID_FT)) + if (cmdcode == be16_to_cpu(SLI_CTNS_GID_FT) || + cmdcode == be16_to_cpu(SLI_CTNS_GFF_ID)) mp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(mp->phys)); else mp->virt = lpfc_mbuf_alloc(phba, 0, &(mp->phys)); @@ -242,8 +237,8 @@ lpfc_alloc_ct_rsp(struct lpfc_hba *phba, int cmdcode, struct ulp_bde64 *bpl, bpl->tus.f.bdeFlags = BUFF_USE_RCV; /* build buffer ptr list for IOCB */ - bpl->addrLow = le32_to_cpu( putPaddrLow(mp->phys) ); - bpl->addrHigh = le32_to_cpu( putPaddrHigh(mp->phys) ); + bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys) ); + bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys) ); bpl->tus.f.bdeSize = (uint16_t) cnt; bpl->tus.w = le32_to_cpu(bpl->tus.w); bpl++; @@ -262,13 +257,14 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp, void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *, struct lpfc_iocbq *), struct lpfc_nodelist *ndlp, uint32_t usr_flg, uint32_t num_entry, - uint32_t tmo) + uint32_t tmo, uint8_t retry) { struct lpfc_hba *phba = vport->phba; struct lpfc_sli *psli = &phba->sli; struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING]; IOCB_t *icmd; struct lpfc_iocbq *geniocb; + int rc; /* Allocate buffer for command iocb */ geniocb = lpfc_sli_get_iocbq(phba); @@ -311,15 +307,25 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp, icmd->ulpClass = CLASS3; icmd->ulpContext = ndlp->nlp_rpi; + if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) { + /* For GEN_REQUEST64_CR, use the RPI */ + icmd->ulpCt_h = 0; + icmd->ulpCt_l = 0; + } + /* Issue GEN REQ IOCB for NPORT */ lpfc_printf_log(phba, KERN_INFO, LOG_ELS, - "%d:0119 Issue GEN REQ IOCB for NPORT x%x " - "Data: x%x x%x\n", phba->brd_no, icmd->un.ulpWord[5], - icmd->ulpIoTag, vport->port_state); + "%d (%d):0119 Issue GEN REQ IOCB to NPORT x%x " + "Data: x%x x%x\n", phba->brd_no, vport->vpi, + ndlp->nlp_DID, icmd->ulpIoTag, + vport->port_state); geniocb->iocb_cmpl = cmpl; geniocb->drvrTimeout = icmd->ulpTimeout + LPFC_DRVR_TIMEOUT; geniocb->vport = vport; - if (lpfc_sli_issue_iocb(phba, pring, geniocb, 0) == IOCB_ERROR) { + geniocb->retry = retry; + rc = lpfc_sli_issue_iocb(phba, pring, geniocb, 0); + + if (rc == IOCB_ERROR) { lpfc_sli_release_iocbq(phba, geniocb); return 1; } @@ -332,7 +338,7 @@ lpfc_ct_cmd(struct lpfc_vport *vport, struct lpfc_dmabuf *inmp, struct lpfc_dmabuf *bmp, struct lpfc_nodelist *ndlp, void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *, struct lpfc_iocbq *), - uint32_t rsp_size) + uint32_t rsp_size, uint8_t retry) { struct lpfc_hba *phba = vport->phba; struct ulp_bde64 *bpl = (struct ulp_bde64 *) bmp->virt; @@ -349,7 +355,7 @@ lpfc_ct_cmd(struct lpfc_vport *vport, struct lpfc_dmabuf *inmp, return -ENOMEM; status = lpfc_gen_req(vport, bmp, inmp, outmp, cmpl, ndlp, 0, - cnt+1, 0); + cnt+1, 0, retry); if (status) { lpfc_free_ct_rsp(phba, outmp); return -ENOMEM; @@ -357,10 +363,23 @@ lpfc_ct_cmd(struct lpfc_vport *vport, struct lpfc_dmabuf *inmp, return 0; } +static struct lpfc_vport * +lpfc_find_vport_by_did(struct lpfc_hba *phba, uint32_t did) { + + struct lpfc_vport *vport_curr; + + list_for_each_entry(vport_curr, &phba->port_list, listentry) { + if ((vport_curr->fc_myDID) && + (vport_curr->fc_myDID == did)) + return vport_curr; + } + + return NULL; +} + static int lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; struct lpfc_sli_ct_request *Response = (struct lpfc_sli_ct_request *) mp->virt; @@ -372,6 +391,7 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size) struct list_head head; lpfc_set_disctmo(vport); + vport->num_disc_nodes = 0; list_add_tail(&head, &mp->list); @@ -392,25 +412,64 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size) /* Get next DID from NameServer List */ CTentry = *ctptr++; Did = ((be32_to_cpu(CTentry)) & Mask_DID); + ndlp = NULL; - /* Check for rscn processing or not */ - if (Did != vport->fc_myDID) - ndlp = lpfc_setup_disc_node(vport, Did); - if (ndlp) { - lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, - "%d:0238 Process x%x NameServer" - " Rsp Data: x%x x%x x%x\n", - phba->brd_no, - Did, ndlp->nlp_flag, - vport->fc_flag, - vport->fc_rscn_id_cnt); - } else { - lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, - "%d:0239 Skip x%x NameServer " - "Rsp Data: x%x x%x x%x\n", - phba->brd_no, - Did, Size, vport->fc_flag, - vport->fc_rscn_id_cnt); + + /* + * Check for rscn processing or not + * To conserve rpi's, filter out addresses for other + * vports on the same physical HBAs. + */ + if ((Did != vport->fc_myDID) && + ((lpfc_find_vport_by_did(phba, Did) == NULL) || + phba->cfg_peer_port_login)) { + if ((vport->port_type != LPFC_NPIV_PORT) || + (vport->fc_flag & FC_RFF_NOT_SUPPORTED) || + (!phba->cfg_vport_restrict_login)) { + ndlp = lpfc_setup_disc_node(vport, Did); + if (ndlp) { + lpfc_printf_log(phba, KERN_INFO, + LOG_DISCOVERY, + "%d (%d):0238 Process " + "x%x NameServer Rsp" + "Data: x%x x%x x%x\n", + phba->brd_no, + vport->vpi, Did, + ndlp->nlp_flag, + vport->fc_flag, + vport->fc_rscn_id_cnt); + } else { + lpfc_printf_log(phba, KERN_INFO, + LOG_DISCOVERY, + "%d (%d):0239 Skip x%x " + "NameServer Rsp Data: " + "x%x x%x\n", + phba->brd_no, + vport->vpi, Did, + vport->fc_flag, + vport->fc_rscn_id_cnt); + } + + } else { + if (!(vport->fc_flag & FC_RSCN_MODE) || + (lpfc_rscn_payload_check(vport, Did))) { + if (lpfc_ns_cmd(vport, + SLI_CTNS_GFF_ID, + 0, Did) == 0) + vport->num_disc_nodes++; + } + else { + lpfc_printf_log(phba, KERN_INFO, + LOG_DISCOVERY, + "%d (%d):0245 Skip x%x " + "NameServer Rsp Data: " + "x%x x%x\n", + phba->brd_no, + vport->vpi, Did, + vport->fc_flag, + vport->fc_rscn_id_cnt); + } + } } if (CTentry & (be32_to_cpu(SLI_CT_LAST_ENTRY))) goto nsout1; @@ -422,34 +481,19 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size) nsout1: list_del(&head); - - /* - * The driver has cycled through all Nports in the RSCN payload. - * Complete the handling by cleaning up and marking the - * current driver state. - */ - if (vport->port_state == LPFC_VPORT_READY) { - lpfc_els_flush_rscn(vport); - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_RSCN_MODE; /* we are still in RSCN mode */ - spin_unlock_irq(shost->host_lock); - } return 0; } - - - static void lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { struct lpfc_vport *vport = cmdiocb->vport; + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); IOCB_t *irsp; struct lpfc_dmabuf *bmp; struct lpfc_dmabuf *inp; struct lpfc_dmabuf *outp; - struct lpfc_nodelist *ndlp; struct lpfc_sli_ct_request *CTrsp; int rc; @@ -460,33 +504,41 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, outp = (struct lpfc_dmabuf *) cmdiocb->context2; bmp = (struct lpfc_dmabuf *) cmdiocb->context3; + /* Don't bother processing response if vport is being torn down. */ + if (vport->load_flag & FC_UNLOADING) + goto out; + irsp = &rspiocb->iocb; if (irsp->ulpStatus) { if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) && ((irsp->un.ulpWord[4] == IOERR_SLI_DOWN) || (irsp->un.ulpWord[4] == IOERR_SLI_ABORTED))) - goto out; + goto err1; /* Check for retry */ if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) { vport->fc_ns_retry++; /* CT command is being retried */ - ndlp = lpfc_findnode_did(vport, NameServer_DID); - if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { - rc = lpfc_ns_cmd(vport, ndlp, SLI_CTNS_GID_FT); - if (rc == 0) - goto out; - } - } + rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, + vport->fc_ns_retry, 0); + if (rc == 0) + goto out; + } +err1: + lpfc_vport_set_state(vport, FC_VPORT_FAILED); + lpfc_printf_log(phba, KERN_ERR, LOG_ELS, + "%d (%d):0257 GID_FT Query error: 0x%x 0x%x\n", + phba->brd_no, vport->vpi, irsp->ulpStatus, + vport->fc_ns_retry); } else { /* Good status, continue checking */ CTrsp = (struct lpfc_sli_ct_request *) outp->virt; if (CTrsp->CommandResponse.bits.CmdRsp == be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) { lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, - "%d:0208 NameServer Rsp " + "%d (%d):0208 NameServer Rsp " "Data: x%x\n", - phba->brd_no, + phba->brd_no, vport->vpi, vport->fc_flag); lpfc_ns_rsp(vport, outp, (uint32_t) (irsp->un.genreq64.bdl.bdeSize)); @@ -494,21 +546,19 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) { /* NameServer Rsp Error */ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, - "%d:0240 NameServer Rsp Error " + "%d (%d):0240 NameServer Rsp Error " "Data: x%x x%x x%x x%x\n", - phba->brd_no, + phba->brd_no, vport->vpi, CTrsp->CommandResponse.bits.CmdRsp, (uint32_t) CTrsp->ReasonCode, (uint32_t) CTrsp->Explanation, vport->fc_flag); } else { /* NameServer Rsp Error */ - lpfc_printf_log(phba, - KERN_INFO, - LOG_DISCOVERY, - "%d:0241 NameServer Rsp Error " + lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, + "%d (%d):0241 NameServer Rsp Error " "Data: x%x x%x x%x x%x\n", - phba->brd_no, + phba->brd_no, vport->vpi, CTrsp->CommandResponse.bits.CmdRsp, (uint32_t) CTrsp->ReasonCode, (uint32_t) CTrsp->Explanation, @@ -516,8 +566,111 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } } /* Link up / RSCN discovery */ - lpfc_disc_start(vport); + if (vport->num_disc_nodes == 0) { + /* + * The driver has cycled through all Nports in the RSCN payload. + * Complete the handling by cleaning up and marking the + * current driver state. + */ + if (vport->port_state >= LPFC_DISC_AUTH) { + if (vport->fc_flag & FC_RSCN_MODE) { + lpfc_els_flush_rscn(vport); + spin_lock_irq(shost->host_lock); + vport->fc_flag |= FC_RSCN_MODE; /* RSCN still */ + spin_unlock_irq(shost->host_lock); + } + else + lpfc_els_flush_rscn(vport); + } + + lpfc_disc_start(vport); + } +out: + lpfc_free_ct_rsp(phba, outp); + lpfc_mbuf_free(phba, inp->virt, inp->phys); + lpfc_mbuf_free(phba, bmp->virt, bmp->phys); + kfree(inp); + kfree(bmp); + lpfc_sli_release_iocbq(phba, cmdiocb); + return; +} + +void +lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +{ + struct lpfc_vport *vport = cmdiocb->vport; + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + IOCB_t *irsp = &rspiocb->iocb; + struct lpfc_dmabuf *bmp = (struct lpfc_dmabuf *) cmdiocb->context3; + struct lpfc_dmabuf *inp = (struct lpfc_dmabuf *) cmdiocb->context1; + struct lpfc_dmabuf *outp = (struct lpfc_dmabuf *) cmdiocb->context2; + struct lpfc_sli_ct_request *CTrsp; + int did; + uint8_t fbits; + struct lpfc_nodelist *ndlp; + + did = ((struct lpfc_sli_ct_request *) inp->virt)->un.gff.PortId; + did = be32_to_cpu(did); + + if (irsp->ulpStatus == IOSTAT_SUCCESS) { + /* Good status, continue checking */ + CTrsp = (struct lpfc_sli_ct_request *) outp->virt; + fbits = CTrsp->un.gff_acc.fbits[FCP_TYPE_FEATURE_OFFSET]; + + if (CTrsp->CommandResponse.bits.CmdRsp == + be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) { + if ((fbits & FC4_FEATURE_INIT) && + !(fbits & FC4_FEATURE_TARGET)) { + lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, + "%d (%d):0245 Skip x%x GFF " + "NameServer Rsp Data: (init) " + "x%x x%x\n", phba->brd_no, + vport->vpi, did, fbits, + vport->fc_rscn_id_cnt); + goto out; + } + } + } + /* This is a target port, unregistered port, or the GFF_ID failed */ + ndlp = lpfc_setup_disc_node(vport, did); + if (ndlp) { + lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, + "%d (%d):0242 Process x%x GFF " + "NameServer Rsp Data: x%x x%x x%x\n", + phba->brd_no, vport->vpi, + did, ndlp->nlp_flag, vport->fc_flag, + vport->fc_rscn_id_cnt); + } else { + lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, + "%d (%d):0243 Skip x%x GFF " + "NameServer Rsp Data: x%x x%x\n", + phba->brd_no, vport->vpi, did, + vport->fc_flag, vport->fc_rscn_id_cnt); + } out: + /* Link up / RSCN discovery */ + if (vport->num_disc_nodes) + vport->num_disc_nodes--; + if (vport->num_disc_nodes == 0) { + /* + * The driver has cycled through all Nports in the RSCN payload. + * Complete the handling by cleaning up and marking the + * current driver state. + */ + if (vport->port_state >= LPFC_DISC_AUTH) { + if (vport->fc_flag & FC_RSCN_MODE) { + lpfc_els_flush_rscn(vport); + spin_lock_irq(shost->host_lock); + vport->fc_flag |= FC_RSCN_MODE; /* RSCN still */ + spin_unlock_irq(shost->host_lock); + } + else + lpfc_els_flush_rscn(vport); + } + lpfc_disc_start(vport); + } + lpfc_free_ct_rsp(phba, outp); lpfc_mbuf_free(phba, inp->virt, inp->phys); lpfc_mbuf_free(phba, bmp->virt, bmp->phys); @@ -527,15 +680,19 @@ out: return; } + static void lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { + struct lpfc_vport *vport = cmdiocb->vport; struct lpfc_dmabuf *bmp; struct lpfc_dmabuf *inp; struct lpfc_dmabuf *outp; IOCB_t *irsp; struct lpfc_sli_ct_request *CTrsp; + int cmdcode, rc; + uint8_t retry; /* we pass cmdiocb to state machine which needs rspiocb as well */ cmdiocb->context_un.rsp_iocb = rspiocb; @@ -545,16 +702,40 @@ lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, bmp = (struct lpfc_dmabuf *) cmdiocb->context3; irsp = &rspiocb->iocb; + cmdcode = be16_to_cpu(((struct lpfc_sli_ct_request *) inp->virt)-> + CommandResponse.bits.CmdRsp); CTrsp = (struct lpfc_sli_ct_request *) outp->virt; - /* RFT request completes status CmdRsp */ + /* NS request completes status CmdRsp */ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, - "%d:0209 RFT request completes ulpStatus x%x " + "%d (%d):0209 NS request %x completes " + "ulpStatus x%x / x%x " "CmdRsp x%x, Context x%x, Tag x%x\n", - phba->brd_no, irsp->ulpStatus, + phba->brd_no, vport->vpi, + cmdcode, irsp->ulpStatus, irsp->un.ulpWord[4], CTrsp->CommandResponse.bits.CmdRsp, cmdiocb->iocb.ulpContext, cmdiocb->iocb.ulpIoTag); + if (irsp->ulpStatus) { + if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) && + ((irsp->un.ulpWord[4] == IOERR_SLI_DOWN) || + (irsp->un.ulpWord[4] == IOERR_SLI_ABORTED))) + goto out; + + retry = cmdiocb->retry; + if (retry >= LPFC_MAX_NS_RETRY) + goto out; + + retry++; + lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, + "%d (%d):0216 Retrying NS cmd %x\n", + phba->brd_no, vport->vpi, cmdcode); + rc = lpfc_ns_cmd(vport, cmdcode, retry, 0); + if (rc == 0) + goto out; + } + +out: lpfc_free_ct_rsp(phba, outp); lpfc_mbuf_free(phba, inp->virt, inp->phys); lpfc_mbuf_free(phba, bmp->virt, bmp->phys); @@ -572,6 +753,14 @@ lpfc_cmpl_ct_cmd_rnn_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, return; } +static void +lpfc_cmpl_ct_cmd_rspn_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +{ + lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb); + return; +} + static void lpfc_cmpl_ct_cmd_rsnn_nn(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) @@ -581,23 +770,54 @@ lpfc_cmpl_ct_cmd_rsnn_nn(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } static void -lpfc_cmpl_ct_cmd_rff_id(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, - struct lpfc_iocbq * rspiocb) +lpfc_cmpl_ct_cmd_rff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) { + IOCB_t *irsp = &rspiocb->iocb; + struct lpfc_vport *vport = cmdiocb->vport; + + if (irsp->ulpStatus != IOSTAT_SUCCESS) + vport->fc_flag |= FC_RFF_NOT_SUPPORTED; + lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb); return; } -void -lpfc_get_hba_sym_node_name(struct lpfc_hba *phba, uint8_t *symbp) +int +lpfc_vport_symbolic_port_name(struct lpfc_vport *vport, char *symbol, + size_t size) +{ + int n; + uint8_t *wwn = vport->phba->wwpn; + + n = snprintf(symbol, size, + "Emulex PPN-%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", + wwn[0], wwn[1], wwn[2], wwn[3], + wwn[4], wwn[5], wwn[6], wwn[7]); + + if (vport->port_type == LPFC_PHYSICAL_PORT) + return n; + + if (n < size) + n += snprintf(symbol + n, size - n, " VPort-%d", vport->vpi); + + if (n < size && vport->vname) + n += snprintf(symbol + n, size - n, " VName-%s", vport->vname); + return n; +} + +int +lpfc_vport_symbolic_node_name(struct lpfc_vport *vport, char *symbol, + size_t size) { char fwrev[16]; + int n; - lpfc_decode_firmware_rev(phba, fwrev, 0); + lpfc_decode_firmware_rev(vport->phba, fwrev, 0); - sprintf(symbp, "Emulex %s FV%s DV%s", phba->ModelName, - fwrev, lpfc_release_version); - return; + n = snprintf(symbol, size, "Emulex %s FV%s DV%s", + vport->phba->ModelName, fwrev, lpfc_release_version); + return n; } /* @@ -608,8 +828,10 @@ lpfc_get_hba_sym_node_name(struct lpfc_hba *phba, uint8_t *symbp) * LI_CTNS_RFT_ID */ int -lpfc_ns_cmd(struct lpfc_vport *vport, struct lpfc_nodelist * ndlp, int cmdcode) +lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, + uint8_t retry, uint32_t context) { + struct lpfc_nodelist * ndlp; struct lpfc_hba *phba = vport->phba; struct lpfc_dmabuf *mp, *bmp; struct lpfc_sli_ct_request *CtReq; @@ -617,6 +839,11 @@ lpfc_ns_cmd(struct lpfc_vport *vport, struct lpfc_nodelist * ndlp, int cmdcode) void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *, struct lpfc_iocbq *) = NULL; uint32_t rsp_size = 1024; + size_t size; + + ndlp = lpfc_findnode_did(vport, NameServer_DID); + if (ndlp == NULL || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) + return 1; /* fill in BDEs for command */ /* Allocate buffer for command payload */ @@ -640,24 +867,26 @@ lpfc_ns_cmd(struct lpfc_vport *vport, struct lpfc_nodelist * ndlp, int cmdcode) goto ns_cmd_free_bmp; /* NameServer Req */ - lpfc_printf_log(phba, - KERN_INFO, - LOG_DISCOVERY, - "%d:0236 NameServer Req Data: x%x x%x x%x\n", - phba->brd_no, cmdcode, vport->fc_flag, + lpfc_printf_log(phba, KERN_INFO ,LOG_DISCOVERY, + "%d (%d):0236 NameServer Req Data: x%x x%x x%x\n", + phba->brd_no, vport->vpi, cmdcode, vport->fc_flag, vport->fc_rscn_id_cnt); bpl = (struct ulp_bde64 *) bmp->virt; memset(bpl, 0, sizeof(struct ulp_bde64)); - bpl->addrHigh = le32_to_cpu( putPaddrHigh(mp->phys) ); - bpl->addrLow = le32_to_cpu( putPaddrLow(mp->phys) ); + bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys) ); + bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys) ); bpl->tus.f.bdeFlags = 0; if (cmdcode == SLI_CTNS_GID_FT) bpl->tus.f.bdeSize = GID_REQUEST_SZ; + else if (cmdcode == SLI_CTNS_GFF_ID) + bpl->tus.f.bdeSize = GFF_REQUEST_SZ; else if (cmdcode == SLI_CTNS_RFT_ID) bpl->tus.f.bdeSize = RFT_REQUEST_SZ; else if (cmdcode == SLI_CTNS_RNN_ID) bpl->tus.f.bdeSize = RNN_REQUEST_SZ; + else if (cmdcode == SLI_CTNS_RSPN_ID) + bpl->tus.f.bdeSize = RSPN_REQUEST_SZ; else if (cmdcode == SLI_CTNS_RSNN_NN) bpl->tus.f.bdeSize = RSNN_REQUEST_SZ; else if (cmdcode == SLI_CTNS_RFF_ID) @@ -678,13 +907,20 @@ lpfc_ns_cmd(struct lpfc_vport *vport, struct lpfc_nodelist * ndlp, int cmdcode) CtReq->CommandResponse.bits.CmdRsp = be16_to_cpu(SLI_CTNS_GI