summary refs log tree commit diff
path: root/drivers/scsi/lpfc
diff options
context:
space:
mode:
authorJames Smart <James.Smart@Emulex.Com>2007-06-17 19:56:37 -0500
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2007-06-17 22:06:27 -0500
commited957684294618602b48f1950b0c9bbcb036583f (patch)
tree4e88dbb2e55013f973ad94099e2963dd507ea719 /drivers/scsi/lpfc
parent2e0fef85e098f6794956b8b80b111179fbb4cbb7 (diff)
downloadlinux-ed957684294618602b48f1950b0c9bbcb036583f.tar.gz
[SCSI] lpfc: NPIV: add SLI-3 interface
NPIV support is only available via new adapter interface extensions,
termed SLI-3. This interface changes some of the basic behaviors such
as command and response ring element sizes and data structures, as
well as a change in buffer posting.  Note: the new firmware extensions
are found only on our mid-range and enterprise 4Gig adapters - so NPIV
support is available only on these newer adapters. The latest firmware
can be downloaded from the Emulex support page.

Signed-off-by: James Smart <James.Smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/lpfc')
-rw-r--r--drivers/scsi/lpfc/lpfc.h35
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h14
-rw-r--r--drivers/scsi/lpfc/lpfc_ct.c183
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c273
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c79
-rw-r--r--drivers/scsi/lpfc/lpfc_hw.h397
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c68
-rw-r--r--drivers/scsi/lpfc/lpfc_mbox.c176
-rw-r--r--drivers/scsi/lpfc/lpfc_mem.c29
-rw-r--r--drivers/scsi/lpfc/lpfc_nportdisc.c36
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c2
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c698
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.h25
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h2
14 files changed, 1522 insertions, 495 deletions
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index 8d718964f281..74f4d18842cc 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -63,6 +63,11 @@ struct lpfc_dma_pool {
 	uint32_t    current_count;
 };
 
+struct hbq_dmabuf {
+	struct lpfc_dmabuf dbuf;
+	uint32_t tag;
+};
+
 /* Priority bit.  Set value to exceed low water mark in lpfc_mem. */
 #define MEM_PRI		0x100
 
@@ -276,8 +281,25 @@ struct lpfc_vport {
 
 };
 
+
+struct hbq_s {
+	uint16_t entry_count;	  /* Current number of HBQ slots */
+	uint32_t next_hbqPutIdx;  /* Index to next HBQ slot to use */
+	uint32_t hbqPutIdx;	  /* HBQ slot to use */
+	uint32_t local_hbqGetIdx; /* Local copy of Get index from Port */
+};
+
+#define MAX_HBQS  16
+
 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
+	uint32_t iocb_cmd_size;
+	uint32_t iocb_rsp_size;
 
 	enum hba_state link_state;
 	uint32_t link_flag;	/* link state flags */
@@ -286,8 +308,6 @@ struct lpfc_hba {
 					/* INIT_LINK mailbox command */
 #define LS_IGNORE_ERATT         0x80000	/* intr handler should ignore ERATT */
 
-	uint32_t pgpOffset; /* PGP offset within host memory */
-
 	struct lpfc_sli2_slim *slim2p;
 	struct lpfc_dmabuf hbqslimp;
 
@@ -371,6 +391,12 @@ 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 */
+	uint32_t hbq_count;	        /* Count of configured HBQs */
+	struct hbq_s hbqs[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 */
 	void __iomem *slim_memmap_p;	/* Kernel memory mapped address for
@@ -385,6 +411,10 @@ struct lpfc_hba {
 					   reg */
 	void __iomem *HCregaddr;	/* virtual address for host ctl reg */
 
+	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 */
+
 	int brd_no;			/* FC board number */
 
 	char SerialNumber[32];		/* adapter Serial Number */
@@ -425,6 +455,7 @@ struct lpfc_hba {
 	/* pci_mem_pools */
 	struct pci_pool *lpfc_scsi_dma_buf_pool;
 	struct pci_pool *lpfc_mbuf_pool;
+	struct pci_pool *lpfc_hbq_pool;
 	struct lpfc_dma_pool lpfc_mbuf_safety_pool;
 
 	mempool_t *mbox_mem_pool;
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index 0081cffd9280..776930727058 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -138,6 +138,10 @@ void lpfc_mbox_put(struct lpfc_hba *, LPFC_MBOXQ_t *);
 LPFC_MBOXQ_t *lpfc_mbox_get(struct lpfc_hba *);
 int lpfc_mbox_tmo_val(struct lpfc_hba *, int);
 
+void lpfc_config_hbq(struct lpfc_hba *, struct lpfc_hbq_init *, uint32_t ,
+		     LPFC_MBOXQ_t *);
+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 *);
 
@@ -172,6 +176,12 @@ 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);
+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 *);
 int lpfc_sli_sum_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, uint16_t,
@@ -198,6 +208,9 @@ void lpfc_sli_abort_fcp_cmpl(struct lpfc_hba * phba,
 			     struct lpfc_iocbq * cmdiocb,
 			     struct lpfc_iocbq * rspiocb);
 
+void *lpfc_hbq_alloc(struct lpfc_hba *, int, dma_addr_t *);
+void lpfc_hbq_free(struct lpfc_hba *, void *, dma_addr_t);
+
 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);
@@ -213,6 +226,7 @@ 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 int lpfc_sli_mode;
 
 void lpfc_get_hba_sym_node_name(struct lpfc_hba *phba, uint8_t *symbp);
 void lpfc_terminate_rport_io(struct fc_rport *);
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index dc25a53524c4..e8ed5d7ccf9f 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -58,25 +58,66 @@ static char *lpfc_release_version = LPFC_DRIVER_VERSION;
 /*
  * lpfc_ct_unsol_event
  */
+static void
+lpfc_ct_unsol_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
+		     struct lpfc_dmabuf *mp, uint32_t size)
+{
+	if (!mp) {
+		printk(KERN_ERR "%s (%d): Unsolited CT, no buffer, "
+		       "piocbq = %p, status = x%x, mp = %p, size = %d\n",
+		       __FUNCTION__, __LINE__,
+		       piocbq, piocbq->iocb.ulpStatus, mp, size);
+	}
+
+	printk(KERN_ERR "%s (%d): Ignoring unsolicted CT piocbq = %p, "
+	       "buffer = %p, size = %d, status = x%x\n",
+	       __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 = NULL;
+
+	mp = sp ? &sp->dbuf : NULL;
+	if (!mp) {
+		printk(KERN_ERR "%s (%d): Unsolited CT, no "
+		       "HBQ buffer, piocbq = %p, status = x%x\n",
+		       __FUNCTION__, __LINE__,
+		       piocbq, piocbq->iocb.ulpStatus);
+	} else {
+		lpfc_ct_unsol_buffer(phba, piocbq, mp, size);
+		printk(KERN_ERR "%s (%d): Ignoring unsolicted CT "
+		       "piocbq = %p, buffer = %p, size = %d, "
+		       "status = x%x\n",
+		       __FUNCTION__, __LINE__,
+		       piocbq, mp, size, piocbq->iocb.ulpStatus);
+	}
+}
+
 void
 lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 		    struct lpfc_iocbq *piocbq)
 {
-
-	struct lpfc_iocbq *next_piocbq;
-	struct lpfc_dmabuf *pmbuf = NULL;
-	struct lpfc_dmabuf *matp = NULL, *next_matp;
-	uint32_t ctx = 0, size = 0, cnt = 0;
+	struct lpfc_dmabuf *mp = NULL;
+	struct hbq_dmabuf  *sp = NULL;
 	IOCB_t *icmd = &piocbq->iocb;
-	IOCB_t *save_icmd = icmd;
-	int i, go_exit = 0;
-	struct list_head head;
+	int i;
+	struct lpfc_iocbq *iocbq;
+	dma_addr_t paddr;
+	uint32_t size;
 
 	if ((icmd->ulpStatus == IOSTAT_LOCAL_REJECT) &&
-		((icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING)) {
+	    ((icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING)) {
 		/* Not enough posted buffers; Try posting more buffers */
 		phba->fc_stat.NoRcvBuf++;
-		lpfc_post_buffer(phba, pring, 0, 1);
+		if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)
+			lpfc_sli_hbqbuf_fill_hbq(phba);
+		else
+			lpfc_post_buffer(phba, pring, 0, 1);
 		return;
 	}
 
@@ -86,62 +127,62 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 	if (icmd->ulpBdeCount == 0)
 		return;
 
-	INIT_LIST_HEAD(&head);
-	list_add_tail(&head, &piocbq->list);
-
-	list_for_each_entry_safe(piocbq, next_piocbq, &head, list) {
-		icmd = &piocbq->iocb;
-		if (ctx == 0)
-			ctx = (uint32_t) (icmd->ulpContext);
-		if (icmd->ulpBdeCount == 0)
-			continue;
-
-		for (i = 0; i < icmd->ulpBdeCount; i++) {
-			matp = lpfc_sli_ringpostbuf_get(phba, pring,
-							getPaddr(icmd->un.
-								 cont64[i].
-								 addrHigh,
-								 icmd->un.
-								 cont64[i].
-								 addrLow));
-			if (!matp) {
-				/* Insert lpfc log message here */
-				lpfc_post_buffer(phba, pring, cnt, 1);
-				go_exit = 1;
-				goto ct_unsol_event_exit_piocbq;
+	if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
+		list_for_each_entry(iocbq, &piocbq->list, list) {
+			icmd = &iocbq->iocb;
+			if (icmd->ulpBdeCount == 0) {
+				printk(KERN_ERR "%s (%d): Unsolited CT, no "
+				       "BDE, iocbq = %p, status = x%x\n",
+				       __FUNCTION__, __LINE__,
+				       iocbq, iocbq->iocb.ulpStatus);
+				continue;
 			}
 
-			/* Typically for Unsolicited CT requests */
-			if (!pmbuf) {
-				pmbuf = matp;
-				INIT_LIST_HEAD(&pmbuf->list);
-			} else
-				list_add_tail(&matp->list, &pmbuf->list);
+			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);
+			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,
+							  size);
+				lpfc_sli_free_hbq(phba, sp);
+			}
 
-			size += icmd->un.cont64[i].tus.f.bdeSize;
-			cnt++;
 		}
+		lpfc_sli_hbqbuf_fill_hbq(phba);
+	} else {
+		struct lpfc_iocbq  *next;
+
+		list_for_each_entry_safe(iocbq, next, &piocbq->list, list) {
+			icmd = &iocbq->iocb;
+			if (icmd->ulpBdeCount == 0) {
+				printk(KERN_ERR "%s (%d): Unsolited CT, no "
+				       "BDE, iocbq = %p, status = x%x\n",
+				       __FUNCTION__, __LINE__,
+				       iocbq, iocbq->iocb.ulpStatus);
+				continue;
+			}
 
-		icmd->ulpBdeCount = 0;
-	}
-
-	lpfc_post_buffer(phba, pring, cnt, 1);
-	if (save_icmd->ulpStatus) {
-		go_exit = 1;
-	}
-
-ct_unsol_event_exit_piocbq:
-	list_del(&head);
-	if (pmbuf) {
-		list_for_each_entry_safe(matp, next_matp, &pmbuf->list, list) {
-			lpfc_mbuf_free(phba, matp->virt, matp->phys);
-			list_del(&matp->list);
-			kfree(matp);
+			for (i = 0; i < icmd->ulpBdeCount; i++) {
+				paddr = getPaddr(icmd->un.cont64[i].addrHigh,
+						 icmd->un.cont64[i].addrLow);
+				mp = lpfc_sli_ringpostbuf_get(phba, 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);
+			}
+			list_del(&iocbq->list);
+			lpfc_sli_release_iocbq(phba, iocbq);
 		}
-		lpfc_mbuf_free(phba, pmbuf->virt, pmbuf->phys);
-		kfree(pmbuf);
 	}
-	return;
 }
 
 static void
@@ -364,9 +405,7 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
 						vport->fc_flag,
 						vport->fc_rscn_id_cnt);
 			} else {
-				lpfc_printf_log(phba,
-						KERN_INFO,
-						LOG_DISCOVERY,
+				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,
@@ -717,12 +756,9 @@ lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 	ndlp = lpfc_findnode_did(vport, FDMI_DID);
 	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));
+		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));
 	}
 
 	switch (be16_to_cpu(fdmi_cmd)) {
@@ -791,9 +827,7 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode)
 	INIT_LIST_HEAD(&bmp->list);
 
 	/* FDMI request */
-	lpfc_printf_log(phba,
-		        KERN_INFO,
-		        LOG_DISCOVERY,
+	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);
@@ -1120,12 +1154,9 @@ fdmi_cmd_free_mp:
 	kfree(mp);
 fdmi_cmd_exit:
 	/* Issue FDMI request failed */
-	lpfc_printf_log(phba,
-		        KERN_INFO,
-		        LOG_DISCOVERY,
+	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
 		        "%d:0244 Issue FDMI request failed Data: x%x\n",
-		        phba->brd_no,
-			cmdcode);
+		        phba->brd_no, cmdcode);
 	return 1;
 }
 
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 0af33bead302..d48247b3b654 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -45,9 +45,7 @@ lpfc_els_chk_latt(struct lpfc_vport *vport)
 {
 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
 	struct lpfc_hba  *phba = vport->phba;
-	LPFC_MBOXQ_t *mbox;
 	uint32_t ha_copy;
-	int rc;
 
 	if (vport->port_state >= LPFC_VPORT_READY ||
 	    phba->link_state == LPFC_LINK_DOWN)
@@ -76,20 +74,7 @@ lpfc_els_chk_latt(struct lpfc_vport *vport)
 	spin_unlock_irq(shost->host_lock);
 
 	if (phba->link_state != LPFC_CLEAR_LA) {
-		if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))) {
-			phba->link_state = LPFC_CLEAR_LA;
-			lpfc_clear_la(phba, mbox);
-			mbox->mbox_cmpl = lpfc_mbx_cmpl_clear_la;
-			mbox->vport = vport;
-			printk(KERN_ERR "%s (%d): do clear_la\n",
-			       __FUNCTION__, __LINE__);
-			rc = lpfc_sli_issue_mbox(phba, mbox,
-						 (MBX_NOWAIT | MBX_STOP_IOCB));
-			if (rc == MBX_NOT_FINISHED) {
-				mempool_free(mbox, phba->mbox_mem_pool);
-				phba->link_state = LPFC_HBA_ERROR;
-			}
-		}
+		lpfc_issue_clear_la(phba, vport);
 	}
 
 	return 1;
@@ -153,8 +138,8 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
 	/* Allocate buffer for Buffer ptr list */
 	pbuflist = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
 	if (pbuflist)
-	    pbuflist->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
-					     &pbuflist->phys);
+		pbuflist->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
+						 &pbuflist->phys);
 	if (pbuflist == 0 || pbuflist->virt == 0) {
 		lpfc_sli_release_iocbq(phba, elsiocb);
 		lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
@@ -289,6 +274,7 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 	vport->port_state = LPFC_FABRIC_CFG_LINK;
 	lpfc_config_link(phba, mbox);
 	mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+	mbox->vport = vport;
 
 	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB);
 	if (rc == MBX_NOT_FINISHED)
@@ -364,6 +350,7 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 		lpfc_config_link(phba, mbox);
 
 		mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+		mbox->vport = vport;
 		rc = lpfc_sli_issue_mbox(phba, mbox,
 				MBX_NOWAIT | MBX_STOP_IOCB);
 		if (rc == MBX_NOT_FINISHED) {
@@ -714,8 +701,10 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 
 	irsp = &rspiocb->iocb;
 	ndlp = lpfc_findnode_did(vport, irsp->un.elsreq64.remoteID);
-	if (!ndlp)
+
+	if (!ndlp) {
 		goto out;
+	}
 
 	/* Since ndlp can be freed in the disc state machine, note if this node
 	 * is being used during discovery.
@@ -1110,9 +1099,8 @@ lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 			/* If we get here, there is nothing left to wait for */
 			if (vport->port_state < LPFC_VPORT_READY &&
 			    phba->link_state != LPFC_CLEAR_LA) {
-				if (vport->port_type == LPFC_PHYSICAL_PORT) {
+				if (vport->port_type == LPFC_PHYSICAL_PORT)
 					lpfc_issue_clear_la(phba, vport);
-				}
 			} else {
 				lpfc_rscn_disc(vport);
 			}
@@ -1420,6 +1408,27 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
 	return 0;
 }
 
+static void
+lpfc_end_rscn(struct lpfc_vport *vport)
+{
+	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
+	if (vport->fc_flag & FC_RSCN_MODE) {
+		/*
+		 * Check to see if more RSCNs came in while we were
+		 * processing this one.
+		 */
+		if (vport->fc_rscn_id_cnt ||
+		    (vport->fc_flag & FC_RSCN_DISCOVERY) != 0)
+			lpfc_els_handle_rscn(vport);
+		else {
+			spin_lock_irq(shost->host_lock);
+			vport->fc_flag &= ~FC_RSCN_MODE;
+			spin_unlock_irq(shost->host_lock);
+		}
+	}
+}
+
 void
 lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp)
 {
@@ -1449,24 +1458,7 @@ lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp)
 				vport->fc_flag &= ~FC_NDISC_ACTIVE;
 				spin_unlock_irq(shost->host_lock);
 				lpfc_can_disctmo(vport);
