浏览代码

[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 <James.Smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
James Smart 18 年之前
父节点
当前提交
92d7f7b0cd

+ 3 - 2
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

+ 111 - 45
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 */
 

+ 295 - 13
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);

+ 56 - 15
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

+ 386 - 134
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 <did> */
 	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 <ulpStatus> CmdRsp <CmdRsp> */
+	/* NS request completes status <ulpStatus> CmdRsp <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_GID_FT);
 		CtReq->un.gid.Fc4Type = SLI_CTPT_FCP;
-		if (vport->port_state < LPFC_VPORT_READY)
+		if (vport->port_state < LPFC_NS_QRY)
 			vport->port_state = LPFC_NS_QRY;
 		lpfc_set_disctmo(vport);
 		cmpl = lpfc_cmpl_ct_cmd_gid_ft;
 		rsp_size = FC_MAX_NS_RSP;
 		break;
 
+	case SLI_CTNS_GFF_ID:
+		CtReq->CommandResponse.bits.CmdRsp =
+			be16_to_cpu(SLI_CTNS_GFF_ID);
+		CtReq->un.gff.PortId = be32_to_cpu(context);
+		cmpl = lpfc_cmpl_ct_cmd_gff_id;
+		break;
+
 	case SLI_CTNS_RFT_ID:
 		CtReq->CommandResponse.bits.CmdRsp =
 		    be16_to_cpu(SLI_CTNS_RFT_ID);
@@ -693,17 +929,6 @@ lpfc_ns_cmd(struct lpfc_vport *vport, struct lpfc_nodelist * ndlp, int cmdcode)
 		cmpl = lpfc_cmpl_ct_cmd_rft_id;
 		break;
 
-	case SLI_CTNS_RFF_ID:
-		CtReq->CommandResponse.bits.CmdRsp =
-			be16_to_cpu(SLI_CTNS_RFF_ID);
-		CtReq->un.rff.PortId = be32_to_cpu(vport->fc_myDID);
-		CtReq->un.rff.feature_res = 0;
-		CtReq->un.rff.feature_tgt = 0;
-		CtReq->un.rff.type_code = FC_FCP_DATA;
-		CtReq->un.rff.feature_init = 1;
-		cmpl = lpfc_cmpl_ct_cmd_rff_id;
-		break;
-
 	case SLI_CTNS_RNN_ID:
 		CtReq->CommandResponse.bits.CmdRsp =
 		    be16_to_cpu(SLI_CTNS_RNN_ID);
@@ -713,18 +938,39 @@ lpfc_ns_cmd(struct lpfc_vport *vport, struct lpfc_nodelist * ndlp, int cmdcode)
 		cmpl = lpfc_cmpl_ct_cmd_rnn_id;
 		break;
 
+	case SLI_CTNS_RSPN_ID:
+		CtReq->CommandResponse.bits.CmdRsp =
+		    be16_to_cpu(SLI_CTNS_RSPN_ID);
+		CtReq->un.rspn.PortId = be32_to_cpu(vport->fc_myDID);
+		size = sizeof(CtReq->un.rspn.symbname);
+		CtReq->un.rspn.len =
+			lpfc_vport_symbolic_port_name(vport,
+			CtReq->un.rspn.symbname, size);
+		cmpl = lpfc_cmpl_ct_cmd_rspn_id;
+		break;
 	case SLI_CTNS_RSNN_NN:
 		CtReq->CommandResponse.bits.CmdRsp =
 		    be16_to_cpu(SLI_CTNS_RSNN_NN);
 		memcpy(CtReq->un.rsnn.wwnn, &vport->fc_nodename,
 		       sizeof (struct lpfc_name));
-		lpfc_get_hba_sym_node_name(phba, CtReq->un.rsnn.symbname);
-		CtReq->un.rsnn.len = strlen(CtReq->un.rsnn.symbname);
+		size = sizeof(CtReq->un.rsnn.symbname);
+		CtReq->un.rsnn.len =
+			lpfc_vport_symbolic_node_name(vport,
+			CtReq->un.rsnn.symbname, size);
 		cmpl = lpfc_cmpl_ct_cmd_rsnn_nn;
 		break;
+	case SLI_CTNS_RFF_ID:
+		vport->fc_flag &= ~FC_RFF_NOT_SUPPORTED;
+		CtReq->CommandResponse.bits.CmdRsp =
+		    be16_to_cpu(SLI_CTNS_RFF_ID);
+		CtReq->un.rff.PortId = be32_to_cpu(vport->fc_myDID);;
+		CtReq->un.rff.fbits = FC4_FEATURE_INIT;
+		CtReq->un.rff.type_code = FC_FCP_DATA;
+		cmpl = lpfc_cmpl_ct_cmd_rff_id;
+		break;
 	}
 
-	if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, rsp_size))
+	if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, rsp_size, retry))
 		/* On success, The cmpl function will free the buffers */
 		return 0;
 
@@ -757,8 +1003,9 @@ lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 	if (fdmi_rsp == be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) {
 		/* FDMI rsp failed */
 		lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-				"%d:0220 FDMI rsp failed Data: x%x\n",
-				phba->brd_no, be16_to_cpu(fdmi_cmd));
+			        "%d (%d):0220 FDMI rsp failed Data: x%x\n",
+			        phba->brd_no, vport->vpi,
+				be16_to_cpu(fdmi_cmd));
 	}
 
 	switch (be16_to_cpu(fdmi_cmd)) {
@@ -828,9 +1075,9 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode)
 
 	/* FDMI request */
 	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-		        "%d:0218 FDMI Request Data: x%x x%x x%x\n",
-		        phba->brd_no,
-			vport->fc_flag, vport->port_state, cmdcode);
+			"%d (%d):0218 FDMI Request Data: x%x x%x x%x\n",
+			phba->brd_no, vport->vpi, vport->fc_flag,
+			vport->port_state, cmdcode);
 
 	CtReq = (struct lpfc_sli_ct_request *) mp->virt;
 
@@ -1134,15 +1381,15 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode)
 	}
 
 	bpl = (struct ulp_bde64 *) bmp->virt;
-	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;
 	bpl->tus.f.bdeSize = size;
 	bpl->tus.w = le32_to_cpu(bpl->tus.w);
 
 	cmpl = lpfc_cmpl_ct_cmd_fdmi;
 
-	if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, FC_MAX_NS_RSP))
+	if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, FC_MAX_NS_RSP, 0))
 		return 0;
 
 	lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
@@ -1155,8 +1402,8 @@ fdmi_cmd_free_mp:
 fdmi_cmd_exit:
 	/* Issue FDMI request failed */
 	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-		        "%d:0244 Issue FDMI request failed Data: x%x\n",
-		        phba->brd_no, cmdcode);
+		        "%d (%d):0244 Issue FDMI request failed Data: x%x\n",
+		        phba->brd_no, vport->vpi, cmdcode);
 	return 1;
 }
 
@@ -1170,10 +1417,15 @@ lpfc_fdmi_tmo(unsigned long ptr)
 	spin_lock_irqsave(&vport->work_port_lock, iflag);
 	if (!(vport->work_port_events & WORKER_FDMI_TMO)) {
 		vport->work_port_events |= WORKER_FDMI_TMO;
+		spin_unlock_irqrestore(&vport->work_port_lock, iflag);
+
+		spin_lock_irqsave(&phba->hbalock, iflag);
 		if (phba->work_wait)
-			wake_up(phba->work_wait);
+			lpfc_worker_wake_up(phba);
+		spin_unlock_irqrestore(&phba->hbalock, iflag);
 	}
-	spin_unlock_irqrestore(&vport->work_port_lock, iflag);
+	else
+		spin_unlock_irqrestore(&vport->work_port_lock, iflag);
 }
 
 void

+ 6 - 2
drivers/scsi/lpfc/lpfc_disc.h

@@ -36,13 +36,14 @@ enum lpfc_work_type {
 	LPFC_EVT_WARM_START,
 	LPFC_EVT_KILL,
 	LPFC_EVT_ELS_RETRY,
+	LPFC_EVT_DEV_LOSS,
 };
 
 /* structure used to queue event to the discovery tasklet */
 struct lpfc_work_evt {
 	struct list_head      evt_listp;
-	void                * evt_arg1;
-	void                * evt_arg2;
+	void                 *evt_arg1;
+	void                 *evt_arg2;
 	enum lpfc_work_type   evt;
 };
 
@@ -73,10 +74,12 @@ struct lpfc_nodelist {
 #define NLP_FCP_2_DEVICE   0x10			/* FCP-2 device */
 
 	struct timer_list   nlp_delayfunc;	/* Used for delayed ELS cmds */
+	struct timer_list   nlp_initiator_tmr;	/* Used with dev_loss */
 	struct fc_rport *rport;			/* Corresponding FC transport
 						   port structure */
 	struct lpfc_vport *vport;
 	struct lpfc_work_evt els_retry_evt;
+	struct lpfc_work_evt dev_loss_evt;
 	unsigned long last_ramp_up_time;        /* jiffy of last ramp up */
 	unsigned long last_q_full_time;		/* jiffy of last queue full */
 	struct kref     kref;
@@ -99,6 +102,7 @@ struct lpfc_nodelist {
 #define NLP_NPR_ADISC      0x2000000	/* Issue ADISC when dq'ed from
 					   NPR list */
 #define NLP_NODEV_REMOVE   0x8000000	/* Defer removal till discovery ends */
+#define NLP_TARGET_REMOVE  0x10000000   /* Target remove in process */
 
 /* There are 4 different double linked lists nodelist entries can reside on.
  * The Port Login (PLOGI) list and Address Discovery (ADISC) list are used

文件差异内容过多而无法显示
+ 328 - 154
drivers/scsi/lpfc/lpfc_els.c


文件差异内容过多而无法显示
+ 448 - 201
drivers/scsi/lpfc/lpfc_hbadisc.c


+ 96 - 29
drivers/scsi/lpfc/lpfc_hw.h

@@ -64,6 +64,7 @@
 #define SLI3_IOCB_CMD_SIZE	128
 #define SLI3_IOCB_RSP_SIZE	64
 
+
 /* Common Transport structures and definitions */
 
 union CtRevisionId {
@@ -84,6 +85,9 @@ union CtCommandResponse {
 	uint32_t word;
 };
 
+#define FC4_FEATURE_INIT 0x2
+#define FC4_FEATURE_TARGET 0x1
+
 struct lpfc_sli_ct_request {
 	/* Structure is in Big Endian format */
 	union CtRevisionId RevisionId;
@@ -126,20 +130,6 @@ struct lpfc_sli_ct_request {
 
 			uint32_t rsvd[7];
 		} rft;
-		struct rff {
-			uint32_t PortId;
-			uint8_t reserved[2];
-#ifdef __BIG_ENDIAN_BITFIELD
-			uint8_t feature_res:6;
-			uint8_t feature_init:1;
-			uint8_t feature_tgt:1;
-#else  /*  __LITTLE_ENDIAN_BITFIELD */
-			uint8_t feature_tgt:1;
-			uint8_t feature_init:1;
-			uint8_t feature_res:6;
-#endif
-			uint8_t type_code;     /* type=8 for FCP */
-		} rff;
 		struct rnn {
 			uint32_t PortId;	/* For RNN_ID requests */
 			uint8_t wwnn[8];
@@ -149,15 +139,42 @@ struct lpfc_sli_ct_request {
 			uint8_t len;
 			uint8_t symbname[255];
 		} rsnn;
+		struct rspn {	/* For RSPN_ID requests */
+			uint32_t PortId;
+			uint8_t len;
+			uint8_t symbname[255];
+		} rspn;
+		struct gff {
+			uint32_t PortId;
+		} gff;
+		struct gff_acc {
+			uint8_t fbits[128];
+		} gff_acc;
+#define FCP_TYPE_FEATURE_OFFSET 4
+		struct rff {
+			uint32_t PortId;
+			uint8_t reserved[2];
+			uint8_t fbits;
+			uint8_t type_code;     /* type=8 for FCP */
+		} rff;
 	} un;
 };
 
 #define  SLI_CT_REVISION        1
-#define  GID_REQUEST_SZ         (sizeof(struct lpfc_sli_ct_request) - 260)
-#define  RFT_REQUEST_SZ         (sizeof(struct lpfc_sli_ct_request) - 228)
-#define  RFF_REQUEST_SZ         (sizeof(struct lpfc_sli_ct_request) - 235)
-#define  RNN_REQUEST_SZ         (sizeof(struct lpfc_sli_ct_request) - 252)
-#define  RSNN_REQUEST_SZ        (sizeof(struct lpfc_sli_ct_request))
+#define  GID_REQUEST_SZ   (offsetof(struct lpfc_sli_ct_request, un) + \
+			   sizeof(struct gid))
+#define  GFF_REQUEST_SZ   (offsetof(struct lpfc_sli_ct_request, un) + \
+			   sizeof(struct gff))
+#define  RFT_REQUEST_SZ   (offsetof(struct lpfc_sli_ct_request, un) + \
+			   sizeof(struct rft))
+#define  RFF_REQUEST_SZ   (offsetof(struct lpfc_sli_ct_request, un) + \
+			   sizeof(struct rff))
+#define  RNN_REQUEST_SZ   (offsetof(struct lpfc_sli_ct_request, un) + \
+			   sizeof(struct rnn))
+#define  RSNN_REQUEST_SZ  (offsetof(struct lpfc_sli_ct_request, un) + \
+			   sizeof(struct rsnn))
+#define  RSPN_REQUEST_SZ  (offsetof(struct lpfc_sli_ct_request, un) + \
+			   sizeof(struct rspn))
 
 /*
  * FsType Definitions
@@ -232,6 +249,7 @@ struct lpfc_sli_ct_request {
 #define  SLI_CTNS_GFT_ID      0x0117
 #define  SLI_CTNS_GSPN_ID     0x0118
 #define  SLI_CTNS_GPT_ID      0x011A
+#define  SLI_CTNS_GFF_ID      0x011F
 #define  SLI_CTNS_GID_PN      0x0121
 #define  SLI_CTNS_GID_NN      0x0131
 #define  SLI_CTNS_GIP_NN      0x0135
@@ -245,9 +263,9 @@ struct lpfc_sli_ct_request {
 #define  SLI_CTNS_RNN_ID      0x0213
 #define  SLI_CTNS_RCS_ID      0x0214
 #define  SLI_CTNS_RFT_ID      0x0217
-#define  SLI_CTNS_RFF_ID      0x021F
 #define  SLI_CTNS_RSPN_ID     0x0218
 #define  SLI_CTNS_RPT_ID      0x021A
+#define  SLI_CTNS_RFF_ID      0x021F
 #define  SLI_CTNS_RIP_NN      0x0235
 #define  SLI_CTNS_RIPA_NN     0x0236
 #define  SLI_CTNS_RSNN_NN     0x0239
@@ -316,8 +334,9 @@ struct csp {
 	uint8_t bbCreditlsb;	/* FC Word 0, byte 3 */
 
 #ifdef __BIG_ENDIAN_BITFIELD
-	uint16_t increasingOffset:1;	/* FC Word 1, bit 31 */
-	uint16_t response_multiple_Nport:1;	/* FC Word 1, bit 29 */
+	uint16_t request_multiple_Nport:1;	/* FC Word 1, bit 31 */
+	uint16_t randomOffset:1;	/* FC Word 1, bit 30 */
+	uint16_t response_multiple_NPort:1;	/* FC Word 1, bit 29 */
 	uint16_t fPort:1;	/* FC Word 1, bit 28 */
 	uint16_t altBbCredit:1;	/* FC Word 1, bit 27 */
 	uint16_t edtovResolution:1;	/* FC Word 1, bit 26 */
