diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 55016328bd784ef608189fb501f53505734da373..5a8d5c4c69bad5cdf85724f9d88fbc22e110289b 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -7,7 +7,6 @@
 #include "qla_def.h"
 
 #include <linux/vmalloc.h>
-#include <scsi/scsi_transport_fc.h>
 
 /* SYSFS attributes --------------------------------------------------------- */
 
@@ -555,6 +554,41 @@ qla2x00_issue_lip(struct Scsi_Host *shost)
 	return 0;
 }
 
+static struct fc_host_statistics *
+qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
+{
+	scsi_qla_host_t *ha = to_qla_host(shost);
+	int rval;
+	uint16_t mb_stat[1];
+	link_stat_t stat_buf;
+	struct fc_host_statistics *pfc_host_stat;
+
+	pfc_host_stat = &ha->fc_host_stat;
+	memset(pfc_host_stat, -1, sizeof(struct fc_host_statistics));
+
+	if (IS_QLA24XX(ha) || IS_QLA25XX(ha)) {
+		rval = qla24xx_get_isp_stats(ha, (uint32_t *)&stat_buf,
+		    sizeof(stat_buf) / 4, mb_stat);
+	} else {
+		rval = qla2x00_get_link_status(ha, ha->loop_id, &stat_buf,
+		    mb_stat);
+	}
+	if (rval != 0) {
+		qla_printk(KERN_WARNING, ha,
+		    "Unable to retrieve host statistics (%d).\n", mb_stat[0]);
+		return pfc_host_stat;
+	}
+
+	pfc_host_stat->link_failure_count = stat_buf.link_fail_cnt;
+	pfc_host_stat->loss_of_sync_count = stat_buf.loss_sync_cnt;
+	pfc_host_stat->loss_of_signal_count = stat_buf.loss_sig_cnt;
+	pfc_host_stat->prim_seq_protocol_err_count = stat_buf.prim_seq_err_cnt;
+	pfc_host_stat->invalid_tx_word_count = stat_buf.inval_xmit_word_cnt;
+	pfc_host_stat->invalid_crc_count = stat_buf.inval_crc_cnt;
+
+	return pfc_host_stat;
+}
+
 struct fc_function_template qla2xxx_transport_functions = {
 
 	.show_host_node_name = 1,
@@ -583,6 +617,7 @@ struct fc_function_template qla2xxx_transport_functions = {
 	.show_rport_dev_loss_tmo = 1,
 
 	.issue_fc_host_lip = qla2x00_issue_lip,
+	.get_fc_host_stats = qla2x00_get_fc_host_stats,
 };
 
 void
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 26af5319c2191dda5bd86a30999ca6ab71b79a2a..414580800dc0c5f89df281910e1204a6e086b760 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -29,6 +29,7 @@
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_transport_fc.h>
 
 #if defined(CONFIG_SCSI_QLA2XXX_EMBEDDED_FIRMWARE)
 #if defined(CONFIG_SCSI_QLA21XX) || defined(CONFIG_SCSI_QLA21XX_MODULE)
@@ -2496,6 +2497,7 @@ typedef struct scsi_qla_host {
 
 	uint16_t	zio_mode;
 	uint16_t	zio_timer;
+	struct fc_host_statistics fc_host_stat;
 } scsi_qla_host_t;
 
 
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 35266bd5d5383ba75919f1e285601577ad3abd54..f2f5454a05e9193420f0abaa7a9114b7e503788f 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -185,6 +185,13 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *, uint16_t *, uint16_t *, uint16_t *,
 extern int
 qla2x00_get_fcal_position_map(scsi_qla_host_t *ha, char *pos_map);
 
+extern int
+qla2x00_get_link_status(scsi_qla_host_t *, uint16_t, link_stat_t *,
+    uint16_t *);
+
+extern int
+qla24xx_get_isp_stats(scsi_qla_host_t *, uint32_t *, uint32_t, uint16_t *);
+
 extern int qla24xx_abort_command(scsi_qla_host_t *, srb_t *);
 extern int qla24xx_abort_target(fc_port_t *);
 
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index e67bb099781818339b6a1ef6342694c54825860c..634ee174bff2a315e95fc29dd6fc41a72145480f 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -8,7 +8,6 @@
 
 #include <linux/delay.h>
 #include <linux/vmalloc.h>
-#include <scsi/scsi_transport_fc.h>
 
 #include "qla_devtbl.h"
 
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 3099b379de9d89d554ebd1b5e9dde9d21fdb5d47..49ce197876b487646e3667df649fbe0bdd442665 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -7,7 +7,6 @@
 #include "qla_def.h"
 
 #include <linux/delay.h>
-#include <scsi/scsi_transport_fc.h>
 
 static void
 qla2x00_mbx_sem_timeout(unsigned long data)
@@ -2017,8 +2016,109 @@ qla2x00_get_fcal_position_map(scsi_qla_host_t *ha, char *pos_map)
 
 	return rval;
 }