-				if (vport->fc_flag & FC_RSCN_MODE) {
-					/*
-					 * Check to see if more RSCNs
-					 * came in while we were
-					 * processing this one.
-					 */
-					if (!vport->fc_rscn_id_cnt &&
-					    !(vport->fc_flag &
-					      FC_RSCN_DISCOVERY)) {
-						spin_lock_irq(shost->host_lock);
-						vport->fc_flag &= ~FC_RSCN_MODE;
-						spin_unlock_irq(
-							shost->host_lock);
-					}
-					else {
-						lpfc_els_handle_rscn(vport);
-					}
-				}
+				lpfc_end_rscn(vport);
 			}
 		}
 	}
@@ -1689,6 +1681,9 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 		retry = 0;
 	}
 
+	if ((vport->load_flag & FC_UNLOADING) != 0)
+		retry = 0;
+
 	if (retry) {
 
 		/* Retry ELS command <elsCmd> to remote NPORT <did> */
@@ -2141,9 +2136,7 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
 
 	cmdsize = sizeof (uint32_t) + sizeof (PRLI);
 	elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
-				     ndlp->nlp_DID,
-				     (ELS_CMD_ACC |
-				      (ELS_CMD_PRLI & ~ELS_RSP_MASK)));
+	     ndlp->nlp_DID, (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK)));
 	if (!elsiocb)
 		return 1;
 
@@ -2361,8 +2354,12 @@ lpfc_els_flush_rscn(struct lpfc_vport *vport)
 
 	for (i = 0; i < vport->fc_rscn_id_cnt; i++) {
 		mp = vport->fc_rscn_id_list[i];
-		lpfc_mbuf_free(phba, mp->virt, mp->phys);
-		kfree(mp);
+		if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)
+			lpfc_sli_hbqbuf_free(phba, mp->virt, mp->phys);
+		else {
+			lpfc_mbuf_free(phba, mp->virt, mp->phys);
+			kfree(mp);
+		}
 		vport->fc_rscn_id_list[i] = NULL;
 	}
 	spin_lock_irq(shost->host_lock);
@@ -2486,9 +2483,7 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
 	cmd &= ELS_CMD_MASK;
 
 	/* RSCN received */
-	lpfc_printf_log(phba,
-			KERN_INFO,
-			LOG_DISCOVERY,
+	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
 			"%d:0214 RSCN received Data: x%x x%x x%x x%x\n",
 			phba->brd_no, vport->fc_flag, payload_len, *lp,
 			vport->fc_rscn_id_cnt);
@@ -2581,9 +2576,7 @@ lpfc_els_handle_rscn(struct lpfc_vport *vport)
 	lpfc_set_disctmo(vport);
 
 	/* RSCN processed */
-	lpfc_printf_log(phba,
-			KERN_INFO,
-			LOG_DISCOVERY,
+	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
 			"%d:0215 RSCN processed Data: x%x x%x x%x x%x\n",
 			phba->brd_no,
 			vport->fc_flag, 0, vport->fc_rscn_id_cnt,
@@ -2683,6 +2676,7 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
 				       phba->cfg_link_speed);
 			mbox->mb.un.varInitLnk.lipsr_AL_PA = 0;
 			mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+			mbox->vport = vport;
 			rc = lpfc_sli_issue_mbox
 				(phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB));
 			lpfc_set_loopback_flag(phba);
@@ -2837,10 +2831,8 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 
 	elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
 	phba->fc_stat.elsXmitACC++;
-
-	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR)
 		lpfc_els_free_iocb(phba, elsiocb);
-	}
 	return;
 }
 
@@ -3015,9 +3007,7 @@ lpfc_els_rcv_farp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
 	fp = (FARP *) lp;
 
 	/* FARP-REQ received from DID <did> */
-	lpfc_printf_log(phba,
-			 KERN_INFO,
-			 LOG_ELS,
+	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
 			 "%d:0601 FARP-REQ received from DID x%x\n",
 			 phba->brd_no, did);
 
@@ -3077,12 +3067,9 @@ lpfc_els_rcv_farpr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
 
 	cmd = *lp++;
 	/* FARP-RSP received from DID <did> */
-	lpfc_printf_log(phba,
-			 KERN_INFO,
-			 LOG_ELS,
+	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
 			 "%d:0600 FARP-RSP received from DID x%x\n",
 			 phba->brd_no, did);
-
 	/* ACCEPT the Farp resp request */
 	lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
 
@@ -3102,8 +3089,9 @@ lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
 	struct lpfc_hba *phba = vport->phba;
 
 	/* FAN received */
-	lpfc_printf_log(phba, KERN_INFO, LOG_ELS, "%d:0265 FAN received\n",
-								phba->brd_no);
+	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+			"%d:0265 FAN received\n",
+			phba->brd_no);
 
 	icmd = &cmdiocb->iocb;
 	did = icmd->un.elsreq64.remoteID;
@@ -3332,79 +3320,40 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport)
 	return;
 }
 
-void
-lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
-		     struct lpfc_iocbq *elsiocb)
+static void
+lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+		      struct lpfc_vport *vport, struct lpfc_dmabuf *mp,
+		      struct lpfc_iocbq *elsiocb)
 {
-	struct lpfc_sli *psli;
 	struct lpfc_nodelist *ndlp;
-	struct lpfc_dmabuf *mp = NULL;
-	uint32_t *lp;
-	IOCB_t *icmd;
 	struct ls_rjt stat;
+	uint32_t *lp;
 	uint32_t cmd, did, newnode, rjt_err = 0;
-	uint32_t drop_cmd = 0;	/* by default do NOT drop received cmd */
-	struct lpfc_vport *vport = NULL;
-
-	psli = &phba->sli;
-	icmd = &elsiocb->iocb;
+	IOCB_t *icmd = &elsiocb->iocb;
 
-	if ((icmd->ulpStatus == IOSTAT_LOCAL_REJECT) &&
-		((icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING)) {
-		phba->fc_stat.NoRcvBuf++;
-		/* Not enough posted buffers; Try posting more buffers */
-		lpfc_post_buffer(phba, pring, 0, 1);
-		return;
-	}
-
-	/* If there are no BDEs associated with this IOCB,
-	 * there is nothing to do.
-	 */
-	if (icmd->ulpBdeCount == 0)
-		return;
-
-		/* type of ELS cmd is first 32bit word in packet */
-	mp = lpfc_sli_ringpostbuf_get(phba, pring,
-				      getPaddr(icmd->un.cont64[0].addrHigh,
-					       icmd->un.cont64[0].addrLow));
-	if (mp == 0) {
-		drop_cmd = 1;
+	if (!vport || !mp)
 		goto dropit;
-	}
-
-	vport = phba->pport;
 
 	newnode = 0;
 	lp = (uint32_t *) mp->virt;
 	cmd = *lp++;
-	lpfc_post_buffer(phba, &psli->ring[LPFC_ELS_RING], 1, 1);
+	if ((phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) == 0)
+		lpfc_post_buffer(phba, pring, 1, 1);
 
-	if (icmd->ulpStatus) {
-		lpfc_mbuf_free(phba, mp->virt, mp->phys);
-		kfree(mp);
-		drop_cmd = 1;
+	if (icmd->ulpStatus)
 		goto dropit;
-	}
 
 	/* Check to see if link went down during discovery */
-	if (lpfc_els_chk_latt(vport)) {
-		lpfc_mbuf_free(phba, mp->virt, mp->phys);
-		kfree(mp);
-		drop_cmd = 1;
+	if (lpfc_els_chk_latt(vport))
 		goto dropit;
-	}
 
 	did = icmd->un.rcvels.remoteID;
 	ndlp = lpfc_findnode_did(vport, did);
 	if (!ndlp) {
 		/* Cannot find existing Fabric ndlp, so allocate a new one */
 		ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
-		if (!ndlp) {
-			lpfc_mbuf_free(phba, mp->virt, mp->phys);
-			kfree(mp);
-			drop_cmd = 1;
+		if (!ndlp)
 			goto dropit;
-		}
 
 		lpfc_nlp_init(vport, ndlp, did);
 		newnode = 1;
@@ -3428,7 +3377,7 @@ lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
 			"%d:0112 ELS command x%x received from NPORT x%x "
 			"Data: x%x\n", phba->brd_no, cmd, did,
-			 vport->port_state);
+			vport->port_state);
 
 	switch (cmd) {
 	case ELS_CMD_PLOGI:
@@ -3537,8 +3486,9 @@ lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 
 		/* Unknown ELS command <elsCmd> received from NPORT <did> */
 		lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
-				"%d:0115 Unknown ELS command x%x received from "
-				"NPORT x%x\n", phba->brd_no, cmd, did);
+				"%d:0115 Unknown ELS command x%x "
+				"received from NPORT x%x\n",
+				phba->brd_no, cmd, did);
 		if (newnode)
 			lpfc_drop_node(vport, ndlp);
 		break;
@@ -3553,20 +3503,89 @@ lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 		lpfc_els_rsp_reject(vport, stat.un.lsRjtError, elsiocb, ndlp);
 	}
 
+	return;
+
+dropit:
+	lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+			"%d:0111 Dropping received ELS cmd "
+			"Data: x%x x%x x%x\n",
+			phba->brd_no,
+			icmd->ulpStatus, icmd->un.ulpWord[4],
+			icmd->ulpTimeout);
+	phba->fc_stat.elsRcvDrop++;
+}
+
+
+void
+lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+		     struct lpfc_iocbq *elsiocb)
+{
+	struct lpfc_vport *vport = phba->pport;
+	struct lpfc_dmabuf *mp = NULL;
+	IOCB_t *icmd = &elsiocb->iocb;
+	struct hbq_dmabuf *sp = NULL;
+	dma_addr_t paddr;
+
+	if ((icmd->ulpStatus == IOSTAT_LOCAL_REJECT) &&
+	    ((icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING)) {
+		phba->fc_stat.NoRcvBuf++;
+		/* Not enough posted buffers; Try posting more buffers */
+		if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)
+			lpfc_sli_hbqbuf_fill_hbq(phba);
+		else
+			lpfc_post_buffer(phba, pring, 0, 1);
+		return;
+	}
+
+	/* If there are no BDEs associated with this IOCB,
+	 * there is nothing to do.
+	 */
+	if (icmd->ulpBdeCount == 0)
+		return;
+
+	/* type of ELS cmd is first 32bit word in packet */
+	if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
+		paddr = getPaddr(icmd->un.cont64[0].addrHigh,
+				 icmd->un.cont64[0].addrLow);
+		sp = lpfc_sli_hbqbuf_find(phba, icmd->un.ulpWord[3]);
+		if (sp)
+			phba->hbq_buff_count--;
+		mp = sp ? &sp->dbuf : NULL;
+	} else {
+		paddr = getPaddr(icmd->un.cont64[0].addrHigh,
+				 icmd->un.cont64[0].addrLow);
+		mp = lpfc_sli_ringpostbuf_get(phba, pring, paddr);
+	}
+
+	lpfc_els_unsol_buffer(phba, pring, vport, mp, elsiocb);
+
 	lpfc_nlp_put(elsiocb->context1);
 	elsiocb->context1 = NULL;
 	if (elsiocb->context2) {
-		lpfc_mbuf_free(phba, mp->virt, mp->phys);
-		kfree(mp);
+		if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)
+			lpfc_sli_free_hbq(phba, sp);
+		else {
+			lpfc_mbuf_free(phba, mp->virt, mp->phys);
+			kfree(mp);
+		}
 	}
-dropit:
-	/* check if need to drop received ELS cmd */
-	if (drop_cmd == 1) {
-		lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
-				"%d:0111 Dropping received ELS cmd "
-				"Data: x%x x%x x%x\n", phba->brd_no,
-				icmd->ulpStatus, icmd->un.ulpWord[4],
-				icmd->ulpTimeout);
-		phba->fc_stat.elsRcvDrop++;
+
+	/* RCV_ELS64_CX provide for 2 BDEs - process 2nd if included */
+	if ((phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) != 0 &&
+	    icmd->ulpBdeCount == 2) {
+		sp = lpfc_sli_hbqbuf_find(phba, icmd->un.ulpWord[15]);
+		if (sp)
+			phba->hbq_buff_count--;
+		mp = sp ? &sp->dbuf : NULL;
+		lpfc_els_unsol_buffer(phba, pring, vport, mp, elsiocb);
+		/* free mp if we are done with it */
+		if (elsiocb->context2) {
+			if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)
+				lpfc_sli_free_hbq(phba, sp);
+			else {
+				lpfc_mbuf_free(phba, mp->virt, mp->phys);
+				kfree(mp);
+			}
+		}
 	}
 }
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index dee875ee6165..20b2a4905daa 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -232,9 +232,9 @@ static void
 lpfc_work_done(struct lpfc_hba *phba)
 {
 	struct lpfc_sli_ring *pring;
-	int i;
 	uint32_t ha_copy, control, work_port_events;
 	struct lpfc_vport *vport;
+	int i;
 
 	spin_lock_irq(&phba->hbalock);
 	ha_copy = phba->work_ha;
@@ -303,9 +303,9 @@ check_work_wait_done(struct lpfc_hba *phba)
 	struct lpfc_vport *vport = phba->pport;
 	int rc = 0;
 
-
 	if (!vport)
 		return 0;
+
 	spin_lock_irq(&phba->hbalock);
 
 	if (phba->work_ha ||
@@ -354,6 +354,7 @@ lpfc_workq_post_event(struct lpfc_hba *phba, void *arg1, void *arg2,
 		      uint32_t evt)
 {
 	struct lpfc_work_evt  *evtp;
+	unsigned long flags;
 
 	/*
 	 * All Mailbox completions and LPFC_ELS_RING rcv ring IOCB events will
@@ -367,11 +368,11 @@ lpfc_workq_post_event(struct lpfc_hba *phba, void *arg1, void *arg2,
 	evtp->evt_arg2  = arg2;
 	evtp->evt       = evt;
 
-	spin_lock_irq(&phba->hbalock);
+	spin_lock_irqsave(&phba->hbalock, flags);
 	list_add_tail(&evtp->evt_listp, &phba->work_list);
 	if (phba->work_wait)
 		wake_up(phba->work_wait);
-	spin_unlock_irq(&phba->hbalock);
+	spin_unlock_irqrestore(&phba->hbalock, flags);
 
 	return 1;
 }
@@ -401,6 +402,7 @@ lpfc_linkdown(struct lpfc_hba *phba)
 	mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
 	if (mb) {
 		lpfc_unreg_did(phba, 0xffffffff, mb);
+		mb->vport = vport;
 		mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
 		if (lpfc_sli_issue_mbox(phba, mb, (MBX_NOWAIT | MBX_STOP_IOCB))
 		    == MBX_NOT_FINISHED) {
@@ -433,6 +435,7 @@ lpfc_linkdown(struct lpfc_hba *phba)
 		if (mb) {
 			lpfc_config_link(phba, mb);
 			mb->mbox_cmpl=lpfc_sli_def_mbox_cmpl;
+			mb->vport = vport;
 			if (lpfc_sli_issue_mbox(phba, mb,
 						(MBX_NOWAIT | MBX_STOP_IOCB))
 			    == MBX_NOT_FINISHED) {
@@ -550,15 +553,11 @@ lpfc_mbx_cmpl_clear_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 		spin_unlock_irq(shost->host_lock);
 	}
 
-	printk(KERN_ERR "%s (%d): vport ready\n",
-	       __FUNCTION__, __LINE__);
 	vport->port_state = LPFC_VPORT_READY;
 
 out:
 	/* Device Discovery completes */
-	lpfc_printf_log(phba,
-			 KERN_INFO,
-			 LOG_DISCOVERY,
+	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
 			 "%d:0225 Device Discovery completes\n",
 			 phba->brd_no);
 
@@ -632,8 +631,6 @@ out:
 			phba->brd_no, vport->port_state);
 
 	lpfc_clear_la(phba, pmb);
-	printk(KERN_ERR "%s (%d): do clear_la\n",
-	       __FUNCTION__, __LINE__);
 	pmb->mbox_cmpl = lpfc_mbx_cmpl_clear_la;
 	pmb->vport = vport;
 	rc = lpfc_sli_issue_mbox(phba, pmb, (MBX_NOWAIT | MBX_STOP_IOCB));
@@ -643,8 +640,6 @@ out:
 		psli->ring[(psli->extra_ring)].flag &= ~LPFC_STOP_IOCB_EVENT;
 		psli->ring[(psli->fcp_ring)].flag &= ~LPFC_STOP_IOCB_EVENT;
 		psli->ring[(psli->next_ring)].flag &= ~LPFC_STOP_IOCB_EVENT;
-		printk(KERN_ERR "%s (%d): vport ready\n",
-		       __FUNCTION__, __LINE__);
 		vport->port_state = LPFC_VPORT_READY;
 	}
 	return;
@@ -702,8 +697,6 @@ out:
 		struct lpfc_sli_ring *next_ring = &psli->ring[psli->next_ring];
 
 		lpfc_clear_la(phba, pmb);
-		printk(KERN_ERR "%s (%d): do clear_la\n",
-		       __FUNCTION__, __LINE__);
 		pmb->mbox_cmpl = lpfc_mbx_cmpl_clear_la;
 		pmb->vport = vport;
 		if (lpfc_sli_issue_mbox(phba, pmb, (MBX_NOWAIT | MBX_STOP_IOCB))
@@ -713,8 +706,6 @@ out:
 			extra_ring->flag &= ~LPFC_STOP_IOCB_EVENT;
 			fcp_ring->flag &= ~LPFC_STOP_IOCB_EVENT;
 			next_ring->flag &= ~LPFC_STOP_IOCB_EVENT;
-			printk(KERN_ERR "%s (%d): vport ready\n",
-			       __FUNCTION__, __LINE__);
 			vport->port_state = LPFC_VPORT_READY;
 		}
 	} else {
@@ -875,12 +866,9 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 
 	/* Check for error */
 	if (mb->mbxStatus) {
-		lpfc_printf_log(phba,
-				KERN_INFO,
-				LOG_LINK_EVENT,
+		lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT,
 				"%d:1307 READ_LA mbox error x%x state x%x\n",
-				phba->brd_no,
-				mb->mbxStatus, vport->port_state);
+				phba->brd_no, mb->mbxStatus, vport->port_state);
 		lpfc_mbx_issue_link_down(phba);
 		phba->link_state = LPFC_HBA_ERROR;
 		goto lpfc_mbx_cmpl_read_la_free_mbuf;
@@ -955,7 +943,6 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 	struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) pmb->context1;
 	struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
 