@@ -336,9 +355,9 @@ struct csp {
 	uint16_t edtovResolution:1;	/* FC Word 1, bit 26 */
 	uint16_t altBbCredit:1;	/* FC Word 1, bit 27 */
 	uint16_t fPort:1;	/* FC Word 1, bit 28 */
-	uint16_t word1Reserved2:1;	/* FC Word 1, bit 29 */
+	uint16_t response_multiple_NPort:1;	/* FC Word 1, bit 29 */
 	uint16_t randomOffset:1;	/* FC Word 1, bit 30 */
-	uint16_t increasingOffset:1;	/* FC Word 1, bit 31 */
+	uint16_t request_multiple_Nport:1;	/* FC Word 1, bit 31 */
 
 	uint16_t payloadlength:1;	/* FC Word 1, bit 16 */
 	uint16_t contIncSeqCnt:1;	/* FC Word 1, bit 17 */
@@ -1268,6 +1287,10 @@ typedef struct {		/* FireFly BIU registers */
 #define MBX_READ_RPI64      0x8F
 #define MBX_REG_LOGIN64     0x93
 #define MBX_READ_LA64       0x95
+#define MBX_REG_VPI	    0x96
+#define MBX_UNREG_VPI	    0x97
+#define MBX_REG_VNPID	    0x96
+#define MBX_UNREG_VNPID	    0x97
 
 #define MBX_FLASH_WR_ULA    0x98
 #define MBX_SET_DEBUG       0x99
@@ -1570,7 +1593,7 @@ typedef struct {
 #define FLAGS_TOPOLOGY_MODE_PT_PT    0x02 /* Attempt pt-pt only */
 #define FLAGS_TOPOLOGY_MODE_LOOP     0x04 /* Attempt loop only */
 #define FLAGS_TOPOLOGY_MODE_PT_LOOP  0x06 /* Attempt pt-pt then loop */
-#define FLAGS_UNREG_LOGIN_ALL        0x08 /* UNREG_LOGIN all on link down */
+#define	FLAGS_UNREG_LOGIN_ALL	     0x08 /* UNREG_LOGIN all on link down */
 #define FLAGS_LIRP_LILP              0x80 /* LIRP / LILP is disabled */
 
 #define FLAGS_TOPOLOGY_FAILOVER      0x0400	/* Bit 10 */
@@ -2086,6 +2109,45 @@ typedef struct {
 #endif
 } UNREG_LOGIN_VAR;
 
+/* Structure for MB Command REG_VPI (0x96) */
+typedef struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t rsvd1;
+	uint32_t rsvd2:8;
+	uint32_t sid:24;
+	uint32_t rsvd3;
+	uint32_t rsvd4;
+	uint32_t rsvd5;
+	uint16_t rsvd6;
+	uint16_t vpi;
+#else	/*  __LITTLE_ENDIAN */
+	uint32_t rsvd1;
+	uint32_t sid:24;
+	uint32_t rsvd2:8;
+	uint32_t rsvd3;
+	uint32_t rsvd4;
+	uint32_t rsvd5;
+	uint16_t vpi;
+	uint16_t rsvd6;
+#endif
+} REG_VPI_VAR;
+
+/* Structure for MB Command UNREG_VPI (0x97) */
+typedef struct {
+	uint32_t rsvd1;
+	uint32_t rsvd2;
+	uint32_t rsvd3;
+	uint32_t rsvd4;
+	uint32_t rsvd5;
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint16_t rsvd6;
+	uint16_t vpi;
+#else	/*  __LITTLE_ENDIAN */
+	uint16_t vpi;
+	uint16_t rsvd6;
+#endif
+} UNREG_VPI_VAR;
+
 /* Structure for MB Command UNREG_D_ID (0x23) */
 
 typedef struct {
@@ -2549,8 +2611,8 @@ typedef union {
 	LOAD_SM_VAR varLdSM;		/* cmd =  1 (LOAD_SM)        */
 	READ_NV_VAR varRDnvp;		/* cmd =  2 (READ_NVPARMS)   */
 	WRITE_NV_VAR varWTnvp;		/* cmd =  3 (WRITE_NVPARMS)  */
-	BIU_DIAG_VAR varBIUdiag;	/* cmd =  4 (RUN_BIU_DIAG)   */
-	INIT_LINK_VAR varInitLnk;	/* cmd =  5 (INIT_LINK)      */
+	BIU_DIAG_VAR varBIUdiag; 	/* cmd =  4 (RUN_BIU_DIAG)   */
+	INIT_LINK_VAR varInitLnk; 	/* cmd =  5 (INIT_LINK)      */
 	DOWN_LINK_VAR varDwnLnk;	/* cmd =  6 (DOWN_LINK)      */
 	CONFIG_LINK varCfgLnk;		/* cmd =  7 (CONFIG_LINK)    */
 	PART_SLIM_VAR varSlim;		/* cmd =  8 (PART_SLIM)      */
@@ -2575,6 +2637,8 @@ typedef union {
 					 */
 	struct config_hbq_var varCfgHbq;/* cmd = 0x7c (CONFIG_HBQ)  */
 	CONFIG_PORT_VAR varCfgPort;	/* cmd = 0x88 (CONFIG_PORT)  */
+	REG_VPI_VAR varRegVpi;		/* cmd = 0x96 (REG_VPI) */
+	UNREG_VPI_VAR varUnregVpi;	/* cmd = 0x97 (UNREG_VPI) */
 } MAILVARIANTS;
 
 /*
@@ -2614,7 +2678,6 @@ typedef union {
 	struct sli3_pgp  s3_pgp;
 } SLI_VAR;
 
-
 typedef struct {
 #ifdef __BIG_ENDIAN_BITFIELD
 	uint16_t mbxStatus;
@@ -2935,6 +2998,8 @@ struct rcv_sli3 {
 	struct ulp_bde64 bde2;
 };
 
+
+
 typedef struct _IOCB {	/* IOCB structure */
 	union {
 		GENERIC_RSP grsp;	/* Generic response */
@@ -3011,6 +3076,7 @@ typedef struct _IOCB {	/* IOCB structure */
 	uint32_t ulpXS:1;
 	uint32_t ulpTimeout:8;
 #endif
+
 	union {
 		struct rcv_sli3 rcvsli3; /* words 8 - 15 */
 		uint32_t sli3Words[24]; /* 96 extra bytes for SLI-3 */
@@ -3024,6 +3090,7 @@ typedef struct _IOCB {	/* IOCB structure */
 #define PARM_UNUSED        0	/* PU field (Word 4) not used */
 #define PARM_REL_OFF       1	/* PU field (Word 4) = R. O. */
 #define PARM_READ_CHECK    2	/* PU field (Word 4) = Data Transfer Length */
+#define PARM_NPIV_DID	   3
 #define CLASS1             0	/* Class 1 */
 #define CLASS2             1	/* Class 2 */
 #define CLASS3             2	/* Class 3 */
@@ -3044,7 +3111,7 @@ typedef struct _IOCB {	/* IOCB structure */
 #define IOSTAT_RSVD2           0xC
 #define IOSTAT_RSVD3           0xD
 #define IOSTAT_RSVD4           0xE
-#define IOSTAT_RSVD5           0xF
+#define IOSTAT_NEED_BUFFER     0xF
 #define IOSTAT_DRIVER_REJECT   0x10   /* ulpStatus  - Driver defined */
 #define IOSTAT_DEFAULT         0xF    /* Same as rsvd5 for now */
 #define IOSTAT_CNT             0x11

+ 189 - 96
drivers/scsi/lpfc/lpfc_init.c

@@ -27,6 +27,7 @@
 #include <linux/kthread.h>
 #include <linux/pci.h>
 #include <linux/spinlock.h>
+#include <linux/ctype.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_device.h>
@@ -40,21 +41,18 @@
 #include "lpfc.h"
 #include "lpfc_logmsg.h"
 #include "lpfc_crtn.h"
+#include "lpfc_vport.h"
 #include "lpfc_version.h"
+#include "lpfc_vport.h"
 
 static int lpfc_parse_vpd(struct lpfc_hba *, uint8_t *, int);
 static void lpfc_get_hba_model_desc(struct lpfc_hba *, uint8_t *, uint8_t *);
 static int lpfc_post_rcv_buf(struct lpfc_hba *);
 
 static struct scsi_transport_template *lpfc_transport_template = NULL;
+static struct scsi_transport_template *lpfc_vport_transport_template = NULL;
 static DEFINE_IDR(lpfc_hba_index);
 
-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");
 
 
 /************************************************************************/
@@ -123,6 +121,8 @@ lpfc_config_port_prep(struct lpfc_hba *phba)
 		       sizeof(phba->wwpn));
 	}
 
+	phba->sli3_options = 0x0;
+
 	/* Setup and issue mailbox READ REV command */
 	lpfc_read_rev(phba, pmb);
 	rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
@@ -136,6 +136,7 @@ lpfc_config_port_prep(struct lpfc_hba *phba)
 		return -ERESTART;
 	}
 
+
 	/*
 	 * The value of rr must be 1 since the driver set the cv field to 1.
 	 * This setting requires the FW to set all revision fields.
@@ -155,6 +156,7 @@ lpfc_config_port_prep(struct lpfc_hba *phba)
 
 	/* Save information as VPD data */
 	vp->rev.rBit = 1;
+	memcpy(&vp->sli3Feat, &mb->un.varRdRev.sli3Feat, sizeof(uint32_t));
 	vp->rev.sli1FwRev = mb->un.varRdRev.sli1FwRev;
 	memcpy(vp->rev.sli1FwName, (char*) mb->un.varRdRev.sli1FwName, 16);
 	vp->rev.sli2FwRev = mb->un.varRdRev.sli2FwRev;
@@ -170,6 +172,13 @@ lpfc_config_port_prep(struct lpfc_hba *phba)
 	vp->rev.postKernRev = mb->un.varRdRev.postKernRev;
 	vp->rev.opFwRev = mb->un.varRdRev.opFwRev;
 
+	/* If the sli feature level is less then 9, we must
+	 * tear down all RPIs and VPIs on link down if NPIV
+	 * is enabled.
+	 */
+	if (vp->rev.feaLevelHigh < 9)
+		phba->sli3_options |= LPFC_SLI3_VPORT_TEARDOWN;
+
 	if (lpfc_is_LC_HBA(phba->pcidev->device))
 		memcpy(phba->RandomData, (char *)&mb->un.varWords[24],
 						sizeof (phba->RandomData));
@@ -197,7 +206,7 @@ lpfc_config_port_prep(struct lpfc_hba *phba)
 		if (mb->un.varDmp.word_cnt > DMP_VPD_SIZE - offset)
 			mb->un.varDmp.word_cnt = DMP_VPD_SIZE - offset;
 		lpfc_sli_pcimem_bcopy(pmb->context2, lpfc_vpd_data + offset,
-							mb->un.varDmp.word_cnt);
+				      mb->un.varDmp.word_cnt);
 		offset += mb->un.varDmp.word_cnt;
 	} while (mb->un.varDmp.word_cnt && offset < DMP_VPD_SIZE);
 	lpfc_parse_vpd(phba, lpfc_vpd_data, offset);
@@ -240,7 +249,7 @@ lpfc_config_port_post(struct lpfc_hba *phba)
 	mb = &pmb->mb;
 
 	/* Get login parameters for NID.  */
-	lpfc_read_sparam(phba, pmb);
+	lpfc_read_sparam(phba, pmb, 0);
 	pmb->vport = vport;
 	if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) {
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
@@ -431,10 +440,9 @@ lpfc_hba_down_prep(struct lpfc_hba *phba)
 	writel(0, phba->HCregaddr);
 	readl(phba->HCregaddr); /* flush */
 
-				/* Cleanup potential discovery resources */
-	lpfc_els_flush_rscn(vport);
-	lpfc_els_flush_cmd(vport);
-	lpfc_disc_flush_list(vport);
+	list_for_each_entry(vport, &phba->port_list, listentry) {
+		lpfc_cleanup_discovery_resources(vport);
+	}
 
 	return 0;
 }
@@ -456,13 +464,17 @@ lpfc_hba_down_post(struct lpfc_hba *phba)
 	struct lpfc_dmabuf *mp, *next_mp;
 	int i;
 
-	/* Cleanup preposted buffers on the ELS ring */
-	pring = &psli->ring[LPFC_ELS_RING];
-	list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) {
-		list_del(&mp->list);
-		pring->postbufq_cnt--;
-		lpfc_mbuf_free(phba, mp->virt, mp->phys);
-		kfree(mp);
+	if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)
+		lpfc_sli_hbqbuf_free_all(phba);
+	else {
+		/* Cleanup preposted buffers on the ELS ring */
+		pring = &psli->ring[LPFC_ELS_RING];
+		list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) {
+			list_del(&mp->list);
+			pring->postbufq_cnt--;
+			lpfc_mbuf_free(phba, mp->virt, mp->phys);
+			kfree(mp);
+		}
 	}
 
 	for (i = 0; i < psli->num_rings; i++) {
@@ -485,10 +497,11 @@ void
 lpfc_handle_eratt(struct lpfc_hba *phba)
 {
 	struct lpfc_vport *vport = phba->pport;
-	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
 	struct lpfc_sli   *psli = &phba->sli;
 	struct lpfc_sli_ring  *pring;
+	struct lpfc_vport *port_iterator;
 	uint32_t event_data;
+	struct Scsi_Host  *shost;
 
 	/* If the pci channel is offline, ignore possible errors,
 	 * since we cannot communicate with the pci card anyway. */
@@ -503,10 +516,17 @@ lpfc_handle_eratt(struct lpfc_hba *phba)
 				"Data: x%x x%x x%x\n",
 				phba->brd_no, phba->work_hs,
 				phba->work_status[0], phba->work_status[1]);
-		spin_lock_irq(shost->host_lock);
-		vport->fc_flag |= FC_ESTABLISH_LINK;
+		list_for_each_entry(port_iterator, &phba->port_list,
+				    listentry) {
+			shost = lpfc_shost_from_vport(port_iterator);
+
+			spin_lock_irq(shost->host_lock);
+			port_iterator->fc_flag |= FC_ESTABLISH_LINK;
+			spin_unlock_irq(shost->host_lock);
+		}
+		spin_lock_irq(&phba->hbalock);
 		psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
-		spin_unlock_irq(shost->host_lock);
+		spin_unlock_irq(&phba->hbalock);
 
 		/*
 		* Firmware stops when it triggled erratt with HS_FFER6.
@@ -543,11 +563,14 @@ lpfc_handle_eratt(struct lpfc_hba *phba)
 				phba->work_status[0], phba->work_status[1]);
 
 		event_data = FC_REG_DUMP_EVENT;
+		shost = lpfc_shost_from_vport(vport);
 		fc_host_post_vendor_event(shost, fc_get_event_number(),
 				sizeof(event_data), (char *) &event_data,
 				SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX);
 
+		spin_lock_irq(&phba->hbalock);
 		psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
+		spin_unlock_irq(&phba->hbalock);
 		lpfc_offline_prep(phba);
 		lpfc_offline(phba);
 		lpfc_unblock_mgmt_io(phba);
@@ -569,6 +592,7 @@ lpfc_handle_latt(struct lpfc_hba *phba)
 {
 	struct lpfc_vport *vport = phba->pport;
 	struct lpfc_sli   *psli = &phba->sli;
+	struct lpfc_vport *port_iterator;
 	LPFC_MBOXQ_t *pmb;
 	volatile uint32_t control;
 	struct lpfc_dmabuf *mp;
@@ -589,7 +613,8 @@ lpfc_handle_latt(struct lpfc_hba *phba)
 	rc = -EIO;
 
 	/* Cleanup any outstanding ELS commands */
-	lpfc_els_flush_cmd(vport);
+	list_for_each_entry(port_iterator, &phba->port_list, listentry)
+		lpfc_els_flush_cmd(port_iterator);
 
 	psli->slistat.link_event++;
 	lpfc_read_la(phba, pmb, mp);
@@ -1023,9 +1048,8 @@ lpfc_post_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, int cnt,
 			return cnt;
 		}
 		lpfc_sli_ringpostbuf_put(phba, pring, mp1);
-		if (mp2) {
+		if (mp2)
 			lpfc_sli_ringpostbuf_put(phba, pring, mp2);
-		}
 	}
 	pring->missbufcnt = 0;
 	return 0;
@@ -1175,34 +1199,45 @@ lpfc_cleanup(struct lpfc_vport *vport)
 static void
 lpfc_establish_link_tmo(unsigned long ptr)
 {
-	struct lpfc_hba   *phba = (struct lpfc_hba *)ptr;
+	struct lpfc_hba   *phba = (struct lpfc_hba *) ptr;
 	struct lpfc_vport *vport = phba->pport;
-	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
 	unsigned long iflag;
 
-
 	/* Re-establishing Link, timer expired */
 	lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
 			"%d:1300 Re-establishing Link, timer expired "
 			"Data: x%x x%x\n",
 			phba->brd_no, vport->fc_flag,
 			vport->port_state);
-	spin_lock_irqsave(shost->host_lock, iflag);
-	vport->fc_flag &= ~FC_ESTABLISH_LINK;
-	spin_unlock_irqrestore(shost->host_lock, iflag);
+	list_for_each_entry(vport, &phba->port_list, listentry) {
+		struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
+		spin_lock_irqsave(shost->host_lock, iflag);
+		vport->fc_flag &= ~FC_ESTABLISH_LINK;
+		spin_unlock_irqrestore(shost->host_lock, iflag);
+	}
+}
+
+void
+lpfc_stop_vport_timers(struct lpfc_vport *vport)
+{
+	del_timer_sync(&vport->els_tmofunc);
+	del_timer_sync(&vport->fc_fdmitmo);
+	lpfc_can_disctmo(vport);
+	return;
 }
 
 static void
-lpfc_stop_timer(struct lpfc_hba *phba)
+lpfc_stop_phba_timers(struct lpfc_hba *phba)
 {
-	struct lpfc_vport *vport = phba->pport;
+	struct lpfc_vport *vport;
 
 	del_timer_sync(&phba->fcp_poll_timer);
 	del_timer_sync(&phba->fc_estabtmo);
-	del_timer_sync(&vport->els_tmofunc);
-	del_timer_sync(&vport->fc_fdmitmo);
-	del_timer_sync(&vport->fc_disctmo);
+	list_for_each_entry(vport, &phba->port_list, listentry)
+		lpfc_stop_vport_timers(vport);
 	del_timer_sync(&phba->sli.mbox_tmo);
+	del_timer_sync(&phba->fabric_block_timer);
 	return;
 }
 
@@ -1210,7 +1245,6 @@ int
 lpfc_online(struct lpfc_hba *phba)
 {
 	struct lpfc_vport *vport = phba->pport;
-	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
 
 	if (!phba)
 		return 0;
@@ -1234,9 +1268,14 @@ lpfc_online(struct lpfc_hba *phba)
 		return 1;
 	}
 
-	spin_lock_irq(shost->host_lock);
-	vport->fc_flag &= ~FC_OFFLINE_MODE;
-	spin_unlock_irq(shost->host_lock);
+	list_for_each_entry(vport, &phba->port_list, listentry) {
+		struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
+		spin_lock_irq(shost->host_lock);
+		vport->fc_flag &= ~FC_OFFLINE_MODE;
+		if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)
+			vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+		spin_unlock_irq(shost->host_lock);
+	}
 
 	lpfc_unblock_mgmt_io(phba);
 	return 0;