+#endif
+
+/*
+ * qla2x00_get_link_status
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *	loop_id = device loop ID.
+ *	ret_buf = pointer to link status return buffer.
+ *
+ * Returns:
+ *	0 = success.
+ *	BIT_0 = mem alloc error.
+ *	BIT_1 = mailbox error.
+ */
+int
+qla2x00_get_link_status(scsi_qla_host_t *ha, uint16_t loop_id,
+    link_stat_t *ret_buf, uint16_t *status)
+{
+	int rval;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+	link_stat_t *stat_buf;
+	dma_addr_t stat_buf_dma;
+
+	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);)
+
+	stat_buf = dma_pool_alloc(ha->s_dma_pool, GFP_ATOMIC, &stat_buf_dma);
+	if (stat_buf == NULL) {
+		DEBUG2_3_11(printk("%s(%ld): Failed to allocate memory.\n",
+		    __func__, ha->host_no));
+		return BIT_0;
+	}
+	memset(stat_buf, 0, sizeof(link_stat_t));
+
+	mcp->mb[0] = MBC_GET_LINK_STATUS;
+	mcp->mb[2] = MSW(stat_buf_dma);
+	mcp->mb[3] = LSW(stat_buf_dma);
+	mcp->mb[6] = MSW(MSD(stat_buf_dma));
+	mcp->mb[7] = LSW(MSD(stat_buf_dma));
+	mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
+	mcp->in_mb = MBX_0;
+	if (IS_QLA24XX(ha) || IS_QLA25XX(ha)) {
+		mcp->mb[1] = loop_id;
+		mcp->mb[4] = 0;
+		mcp->mb[10] = 0;
+		mcp->out_mb |= MBX_10|MBX_4|MBX_1;
+		mcp->in_mb |= MBX_1;
+	} else if (HAS_EXTENDED_IDS(ha)) {
+		mcp->mb[1] = loop_id;
+		mcp->mb[10] = 0;
+		mcp->out_mb |= MBX_10|MBX_1;
+	} else {
+		mcp->mb[1] = loop_id << 8;
+		mcp->out_mb |= MBX_1;
+	}
+	mcp->tov = 30;
+	mcp->flags = IOCTL_CMD;
+	rval = qla2x00_mailbox_command(ha, mcp);
+
+	if (rval == QLA_SUCCESS) {
+		if (mcp->mb[0] != MBS_COMMAND_COMPLETE) {
+			DEBUG2_3_11(printk("%s(%ld): cmd failed. mbx0=%x.\n",
+			    __func__, ha->host_no, mcp->mb[0]);)
+			status[0] = mcp->mb[0];
+			rval = BIT_1;
+		} else {
+			/* copy over data -- firmware data is LE. */
+			ret_buf->link_fail_cnt =
+			    le32_to_cpu(stat_buf->link_fail_cnt);
+			ret_buf->loss_sync_cnt =
+			    le32_to_cpu(stat_buf->loss_sync_cnt);
+			ret_buf->loss_sig_cnt =
+			    le32_to_cpu(stat_buf->loss_sig_cnt);
+			ret_buf->prim_seq_err_cnt =
+			    le32_to_cpu(stat_buf->prim_seq_err_cnt);
+			ret_buf->inval_xmit_word_cnt =
+			    le32_to_cpu(stat_buf->inval_xmit_word_cnt);
+			ret_buf->inval_crc_cnt =
+			    le32_to_cpu(stat_buf->inval_crc_cnt);
+
+			DEBUG11(printk("%s(%ld): stat dump: fail_cnt=%d "
+			    "loss_sync=%d loss_sig=%d seq_err=%d "
+			    "inval_xmt_word=%d inval_crc=%d.\n", __func__,
+			    ha->host_no, stat_buf->link_fail_cnt,
+			    stat_buf->loss_sync_cnt, stat_buf->loss_sig_cnt,
+			    stat_buf->prim_seq_err_cnt,
+			    stat_buf->inval_xmit_word_cnt,
+			    stat_buf->inval_crc_cnt);)
+		}
+	} else {
+		/* Failed. */
+		DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
+		    ha->host_no, rval);)
+		rval = BIT_1;
+	}
+
+	dma_pool_free(ha->s_dma_pool, stat_buf, stat_buf_dma);
 
-uint8_t
+	return rval;
+}
+
+int
 qla24xx_get_isp_stats(scsi_qla_host_t *ha, uint32_t *dwbuf, uint32_t dwords,
     uint16_t *status)
 {
@@ -2080,7 +2180,6 @@ qla24xx_get_isp_stats(scsi_qla_host_t *ha, uint32_t *dwbuf, uint32_t dwords,
 
 	return rval;
 }
-#endif
 
 int
 qla24xx_abort_command(scsi_qla_host_t *ha, srb_t *sp)
diff --git a/drivers/scsi/qla2xxx/qla_rscn.c b/drivers/scsi/qla2xxx/qla_rscn.c
index 2c3342108dd82219f311adc9644cd50acbc9a3eb..b70bebe18c0123458150e0e0031fa537edf0b05e 100644
--- a/drivers/scsi/qla2xxx/qla_rscn.c
+++ b/drivers/scsi/qla2xxx/qla_rscn.c
@@ -6,8 +6,6 @@
  */
 #include "qla_def.h"
 
-#include <scsi/scsi_transport_fc.h>
-
 /**
  * IO descriptor handle definitions.
  *