-
 	pmb->context1 = NULL;
 
 	/* Good status, call state machine */
@@ -1553,6 +1540,7 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
 		mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
 		if (mbox) {
 			lpfc_unreg_login(phba, ndlp->nlp_rpi, mbox);
+			mbox->vport = vport;
 			mbox->mbox_cmpl=lpfc_sli_def_mbox_cmpl;
 			rc = lpfc_sli_issue_mbox
 				    (phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB));
@@ -1925,8 +1913,6 @@ lpfc_disc_start(struct lpfc_vport *vport)
 	if (vport->port_state < LPFC_VPORT_READY && !clear_la_pending) {
 		if (vport->port_type == LPFC_PHYSICAL_PORT) {
 		/* If we get here, there is nothing to ADISC */
-			printk(KERN_ERR "%s (%d): do clear_la\n",
-			       __FUNCTION__, __LINE__);
 			lpfc_issue_clear_la(phba, vport);
 		} else if (!(vport->fc_flag & FC_ABORT_DISCOVERY)) {
 
@@ -1940,8 +1926,6 @@ lpfc_disc_start(struct lpfc_vport *vport)
 				vport->fc_flag &= ~FC_NDISC_ACTIVE;
 				spin_unlock_irq(shost->host_lock);
 			}
-			printk(KERN_ERR "%s (%d): vport ready\n",
-			       __FUNCTION__, __LINE__);
 			vport->port_state = LPFC_VPORT_READY;
 		}
 	} else {
@@ -2095,13 +2079,10 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
 	if (!(vport->fc_flag & FC_DISC_TMO))
 		return;
 
-
 	spin_lock_irq(shost->host_lock);
 	vport->fc_flag &= ~FC_DISC_TMO;
 	spin_unlock_irq(shost->host_lock);
 
-	printk(KERN_ERR "%s (%d): link_state = %d, port_state = %d\n",
-	       __FUNCTION__, __LINE__, phba->link_state, vport->port_state);
 	switch (vport->port_state) {
 
 	case LPFC_LOCAL_CFG_LINK:
@@ -2109,9 +2090,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
 	 * FAN
 	 */
 				/* FAN timeout */
-		lpfc_printf_log(phba,
-				 KERN_WARNING,
-				 LOG_DISCOVERY,
+		lpfc_printf_log(phba, KERN_WARNING, LOG_DISCOVERY,
 				 "%d:0221 FAN timeout\n",
 				 phba->brd_no);
 
@@ -2138,9 +2117,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
 	case LPFC_FLOGI:
 	/* port_state is identically LPFC_FLOGI while waiting for FLOGI cmpl */
 		/* Initial FLOGI timeout */
-		lpfc_printf_log(phba,
-				 KERN_ERR,
-				 LOG_DISCOVERY,
+		lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
 				 "%d:0222 Initial FLOGI timeout\n",
 				 phba->brd_no);
 
@@ -2203,8 +2180,6 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
 
 		phba->link_state = LPFC_CLEAR_LA;
 		lpfc_clear_la(phba, clearlambox);
-		printk(KERN_ERR "%s (%d): do clear_la\n",
-		       __FUNCTION__, __LINE__);
 		clearlambox->mbox_cmpl = lpfc_mbx_cmpl_clear_la;
 		clearlambox->vport = vport;
 		rc = lpfc_sli_issue_mbox(phba, clearlambox,
@@ -2230,6 +2205,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
 		lpfc_init_link(phba, initlinkmbox, phba->cfg_topology,
 			       phba->cfg_link_speed);
 		initlinkmbox->mb.un.varInitLnk.lipsr_AL_PA = 0;
+		initlinkmbox->vport = vport;
 		rc = lpfc_sli_issue_mbox(phba, initlinkmbox,
 					 (MBX_NOWAIT | MBX_STOP_IOCB));
 		lpfc_set_loopback_flag(phba);
@@ -2240,9 +2216,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
 
 	case LPFC_DISC_AUTH:
 	/* Node Authentication timeout */
-		lpfc_printf_log(phba,
-				 KERN_ERR,
-				 LOG_DISCOVERY,
+		lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
 				 "%d:0227 Node Authentication timeout\n",
 				 phba->brd_no);
 		lpfc_disc_flush_list(vport);
@@ -2259,8 +2233,6 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
 		}
 		phba->link_state = LPFC_CLEAR_LA;
 		lpfc_clear_la(phba, clearlambox);
-		printk(KERN_ERR "%s (%d): do clear_la\n",
-		       __FUNCTION__, __LINE__);
 		clearlambox->mbox_cmpl = lpfc_mbx_cmpl_clear_la;
 		clearlambox->vport = vport;
 		rc = lpfc_sli_issue_mbox(phba, clearlambox,
@@ -2273,9 +2245,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
 
 	case LPFC_VPORT_READY:
 		if (vport->fc_flag & FC_RSCN_MODE) {
-			lpfc_printf_log(phba,
-					KERN_ERR,
-					LOG_DISCOVERY,
+			lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
 					"%d:0231 RSCN timeout Data: x%x x%x\n",
 					phba->brd_no,
 					vport->fc_ns_retry, LPFC_MAX_NS_RETRY);
@@ -2291,13 +2261,10 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
 	case LPFC_STATE_UNKNOWN:
 	case LPFC_NS_REG:
 	case LPFC_BUILD_DISC_LIST:
-		lpfc_printf_log(phba,
-				KERN_ERR,
-				LOG_DISCOVERY,
+		lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
 				"%d:0229 Unexpected discovery timeout, vport "
 				"State x%x\n",
-				vport->port_state,
-				phba->brd_no);
+				vport->port_state, phba->brd_no);
 
 		break;
 	}
@@ -2305,9 +2272,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
 	switch (phba->link_state) {
 	case LPFC_CLEAR_LA:
 	/* CLEAR LA timeout */
-		lpfc_printf_log(phba,
-				KERN_ERR,
-				LOG_DISCOVERY,
+		lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
 				"%d:0228 CLEAR LA timeout\n",
 				phba->brd_no);
 		clrlaerr = 1;
@@ -2320,9 +2285,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
 	case LPFC_LINK_DOWN:
 	case LPFC_LINK_UP:
 	case LPFC_HBA_ERROR:
-		lpfc_printf_log(phba,
-				KERN_ERR,
-				LOG_DISCOVERY,
+		lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
 				"%d:0230 Unexpected timeout, hba link "
 				"state x%x\n",
 				phba->brd_no, phba->link_state);
@@ -2335,8 +2298,6 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
 		psli->ring[(psli->extra_ring)].flag &= ~LPFC_STOP_IOCB_EVENT;
 		psli->ring[(psli->fcp_ring)].flag &= ~LPFC_STOP_IOCB_EVENT;
 		psli->ring[(psli->next_ring)].flag &= ~LPFC_STOP_IOCB_EVENT;
-		printk(KERN_ERR "%s (%d): vport ready\n",
-		       __FUNCTION__, __LINE__);
 		vport->port_state = LPFC_VPORT_READY;
 	}
 
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index c4be6dc00c4c..430416805e85 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -59,6 +59,11 @@
 #define SLI2_IOCB_CMD_R3XTRA_ENTRIES 24
 #define SLI2_IOCB_RSP_R3XTRA_ENTRIES 32
 
+#define SLI2_IOCB_CMD_SIZE	32
+#define SLI2_IOCB_RSP_SIZE	32
+#define SLI3_IOCB_CMD_SIZE	128
+#define SLI3_IOCB_RSP_SIZE	64
+
 /* Common Transport structures and definitions */
 
 union CtRevisionId {
@@ -1255,6 +1260,7 @@ typedef struct {		/* FireFly BIU registers */
 #define MBX_CONFIG_FARP     0x25
 #define MBX_BEACON          0x2A
 
+#define MBX_CONFIG_HBQ	    0x7C
 #define MBX_LOAD_AREA       0x81
 #define MBX_RUN_BIU_DIAG64  0x84
 #define MBX_CONFIG_PORT     0x88
@@ -1334,6 +1340,10 @@ typedef struct {		/* FireFly BIU registers */
 #define CMD_FCP_TRECEIVE64_CX   0xA1
 #define CMD_FCP_TRSP64_CX       0xA3
 
+#define CMD_IOCB_RCV_SEQ64_CX	0xB5
+#define CMD_IOCB_RCV_ELS64_CX	0xB7
+#define CMD_IOCB_RCV_CONT64_CX	0xBB
+
 #define CMD_GEN_REQUEST64_CR    0xC2
 #define CMD_GEN_REQUEST64_CX    0xC3
 
@@ -1560,6 +1570,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_LIRP_LILP              0x80 /* LIRP / LILP is disabled */
 
 #define FLAGS_TOPOLOGY_FAILOVER      0x0400	/* Bit 10 */
@@ -1817,6 +1828,13 @@ typedef struct {
 				      structure */
 		struct ulp_bde64 sp64;
 	} un;
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint16_t rsvd3;
+	uint16_t vpi;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint16_t vpi;
+	uint16_t rsvd3;
+#endif
 } READ_SPARM_VAR;
 
 /* Structure for MB Command READ_STATUS (14) */
@@ -1917,11 +1935,17 @@ typedef struct {
 #ifdef __BIG_ENDIAN_BITFIELD
 	uint32_t cv:1;
 	uint32_t rr:1;
-	uint32_t rsvd1:29;
+	uint32_t rsvd2:2;
+	uint32_t v3req:1;
+	uint32_t v3rsp:1;
+	uint32_t rsvd1:25;
 	uint32_t rv:1;
 #else	/*  __LITTLE_ENDIAN_BITFIELD */
 	uint32_t rv:1;
-	uint32_t rsvd1:29;
+	uint32_t rsvd1:25;
+	uint32_t v3rsp:1;
+	uint32_t v3req:1;
+	uint32_t rsvd2:2;
 	uint32_t rr:1;
 	uint32_t cv:1;
 #endif
@@ -1971,8 +1995,8 @@ typedef struct {
 	uint8_t sli1FwName[16];
 	uint32_t sli2FwRev;
 	uint8_t sli2FwName[16];
-	uint32_t rsvd2;
-	uint32_t RandomData[7];
+	uint32_t sli3Feat;
+	uint32_t RandomData[6];
 } READ_REV_VAR;
 
 /* Structure for MB Command READ_LINK_STAT (18) */
@@ -2012,6 +2036,14 @@ typedef struct {
 		struct ulp_bde64 sp64;
 	} un;
 
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint16_t rsvd6;
+	uint16_t vpi;
+#else /* __LITTLE_ENDIAN_BITFIELD */
+	uint16_t vpi;
+	uint16_t rsvd6;
+#endif
+
 } REG_LOGIN_VAR;
 
 /* Word 30 contents for REG_LOGIN */
@@ -2036,9 +2068,21 @@ typedef struct {
 #ifdef __BIG_ENDIAN_BITFIELD
 	uint16_t rsvd1;
 	uint16_t rpi;
+	uint32_t rsvd2;
+	uint32_t rsvd3;
+	uint32_t rsvd4;
+	uint32_t rsvd5;
+	uint16_t rsvd6;
+	uint16_t vpi;
 #else	/*  __LITTLE_ENDIAN_BITFIELD */
 	uint16_t rpi;
 	uint16_t rsvd1;
+	uint32_t rsvd2;
+	uint32_t rsvd3;
+	uint32_t rsvd4;
+	uint32_t rsvd5;
+	uint16_t vpi;
+	uint16_t rsvd6;
 #endif
 } UNREG_LOGIN_VAR;
 
@@ -2046,6 +2090,17 @@ typedef struct {
 
 typedef struct {
 	uint32_t did;
+	uint32_t rsvd2;
+	uint32_t rsvd3;
+	uint32_t rsvd4;
+	uint32_t rsvd5;
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint16_t rsvd6;
+	uint16_t vpi;
+#else
+	uint16_t vpi;
+	uint16_t rsvd6;
+#endif
 } UNREG_D_ID_VAR;
 
 /* Structure for MB Command READ_LA (21) */
@@ -2177,13 +2232,240 @@ typedef struct {
 #define  DMP_RSP_OFFSET          0x14   /* word 5 contains first word of rsp */
 #define  DMP_RSP_SIZE            0x6C   /* maximum of 27 words of rsp data */
 
+struct hbq_mask {
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint8_t tmatch;
+	uint8_t tmask;
+	uint8_t rctlmatch;
+	uint8_t rctlmask;
+#else	/*  __LITTLE_ENDIAN */
+	uint8_t rctlmask;
+	uint8_t rctlmatch;
+	uint8_t tmask;
+	uint8_t tmatch;
+#endif
+};
+
+
+/* Structure for MB Command CONFIG_HBQ (7c) */
+
+struct config_hbq_var {
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t rsvd1      :7;
+	uint32_t recvNotify :1;     /* Receive Notification */
+	uint32_t numMask    :8;     /* # Mask Entries       */
+	uint32_t profile    :8;     /* Selection Profile    */
+	uint32_t rsvd2      :8;
+#else	/*  __LITTLE_ENDIAN */
+	uint32_t rsvd2      :8;
+	uint32_t profile    :8;     /* Selection Profile    */
+	uint32_t numMask    :8;     /* # Mask Entries       */
+	uint32_t recvNotify :1;     /* Receive Notification */
+	uint32_t rsvd1      :7;
+#endif
+
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t hbqId      :16;
+	uint32_t rsvd3      :12;
+	uint32_t ringMask   :4;
+#else	/*  __LITTLE_ENDIAN */
+	uint32_t ringMask   :4;
+	uint32_t rsvd3      :12;
+	uint32_t hbqId      :16;
+#endif
+
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t entry_count :16;
+	uint32_t rsvd4        :8;
+	uint32_t headerLen    :8;
+#else	/*  __LITTLE_ENDIAN */
+	uint32_t headerLen    :8;
+	uint32_t rsvd4        :8;
+	uint32_t entry_count :16;
+#endif
+
+	uint32_t hbqaddrLow;
+	uint32_t hbqaddrHigh;
+
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t rsvd5      :31;
+	uint32_t logEntry   :1;
+#else	/*  __LITTLE_ENDIAN */
+	uint32_t logEntry   :1;
+	uint32_t rsvd5      :31;
+#endif
+
+	uint32_t rsvd6;    /* w7 */
+	uint32_t rsvd7;    /* w8 */
+	uint32_t rsvd8;    /* w9 */
+
+	struct hbq_mask hbqMasks[6];
+
+
+	union {
+		uint32_t allprofiles[12];
+
+		struct {
+			#ifdef __BIG_ENDIAN_BITFIELD
+				uint32_t	seqlenoff	:16;
+				uint32_t	maxlen		:16;
+			#else	/*  __LITTLE_ENDIAN */
+				uint32_t	maxlen		:16;
+				uint32_t	seqlenoff	:16;
+			#endif
+			#ifdef __BIG_ENDIAN_BITFIELD
+				uint32_t	rsvd1		:28;
+				uint32_t	seqlenbcnt	:4;
+			#else	/*  __LITTLE_ENDIAN */
+				uint32_t	seqlenbcnt	:4;
+				uint32_t	rsvd1		:28;
+			#endif
+			uint32_t rsvd[10];
+		} profile2;
+
+		struct {
+			#ifdef __BIG_ENDIAN_BITFIELD
+				uint32_t	seqlenoff	:16;
+				uint32_t	maxlen		:16;
+			#else	/*  __LITTLE_ENDIAN */
+				uint32_t	maxlen		:16;
+				uint32_t	seqlenoff	:16;
+			#endif
+			#ifdef __BIG_ENDIAN_BITFIELD
+				uint32_t	cmdcodeoff	:28;
+				uint32_t	rsvd1		:12;
+				uint32_t	seqlenbcnt	:4;
+			#else	/*  __LITTLE_ENDIAN */
+				uint32_t	seqlenbcnt	:4;
+				uint32_t	rsvd1		:12;
+				uint32_t	cmdcodeoff	:28;
+			#endif
+			uint32_t cmdmatch[8];
+
+			uint32_t rsvd[2];
+		} profile3;
+
+		struct {
+			#ifdef __BIG_ENDIAN_BITFIELD
+				uint32_t	seqlenoff	:16;
+				uint32_t	maxlen		:16;
+			#else	/*  __LITTLE_ENDIAN */
+				uint32_t	maxlen		:16;
+				uint32_t	seqlenoff	:16;
+			#endif
+			#ifdef __BIG_ENDIAN_BITFIELD
+				uint32_t	cmdcodeoff	:28;
+				uint32_t	rsvd1		:12;
+				uint32_t	seqlenbcnt	:4;
+			#else	/*  __LITTLE_ENDIAN */
+				uint32_t	seqlenbcnt	:4;
+				uint32_t	rsvd1		:12;
+				uint32_t	cmdcodeoff	:28;
+			#endif
+			uint32_t cmdmatch[8];
+
+			uint32_t rsvd[2];
+		} profile5;
+
+	} profiles;
+
+};
+
+
 
 /* Structure for MB Command CONFIG_PORT (0x88) */
 typedef struct {
-	uint32_t pcbLen;
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t cBE       :  1;
+	uint32_t cET       :  1;
+	uint32_t cHpcb     :  1;
+	uint32_t cMA       :  1;
+	uint32_t sli_mode  :  4;
+	uint32_t pcbLen    : 24;       /* bit 23:0  of memory based port
+					* config block */
+#else	/*  __LITTLE_ENDIAN */
+	uint32_t pcbLen    : 24;       /* bit 23:0  of memory based port
+					* config block */
+	uint32_t sli_mode  :  4;
+	uint32_t cMA       :  1;
+	uint32_t cHpcb     :  1;
+	uint32_t cET       :  1;
+	uint32_t cBE       :  1;
+#endif
+
 	uint32_t pcbLow;       /* bit 31:0  of memory based port config block */
 	uint32_t pcbHigh;      /* bit 63:32 of memory based port config block */
-	uint32_t hbainit[5];
+	uint32_t hbainit[6];
+
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t rsvd      : 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 rsvd      : 24;  /* Reserved                             */
+#endif
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t rsvd2     : 24;  /* Reserved                             */
+	uint32_t gmv	   :  1;  /* Grant Max VPIs                       */
+	uint32_t gcrp	   :  1;  /* Grant Command Ring Polling           */
+	uint32_t gsah	   :  1;  /* Grant Synchronous Abort Handling     */
+	uint32_t ghbs	   :  1;  /* Grant Host Backing Store             */
+	uint32_t ginb	   :  1;  /* Grant Interrupt Notification Block   */
+	uint32_t gerbm	   :  1;  /* Grant ERBM Request                   */
+	uint32_t gmx	   :  1;  /* Grant Max XRIs                       */
+	uint32_t gmr	   :  1;  /* Grant Max RPIs                       */
+#else	/*  __LITTLE_ENDIAN */
+	uint32_t gmr	   :  1;  /* Grant Max RPIs                       */
+	uint32_t gmx	   :  1;  /* Grant Max XRIs                       */
+	uint32_t gerbm	   :  1;  /* Grant ERBM Request                   */
+	uint32_t ginb	   :  1;  /* Grant Interrupt Notification Block   */
+	uint32_t ghbs	   :  1;  /* Grant Host Backing Store             */
+	uint32_t gsah	   :  1;  /* Grant Synchronous Abort Handling     */
+	uint32_t gcrp	   :  1;  /* Grant Command Ring Polling           */
+	uint32_t gmv	   :  1;  /* Grant Max VPIs                       */
+	uint32_t rsvd2     : 24;  /* Reserved                             */
+#endif
+
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t max_rpi   : 16;  /* Max RPIs Port should configure       */
+	uint32_t max_xri   : 16;  /* Max XRIs Port should configure       */
+#else	/*  __LITTLE_ENDIAN */
+	uint32_t max_xri   : 16;  /* Max XRIs Port should configure       */
+	uint32_t max_rpi   : 16;  /* Max RPIs Port should configure       */
+#endif
+
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t max_hbq   : 16;  /* Max HBQs Host expect to configure    */
+	uint32_t rsvd3     : 16;  /* Max HBQs Host expect to configure    */
+#else	/*  __LITTLE_ENDIAN */
+	uint32_t rsvd3     : 16;  /* Max HBQs Host expect to configure    */
+	uint32_t max_hbq   : 16;  /* Max HBQs Host expect to configure    */
+#endif
+
+	uint32_t rsvd4;           /* Reserved                             */
+
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t rsvd5      : 16;  /* Reserved                             */
+	uint32_t max_vpi    : 16;  /* Max number of virt N-Ports           */
+#else	/*  __LITTLE_ENDIAN */
+	uint32_t max_vpi    : 16;  /* Max number of virt N-Ports           */
+	uint32_t rsvd5      : 16;  /* Reserved                             */
+#endif
+
 } CONFIG_PORT_VAR;
 
 /* SLI-2 Port Control Block */
@@ -2261,33 +2543,38 @@ typedef struct {
 #define MAILBOX_CMD_SIZE	(MAILBOX_CMD_WSIZE * sizeof(uint32_t))
 
 typedef union {
-	uint32_t varWords[MAILBOX_CMD_WSIZE - 1];
-	LOAD_SM_VAR varLdSM;	/* cmd =  1 (LOAD_SM)        */
-	READ_NV_VAR varRDnvp;	/* cmd =  2 (READ_NVPARMS)   */
-	WRITE_NV_VAR varWTnvp;	/* cmd =  3 (WRITE_NVPARMS)  */
+	uint32_t varWords[MAILBOX_CMD_WSIZE - 1]; /* first word is type/
+						    * feature/max ring number
+						    */
+	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)      */
 	DOWN_LINK_VAR varDwnLnk;	/* cmd =  6 (DOWN_LINK)      */
-	CONFIG_LINK varCfgLnk;	/* cmd =  7 (CONFIG_LINK)    */
-	PART_SLIM_VAR varSlim;	/* cmd =  8 (PART_SLIM)      */
+	CONFIG_LINK varCfgLnk;		/* cmd =  7 (CONFIG_LINK)    */
+	PART_SLIM_VAR varSlim;		/* cmd =  8 (PART_SLIM)      */
 	CONFIG_RING_VAR varCfgRing;	/* cmd =  9 (CONFIG_RING)    */
 	RESET_RING_VAR varRstRing;	/* cmd = 10 (RESET_RING)     */
 	READ_CONFIG_VAR varRdConfig;	/* cmd = 11 (READ_CONFIG)    */
 	READ_RCONF_VAR varRdRConfig;	/* cmd = 12 (READ_RCONFIG)   */
 	READ_SPARM_VAR varRdSparm;	/* cmd = 13 (READ_SPARM(64)) */
 	READ_STATUS_VAR varRdStatus;	/* cmd = 14 (READ_STATUS)    */
-	READ_RPI_VAR varRdRPI;	/* cmd = 15 (READ_RPI(64))   */
-	READ_XRI_VAR varRdXRI;	/* cmd = 16 (READ_XRI)       */
-	READ_REV_VAR varRdRev;	/* cmd = 17 (READ_REV)       */
-	READ_LNK_VAR varRdLnk;	/* cmd = 18 (READ_LNK_STAT)  */
+	READ_RPI_VAR varRdRPI;		/* cmd = 15 (READ_RPI(64))   */
+	READ_XRI_VAR varRdXRI;		/* cmd = 16 (READ_XRI)       */
+	READ_REV_VAR varRdRev;		/* cmd = 17 (READ_REV)       */
+	READ_LNK_VAR varRdLnk;		/* cmd = 18 (READ_LNK_STAT)  */
 	REG_LOGIN_VAR varRegLogin;	/* cmd = 19 (REG_LOGIN(64))  */
 	UNREG_LOGIN_VAR varUnregLogin;	/* cmd = 20 (UNREG_LOGIN)    */
-	READ_LA_VAR varReadLA;	/* cmd = 21 (READ_LA(64))    */
+	READ_LA_VAR varReadLA;		/* cmd = 21 (READ_LA(64))    */
 	CLEAR_LA_VAR varClearLA;	/* cmd = 22 (CLEAR_LA)       */
-	DUMP_VAR varDmp;	/* Warm Start DUMP mbx cmd   */
-	UNREG_D_ID_VAR varUnregDID; /* cmd = 0x23 (UNREG_D_ID)   */
-	CONFIG_FARP_VAR varCfgFarp; /* cmd = 0x25 (CONFIG_FARP)  NEW_FEATURE */
-	CONFIG_PORT_VAR varCfgPort; /* cmd = 0x88 (CONFIG_PORT)  */
+	DUMP_VAR varDmp;		/* Warm Start DUMP mbx cmd   */
+	UNREG_D_ID_VAR varUnregDID;	/* cmd = 0x23 (UNREG_D_ID)   */
+	CONFIG_FARP_VAR varCfgFarp;	/* cmd = 0x25 (CONFIG_FARP)
+					 * NEW_FEATURE
+					 */
+	struct config_hbq_var varCfgHbq;/* cmd = 0x7c (CONFIG_HBQ)  */
+	CONFIG_PORT_VAR varCfgPort;	/* cmd = 0x88 (CONFIG_PORT)  */
 } MAILVARIANTS;
 
 /*
@@ -2304,16 +2591,30 @@ struct lpfc_pgp {
 	__le32 rspPutInx;
 };
 
-typedef struct _SLI2_DESC {
-	struct lpfc_hgp host[MAX_RINGS];
+struct sli2_desc {
 	uint32_t unused1[16];
+	struct lpfc_hgp host[MAX_RINGS];
+	struct lpfc_pgp port[MAX_RINGS];
+};
+
+struct sli3_desc {
+	struct lpfc_hgp host[MAX_RINGS];
+	uint32_t reserved[8];
+	uint32_t hbq_put[16];
+};
+
+struct sli3_pgp {
 	struct lpfc_pgp port[MAX_RINGS];
-} SLI2_DESC;
+	uint32_t hbq_get[16];
+};
 
 typedef union {
-	SLI2_DESC s2;
+	struct sli2_desc s2;
+	struct sli3_desc s3;
+	struct sli3_pgp  s3_pgp;
 } SLI_VAR;
 
+
 typedef struct {
 #ifdef __BIG_ENDIAN_BITFIELD
 	uint16_t mbxStatus;
@@ -2617,6 +2918,23 @@ typedef struct {
 	uint32_t fcpt_Length;	/* transfer ready for IWRITE */
 } FCPT_FIELDS64;
 
+/* IOCB Command template for CMD_IOCB_RCV_ELS64_CX (0xB7)
+   or CMD_IOCB_RCV_SEQ64_CX (0xB5) */
+
+struct rcv_sli3 {
+	uint32_t word8Rsvd;
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint16_t vpi;
+	uint16_t word9Rsvd;
+#else  /*  __LITTLE_ENDIAN */
+	uint16_t word9Rsvd;
+	uint16_t vpi;
+#endif
+	uint32_t word10Rsvd;
+	uint32_t acc_len;      /* accumulated length */
+	struct ulp_bde64 bde2;
+};
+
 typedef struct _IOCB {	/* IOCB structure */
 	union {
 		GENERIC_RSP grsp;	/* Generic response */
@@ -2631,8 +2949,8 @@ typedef struct _IOCB {	/* IOCB structure */
 
 		/* SLI-2 structures */
 
-		struct ulp_bde64 cont64[2];	/* up to 2 64 bit continuation
-					   bde_64s */
+		struct ulp_bde64 cont64[2];  /* up to 2 64 bit continuation
+					      * bde_64s */
 		ELS_REQUEST64 elsreq64;	/* ELS_REQUEST template */
 		GEN_REQUEST64 genreq64;	/* GEN_REQUEST template */
 		RCV_ELS_REQ64 rcvels64;	/* RCV_ELS_REQ template */
@@ -2693,7 +3011,16 @@ 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 */
+	} unsli3;
+
+#define ulpCt_h ulpXS
+#define ulpCt_l ulpFCP2Rcvy
 
+#define IOCB_FCP	   1	/* IOCB is used for FCP ELS cmds-ulpRsvByte */
+#define IOCB_IP		   2	/* IOCB is used for IP ELS cmds */
 #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 */
@@ -2724,21 +3051,33 @@ typedef struct _IOCB {	/* IOCB structure */
 
 } IOCB_t;
 
+/* Structure used for a single HBQ entry */
+struct lpfc_hbq_entry {
+	struct ulp_bde64 bde;
+	uint32_t buffer_tag;
+};
+
 
 #define SLI1_SLIM_SIZE   (4 * 1024)
 
 /* Up to 498 IOCBs will fit into 16k
  * 256 (MAILBOX_t) + 140 (PCB_t) + ( 32 (IOCB_t) * 498 ) = < 16384
  */
-#define SLI2_SLIM_SIZE   (16 * 1024)
+#define SLI2_SLIM_SIZE   (64 * 1024)
 
 /* Maximum IOCBs that will fit in SLI2 slim */
 #define MAX_SLI2_IOCB    498
+#define MAX_SLIM_IOCB_SIZE (SLI2_SLIM_SIZE - \
+			    (sizeof(MAILBOX_t) + sizeof(PCB_t)))
+
+/* HBQ entries are 4 words each = 4k */
+#define LPFC_TOTAL_HBQ_SIZE (sizeof(struct lpfc_hbq_entry) *  \
+			     lpfc_sli_hbq_count())
 
 struct lpfc_sli2_slim {
 	MAILBOX_t mbx;
 	PCB_t pcb;
-	IOCB_t IOCBs[MAX_SLI2_IOCB];
+	IOCB_t IOCBs[MAX_SLIM_IOCB_SIZE];
 };
 
 /*
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index e11c4cda0f3f..e50c5ad252f9 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -49,6 +49,12 @@ static int lpfc_post_rcv_buf(struct lpfc_hba *);
 static struct scsi_transport_template *lpfc_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");
 
 
 /************************************************************************/
@@ -102,9 +108,7 @@ lpfc_config_port_prep(struct lpfc_hba *phba)
 		rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
 
 		if (rc != MBX_SUCCESS) {
-			lpfc_printf_log(phba,
-					KERN_ERR,
-					LOG_MBOX,
+			lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
 					"%d:0324 Config Port initialization "
 					"error, mbxCmd x%x READ_NVPARM, "
 					"mbxStatus x%x\n",
@@ -123,9 +127,7 @@ lpfc_config_port_prep(struct lpfc_hba *phba)
 	lpfc_read_rev(phba, pmb);
 	rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
 	if (rc != MBX_SUCCESS) {
-		lpfc_printf_log(phba,
-				KERN_ERR,
-				LOG_INIT,
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 				"%d:0439 Adapter failed to init, mbxCmd x%x "
 				"READ_REV, mbxStatus x%x\n",
 				phba->brd_no,
@@ -148,6 +150,9 @@ lpfc_config_port_prep(struct lpfc_hba *phba)
 		return -ERESTART;
 	}
 
+	if (phba->sli_rev == 3 && !mb->un.varRdRev.v3rsp)
+		return -EINVAL;
+
 	/* Save information as VPD data */
 	vp->rev.rBit = 1;
 	vp->rev.sli1FwRev = mb->un.varRdRev.sli1FwRev;
@@ -236,10 +241,9 @@ lpfc_config_port_post(struct lpfc_hba *phba)
 
 	/* Get login parameters for NID.  */
 	lpfc_read_sparam(phba, pmb);
+	pmb->vport = vport;
 	if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) {
-		lpfc_printf_log(phba,
-				KERN_ERR,
-				LOG_INIT,
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 				"%d:0448 Adapter failed init, mbxCmd x%x "
 				"READ_SPARM mbxStatus x%x\n",
 				phba->brd_no,
@@ -296,10 +300,9 @@ lpfc_config_port_post(struct lpfc_hba *phba)
 	}
 
 	lpfc_read_config(phba, pmb);
+	pmb->vport = vport;
 	if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) {
-		lpfc_printf_log(phba,
-				KERN_ERR,
-				LOG_INIT,
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 				"%d:0453 Adapter failed to init, mbxCmd x%x "
 				"READ_CONFIG, mbxStatus x%x\n",
 				phba->brd_no,
@@ -331,9 +334,7 @@ lpfc_config_port_post(struct lpfc_hba *phba)
 	    || ((phba->cfg_link_speed == LINK_SPEED_10G)
 		&& !(phba->lmt & LMT_10Gb))) {
 		/* Reset link speed to auto */
-		lpfc_printf_log(phba,
-			KERN_WARNING,
-			LOG_LINK_EVENT,
+		lpfc_printf_log(phba, KERN_WARNING, LOG_LINK_EVENT,
 			"%d:1302 Invalid speed for this board: "
 			"Reset link speed to auto: x%x\n",
 			phba->brd_no,
@@ -352,7 +353,8 @@ lpfc_config_port_post(struct lpfc_hba *phba)
 		psli->ring[psli->next_ring].flag |= LPFC_STOP_IOCB_EVENT;
 
 	/* Post receive buffers for desired rings */
-	lpfc_post_rcv_buf(phba);
+	if (phba->sli_rev != 3)
+		lpfc_post_rcv_buf(phba);
 
 	/* Enable appropriate host interrupts */
 	spin_lock_irq(&phba->hbalock);
@@ -383,12 +385,11 @@ lpfc_config_port_post(struct lpfc_hba *phba)
 
 	lpfc_init_link(phba, pmb, phba->cfg_topology, phba->cfg_link_speed);
 	pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+	pmb->vport = vport;
 	rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
 	lpfc_set_loopback_flag(phba);
 	if (rc != MBX_SUCCESS) {
-		lpfc_printf_log(phba,
-				KERN_ERR,
-				LOG_INIT,
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 				"%d:0454 Adapter failed to init, mbxCmd x%x "
 				"INIT_LINK, mbxStatus x%x\n",
 				phba->brd_no,
@@ -630,9 +631,7 @@ lpfc_handle_latt_err_exit:
 
 	/* The other case is an error from issue_mbox */
 	if (rc == -ENOMEM)
-		lpfc_printf_log(phba,
-				KERN_WARNING,
-				LOG_MBOX,
+		lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
 			        "%d:0300 READ_LA: no buffers\n",
 				phba->brd_no);
 
@@ -658,9 +657,7 @@ lpfc_parse_vpd(struct lpfc_hba *phba, uint8_t *vpd, int len)
 		return 0;
 
 	/* Vital Product */
-	lpfc_printf_log(phba,
-			KERN_INFO,
-			LOG_INIT,
+	lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
 			"%d:0455 Vital Product Data: x%x x%x x%x x%x\n",
 			phba->brd_no,
 			(uint32_t) vpd[0], (uint32_t) vpd[1], (uint32_t) vpd[2],
@@ -1221,9 +1218,7 @@ lpfc_online(struct lpfc_hba *phba)
 	if (!(vport->fc_flag & FC_OFFLINE_MODE))
 		return 0;
 
-	lpfc_printf_log(phba,
-		       KERN_WARNING,
-		       LOG_INIT,
+	lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
 		       "%d:0458 Bring Adapter online\n",
 		       phba->brd_no);
 
@@ -1633,13 +1628,22 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
 
 	memset(phba->slim2p, 0, SLI2_SLIM_SIZE);
 
+	phba->hbqslimp.virt = dma_alloc_coherent(&phba->pcidev->dev,
+						 lpfc_sli_hbq_size(),
+						 &phba->hbqslimp.phys,
+						 GFP_KERNEL);
+	if (!phba->hbqslimp.virt)
+		goto out_free_slim;
+
+	memset(phba->hbqslimp.virt, 0, lpfc_sli_hbq_size());
+
 	/* Initialize the SLI Layer to run with lpfc HBAs. */
 	lpfc_sli_setup(phba);
 	lpfc_sli_queue_setup(phba);
 
 	error = lpfc_mem_alloc(phba);
 	if (error)
-		goto out_free_slim;
+		goto out_free_hbqslimp;
 
 	/* Initialize and populate the iocb list per host.  */
 	INIT_LIST_HEAD(&phba->lpfc_iocb_list);
@@ -1753,6 +1757,9 @@ out_free_iocbq:
 		phba->total_iocbq_bufs--;
 	}
 	lpfc_mem_free(phba);
+out_free_hbqslimp:
+	dma_free_coherent(&pdev->dev, lpfc_sli_hbq_size(), phba->hbqslimp.virt,
+			  phba->hbqslimp.phys);
 out_free_slim:
 	dma_free_coherent(&pdev->dev, SLI2_SLIM_SIZE, phba->slim2p,
 							phba->slim2p_mapping);
@@ -1811,6 +1818,9 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
 	lpfc_scsi_free(phba);
 	lpfc_mem_free(phba);
 
+	dma_free_coherent(&pdev->dev, lpfc_sli_hbq_size(), phba->hbqslimp.virt,
+			  phba->hbqslimp.phys);
+
 	/* Free resources associated with SLI2 interface */
 	dma_free_coherent(&pdev->dev, SLI2_SLIM_SIZE,
 			  phba->slim2p, phba->slim2p_mapping);
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
index 86757ec53057..977799c2b2c2 100644
--- a/drivers/scsi/lpfc/lpfc_mbox.c
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -232,6 +232,7 @@ 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;
 }
 
@@ -418,6 +419,10 @@ lpfc_config_pcb_setup(struct lpfc_hba * phba)
 	for (i = 0; i < psli->num_rings; i++) {
 		pring = &psli->ring[i];
 
+		pring->sizeCiocb = phba->sli_rev == 3 ? SLI3_IOCB_CMD_SIZE:
+			SLI2_IOCB_CMD_SIZE;
+		pring->sizeRiocb = phba->sli_rev == 3 ? SLI3_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)) {
@@ -432,8 +437,7 @@ 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] -
@@ -444,8 +448,7 @@ lpfc_config_pcb_setup(struct lpfc_hba * phba)
 		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] -
@@ -463,11 +466,103 @@ lpfc_read_rev(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 	MAILBOX_t *mb = &pmb->mb;
 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
 	mb->un.varRdRev.cv = 1;
+	mb->un.varRdRev.v3req = 1; /* Request SLI3 info */
 	mb->mbxCommand = MBX_READ_REV;
 	mb->mbxOwner = OWN_HOST;
 	return;
 }
 
+static void
+lpfc_build_hbq_profile2(struct config_hbq_var *hbqmb,
+			struct lpfc_hbq_init  *hbq_desc)
+{
+	hbqmb->profiles.profile2.seqlenbcnt = hbq_desc->seqlenbcnt;
+	hbqmb->profiles.profile2.maxlen     = hbq_desc->maxlen;
+	hbqmb->profiles.profile2.seqlenoff  = hbq_desc->seqlenoff;
+}
+
+static void
+lpfc_build_hbq_profile3(struct config_hbq_var *hbqmb,
+			struct lpfc_hbq_init  *hbq_desc)
+{
+	hbqmb->profiles.profile3.seqlenbcnt = hbq_desc->seqlenbcnt;
+	hbqmb->profiles.profile3.maxlen     = hbq_desc->maxlen;
+	hbqmb->profiles.profile3.cmdcodeoff = hbq_desc->cmdcodeoff;
+	hbqmb->profiles.profile3.seqlenoff  = hbq_desc->seqlenoff;
+	memcpy(&hbqmb->profiles.profile3.cmdmatch, hbq_desc->cmdmatch,
+	       sizeof(hbqmb->profiles.profile3.cmdmatch));
+}
+
+static void
+lpfc_build_hbq_profile5(struct config_hbq_var *hbqmb,
+			struct lpfc_hbq_init  *hbq_desc)
+{
+	hbqmb->profiles.profile5.seqlenbcnt = hbq_desc->seqlenbcnt;
+	hbqmb->profiles.profile5.maxlen     = hbq_desc->maxlen;
+	hbqmb->profiles.profile5.cmdcodeoff = hbq_desc->cmdcodeoff;
+	hbqmb->profiles.profile5.seqlenoff  = hbq_desc->seqlenoff;
+	memcpy(&hbqmb->profiles.profile5.cmdmatch, hbq_desc->cmdmatch,
+	       sizeof(hbqmb->profiles.profile5.cmdmatch));
+}
+
+void
+lpfc_config_hbq(struct lpfc_hba *phba, struct lpfc_hbq_init *hbq_desc,
+		uint32_t hbq_entry_index, LPFC_MBOXQ_t *pmb)
+{
+	int i;
+	MAILBOX_t *mb = &pmb->mb;
+	struct config_hbq_var *hbqmb = &mb->un.varCfgHbq;
+
+	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
+	hbqmb->entry_count = hbq_desc->entry_count;   /* # entries in HBQ */
+	hbqmb->recvNotify = hbq_desc->rn;             /* Receive
+						       * Notification */
+	hbqmb->numMask    = hbq_desc->mask_count;     /* # R_CTL/TYPE masks
+						       * # in words 0-19 */
+	hbqmb->profile    = hbq_desc->profile;        /* Selection profile:
+						       * 0 = all,
+						       * 7 = logentry */
+	hbqmb->ringMask   = hbq_desc->ring_mask;      /* Binds HBQ to a ring
+						       * e.g. Ring0=b0001,
+						       * ring2=b0100 */
+	hbqmb->headerLen  = hbq_desc->headerLen;      /* 0 if not profile 4
+						       * or 5 */
+	hbqmb->logEntry   = hbq_desc->logEntry;       /* Set to 1 if this
+						       * HBQ will be used
+						       * for LogEntry
+						       * buffers */
+	hbqmb->hbqaddrLow = putPaddrLow(phba->hbqslimp.phys) +
+		hbq_entry_index * sizeof(struct lpfc_hbq_entry);
+	hbqmb->hbqaddrHigh = putPaddrHigh(phba->hbqslimp.phys);
+
+	mb->mbxCommand = MBX_CONFIG_HBQ;
+	mb->mbxOwner = OWN_HOST;
+
+	/* 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)
+		lpfc_build_hbq_profile3(hbqmb, hbq_desc);
+	else if (hbq_desc->profile == 5)
+		lpfc_build_hbq_profile5(hbqmb, hbq_desc);
+
+	/* Return if no rctl / type masks for this HBQ */
+	if (!hbq_desc->mask_count)
+		return;
+
+	/* Otherwise we setup specific rctl / type masks for this HBQ */
+	for (i = 0; i < hbq_desc->mask_count; i++) {
+		hbqmb->hbqMasks[i].tmatch = hbq_desc->hbqMasks[i].tmatch;
+		hbqmb->hbqMasks[i].tmask  = hbq_desc->hbqMasks[i].tmask;
+		hbqmb->hbqMasks[i].rctlmatch = hbq_desc->hbqMasks[i].rctlmatch;
+		hbqmb->hbqMasks[i].rctlmask  = hbq_desc->hbqMasks[i].rctlmask;
+	}
+
+	return;
+}
+
 void
 lpfc_config_ring(struct lpfc_hba * phba, int ring, LPFC_MBOXQ_t * pmb)
 {
@@ -512,13 +607,14 @@ 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)
 {
+	MAILBOX_t __iomem *mb_slim = (MAILBOX_t __iomem *) phba->MBslimaddr;
 	MAILBOX_t *mb = &pmb->mb;
 	dma_addr_t pdma_addr;
 	uint32_t bar_low, bar_high;
 	size_t offset;
 	struct lpfc_hgp hgp;
-	void __iomem *to_slim;
 	int i;
+	uint32_t pgp_offset;
 
 	memset(pmb, 0, sizeof(LPFC_MBOXQ_t));
 	mb->mbxCommand = MBX_CONFIG_PORT;
@@ -531,12 +627,21 @@ lpfc_config_port(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 	mb->un.varCfgPort.pcbLow = putPaddrLow(pdma_addr);
 	mb->un.varCfgPort.pcbHigh = putPaddrHigh(pdma_addr);
 
+	/* If HBA supports SLI=3 ask for it */
+
+	mb->un.varCfgPort.sli_mode = phba->sli_rev;
+	if (phba->sli_rev == 3) {
+		mb->un.varCfgPort.cerbm = 1; /* Request HBQs */
+		mb->un.varCfgPort.max_hbq = 1; /* Requesting 2 HBQs */
+	}
+
 	/* Now setup pcb */
 	phba->slim2p->pcb.type = TYPE_NATIVE_SLI2;
 	phba->slim2p->pcb.feature = FEATURE_INITIAL_SLI2;
 
 	/* Setup Mailbox pointers */
-	phba->slim2p->pcb.mailBoxSize = sizeof(MAILBOX_t);
+	phba->slim2p->pcb.mailBoxSize = offsetof(MAILBOX_t, us) +
+		sizeof(struct sli2_desc);
 	offset = (uint8_t *)&phba->slim2p->mbx - (uint8_t *)phba->slim2p;
 	pdma_addr = phba->slim2p_mapping + offset;
 	phba->slim2p->pcb.mbAddrHigh = putPaddrHigh(pdma_addr);
@@ -564,29 +669,70 @@ lpfc_config_port(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 	pci_read_config_dword(phba->pcidev, PCI_BASE_ADDRESS_0, &bar_low);
 	pci_read_config_dword(phba->pcidev, PCI_BASE_ADDRESS_1, &bar_high);
 
+	/*
+	 * Set up HGP - Port Memory
+	 *
+	 * The port expects the host get/put pointers to reside in memory
+	 * following the "non-diagnostic" mode mailbox (32 words, 0x80 bytes)
+	 * area of SLIM.  In SLI-2 mode, there's an additional 16 reserved
+	 * words (0x40 bytes).  This area is not reserved if HBQs are
+	 * configured in SLI-3.
+	 *
+	 * CR0Put    - SLI2(no HBQs) = 0xc0, With HBQs = 0x80
+	 * RR0Get                      0xc4              0x84
+	 * CR1Put                      0xc8              0x88
+	 * RR1Get                      0xcc              0x8c
+	 * CR2Put                      0xd0              0x90
+	 * RR2Get                      0xd4              0x94
+	 * CR3Put                      0xd8              0x98
+	 * RR3Get                      0xdc              0x9c
+	 *
+	 * Reserved                    0xa0-0xbf
+	 *    If HBQs configured:
+	 *                         HBQ 0 Put ptr  0xc0
+	 *                         HBQ 1 Put ptr  0xc4
+	 *                         HBQ 2 Put ptr  0xc8
+	 *                         ......
+	 *                         HBQ(M-1)Put Pointer 0xc0+(M-1)*4
+	 *
+	 */
+
+	if (phba->sli_rev == 3) {
+		phba->host_gp = &mb_slim->us.s3.host[0];
+		phba->hbq_put = &mb_slim->us.s3.hbq_put[0];
+	} else {
+		phba->host_gp = &mb_slim->us.s2.host[0];
+		phba->hbq_put = NULL;
+	}
 
 	/* mask off BAR0's flag bits 0 - 3 */
 	phba->slim2p->pcb.hgpAddrLow = (bar_low & PCI_BASE_ADDRESS_MEM_MASK) +
-					(SLIMOFF*sizeof(uint32_t));
+		(void __iomem *) phba->host_gp -
+		(void __iomem *)phba->MBslimaddr;
 	if (bar_low & PCI_BASE_ADDRESS_MEM_TYPE_64)
 		phba->slim2p->pcb.hgpAddrHigh = bar_high;
 	else
 		phba->slim2p->pcb.hgpAddrHigh = 0;
 	/* write HGP data to SLIM at the required longword offset */
 	memset(&hgp, 0, sizeof(struct lpfc_hgp));
-	to_slim = phba->MBslimaddr + (SLIMOFF*sizeof (uint32_t));
 
 	for (i=0; i < phba->sli.num_rings; i++) {
-		lpfc_memcpy_to_slim(to_slim, &hgp, sizeof(struct lpfc_hgp));
-		to_slim += sizeof (struct lpfc_hgp);
+		lpfc_memcpy_to_slim(phba->host_gp + i, &hgp,
+				    sizeof(*phba->host_gp));
 	}
 
 	/* Setup Port Group ring pointer */
-	offset = (uint8_t *)&phba->slim2p->mbx.us.s2.port -
-		 (uint8_t *)phba->slim2p;
-	pdma_addr = phba->slim2p_mapping + offset;
+	if (phba->sli_rev == 3)
+		pgp_offset = (uint8_t *)&phba->slim2p->mbx.us.s3_pgp.port -
+			(uint8_t *)phba->slim2p;
+	else
+		pgp_offset = (uint8_t *)&phba->slim2p->mbx.us.s2.port -
+			(uint8_t *)phba->slim2p;
+
+	pdma_addr = phba->slim2p_mapping + pgp_offset;
 	phba->slim2p->pcb.pgpAddrHigh = putPaddrHigh(pdma_addr);
 	phba->slim2p->pcb.pgpAddrLow = putPaddrLow(pdma_addr);
+	phba->hbq_get = &phba->slim2p->mbx.us.s3_pgp.hbq_get[0];
 
 	/* Use callback routine to setp rings in the pcb */
 	lpfc_config_pcb_setup(phba);
@@ -603,10 +749,6 @@ 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));
-
-	lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-		        "%d:0405 Service Level Interface (SLI) 2 selected\n",
-		        phba->brd_no);
 }
 
 void
diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c
index 3aa1dff15446..435dc2ec9357 100644
--- a/drivers/scsi/lpfc/lpfc_mem.c
+++ b/drivers/scsi/lpfc/lpfc_mem.c
@@ -82,8 +82,16 @@ lpfc_mem_alloc(struct lpfc_hba * phba)
 	if (!phba->nlp_mem_pool)
 		goto fail_free_mbox_pool;
 
+	phba->lpfc_hbq_pool = pci_pool_create("lpfc_hbq_pool",phba->pcidev,
+					      LPFC_BPL_SIZE, 8, 0);
+	if (!phba->lpfc_hbq_pool)
+		goto fail_free_nlp_mem_pool;
+
 	return 0;
 
+ fail_free_nlp_mem_pool:
+	mempool_destroy(phba->nlp_mem_pool);
+	phba->nlp_mem_pool = NULL;
  fail_free_mbox_pool:
 	mempool_destroy(phba->mbox_mem_pool);
 	phba->mbox_mem_pool = NULL;
@@ -111,6 +119,8 @@ lpfc_mem_free(struct lpfc_hba * phba)
 	struct lpfc_dmabuf   *mp;
 	int i;
 
+	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);
@@ -140,12 +150,14 @@ lpfc_mem_free(struct lpfc_hba * phba)
 						 pool->elements[i].phys);
 	kfree(pool->elements);
 
+	pci_pool_destroy(phba->lpfc_hbq_pool);
 	mempool_destroy(phba->nlp_mem_pool);
 	mempool_destroy(phba->mbox_mem_pool);
 
 	pci_pool_destroy(phba->lpfc_scsi_dma_buf_pool);
 	pci_pool_destroy(phba->lpfc_mbuf_pool);
 
+	phba->lpfc_hbq_pool = NULL;
 	phba->nlp_mem_pool = NULL;
 	phba->mbox_mem_pool = NULL;
 	phba->lpfc_scsi_dma_buf_pool = NULL;
@@ -201,3 +213,20 @@ lpfc_mbuf_free(struct lpfc_hba * phba, void *virt, dma_addr_t dma)
 	spin_unlock_irqrestore(&phba->hbalock, iflags);
 	return;
 }
+
+
+void *
+lpfc_hbq_alloc(struct lpfc_hba *phba, int mem_flags, dma_addr_t *handle)
+{
+	void *ret;
+	ret = pci_pool_alloc(phba->lpfc_hbq_pool, GFP_ATOMIC, handle);
+	return ret;
+}
+
+void
+lpfc_hbq_free(struct lpfc_hba *phba, void *virt, dma_addr_t dma)
+{
+	pci_pool_free(phba->lpfc_hbq_pool, virt, dma);
+	return;
+}
+
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index e6452b88d958..b1727481a1e6 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -255,9 +255,8 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 				/* Start discovery - this should just do
 				   CLEAR_LA */
 				lpfc_disc_start(vport);
-			} else {
+			} else
 				lpfc_initial_flogi(vport);
-			}
 		} else {
 			stat.un.b.lsRjtRsnCode = LSRJT_LOGICAL_BSY;
 			stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
@@ -279,19 +278,16 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 	icmd = &cmdiocb->iocb;
 
 	/* PLOGI chkparm OK */
-	lpfc_printf_log(phba,
-			KERN_INFO,
-			LOG_ELS,
+	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,
 			ndlp->nlp_DID, ndlp->nlp_state, ndlp->nlp_flag,
 			ndlp->nlp_rpi);
 
-	if (phba->cfg_fcp_class == 2 && sp->cls2.classValid) {
+	if (phba->cfg_fcp_class == 2 && sp->cls2.classValid)
 		ndlp->nlp_fcp_info |= CLASS2;
-	} else {
+	else
 		ndlp->nlp_fcp_info |= CLASS3;
-	}
 
 	ndlp->nlp_class_sup = 0;
 	if (sp->cls1.classValid)
@@ -327,6 +323,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 			goto out;
 		lpfc_config_link(phba, mbox);
 		mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+		mbox->vport = vport;
 		rc = lpfc_sli_issue_mbox
 			(phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB));
 		if (rc == MBX_NOT_FINISHED) {
@@ -544,9 +541,7 @@ static uint32_t
 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,
+	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,
@@ -728,9 +723,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
 		goto out;
 
 	/* PLOGI chkparm OK */
-	lpfc_printf_log(phba,
-			KERN_INFO,
-			LOG_ELS,
+	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
 			"%d:0121 PLOGI chkparm OK "
 			"Data: x%x x%x x%x x%x\n",
 			phba->brd_no,
@@ -1105,9 +1098,7 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport,
 
 	if (mb->mbxStatus) {
 		/* RegLogin failed */
-		lpfc_printf_log(phba,
-				KERN_ERR,
-				LOG_DISCOVERY,
+		lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
 				"%d:0246 RegLogin failed Data: x%x x%x x%x\n",
 				phba->brd_no,
 				did, mb->mbxStatus, vport->port_state);
@@ -1470,15 +1461,12 @@ static uint32_t
 lpfc_rcv_prlo_mapped_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 			  void *arg, uint32_t evt)
 {
-	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
 	struct lpfc_hba  *phba = vport->phba;
 	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
 
 	/* flush the target */
-	spin_lock_irq(shost->host_lock);
 	lpfc_sli_abort_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring],
 			       ndlp->nlp_sid, 0, 0, LPFC_CTX_TGT);
-	spin_unlock_irq(shost->host_lock);
 
 	/* Treat like rcv logo */
 	lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_PRLO);
@@ -1926,9 +1914,7 @@ lpfc_disc_state_machine(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 	cur_state = ndlp->nlp_state;
 
 	/* DSM in event <evt> on NPort <nlp_DID> in state <cur_state> */
-	lpfc_printf_log(phba,
-			KERN_INFO,
-			LOG_DISCOVERY,
+	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,
@@ -1938,9 +1924,7 @@ lpfc_disc_state_machine(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 	rc = (func) (vport, ndlp, arg, evt);
 
 	/* DSM out state <rc> on NPort <nlp_DID> */
-	lpfc_printf_log(phba,
-		       KERN_INFO,
-		       LOG_DISCOVERY,
+	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);
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 6db7ad83cc39..90c88733a4f5 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -840,7 +840,7 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
 		cmnd->result = ScsiResult(DID_BUS_BUSY, 0);
 		goto out_fail_command;
 	}
-	lpfc_cmd = lpfc_get_scsi_buf (phba);
+	lpfc_cmd = lpfc_get_scsi_buf(phba);
 	if (lpfc_cmd == NULL) {
 		lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
 				"%d:0707 driver's buffer pool is empty, "
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 1edac15eed40..6e0b42bcebe7 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -65,6 +65,25 @@ typedef enum _lpfc_iocb_type {
 	LPFC_ABORT_IOCB
 } lpfc_iocb_type;
 
+/*
+ * SLI-2/SLI-3 provide different sized iocbs.  Given a pointer to the start of
+ * the ring, and the slot number of the desired iocb entry, calc a pointer to
+ * that entry.
+ */
+static inline IOCB_t *
+lpfc_cmd_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
+{
+	return (IOCB_t *) (((char *) pring->cmdringaddr) +
+			   pring->cmdidx * phba->iocb_cmd_size);
+}
+
+static inline IOCB_t *
+lpfc_resp_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
+{
+	return (IOCB_t *) (((char *) pring->rspringaddr) +
+			   pring->rspidx * phba->iocb_rsp_size);
+}
+
 static struct lpfc_iocbq *
 __lpfc_sli_get_iocbq(struct lpfc_hba *phba)
 {
@@ -180,6 +199,9 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd)
 	case CMD_RCV_ELS_REQ_CX:
 	case CMD_RCV_SEQUENCE64_CX:
 	case CMD_RCV_ELS_REQ64_CX:
+	case CMD_IOCB_RCV_SEQ64_CX:
+	case CMD_IOCB_RCV_ELS64_CX:
+	case CMD_IOCB_RCV_CONT64_CX:
 		type = LPFC_UNSOL_IOCB;
 		break;
 	default:
@@ -191,14 +213,19 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd)
 }
 
 static int
-lpfc_sli_ring_map(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
+lpfc_sli_ring_map(struct lpfc_hba *phba)
 {
 	struct lpfc_sli *psli = &phba->sli;
-	MAILBOX_t *pmbox = &pmb->mb;
-	int i, rc;
+	LPFC_MBOXQ_t *pmb;
+	MAILBOX_t *pmbox;
+	int i, rc, ret = 0;
 
+	pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (!pmb)
+		return -ENOMEM;
+	pmbox = &pmb->mb;
+	phba->link_state = LPFC_INIT_MBX_CMDS;
 	for (i = 0; i < psli->num_rings; i++) {
-		phba->link_state = LPFC_INIT_MBX_CMDS;
 		lpfc_config_ring(phba, i, pmb);
 		rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
 		if (rc != MBX_SUCCESS) {
@@ -213,10 +240,12 @@ lpfc_sli_ring_map(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 					pmbox->mbxStatus,
 					i);
 			phba->link_state = LPFC_HBA_ERROR;
-			return -ENXIO;
+			ret = -ENXIO;
+			break;
 		}
 	}
-	return 0;
+	mempool_free(pmb, phba->mbox_mem_pool);
+	return ret;
 }
 
 static int
@@ -255,9 +284,10 @@ lpfc_sli_ringtx_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
 static IOCB_t *
 lpfc_sli_next_iocb_slot (struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
 {
-	struct lpfc_pgp *pgp = &phba->slim2p->mbx.us.s2.port[pring->ringno];
+	struct lpfc_pgp *pgp = (phba->sli_rev == 3) ?
+		&phba->slim2p->mbx.us.s3_pgp.port[pring->ringno] :
+		&phba->slim2p->mbx.us.s2.port[pring->ringno];
 	uint32_t  max_cmd_idx = pring->numCiocb;
-	IOCB_t *iocb = NULL;
 
 	if ((pring->next_cmdidx == pring->cmdidx) &&
 	   (++pring->next_cmdidx >= max_cmd_idx))
@@ -291,9 +321,7 @@ lpfc_sli_next_iocb_slot (struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
 			return NULL;
 	}
 
-	iocb = IOCB_ENTRY(pring->cmdringaddr, pring->cmdidx);
-
-	return iocb;
+	return lpfc_cmd_iocb(phba, pring);
 }
 
 uint16_t
@@ -390,8 +418,7 @@ lpfc_sli_submit_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 	 * driver will put a command into.
 	 */
 	pring->cmdidx = pring->next_cmdidx;
-	writel(pring->cmdidx, phba->MBslimaddr
-	       + (SLIMOFF + (pring->ringno * 2)) * 4);
+	writel(pring->cmdidx, &phba->host_gp[pring->ringno].cmdPutInx);
 }
 
 static void
@@ -462,7 +489,9 @@ lpfc_sli_resume_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
 static void
 lpfc_sli_turn_on_ring(struct lpfc_hba *phba, int ringno)
 {
-	struct lpfc_pgp  *pgp = &phba->slim2p->mbx.us.s2.port[ringno];
+	struct lpfc_pgp *pgp = (phba->sli_rev == 3) ?
+		&phba->slim2p->mbx.us.s3_pgp.port[ringno] :
+		&phba->slim2p->mbx.us.s2.port[ringno];
 	unsigned long iflags;
 
 	/* If the ring is active, flag it */
@@ -481,6 +510,168 @@ lpfc_sli_turn_on_ring(struct lpfc_hba *phba, int ringno)
 	spin_unlock_irqrestore(&phba->hbalock, iflags);
 }
 
+struct lpfc_hbq_entry *
+lpfc_sli_next_hbq_slot(struct lpfc_hba *phba, uint32_t hbqno)
+{
+	struct hbq_s *hbqp = &phba->hbqs[hbqno];
+
+	if (hbqp->next_hbqPutIdx == hbqp->hbqPutIdx &&
+	    ++hbqp->next_hbqPutIdx >= hbqp->entry_count)
+		hbqp->next_hbqPutIdx = 0;
+
+	if (unlikely(hbqp->local_hbqGetIdx == hbqp->next_hbqPutIdx)) {
+		uint32_t raw_index = readl(&phba->hbq_get[hbqno]);
+		uint32_t getidx = le32_to_cpu(raw_index);
+
+		hbqp->local_hbqGetIdx = getidx;
+
+		if (unlikely(hbqp->local_hbqGetIdx >= hbqp->entry_count)) {
+			lpfc_printf_log(phba, KERN_ERR,
+					LOG_SLI,
+					"%d:1802 HBQ %d: local_hbqGetIdx "
+					"%u is > than hbqp->entry_count %u\n",
+					phba->brd_no, hbqno,
+					hbqp->local_hbqGetIdx,
+					hbqp->entry_count);
+
+			phba->link_state = LPFC_HBA_ERROR;
+			return NULL;
+		}
+
+		if (hbqp->local_hbqGetIdx == hbqp->next_hbqPutIdx)
+			return NULL;
+	}
+
+	return (struct lpfc_hbq_entry *) phba->hbqslimp.virt + hbqp->hbqPutIdx;
+}
+
+void
+lpfc_sli_hbqbuf_free_all(struct lpfc_hba *phba)
+{
+	uint32_t  i;
+
+	if (!phba->hbq_buffer_pool)
+		return;
+	/* Return all memory used by all HBQs */
+	for (i = 0; i < phba->hbq_buffer_count; i++) {
+		lpfc_hbq_free(phba, phba->hbq_buffer_pool[i].dbuf.virt,
+			      phba->hbq_buffer_pool[i].dbuf.phys);
+	}
+	kfree(phba->hbq_buffer_pool);
+	phba->hbq_buffer_pool = NULL;
+}
+
+static void
+lpfc_sli_hbq_to_firmware(struct lpfc_hba *phba, uint32_t hbqno,
+			 struct hbq_dmabuf *hbq_buf_desc)
+{
+	struct lpfc_hbq_entry *hbqe;
+
+	/* Get next HBQ entry slot to use */
+	hbqe = lpfc_sli_next_hbq_slot(phba, hbqno);
+	if (hbqe) {
+		struct hbq_s *hbqp = &phba->hbqs[hbqno];
+
+		hbqe->bde.addrHigh = putPaddrHigh(hbq_buf_desc->dbuf.phys);
+		hbqe->bde.addrLow  = putPaddrLow(hbq_buf_desc->dbuf.phys);
+		hbqe->bde.tus.f.bdeSize = FCELSSIZE;
+		hbqe->bde.tus.f.bdeFlags = 0;
+		hbqe->buffer_tag = hbq_buf_desc->tag;
+		/* Sync SLIM */
+		hbqp->hbqPutIdx = hbqp->next_hbqPutIdx;
+		writel(hbqp->hbqPutIdx, phba->hbq_put + hbqno);
+		/* flush */
+		readl(phba->hbq_put + hbqno);
+		phba->hbq_buff_count++;
+	}
+}
+
+static void
+lpfc_sli_fill_hbq(struct lpfc_hba *phba, uint32_t hbqno, uint32_t buffer_index)
+{
+	struct hbq_dmabuf *hbq_buf_desc;
+	uint32_t i;
+
+	for (i = 0; i < phba->hbqs[hbqno].entry_count; i++) {
+		/* Search hbqbufq, from the begining,
+		 * looking for an unused entry
+		 */
+		phba->hbq_buffer_pool[buffer_index + i].tag |= hbqno << 16;
+		hbq_buf_desc = phba->hbq_buffer_pool + buffer_index + i;
+		lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buf_desc);
+	}
+}
+
+int
+lpfc_sli_hbqbuf_fill_hbq(struct lpfc_hba *phba)
+{
+	return 0;
+}
+
+static int
+lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba)
+{
+	uint32_t buffer_index = 0;
+	uint32_t hbqno;
+
+	/* Populate HBQ entries */
+	for (hbqno = 0; hbqno < phba->hbq_count; ++hbqno) {
+		/* Find ring associated with HBQ */
+
+		lpfc_sli_fill_hbq(phba, hbqno, buffer_index);
+		buffer_index += phba->hbqs[hbqno].entry_count;
+	}
+	return 0;
+}
+
+struct hbq_dmabuf *
+lpfc_sli_hbqbuf_find(struct lpfc_hba *phba, uint32_t tag)
+{
+	if ((tag & 0xffff) < phba->hbq_buffer_count)
+		return phba->hbq_buffer_pool + (tag & 0xffff);
+
+	lpfc_printf_log(phba, KERN_ERR,
+			LOG_SLI,
+			"%d:1803 Bad hbq tag. Data: x%x x%x\n",
+			phba->brd_no, tag,
+			phba->hbq_buffer_count);
+	return NULL;
+}
+
+void
+lpfc_sli_hbqbuf_free(struct lpfc_hba *phba, void *virt, dma_addr_t phys)
+{
+	uint32_t i, hbqno;
+
+	for (i = 0; i < phba->hbq_buffer_count; i++) {
+		/* Search hbqbufq, from the begining, looking for a match on
+		   phys */
+		if (phba->hbq_buffer_pool[i].dbuf.phys == phys) {
+			hbqno = phba->hbq_buffer_pool[i].tag >> 16;
+			lpfc_sli_hbq_to_firmware(phba, hbqno,
+						 phba->hbq_buffer_pool + i);
+			return;
+		}
+	}
+
+	lpfc_printf_log(phba, KERN_ERR,
+			LOG_SLI,
+			"%d:1804 Cannot find virtual addr for "
+			"mapped buf. Data x%llx\n",
+			phba->brd_no, (unsigned long long) phys);
+}
+
+void
+lpfc_sli_free_hbq(struct lpfc_hba *phba, struct hbq_dmabuf *sp)
+{
+	uint32_t hbqno;
+
+	if (sp) {
+		hbqno = sp->tag >> 16;
+		lpfc_sli_hbq_to_firmware(phba, hbqno, sp);
+	}
+}
+
 static int
 lpfc_sli_chk_mbx_command(uint8_t mbxCommand)
 {
@@ -757,7 +948,9 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 	match = 0;
 	irsp = &(saveq->iocb);
 	if ((irsp->ulpCommand == CMD_RCV_ELS_REQ64_CX)
-	    || (irsp->ulpCommand == CMD_RCV_ELS_REQ_CX)) {
+	    || (irsp->ulpCommand == CMD_RCV_ELS_REQ_CX)
+	    || (irsp->ulpCommand == CMD_IOCB_RCV_ELS64_CX)
+	    || (irsp->ulpCommand == CMD_IOCB_RCV_CONT64_CX)) {
 		Rctl = FC_ELS_REQ;
 		Type = FC_ELS_DATA;
 	} else {
@@ -769,7 +962,8 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 
 		/* Firmware Workaround */
 		if ((Rctl == 0) && (pring->ringno == LPFC_ELS_RING) &&
-			(irsp->ulpCommand == CMD_RCV_SEQUENCE64_CX)) {
+		    (irsp->ulpCommand == CMD_RCV_SEQUENCE64_CX ||
+		     irsp->ulpCommand == CMD_IOCB_RCV_SEQ64_CX)) {
 			Rctl = FC_ELS_REQ;
 			Type = FC_ELS_DATA;
 			w5p->hcsw.Rctl = Rctl;
@@ -906,7 +1100,10 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 static void
 lpfc_sli_rsp_pointers_error(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
 {
-	struct lpfc_pgp *pgp = &phba->slim2p->mbx.us.s2.port[pring->ringno];
+	struct lpfc_pgp *pgp = (phba->sli_rev == 3) ?
+		&phba->slim2p->mbx.us.s3_pgp.port[pring->ringno] :
+		&phba->slim2p->mbx.us.s2.port[pring->ringno];
+
 	/*
 	 * Ring <ringno> handler: portRspPut <portRspPut> is bigger then
 	 * rsp ring <portRspMax>
@@ -945,14 +1142,15 @@ void lpfc_sli_poll_fcp_ring(struct lpfc_hba *phba)
 	uint32_t portRspPut, portRspMax;
 	int type;
 	uint32_t rsp_cmpl = 0;
-	void __iomem *to_slim;
 	uint32_t ha_copy;
 	unsigned long iflags;
 
 	pring->stats.iocb_event++;
 
-	/* The driver assumes SLI-2 mode */
-	pgp =  &phba->slim2p->mbx.us.s2.port[pring->ringno];
+	pgp = (phba->sli_rev == 3) ?
+		&phba->slim2p->mbx.us.s3_pgp.port[pring->ringno] :
+		&phba->slim2p->mbx.us.s2.port[pring->ringno];
+
 
 	/*
 	 * The next available response entry should never exceed the maximum
@@ -967,9 +1165,7 @@ void lpfc_sli_poll_fcp_ring(struct lpfc_hba *phba)
 
 	rmb();
 	while (pring->rspidx != portRspPut) {
-
-		entry = IOCB_ENTRY(pring->rspringaddr, pring->rspidx);
-
+		entry = lpfc_resp_iocb(phba, pring);
 		if (++pring->rspidx >= portRspMax)
 			pring->rspidx = 0;
 
@@ -1050,9 +1246,7 @@ void lpfc_sli_poll_fcp_ring(struct lpfc_hba *phba)
 		 * been updated, sync the pgp->rspPutInx and fetch the new port
 		 * response put pointer.
 		 */
-		to_slim = phba->MBslimaddr +
-			(SLIMOFF + (pring->ringno * 2) + 1) * 4;
-		writeb(pring->rspidx, to_slim);
+		writel(pring->rspidx, &phba->host_gp[pring->ringno].rspGetInx);
 
 		if (pring->rspidx == portRspPut)
 			portRspPut = le32_to_cpu(pgp->rspPutInx);
@@ -1096,7 +1290,9 @@ static int
 lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba,
 				struct lpfc_sli_ring *pring, uint32_t mask)
 {
-	struct lpfc_pgp  *pgp = &phba->slim2p->mbx.us.s2.port[pring->ringno];
+	struct lpfc_pgp *pgp = (phba->sli_rev == 3) ?
+		&phba->slim2p->mbx.us.s3_pgp.port[pring->ringno] :
+		&phba->slim2p->mbx.us.s2.port[pring->ringno];
 	IOCB_t *irsp = NULL;
 	IOCB_t *entry = NULL;
 	struct lpfc_iocbq *cmdiocbq = NULL;
@@ -1107,7 +1303,6 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba,
 	lpfc_iocb_type type;
 	unsigned long iflag;
 	uint32_t rsp_cmpl = 0;
-	void __iomem *to_slim;
 
 	spin_lock_irqsave(&phba->hbalock, iflag);
 	pring->stats.iocb_event++;
@@ -1131,14 +1326,14 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba,
 		 * structure.  The copy involves a byte-swap since the
 		 * network byte order and pci byte orders are different.
 		 */
-		entry = IOCB_ENTRY(pring->rspringaddr, pring->rspidx);
+		entry = lpfc_resp_iocb(phba, pring);
 
 		if (++pring->rspidx >= portRspMax)
 			pring->rspidx = 0;
 
 		lpfc_sli_pcimem_bcopy((uint32_t *) entry,
 				      (uint32_t *) &rspiocbq.iocb,
-				      sizeof(IOCB_t));
+				      phba->iocb_rsp_size);
 		INIT_LIST_HEAD(&(rspiocbq.list));
 		irsp = &rspiocbq.iocb;
 
@@ -1222,9 +1417,7 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba,
 		 * been updated, sync the pgp->rspPutInx and fetch the new port
 		 * response put pointer.
 		 */
-		to_slim = phba->MBslimaddr +
-			(SLIMOFF + (pring->ringno * 2) + 1) * 4;
-		writel(pring->rspidx, to_slim);
+		writel(pring->rspidx, &phba->host_gp[pring->ringno].rspGetInx);
 
 		if (pring->rspidx == portRspPut)
 			portRspPut = le32_to_cpu(pgp->rspPutInx);
@@ -1258,7 +1451,9 @@ int
 lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
 				struct lpfc_sli_ring *pring, uint32_t mask)
 {
-	struct lpfc_pgp  *pgp = &phba->slim2p->mbx.us.s2.port[pring->ringno];
+	struct lpfc_pgp *pgp = (phba->sli_rev == 3) ?
+		&phba->slim2p->mbx.us.s3_pgp.port[pring->ringno] :
+		&phba->slim2p->mbx.us.s2.port[pring->ringno];
 	IOCB_t *entry;
 	IOCB_t *irsp = NULL;
 	struct lpfc_iocbq *rspiocbp = NULL;
@@ -1271,7 +1466,6 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
 	uint32_t portRspPut, portRspMax;
 	int rc = 1;
 	unsigned long iflag;
-	void __iomem *to_slim;
 
 	spin_lock_irqsave(&phba->hbalock, iflag);
 	pring->stats.iocb_event++;
@@ -1287,9 +1481,7 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
 		 * Ring <ringno> handler: portRspPut <portRspPut> is bigger then
 		 * rsp ring <portRspMax>
 		 */
-		lpfc_printf_log(phba,
-				KERN_ERR,
-				LOG_SLI,
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
 				"%d:0303 Ring %d handler: portRspPut %d "
 				"is bigger then rsp ring %d\n",
 				phba->brd_no,
@@ -1319,7 +1511,8 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
 		 * the ulpLe field is set, the entire Command has been
 		 * received.
 		 */
-		entry = IOCB_ENTRY(pring->rspringaddr, pring->rspidx);
+		entry = lpfc_resp_iocb(phba, pring);
+
 		rspiocbp = __lpfc_sli_get_iocbq(phba);
 		if (rspiocbp == NULL) {
 			printk(KERN_ERR "%s: out of buffers! Failing "
@@ -1327,15 +1520,14 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
 			break;
 		}
 
-		lpfc_sli_pcimem_bcopy(entry, &rspiocbp->iocb, sizeof(IOCB_t));
+		lpfc_sli_pcimem_bcopy(entry, &rspiocbp->iocb,
+				      phba->iocb_rsp_size);
 		irsp = &rspiocbp->iocb;
 
 		if (++pring->rspidx >= portRspMax)
 			pring->rspidx = 0;
 
-		to_slim = phba->MBslimaddr + (SLIMOFF + (pring->ringno * 2)
-					      + 1) * 4;
-		writel(pring->rspidx, to_slim);
+		writel(pring->rspidx, &phba->host_gp[pring->ringno].rspGetInx);
 
 		if (list_empty(&(pring->iocb_continueq))) {
 			list_add(&rspiocbp->list, &(pring->iocb_continueq));
@@ -1361,21 +1553,31 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
 
 			if (irsp->ulpStatus) {
 				/* Rsp ring <ringno> error: IOCB */
-				lpfc_printf_log(phba,
-					KERN_WARNING,
-					LOG_SLI,
-					"%d:0328 Rsp Ring %d error: IOCB Data: "
-					"x%x x%x x%x x%x x%x x%x x%x x%x\n",
-					phba->brd_no,
-					pring->ringno,
-					irsp->un.ulpWord[0],
-					irsp->un.ulpWord[1],
-					irsp->un.ulpWord[2],
-					irsp->un.ulpWord[3],
-					irsp->un.ulpWord[4],
-					irsp->un.ulpWord[5],
-					*(((uint32_t *) irsp) + 6),
-					*(((uint32_t *) irsp) + 7));
+				lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+						"%d:0328 Rsp Ring %d error: "
+						"IOCB Data: "
+						"x%x x%x x%x x%x "
+						"x%x x%x x%x x%x "
+						"x%x x%x x%x x%x "
+						"x%x x%x x%x x%x\n",
+						phba->brd_no,
+						pring->ringno,
+						irsp->un.ulpWord[0],
+						irsp->un.ulpWord[1],
+						irsp->un.ulpWord[2],
+						irsp->un.ulpWord[3],
+						irsp->un.ulpWord[4],
+						irsp->un.ulpWord[5],
+						*(((uint32_t *) irsp) + 6),
+						*(((uint32_t *) irsp) + 7),
+						*(((uint32_t *) irsp) + 8),
+						*(((uint32_t *) irsp) + 9),
+						*(((uint32_t *) irsp) + 10),
+						*(((uint32_t *) irsp) + 11),
+						*(((uint32_t *) irsp) + 12),
+						*(((uint32_t *) irsp) + 13),
+						*(((uint32_t *) irsp) + 14),
+						*(((uint32_t *) irsp) + 15));
 			}
 
 			/*
@@ -1659,13 +1861,9 @@ lpfc_sli_brdkill(struct lpfc_hba *phba)
 	psli = &phba->sli;
 
 	/* Kill HBA */
-	lpfc_printf_log(phba,
-		KERN_INFO,
-		LOG_SLI,
+	lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
 		"%d:0329 Kill HBA Data: x%x x%x\n",
-		phba->brd_no,
-		phba->pport->port_state,
-		psli->sli_flag);
+		phba->brd_no, phba->pport->port_state, psli->sli_flag);
 
 	if ((pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool,
 						  GFP_KERNEL)) == 0)
@@ -1857,13 +2055,10 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba)
 		if (i++ >= 20) {
 			/* Adapter failed to init, timeout, status reg
 			   <status> */
-			lpfc_printf_log(phba,
-					KERN_ERR,
-					LOG_INIT,
+			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 					"%d:0436 Adapter failed to init, "
 					"timeout, status reg x%x\n",
-					phba->brd_no,
-					status);
+					phba->brd_no, status);
 			phba->link_state = LPFC_HBA_ERROR;
 			return -ETIMEDOUT;
 		}
@@ -1873,9 +2068,7 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba)
 			/* ERROR: During chipset initialization */
 			/* Adapter failed to init, chipset, status reg
 			   <status> */
-			lpfc_printf_log(phba,
-					KERN_ERR,
-					LOG_INIT,
+			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 					"%d:0437 Adapter failed to init, "
 					"chipset, status reg x%x\n",
 					phba->brd_no,
@@ -1905,9 +2098,7 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba)
 	if (status & HS_FFERM) {
 		/* ERROR: During chipset initialization */
 		/* Adapter failed to init, chipset, status reg <status> */
-		lpfc_printf_log(phba,
-				KERN_ERR,
-				LOG_INIT,
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 				"%d:0438 Adapter failed to init, chipset, "
 				"status reg x%x\n",
 				phba->brd_no,
@@ -1926,8 +2117,145 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba)
 	return 0;
 }
 
+static struct hbq_dmabuf *
+lpfc_alloc_hbq_buffers(struct lpfc_hba *phba, int count)
+{
+	struct hbq_dmabuf *hbq_buffer_pool;
+	int  i;
+
+	hbq_buffer_pool = kmalloc(count * sizeof(struct hbq_dmabuf),
+				  GFP_KERNEL);
+	if (!hbq_buffer_pool)
+		goto out;
+
+	for (i = 0; i < count; ++i) {
+		hbq_buffer_pool[i].dbuf.virt =
+			lpfc_hbq_alloc(phba, MEM_PRI,
+				       &hbq_buffer_pool[i].dbuf.phys);
+		if (hbq_buffer_pool[i].dbuf.virt == NULL)
+			goto alloc_failed;
+		hbq_buffer_pool[i].tag = i;
+	}
+	goto out;
+
+alloc_failed:
+	while (--i >= 0)
+		lpfc_hbq_free(phba, hbq_buffer_pool[i].dbuf.virt,
+			      hbq_buffer_pool[i].dbuf.phys);
+	kfree(hbq_buffer_pool);
+	hbq_buffer_pool = NULL;
+
+out:
+	phba->hbq_buffer_pool = hbq_buffer_pool;
+	return hbq_buffer_pool;
+}
+
+static struct lpfc_hbq_init lpfc_els_hbq = {
+	.rn = 1,
+	.entry_count = 1200,
+	.mask_count = 0,
+	.profile = 0,
+	.ring_mask = 1 << LPFC_ELS_RING,
+};
+
+static struct lpfc_hbq_init *lpfc_hbq_definitions[] = {
+	&lpfc_els_hbq,
+};
+
+static int
+lpfc_sli_hbq_count(void)
+{
+	return ARRAY_SIZE(lpfc_hbq_definitions);
+}
+
+static int
+lpfc_sli_hbq_entry_count(void)
+{
+	int  hbq_count = lpfc_sli_hbq_count();
+	int  count = 0;
+	int  i;
+
+	for (i = 0; i < hbq_count; ++i)
+		count += lpfc_hbq_definitions[i]->entry_count;
+	return count;
+}
+
 int
-lpfc_sli_hba_setup(struct lpfc_hba *phba)
+lpfc_sli_hbq_size(void)
+{
+	return lpfc_sli_hbq_entry_count() * sizeof(struct lpfc_hbq_entry);
+}
+
+static int
+lpfc_sli_hbq_setup(struct lpfc_hba *phba)
+{
+	int  hbq_count = lpfc_sli_hbq_count();
+	LPFC_MBOXQ_t *pmb;
+	MAILBOX_t *pmbox;
+	uint32_t hbqno;
+	uint32_t hbq_entry_index;
+	uint32_t hbq_buffer_count;
+
+	/* count hbq buffers */
+	hbq_buffer_count = lpfc_sli_hbq_entry_count();
+	if (!lpfc_alloc_hbq_buffers(phba, hbq_buffer_count))
+		return -ENOMEM;
+
+	phba->hbq_buffer_count = hbq_buffer_count;
+
+	/* Get a Mailbox buffer to setup mailbox
+	 * commands for HBA initialization
+	 */
+	pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+
+	if (!pmb)
+		return -ENOMEM;
+
+	pmbox = &pmb->mb;
+
+	/* Initialize the struct lpfc_sli_hbq structure for each hbq */
+	phba->link_state = LPFC_INIT_MBX_CMDS;
+
+	hbq_entry_index = 0;
+	for (hbqno = 0; hbqno < hbq_count; ++hbqno) {
+		phba->hbqs[hbqno].next_hbqPutIdx = 0;
+		phba->hbqs[hbqno].hbqPutIdx      = 0;
+		phba->hbqs[hbqno].local_hbqGetIdx   = 0;
+		phba->hbqs[hbqno].entry_count =
+			lpfc_hbq_definitions[hbqno]->entry_count;
+		lpfc_config_hbq(phba, lpfc_hbq_definitions[hbqno],
+				hbq_entry_index, pmb);
+		hbq_entry_index += phba->hbqs[hbqno].entry_count;
+
+		if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) {
+			/* Adapter failed to init, mbxCmd <cmd> CFG_RING,
+			   mbxStatus <status>, ring <num> */
+
+			lpfc_printf_log(phba, KERN_ERR,
+					LOG_SLI,
+					"%d:1805 Adapter failed to init. "
+					"Data: x%x x%x x%x\n",
+					phba->brd_no, pmbox->mbxCommand,
+					pmbox->mbxStatus, hbqno);
+
+			phba->link_state = LPFC_HBA_ERROR;
+			mempool_free(pmb, phba->mbox_mem_pool);
+			/* Free all HBQ memory */
+			lpfc_sli_hbqbuf_free_all(phba);
+			return ENXIO;
+		}
+	}
+	phba->hbq_count = hbq_count;
+
+	/* Initially populate or replenish the HBQs */
+	lpfc_sli_hbqbuf_fill_hbqs(phba);
+	mempool_free(pmb, phba->mbox_mem_pool);
+
+	return 0;
+}
+
+static int
+lpfc_do_config_port(struct lpfc_hba *phba, int sli_mode)
 {
 	LPFC_MBOXQ_t *pmb;
 	uint32_t resetcount = 0, rc = 0, done = 0;
@@ -1938,6 +2266,7 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba)
 		return -ENOMEM;
 	}
 
+	phba->sli_rev = sli_mode;
 	while (resetcount < 2 && !done) {
 		spin_lock_irq(&phba->hbalock);
 		phba->sli.sli_flag |= LPFC_SLI_MBOX_ACTIVE;
@@ -1954,14 +2283,14 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba)
 		spin_unlock_irq(&phba->hbalock);
 		resetcount++;
 
-	/* Call pre CONFIG_PORT mailbox command initialization.  A value of 0
-	 * means the call was successful.  Any other nonzero value is a failure,
-	 * but if ERESTART is returned, the driver may reset the HBA and try
-	 * again.
-	 */
+		/* Call pre CONFIG_PORT mailbox command initialization.  A
+		 * value of 0 means the call was successful.  Any other
+		 * nonzero value is a failure, but if ERESTART is returned,
+		 * the driver may reset the HBA and try again.
+		 */
 		rc = lpfc_config_port_prep(phba);
 		if (rc == -ERESTART) {
-			phba->pport->port_state = 0;
+			phba->link_state = LPFC_LINK_UNKNOWN;
 			continue;
 		} else if (rc) {
 			break;
@@ -1970,39 +2299,116 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba)
 		phba->link_state = LPFC_INIT_MBX_CMDS;
 		lpfc_config_port(phba, pmb);
 		rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
-		if (rc == MBX_SUCCESS)
-			done = 1;
-		else {
+		if (rc != MBX_SUCCESS) {
 			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-				"%d:0442 Adapter failed to init, mbxCmd x%x "
-				"CONFIG_PORT, mbxStatus x%x Data: x%x\n",
-				phba->brd_no, pmb->mb.mbxCommand,
-				pmb->mb.mbxStatus, 0);
+					"%d:0442 Adapter failed to init, "
+					"mbxCmd x%x CONFIG_PORT, mbxStatus "
+					"x%x Data: x%x\n",
+					phba->brd_no, pmb->mb.mbxCommand,
+					pmb->mb.mbxStatus, 0);
 			spin_lock_irq(&phba->hbalock);
 			phba->sli.sli_flag &= ~LPFC_SLI2_ACTIVE;
 			spin_unlock_irq(&phba->hbalock);
 			rc = -ENXIO;
+		} else {
+			done = 1;
+			/* DBG: Do we need max_vpi, reg_vpi for that matter
+			   phba->max_vpi = 0;
+			*/
 		}
 	}
-	if (!done)
+
+	if (!done) {
+		rc = -EINVAL;
+		goto do_prep_failed;
+	}
+
+	if ((pmb->mb.un.varCfgPort.sli_mode == 3) &&
+	    (!pmb->mb.un.varCfgPort.cMA)) {
+		rc = -ENXIO;
+		goto do_prep_failed;
+	}
+	return rc;
+
+ do_prep_failed:
+	mempool_free(pmb, phba->mbox_mem_pool);
+	return rc;
+}
+
+int
+lpfc_sli_hba_setup(struct lpfc_hba *phba)
+{
+	uint32_t rc;
+	int mode = 3;
+
+	switch (lpfc_sli_mode) {
+	case 2:
+		mode = 2;
+		break;
+	case 0:
+	case 3:
+		break;
+	default:
+		lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+				"%d:1819 Unrecognized lpfc_sli_mode "
+				"parameter: %d.\n",
+				phba->brd_no, lpfc_sli_mode);
+
+		break;
+	}
+
+	rc = lpfc_do_config_port(phba, mode);
+	if (rc && lpfc_sli_mode == 3)
+		lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+				"%d:1820 Unable to select SLI-3.  "
+				"Not supported by adapter.\n",
+				phba->brd_no);
+	if (rc && mode != 2)
+		rc = lpfc_do_config_port(phba, 2);
+	if (rc)
 		goto lpfc_sli_hba_setup_error;
 