@@ -1288,31 +1327,37 @@ lpfc_offline(struct lpfc_hba *phba)
 {
 	struct lpfc_vport *vport = phba->pport;
 	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
-	unsigned long iflag;
+	struct lpfc_vport *port_iterator;
 
 	if (vport->fc_flag & FC_OFFLINE_MODE)
 		return;
 
 	/* stop all timers associated with this hba */
-	lpfc_stop_timer(phba);
+	lpfc_stop_phba_timers(phba);
+	list_for_each_entry(port_iterator, &phba->port_list, listentry) {
+		port_iterator->work_port_events = 0;
+	}
 
-	lpfc_printf_log(phba,
-		       KERN_WARNING,
-		       LOG_INIT,
+	lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
 		       "%d:0460 Bring Adapter offline\n",
 		       phba->brd_no);
 
 	/* Bring down the SLI Layer and cleanup.  The HBA is offline
 	   now.  */
 	lpfc_sli_hba_down(phba);
-	lpfc_cleanup(vport);
-	spin_lock_irqsave(shost->host_lock, iflag);
-	spin_lock(&phba->hbalock);
+	spin_lock_irq(&phba->hbalock);
 	phba->work_ha = 0;
-	vport->work_port_events = 0;
 	vport->fc_flag |= FC_OFFLINE_MODE;
-	spin_unlock(&phba->hbalock);
-	spin_unlock_irqrestore(shost->host_lock, iflag);
+	spin_unlock_irq(&phba->hbalock);
+	list_for_each_entry(port_iterator, &phba->port_list, listentry) {
+		shost = lpfc_shost_from_vport(port_iterator);
+
+		lpfc_cleanup(port_iterator);
+		spin_lock_irq(shost->host_lock);
+		vport->work_port_events = 0;
+		vport->fc_flag |= FC_OFFLINE_MODE;
+		spin_unlock_irq(shost->host_lock);
+	}
 }
 
 /******************************************************************************
@@ -1332,7 +1377,7 @@ lpfc_scsi_free(struct lpfc_hba *phba)
 	list_for_each_entry_safe(sb, sb_next, &phba->lpfc_scsi_buf_list, list) {
 		list_del(&sb->list);
 		pci_pool_free(phba->lpfc_scsi_dma_buf_pool, sb->data,
-								sb->dma_handle);
+			      sb->dma_handle);
 		kfree(sb);
 		phba->total_scsi_bufs--;
 	}
@@ -1349,8 +1394,9 @@ lpfc_scsi_free(struct lpfc_hba *phba)
 	return 0;
 }
 
+
 struct lpfc_vport *
-lpfc_create_port(struct lpfc_hba *phba, int instance)
+lpfc_create_port(struct lpfc_hba *phba, int instance, struct fc_vport *fc_vport)
 {
 	struct lpfc_vport *vport;
 	struct Scsi_Host  *shost;
@@ -1364,6 +1410,7 @@ lpfc_create_port(struct lpfc_hba *phba, int instance)
 	vport->phba = phba;
 
 	vport->load_flag |= FC_LOADING;
+	vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
 
 	shost->unique_id = instance;
 	shost->max_id = LPFC_MAX_TARGET;
@@ -1376,7 +1423,13 @@ lpfc_create_port(struct lpfc_hba *phba, int instance)
 	 * max xri value determined in hba setup.
 	 */
 	shost->can_queue = phba->cfg_hba_queue_depth - 10;
-	shost->transportt = lpfc_transport_template;
+	if (fc_vport != NULL) {
+		shost->transportt = lpfc_vport_transport_template;
+		vport->port_type = LPFC_NPIV_PORT;
+	} else {
+		shost->transportt = lpfc_transport_template;
+		vport->port_type = LPFC_PHYSICAL_PORT;
+	}
 
 	/* Initialize all internally managed lists. */
 	INIT_LIST_HEAD(&vport->fc_nodes);
@@ -1384,22 +1437,28 @@ lpfc_create_port(struct lpfc_hba *phba, int instance)
 
 	init_timer(&vport->fc_disctmo);
 	vport->fc_disctmo.function = lpfc_disc_timeout;
-	vport->fc_disctmo.data = (unsigned long) vport;
+	vport->fc_disctmo.data = (unsigned long)vport;
 
 	init_timer(&vport->fc_fdmitmo);
 	vport->fc_fdmitmo.function = lpfc_fdmi_tmo;
-	vport->fc_fdmitmo.data = (unsigned long) vport;
+	vport->fc_fdmitmo.data = (unsigned long)vport;
 
 	init_timer(&vport->els_tmofunc);
 	vport->els_tmofunc.function = lpfc_els_timeout;
-	vport->els_tmofunc.data = (unsigned long) vport;
+	vport->els_tmofunc.data = (unsigned long)vport;
 
-	error = scsi_add_host(shost, &phba->pcidev->dev);
+	if (fc_vport != NULL) {
+		error = scsi_add_host(shost, &fc_vport->dev);
+	} else {
+		error = scsi_add_host(shost, &phba->pcidev->dev);
+	}
 	if (error)
 		goto out_put_shost;
 
+	if (!shost->shost_classdev.kobj.dentry)
+		goto out_put_shost;
+
 	list_add_tail(&vport->listentry, &phba->port_list);
-	scsi_scan_host(shost);
 	return vport;
 
 out_put_shost:
@@ -1411,19 +1470,40 @@ out:
 void
 destroy_port(struct lpfc_vport *vport)
 {
-	lpfc_cleanup(vport);
-	list_del(&vport->listentry);
+	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+	struct lpfc_hba  *phba = vport->phba;
+
+	kfree(vport->vname);
 	lpfc_free_sysfs_attr(vport);
-	fc_remove_host(lpfc_shost_from_vport(vport));
-	scsi_remove_host(lpfc_shost_from_vport(vport));
+
+	fc_remove_host(shost);
+	scsi_remove_host(shost);
+
+	spin_lock_irq(&phba->hbalock);
+	list_del_init(&vport->listentry);
+	spin_unlock_irq(&phba->hbalock);
+
+	lpfc_cleanup(vport);
 	return;
 }
 
+int
+lpfc_get_instance(void)
+{
+	int instance = 0;
+
+	/* Assign an unused number */
+	if (!idr_pre_get(&lpfc_hba_index, GFP_KERNEL))
+		return -1;
+	if (idr_get_new(&lpfc_hba_index, NULL, &instance))
+		return -1;
+	return instance;
+}
+
 static void
 lpfc_remove_device(struct lpfc_vport *vport)
 {
 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
-	struct lpfc_hba  *phba  = vport->phba;
 
 	lpfc_free_sysfs_attr(vport);
 
@@ -1433,8 +1513,6 @@ lpfc_remove_device(struct lpfc_vport *vport)
 
 	fc_remove_host(shost);
 	scsi_remove_host(shost);
-
-	kthread_stop(phba->worker_thread);
 }
 
 void lpfc_scan_start(struct Scsi_Host *shost)
@@ -1442,7 +1520,7 @@ void lpfc_scan_start(struct Scsi_Host *shost)
 	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
 	struct lpfc_hba   *phba = vport->phba;
 
-	if (lpfc_alloc_sysfs_attr(vport))
+	if (lpfc_sli_hba_setup(phba))
 		goto error;
 
 	/*
@@ -1486,6 +1564,14 @@ int lpfc_scan_finished(struct Scsi_Host *shost, unsigned long time)
 		return 0;
 
 finished:
+	lpfc_host_attrib_init(shost);
+	return 1;
+}
+
+void lpfc_host_attrib_init(struct Scsi_Host *shost)
+{
+	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+	struct lpfc_hba   *phba = vport->phba;
 	/*
 	 * Set fixed host attributes.  Must done after lpfc_sli_hba_setup().
 	 */
@@ -1499,7 +1585,8 @@ finished:
 	fc_host_supported_fc4s(shost)[2] = 1;
 	fc_host_supported_fc4s(shost)[7] = 1;
 
-	lpfc_get_hba_sym_node_name(phba, fc_host_symbolic_name(shost));
+	lpfc_vport_symbolic_node_name(vport, fc_host_symbolic_name(shost),
+				 sizeof fc_host_symbolic_name(shost));
 
 	fc_host_supported_speeds(shost) = 0;
 	if (phba->lmt & LMT_10Gb)
@@ -1521,11 +1608,10 @@ finished:
 	fc_host_active_fc4s(shost)[2] = 1;
 	fc_host_active_fc4s(shost)[7] = 1;
 
+	fc_host_max_npiv_vports(shost) = phba->max_vpi;
 	spin_lock_irq(shost->host_lock);
 	vport->fc_flag &= ~FC_LOADING;
 	spin_unlock_irq(shost->host_lock);
-
-	return 1;
 }
 
 static int __devinit
@@ -1555,20 +1641,17 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
 	phba->pcidev = pdev;
 
 	/* Assign an unused board number */
-	if (!idr_pre_get(&lpfc_hba_index, GFP_KERNEL))
-		goto out_free_phba;
-
-	error = idr_get_new(&lpfc_hba_index, NULL, &phba->brd_no);
-	if (error)
+	if ((phba->brd_no = lpfc_get_instance()) < 0)
 		goto out_free_phba;
 
 	INIT_LIST_HEAD(&phba->port_list);
-
+	INIT_LIST_HEAD(&phba->hbq_buffer_list);
 	/*
 	 * Get all the module params for configuring this host and then
 	 * establish the host.
 	 */
 	lpfc_get_cfgparam(phba);
+	phba->max_vpi = LPFC_MAX_VPI;
 
 	/* Initialize timers used by driver */
 	init_timer(&phba->fc_estabtmo);
@@ -1581,6 +1664,9 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
 	init_timer(&phba->fcp_poll_timer);
 	phba->fcp_poll_timer.function = lpfc_poll_timeout;
 	phba->fcp_poll_timer.data = (unsigned long) phba;
+	init_timer(&phba->fabric_block_timer);
+	phba->fabric_block_timer.function = lpfc_fabric_block_timeout;
+	phba->fabric_block_timer.data = (unsigned long) phba;
 
 	pci_set_master(pdev);
 	retval = pci_set_mwi(pdev);
@@ -1696,15 +1782,17 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
 	spin_lock_init(&phba->scsi_buf_list_lock);
 	INIT_LIST_HEAD(&phba->lpfc_scsi_buf_list);
 
-	vport = lpfc_create_port(phba, phba->brd_no);
+	/* Initialize list of fabric iocbs */
+	INIT_LIST_HEAD(&phba->fabric_iocb_list);
+
+	vport = lpfc_create_port(phba, phba->brd_no, NULL);
 	if (!vport)
 		goto out_kthread_stop;
 
 	shost = lpfc_shost_from_vport(vport);
-	vport->port_type = LPFC_PHYSICAL_PORT;
 	phba->pport = vport;
 
-	pci_set_drvdata(pdev, lpfc_shost_from_vport(vport));
+	pci_set_drvdata(pdev, shost);
 
 	if (phba->cfg_use_msi) {
 		error = pci_enable_msi(phba->pcidev);
@@ -1720,7 +1808,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 			"%d:0451 Enable interrupt handler failed\n",
 			phba->brd_no);
-		goto out_destroy_port;
+		goto out_disable_msi;
 	}
 
 	phba->MBslimaddr = phba->slim_memmap_p;
@@ -1729,10 +1817,10 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
 	phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET;
 	phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET;
 
-	error = lpfc_sli_hba_setup(phba);
-	if (error)
+	if (lpfc_alloc_sysfs_attr(vport))
 		goto out_free_irq;
 
+	scsi_scan_host(shost);
 	if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
 		spin_lock_irq(shost->host_lock);
 		lpfc_poll_start_timer(phba);
@@ -1742,11 +1830,11 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
 	return 0;
 
 out_free_irq:
-	lpfc_stop_timer(phba);
+	lpfc_stop_phba_timers(phba);
 	phba->pport->work_port_events = 0;
 	free_irq(phba->pcidev->irq, phba);
+out_disable_msi:
 	pci_disable_msi(phba->pcidev);
-out_destroy_port:
 	destroy_port(vport);
 out_kthread_stop:
 	kthread_stop(phba->worker_thread);
@@ -1786,9 +1874,9 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
 	struct Scsi_Host  *shost = pci_get_drvdata(pdev);
 	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
 	struct lpfc_hba   *phba = vport->phba;
-
-	vport->load_flag |= FC_UNLOADING;
-	lpfc_remove_device(vport);
+	struct lpfc_vport *port_iterator;
+	list_for_each_entry(port_iterator, &phba->port_list, listentry)
+		port_iterator->load_flag |= FC_UNLOADING;
 
 	/*
 	 * Bring down the SLI Layer. This step disable all interrupts,
@@ -1798,7 +1886,7 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
 	lpfc_sli_hba_down(phba);
 	lpfc_sli_brdrestart(phba);
 
-	lpfc_stop_timer(phba);
+	lpfc_stop_phba_timers(phba);
 
 	kthread_stop(phba->worker_thread);
 
@@ -1806,7 +1894,6 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
 	free_irq(phba->pcidev->irq, phba);
 	pci_disable_msi(phba->pcidev);
 
-	vport->work_port_events = 0;
 	destroy_port(vport);
 
 	pci_set_drvdata(pdev, NULL);
@@ -1892,13 +1979,14 @@ static pci_ers_result_t lpfc_io_slot_reset(struct pci_dev *pdev)
 	pci_set_master(pdev);
 
 	/* Re-establishing Link */
-	spin_lock_irq(&phba->hbalock);
-	phba->pport->fc_flag |= FC_ESTABLISH_LINK;
-	spin_unlock_irq(&phba->hbalock);
 	spin_lock_irq(host->host_lock);
-	psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
+	phba->pport->fc_flag |= FC_ESTABLISH_LINK;
 	spin_unlock_irq(host->host_lock);
 
+	spin_lock_irq(&phba->hbalock);
+	psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
+	spin_unlock_irq(&phba->hbalock);
+
 
 	/* Take device offline; this will perform cleanup */
 	lpfc_offline(phba);
@@ -2020,11 +2108,15 @@ lpfc_init(void)
 
 	lpfc_transport_template =
 				fc_attach_transport(&lpfc_transport_functions);
-	if (!lpfc_transport_template)
+	lpfc_vport_transport_template =
+			fc_attach_transport(&lpfc_vport_transport_functions);
+	if (!lpfc_transport_template || !lpfc_vport_transport_template)
 		return -ENOMEM;
 	error = pci_register_driver(&lpfc_driver);
-	if (error)
+	if (error) {
 		fc_release_transport(lpfc_transport_template);
+		fc_release_transport(lpfc_vport_transport_template);
+	}
 
 	return error;
 }
@@ -2034,6 +2126,7 @@ lpfc_exit(void)
 {
 	pci_unregister_driver(&lpfc_driver);
 	fc_release_transport(lpfc_transport_template);
+	fc_release_transport(lpfc_vport_transport_template);
 }
 
 module_init(lpfc_init);

+ 1 - 0
drivers/scsi/lpfc/lpfc_logmsg.h

@@ -30,6 +30,7 @@
 #define LOG_SLI                       0x800	/* SLI events */
 #define LOG_FCP_ERROR                 0x1000	/* log errors, not underruns */
 #define LOG_LIBDFC                    0x2000	/* Libdfc events */
+#define LOG_VPORT                     0x4000	/* NPIV events */
 #define LOG_ALL_MSG                   0xffff	/* LOG all messages */
 
 #define lpfc_printf_log(phba, level, mask, fmt, arg...) \

+ 96 - 35
drivers/scsi/lpfc/lpfc_mbox.c

@@ -106,7 +106,7 @@ lpfc_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, struct lpfc_dmabuf *mp)
 	 */
 	pmb->context1 = (uint8_t *) mp;
 	mb->mbxOwner = OWN_HOST;
-	return 0;
+	return (0);
 }
 
 /**********************************************/