-	rc = lpfc_sli_ring_map(phba, pmb);
+	if (phba->sli_rev == 3) {
+		phba->iocb_cmd_size = SLI3_IOCB_CMD_SIZE;
+		phba->iocb_rsp_size = SLI3_IOCB_RSP_SIZE;
+		phba->sli3_options |= LPFC_SLI3_ENABLED;
+		phba->sli3_options |= LPFC_SLI3_HBQ_ENABLED;
+
+	} else {
+		phba->iocb_cmd_size = SLI2_IOCB_CMD_SIZE;
+		phba->iocb_rsp_size = SLI2_IOCB_RSP_SIZE;
+		phba->sli3_options = 0x0;
+	}
+
+	lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+			"%d:0444 Firmware in SLI %x mode.\n",
+			phba->brd_no, phba->sli_rev);
+	rc = lpfc_sli_ring_map(phba);
 
 	if (rc)
 		goto lpfc_sli_hba_setup_error;
 
+	/* Init HBQs */
+
+	if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
+		rc = lpfc_sli_hbq_setup(phba);
+		if (rc)
+			goto lpfc_sli_hba_setup_error;
+	}
+
 	phba->sli.sli_flag |= LPFC_PROCESS_LA;
 
 	rc = lpfc_config_port_post(phba);
 	if (rc)
 		goto lpfc_sli_hba_setup_error;
 
-	goto lpfc_sli_hba_setup_exit;
-lpfc_sli_hba_setup_error:
+	return rc;
+
+ lpfc_sli_hba_setup_error:
 	phba->link_state = LPFC_HBA_ERROR;
-lpfc_sli_hba_setup_exit:
-	mempool_free(pmb, phba->mbox_mem_pool);
+	lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+			"%d:0445 Firmware initialization failed\n",
+			phba->brd_no);
 	return rc;
 }
 
@@ -2027,7 +2433,7 @@ lpfc_mbox_timeout(unsigned long ptr)
 	uint32_t tmo_posted;
 
 	spin_lock_irqsave(&phba->pport->work_port_lock, iflag);
-	tmo_posted = (phba->pport->work_port_events & WORKER_MBOX_TMO) == 0;
+	tmo_posted = (phba->pport->work_port_events & WORKER_MBOX_TMO);
 	if (!tmo_posted)
 		phba->pport->work_port_events |= WORKER_MBOX_TMO;
 	spin_unlock_irqrestore(&phba->pport->work_port_lock, iflag);
@@ -2051,9 +2457,7 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba)
 	}
 
 	/* Mbox cmd <mbxCommand> timeout */
-	lpfc_printf_log(phba,
-		KERN_ERR,
-		LOG_MBOX | LOG_SLI,
+	lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
 		"%d:0310 Mailbox command x%x timeout Data: x%x x%x x%p\n",
 		phba->brd_no,
 		mb->mbxCommand,
@@ -2105,13 +2509,25 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
 	volatile uint32_t word0, ldata;
 	void __iomem *to_slim;
 
+	if (pmbox->mbox_cmpl && pmbox->mbox_cmpl != lpfc_sli_def_mbox_cmpl &&
+	    pmbox->mbox_cmpl != lpfc_sli_wake_mbox_wait) {
+		if(!pmbox->vport) {
+			lpfc_printf_log(phba, KERN_ERR,
+					LOG_MBOX,
+					"%d:1806 Mbox x%x failed. No vport\n",
+					phba->brd_no,
+					pmbox->mb.mbxCommand);
+			dump_stack();
+			return MBXERR_ERROR;
+		}
+	}
+
 	/* If the PCI channel is in offline state, do not post mbox. */
 	if (unlikely(pci_channel_offline(phba->pcidev)))
 		return MBX_NOT_FINISHED;
 
 	spin_lock_irqsave(&phba->hbalock, drvr_flag);
 	psli = &phba->sli;
-
 	mb = &pmbox->mb;
 	status = MBX_SUCCESS;
 
@@ -2172,15 +2588,11 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
 		lpfc_mbox_put(phba, pmbox);
 
 		/* Mbox cmd issue - BUSY */
-		lpfc_printf_log(phba,
-			KERN_INFO,
-			LOG_MBOX | LOG_SLI,
+		lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
 			"%d:0308 Mbox cmd issue - BUSY Data: x%x x%x x%x x%x\n",
 			phba->brd_no,
-			mb->mbxCommand,
-			phba->pport->port_state,
-			psli->sli_flag,
-			flag);
+			mb->mbxCommand, phba->pport->port_state,
+			psli->sli_flag, flag);
 
 		psli->slistat.mbox_busy++;
 		spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