@@ -209,7 +209,7 @@ lpfc_init_link(struct lpfc_hba * phba,
 	 */
 	vpd = &phba->vpd;
 	if (vpd->rev.feaLevelHigh >= 0x02){
-		switch (linkspeed){
+		switch(linkspeed){
 			case LINK_SPEED_1G:
 			case LINK_SPEED_2G:
 			case LINK_SPEED_4G:
@@ -232,7 +232,6 @@ lpfc_init_link(struct lpfc_hba * phba,
 	mb->mbxCommand = (volatile uint8_t)MBX_INIT_LINK;
 	mb->mbxOwner = OWN_HOST;
 	mb->un.varInitLnk.fabric_AL_PA = phba->fc_pref_ALPA;
-	mb->un.varInitLnk.link_flags |= FLAGS_UNREG_LOGIN_ALL;
 	return;
 }
 
@@ -241,7 +240,7 @@ lpfc_init_link(struct lpfc_hba * phba,
 /*                    mailbox command         */
 /**********************************************/
 int
-lpfc_read_sparam(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+lpfc_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, int vpi)
 {
 	struct lpfc_dmabuf *mp;
 	MAILBOX_t *mb;
@@ -265,18 +264,19 @@ lpfc_read_sparam(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 			        LOG_MBOX,
 			        "%d:0301 READ_SPARAM: no buffers\n",
 			        phba->brd_no);
-		return 1;
+		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);
+	mb->un.varRdSparm.vpi = vpi;
 
 	/* save address for completion */
 	pmb->context1 = mp;
 
-	return 0;
+	return (0);
 }
 
 /********************************************/
@@ -284,7 +284,8 @@ lpfc_read_sparam(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 /*                  mailbox command         */
 /********************************************/
 void
-lpfc_unreg_did(struct lpfc_hba *phba, uint32_t did, LPFC_MBOXQ_t *pmb)
+lpfc_unreg_did(struct lpfc_hba * phba, uint16_t vpi, uint32_t did,
+	       LPFC_MBOXQ_t * pmb)
 {
 	MAILBOX_t *mb;
 
@@ -292,6 +293,7 @@ lpfc_unreg_did(struct lpfc_hba *phba, uint32_t did, LPFC_MBOXQ_t *pmb)
 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
 
 	mb->un.varUnregDID.did = did;
+	mb->un.varUnregDID.vpi = vpi;
 
 	mb->mbxCommand = MBX_UNREG_D_ID;
 	mb->mbxOwner = OWN_HOST;
@@ -337,8 +339,8 @@ lpfc_read_lnk_stat(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 /*                  mailbox command         */
 /********************************************/
 int
-lpfc_reg_login(struct lpfc_hba *phba, uint32_t did, uint8_t *param,
-	       LPFC_MBOXQ_t *pmb, uint32_t flag)
+lpfc_reg_login(struct lpfc_hba *phba, uint16_t vpi, uint32_t did,
+	       uint8_t *param, LPFC_MBOXQ_t *pmb, uint32_t flag)
 {
 	MAILBOX_t *mb = &pmb->mb;
 	uint8_t *sparam;
@@ -347,6 +349,7 @@ lpfc_reg_login(struct lpfc_hba *phba, uint32_t did, uint8_t *param,
 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
 
 	mb->un.varRegLogin.rpi = 0;
+	mb->un.varRegLogin.vpi = vpi;
 	mb->un.varRegLogin.did = did;
 	mb->un.varWords[30] = flag;	/* Set flag to issue action on cmpl */
 
@@ -358,13 +361,11 @@ lpfc_reg_login(struct lpfc_hba *phba, uint32_t did, uint8_t *param,
 		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;
+		lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
+				"%d (%d):0302 REG_LOGIN: no buffers, DID x%x, "
+				"flag x%x\n",
+				phba->brd_no, vpi, did, flag);
+		return (1);
 	}
 	INIT_LIST_HEAD(&mp->list);
 	sparam = mp->virt;
@@ -380,7 +381,7 @@ lpfc_reg_login(struct lpfc_hba *phba, uint32_t did, uint8_t *param,
 	mb->un.varRegLogin.un.sp64.addrHigh = putPaddrHigh(mp->phys);
 	mb->un.varRegLogin.un.sp64.addrLow = putPaddrLow(mp->phys);
 
-	return 0;
+	return (0);
 }
 
 /**********************************************/
@@ -388,7 +389,8 @@ lpfc_reg_login(struct lpfc_hba *phba, uint32_t did, uint8_t *param,
 /*                    mailbox command         */
 /**********************************************/
 void
-lpfc_unreg_login(struct lpfc_hba *phba, uint32_t rpi, LPFC_MBOXQ_t * pmb)
+lpfc_unreg_login(struct lpfc_hba *phba, uint16_t vpi, uint32_t rpi,
+		 LPFC_MBOXQ_t * pmb)
 {
 	MAILBOX_t *mb;
 
@@ -397,12 +399,52 @@ lpfc_unreg_login(struct lpfc_hba *phba, uint32_t rpi, LPFC_MBOXQ_t * pmb)
 
 	mb->un.varUnregLogin.rpi = (uint16_t) rpi;
 	mb->un.varUnregLogin.rsvd1 = 0;
+	mb->un.varUnregLogin.vpi = vpi;
 
 	mb->mbxCommand = MBX_UNREG_LOGIN;
 	mb->mbxOwner = OWN_HOST;
 	return;
 }
 
+/**************************************************/
+/*  lpfc_reg_vpi   Issue a REG_VPI                */
+/*                    mailbox command             */
+/**************************************************/
+void
+lpfc_reg_vpi(struct lpfc_hba *phba, uint16_t vpi, uint32_t sid,
+	     LPFC_MBOXQ_t *pmb)
+{
+	MAILBOX_t *mb = &pmb->mb;
+
+	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
+
+	mb->un.varRegVpi.vpi = vpi;
+	mb->un.varRegVpi.sid = sid;
+
+	mb->mbxCommand = MBX_REG_VPI;
+	mb->mbxOwner = OWN_HOST;
+	return;
+
+}
+
+/**************************************************/
+/*  lpfc_unreg_vpi   Issue a UNREG_VNPI           */
+/*                    mailbox command             */
+/**************************************************/
+void
+lpfc_unreg_vpi(struct lpfc_hba *phba, uint16_t vpi, LPFC_MBOXQ_t *pmb)
+{
+	MAILBOX_t *mb = &pmb->mb;
+	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
+
+	mb->un.varUnregVpi.vpi = vpi;
+
+	mb->mbxCommand = MBX_UNREG_VPI;
+	mb->mbxOwner = OWN_HOST;
+	return;
+
+}
+
 static void
 lpfc_config_pcb_setup(struct lpfc_hba * phba)
 {
@@ -420,9 +462,9 @@ lpfc_config_pcb_setup(struct lpfc_hba * phba)
 		pring = &psli->ring[i];
 
 		pring->sizeCiocb = phba->sli_rev == 3 ? SLI3_IOCB_CMD_SIZE:
-			SLI2_IOCB_CMD_SIZE;
+							SLI2_IOCB_CMD_SIZE;
 		pring->sizeRiocb = phba->sli_rev == 3 ? SLI3_IOCB_RSP_SIZE:
-			SLI2_IOCB_RSP_SIZE;
+							SLI2_IOCB_RSP_SIZE;
 		/* A ring MUST have both cmd and rsp entries defined to be
 		   valid */
 		if ((pring->numCiocb == 0) || (pring->numRiocb == 0)) {
@@ -437,18 +479,18 @@ lpfc_config_pcb_setup(struct lpfc_hba * phba)
 			continue;
 		}
 		/* Command ring setup for ring */
-		pring->cmdringaddr = (void *)&phba->slim2p->IOCBs[iocbCnt];
+		pring->cmdringaddr = (void *) &phba->slim2p->IOCBs[iocbCnt];
 		pcbp->rdsc[i].cmdEntries = pring->numCiocb;
 
-		offset = (uint8_t *)&phba->slim2p->IOCBs[iocbCnt] -
-			 (uint8_t *)phba->slim2p;
+		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];
+		pring->rspringaddr = (void *) &phba->slim2p->IOCBs[iocbCnt];
 
 		pcbp->rdsc[i].rspEntries = pring->numRiocb;
 		offset = (uint8_t *)&phba->slim2p->IOCBs[iocbCnt] -
@@ -519,7 +561,7 @@ lpfc_config_hbq(struct lpfc_hba *phba, struct lpfc_hbq_init *hbq_desc,
 						       * Notification */
 	hbqmb->numMask    = hbq_desc->mask_count;     /* # R_CTL/TYPE masks
 						       * # in words 0-19 */
-	hbqmb->profile    = hbq_desc->profile;        /* Selection profile:
+	hbqmb->profile    = hbq_desc->profile;	      /* Selection profile:
 						       * 0 = all,
 						       * 7 = logentry */
 	hbqmb->ringMask   = hbq_desc->ring_mask;      /* Binds HBQ to a ring
@@ -538,9 +580,9 @@ lpfc_config_hbq(struct lpfc_hba *phba, struct lpfc_hbq_init *hbq_desc,
 	mb->mbxCommand = MBX_CONFIG_HBQ;
 	mb->mbxOwner = OWN_HOST;
 
-	/* Copy info for profiles 2,3,5. Other
-	 * profiles this area is reserved
-	 */
+				/* Copy info for profiles 2,3,5. Other
+				 * profiles this area is reserved
+				 */
 	if (hbq_desc->profile == 2)
 		lpfc_build_hbq_profile2(hbqmb, hbq_desc);
 	else if (hbq_desc->profile == 3)
@@ -563,6 +605,8 @@ lpfc_config_hbq(struct lpfc_hba *phba, struct lpfc_hbq_init *hbq_desc,
 	return;
 }
 
+
+
 void
 lpfc_config_ring(struct lpfc_hba * phba, int ring, LPFC_MBOXQ_t * pmb)
 {
@@ -605,7 +649,7 @@ lpfc_config_ring(struct lpfc_hba * phba, int ring, LPFC_MBOXQ_t * pmb)
 }
 
 void
-lpfc_config_port(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 {
 	MAILBOX_t __iomem *mb_slim = (MAILBOX_t __iomem *) phba->MBslimaddr;
 	MAILBOX_t *mb = &pmb->mb;
@@ -629,11 +673,19 @@ lpfc_config_port(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 
 	/* If HBA supports SLI=3 ask for it */
 
-	mb->un.varCfgPort.sli_mode = phba->sli_rev;
-	if (phba->sli_rev == 3) {
+	if (phba->sli_rev == 3 && phba->vpd.sli3Feat.cerbm) {
 		mb->un.varCfgPort.cerbm = 1; /* Request HBQs */
 		mb->un.varCfgPort.max_hbq = 1; /* Requesting 2 HBQs */
-	}
+		if (phba->max_vpi && lpfc_npiv_enable &&
+		    phba->vpd.sli3Feat.cmv) {
+			mb->un.varCfgPort.max_vpi = phba->max_vpi;
+			mb->un.varCfgPort.cmv = 1;
+			phba->sli3_options |= LPFC_SLI3_NPIV_ENABLED;
+		} else
+			mb->un.varCfgPort.max_vpi = phba->max_vpi = 0;
+	} else
+		phba->sli_rev = 2;
+	mb->un.varCfgPort.sli_mode = phba->sli_rev;
 
 	/* Now setup pcb */
 	phba->slim2p->pcb.type = TYPE_NATIVE_SLI2;
@@ -748,7 +800,7 @@ lpfc_config_port(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 
 	/* Swap PCB if needed */
 	lpfc_sli_pcimem_bcopy(&phba->slim2p->pcb, &phba->slim2p->pcb,
-								sizeof (PCB_t));
+			      sizeof(PCB_t));
 }
 
 void
@@ -783,13 +835,22 @@ lpfc_mbox_get(struct lpfc_hba * phba)
 	struct lpfc_sli *psli = &phba->sli;
 
 	list_remove_head((&psli->mboxq), mbq, LPFC_MBOXQ_t, list);
-	if (mbq) {
+	if (mbq)
 		psli->mboxq_cnt--;
-	}
 
 	return mbq;
 }
 
+void
+lpfc_mbox_cmpl_put(struct lpfc_hba * phba, LPFC_MBOXQ_t * mbq)
+{
+	/* This function expects to be called from interupt context */
+	spin_lock(&phba->hbalock);
+	list_add_tail(&mbq->list, &phba->sli.mboxq_cmpl);
+	spin_unlock(&phba->hbalock);
+	return;
+}
+
 int
 lpfc_mbox_tmo_val(struct lpfc_hba *phba, int cmd)
 {

+ 41 - 5
drivers/scsi/lpfc/lpfc_mem.c

@@ -44,6 +44,7 @@ int
 lpfc_mem_alloc(struct lpfc_hba * phba)
 {
 	struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool;
+	int longs;
 	int i;
 
 	phba->lpfc_scsi_dma_buf_pool = pci_pool_create("lpfc_scsi_dma_buf_pool",
@@ -87,8 +88,15 @@ lpfc_mem_alloc(struct lpfc_hba * phba)
 	if (!phba->lpfc_hbq_pool)
 		goto fail_free_nlp_mem_pool;
 
+	longs = (phba->max_vpi + BITS_PER_LONG - 1) / BITS_PER_LONG;
+	phba->vpi_bmask = kzalloc(longs * sizeof(unsigned long), GFP_KERNEL);
+	if (!phba->vpi_bmask)
+		goto fail_free_hbq_pool;
+
 	return 0;
 
+ fail_free_hbq_pool:
+	lpfc_sli_hbqbuf_free_all(phba);
  fail_free_nlp_mem_pool:
 	mempool_destroy(phba->nlp_mem_pool);
 	phba->nlp_mem_pool = NULL;
@@ -119,9 +127,9 @@ lpfc_mem_free(struct lpfc_hba * phba)
 	struct lpfc_dmabuf   *mp;
 	int i;
 
+	kfree(phba->vpi_bmask);
 	lpfc_sli_hbqbuf_free_all(phba);
 
-	spin_lock_irq(&phba->hbalock);
 	list_for_each_entry_safe(mbox, next_mbox, &psli->mboxq, list) {
 		mp = (struct lpfc_dmabuf *) (mbox->context1);
 		if (mp) {
@@ -131,9 +139,17 @@ lpfc_mem_free(struct lpfc_hba * phba)
 		list_del(&mbox->list);
 		mempool_free(mbox, phba->mbox_mem_pool);
 	}
+	list_for_each_entry_safe(mbox, next_mbox, &psli->mboxq_cmpl, 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;
-	spin_unlock_irq(&phba->hbalock);
 	if (psli->mbox_active) {
 		mbox = psli->mbox_active;
 		mp = (struct lpfc_dmabuf *) (mbox->context1);
@@ -163,7 +179,7 @@ lpfc_mem_free(struct lpfc_hba * phba)
 	phba->lpfc_scsi_dma_buf_pool = NULL;
 	phba->lpfc_mbuf_pool = NULL;
 
-	/* Free the iocb lookup array */
+				/* Free the iocb lookup array */
 	kfree(psli->iocbq_lookup);
 	psli->iocbq_lookup = NULL;
 
@@ -179,7 +195,7 @@ lpfc_mbuf_alloc(struct lpfc_hba *phba, int mem_flags, dma_addr_t *handle)
 	ret = pci_pool_alloc(phba->lpfc_mbuf_pool, GFP_KERNEL, handle);
 
 	spin_lock_irqsave(&phba->hbalock, iflags);
-	if (!ret && ( mem_flags & MEM_PRI) && pool->current_count) {
+	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;
@@ -214,7 +230,6 @@ lpfc_mbuf_free(struct lpfc_hba * phba, void *virt, dma_addr_t dma)
 	return;
 }
 
-
 void *
 lpfc_hbq_alloc(struct lpfc_hba *phba, int mem_flags, dma_addr_t *handle)
 {
@@ -230,3 +245,24 @@ lpfc_hbq_free(struct lpfc_hba *phba, void *virt, dma_addr_t dma)
 	return;
 }
 
+void
+lpfc_in_buf_free(struct lpfc_hba *phba, struct lpfc_dmabuf *mp)
+{
+	struct hbq_dmabuf *hbq_entry;
+
+	if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
+		hbq_entry = container_of(mp, struct hbq_dmabuf, dbuf);
+		if (hbq_entry->tag == -1) {
+			lpfc_hbq_free(phba, hbq_entry->dbuf.virt,
+				      hbq_entry->dbuf.phys);
+			kfree(hbq_entry);
+		} else {
+			lpfc_sli_free_hbq(phba, hbq_entry);
+		}
+	} else {
+		lpfc_mbuf_free(phba, mp->virt, mp->phys);
+		kfree(mp);
+	}
+	return;
+}
+

+ 207 - 91
drivers/scsi/lpfc/lpfc_nportdisc.c

@@ -1,4 +1,4 @@
-/*******************************************************************
+ /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
  * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
@@ -35,6 +35,7 @@
 #include "lpfc.h"
 #include "lpfc_logmsg.h"
 #include "lpfc_crtn.h"
+#include "lpfc_vport.h"
 
 
 /* Called to verify a rcv'ed ADISC was intended for us. */
@@ -74,12 +75,14 @@ lpfc_check_sparm(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 				hsp->cls1.rcvDataSizeLsb;
 		ssp_value = (sp->cls1.rcvDataSizeMsb << 8) |
 				sp->cls1.rcvDataSizeLsb;
+		if (!ssp_value)
+			goto bad_service_param;
 		if (ssp_value > hsp_value) {
 			sp->cls1.rcvDataSizeLsb = hsp->cls1.rcvDataSizeLsb;
 			sp->cls1.rcvDataSizeMsb = hsp->cls1.rcvDataSizeMsb;
 		}
 	} else if (class == CLASS1) {
-		return 0;
+		goto bad_service_param;
 	}
 
 	if (sp->cls2.classValid) {
@@ -87,12 +90,14 @@ lpfc_check_sparm(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 				hsp->cls2.rcvDataSizeLsb;
 		ssp_value = (sp->cls2.rcvDataSizeMsb << 8) |
 				sp->cls2.rcvDataSizeLsb;
+		if (!ssp_value)
+			goto bad_service_param;
 		if (ssp_value > hsp_value) {
 			sp->cls2.rcvDataSizeLsb = hsp->cls2.rcvDataSizeLsb;
 			sp->cls2.rcvDataSizeMsb = hsp->cls2.rcvDataSizeMsb;
 		}
 	} else if (class == CLASS2) {
-		return 0;
+		goto bad_service_param;
 	}
 
 	if (sp->cls3.classValid) {
@@ -100,12 +105,14 @@ lpfc_check_sparm(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 				hsp->cls3.rcvDataSizeLsb;
 		ssp_value = (sp->cls3.rcvDataSizeMsb << 8) |
 				sp->cls3.rcvDataSizeLsb;
+		if (!ssp_value)
+			goto bad_service_param;
 		if (ssp_value > hsp_value) {
 			sp->cls3.rcvDataSizeLsb = hsp->cls3.rcvDataSizeLsb;
 			sp->cls3.rcvDataSizeMsb = hsp->cls3.rcvDataSizeMsb;
 		}
 	} else if (class == CLASS3) {
-		return 0;
+		goto bad_service_param;
 	}
 
 	/*
@@ -124,11 +131,22 @@ lpfc_check_sparm(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 	memcpy(&ndlp->nlp_nodename, &sp->nodeName, sizeof (struct lpfc_name));
 	memcpy(&ndlp->nlp_portname, &sp->portName, sizeof (struct lpfc_name));
 	return 1;
+bad_service_param:
+	lpfc_printf_log(vport->phba, KERN_ERR, LOG_DISCOVERY,
+			"%d (%d):0207 Device %x "
+			"(%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x) sent "
+			"invalid service parameters.  Ignoring device.\n",
+			vport->phba->brd_no, ndlp->vport->vpi, ndlp->nlp_DID,
+			sp->nodeName.u.wwn[0], sp->nodeName.u.wwn[1],
+			sp->nodeName.u.wwn[2], sp->nodeName.u.wwn[3],
+			sp->nodeName.u.wwn[4], sp->nodeName.u.wwn[5],
+			sp->nodeName.u.wwn[6], sp->nodeName.u.wwn[7]);
+	return 0;
 }
 
 static void *
 lpfc_check_elscmpl_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
-		      struct lpfc_iocbq *rspiocb)
+			struct lpfc_iocbq *rspiocb)
 {
 	struct lpfc_dmabuf *pcmd, *prsp;
 	uint32_t *lp;
@@ -176,10 +194,12 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
 
 	/* Abort outstanding I/O on NPort <nlp_DID> */
 	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-			"%d:0205 Abort outstanding I/O on NPort x%x "
+			"%d (%d):0205 Abort outstanding I/O on NPort x%x "
 			"Data: x%x x%x x%x\n",
-			phba->brd_no, ndlp->nlp_DID, ndlp->nlp_flag,
-			ndlp->nlp_state, ndlp->nlp_rpi);
+			phba->brd_no, ndlp->vport->vpi, ndlp->nlp_DID,
+			ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
+
+	lpfc_fabric_abort_nport(ndlp);
 
 	/* First check the txq */
 	spin_lock_irq(&phba->hbalock);
@@ -198,15 +218,16 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
 	list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
 		/* Check to see if iocb matches the nport we are looking
 		   for */
-		if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp))
+		if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) {
 			lpfc_sli_issue_abort_iotag(phba, pring, iocb);
+		}
 	}
 	spin_unlock_irq(&phba->hbalock);
 
 	while (!list_empty(&completions)) {
 		iocb = list_get_first(&completions, struct lpfc_iocbq, list);
 		cmd = &iocb->iocb;
-		list_del(&iocb->list);
+		list_del_init(&iocb->list);
 
 		if (!iocb->iocb_cmpl)
 			lpfc_sli_release_iocbq(phba, iocb);
@@ -225,7 +246,7 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
 
 static int
 lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
-		      struct lpfc_iocbq *cmdiocb)
+	       struct lpfc_iocbq *cmdiocb)
 {
 	struct Scsi_Host   *shost = lpfc_shost_from_vport(vport);
 	struct lpfc_hba    *phba = vport->phba;
@@ -244,7 +265,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 		 * the FLOGI and resend it first.
 		 */
 		if (vport->fc_flag & FC_PT2PT) {
-			lpfc_els_abort_flogi(phba);
+			 lpfc_els_abort_flogi(phba);
 		        if (!(vport->fc_flag & FC_PT2PT_PLOGI)) {
 				/* If the other side is supposed to initiate
 				 * the PLOGI anyway, just ACC it now and
@@ -279,8 +300,8 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 
 	/* PLOGI chkparm OK */
 	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-			"%d:0114 PLOGI chkparm OK Data: x%x x%x x%x x%x\n",
-			phba->brd_no,
+			"%d (%d):0114 PLOGI chkparm OK Data: x%x x%x x%x x%x\n",
+			phba->brd_no, vport->vpi,
 			ndlp->nlp_DID, ndlp->nlp_state, ndlp->nlp_flag,
 			ndlp->nlp_rpi);
 
@@ -314,8 +335,8 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 		return 1;
 	}
 
-	if ((vport->fc_flag & FC_PT2PT)
-	    && !(vport->fc_flag & FC_PT2PT_PLOGI)) {
+	if ((vport->fc_flag & FC_PT2PT) &&
+	    !(vport->fc_flag & FC_PT2PT_PLOGI)) {
 		/* rcv'ed PLOGI decides what our NPortId will be */
 		vport->fc_myDID = icmd->un.rcvels.parmRo;
 		mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
@@ -327,7 +348,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 		rc = lpfc_sli_issue_mbox
 			(phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB));
 		if (rc == MBX_NOT_FINISHED) {
-			mempool_free( mbox, phba->mbox_mem_pool);
+			mempool_free(mbox, phba->mbox_mem_pool);
 			goto out;
 		}
 
@@ -337,8 +358,8 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 	if (!mbox)
 		goto out;
 
-	rc = lpfc_reg_login(phba, icmd->un.rcvels.remoteID, (uint8_t *) sp,
-			    mbox, 0);
+	rc = lpfc_reg_login(phba, vport->vpi, icmd->un.rcvels.remoteID,
+			    (uint8_t *) sp, mbox, 0);
 	if (rc) {
 		mempool_free(mbox, phba->mbox_mem_pool);
 		goto out;
@@ -415,7 +436,7 @@ lpfc_rcv_padisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 			lpfc_els_rsp_adisc_acc(vport, cmdiocb, ndlp);
 		} else {
 			lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp,
-				NULL, 0);
+					 NULL, 0);
 		}
 		return 1;
 	}
@@ -457,7 +478,7 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 		lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
 
 	if (!(ndlp->nlp_type & NLP_FABRIC) ||
-		(ndlp->nlp_state == NLP_STE_ADISC_ISSUE)) {
+	    (ndlp->nlp_state == NLP_STE_ADISC_ISSUE)) {
 		/* Only try to re-login if this is NOT a Fabric Node */
 		mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
 		spin_lock_irq(shost->host_lock);
@@ -499,8 +520,7 @@ lpfc_rcv_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 
 	ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR);
 	ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE;
-	if ((npr->acceptRspCode == PRLI_REQ_EXECUTED) &&
-	    (npr->prliType == PRLI_FCP_TYPE)) {
+	if (npr->prliType == PRLI_FCP_TYPE) {
 		if (npr->initiatorFunc)
 			ndlp->nlp_type |= NLP_FCP_INITIATOR;
 		if (npr->targetFunc)
@@ -526,15 +546,16 @@ lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
 	struct lpfc_hba  *phba = vport->phba;
 
 	/* Check config parameter use-adisc or FCP-2 */
-	if (phba->cfg_use_adisc == 0 &&
-	    (vport->fc_flag & FC_RSCN_MODE) == 0 &&
-	    (ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) == 0)
-			return 0;
-
-	spin_lock_irq(shost->host_lock);
-	ndlp->nlp_flag |= NLP_NPR_ADISC;
-	spin_unlock_irq(shost->host_lock);
-	return 1;
+	if ((phba->cfg_use_adisc && (vport->fc_flag & FC_RSCN_MODE)) ||
+	    ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) {
+		spin_lock_irq(shost->host_lock);
+		ndlp->nlp_flag |= NLP_NPR_ADISC;
+		spin_unlock_irq(shost->host_lock);
+		return 1;
+	}
+	ndlp->nlp_flag &= ~NLP_NPR_ADISC;
+	lpfc_unreg_rpi(vport, ndlp);
+	return 0;
 }
 
 static uint32_t
@@ -542,9 +563,9 @@ lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 		  void *arg, uint32_t evt)
 {
 	lpfc_printf_log(vport->phba, KERN_ERR, LOG_DISCOVERY,
-			"%d:0253 Illegal State Transition: node x%x event x%x, "
-			"state x%x Data: x%x x%x\n",
-			vport->phba->brd_no,
+			"%d (%d):0253 Illegal State Transition: node x%x "
+			"event x%x, state x%x Data: x%x x%x\n",
+			vport->phba->brd_no, vport->vpi,
 			ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi,
 			ndlp->nlp_flag);
 	return ndlp->nlp_state;
@@ -629,7 +650,7 @@ lpfc_rcv_plogi_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 	 */
 	phba->fc_stat.elsLogiCol++;
 	port_cmp = memcmp(&vport->fc_portname, &sp->portName,
-			  sizeof (struct lpfc_name));
+			  sizeof(struct lpfc_name));
 
 	if (port_cmp >= 0) {
 		/* Reject this request because the remote node will accept
@@ -644,13 +665,27 @@ lpfc_rcv_plogi_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 	return ndlp->nlp_state;
 }
 
+static uint32_t
+lpfc_rcv_prli_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+			  void *arg, uint32_t evt)
+{
+	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
+	struct ls_rjt     stat;
+
+	memset(&stat, 0, sizeof (struct ls_rjt));
+	stat.un.b.lsRjtRsnCode = LSRJT_LOGICAL_BSY;
+	stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
+	lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp);
+	return ndlp->nlp_state;
+}
+
 static uint32_t
 lpfc_rcv_logo_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 			  void *arg, uint32_t evt)
 {
 	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
 
-	/* software abort outstanding PLOGI */
+				/* software abort outstanding PLOGI */
 	lpfc_els_abort(vport->phba, ndlp);
 
 	lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO);
@@ -724,9 +759,9 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
 
 	/* PLOGI chkparm OK */
 	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-			"%d:0121 PLOGI chkparm OK "
+			"%d (%d):0121 PLOGI chkparm OK "
 			"Data: x%x x%x x%x x%x\n",
-			phba->brd_no,
+			phba->brd_no, vport->vpi,
 			ndlp->nlp_DID, ndlp->nlp_state,
 			ndlp->nlp_flag, ndlp->nlp_rpi);
 
@@ -748,13 +783,20 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
 		((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb;
 
 	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-	if (!mbox)
+	if (!mbox) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+			"%d (%d):0133 PLOGI: no memory for reg_login "
+			"Data: x%x x%x x%x x%x\n",
+			phba->brd_no, vport->vpi,
+			ndlp->nlp_DID, ndlp->nlp_state,
+			ndlp->nlp_flag, ndlp->nlp_rpi);
 		goto out;
+	}
 
 	lpfc_unreg_rpi(vport, ndlp);
 
-	if (lpfc_reg_login(phba, irsp->un.elsreq64.remoteID, (uint8_t *) sp,
-			   mbox, 0) == 0) {
+	if (lpfc_reg_login(phba, vport->vpi, irsp->un.elsreq64.remoteID,
+			   (uint8_t *) sp, mbox, 0) == 0) {
 		switch (ndlp->nlp_DID) {
 		case NameServer_DID:
 			mbox->mbox_cmpl = lpfc_mbx_cmpl_ns_reg_login;
@@ -775,16 +817,37 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
 			return ndlp->nlp_state;
 		}
 		lpfc_nlp_put(ndlp);
-		mp = (struct lpfc_dmabuf *)mbox->context1;
+		mp = (struct lpfc_dmabuf *) mbox->context1;
 		lpfc_mbuf_free(phba, mp->virt, mp->phys);
 		kfree(mp);
 		mempool_free(mbox, phba->mbox_mem_pool);
+
+		lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+			"%d (%d):0134 PLOGI: cannot issue reg_login "
+			"Data: x%x x%x x%x x%x\n",
+			phba->brd_no, vport->vpi,
+			ndlp->nlp_DID, ndlp->nlp_state,
+			ndlp->nlp_flag, ndlp->nlp_rpi);
 	} else {
 		mempool_free(mbox, phba->mbox_mem_pool);
+
+		lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+			"%d (%d):0135 PLOGI: cannot format reg_login "
+			"Data: x%x x%x x%x x%x\n",
+			phba->brd_no, vport->vpi,
+			ndlp->nlp_DID, ndlp->nlp_state,
+			ndlp->nlp_flag, ndlp->nlp_rpi);
 	}
 
 
- out:
+out:
+	if (ndlp->nlp_DID == NameServer_DID) {
+		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+		lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+			"%d (%d):0261 Cannot Register NameServer login\n",
+			phba->brd_no, vport->vpi);
+	}
+
 	/* Free this node since the driver cannot login or has the wrong
 	   sparm */
 	lpfc_drop_node(vport, ndlp);
@@ -820,12 +883,18 @@ lpfc_device_recov_plogi_issue(struct lpfc_vport *vport,
 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
 	struct lpfc_hba  *phba = vport->phba;
 
+	/* Don't do anything that will mess up processing of the
+	 * previous RSCN.
+	 */
+	if (vport->fc_flag & FC_RSCN_DEFERRED)
+		return ndlp->nlp_state;
+
 	/* software abort outstanding PLOGI */
 	lpfc_els_abort(phba, ndlp);
 
 	ndlp->nlp_prev_state = NLP_STE_PLOGI_ISSUE;
-	spin_lock_irq(shost->host_lock);
 	lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+	spin_lock_irq(shost->host_lock);
 	ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
 	spin_unlock_irq(shost->host_lock);
 
@@ -924,7 +993,7 @@ lpfc_cmpl_adisc_adisc_issue(struct lpfc_vport *vport,
 	irsp = &rspiocb->iocb;
 
 	if ((irsp->ulpStatus) ||
-	     (!lpfc_check_adisc(vport, ndlp, &ap->nodeName, &ap->portName))) {
+	    (!lpfc_check_adisc(vport, ndlp, &ap->nodeName, &ap->portName))) {
 		/* 1 sec timeout */
 		mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ);
 		spin_lock_irq(shost->host_lock);
@@ -980,6 +1049,12 @@ lpfc_device_recov_adisc_issue(struct lpfc_vport *vport,
 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
 	struct lpfc_hba  *phba = vport->phba;
 
+	/* Don't do anything that will mess up processing of the
+	 * previous RSCN.
+	 */
+	if (vport->fc_flag & FC_RSCN_DEFERRED)
+		return ndlp->nlp_state;
+
 	/* software abort outstanding ADISC */
 	lpfc_els_abort(phba, ndlp);
 
@@ -987,9 +1062,8 @@ lpfc_device_recov_adisc_issue(struct lpfc_vport *vport,
 	lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
 	spin_lock_irq(shost->host_lock);
 	ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
-	ndlp->nlp_flag |= NLP_NPR_ADISC;
 	spin_unlock_irq(shost->host_lock);
-
+	lpfc_disc_set_adisc(vport, ndlp);
 	return ndlp->nlp_state;
 }
 
@@ -1035,6 +1109,7 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_vport *vport,
 	if ((mb = phba->sli.mbox_active)) {
 		if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) &&
 		   (ndlp == (struct lpfc_nodelist *) mb->context2)) {
+			lpfc_nlp_put(ndlp);
 			mb->context2 = NULL;
 			mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
 		}
@@ -1049,6 +1124,7 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_vport *vport,
 				lpfc_mbuf_free(phba, mp->virt, mp->phys);
 				kfree(mp);
 			}
+			lpfc_nlp_put(ndlp);
 			list_del(&mb->list);
 			mempool_free(mb, phba->mbox_mem_pool);
 		}
@@ -1099,8 +1175,9 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport,
 	if (mb->mbxStatus) {
 		/* RegLogin failed */
 		lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
-				"%d:0246 RegLogin failed Data: x%x x%x x%x\n",
-				phba->brd_no,
+				"%d (%d):0246 RegLogin failed Data: x%x x%x "
+				"x%x\n",
+				phba->brd_no, vport->vpi,
 				did, mb->mbxStatus, vport->port_state);
 
 		/*
@@ -1167,11 +1244,18 @@ lpfc_device_recov_reglogin_issue(struct lpfc_vport *vport,
 {
 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
 
+	/* Don't do anything that will mess up processing of the
+	 * previous RSCN.
+	 */
+	if (vport->fc_flag & FC_RSCN_DEFERRED)
+		return ndlp->nlp_state;
+
 	ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
 	lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
 	spin_lock_irq(shost->host_lock);
 	ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
 	spin_unlock_irq(shost->host_lock);
+	lpfc_disc_set_adisc(vport, ndlp);
 	return ndlp->nlp_state;
 }
 
@@ -1239,6 +1323,7 @@ static uint32_t
 lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 			  void *arg, uint32_t evt)
 {
+	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
 	struct lpfc_iocbq *cmdiocb, *rspiocb;
 	struct lpfc_hba   *phba = vport->phba;
 	IOCB_t *irsp;
@@ -1267,29 +1352,45 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 		if (npr->Retry)
 			ndlp->nlp_fcp_info |= NLP_FCP_2_DEVICE;
 	}
+	if (!(ndlp->nlp_type & NLP_FCP_TARGET) &&
+	    (vport->port_type == LPFC_NPIV_PORT) &&
+	     phba->cfg_vport_restrict_login) {
+		spin_lock_irq(shost->host_lock);
+		ndlp->nlp_flag |= NLP_TARGET_REMOVE;
+		spin_unlock_irq(shost->host_lock);
+		lpfc_issue_els_logo(vport, ndlp, 0);
+
+		ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
+		lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
+		return ndlp->nlp_state;
+	}
 
 	ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
-	lpfc_nlp_set_state(vport, ndlp, NLP_STE_MAPPED_NODE);
+	if (ndlp->nlp_type & NLP_FCP_TARGET)
+		lpfc_nlp_set_state(vport, ndlp, NLP_STE_MAPPED_NODE);
+	else
+		lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
 	return ndlp->nlp_state;
 }
 
 /*! lpfc_device_rm_prli_issue
-  *
-  * \pre
-  * \post
-  * \param   phba
-  * \param   ndlp
-  * \param   arg
-  * \param   evt
-  * \return  uint32_t
-  *
-  * \b Description:
-  *    This routine is envoked when we a request to remove a nport we are in the
-  *    process of PRLIing. We should software abort outstanding prli, unreg
-  *    login, send a logout. We will change node state to UNUSED_NODE, put it
-  *    in plogi state so it can be freed when LOGO completes.
-  *
-  */
+ *
+ * \pre
+ * \post
+ * \param   phba
+ * \param   ndlp
+ * \param   arg
+ * \param   evt
+ * \return  uint32_t
+ *
+ * \b Description:
+ *    This routine is envoked when we a request to remove a nport we are in the
+ *    process of PRLIing. We should software abort outstanding prli, unreg
+ *    login, send a logout. We will change node state to UNUSED_NODE, put it
+ *    on plogi list so it can be freed when LOGO completes.
+ *
+ */
+
 static uint32_t
 lpfc_device_rm_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 			  void *arg, uint32_t evt)
@@ -1312,21 +1413,21 @@ lpfc_device_rm_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 
 
 /*! lpfc_device_recov_prli_issue
-  *
-  * \pre
-  * \post
-  * \param   phba
-  * \param   ndlp
-  * \param   arg
-  * \param   evt
-  * \return  uint32_t
-  *
-  * \b Description:
-  *    The routine is envoked when the state of a device is unknown, like
-  *    during a link down. We should remove the nodelist entry from the
-  *    unmapped list, issue a UNREG_LOGIN, do a software abort of the
-  *    outstanding PRLI command, then free the node entry.
-  */
+ *
+ * \pre
+ * \post
+ * \param   phba
+ * \param   ndlp
+ * \param   arg
+ * \param   evt
+ * \return  uint32_t
+ *
+ * \b Description:
+ *    The routine is envoked when the state of a device is unknown, like
+ *    during a link down. We should remove the nodelist entry from the
+ *    unmapped list, issue a UNREG_LOGIN, do a software abort of the
+ *    outstanding PRLI command, then free the node entry.
+ */
 static uint32_t
 lpfc_device_recov_prli_issue(struct lpfc_vport *vport,
 			     struct lpfc_nodelist *ndlp,
@@ -1336,6 +1437,12 @@ lpfc_device_recov_prli_issue(struct lpfc_vport *vport,
 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
 	struct lpfc_hba  *phba = vport->phba;
 
+	/* Don't do anything that will mess up processing of the
+	 * previous RSCN.
+	 */
+	if (vport->fc_flag & FC_RSCN_DEFERRED)
+		return ndlp->nlp_state;
+
 	/* software abort outstanding PRLI */
 	lpfc_els_abort(phba, ndlp);
 
@@ -1344,6 +1451,7 @@ lpfc_device_recov_prli_issue(struct lpfc_vport *vport,
 	spin_lock_irq(shost->host_lock);
 	ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
 	spin_unlock_irq(shost->host_lock);
+	lpfc_disc_set_adisc(vport, ndlp);
 	return ndlp->nlp_state;
 }
 
@@ -1466,7 +1574,7 @@ lpfc_rcv_prlo_mapped_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 
 	/* flush the target */
 	lpfc_sli_abort_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring],
-			       ndlp->nlp_sid, 0, 0, LPFC_CTX_TGT);
+			    ndlp->nlp_sid, 0, 0, LPFC_CTX_TGT);
 
 	/* Treat like rcv logo */
 	lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_PRLO);
@@ -1573,8 +1681,9 @@ lpfc_rcv_padisc_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 	 * here will affect the counting of discovery threads.
 	 */
 	if (!(ndlp->nlp_flag & NLP_DELAY_TMO) &&
-	    !(ndlp->nlp_flag & NLP_NPR_2B_DISC)){
+	    !(ndlp->nlp_flag & NLP_NPR_2B_DISC)) {
 		if (ndlp->nlp_flag & NLP_NPR_ADISC) {
+			ndlp->nlp_flag &= ~NLP_NPR_ADISC;
 			ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
 			lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE);
 			lpfc_issue_els_adisc(vport, ndlp, 0);
@@ -1719,6 +1828,12 @@ lpfc_device_recov_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 {
 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
 
+	/* Don't do anything that will mess up processing of the
+	 * previous RSCN.
+	 */
+	if (vport->fc_flag & FC_RSCN_DEFERRED)
+		return ndlp->nlp_state;
+
 	spin_lock_irq(shost->host_lock);
 	ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
 	spin_unlock_irq(shost->host_lock);
@@ -1803,7 +1918,7 @@ static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT])
 	lpfc_disc_illegal,		/* DEVICE_RECOVERY */
 
 	lpfc_rcv_plogi_plogi_issue,	/* RCV_PLOGI   PLOGI_ISSUE    */
-	lpfc_rcv_els_plogi_issue,	/* RCV_PRLI        */
+	lpfc_rcv_prli_plogi_issue,	/* RCV_PRLI        */
 	lpfc_rcv_logo_plogi_issue,	/* RCV_LOGO        */
 	lpfc_rcv_els_plogi_issue,	/* RCV_ADISC       */
 	lpfc_rcv_els_plogi_issue,	/* RCV_PDISC       */
@@ -1915,9 +2030,9 @@ lpfc_disc_state_machine(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 
 	/* DSM in event <evt> on NPort <nlp_DID> in state <cur_state> */
 	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-			"%d:0211 DSM in event x%x on NPort x%x in state %d "
-			"Data: x%x\n",
-			phba->brd_no,
+			"%d (%d):0211 DSM in event x%x on NPort x%x in "
+			"state %d Data: x%x\n",
+			phba->brd_no, vport->vpi,
 			evt, ndlp->nlp_DID, cur_state, ndlp->nlp_flag);
 
 	func = lpfc_disc_action[(cur_state * NLP_EVT_MAX_EVENT) + evt];
@@ -1925,9 +2040,10 @@ lpfc_disc_state_machine(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 
 	/* DSM out state <rc> on NPort <nlp_DID> */
 	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-		       "%d:0212 DSM out state %d on NPort x%x Data: x%x\n",
-		       phba->brd_no,
-		       rc, ndlp->nlp_DID, ndlp->nlp_flag);
+			"%d (%d):0212 DSM out state %d on NPort x%x "
+			"Data: x%x\n",
+			phba->brd_no, vport->vpi,
+			rc, ndlp->nlp_DID, ndlp->nlp_flag);
 
 	lpfc_nlp_put(ndlp);
 

+ 272 - 83
drivers/scsi/lpfc/lpfc_scsi.c

@@ -37,10 +37,159 @@
 #include "lpfc.h"
 #include "lpfc_logmsg.h"
 #include "lpfc_crtn.h"
+#include "lpfc_vport.h"
 
 #define LPFC_RESET_WAIT  2
 #define LPFC_ABORT_WAIT  2
 
+/*
+ * This function is called with no lock held when there is a resource
+ * error in driver or in firmware.
+ */
+void
+lpfc_adjust_queue_depth(struct lpfc_hba *phba)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&phba->hbalock, flags);
+	atomic_inc(&phba->num_rsrc_err);
+	phba->last_rsrc_error_time = jiffies;
+
+	if ((phba->last_ramp_down_time + QUEUE_RAMP_DOWN_INTERVAL) > jiffies) {
+		spin_unlock_irqrestore(&phba->hbalock, flags);
+		return;
+	}
+
+	phba->last_ramp_down_time = jiffies;
+
+	spin_unlock_irqrestore(&phba->hbalock, flags);
+
+	spin_lock_irqsave(&phba->pport->work_port_lock, flags);
+	if ((phba->pport->work_port_events &
+		WORKER_RAMP_DOWN_QUEUE) == 0) {
+		phba->pport->work_port_events |= WORKER_RAMP_DOWN_QUEUE;
+	}
+	spin_unlock_irqrestore(&phba->pport->work_port_lock, flags);
+
+	spin_lock_irqsave(&phba->hbalock, flags);
+	if (phba->work_wait)
+		wake_up(phba->work_wait);
+	spin_unlock_irqrestore(&phba->hbalock, flags);
+
+	return;
+}
+
+/*
+ * This function is called with no lock held when there is a successful
+ * SCSI command completion.
+ */
+static inline void
+lpfc_rampup_queue_depth(struct lpfc_hba *phba,
+			struct scsi_device *sdev)
+{
+	unsigned long flags;
+	atomic_inc(&phba->num_cmd_success);
+
+	if (phba->cfg_lun_queue_depth <= sdev->queue_depth)
+		return;
+
+	spin_lock_irqsave(&phba->hbalock, flags);
+	if (((phba->last_ramp_up_time + QUEUE_RAMP_UP_INTERVAL) > jiffies) ||
+	 ((phba->last_rsrc_error_time + QUEUE_RAMP_UP_INTERVAL ) > jiffies)) {
+		spin_unlock_irqrestore(&phba->hbalock, flags);
+		return;
+	}
+
+	phba->last_ramp_up_time = jiffies;
+	spin_unlock_irqrestore(&phba->hbalock, flags);
+
+	spin_lock_irqsave(&phba->pport->work_port_lock, flags);
+	if ((phba->pport->work_port_events &
+		WORKER_RAMP_UP_QUEUE) == 0) {
+		phba->pport->work_port_events |= WORKER_RAMP_UP_QUEUE;
+	}
+	spin_unlock_irqrestore(&phba->pport->work_port_lock, flags);
+
+	spin_lock_irqsave(&phba->hbalock, flags);
+	if (phba->work_wait)
+		wake_up(phba->work_wait);
+	spin_unlock_irqrestore(&phba->hbalock, flags);
+}
+
+void
+lpfc_ramp_down_queue_handler(struct lpfc_hba *phba)
+{
+	struct lpfc_vport *vport;
+	struct Scsi_Host  *host;
+	struct scsi_device *sdev;
+	unsigned long new_queue_depth;
+	unsigned long num_rsrc_err, num_cmd_success;
+
+	num_rsrc_err = atomic_read(&phba->num_rsrc_err);
+	num_cmd_success = atomic_read(&phba->num_cmd_success);
+
+	spin_lock_irq(&phba->hbalock);
+	list_for_each_entry(vport, &phba->port_list, listentry) {
+		host = lpfc_shost_from_vport(vport);
+		if (!scsi_host_get(host))
+			continue;
+
+		spin_unlock_irq(&phba->hbalock);
+
+		shost_for_each_device(sdev, host) {
+			new_queue_depth = sdev->queue_depth * num_rsrc_err /
+			(num_rsrc_err + num_cmd_success);
+			if (!new_queue_depth)
+				new_queue_depth = sdev->queue_depth - 1;
+			else
+				new_queue_depth =
+					sdev->queue_depth - new_queue_depth;
+
+			if (sdev->ordered_tags)
+				scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
+					new_queue_depth);
+			else
+				scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG,
+					new_queue_depth);
+		}
+		spin_lock_irq(&phba->hbalock);
+		scsi_host_put(host);
+	}
+	spin_unlock_irq(&phba->hbalock);
+	atomic_set(&phba->num_rsrc_err, 0);
+	atomic_set(&phba->num_cmd_success, 0);
+}
+
+void
+lpfc_ramp_up_queue_handler(struct lpfc_hba *phba)
+{
+	struct lpfc_vport *vport;
+	struct Scsi_Host  *host;
+	struct scsi_device *sdev;
+
+	spin_lock_irq(&phba->hbalock);
+	list_for_each_entry(vport, &phba->port_list, listentry) {
+		host = lpfc_shost_from_vport(vport);
+		if (!scsi_host_get(host))
+			continue;
+
+		spin_unlock_irq(&phba->hbalock);
+		shost_for_each_device(sdev, host) {
+			if (sdev->ordered_tags)
+				scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
+					sdev->queue_depth+1);
+			else
+				scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG,
+					sdev->queue_depth+1);
+		}
+		spin_lock_irq(&phba->hbalock);
+		scsi_host_put(host);
+	}
+	spin_unlock_irq(&phba->hbalock);
+	atomic_set(&phba->num_rsrc_err, 0);
+	atomic_set(&phba->num_cmd_success, 0);
+}
+
 /*
  * This routine allocates a scsi buffer, which contains all the necessary
  * information needed to initiate a SCSI I/O.  The non-DMAable buffer region
@@ -154,7 +303,7 @@ lpfc_get_scsi_buf(struct lpfc_hba * phba)
 }
 
 static void
-lpfc_release_scsi_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * psb)
+lpfc_release_scsi_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb)
 {
 	unsigned long iflag = 0;
 
@@ -165,13 +314,16 @@ lpfc_release_scsi_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * psb)
 }
 
 static int
-lpfc_scsi_prep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * lpfc_cmd)
+lpfc_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
 {
 	struct scsi_cmnd *scsi_cmnd = lpfc_cmd->pCmd;
 	struct scatterlist *sgel = NULL;
 	struct fcp_cmnd *fcp_cmnd = lpfc_cmd->fcp_cmnd;
 	struct ulp_bde64 *bpl = lpfc_cmd->fcp_bpl;
 	IOCB_t *iocb_cmd = &lpfc_cmd->cur_iocbq.iocb;
+	uint32_t vpi = (lpfc_cmd->cur_iocbq.vport
+			? lpfc_cmd->cur_iocbq.vport->vpi
+			: 0);
 	dma_addr_t physaddr;
 	uint32_t i, num_bde = 0;
 	int datadir = scsi_cmnd->sc_data_direction;
@@ -235,9 +387,9 @@ lpfc_scsi_prep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * lpfc_cmd)
 		dma_error = dma_mapping_error(physaddr);
 		if (dma_error) {
 			lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
-				"%d:0718 Unable to dma_map_single "
-				"request_buffer: x%x\n",
-				phba->brd_no, dma_error);
+					"%d (%d):0718 Unable to dma_map_single "
+					"request_buffer: x%x\n",
+					phba->brd_no, vpi, dma_error);
 			return 1;
 		}
 
@@ -299,6 +451,7 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
 	struct fcp_rsp *fcprsp = lpfc_cmd->fcp_rsp;
 	struct lpfc_hba *phba = vport->phba;
 	uint32_t fcpi_parm = rsp_iocb->iocb.un.fcpi.fcpi_parm;
+	uint32_t vpi = vport->vpi;
 	uint32_t resp_info = fcprsp->rspStatus2;
 	uint32_t scsi_status = fcprsp->rspStatus3;
 	uint32_t *lp;
@@ -331,9 +484,9 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
 		logit = LOG_FCP;
 
 	lpfc_printf_log(phba, KERN_WARNING, logit,
-			"%d:0730 FCP command x%x failed: x%x SNS x%x x%x "
+			"%d (%d):0730 FCP command x%x failed: x%x SNS x%x x%x "
 			"Data: x%x x%x x%x x%x x%x\n",
-			phba->brd_no, cmnd->cmnd[0], scsi_status,
+			phba->brd_no, vpi, cmnd->cmnd[0], scsi_status,
 			be32_to_cpu(*lp), be32_to_cpu(*(lp + 3)), resp_info,
 			be32_to_cpu(fcprsp->rspResId),
 			be32_to_cpu(fcprsp->rspSnsLen),
@@ -354,10 +507,11 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
 		cmnd->resid = be32_to_cpu(fcprsp->rspResId);
 
 		lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
-				"%d:0716 FCP Read Underrun, expected %d, "
-				"residual %d Data: x%x x%x x%x\n", phba->brd_no,
-				be32_to_cpu(fcpcmd->fcpDl), cmnd->resid,
-				fcpi_parm, cmnd->cmnd[0], cmnd->underflow);
+				"%d (%d):0716 FCP Read Underrun, expected %d, "
+				"residual %d Data: x%x x%x x%x\n",
+				phba->brd_no, vpi, be32_to_cpu(fcpcmd->fcpDl),
+				cmnd->resid, fcpi_parm, cmnd->cmnd[0],
+				cmnd->underflow);
 
 		/*
 		 * If there is an under run check if under run reported by
@@ -368,12 +522,12 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
 			fcpi_parm &&
 			(cmnd->resid != fcpi_parm)) {
 			lpfc_printf_log(phba, KERN_WARNING,
-				LOG_FCP | LOG_FCP_ERROR,
-				"%d:0735 FCP Read Check Error and Underrun "
-				"Data: x%x x%x x%x x%x\n", phba->brd_no,
-				be32_to_cpu(fcpcmd->fcpDl),
-				cmnd->resid,
-				fcpi_parm, cmnd->cmnd[0]);
+					LOG_FCP | LOG_FCP_ERROR,
+					"%d (%d):0735 FCP Read Check Error "
+					"and Underrun Data: x%x x%x x%x x%x\n",
+					phba->brd_no, vpi,
+					be32_to_cpu(fcpcmd->fcpDl),
+					cmnd->resid, fcpi_parm, cmnd->cmnd[0]);
 			cmnd->resid = cmnd->request_bufflen;
 			host_status = DID_ERROR;
 		}
@@ -387,19 +541,20 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
 		    (scsi_status == SAM_STAT_GOOD) &&
 		    (cmnd->request_bufflen - cmnd->resid) < cmnd->underflow) {
 			lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
-					"%d:0717 FCP command x%x residual "
+					"%d (%d):0717 FCP command x%x residual "
 					"underrun converted to error "
-					"Data: x%x x%x x%x\n", phba->brd_no,
-					cmnd->cmnd[0], cmnd->request_bufflen,
-					cmnd->resid, cmnd->underflow);
+					"Data: x%x x%x x%x\n",
+					phba->brd_no, vpi, cmnd->cmnd[0],
+					cmnd->request_bufflen, cmnd->resid,
+					cmnd->underflow);
 
 			host_status = DID_ERROR;
 		}
 	} else if (resp_info & RESID_OVER) {
 		lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
-				"%d:0720 FCP command x%x residual "
+				"%d (%d):0720 FCP command x%x residual "
 				"overrun error. Data: x%x x%x \n",
-				phba->brd_no, cmnd->cmnd[0],
+				phba->brd_no, vpi, cmnd->cmnd[0],
 				cmnd->request_bufflen, cmnd->resid);
 		host_status = DID_ERROR;
 
@@ -410,11 +565,12 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
 	} else if ((scsi_status == SAM_STAT_GOOD) && fcpi_parm &&
 			(cmnd->sc_data_direction == DMA_FROM_DEVICE)) {
 		lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_FCP_ERROR,
-			"%d:0734 FCP Read Check Error Data: "
-			"x%x x%x x%x x%x\n", phba->brd_no,
-			be32_to_cpu(fcpcmd->fcpDl),
-			be32_to_cpu(fcprsp->rspResId),
-			fcpi_parm, cmnd->cmnd[0]);
+				"%d (%d):0734 FCP Read Check Error Data: "
+				"x%x x%x x%x x%x\n",
+				phba->brd_no, vpi,
+				be32_to_cpu(fcpcmd->fcpDl),
+				be32_to_cpu(fcprsp->rspResId),
+				fcpi_parm, cmnd->cmnd[0]);
 		host_status = DID_ERROR;
 		cmnd->resid = cmnd->request_bufflen;
 	}
@@ -433,6 +589,9 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
 	struct lpfc_rport_data *rdata = lpfc_cmd->rdata;
 	struct lpfc_nodelist *pnode = rdata->pnode;
 	struct scsi_cmnd *cmd = lpfc_cmd->pCmd;
+	uint32_t vpi = (lpfc_cmd->cur_iocbq.vport
+			? lpfc_cmd->cur_iocbq.vport->vpi
+			: 0);
 	int result;
 	struct scsi_device *sdev, *tmp_sdev;
 	int depth = 0;
@@ -448,11 +607,13 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
 			lpfc_cmd->status = IOSTAT_DEFAULT;
 
 		lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
-				"%d:0729 FCP cmd x%x failed <%d/%d> status: "
-				"x%x result: x%x Data: x%x x%x\n",
-				phba->brd_no, cmd->cmnd[0], cmd->device->id,
-				cmd->device->lun, lpfc_cmd->status,
-				lpfc_cmd->result, pIocbOut->iocb.ulpContext,
+				"%d (%d):0729 FCP cmd x%x failed <%d/%d> "
+				"status: x%x result: x%x Data: x%x x%x\n",
+				phba->brd_no, vpi, cmd->cmnd[0],
+				cmd->device ? cmd->device->id : 0xffff,
+				cmd->device ? cmd->device->lun : 0xffff,
+				lpfc_cmd->status, lpfc_cmd->result,
+				pIocbOut->iocb.ulpContext,
 				lpfc_cmd->cur_iocbq.iocb.ulpIoTag);
 
 		switch (lpfc_cmd->status) {
@@ -464,6 +625,13 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
 		case IOSTAT_FABRIC_BSY:
 			cmd->result = ScsiResult(DID_BUS_BUSY, 0);
 			break;
+		case IOSTAT_LOCAL_REJECT:
+			if (lpfc_cmd->result == RJT_UNAVAIL_PERM ||
+			    lpfc_cmd->result == IOERR_NO_RESOURCES ||
+			    lpfc_cmd->result == RJT_LOGIN_REQUIRED) {
+				cmd->result = ScsiResult(DID_REQUEUE, 0);
+			break;
+		} /* else: fall through */
 		default:
 			cmd->result = ScsiResult(DID_ERROR, 0);
 			break;