@@ -2223,15 +2635,11 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
 	}
 
 	/* Mailbox cmd <cmd> issue */
-	lpfc_printf_log(phba,
-		KERN_INFO,
-		LOG_MBOX | LOG_SLI,
+	lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
 		"%d:0309 Mailbox cmd x%x issue Data: x%x x%x x%x\n",
 		phba->brd_no,
-		mb->mbxCommand,
-		phba->pport->port_state,
-		psli->sli_flag,
-			flag);
+		mb->mbxCommand, phba->pport->port_state,
+		psli->sli_flag, flag);
 
 	psli->slistat.mbox_cmd++;
 	evtctr = psli->slistat.mbox_event;
@@ -2526,7 +2934,7 @@ lpfc_extra_ring_setup( struct lpfc_hba *phba)
 int
 lpfc_sli_setup(struct lpfc_hba *phba)
 {
-	int i, totiocb = 0;
+	int i, totiocbsize = 0;
 	struct lpfc_sli *psli = &phba->sli;
 	struct lpfc_sli_ring *pring;
 
@@ -2551,9 +2959,15 @@ lpfc_sli_setup(struct lpfc_hba *phba)
 			pring->numRiocb += SLI2_IOCB_RSP_R1XTRA_ENTRIES;
 			pring->numCiocb += SLI2_IOCB_CMD_R3XTRA_ENTRIES;
 			pring->numRiocb += SLI2_IOCB_RSP_R3XTRA_ENTRIES;
+			pring->sizeCiocb = (phba->sli_rev == 3) ?
+				SLI3_IOCB_CMD_SIZE :
+				SLI2_IOCB_CMD_SIZE;
+			pring->sizeRiocb = (phba->sli_rev == 3) ?
+				SLI3_IOCB_RSP_SIZE :
+				SLI2_IOCB_RSP_SIZE;
 			pring->iotag_ctr = 0;
 			pring->iotag_max =
-			    (phba->cfg_hba_queue_depth * 2);
+				(phba->cfg_hba_queue_depth * 2);
 			pring->fast_iotag = pring->iotag_max;
 			pring->num_mask = 0;
 			break;
@@ -2561,6 +2975,12 @@ lpfc_sli_setup(struct lpfc_hba *phba)
 			/* numCiocb and numRiocb are used in config_port */
 			pring->numCiocb = SLI2_IOCB_CMD_R1_ENTRIES;
 			pring->numRiocb = SLI2_IOCB_RSP_R1_ENTRIES;
+			pring->sizeCiocb = (phba->sli_rev == 3) ?
+				SLI3_IOCB_CMD_SIZE :
+				SLI2_IOCB_CMD_SIZE;
+			pring->sizeRiocb = (phba->sli_rev == 3) ?
+				SLI3_IOCB_RSP_SIZE :
+				SLI2_IOCB_RSP_SIZE;
 			pring->iotag_max = phba->cfg_hba_queue_depth;
 			pring->num_mask = 0;
 			break;
@@ -2568,6 +2988,12 @@ lpfc_sli_setup(struct lpfc_hba *phba)
 			/* numCiocb and numRiocb are used in config_port */
 			pring->numCiocb = SLI2_IOCB_CMD_R2_ENTRIES;
 			pring->numRiocb = SLI2_IOCB_RSP_R2_ENTRIES;
+			pring->sizeCiocb = (phba->sli_rev == 3) ?
+				SLI3_IOCB_CMD_SIZE :
+				SLI2_IOCB_CMD_SIZE;
+			pring->sizeRiocb = (phba->sli_rev == 3) ?
+				SLI3_IOCB_RSP_SIZE :
+				SLI2_IOCB_RSP_SIZE;
 			pring->fast_iotag = 0;
 			pring->iotag_ctr = 0;
 			pring->iotag_max = 4096;
@@ -2576,36 +3002,38 @@ lpfc_sli_setup(struct lpfc_hba *phba)
 			pring->prt[0].rctl = FC_ELS_REQ;
 			pring->prt[0].type = FC_ELS_DATA;
 			pring->prt[0].lpfc_sli_rcv_unsol_event =
-			    lpfc_els_unsol_event;
+				lpfc_els_unsol_event;
 			pring->prt[1].profile = 0;	/* Mask 1 */
 			pring->prt[1].rctl = FC_ELS_RSP;
 			pring->prt[1].type = FC_ELS_DATA;
 			pring->prt[1].lpfc_sli_rcv_unsol_event =
-			    lpfc_els_unsol_event;
+				lpfc_els_unsol_event;
 			pring->prt[2].profile = 0;	/* Mask 2 */
 			/* NameServer Inquiry */
 			pring->prt[2].rctl = FC_UNSOL_CTL;
 			/* NameServer */
 			pring->prt[2].type = FC_COMMON_TRANSPORT_ULP;
 			pring->prt[2].lpfc_sli_rcv_unsol_event =
-			    lpfc_ct_unsol_event;
+				lpfc_ct_unsol_event;
 			pring->prt[3].profile = 0;	/* Mask 3 */
 			/* NameServer response */
 			pring->prt[3].rctl = FC_SOL_CTL;
 			/* NameServer */
 			pring->prt[3].type = FC_COMMON_TRANSPORT_ULP;
 			pring->prt[3].lpfc_sli_rcv_unsol_event =
-			    lpfc_ct_unsol_event;
+				lpfc_ct_unsol_event;
 			break;
 		}