@@ -480,9 +648,9 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
 		uint32_t *lp = (uint32_t *)cmd->sense_buffer;
 
 		lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
-				"%d:0710 Iodone <%d/%d> cmd %p, error x%x "
-				"SNS x%x x%x Data: x%x x%x\n",
-				phba->brd_no, cmd->device->id,
+				"%d (%d):0710 Iodone <%d/%d> cmd %p, error "
+				"x%x SNS x%x x%x Data: x%x x%x\n",
+				phba->brd_no, vpi, cmd->device->id,
 				cmd->device->lun, cmd, cmd->result,
 				*lp, *(lp + 3), cmd->retries, cmd->resid);
 	}
@@ -497,6 +665,10 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
 		return;
 	}
 
+
+	if (!result)
+		lpfc_rampup_queue_depth(phba, sdev);
+
 	if (!result && pnode != NULL &&
 	   ((jiffies - pnode->last_ramp_up_time) >
 		LPFC_Q_RAMP_UP_INTERVAL * HZ) &&
@@ -545,8 +717,9 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
 
 		if (depth) {
 			lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
-				"%d:0711 detected queue full - lun queue depth "
-				" adjusted to %d.\n", phba->brd_no, depth);
+					"%d (%d):0711 detected queue full - "
+					"lun queue depth  adjusted to %d.\n",
+					phba->brd_no, vpi, depth);
 		}
 	}
 
@@ -733,10 +906,10 @@ lpfc_scsi_tgt_reset(struct lpfc_scsi_buf *lpfc_cmd, struct lpfc_vport *vport,
 
 	/* Issue Target Reset to TGT <num> */
 	lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
-			"%d:0702 Issue Target Reset to TGT %d "
+			"%d (%d):0702 Issue Target Reset to TGT %d "
 			"Data: x%x x%x\n",
-			phba->brd_no, tgt_id, rdata->pnode->nlp_rpi,
-			rdata->pnode->nlp_flag);
+			phba->brd_no, vport->vpi, tgt_id,
+			rdata->pnode->nlp_rpi, rdata->pnode->nlp_flag);
 
 	ret = lpfc_sli_issue_iocb_wait(phba,
 				       &phba->sli.ring[phba->sli.fcp_ring],
@@ -842,9 +1015,12 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
 	}
 	lpfc_cmd = lpfc_get_scsi_buf(phba);
 	if (lpfc_cmd == NULL) {
+		lpfc_adjust_queue_depth(phba);
+
 		lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
-				"%d:0707 driver's buffer pool is empty, "
-				"IO busied\n", phba->brd_no);
+				"%d (%d):0707 driver's buffer pool is empty, "
+				"IO busied\n",
+				phba->brd_no, vport->vpi);
 		goto out_host_busy;
 	}
 