-		totiocb += (pring->numCiocb + pring->numRiocb);
+		totiocbsize += (pring->numCiocb * pring->sizeCiocb) +
+			(pring->numRiocb * pring->sizeRiocb);
 	}
-	if (totiocb > MAX_SLI2_IOCB) {
+	if (totiocbsize > MAX_SLIM_IOCB_SIZE) {
 		/* Too many cmd / rsp ring entries in SLI2 SLIM */
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 				"%d:0462 Too many cmd / rsp ring entries in "
-				"SLI2 SLIM Data: x%x x%x\n",
-				phba->brd_no, totiocb, MAX_SLI2_IOCB);
+				"SLI2 SLIM Data: x%x x%lx\n",
+				phba->brd_no, totiocbsize,
+				(unsigned long) MAX_SLIM_IOCB_SIZE);
 	}
 	if (phba->cfg_multi_ring_support == 2)
 		lpfc_extra_ring_setup(phba);
@@ -2689,6 +3117,7 @@ lpfc_sli_hba_down(struct lpfc_hba *phba)
 	phba->pport->work_port_events &= ~WORKER_MBOX_TMO;
 	spin_unlock_irqrestore(&phba->pport->work_port_lock, flags);
 
+	spin_lock_irqsave(&phba->hbalock, flags);
 	pmb = psli->mbox_active;
 	if (pmb) {
 		psli->mbox_active = NULL;
@@ -2708,6 +3137,9 @@ lpfc_sli_hba_down(struct lpfc_hba *phba)
 	}
 	INIT_LIST_HEAD(&psli->mboxq);
 