@@ -865,7 +1041,7 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
 	lpfc_scsi_prep_cmnd(vport, lpfc_cmd, ndlp);
 
 	err = lpfc_sli_issue_iocb(phba, &phba->sli.ring[psli->fcp_ring],
-				&lpfc_cmd->cur_iocbq, SLI_IOCB_RET_IOCB);
+				  &lpfc_cmd->cur_iocbq, SLI_IOCB_RET_IOCB);
 	if (err)
 		goto out_host_busy_free_buf;
 
@@ -986,18 +1162,19 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
 	if (lpfc_cmd->pCmd == cmnd) {
 		ret = FAILED;
 		lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
-				"%d:0748 abort handler timed out waiting for "
-				"abort to complete: ret %#x, ID %d, LUN %d, "
-				"snum %#lx\n",
-				phba->brd_no,  ret, cmnd->device->id,
-				cmnd->device->lun, cmnd->serial_number);
+				"%d (%d):0748 abort handler timed out waiting "
+				"for abort to complete: ret %#x, ID %d, "
+				"LUN %d, snum %#lx\n",
+				phba->brd_no, vport->vpi, ret,
+				cmnd->device->id, cmnd->device->lun,
+				cmnd->serial_number);
 	}
 
  out:
 	lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
-			"%d:0749 SCSI Layer I/O Abort Request "
+			"%d (%d):0749 SCSI Layer I/O Abort Request "
 			"Status x%x ID %d LUN %d snum %#lx\n",
-			phba->brd_no, ret, cmnd->device->id,
+			phba->brd_no, vport->vpi, ret, cmnd->device->id,
 			cmnd->device->lun, cmnd->serial_number);
 
 	return ret;
@@ -1024,7 +1201,7 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd)
 	 * If target is not in a MAPPED state, delay the reset until
 	 * target is rediscovered or devloss timeout expires.
 	 */
-	while ( 1 ) {
+	while (1) {
 		if (!pnode)
 			goto out;
 
@@ -1035,9 +1212,10 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd)
 			if (!rdata ||
 				(loopcnt > ((phba->cfg_devloss_tmo * 2) + 1))) {
 				lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
-		   			"%d:0721 LUN Reset rport failure:"
-					" cnt x%x rdata x%p\n",
-		   			phba->brd_no, loopcnt, rdata);
+						"%d (%d):0721 LUN Reset rport "
+						"failure: cnt x%x rdata x%p\n",
+						phba->brd_no, vport->vpi,
+						loopcnt, rdata);
 				goto out;
 			}
 			pnode = rdata->pnode;
@@ -1068,8 +1246,9 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd)
 		goto out_free_scsi_buf;
 
 	lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
-			"%d:0703 Issue target reset to TGT %d LUN %d rpi x%x "
-			"nlp_flag x%x\n", phba->brd_no, cmnd->device->id,
+			"%d (%d):0703 Issue target reset to TGT %d LUN %d "
+			"rpi x%x nlp_flag x%x\n",
+			phba->brd_no, vport->vpi, cmnd->device->id,
 			cmnd->device->lun, pnode->nlp_rpi, pnode->nlp_flag);
 
 	iocb_status = lpfc_sli_issue_iocb_wait(phba,
@@ -1103,7 +1282,7 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd)
 				    cmnd->device->id, cmnd->device->lun,
 				    0, LPFC_CTX_LUN);
 	loopcnt = 0;
-	while (cnt) {
+	while(cnt) {
 		schedule_timeout_uninterruptible(LPFC_RESET_WAIT*HZ);
 
 		if (++loopcnt
@@ -1118,8 +1297,9 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd)
 
 	if (cnt) {
 		lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
-			"%d:0719 device reset I/O flush failure: cnt x%x\n",
-			phba->brd_no, cnt);
+				"%d (%d):0719 device reset I/O flush failure: "
+				"cnt x%x\n",
+				phba->brd_no, vport->vpi, cnt);
 		ret = FAILED;
 	}
 
@@ -1128,10 +1308,10 @@ out_free_scsi_buf:
 		lpfc_release_scsi_buf(phba, lpfc_cmd);
 	}
 	lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
-			"%d:0713 SCSI layer issued device reset (%d, %d) "
+			"%d (%d):0713 SCSI layer issued device reset (%d, %d) "
 			"return x%x status x%x result x%x\n",
-			phba->brd_no, cmnd->device->id, cmnd->device->lun,
-			ret, cmd_status, cmd_result);
+			phba->brd_no, vport->vpi, cmnd->device->id,
+			cmnd->device->lun, ret, cmd_status, cmd_result);
 
 out:
 	return ret;
@@ -1184,8 +1364,9 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd)
 					  ndlp->rport->dd_data);
 		if (ret != SUCCESS) {
 			lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
-				"%d:0700 Bus Reset on target %d failed\n",
-				phba->brd_no, i);
+					"%d (%d):0700 Bus Reset on target %d "
+					"failed\n",
+					phba->brd_no, vport->vpi, i);
 			err_count++;
 			break;
 		}
@@ -1210,7 +1391,7 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd)
 		lpfc_sli_abort_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring],
 				    0, 0, 0, LPFC_CTX_HOST);
 	loopcnt = 0;
-	while (cnt) {
+	while(cnt) {
 		schedule_timeout_uninterruptible(LPFC_RESET_WAIT*HZ);
 
 		if (++loopcnt
@@ -1224,16 +1405,15 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd)
 
 	if (cnt) {
 		lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
-		   "%d:0715 Bus Reset I/O flush failure: cnt x%x left x%x\n",
-		   phba->brd_no, cnt, i);
+				"%d (%d):0715 Bus Reset I/O flush failure: "
+				"cnt x%x left x%x\n",
+				phba->brd_no, vport->vpi, cnt, i);
 		ret = FAILED;
 	}
 
-	lpfc_printf_log(phba,
-			KERN_ERR,
-			LOG_FCP,
-			"%d:0714 SCSI layer issued Bus Reset Data: x%x\n",
-			phba->brd_no, ret);
+	lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
+			"%d (%d):0714 SCSI layer issued Bus Reset Data: x%x\n",
+			phba->brd_no, vport->vpi, ret);
 out:
 	return ret;
 }
@@ -1263,17 +1443,24 @@ lpfc_slave_alloc(struct scsi_device *sdev)
 	 */
 	total = phba->total_scsi_bufs;
 	num_to_alloc = phba->cfg_lun_queue_depth + 2;
-	if (total >= phba->cfg_hba_queue_depth) {
+
+	/* Allow some exchanges to be available always to complete discovery */
+	if (total >= phba->cfg_hba_queue_depth - LPFC_DISC_IOCB_BUFF_COUNT ) {
 		lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
-				"%d:0704 At limitation of %d preallocated "
-				"command buffers\n", phba->brd_no, total);
+				"%d (%d):0704 At limitation of %d "
+				"preallocated command buffers\n",
+				phba->brd_no, vport->vpi, total);
 		return 0;
-	} else if (total + num_to_alloc > phba->cfg_hba_queue_depth) {
+
+	/* Allow some exchanges to be available always to complete discovery */
+	} else if (total + num_to_alloc >
+		phba->cfg_hba_queue_depth - LPFC_DISC_IOCB_BUFF_COUNT ) {
 		lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
-				"%d:0705 Allocation request of %d command "
-				"buffers will exceed max of %d.  Reducing "
-				"allocation request to %d.\n", phba->brd_no,
-				num_to_alloc, phba->cfg_hba_queue_depth,
+				"%d (%d):0705 Allocation request of %d "
+				"command buffers will exceed max of %d.  "
+				"Reducing allocation request to %d.\n",
+				phba->brd_no, vport->vpi, num_to_alloc,
+				phba->cfg_hba_queue_depth,
 				(phba->cfg_hba_queue_depth - total));
 		num_to_alloc = phba->cfg_hba_queue_depth - total;
 	}
@@ -1282,8 +1469,9 @@ lpfc_slave_alloc(struct scsi_device *sdev)
 		scsi_buf = lpfc_new_scsi_buf(vport);
 		if (!scsi_buf) {
 			lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
-					"%d:0706 Failed to allocate command "
-					"buffer\n", phba->brd_no);
+					"%d (%d):0706 Failed to allocate "
+					"command buffer\n",
+					phba->brd_no, vport->vpi);
 			break;
 		}
 
@@ -1331,6 +1519,7 @@ lpfc_slave_destroy(struct scsi_device *sdev)
 	return;
 }
 