+	/* Free all HBQ memory */
+	lpfc_sli_hbqbuf_free_all(phba);
+
 	return 1;
 }
 
@@ -3075,11 +3507,9 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba,
 	retval = lpfc_sli_issue_iocb(phba, pring, piocb, 0);
 	if (retval == IOCB_SUCCESS) {
 		timeout_req = timeout * HZ;
-		spin_unlock_irq(&phba->hbalock);
 		timeleft = wait_event_timeout(done_q,
 				piocb->iocb_flag & LPFC_IO_WAKE,
 				timeout_req);
-		spin_lock_irq(&phba->hbalock);
 
 		if (piocb->iocb_flag & LPFC_IO_WAKE) {
 			lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
@@ -3164,13 +3594,25 @@ lpfc_sli_flush_mbox_queue(struct lpfc_hba * phba)
 {
 	struct lpfc_vport *vport = phba->pport;
 	int i = 0;
+	uint32_t ha_copy;
 
 	while (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE && !vport->stopped) {
 		if (i++ > LPFC_MBOX_TMO * 1000)
 			return 1;
 
-		if (lpfc_sli_handle_mb_event(phba) == 0)
-			i = 0;
+		/*
+		 * Call lpfc_sli_handle_mb_event only if a mailbox cmd
+		 * did finish. This way we won't get the misleading
+		 * "Stray Mailbox Interrupt" message.
+		 */
+		spin_lock_irq(&phba->hbalock);
+		ha_copy = phba->work_ha;
+		phba->work_ha &= ~HA_MBATT;
+		spin_unlock_irq(&phba->hbalock);
+
+		if (ha_copy & HA_MBATT)
+			if (lpfc_sli_handle_mb_event(phba) == 0)
+				i = 0;
 
 		msleep(1);
 	}
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
index 0e857e51a2c4..190d55a69b2a 100644
--- a/drivers/scsi/lpfc/lpfc_sli.h
+++ b/drivers/scsi/lpfc/lpfc_sli.h
@@ -138,6 +138,8 @@ struct lpfc_sli_ring {
 	uint8_t ringno;		/* ring number */
 	uint16_t numCiocb;	/* number of command iocb's per ring */
 	uint16_t numRiocb;	/* number of rsp iocb's per ring */
+	uint16_t sizeCiocb;	/* Size of command iocb's in this ring */
+	uint16_t sizeRiocb; 	/* Size of response iocb's in this ring */
 
 	uint32_t fast_iotag;	/* max fastlookup based iotag           */
 	uint32_t iotag_ctr;	/* keeps track of the next iotag to use */
@@ -168,6 +170,29 @@ struct lpfc_sli_ring {
 					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 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 */
+	uint32_t ring_mask;	/* Binds HBQ to a ring e.g. Ring0=b0001,
+				 * ring2=b0100 */
+	uint32_t hbq_index;	/* index of this hbq in ring .HBQs[] */
+
+	uint32_t seqlenoff;
+	uint32_t maxlen;
+	uint32_t seqlenbcnt;
+	uint32_t cmdcodeoff;
+	uint32_t cmdmatch[8];
+	uint32_t mask_count;	/* number of mask entries in prt array */
+	struct hbq_mask hbqMasks[6];
+} ;
+
+#define LPFC_MAX_HBQ 16
+
+
 /* Structure used to hold SLI statistical counters and info */
 struct lpfc_sli_stat {
 	uint64_t mbox_stat_err;  /* Mbox cmds completed status error */
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index 0a7937351448..fd10fa16980e 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -18,7 +18,7 @@
  * included with this package.                                     *
  *******************************************************************/
 
-#define LPFC_DRIVER_VERSION "8.1.12_psplit"
+#define LPFC_DRIVER_VERSION "8.1.12_sli3"
 
 #define LPFC_DRIVER_NAME "lpfc"