+
 struct scsi_host_template lpfc_template = {
 	.module			= THIS_MODULE,
 	.name			= LPFC_DRIVER_NAME,

文件差异内容过多而无法显示
+ 284 - 323
drivers/scsi/lpfc/lpfc_sli.c


+ 10 - 7
drivers/scsi/lpfc/lpfc_sli.h

@@ -44,6 +44,7 @@ struct lpfc_iocbq {
 #define LPFC_IO_WAKE		2	/* High Priority Queue signal flag */
 #define LPFC_IO_FCP		4	/* FCP command -- iocbq in scsi_buf */
 #define LPFC_DRIVER_ABORTED	8	/* driver aborted this request */
+#define LPFC_IO_FABRIC		0x10	/* Iocb send using fabric scheduler */
 
 	uint8_t abort_count;
 	uint8_t rsvd2;
@@ -58,6 +59,8 @@ struct lpfc_iocbq {
 		struct lpfcMboxq   *mbox;
 	} context_un;
 
+	void (*fabric_iocb_cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
+			   struct lpfc_iocbq *);
 	void (*iocb_cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
 			   struct lpfc_iocbq *);
 
@@ -173,7 +176,7 @@ struct lpfc_sli_ring {
 /* Structure used for configuring rings to a specific profile or rctl / type */
 struct lpfc_hbq_init {
 	uint32_t rn;		/* Receive buffer notification */
-	uint32_t entry_count;	/* # of entries in HBQ */
+	uint32_t entry_count;	/* max # of entries in HBQ */
 	uint32_t headerLen;	/* 0 if not profile 4 or 5 */
 	uint32_t logEntry;	/* Set to 1 if this HBQ used for LogEntry */
 	uint32_t profile;	/* Selection profile 0=all, 7=logentry */
@@ -188,6 +191,11 @@ struct lpfc_hbq_init {
 	uint32_t cmdmatch[8];
 	uint32_t mask_count;	/* number of mask entries in prt array */
 	struct hbq_mask hbqMasks[6];
+
+	/* Non-config rings fields to keep track of buffer allocations */
+	uint32_t buffer_count;	/* number of buffers allocated */
+	uint32_t init_count;	/* number to allocate when initialized */
+	uint32_t add_count;	/* number to allocate when starved */
 } ;
 
 #define LPFC_MAX_HBQ 16
@@ -238,6 +246,7 @@ struct lpfc_sli {
 	uint16_t mboxq_cnt;	/* current length of queue */
 	uint16_t mboxq_max;	/* max length */
 	LPFC_MBOXQ_t *mbox_active;	/* active mboxq information */
+	struct list_head mboxq_cmpl;
 
 	struct timer_list mbox_tmo;	/* Hold clk to timeout active mbox
 					   cmd */
@@ -250,12 +259,6 @@ struct lpfc_sli {
 	struct lpfc_lnk_stat lnk_stat_offsets;
 };
 
-/* 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 */
 #define LPFC_MBOX_TMO_FLASH_CMD 300     /* Sec tmo for outstanding FLASH write

+ 1 - 1
drivers/scsi/lpfc/lpfc_version.h

@@ -18,7 +18,7 @@
  * included with this package.                                     *
  *******************************************************************/
 
-#define LPFC_DRIVER_VERSION "8.1.12_sli3"
+#define LPFC_DRIVER_VERSION "8.2.0"
 
 #define LPFC_DRIVER_NAME "lpfc"
 

+ 508 - 0
drivers/scsi/lpfc/lpfc_vport.c

@@ -0,0 +1,508 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for         *
+ * Fibre Channel Host Bus Adapters.                                *
+ * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * EMULEX and SLI are trademarks of Emulex.                        *
+ * www.emulex.com                                                  *
+ * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
+ *                                                                 *
+ * This program is free software; you can redistribute it and/or   *
+ * modify it under the terms of version 2 of the GNU General       *
+ * Public License as published by the Free Software Foundation.    *
+ * This program is distributed in the hope that it will be useful. *
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
+ * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
+ * more details, a copy of which can be found in the file COPYING  *
+ * included with this package.                                     *
+ *******************************************************************/
+
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/idr.h>
+#include <linux/interrupt.h>
+#include <linux/kthread.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport_fc.h>
+#include "lpfc_hw.h"
+#include "lpfc_sli.h"
+#include "lpfc_disc.h"
+#include "lpfc_scsi.h"
+#include "lpfc.h"
+#include "lpfc_logmsg.h"
+#include "lpfc_crtn.h"
+#include "lpfc_version.h"
+#include "lpfc_vport.h"
+
+inline void lpfc_vport_set_state(struct lpfc_vport *vport,
+				 enum fc_vport_state new_state)
+{
+	struct fc_vport *fc_vport = vport->fc_vport;
+
+	if (fc_vport) {
+		/*
+		 * When the transport defines fc_vport_set state we will replace
+		 * this code with the following line
+		 */
+		/* fc_vport_set_state(fc_vport, new_state); */
+		if (new_state != FC_VPORT_INITIALIZING)
+			fc_vport->vport_last_state = fc_vport->vport_state;
+		fc_vport->vport_state = new_state;
+	}
+
+	/* for all the error states we will set the invternal state to FAILED */
+	switch (new_state) {
+	case FC_VPORT_NO_FABRIC_SUPP:
+	case FC_VPORT_NO_FABRIC_RSCS:
+	case FC_VPORT_FABRIC_LOGOUT:
+	case FC_VPORT_FABRIC_REJ_WWN:
+	case FC_VPORT_FAILED:
+		vport->port_state = LPFC_VPORT_FAILED;
+		break;
+	case FC_VPORT_LINKDOWN:
+		vport->port_state = LPFC_VPORT_UNKNOWN;
+		break;
+	default:
+		/* do nothing */
+		break;
+	}
+}
+
+static int
+lpfc_alloc_vpi(struct lpfc_hba *phba)
+{
+	int  vpi;
+
+	spin_lock_irq(&phba->hbalock);
+	vpi = find_next_zero_bit(phba->vpi_bmask, phba->max_vpi, 1);
+	if (vpi > phba->max_vpi)
+		vpi = 0;
+	else
+		set_bit(vpi, phba->vpi_bmask);
+	spin_unlock_irq(&phba->hbalock);
+	return vpi;
+}
+
+static void
+lpfc_free_vpi(struct lpfc_hba *phba, int vpi)
+{
+	spin_lock_irq(&phba->hbalock);
+	clear_bit(vpi, phba->vpi_bmask);
+	spin_unlock_irq(&phba->hbalock);
+}
+
+static int
+lpfc_vport_sparm(struct lpfc_hba *phba, struct lpfc_vport *vport)
+{
+	LPFC_MBOXQ_t *pmb;
+	MAILBOX_t *mb;
+	struct lpfc_dmabuf *mp;
+	int  rc;
+
+	pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (!pmb) {
+		return -ENOMEM;
+	}
+	mb = &pmb->mb;
+
+	lpfc_read_sparam(phba, pmb, vport->vpi);
+	/*
+	 * Grab buffer pointer and clear context1 so we can use
+	 * lpfc_sli_issue_box_wait
+	 */
+	mp = (struct lpfc_dmabuf *) pmb->context1;
+	pmb->context1 = NULL;
+
+	pmb->vport = vport;
+	rc = lpfc_sli_issue_mbox_wait(phba, pmb, phba->fc_ratov * 2);
+	if (rc != MBX_SUCCESS) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT,
+				"%d (%d):1818 VPort failed init, mbxCmd x%x "
+				"READ_SPARM mbxStatus x%x, rc = x%x\n",
+				phba->brd_no, vport->vpi,
+				mb->mbxCommand, mb->mbxStatus, rc);
+		lpfc_mbuf_free(phba, mp->virt, mp->phys);
+		kfree(mp);
+		mempool_free(pmb, phba->mbox_mem_pool);
+		return -EIO;
+	}
+
+	memcpy(&vport->fc_sparam, mp->virt, sizeof (struct serv_parm));
+	memcpy(&vport->fc_nodename, &vport->fc_sparam.nodeName,
+	       sizeof (struct lpfc_name));
+	memcpy(&vport->fc_portname, &vport->fc_sparam.portName,
+	       sizeof (struct lpfc_name));
+
+	lpfc_mbuf_free(phba, mp->virt, mp->phys);
+	kfree(mp);
+	mempool_free(pmb, phba->mbox_mem_pool);
+
+	return 0;
+}
+
+static int
+lpfc_valid_wwn_format(struct lpfc_hba *phba, struct lpfc_name *wwn,
+		      const char *name_type)
+{
+				/* ensure that IEEE format 1 addresses
+				 * contain zeros in bits 59-48
+				 */
+	if (!((wwn->u.wwn[0] >> 4) == 1 &&
+	      ((wwn->u.wwn[0] & 0xf) != 0 || (wwn->u.wwn[1] & 0xf) != 0)))
+		return 1;
+
+	lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
+			"%d:1822 Invalid %s: %02x:%02x:%02x:%02x:"
+			"%02x:%02x:%02x:%02x\n",
+			phba->brd_no, name_type,
+			wwn->u.wwn[0], wwn->u.wwn[1],
+			wwn->u.wwn[2], wwn->u.wwn[3],
+			wwn->u.wwn[4], wwn->u.wwn[5],
+			wwn->u.wwn[6], wwn->u.wwn[7]);
+	return 0;
+}
+
+static int
+lpfc_unique_wwpn(struct lpfc_hba *phba, struct lpfc_vport *new_vport)
+{
+	struct lpfc_vport *vport;
+
+	list_for_each_entry(vport, &phba->port_list, listentry) {
+		if (vport == new_vport)
+			continue;
+		/* If they match, return not unique */
+		if (memcmp(&vport->fc_sparam.portName,
+			&new_vport->fc_sparam.portName,
+			sizeof(struct lpfc_name)) == 0)
+			return 0;
+	}
+	return 1;
+}
+
+int
+lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
+{
+	struct lpfc_nodelist *ndlp;
+	struct lpfc_vport *pport =
+		(struct lpfc_vport *) fc_vport->shost->hostdata;
+	struct lpfc_hba   *phba = pport->phba;
+	struct lpfc_vport *vport = NULL;
+	int instance;
+	int vpi;
+	int rc = VPORT_ERROR;
+
+	if ((phba->sli_rev < 3) ||
+		!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
+				"%d:1808 Create VPORT failed: "
+				"NPIV is not enabled: SLImode:%d\n",
+				phba->brd_no, phba->sli_rev);
+		rc = VPORT_INVAL;
+		goto error_out;
+	}
+
+	vpi = lpfc_alloc_vpi(phba);
+	if (vpi == 0) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
+				"%d:1809 Create VPORT failed: "
+				"Max VPORTs (%d) exceeded\n",
+				phba->brd_no, phba->max_vpi);
+		rc = VPORT_NORESOURCES;
+		goto error_out;
+	}
+
+
+	/* Assign an unused board number */
+	if ((instance = lpfc_get_instance()) < 0) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
+				"%d:1810 Create VPORT failed: Cannot get "
+				"instance number\n", phba->brd_no);
+		lpfc_free_vpi(phba, vpi);
+		rc = VPORT_NORESOURCES;
+		goto error_out;
+	}
+
+	vport = lpfc_create_port(phba, instance, fc_vport);
+	if (!vport) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
+				"%d:1811 Create VPORT failed: vpi x%x\n",
+				phba->brd_no, vpi);
+		lpfc_free_vpi(phba, vpi);
+		rc = VPORT_NORESOURCES;
+		goto error_out;
+	}
+
+	vport->vpi = vpi;
+	if (lpfc_vport_sparm(phba, vport)) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
+				"%d:1813 Create VPORT failed: vpi:%d "
+				"Cannot get sparam\n",
+				phba->brd_no, vpi);
+		lpfc_free_vpi(phba, vpi);
+		destroy_port(vport);
+		rc = VPORT_NORESOURCES;
+		goto error_out;
+	}
+
+	memcpy(vport->fc_portname.u.wwn, vport->fc_sparam.portName.u.wwn, 8);
+	memcpy(vport->fc_nodename.u.wwn, vport->fc_sparam.nodeName.u.wwn, 8);
+
+	if (fc_vport->node_name != 0)
+		u64_to_wwn(fc_vport->node_name, vport->fc_nodename.u.wwn);
+	if (fc_vport->port_name != 0)
+		u64_to_wwn(fc_vport->port_name, vport->fc_portname.u.wwn);
+
+	memcpy(&vport->fc_sparam.portName, vport->fc_portname.u.wwn, 8);
+	memcpy(&vport->fc_sparam.nodeName, vport->fc_nodename.u.wwn, 8);
+
+	if (!lpfc_valid_wwn_format(phba, &vport->fc_sparam.nodeName, "WWNN") ||
+	    !lpfc_valid_wwn_format(phba, &vport->fc_sparam.portName, "WWPN")) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
+				"%d:1821 Create VPORT failed: vpi:%d "
+				"Invalid WWN format\n",
+				phba->brd_no, vpi);
+		lpfc_free_vpi(phba, vpi);
+		destroy_port(vport);
+		rc = VPORT_INVAL;
+		goto error_out;
+	}
+
+	if (!lpfc_unique_wwpn(phba, vport)) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
+				"%d:1823 Create VPORT failed: vpi:%d "
+				"Duplicate WWN on HBA\n",
+				phba->brd_no, vpi);
+		lpfc_free_vpi(phba, vpi);
+		destroy_port(vport);
+		rc = VPORT_INVAL;
+		goto error_out;
+	}
+
+	*(struct lpfc_vport **)fc_vport->dd_data = vport;
+	vport->fc_vport = fc_vport;
+
+	if ((phba->link_state < LPFC_LINK_UP) ||
+	    (phba->fc_topology == TOPOLOGY_LOOP)) {
+		lpfc_vport_set_state(vport, FC_VPORT_LINKDOWN);
+		rc = VPORT_OK;
+		goto out;
+	}
+
+	if (disable) {
+		rc = VPORT_OK;
+		goto out;
+	}
+
+	/* Use the Physical nodes Fabric NDLP to determine if the link is
+	 * up and ready to FDISC.
+	 */
+	ndlp = lpfc_findnode_did(phba->pport, Fabric_DID);
+	if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
+		lpfc_set_disctmo(vport);
+		lpfc_initial_fdisc(vport);
+	} else {
+		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+	}
+	rc = VPORT_OK;
+
+out:
+	lpfc_host_attrib_init(lpfc_shost_from_vport(vport));
+error_out:
+	return rc;
+}
+
+int
+disable_vport(struct fc_vport *fc_vport)
+{
+	struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data;
+	struct lpfc_hba   *phba = vport->phba;
+	struct lpfc_nodelist *ndlp = NULL, *next_ndlp = NULL;
+	long timeout;
+
+	ndlp = lpfc_findnode_did(vport, Fabric_DID);
+	if (ndlp && phba->link_state >= LPFC_LINK_UP) {
+		vport->unreg_vpi_cmpl = VPORT_INVAL;
+		timeout = msecs_to_jiffies(phba->fc_ratov * 2000);
+		if (!lpfc_issue_els_npiv_logo(vport, ndlp))
+			while (vport->unreg_vpi_cmpl == VPORT_INVAL && timeout)
+				timeout = schedule_timeout(timeout);
+	}
+
+	lpfc_sli_host_down(vport);
+
+	/* Mark all nodes for discovery so we can remove them by
+	 * calling lpfc_cleanup_rpis(vport, 1)
+	 */
+	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
+		if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
+			continue;
+		lpfc_disc_state_machine(vport, ndlp, NULL,
+					NLP_EVT_DEVICE_RECOVERY);
+	}
+	lpfc_cleanup_rpis(vport, 1);
+
+	lpfc_stop_vport_timers(vport);
+	lpfc_unreg_all_rpis(vport);
+	lpfc_unreg_default_rpis(vport);
+	/*
+	 * Completion of unreg_vpi (lpfc_mbx_cmpl_unreg_vpi) does the
+	 * scsi_host_put() to release the vport.
+	 */
+	lpfc_mbx_unreg_vpi(vport);
+
+	lpfc_vport_set_state(vport, FC_VPORT_DISABLED);
+	return VPORT_OK;
+}
+
+int
+enable_vport(struct fc_vport *fc_vport)
+{
+	struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data;
+	struct lpfc_hba   *phba = vport->phba;
+	struct lpfc_nodelist *ndlp = NULL;
+
+	if ((phba->link_state < LPFC_LINK_UP) ||
+	    (phba->fc_topology == TOPOLOGY_LOOP)) {
+		lpfc_vport_set_state(vport, FC_VPORT_LINKDOWN);
+		return VPORT_OK;
+	}
+
+	vport->load_flag |= FC_LOADING;
+	vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+
+	/* Use the Physical nodes Fabric NDLP to determine if the link is
+	 * up and ready to FDISC.
+	 */
+	ndlp = lpfc_findnode_did(phba->pport, Fabric_DID);
+	if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
+		lpfc_set_disctmo(vport);
+		lpfc_initial_fdisc(vport);
+	} else {
+		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+	}
+
+	return VPORT_OK;
+}
+
+int
+lpfc_vport_disable(struct fc_vport *fc_vport, bool disable)
+{
+	if (disable)
+		return disable_vport(fc_vport);
+	else
+		return enable_vport(fc_vport);
+}
+
+
+int
+lpfc_vport_delete(struct fc_vport *fc_vport)
+{
+	struct lpfc_nodelist *ndlp = NULL;
+	struct lpfc_nodelist *next_ndlp;
+	struct Scsi_Host *shost = (struct Scsi_Host *) fc_vport->shost;
+	struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data;
+	struct lpfc_hba   *phba = vport->phba;
+	long timeout;
+	int rc = VPORT_ERROR;
+
+	/*
+	 * This is a bit of a mess.  We want to ensure the shost doesn't get
+	 * torn down until we're done with the embedded lpfc_vport structure.
+	 *
+	 * Beyond holding a reference for this function, we also need a
+	 * reference for outstanding I/O requests we schedule during delete
+	 * processing.  But once we scsi_remove_host() we can no longer obtain
+	 * a reference through scsi_host_get().
+	 *
+	 * So we take two references here.  We release one reference at the
+	 * bottom of the function -- after delinking the vport.  And we
+	 * release the other at the completion of the unreg_vpi that get's
+	 * initiated after we've disposed of all other resources associated
+	 * with the port.
+	 */
+	if (!scsi_host_get(shost) || !scsi_host_get(shost))
+		return VPORT_INVAL;
+
+	if (vport->port_type == LPFC_PHYSICAL_PORT) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
+				"%d:1812 vport_delete failed: Cannot delete "
+				"physical host\n", phba->brd_no);
+		goto out;
+	}
+
+	vport->load_flag |= FC_UNLOADING;
+
+	kfree(vport->vname);
+	fc_remove_host(lpfc_shost_from_vport(vport));
+	scsi_remove_host(lpfc_shost_from_vport(vport));
+
+	ndlp = lpfc_findnode_did(phba->pport, Fabric_DID);
+	if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE &&
+		phba->link_state >= LPFC_LINK_UP) {
+
+		/* First look for the Fabric ndlp */
+		ndlp = lpfc_findnode_did(vport, Fabric_DID);
+		if (!ndlp) {
+			/* Cannot find existing Fabric ndlp, allocate one */
+			ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
+			if (!ndlp)
+				goto skip_logo;
+			lpfc_nlp_init(vport, ndlp, Fabric_DID);
+		} else {
+			lpfc_dequeue_node(vport, ndlp);
+		}
+		vport->unreg_vpi_cmpl = VPORT_INVAL;
+		timeout = msecs_to_jiffies(phba->fc_ratov * 2000);
+		if (!lpfc_issue_els_npiv_logo(vport, ndlp))
+			while (vport->unreg_vpi_cmpl == VPORT_INVAL && timeout)
+				timeout = schedule_timeout(timeout);
+	}
+
+skip_logo:
+	lpfc_sli_host_down(vport);
+
+	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
+		lpfc_disc_state_machine(vport, ndlp, NULL,
+					     NLP_EVT_DEVICE_RECOVERY);
+		lpfc_disc_state_machine(vport, ndlp, NULL,
+					     NLP_EVT_DEVICE_RM);
+	}
+
+	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
+		/* free any ndlp's in unused state */
+		if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
+			lpfc_drop_node(vport, ndlp);
+	}
+
+	lpfc_stop_vport_timers(vport);
+	lpfc_unreg_all_rpis(vport);
+	lpfc_unreg_default_rpis(vport);
+	/*
+	 * Completion of unreg_vpi (lpfc_mbx_cmpl_unreg_vpi) does the
+	 * scsi_host_put() to release the vport.
+	 */
+	lpfc_mbx_unreg_vpi(vport);
+
+	lpfc_free_vpi(phba, vport->vpi);
+	vport->work_port_events = 0;
+	spin_lock_irq(&phba->hbalock);
+	list_del_init(&vport->listentry);
+	spin_unlock_irq(&phba->hbalock);
+
+	rc = VPORT_OK;
+out:
+	scsi_host_put(shost);
+	return rc;
+}
+
+
+EXPORT_SYMBOL(lpfc_vport_create);
+EXPORT_SYMBOL(lpfc_vport_delete);

+ 113 - 0
drivers/scsi/lpfc/lpfc_vport.h

@@ -0,0 +1,113 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for         *
+ * Fibre Channel Host Bus Adapters.                                *
+ * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * EMULEX and SLI are trademarks of Emulex.                        *
+ * www.emulex.com                                                  *
+ * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
+ *                                                                 *
+ * This program is free software; you can redistribute it and/or   *
+ * modify it under the terms of version 2 of the GNU General       *
+ * Public License as published by the Free Software Foundation.    *
+ * This program is distributed in the hope that it will be useful. *
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
+ * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
+ * more details, a copy of which can be found in the file COPYING  *
+ * included with this package.                                     *
+ *******************************************************************/
+
+#ifndef _H_LPFC_VPORT
+#define _H_LPFC_VPORT
+
+/* API version values (each will be an individual bit) */
+#define VPORT_API_VERSION_1	0x01
+
+/* Values returned via lpfc_vport_getinfo() */
+struct vport_info {
+
+	uint32_t api_versions;
+	uint8_t linktype;
+#define  VPORT_TYPE_PHYSICAL	0
+#define  VPORT_TYPE_VIRTUAL	1
+
+	uint8_t state;
+#define  VPORT_STATE_OFFLINE	0
+#define  VPORT_STATE_ACTIVE	1
+#define  VPORT_STATE_FAILED	2
+
+	uint8_t fail_reason;
+	uint8_t prev_fail_reason;
+#define  VPORT_FAIL_UNKNOWN	0
+#define  VPORT_FAIL_LINKDOWN	1
+#define  VPORT_FAIL_FAB_UNSUPPORTED	2
+#define  VPORT_FAIL_FAB_NORESOURCES	3
+#define  VPORT_FAIL_FAB_LOGOUT	4
+#define  VPORT_FAIL_ADAP_NORESOURCES	5
+
+	uint8_t node_name[8];	/* WWNN */
+	uint8_t port_name[8];	/* WWPN */
+
+	struct Scsi_Host *shost;
+
+/* Following values are valid only on physical links */
+	uint32_t vports_max;
+	uint32_t vports_inuse;
+	uint32_t rpi_max;
+	uint32_t rpi_inuse;
+#define  VPORT_CNT_INVALID	0xFFFFFFFF
+};
+
+/* data used  in link creation */
+struct vport_data {
+	uint32_t api_version;
+
+	uint32_t options;
+#define  VPORT_OPT_AUTORETRY	0x01
+
+	uint8_t node_name[8];	/* WWNN */
+	uint8_t port_name[8];	/* WWPN */
+
+/*
+ *  Upon successful creation, vport_shost will point to the new Scsi_Host
+ *  structure for the new virtual link.
+ */
+	struct Scsi_Host *vport_shost;
+};
+
+/* API function return codes */
+#define VPORT_OK	0
+#define VPORT_ERROR	-1
+#define VPORT_INVAL	-2
+#define VPORT_NOMEM	-3
+#define VPORT_NORESOURCES	-4
+
+int lpfc_vport_create(struct fc_vport *, bool);
+int lpfc_vport_delete(struct fc_vport *);
+int lpfc_vport_getinfo(struct Scsi_Host *, struct vport_info *);
+int lpfc_vport_tgt_remove(struct Scsi_Host *, uint, uint);
+
+/*
+ *  queuecommand  VPORT-specific return codes. Specified in  the host byte code.
+ *  Returned when the virtual link has failed or is not active.
+ */
+#define  DID_VPORT_ERROR	0x0f
+
+#define VPORT_INFO	0x1
+#define VPORT_CREATE	0x2
+#define VPORT_DELETE	0x4
+
+struct vport_cmd_tag {
+	uint32_t cmd;
+	struct vport_data cdata;
+	struct vport_info cinfo;
+	void *vport;
+	int vport_num;
+};
+
+void lpfc_vport_set_state(struct lpfc_vport *vport,
+			  enum fc_vport_state new_state);
+
+#endif /* H_LPFC_VPORT */

部分文件因为文件数量过多而无法显示