Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > fc11cd6e1c513a17304da94a5390f3cd > files > 3584

kernel-2.6.18-194.11.1.el5.src.rpm

From: Marcus Barrow <mbarrow@redhat.com>
Date: Thu, 2 Jul 2009 12:49:12 -0400
Subject: [scsi] qla2xxx: rhel-5.4 fixes and cleanups
Message-id: 20090702164912.9857.72122.sendpatchset@file.bos.redhat.com
O-Subject: [rhel 5.4 patch] [V2] qla2xxx - Testing fixes, updates 5
Bugzilla: 507246
RH-Acked-by: Rob Evers <revers@redhat.com>

BZ 507246

Version 2 of this patch. This addresses Pete Zaitcev's concerns about a line
of code included for RHEL 5 builds before -153. The code has been removed
from the Makefile and from the .c code. This code was to support testing
during some development work on EEH. Qla2xxx doesn't support EEH in 5.3,
so the code has been removed.

This patch provides fixes from testing at QLogic and it's partners.
It applies and builds cleanly with 2.6.18-154.

 - Encapsulate printks in proper DEBUG macros
 - Do not initialize adapter if qla2x00_get_fw_version fails:  Upstream
 - Fixed messages while falling back to gold firmware:  Upstream
 - Add 10Gb iiDMA support:  Upstream
 - Add notification message when an NPIV fails to acquire a port-id:  Upstream
 - Fallback enode mac should not be a multicast address:  Upstream
 - Avoid redundant RISC reset during re-initialization:  Upstream
 - Query supported RISC registers bits in determining a paused state:  Upstream
 - Avoid DPC processing while driver is unloading:  Upstream
 - Avoid explicit LOGO during driver host tear down:  Upstream
 - Reduce lock contention during DPC processing:  Upstream
 - Remove noisy ct els .not available message:  Upstream
 - Conditionally disable automatic queue full tracking:  Upstream
 - Fixup qla2x00_eh_wait_on_command usages:  Upstream
 - Add Loopback support using Netlink Interface:  Management App support, going upstream

 - Export firmware state for application support:
 - Propagate residual length to upper layers
 - Fix EEH handling
 - Limit querying to supported mailbox registers while reading FW state
 - Correct iiDMA update calling conventions
 - Added iIDMA get set support for Application

 - Updated driver version to 8.03.00.08.05.04-k

diff --git a/drivers/scsi/qla2xxx/Makefile b/drivers/scsi/qla2xxx/Makefile
index bcc2dfc..af8486f 100644
--- a/drivers/scsi/qla2xxx/Makefile
+++ b/drivers/scsi/qla2xxx/Makefile
@@ -1,4 +1,5 @@
 EXTRA_CFLAGS += -DNETLINK_FCTRANSPORT=20
+
 qla2xxx-y := qla_os.o qla_init.o qla_mbx.o qla_iocb.o qla_isr.o qla_gs.o \
 		qla_dbg.o qla_sup.o qla_attr.o qla_mid.o qla_nlnk.o ql2100_fw.o \
 		ql2200_fw.o ql2300_fw.o ql2322_fw.o ql2400_fw.o ql2500_fw.o
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index dc72f60..3e3b204 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -299,6 +299,9 @@ qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj, char *buf, loff_t off,
 	if (off)
 		return 0;
 
+	if (unlikely(pci_channel_offline(ha->pdev)))
+		return 0;
+
 	if (sscanf(buf, "%d:%x:%x", &val, &start, &size) < 1)
 		return -EINVAL;
 	if (start > ha->optrom_size)
@@ -442,6 +445,9 @@ qla2x00_sysfs_read_vpd(struct kobject *kobj, char *buf, loff_t off,
 	int           size = ha->vpd_size;
 	char          *vpd_cache = ha->vpd;
 
+	if (unlikely(pci_channel_offline(ha->pdev)))
+		return 0;
+
 	if (!capable(CAP_SYS_ADMIN) || off > size || count == 0)
 		return 0;
 	if (off + count > size) {
@@ -466,6 +472,9 @@ qla2x00_sysfs_write_vpd(struct kobject *kobj, char *buf, loff_t off,
 	uint8_t *tmp_data = NULL;
 	int status ;
 
+	if (unlikely(pci_channel_offline(ha->pdev)))
+		return 0;
+
 	if (!capable(CAP_SYS_ADMIN) || off != 0 || count != ha->vpd_size ||
 	    !ha->isp_ops->write_nvram)
 		return 0;
@@ -559,7 +568,7 @@ static struct bin_attribute sysfs_sfp_attr = {
 	.read = qla2x00_sysfs_read_sfp,
 };
 
-static fc_port_t *
+fc_port_t *
 qla2x00_find_port(struct scsi_qla_host *ha, uint8_t *pn)
 {
 	fc_port_t *fcport;
@@ -574,6 +583,9 @@ qla2x00_find_port(struct scsi_qla_host *ha, uint8_t *pn)
 static void
 qla2x00_wait_for_passthru_completion(struct scsi_qla_host *ha)
 {
+	if (unlikely(pci_channel_offline(ha->pdev)))
+		return;
+
 	if (!wait_for_completion_timeout(&ha->pass_thru_intr_comp, 10 * HZ)) {
 		DEBUG2(qla_printk(KERN_WARNING, ha,
 		    "Passthru request timed out.\n"));
@@ -592,7 +604,7 @@ qla2x00_sysfs_read_els(struct kobject *kobj, char *buf, loff_t off,
 		return 0;
 
 	if (!ha->pass_thru_cmd_in_process || !ha->pass_thru_cmd_result) {
-		DEBUG2(qla_printk(KERN_WARNING, ha,
+		DEBUG3(qla_printk(KERN_WARNING, ha,
 		    "Passthru ELS response is not available.\n"));
 		return 0;
 	}
@@ -727,7 +739,7 @@ qla2x00_sysfs_read_ct(struct kobject *kobj, char *buf, loff_t off,
 	    container_of(kobj, struct device, kobj)));
 
 	if (!ha->pass_thru_cmd_in_process || !ha->pass_thru_cmd_result) {
-		DEBUG2(qla_printk(KERN_WARNING, ha,
+		DEBUG3(qla_printk(KERN_WARNING, ha,
 		    "Passthru CT response is not available.\n"));
 		return 0;
 	}
@@ -1834,6 +1846,19 @@ qla2x00_fabric_param_show(struct class_device *cdev, char *buf)
         return snprintf(buf, PAGE_SIZE, "%d\n", ha->switch_cap);
 }
 
+static ssize_t
+qla2x00_fw_state_show(struct class_device *cdev, char *buf)
+{
+	int rval;
+	uint16_t state[5];
+	scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+	scsi_qla_host_t *pha = to_qla_parent(ha);
+	rval = qla2x00_get_firmware_state(pha, state);
+	if (rval != QLA_SUCCESS)
+	    memset(state, -1, sizeof(state));
+	return snprintf(buf, PAGE_SIZE, "0x%x 0x%x 0x%x 0x%x 0x%x\n", state[0],
+	    state[1], state[2], state[3], state[4]);
+}
 static CLASS_DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show,
 	NULL);
 static CLASS_DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL);
@@ -1893,6 +1918,8 @@ static CLASS_DEVICE_ATTR(vn_port_mac_address, S_IRUGO,
                    qla2x00_vn_port_mac_address_show, NULL);
 static CLASS_DEVICE_ATTR(fabric_param, S_IRUGO,
                    qla2x00_fabric_param_show, NULL);
+static CLASS_DEVICE_ATTR(fw_state, S_IRUGO,
+                   qla2x00_fw_state_show, NULL);
 
 
 struct class_device_attribute *qla2x00_host_attrs[] = {
@@ -1913,6 +1940,7 @@ struct class_device_attribute *qla2x00_host_attrs[] = {
 	&class_device_attr_optrom_fcode_version,
 	&class_device_attr_optrom_fw_version,
 	&class_device_attr_total_isp_aborts,
+	&class_device_attr_fw_state,
 	NULL,
 };
 
@@ -1945,6 +1973,7 @@ struct class_device_attribute *qla24xx_host_attrs[] = {
 	&class_device_attr_vlan_id,
 	&class_device_attr_vn_port_mac_address,
 	&class_device_attr_fabric_param,
+	&class_device_attr_fw_state,
 	NULL,
 };
 
@@ -1979,6 +2008,7 @@ struct class_device_attribute *qla24xx_host_vport_attrs[] = {
 	&class_device_attr_vlan_id,
 	&class_device_attr_vn_port_mac_address,
 	&class_device_attr_fabric_param,
+	&class_device_attr_fw_state,
 	NULL,
 };
 
@@ -2124,11 +2154,17 @@ qla2x00_dev_loss_tmo_callbk(struct fc_rport *rport)
 		return ;
 	}
 
+	if (unlikely(pci_channel_offline(fcport->ha->pdev))) {
+		qla2x00_abort_all_cmds(fcport->ha, DID_NO_CONNECT << 16);
+		return;
+	}
+
 	/*
 	 * At this point all fcport's software-states are cleared.  Perform any
 	 * final cleanup of firmware resources (PCBs and XCBs).
 	 */
-	if (fcport->loop_id != FC_NO_LOOP_ID) {
+	if (fcport->loop_id != FC_NO_LOOP_ID &&
+	    !test_bit(UNLOADING, &fcport->ha->dpc_flags)) {
 		fcport->ha->isp_ops->fabric_logout(fcport->ha,
 			fcport->loop_id, fcport->d_id.b.domain,
 			fcport->d_id.b.area, fcport->d_id.b.al_pa);
@@ -2160,11 +2196,18 @@ qla2x00_terminate_rport_io(struct fc_rport *rport)
 	if (test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags)) {
 		return ;
 	}
+
+	if (unlikely(pci_channel_offline(fcport->ha->pdev))) {
+		qla2x00_abort_all_cmds(fcport->ha, DID_NO_CONNECT << 16);
+		return;
+	}
+
 	/*
 	 * At this point all fcport's software-states are cleared.  Perform any
 	 * final cleanup of firmware resources (PCBs and XCBs).
 	 */
-	if (fcport->loop_id != FC_NO_LOOP_ID) {
+	if (fcport->loop_id != FC_NO_LOOP_ID &&
+	    !test_bit(UNLOADING, &fcport->ha->dpc_flags)) {
 		fcport->ha->isp_ops->fabric_logout(fcport->ha,
 			fcport->loop_id, fcport->d_id.b.domain,
 			fcport->d_id.b.area, fcport->d_id.b.al_pa);
@@ -2195,6 +2238,19 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
 
 	pfc_host_stat = &ha->fc_host_stat;
 	memset(pfc_host_stat, -1, sizeof(struct fc_host_statistics));
+	if (test_bit(UNLOADING, &ha->dpc_flags))
+		goto done;
+
+	if (unlikely(pci_channel_offline(ha->pdev)))
+		goto done;
+
+	if (test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) ||
+	    test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) ||
+	    test_bit(ISP_ABORT_RETRY, &ha->dpc_flags)) {
+		DEBUG2_3_11(printk("%s(%ld): isp reset in progress.\n",
+		   __func__, ha->host_no));
+		goto done;
+	}
 
 	stats = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &stats_dma);
 	if (stats == NULL) {
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index b1dec9e..9918475 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -172,11 +172,9 @@ qla24xx_pause_risc(struct device_reg_24xx __iomem *reg)
 	int rval = QLA_SUCCESS;
 	uint32_t cnt;
 
-	if (RD_REG_DWORD(&reg->hccr) & HCCRX_RISC_PAUSE)
-		return rval;
-
 	WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_PAUSE);
-	for (cnt = 30000; (RD_REG_DWORD(&reg->hccr) & HCCRX_RISC_PAUSE) == 0 &&
+	for (cnt = 30000;
+	    (RD_REG_DWORD(&reg->host_status) & HCCRX_RISC_PAUSE) == 0 &&
 	    rval == QLA_SUCCESS; cnt--) {
 		if (cnt)
 			udelay(100);
diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h
index f145fe3..7bf7ec8 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.h
+++ b/drivers/scsi/qla2xxx/qla_dbg.h
@@ -23,6 +23,7 @@
 /* #define QL_DEBUG_LEVEL_14 */ /* Output RSCN trace msgs */
 /* #define QL_DEBUG_LEVEL_15 */ /* Output NPIV trace msgs */
 /* #define QL_DEBUG_LEVEL_16 */ /* Output ISP84XX trace msgs */
+/* #define QL_DEBUG_LEVEL_17 */ /* Output EEH trace msgs */
 /*
  *  Local Macro Definitions.
  */
@@ -141,6 +142,12 @@
 #define DEBUG16(x)	do {} while (0)
 #endif
 
+#if defined(QL_DEBUG_LEVEL_17)
+#define DEBUG17(x)      do {x;} while (0)
+#else
+#define DEBUG17(x)	do {} while (0)
+#endif
+
 /*
  * Firmware Dump structure definition
  */
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index e6f1af0..599769b 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -2254,6 +2254,17 @@ struct qlfc_fw {
         uint32_t len;
 };
 
+struct qla_loopback {
+        void *loopback_buf;
+        dma_addr_t loopback_dma;
+        uint32_t len;
+};
+
+#define	INT_DEF_LB_LOOPBACK_CMD		0
+#define	INT_DEF_LB_ECHO_CMD		1
+
+#define	QLA_RESET_FC_LB_FAILED		0x17
+
 /* Work events.  */
 enum qla_work_type {
        QLA_EVT_IDC_ACK,
@@ -2315,6 +2326,7 @@ typedef struct scsi_qla_host {
 		uint32_t        chip_reset_done         :1;
 		uint32_t        running_gold_fw		:1;
 		uint32_t        fac_supported		:1;
+		uint32_t        eeh_busy		:1;
 	} flags;
 
 	atomic_t	loop_state;
@@ -2355,7 +2367,8 @@ typedef struct scsi_qla_host {
 #define REGISTER_FDMI_NEEDED	26
 #define FCPORT_UPDATE_NEEDED	27
 #define VP_DPC_NEEDED		28	/* wake up for VP dpc handling */
-#define NPIV_CONFIG_NEEDED	29
+#define UNLOADING		29
+#define NPIV_CONFIG_NEEDED	30
 
 	uint32_t	device_flags;
 #define DFLG_LOCAL_DEVICES		BIT_0
@@ -2437,6 +2450,7 @@ typedef struct scsi_qla_host {
 	 */
 
 	spinlock_t		hardware_lock ____cacheline_aligned;
+	spinlock_t		work_lock;
 
 	device_reg_t __iomem *iobase;		/* Base I/O address */
 	resource_size_t pio_address;
@@ -2766,6 +2780,7 @@ typedef struct scsi_qla_host {
 	struct qlfc_aen_log aen_log;
 	struct qla_statistics qla_stats;
 	struct qlfc_fw fw_buf;
+	struct qla_loopback loopback_buf;
 } scsi_qla_host_t;
 
 
@@ -2852,4 +2867,7 @@ qla2xxx_log_aen(scsi_qla_host_t *ha, uint16_t code, uint16_t p1, uint16_t p2,
 	}
 }
 
+/* dest_type used for iidma */
+#define	EXT_DEF_TYPE_WWPN		2
+
 #endif
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 9b21639..b3df11e 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -73,10 +73,12 @@ extern int ql2xfdmienable;
 extern int ql2xallocfwdump;
 extern int ql2xextended_error_logging;
 extern int ql2xqfullrampup;
+extern int ql2xqfulltracking;
 extern int ql2xenablemsix;
 extern int num_hosts;
 
 extern int qla2x00_loop_reset(scsi_qla_host_t *);
+extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int);
 
 extern void qla2x00_abort_fcport_cmds(fc_port_t *);
 
@@ -151,7 +153,7 @@ qla2x00_dump_ram(scsi_qla_host_t *, dma_addr_t, uint32_t, uint32_t);
 extern int
 qla2x00_execute_fw(scsi_qla_host_t *, uint32_t);
 
-extern void
+extern int
 qla2x00_get_fw_version(scsi_qla_host_t *, uint16_t *, uint16_t *, uint16_t *,
     uint16_t *, uint32_t *, uint8_t *, uint32_t *, uint8_t *);
 
@@ -273,6 +275,9 @@ qla2x00_write_edc(scsi_qla_host_t *, uint16_t, uint16_t, dma_addr_t,
 extern int
 qla2x00_set_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t *);
 
+extern int
+qla2x00_get_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t *, uint16_t *);
+
 extern int qla84xx_verify_chip(struct scsi_qla_host *, uint16_t *);
 
 extern int
@@ -290,6 +295,12 @@ qla81xx_fac_do_write_enable(scsi_qla_host_t *, int);
 extern int
 qla81xx_fac_erase_sector(scsi_qla_host_t *, uint32_t, uint32_t);
 
+extern int
+qla2x00_read_ram_word(scsi_qla_host_t *, uint32_t, uint32_t *);
+
+extern int
+qla2x00_write_ram_word(scsi_qla_host_t *, uint32_t, uint32_t);
+
 /*
  * Global Function Prototypes in qla_isr.c source file.
  */
@@ -403,4 +414,9 @@ extern int ql_nl_register(void);
 extern void ql_nl_unregister(void);
 extern void qla_free_nlnk_dmabuf(scsi_qla_host_t *);
 
+/*
+ * Global functions in qla_attr.c
+ */
+extern fc_port_t *qla2x00_find_port(struct scsi_qla_host *, uint8_t *);
+
 #endif /* _QLA_GBL_H */
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index c2ad058..db04b18 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -1876,6 +1876,9 @@ qla2x00_gpsc(scsi_qla_host_t *ha, sw_info_t *list)
 			case BIT_13:
 				list[i].fp_speed = PORT_SPEED_4GB;
 				break;
+			case BIT_12:
+				list[i].fp_speed = PORT_SPEED_10GB;
+				break;
 			case BIT_11:
 				list[i].fp_speed = PORT_SPEED_8GB;
 				break;
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 50f07d1..d6bfe14 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -68,6 +68,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha)
 	ha->flags.chip_reset_done = 0;
 	ha->flags.reset_active = 0;
 	ha->flags.pci_channel_io_perm_failure = 0;
+	ha->flags.eeh_busy = 0;
 	atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);
 	atomic_set(&ha->loop_state, LOOP_DOWN);
 	ha->device_flags = DFLG_NO_CABLE;
@@ -430,6 +431,9 @@ qla2x00_reset_chip(scsi_qla_host_t *ha)
 	uint32_t	cnt;
 	uint16_t	cmd;
 
+	if (unlikely(pci_channel_offline(ha->pdev)))
+		return;
+
 	ha->isp_ops->disable_intrs(ha);
 
 	spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -773,9 +777,6 @@ qla24xx_chip_diag(scsi_qla_host_t *ha)
 {
 	int rval;
 
-	/* Perform RISC reset. */
-	qla24xx_reset_risc(ha);
-
 	ha->fw_transfer_size = REQUEST_ENTRY_SIZE * 1024;
 
 	rval = qla2x00_mbx_reg_test(ha);
@@ -951,6 +952,77 @@ qla2x00_resize_request_q(scsi_qla_host_t *ha)
 	ha->request_dma = request_dma;
 }
 
+static int
+qla81xx_mpi_sync(scsi_qla_host_t *ha)
+{
+#define MPS_MASK	0xef
+	int rval;
+	uint16_t dc;
+	uint32_t dw;
+
+	if (!IS_QLA81XX(ha))
+		return QLA_SUCCESS;
+
+	rval = qla2x00_write_ram_word(ha, 0x7c00, 1);
+	if (rval != QLA_SUCCESS) {
+		DEBUG2(qla_printk(KERN_WARNING, ha,
+		    "Sync-MPI: Unable to acquire semaphore.\n"));
+		goto done;
+	}
+
+	pci_read_config_word(ha->pdev, 0x54, &dc);
+	rval = qla2x00_read_ram_word(ha, 0x7a15, &dw);
+	if (rval != QLA_SUCCESS) {
+		DEBUG2(qla_printk(KERN_WARNING, ha,
+		    "Sync-MPI: Unable to read sync.\n"));
+		goto done_release;
+	}
+
+	DEBUG17(qla_printk(KERN_WARNING, ha,
+	    "mpi_sync rd: dc: %02x dw:%x\n", dc, dw));
+
+	dc &= MPS_MASK;
+	if (dc == (dw & MPS_MASK))
+		goto done_release;
+
+	dw &= ~MPS_MASK;
+	dw |= dc;
+
+	DEBUG17(qla_printk(KERN_WARNING, ha,
+	    "mpi_sync wr: dc: %02x dw:%x\n", dc, dw));
+
+	rval = qla2x00_write_ram_word(ha, 0x7a15, dw);
+	if (rval != QLA_SUCCESS) {
+		DEBUG2(qla_printk(KERN_WARNING, ha,
+		    "Sync-MPI: Unable to gain sync.\n"));
+	}
+
+done_release:
+	rval = qla2x00_write_ram_word(ha, 0x7c00, 0);
+	if (rval != QLA_SUCCESS) {
+		DEBUG2(qla_printk(KERN_WARNING, ha,
+		    "Sync-MPI: Unable to release semaphore.\n"));
+	}
+
+done:
+
+#ifdef QL_DEBUG_LEVEL_17
+	{
+		uint8_t b;
+		uint32_t i;
+
+		printk("mpi_sync: ");
+		for (i = 0; i < 256; i++) {
+			pci_read_config_byte(ha->pdev, i, &b);
+			printk("%s%02x", (i%16) ? " " : "\n", b);
+		}
+		printk("\n");
+	}
+#endif
+
+	return rval;
+}
+
 /**
  * qla2x00_setup_chip() - Load and start RISC firmware.
  * @ha: HA context
@@ -964,6 +1036,8 @@ qla2x00_setup_chip(scsi_qla_host_t *ha)
 	uint16_t fw_major_version;
 	uint32_t srisc_address = 0;
 
+	qla81xx_mpi_sync(ha);
+
 	/* Load firmware sequences */
 	rval = ha->isp_ops->load_risc(ha, &srisc_address);
 	if (rval == QLA_SUCCESS) {
@@ -981,13 +1055,15 @@ qla2x00_setup_chip(scsi_qla_host_t *ha)
 			if (rval == QLA_SUCCESS) {
 				fw_major_version = ha->fw_major_version;
 			
-				qla2x00_get_fw_version(ha,
+				rval = qla2x00_get_fw_version(ha,
 				    &ha->fw_major_version,
 				    &ha->fw_minor_version,
 				    &ha->fw_subminor_version,
 				    &ha->fw_attributes, &ha->fw_memory_size,
 				    ha->mpi_version, &ha->mpi_capabilities,
 				    ha->phy_version);
+				if (rval != QLA_SUCCESS)
+					goto setup_failed;
 
 				ha->flags.npiv_supported = 0;
 				if ((IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) ||
@@ -1030,6 +1106,7 @@ qla2x00_setup_chip(scsi_qla_host_t *ha)
                 }
         }
 
+setup_failed:
 	if (rval) {
 		DEBUG2_3(printk("scsi(%ld): Setup chip **** FAILED ****.\n",
 		    ha->host_no));
@@ -1292,7 +1369,7 @@ qla2x00_fw_ready(scsi_qla_host_t *ha)
 	unsigned long	wtime, mtime, cs84xx_time;
 	uint16_t	min_wait;	/* Minimum wait time if loop is down */
 	uint16_t	wait_time;	/* Wait time if loop is coming ready */
-	uint16_t	state[3];
+	uint16_t	state[5];
 
 	rval = QLA_SUCCESS;
 
@@ -1390,8 +1467,9 @@ qla2x00_fw_ready(scsi_qla_host_t *ha)
 		    ha->host_no, state[0], jiffies));
 	} while (1);
 
-	DEBUG(printk("scsi(%ld): fw_state=%x curr time=%lx.\n",
-	    ha->host_no, state[0], jiffies));
+	DEBUG(printk("scsi(%ld): fw_state=%x (%x, %x, %x, %x) curr time=%lx.\n",
+	    ha->host_no, state[0], state[1], state[2], state[3], state[4],
+	    jiffies));
 
 	if (rval) {
 		DEBUG2_3(printk("scsi(%ld): Firmware ready **** FAILED ****.\n",
@@ -2183,9 +2261,10 @@ static void
 qla2x00_iidma_fcport(scsi_qla_host_t *ha, fc_port_t *fcport)
 {
 #define LS_UNKNOWN      2
-	static char *link_speeds[5] = { "1", "2", "?", "4", "8" };
+	static char *link_speeds[] = { "1", "2", "?", "4", "8", "10"};
+	char *link_speed;
 	int rval;
-	uint16_t mb[6];
+	uint16_t mb[4];
 
 	if (!IS_IIDMA_CAPABLE(ha))
 		return;
@@ -2205,10 +2284,15 @@ qla2x00_iidma_fcport(scsi_qla_host_t *ha, fc_port_t *fcport)
 		    fcport->port_name[6], fcport->port_name[7], rval,
 		    fcport->fp_speed, mb[0], mb[1]));
 	} else {
+		link_speed = link_speeds[LS_UNKNOWN];
+		if (fcport->fp_speed < 5)
+			link_speed = link_speeds[fcport->fp_speed];
+		else if (fcport->fp_speed == 0x13)
+			link_speed = link_speeds[5];
 		DEBUG2(qla_printk(KERN_INFO, ha,
 		    "iIDMA adjusted to %s GB/s on "
 		    "%02x%02x%02x%02x%02x%02x%02x%02x.\n",
-		    link_speeds[fcport->fp_speed], fcport->port_name[0],
+		    link_speed, fcport->port_name[0],
 		    fcport->port_name[1], fcport->port_name[2],
 		    fcport->port_name[3], fcport->port_name[4],
 		    fcport->port_name[5], fcport->port_name[6],
@@ -3231,9 +3315,6 @@ int
 qla2x00_abort_isp(scsi_qla_host_t *ha)
 {
 	int rval;
-	unsigned long flags = 0;
-	uint16_t       cnt;
-	srb_t          *sp;
 	uint8_t        status = 0;
 	scsi_qla_host_t *vha;
 
@@ -3257,19 +3338,8 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
 				    LOOP_DOWN_TIME);
 		}
 
-		spin_lock_irqsave(&ha->hardware_lock, flags);
 		/* Requeue all commands in outstanding command list. */
-		for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
-			sp = ha->outstanding_cmds[cnt];
-			if (sp) {
-				ha->outstanding_cmds[cnt] = NULL;
-				sp->flags = 0;
-				sp->cmd->result = DID_RESET << 16;
-				sp->cmd->host_scribble = (unsigned char *)NULL;
-				qla2x00_sp_compl(ha, sp);
-			}
-		}
-		spin_unlock_irqrestore(&ha->hardware_lock, flags);
+		qla2x00_abort_all_cmds(ha, DID_RESET << 16);
 
 		if (pci_channel_offline(ha->pdev) &&
 		    ha->flags.pci_channel_io_perm_failure) {
@@ -4021,21 +4091,16 @@ qla81xx_load_risc(scsi_qla_host_t *ha, uint32_t *srisc_addr)
          * 2) Golden firmware residing in flash.
          */
         rval = qla24xx_load_risc_flash(ha, srisc_addr, ha->flt_region_fw);
-        if (rval == QLA_SUCCESS)
+        if (rval == QLA_SUCCESS || !ha->flt_region_gold_fw)
                 return rval;
 
-	qla_printk(KERN_ERR, ha, "Unable to load operational firmware.\n");
-	if (ha->flt_region_gold_fw) {
-		qla_printk(KERN_ERR, ha, "Falling back to golden firmware.\n");
-		qla_printk(KERN_ERR, ha, "Please update the operational firmware.\n");
-		rval = qla24xx_load_risc_flash(ha, srisc_addr,
-		    ha->flt_region_gold_fw);
-		if (rval == QLA_SUCCESS)
-			ha->flags.running_gold_fw = 1; 
-		else
-			qla_printk(KERN_ERR, ha, "Unable to load golden firmware,"
-			    " disabling adapter.\n");
-	}
+	qla_printk(KERN_ERR, ha, "FW: Attempting to fallback to golden firmware...\n");
+	rval = qla24xx_load_risc_flash(ha, srisc_addr,
+			ha->flt_region_gold_fw);
+	if (rval == QLA_SUCCESS)
+		ha->flags.running_gold_fw = 1; 
+	else
+		qla_printk(KERN_ERR, ha, "FW: Please update operational firmware...\n");
 	return rval;
 }
 
@@ -4242,7 +4307,7 @@ qla81xx_nvram_config(scsi_qla_host_t *ha)
 	memcpy(icb->enode_mac, nv->enode_mac, sizeof(icb->enode_mac));
 	/* Some boards (with valid NVRAMs) still have NULL enode_mac!! */
 	if (!memcmp(icb->enode_mac, "\0\0\0\0\0\0", sizeof(icb->enode_mac))) {
-		icb->enode_mac[0] = 0x01;
+		icb->enode_mac[0] = 0x00;
 		icb->enode_mac[1] = 0x02;
 		icb->enode_mac[2] = 0x03;
 		icb->enode_mac[3] = 0x04;
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 882ee92..8240efb 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -477,6 +477,7 @@ skip_rio:
 		qla_printk(KERN_INFO, ha, "LOOP UP detected (%s Gbps).\n",
 		    link_speed);
 
+		ha->current_topology = 0;
 		ha->flags.management_server_logged_in = 0;
 		break;
 
@@ -794,6 +795,9 @@ qla2x00_ramp_up_queue_depth(scsi_qla_host_t *ha, srb_t *sp)
 	fc_port_t *fcport;
 	struct scsi_device *sdev;
 
+        if (!ql2xqfulltracking)
+                return;
+
 	sdev = sp->cmd->device;
 	if (sdev->queue_depth >= ha->max_q_depth)
 		return;
@@ -1122,6 +1126,8 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
 			    scsi_status));
 
 			/* Adjust queue depth for all luns on the port. */
+			if (!ql2xqfulltracking)
+				break;
 			fcport->last_queue_full = jiffies;
 			starget_for_each_device(cp->device->sdev_target,
 			    fcport, qla2x00_adjust_sdev_qdepth_down);
@@ -1181,6 +1187,9 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
 				 * Adjust queue depth for all luns on the
 				 * port.
 				 */
+				if (!ql2xqfulltracking)
+					break;
+
 				fcport->last_queue_full = jiffies;
 				starget_for_each_device(
 				    cp->device->sdev_target, fcport,
@@ -1227,7 +1236,7 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
 					      cp->device->channel, cp->device->id,
 					      cp->device->lun, resid,
 					      scsi_bufflen(cp)));
-
+				scsi_set_resid(cp, resid);
 				cp->result = DID_ERROR << 16;
 				break;
 			}
@@ -1694,6 +1703,9 @@ qla24xx_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
 	reg = &ha->iobase->isp24;
 	status = 0;
 
+	if (unlikely(pci_channel_offline(ha->pdev)))
+		return IRQ_HANDLED;
+
 	spin_lock_irqsave(&ha->hardware_lock, flags);
 	for (iter = 50; iter--; ) {
 		stat = RD_REG_DWORD(&reg->host_status);
@@ -1744,6 +1756,13 @@ qla24xx_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
 	}
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
+#ifdef QL_DEBUG_LEVEL_17
+	if (!irq && ha->flags.eeh_busy)
+		qla_printk(KERN_WARNING, ha,
+		    "isr: status %x, cmd_flags %lx, mbox_int %x, stat %x\n",
+		    status, ha->mbx_cmd_flags, ha->flags.mbox_int, stat);
+#endif
+
 	if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
 	    (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
 		set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index c997a9e..3085c40 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -58,6 +58,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
 	 * non ISP abort time.
 	 */
 	if (!ha->flags.pci_channel_io_perm_failure) {
+
 		if (!wait_for_completion_timeout(&ha->mbx_cmd_comp,
 		    mcp->tov * HZ)) {
 			/* Timeout occurred. Return error. */
@@ -146,6 +147,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
 		wait_time = jiffies + mcp->tov * HZ; /* wait at most tov secs */
+
 		while (!ha->flags.mbox_int) {
 			if (time_after(jiffies, wait_time))
 				break;
@@ -153,10 +155,14 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
 			/* Check for pending interrupts. */
 			qla2x00_poll(ha);
 
-			if (command != MBC_LOAD_RISC_RAM_EXTENDED &&
-			    !ha->flags.mbox_int)
+			if (!ha->flags.mbox_int &&
+			    !(IS_QLA2200(ha) &&
+			    command == MBC_LOAD_RISC_RAM_EXTENDED))
 				msleep(10);
 		} /* while */
+		DEBUG17(qla_printk(KERN_WARNING, ha,
+			"Waited %d sec\n",
+			(uint)((jiffies - (wait_time - (mcp->tov * HZ)))/HZ)));
 	}
 
 	/* Check whether we timed out */
@@ -226,7 +232,8 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
 
 	if (rval == QLA_FUNCTION_TIMEOUT &&
 	    mcp->mb[0] != MBC_GEN_SYSTEM_ERROR) {
-		if (!io_lock_on || (mcp->flags & IOCTL_CMD)) {
+		if (!io_lock_on || (mcp->flags & IOCTL_CMD) ||
+		    ha->flags.eeh_busy) {
 			/* not in dpc. schedule it for dpc to take over. */
 			DEBUG(printk("%s(%ld): timeout schedule "
 			    "isp_abort_needed.\n", __func__, ha->host_no));
@@ -234,7 +241,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
 			    "isp_abort_needed.\n", __func__, ha->host_no));
 			qla_printk(KERN_WARNING, ha,
 			    "Mailbox command timeout occured. Scheduling ISP "
-			    "abort.\n");
+			    "abort. eeh_busy: 0x%x\n", ha->flags.eeh_busy);
 			set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
 			qla2xxx_wake_dpc(ha);
 		} else if (!abort_active) {
@@ -402,7 +409,7 @@ qla2x00_execute_fw(scsi_qla_host_t *ha, uint32_t risc_addr)
  * Context:
  *	Kernel context.
  */
-void
+int
 qla2x00_get_fw_version(scsi_qla_host_t *ha, uint16_t *major, uint16_t *minor,
     uint16_t *subminor, uint16_t *attributes, uint32_t *memory, uint8_t *mpi,
     uint32_t *mpi_caps, uint8_t *phy)
@@ -423,6 +430,9 @@ qla2x00_get_fw_version(scsi_qla_host_t *ha, uint16_t *major, uint16_t *minor,
 	mcp->tov = 30;
 	rval = qla2x00_mailbox_command(ha, mcp);
 
+	if (rval != QLA_SUCCESS)
+		goto get_failed;
+
 	/* Return mailbox data. */
 	*major = mcp->mb[1];
 	*minor = mcp->mb[2];
@@ -442,7 +452,7 @@ qla2x00_get_fw_version(scsi_qla_host_t *ha, uint16_t *major, uint16_t *minor,
 		phy[2] = mcp->mb[9] & 0xff;
 	}
 
-
+get_failed:
 	if (rval != QLA_SUCCESS) {
 		/*EMPTY*/
 		DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
@@ -451,6 +461,7 @@ qla2x00_get_fw_version(scsi_qla_host_t *ha, uint16_t *major, uint16_t *minor,
 		/*EMPTY*/
 		DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
 	}
+	return rval;
 }
 
 /*
@@ -1228,15 +1239,22 @@ qla2x00_get_firmware_state(scsi_qla_host_t *ha, uint16_t *states)
 
 	mcp->mb[0] = MBC_GET_FIRMWARE_STATE;
 	mcp->out_mb = MBX_0;
-	mcp->in_mb = MBX_3|MBX_2|MBX_1|MBX_0;
+	if (IS_FWI2_CAPABLE(ha))
+		mcp->in_mb = MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+	else
+		mcp->in_mb = MBX_1|MBX_0;
 	mcp->tov = 30;
 	mcp->flags = 0;
 	rval = qla2x00_mailbox_command(ha, mcp);
 
 	/* Return firmware state. */
 	states[0] = mcp->mb[1];
-	states[1] = mcp->mb[2];
-	states[2] = mcp->mb[3];
+	if (IS_FWI2_CAPABLE(ha)) {
+		states[1] = mcp->mb[2];
+		states[2] = mcp->mb[3];
+		states[3] = mcp->mb[4];
+		states[4] = mcp->mb[5];
+	}
 
 	if (rval != QLA_SUCCESS) {
 		/*EMPTY*/
@@ -2417,6 +2435,10 @@ qla2x00_trace_control(scsi_qla_host_t *ha, uint16_t ctrl, dma_addr_t eft_dma,
 	if (!IS_FWI2_CAPABLE(ha))
 		return QLA_FUNCTION_FAILED;
 
+	/* Return if pci_channel_offline */
+	if (unlikely(pci_channel_offline(ha->pdev)))
+		return QLA_FUNCTION_FAILED;
+
 	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
 
 	mcp->mb[0] = MBC_TRACE_CONTROL;
@@ -2485,6 +2507,48 @@ qla2x00_read_sfp(scsi_qla_host_t *ha, dma_addr_t sfp_dma, uint16_t addr,
 }
 
 int
+qla2x00_get_idma_speed(scsi_qla_host_t *ha, uint16_t loop_id,
+    uint16_t *port_speed, uint16_t *mb)
+{
+	int rval;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+
+	if (!IS_IIDMA_CAPABLE(ha))
+		return QLA_FUNCTION_FAILED;
+
+	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+
+	mcp->mb[0] = MBC_PORT_PARAMS;
+	mcp->mb[1] = loop_id;
+	mcp->mb[2] = mcp->mb[3] = 0;
+	mcp->mb[9] = ha->vp_idx;
+	mcp->out_mb = MBX_9|MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->in_mb = MBX_3|MBX_1|MBX_0;
+	mcp->tov = MBX_TOV_SECONDS;
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(ha, mcp);
+
+	/* Return mailbox statuses. */
+	if (mb != NULL) {
+		mb[0] = mcp->mb[0];
+		mb[1] = mcp->mb[1];
+		mb[3] = mcp->mb[3];
+	}
+
+	if (rval != QLA_SUCCESS) {
+		DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
+		    ha->host_no, rval));
+	} else {
+		DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
+		if (port_speed)
+			*port_speed = mcp->mb[3];
+	}
+
+	return rval;
+}
+
+int
 qla2x00_set_idma_speed(scsi_qla_host_t *ha, uint16_t loop_id,
     uint16_t port_speed, uint16_t *mb)
 {
@@ -2500,10 +2564,14 @@ qla2x00_set_idma_speed(scsi_qla_host_t *ha, uint16_t loop_id,
 	mcp->mb[0] = MBC_PORT_PARAMS;
 	mcp->mb[1] = loop_id;
 	mcp->mb[2] = BIT_0;
-	mcp->mb[3] = port_speed & (BIT_2|BIT_1|BIT_0);
-	mcp->mb[4] = mcp->mb[5] = 0;
-	mcp->out_mb = MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
-	mcp->in_mb = MBX_5|MBX_4|MBX_3|MBX_1|MBX_0;
+	if (IS_QLA81XX(ha))
+		mcp->mb[3] = port_speed & (BIT_5|BIT_4|BIT_3|BIT_2|BIT_1|BIT_0);
+	else
+		mcp->mb[3] = port_speed & (BIT_2|BIT_1|BIT_0);
+
+	mcp->mb[9] = ha->vp_idx;
+	mcp->out_mb = MBX_9|MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->in_mb = MBX_3|MBX_1|MBX_0;
 	mcp->tov = 30;
 	mcp->flags = 0;
 	rval = qla2x00_mailbox_command(ha, mcp);
@@ -2513,8 +2581,6 @@ qla2x00_set_idma_speed(scsi_qla_host_t *ha, uint16_t loop_id,
 		mb[0] = mcp->mb[0];
 		mb[1] = mcp->mb[1];
 		mb[3] = mcp->mb[3];
-		mb[4] = mcp->mb[4];
-		mb[5] = mcp->mb[5];
 	}
 
 	if (rval != QLA_SUCCESS) {
@@ -2605,8 +2671,11 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *ha,
 		if (vp_idx == 0)
 			return;
 
-		if (MSB(rptid_entry->vp_idx) == 1)
+		if (MSB(rptid_entry->vp_idx) == 1) {
+			DEBUG2(printk("scsi(%ld): Could not acquire ID for "
+			    "VP[%d].\n", ha->host_no, vp_idx));
 			return;
+		}
 
 		list_for_each_entry(vha, &ha->vp_list, vp_list)
 			if (vp_idx == vha->vp_idx)
@@ -3270,3 +3339,157 @@ qla2x00_get_dcbx_params(scsi_qla_host_t *ha, dma_addr_t tlv_dma,
         return rval;
 }
  
+int
+qla2x00_loopback_test(scsi_qla_host_t *ha, struct msg_loopback *req,
+    uint16_t *ret_mb)
+{
+	int		rval;
+	mbx_cmd_t	mc;
+	mbx_cmd_t	*mcp = &mc;
+
+	DEBUG11(printk("%s(%ld): Options=%x iterations=%x MAILBOX_CNT=%d.\n",
+	     __func__, ha->host_no, req->Options, req->IterationCount,
+	     MAILBOX_REGISTER_COUNT));
+
+	memset(mcp->mb, 0 , sizeof(mcp->mb));
+
+	mcp->mb[0] = MBC_DIAGNOSTIC_LOOP_BACK;
+	mcp->mb[1] = req->options | BIT_6;
+	mcp->mb[10] = LSW(req->tx_cnt);
+	mcp->mb[11] = MSW(req->tx_cnt);
+	mcp->mb[14] = LSW(ha->loopback_buf.loopback_dma);
+	mcp->mb[15] = MSW(ha->loopback_buf.loopback_dma);
+	mcp->mb[20] = LSW(MSD(ha->loopback_buf.loopback_dma));
+	mcp->mb[21] = MSW(MSD(ha->loopback_buf.loopback_dma));
+	mcp->mb[16] = LSW(ha->loopback_buf.loopback_dma);
+	mcp->mb[17] = MSW(ha->loopback_buf.loopback_dma);
+	mcp->mb[6] = LSW(MSD(ha->loopback_buf.loopback_dma));
+	mcp->mb[7] = MSW(MSD(ha->loopback_buf.loopback_dma));
+	mcp->mb[18] = LSW(req->iter_cnt);
+	mcp->mb[19] = MSW(req->iter_cnt);
+	mcp->out_mb = MBX_21|MBX_20|MBX_19|MBX_18|MBX_17|MBX_16|MBX_15|
+	    MBX_14|MBX_13|MBX_12|MBX_11|MBX_10|MBX_7|MBX_6|MBX_1|MBX_0;
+	mcp->in_mb = MBX_19|MBX_18|MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->buf_size = req->tx_cnt;
+	mcp->flags = MBX_DMA_OUT|MBX_DMA_IN|IOCTL_CMD;
+	mcp->tov = MBX_TOV_SECONDS;
+	rval = qla2x00_mailbox_command(ha, mcp);
+
+	/* Always copy back return mailbox values. */
+	memcpy((void *)ret_mb, (void *)mcp->mb, sizeof(mcp->mb));
+
+	if (rval != QLA_SUCCESS) {
+		DEBUG3_11(printk("%s(%ld): mailbox command FAILED=%x.\n",
+		    __func__, ha->host_no, mcp->mb[0]));
+	} else {
+		DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
+	}
+
+	return rval;
+}
+
+int
+qla2x00_echo_test(scsi_qla_host_t *ha, struct msg_loopback *req,
+    uint16_t *ret_mb)
+{
+	int		rval;
+	mbx_cmd_t	mc;
+	mbx_cmd_t	*mcp = &mc;
+
+	memset(mcp->mb, 0 , sizeof(mcp->mb));
+
+	mcp->mb[0] = MBC_DIAGNOSTIC_ECHO;
+	mcp->mb[1] = BIT_6;
+	mcp->mb[10] = req->tx_cnt;
+	mcp->mb[14] = LSW(ha->loopback_buf.loopback_dma);
+	mcp->mb[15] = MSW(ha->loopback_buf.loopback_dma);
+	mcp->mb[20] = LSW(MSD(ha->loopback_buf.loopback_dma));
+	mcp->mb[21] = MSW(MSD(ha->loopback_buf.loopback_dma));
+	mcp->mb[16] = LSW(ha->loopback_buf.loopback_dma);
+	mcp->mb[17] = MSW(ha->loopback_buf.loopback_dma);
+	mcp->mb[6] = LSW(MSD(ha->loopback_buf.loopback_dma));
+	mcp->mb[7] = MSW(MSD(ha->loopback_buf.loopback_dma));
+	mcp->out_mb = MBX_21|MBX_20|MBX_17|MBX_16|MBX_15|MBX_14|MBX_10|
+	   MBX_7|MBX_6|MBX_2|MBX_1|MBX_0;
+	mcp->in_mb = MBX_1|MBX_0;
+	mcp->buf_size = req->tx_cnt;
+	mcp->flags = MBX_DMA_OUT|MBX_DMA_IN|IOCTL_CMD;
+	mcp->tov = MBX_TOV_SECONDS;
+	rval = qla2x00_mailbox_command(ha, mcp);
+
+	/* Always copy back return mailbox values. */
+	memcpy((void *)ret_mb, (void *)mcp->mb, sizeof(mcp->mb));
+
+	if (rval != QLA_SUCCESS) {
+		DEBUG3_11(printk("%s(%ld): mailbox command FAILED=%x.\n",
+		    __func__, ha->host_no, mcp->mb[0]));
+	} else {
+		DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
+	}
+
+	return rval;
+}
+
+
+int
+qla2x00_read_ram_word(scsi_qla_host_t *ha, uint32_t risc_addr, uint32_t *data)
+{
+	int rval;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+
+	if (!IS_FWI2_CAPABLE(ha))
+		return QLA_FUNCTION_FAILED;
+
+	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+
+	mcp->mb[0] = MBC_READ_RAM_EXTENDED;
+	mcp->mb[1] = LSW(risc_addr);
+	mcp->mb[8] = MSW(risc_addr);
+	mcp->out_mb = MBX_8|MBX_1|MBX_0;
+	mcp->in_mb = MBX_3|MBX_2|MBX_0;
+	mcp->tov = 30;
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(ha, mcp);
+	if (rval != QLA_SUCCESS) {
+		DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x.\n", __func__,
+		    ha->host_no, rval, mcp->mb[0]));
+	} else {
+		DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
+		*data = mcp->mb[3] << 16 | mcp->mb[2];
+	}
+
+	return rval;
+}
+
+	int
+qla2x00_write_ram_word(scsi_qla_host_t *ha, uint32_t risc_addr, uint32_t data)
+{
+	int rval;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+
+	if (!IS_FWI2_CAPABLE(ha))
+		return QLA_FUNCTION_FAILED;
+
+	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+
+	mcp->mb[0] = MBC_WRITE_RAM_WORD_EXTENDED;
+	mcp->mb[1] = LSW(risc_addr);
+	mcp->mb[2] = LSW(data);
+	mcp->mb[3] = MSW(data);
+	mcp->mb[8] = MSW(risc_addr);
+	mcp->out_mb = MBX_8|MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->in_mb = MBX_0;
+	mcp->tov = 30;
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(ha, mcp);
+	if (rval != QLA_SUCCESS) {
+		DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x.\n", __func__,
+		    ha->host_no, rval, mcp->mb[0]));
+	} else {
+		DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
+	}
+
+	return rval;
+}
diff --git a/drivers/scsi/qla2xxx/qla_nlnk.c b/drivers/scsi/qla2xxx/qla_nlnk.c
index 44fedfd..049b622 100644
--- a/drivers/scsi/qla2xxx/qla_nlnk.c
+++ b/drivers/scsi/qla2xxx/qla_nlnk.c
@@ -8,7 +8,6 @@
 #include "qla_def.h"
 #include <net/sock.h>
 #include <net/netlink.h>
-#include "qla_nlnk.h"
 
 static struct sock *ql_fc_nl_sock = NULL;
 static int ql_fc_nl_event(struct notifier_block *this,
@@ -20,6 +19,11 @@ static struct notifier_block ql_fc_nl_notifier = {
 
 static struct qlfc_aen_log aen_log;
 
+extern int qla2x00_echo_test(scsi_qla_host_t *, struct msg_loopback *,
+    uint16_t *);
+extern int qla2x00_loopback_test(scsi_qla_host_t *, struct msg_loopback *,
+    uint16_t *);
+
 /*
  * local functions
  */
@@ -41,8 +45,8 @@ static int qla84xx_update_fw(struct scsi_qla_host *ha, int rlen,
 
 	if (rlen < (sizeof(struct msg_update_fw) + upd_fw->len +
 		offsetof(struct qla_fc_msg, u))){
-		printk(KERN_ERR "%s(%lu): invalid len\n",
-			__func__, ha->host_no);
+		DEBUG16(printk(KERN_ERR "%s(%lu): invalid len\n",
+			__func__, ha->host_no));
 		return -EINVAL;
 	}
 
@@ -50,16 +54,16 @@ static int qla84xx_update_fw(struct scsi_qla_host *ha, int rlen,
 	if (!upd_fw->offset) {
 		if (qlfw->fw_buf || !upd_fw->fw_len ||
 			upd_fw->len > upd_fw->fw_len) {
-			printk(KERN_ERR "%s(%lu): invalid offset or fw_len\n",
-				__func__, ha->host_no);
+			DEBUG16(printk(KERN_ERR "%s(%lu): invalid offset"
+			    " or fw_len\n", __func__, ha->host_no));
 			return -EINVAL;
 		} else {
 			qlfw->fw_buf = dma_alloc_coherent(&ha->pdev->dev,
 						upd_fw->fw_len, &qlfw->fw_dma,
 						GFP_KERNEL);
 			if (qlfw->fw_buf == NULL) {
-				printk(KERN_ERR "%s: dma alloc failed%lu\n",
-					__func__, ha->host_no);
+				DEBUG2(printk(KERN_ERR "%s(%lu): dma alloc "
+				    "failed\n", __func__, ha->host_no));
 				return (-ENOMEM);
 			}
 			qlfw->len = upd_fw->fw_len;
@@ -67,16 +71,16 @@ static int qla84xx_update_fw(struct scsi_qla_host *ha, int rlen,
 		fw_ver = le32_to_cpu(*((uint32_t *)
 				((uint32_t *)upd_fw->fw_bytes + 2)));
 		if (!fw_ver) {
-			printk(KERN_ERR "%s(%lu): invalid fw revision 0x%x\n",
-				__func__, ha->host_no, fw_ver);
+			DEBUG16(printk(KERN_ERR "%s(%lu): invalid fw revision"
+			    " 0x%x\n", __func__, ha->host_no, fw_ver));
 			return -EINVAL;
 		}
 	} else {
 		/* make sure we have a buffer allocated */
 		if (!qlfw->fw_buf || upd_fw->fw_len != qlfw->len ||
 			((upd_fw->offset + upd_fw->len) > upd_fw->fw_len)){
-			printk(KERN_ERR "%s(%lu): invalid size of offset=0"
-				" expected\n", __func__, ha->host_no);
+			DEBUG16(printk(KERN_ERR "%s(%lu): invalid size of "
+			    "offset=0 expected\n", __func__, ha->host_no));
 			return -EINVAL;
 		}
 	}
@@ -89,8 +93,8 @@ static int qla84xx_update_fw(struct scsi_qla_host *ha, int rlen,
 	
 	mn = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &mn_dma);
 	if (mn == NULL) {
-		printk(KERN_ERR "%s: dma alloc for fw buffer failed%lu\n",
-			__func__, ha->host_no);
+		DEBUG2(printk(KERN_ERR "%s: dma alloc for fw buffer "
+		    "failed%lu\n", __func__, ha->host_no));
 		return -ENOMEM;
 	}
 
@@ -119,7 +123,8 @@ static int qla84xx_update_fw(struct scsi_qla_host *ha, int rlen,
 	ret = qla2x00_issue_iocb_timeout(ha, mn, mn_dma, 0, 120);
 
 	if (ret != QLA_SUCCESS) {
-		printk(KERN_ERR "%s(%lu): failed\n", __func__, ha->host_no);
+		DEBUG2(printk(KERN_ERR "%s(%lu): failed\n", __func__,
+		    ha->host_no));
 	}
 
 	qla_free_nlnk_dmabuf(ha);
@@ -143,8 +148,8 @@ qla84xx_mgmt_cmd(scsi_qla_host_t *ha, struct qla_fc_msg *cmd, int rlen,
 
 	mn = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &mn_dma);
 	if (mn == NULL) {
-		printk(KERN_ERR "%s: dma alloc for fw buffer failed%lu\n",
-			__FUNCTION__, ha->host_no);
+		DEBUG2(printk(KERN_ERR "%s: dma alloc for fw buffer "
+		    "failed%lu\n", __func__, ha->host_no));
 		return (-ENOMEM);
 	}
 
@@ -183,12 +188,13 @@ qla84xx_mgmt_cmd(scsi_qla_host_t *ha, struct qla_fc_msg *cmd, int rlen,
 		goto exit_mgmt0;
 	}
 
-	if ((len = ql84_mgmt->len) && ql84_mgmt->cmd != QLA84_MGMT_CHNG_CONFIG) {
+	if ((len = ql84_mgmt->len) &&
+	    ql84_mgmt->cmd != QLA84_MGMT_CHNG_CONFIG) {
 		mgmt_b = dma_alloc_coherent(&ha->pdev->dev, len,
 				&mgmt_dma, GFP_KERNEL);
 		if (mgmt_b == NULL) {
-			printk(KERN_ERR "%s: dma alloc mgmt_b failed%lu\n",
-				__func__, ha->host_no);
+			DEBUG2(printk(KERN_ERR "%s: dma alloc mgmt_b "
+			    "failed%lu\n", __func__, ha->host_no));
 			ret = -ENOMEM;
 			goto exit_mgmt0;
 		}
@@ -204,14 +210,17 @@ qla84xx_mgmt_cmd(scsi_qla_host_t *ha, struct qla_fc_msg *cmd, int rlen,
 	}
 
 	ret = qla2x00_issue_iocb(ha, mn, mn_dma, 0);
-	cmd->error = ret;
-
-	if ((ret != QLA_SUCCESS)||(ql84_mgmt->cmd == QLA84_MGMT_WRITE_MEM)||(ql84_mgmt->cmd == QLA84_MGMT_CHNG_CONFIG)) {
-		if (ret != QLA_SUCCESS) printk(KERN_ERR "%s(%lu): failed\n", __func__, ha->host_no);
+	cmd->error = ret; 
+	if ((ret != QLA_SUCCESS) || (ql84_mgmt->cmd == QLA84_MGMT_WRITE_MEM)
+	    ||(ql84_mgmt->cmd == QLA84_MGMT_CHNG_CONFIG)) {
+		if (ret != QLA_SUCCESS) 
+			DEBUG2(printk(KERN_ERR "%s(%lu): failed\n",
+			    __func__, ha->host_no));
 		ret = ql_fc_nl_rsp(pid, seq, type, cmd, rsp_hdr_len, NULL, 0);
 	} else if ((ql84_mgmt->cmd == QLA84_MGMT_READ_MEM)||
 			(ql84_mgmt->cmd == QLA84_MGMT_GET_INFO)) {
-		ret = ql_fc_nl_rsp(pid, seq, type, cmd, rsp_hdr_len, mgmt_b, len);
+		ret = ql_fc_nl_rsp(pid, seq, type, cmd, rsp_hdr_len, mgmt_b,
+		    len);
 	}
 
 	if (mgmt_b)
@@ -238,8 +247,8 @@ qla81xx_mgmt_cmd(scsi_qla_host_t *ha, struct qla_fc_msg *cmd, int rlen,
 
 	mgmt_b = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &mgmt_dma);
 	if (mgmt_b == NULL) {
-		printk(KERN_ERR "%s: dma alloc mgmt_b failed%lu\n",
-			__func__, ha->host_no);
+		DEBUG2(printk(KERN_ERR "%s: dma alloc mgmt_b failed%lu\n",
+			__func__, ha->host_no));
 		return -ENOMEM;
 	}
 
@@ -248,8 +257,8 @@ qla81xx_mgmt_cmd(scsi_qla_host_t *ha, struct qla_fc_msg *cmd, int rlen,
 		ret = qla81xx_get_xgmac_stats(ha, ql84_mgmt->len, mgmt_dma);
 		cmd->error = ret;
 		if (ret != QLA_SUCCESS) {
-			printk(KERN_ERR "%s(%lu): failed\n", __func__,
-			    ha->host_no);
+			DEBUG2(printk(KERN_ERR "%s(%lu): failed\n", __func__,
+			    ha->host_no));
 			ret = ql_fc_nl_rsp(pid, seq, type, cmd, rsp_hdr_len,
 			    NULL, 0);
 		} else
@@ -276,6 +285,241 @@ ql_fc_get_aen(scsi_qla_host_t *ha)
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 }
 
+static int ql_fc_loopback(struct scsi_qla_host *ha, struct sk_buff *skb,
+    struct nlmsghdr *nlh, struct qla_fc_msg *ql_cmd, int rcvlen)
+{
+	struct qla_loopback *qlloopback = NULL;
+	struct msg_loopback *loopback = NULL;
+	uint16_t ret_mb[MAILBOX_REGISTER_COUNT];
+	int ret = 0;
+	int rsp_hdr_len = offsetof(struct qla_fc_msg, u) +
+	    offsetof(struct msg_loopback, bytes);
+
+	if (test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) ||
+	    test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) ||
+	    test_bit(ISP_ABORT_RETRY, &ha->dpc_flags)) {
+		ql_cmd->error = -EBUSY;
+		goto cleanup;
+	}
+
+	if (ql_cmd->cmd != QLFC_LOOPBACK_CMD)
+		goto send_data;
+
+	loopback = &ql_cmd->u.utok.qla_loopback;
+
+	if (rcvlen - sizeof(struct scsi_nl_hdr) <
+	    (sizeof(struct msg_loopback) + loopback->len + rsp_hdr_len)) {
+		DEBUG16(printk(KERN_ERR "%s(%lu): invalid len\n",
+		    __func__, ha->host_no));
+
+		ql_cmd->error = -EINVAL;
+		goto cleanup;
+	}
+
+	qlloopback = &ha->loopback_buf;
+	if (!loopback->offset) {
+		if (qlloopback->loopback_buf || !loopback->total_len ||
+			loopback->len > loopback->total_len) {
+			DEBUG16(printk(KERN_ERR "%s(%lu): invalid offset"
+			    " or total_len\n", __func__, ha->host_no));
+
+			ql_cmd->error = -EINVAL;
+			goto cleanup;
+		} else {
+			qlloopback->loopback_buf =
+			    dma_alloc_coherent(&ha->pdev->dev,
+			    loopback->total_len, &qlloopback->loopback_dma,
+			    GFP_KERNEL);
+
+			if (qlloopback->loopback_buf == NULL) {
+				DEBUG2(printk(KERN_ERR "%s(%lu): dma alloc "
+				    "failed\n", __func__, ha->host_no));
+
+				ql_cmd->error = -ENOMEM;
+				goto cleanup;
+			}
+			qlloopback->len = loopback->total_len;
+		}
+	} else {
+		/* make sure we have a buffer allocated */
+		if (!qlloopback->loopback_buf ||
+		    loopback->total_len != qlloopback->len ||
+		    ((loopback->offset + loopback->len) >
+		    loopback->total_len)) {
+			DEBUG16(printk(KERN_ERR "%s(%lu): invalid size of "
+			    "offset=0 expected\n", __func__, ha->host_no));
+
+			ql_cmd->error = -EINVAL;
+			goto cleanup;
+		}
+	}
+
+	/* Copy the data into DMA Buffer */
+	memcpy(((uint8_t *)qlloopback->loopback_buf + loopback->offset),
+	    loopback->bytes, loopback->len);
+
+	if ((loopback->offset + loopback->len) != qlloopback->len) {
+		ql_cmd->error = 0;
+		return ql_fc_nl_rsp(NETLINK_CREDS(skb)->pid,
+		    nlh->nlmsg_seq, (uint32_t)nlh->nlmsg_type,
+		    ql_cmd, rsp_hdr_len, NULL, 0);
+	}
+
+	if (ha->current_topology == ISP_CFG_F) {
+		if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
+			ql_cmd->error = -EINVAL;
+			goto cleanup;
+		}
+
+		ret = qla2x00_echo_test(ha, loopback, ret_mb);
+		loopback->cmd_sent = INT_DEF_LB_ECHO_CMD;
+	} else {
+		ret = qla2x00_loopback_test(ha, loopback, ret_mb);
+		loopback->cmd_sent = INT_DEF_LB_LOOPBACK_CMD;
+
+		 if (IS_QLA81XX(ha)) {
+			if (ret_mb[0] == MBS_COMMAND_ERROR &&
+			    ret_mb[1] == QLA_RESET_FC_LB_FAILED) {
+				DEBUG2(printk(KERN_ERR "%s(%ld): ABORTing "
+				    "ISP\n", __func__, ha->host_no));
+				set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+				qla2xxx_wake_dpc(ha);
+			}
+		}
+	}
+
+	ql_cmd->error = 0;
+	if (ret != QLA_SUCCESS) {
+		DEBUG2(printk(KERN_ERR "%s(%lu): failed\n", __func__,
+		    ha->host_no));
+	}
+
+	loopback->comp_stat = ret_mb[0];
+
+	if ((loopback->comp_stat == MBS_COMMAND_COMPLETE) ||
+	    (loopback->comp_stat == MBS_DIAG_ECHO_TEST_ERROR)) {
+		loopback->crc_err_cnt = ret_mb[1];
+		loopback->disparity_err_cnt = ret_mb[2];
+		loopback->frame_len_err_cnt = ret_mb[3];
+		loopback->iter_cnt_last_err = (ret_mb[19] << 16) | ret_mb[18];
+	}
+
+	return ql_fc_nl_rsp(NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq,
+	    (uint32_t)nlh->nlmsg_type, ql_cmd, rsp_hdr_len, NULL, 0);
+
+send_data:
+	if (ql_cmd->cmd != QLFC_LOOPBACK_DATA) {
+		DEBUG16(printk(KERN_ERR "%s(%lu): invalid command\n",
+		__func__, ha->host_no));
+
+		ql_cmd->error = -EINVAL;
+		goto cleanup;
+	}
+
+	loopback = &ql_cmd->u.ktou.qla_loopback;
+	qlloopback = &ha->loopback_buf;
+
+	if ((loopback->offset + loopback->len) > qlloopback->len) {
+		ql_cmd->error = -EINVAL;
+		goto cleanup;
+	}
+
+	ql_cmd->error = 0;
+	ret = ql_fc_nl_rsp(NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq,
+	    (uint32_t)nlh->nlmsg_type, ql_cmd, rsp_hdr_len,
+	    ((uint8_t *)qlloopback->loopback_buf + loopback->offset),
+	    loopback->len);
+
+	if ((loopback->offset + loopback->len) == qlloopback->len) {
+cleanup:
+		if (qlloopback && qlloopback->loopback_buf) {
+			dma_free_coherent(&ha->pdev->dev, qlloopback->len,
+			    qlloopback->loopback_buf,
+			    qlloopback->loopback_dma);
+			qlloopback->loopback_buf = NULL;
+		}
+	}
+
+	if (ql_cmd->error)
+		ret = ql_fc_nl_rsp(NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq,
+		    (uint32_t)nlh->nlmsg_type, ql_cmd, rsp_hdr_len, NULL, 0);
+	return ret;
+}
+
+static int ql_fc_iidma(struct scsi_qla_host *ha, struct sk_buff *skb,
+    struct nlmsghdr *nlh, struct qla_fc_msg *ql_cmd, int rcvlen)
+{
+	struct qla_port_param *port_param = NULL;
+	fc_port_t *fcport = NULL;
+	uint16_t mb[MAILBOX_REGISTER_COUNT];
+	int ret = 0;
+	int rsp_hdr_len = offsetof(struct qla_fc_msg, u) +
+	    sizeof(struct qla_port_param);
+
+	if (test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) ||
+	    test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) ||
+	    test_bit(ISP_ABORT_RETRY, &ha->dpc_flags)) {
+		ql_cmd->error = -EBUSY;
+		goto cleanup;
+	}
+
+	if ((rcvlen - sizeof(struct scsi_nl_hdr)) <
+	    (sizeof(struct qla_port_param))) {
+		DEBUG16(printk(KERN_ERR "%s(%lu): invalid len\n",
+		    __func__, ha->host_no));
+		ql_cmd->error = -EINVAL;
+		goto cleanup;
+	}
+
+	if (!IS_IIDMA_CAPABLE(ha)) {
+		DEBUG16(printk(KERN_ERR "%s(%lu): iiDMA not supported\n",
+		    __func__, ha->host_no));
+		ql_cmd->error = -EINVAL;
+		goto cleanup;
+	}
+
+	port_param = &ql_cmd->u.port_param;
+
+	if (port_param->fc_scsi_addr.dest_type != EXT_DEF_TYPE_WWPN) {
+		DEBUG16(printk(KERN_ERR "%s(%ld): Invalid destination type\n",
+		    __func__, ha->host_no));
+		ql_cmd->error = -EINVAL;
+		goto cleanup;
+	}
+
+	fcport = qla2x00_find_port(ha, port_param->fc_scsi_addr.dest_addr.wwpn);
+	if (!fcport) {
+		DEBUG16(printk(KERN_ERR "%s(%ld): Failed to find port\n",
+		    __func__, ha->host_no));
+		ql_cmd->error = -EINVAL;
+		goto cleanup;
+	}
+
+	if (port_param->mode)
+		ret = qla2x00_set_idma_speed(ha, fcport->loop_id,
+		    port_param->speed, mb);
+	else
+		ret = qla2x00_get_idma_speed(ha, fcport->loop_id,
+		    &port_param->speed, mb);
+
+	if (ret != QLA_SUCCESS) {
+		DEBUG16(printk(KERN_ERR "scsi(%ld): iIDMA cmd failed for "
+		    "%02x%02x%02x%02x%02x%02x%02x%02x -- %04x %x %04x %04x.\n",
+		    ha->host_no, fcport->port_name[0], fcport->port_name[1],
+		    fcport->port_name[2], fcport->port_name[3],
+		    fcport->port_name[4], fcport->port_name[5],
+		    fcport->port_name[6], fcport->port_name[7], ret,
+		    fcport->fp_speed, mb[0], mb[1]));
+		ql_cmd->error = -EINVAL;
+		goto cleanup;
+	}
+
+	ql_cmd->error = 0;
+cleanup:
+	return ql_fc_nl_rsp(NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq,
+	    (uint32_t)nlh->nlmsg_type, ql_cmd, rsp_hdr_len, NULL, 0);
+}
+
 /*
  * Netlink Interface Related Functions
  */
@@ -306,21 +550,21 @@ ql_fc_nl_rcv_msg(struct sk_buff *skb)
 
 		if ((nlh->nlmsg_len < (sizeof(*nlh) + sizeof(*snlh))) ||
 		    (skb->len < nlh->nlmsg_len)) {
-			printk(KERN_WARNING "%s: discarding partial skb\n",
-			       __FUNCTION__);
+			DEBUG16(printk(KERN_WARNING "%s: discarding partial "
+			    "skb\n", __func__));
 			break;
 		}
 
 		rlen = NLMSG_ALIGN(nlh->nlmsg_len);
 		if (rlen > skb->len) {
-			printk(KERN_WARNING "%s: rlen > skb->len\n",
-				 __FUNCTION__);
+			DEBUG16(printk(KERN_WARNING "%s: rlen > skb->len\n",
+				 __func__));
 			rlen = skb->len;
 		}
 
 		if (nlh->nlmsg_type != FC_TRANSPORT_MSG) {
-			printk(KERN_WARNING "%s: Not FC_TRANSPORT_MSG\n",
-			       __FUNCTION__);
+			DEBUG16(printk(KERN_WARNING "%s: Not FC_TRANSPORT_MSG\n"
+			    , __func__));
 			err = -EBADMSG;
 			goto next_msg;
 		}
@@ -328,8 +572,8 @@ ql_fc_nl_rcv_msg(struct sk_buff *skb)
 		snlh = NLMSG_DATA(nlh);
 		if ((snlh->version != SCSI_NL_VERSION) ||
 		    (snlh->magic != SCSI_NL_MAGIC)) {
-			printk(KERN_WARNING "%s: Bad Version or Magic number\n",
-			       __FUNCTION__);
+			DEBUG16(printk(KERN_WARNING "%s: Bad Version or Magic"
+			    " number\n", __func__));
 			err = -EPROTOTYPE;
 			goto next_msg;
 		}
@@ -364,8 +608,8 @@ ql_fc_proc_nl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int rcvlen)
 
 	shost = scsi_host_lookup(ql_cmd->host_no);
 	if (IS_ERR(shost)) {
-		printk(KERN_ERR "%s: could not find host no %u\n", __func__,
-			ql_cmd->host_no);
+		DEBUG16(printk(KERN_ERR "%s: could not find host no %u\n",
+		    __func__, ql_cmd->host_no));
 		err = -ENODEV;
 		goto exit_proc_nl_rcv_msg;
 	}
@@ -373,19 +617,26 @@ ql_fc_proc_nl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int rcvlen)
 	ha = (struct scsi_qla_host *)shost->hostdata;
 
 	if (!ha) {
-		printk(KERN_ERR "%s: found invalid host.\n", __func__);
+		DEBUG16(printk(KERN_ERR "%s: found invalid host.\n", __func__));
 		err = -ENODEV;
 		goto exit_proc_nl_rcv_msg;
 	}
 
-	/* Allow AEN command for all HBAs */
-	if (ql_cmd->cmd == QLFC_GET_AEN) {
+	switch (ql_cmd->cmd) {
+	case QLFC_GET_AEN:
 		rsp_hdr_len = offsetof(struct qla_fc_msg, u);
 		ql_cmd->error = 0;
 		ql_fc_get_aen(ha);
 		return ql_fc_nl_rsp(NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq,
 			(uint32_t)nlh->nlmsg_type, ql_cmd, rsp_hdr_len,
 			&aen_log, sizeof(struct qlfc_aen_log));
+
+	case QLFC_LOOPBACK_CMD:
+	case QLFC_LOOPBACK_DATA:
+		return ql_fc_loopback(ha, skb, nlh, ql_cmd, rcvlen);
+
+	case QLFC_IIDMA:
+		return ql_fc_iidma(ha, skb, nlh, ql_cmd, rcvlen);
 	}
 
 	/* Use existing 84xx interface to get MPI XGMAC statistics for
@@ -393,8 +644,8 @@ ql_fc_proc_nl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int rcvlen)
 	 */
 	if ((!IS_QLA81XX(ha) && !IS_QLA84XX(ha)) ||
 	    (IS_QLA81XX(ha) && (ql_cmd->cmd != QLA84_MGMT_CMD))) {
-		printk(KERN_ERR "%s: invalid host ha = %p dtype = 0x%x\n",
-			__func__, ha, (ha ? DT_MASK(ha): ~0));
+		DEBUG16(printk(KERN_ERR "%s: invalid host ha = %p"
+		    "dtype = 0x%x\n", __func__, ha, (ha ? DT_MASK(ha): ~0)));
 		err = -ENODEV;
 		goto exit_proc_nl_rcv_msg;
 	}
@@ -445,7 +696,8 @@ exit_proc_nl_rcv_msg:
 static int
 ql_fc_nl_event(struct notifier_block *this, unsigned long event, void *ptr)
 {
-	DEBUG16(printk(KERN_WARNING "%s: event 0x%lx ptr = %p\n", __func__, event, ptr));
+	DEBUG16(printk(KERN_WARNING "%s: event 0x%lx ptr = %p\n",
+	    __func__, event, ptr));
 	return NOTIFY_DONE;
 }
 
@@ -460,7 +712,7 @@ ql_fc_nl_rsp(uint32_t pid, uint32_t seq, uint32_t type, void *hdr, int hdr_len,
 	
 	skb = alloc_skb(len, GFP_ATOMIC);
 	if (!skb) {
-		printk(KERN_ERR "%s: Could not alloc skb\n", __func__);
+		DEBUG2(printk(KERN_ERR "%s: Could not alloc skb\n", __func__));
 		return -ENOMEM;
 	}
 	nlh = __nlmsg_put(skb, pid, seq, type, (len - sizeof(*nlh)), 0);
@@ -472,7 +724,8 @@ ql_fc_nl_rsp(uint32_t pid, uint32_t seq, uint32_t type, void *hdr, int hdr_len,
 	
 	rc = netlink_unicast(ql_fc_nl_sock, skb, pid, MSG_DONTWAIT);
 	if (rc < 0) {
-		printk(KERN_ERR "%s: netlink_unicast failed\n", __func__);
+		DEBUG16(printk(KERN_ERR "%s: netlink_unicast failed\n",
+		    __func__));
 		return rc;
 	}
 	return 0;
diff --git a/drivers/scsi/qla2xxx/qla_nlnk.h b/drivers/scsi/qla2xxx/qla_nlnk.h
index 91ff73f..b813514 100644
--- a/drivers/scsi/qla2xxx/qla_nlnk.h
+++ b/drivers/scsi/qla2xxx/qla_nlnk.h
@@ -8,21 +8,60 @@
 #define _QLA_NLNK_H_
 
 #ifndef NETLINK_FCTRANSPORT
-#define NETLINK_FCTRANSPORT 20
+#define NETLINK_FCTRANSPORT	20
 #endif
 #define QL_FC_NL_GROUP_CNT	0
 
-#define FC_TRANSPORT_MSG		NLMSG_MIN_TYPE + 1
+#define NLMSG_MIN_TYPE		0x10	/* 0x10: reserved control messages */
+#define FC_TRANSPORT_MSG	NLMSG_MIN_TYPE + 1
+
+#define SCSI_NL_VERSION		1
+#define SCSI_NL_MAGIC		0xA1B2
 
 /* 
  * Transport Message Types
  */
 #define FC_NL_VNDR_SPECIFIC	0x8000
 
+#ifndef SOL_NETLINK
+#define SOL_NETLINK    270
+#endif
+
+#ifndef        FCH_EVT_LIP
+#define        FCH_EVT_LIP             0x1
+#endif
+
+#ifndef        FCH_EVT_LINKUP
+#define        FCH_EVT_LINKUP          0x2
+#endif
+
+#ifndef        FCH_EVT_LINKDOWN
+#define        FCH_EVT_LINKDOWN        0x3
+#endif
+
+#ifndef        FCH_EVT_LIPRESET
+#define        FCH_EVT_LIPRESET        0x4
+#endif
+
+#ifndef        FCH_EVT_RSCN
+#define        FCH_EVT_RSCN            0x5
+#endif
+
+
 /*
  * Structures
  */
 
+#ifndef SCSI_NETLINK_H
+struct scsi_nl_hdr {
+        uint8_t version;
+        uint8_t transport;
+        uint16_t magic;
+        uint16_t msgtype;
+        uint16_t msglen;
+} __attribute__((aligned(sizeof(uint64_t))));
+#endif
+
 struct qla84_mgmt_param {
 	union {
 		struct {
@@ -129,6 +168,62 @@ struct msg_update_fw {
 	uint8_t fw_bytes[0];
 };
 
+struct msg_loopback {
+	uint16_t options;
+	uint32_t tx_cnt;
+	uint32_t iter_cnt;
+	uint64_t tx_buf_address;
+	uint32_t tx_buf_len;
+	uint16_t reserved1[9];
+
+	uint64_t rx_buf_address;
+        uint32_t rx_buf_len;
+        uint16_t comp_stat;
+        uint16_t crc_err_cnt;
+        uint16_t disparity_err_cnt;
+        uint16_t frame_len_err_cnt;
+        uint32_t iter_cnt_last_err;
+        uint8_t  cmd_sent;
+        uint8_t  reserved;
+        uint16_t reserved2[7];
+
+	/*
+	 * offset, len, total_len are present to overcome the current limitation
+	 * of 128Kb xfer size. The data is sent in smaller chunks. Each chunk
+	 * specifies the byte "offset" where it fits in the data buffer. The
+	 * number of bytes in each chunk is specified in "len". "total_len"
+	 * is the total size of data. The first chunk should start at offset = 0.
+	 * When offset+len == total_len, the data is written.
+	 */
+	uint32_t offset;/* start offset */
+	uint32_t len;	/* num bytes in cur xfer */
+	uint32_t total_len; /* size of data in bytes */
+	uint8_t bytes[0];
+} __attribute__ ((packed));
+
+struct qla_scsi_addr {
+	uint16_t bus;
+	uint16_t target;
+} __attribute__ ((packed));
+
+struct qla_ext_dest_addr {
+	union {
+		uint8_t wwnn[8];
+		uint8_t wwpn[8];
+		uint8_t id[4];
+		struct qla_scsi_addr scsi_addr;
+	} dest_addr;
+	uint16_t dest_type;
+	uint16_t lun;
+	uint16_t padding[2];
+} __attribute__ ((packed));
+
+struct qla_port_param {
+	struct qla_ext_dest_addr fc_scsi_addr;
+	uint16_t mode;
+	uint16_t speed;
+} __attribute__ ((packed));
+
 struct qla_fc_msg {
 
 	uint64_t magic;
@@ -137,10 +232,13 @@ struct qla_fc_msg {
 	uint16_t vmsg_datalen;
 
 	uint32_t cmd;
-#define QLA84_RESET	0x01
-#define QLA84_UPDATE_FW	0x02
-#define QLA84_MGMT_CMD	0x03
-#define QLFC_GET_AEN	0x04
+#define QLA84_RESET		0x01
+#define QLA84_UPDATE_FW		0x02
+#define QLA84_MGMT_CMD		0x03
+#define QLFC_GET_AEN		0x04
+#define QLFC_LOOPBACK_CMD	0x05
+#define QLFC_LOOPBACK_DATA	0x06
+#define QLFC_IIDMA		0x07
 
 	uint32_t error; /* interface or resource error holder*/
 
@@ -156,12 +254,16 @@ struct qla_fc_msg {
 
 			struct msg_update_fw qla84_update_fw;
 			struct qla84_msg_mgmt mgmt;
+			struct msg_loopback qla_loopback;
 		} utok;
 	
 		union {
 			struct qla84_msg_mgmt mgmt;
 			struct qlfc_aen_log aen_log;
+			struct msg_loopback qla_loopback;
 		} ktou;
+
+		struct qla_port_param port_param;
 	} u;
 } __attribute__ ((aligned (sizeof(uint64_t))));
 	
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 519ac68..8175167 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -90,6 +90,14 @@ module_param(ql2xmaxqdepth, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(ql2xmaxqdepth,
 		"Maximum queue depth to report for target devices.");
 
+int ql2xqfulltracking = 1;
+module_param(ql2xqfulltracking, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(ql2xqfulltracking,
+               "Controls whether the driver tracks queue full status "
+               "returns and dynamically adjusts a scsi device's queue "
+               "depth.  Default is 1, perform tracking.  Set to 0 to "
+               "disable dynamic tracking and adjustment of queue depth.");
+
 int ql2xqfullrampup = 120;
 module_param(ql2xqfullrampup, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(ql2xqfullrampup,
@@ -397,8 +405,11 @@ qla2x00_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 	srb_t *sp;
 	int rval;
 
-	if (unlikely(pci_channel_offline(ha->pdev))) {
-		cmd->result = DID_REQUEUE << 16;
+	if (ha->flags.eeh_busy) {
+		if (ha->flags.pci_channel_io_perm_failure)
+			cmd->result = DID_NO_CONNECT << 16;
+		else
+			cmd->result = DID_REQUEUE << 16;
 		goto qc_fail_command;
 	}
 
@@ -464,11 +475,15 @@ qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 	srb_t *sp;
 	int rval;
 
-	if (unlikely(pci_channel_offline(ha->pdev))) {
-		cmd->result = DID_REQUEUE << 16;
+	if (ha->flags.eeh_busy) {
+		if (ha->flags.pci_channel_io_perm_failure)
+			cmd->result = DID_NO_CONNECT << 16;
+		else
+			cmd->result = DID_REQUEUE << 16;
 		goto qc24_fail_command;
 	}
 
+
 	rval = fc_remote_port_chkready(rport);
 	if (rval) {
 		cmd->result = rval;
@@ -544,6 +559,11 @@ qla2x00_eh_wait_on_command(scsi_qla_host_t *ha, struct scsi_cmnd *cmd)
 	unsigned long wait_iter = ABORT_WAIT_ITER;
 	int ret = QLA_SUCCESS;
 
+	if (unlikely(pci_channel_offline(ha->pdev)) || ha->flags.eeh_busy) {
+		qla_printk(KERN_WARNING, ha, "return:eh_wait\n");
+		return ret;
+	}
+
 	while (CMD_SP(cmd)) {
 		msleep(ABORT_POLLING_PERIOD);
 
@@ -828,7 +848,8 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
 *    ha - pointer to scsi_qla_host structure.
 *    t  - target
 * Returns:
-*    Either SUCCESS or FAILED.
+*     0 - SUCCESS 
+*     1 - FAILED.
 *
 * Note:
 **************************************************************************/
@@ -855,7 +876,8 @@ qla2x00_eh_wait_for_pending_target_commands(scsi_qla_host_t *ha, unsigned int t)
 			cmd = sp->cmd;
 			spin_unlock_irqrestore(&pha->hardware_lock, flags);
 			if (cmd->device->id == t) {
-				if (!qla2x00_eh_wait_on_command(ha, cmd)) {
+				if (qla2x00_eh_wait_on_command(ha, cmd) !=
+				    QLA_SUCCESS) {
 					status = 1;
 					break;
 				}
@@ -991,9 +1013,11 @@ qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *ha)
 		if (sp) {
 			cmd = sp->cmd;
 			spin_unlock_irqrestore(&ha->hardware_lock, flags);
-			status = qla2x00_eh_wait_on_command(ha, cmd);
-			if (status == 0)
+			if (qla2x00_eh_wait_on_command(ha, cmd) !=
+			    QLA_SUCCESS) {
+				status = 0;
 				break;
+			}
 		}
 		else {
 			spin_unlock_irqrestore(&ha->hardware_lock, flags);
@@ -1201,6 +1225,27 @@ qla2x00_loop_reset(scsi_qla_host_t *ha)
 	return QLA_SUCCESS;
 }
 
+void
+qla2x00_abort_all_cmds(scsi_qla_host_t *ha, int res)
+{
+	int cnt;
+	unsigned long flags;
+	srb_t *sp;
+
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+	for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
+		sp = ha->outstanding_cmds[cnt];
+		if (sp) {
+			ha->outstanding_cmds[cnt] = NULL;
+			sp->flags = 0;
+			sp->cmd->result = res;
+			sp->cmd->host_scribble = (unsigned char *)NULL;
+			qla2x00_sp_compl(ha, sp);
+		}
+	}
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
 /*
  * qla2x00_device_reset
  *	Issue bus device reset message to the target.
@@ -1759,6 +1804,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 	    ha->iobase);
 
 	spin_lock_init(&ha->hardware_lock);
+	spin_lock_init(&ha->work_lock);
 
 	ha->prev_topology = 0;
 	ha->init_cb_size = sizeof(init_cb_t);
@@ -1922,6 +1968,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 	if (ret)
 		goto probe_failed;
 
+	pci_save_state(ha->pdev);
+
 	/* Initialized the timer */
 	qla2x00_start_timer(ha, qla2x00_timer, WATCH_INTERVAL);
 
@@ -2011,6 +2059,7 @@ qla2x00_remove_one(struct pci_dev *pdev)
 	scsi_qla_host_t *vhatmp;
 
 	ha = pci_get_drvdata(pdev);
+	set_bit(UNLOADING, &ha->dpc_flags);
 
 	if (!list_empty(&ha->vp_list)) {
 		/* release VP resources */
@@ -2042,6 +2091,8 @@ qla2x00_remove_one(struct pci_dev *pdev)
 		}
 	}
 
+	set_bit(UNLOADING, &ha->dpc_flags);
+
 	/* Disable timer */
 	if (ha->timer_active)
 		qla2x00_stop_timer(ha);
@@ -2081,6 +2132,8 @@ qla2x00_remove_one(struct pci_dev *pdev)
 static void
 qla2x00_free_device(scsi_qla_host_t *ha)
 {
+	qla2x00_abort_all_cmds(ha, DID_NO_CONNECT << 16);
+
 	/* Disable timer */
 	if (ha->timer_active)
 		qla2x00_stop_timer(ha);
@@ -2644,13 +2697,11 @@ qla2x00_free_sp_pool( scsi_qla_host_t *ha)
 }
 
 static struct qla_work_evt *
-qla2x00_alloc_work(struct scsi_qla_host *ha, enum qla_work_type type,
-    int locked)
+qla2x00_alloc_work(struct scsi_qla_host *ha, enum qla_work_type type)
 {
        struct qla_work_evt *e;
 
-       e = kzalloc(sizeof(struct qla_work_evt), locked ? GFP_ATOMIC:
-           GFP_KERNEL);
+       e = kzalloc(sizeof(struct qla_work_evt), GFP_ATOMIC);
        if (!e)
                return NULL;
 
@@ -2661,16 +2712,14 @@ qla2x00_alloc_work(struct scsi_qla_host *ha, enum qla_work_type type,
 }
 
 static int
-qla2x00_post_work(struct scsi_qla_host *ha, struct qla_work_evt *e, int locked)
+qla2x00_post_work(struct scsi_qla_host *ha, struct qla_work_evt *e)
 {
 	unsigned long flags = 0;
 
-	if (!locked)
-		spin_lock_irqsave(&ha->hardware_lock, flags);
+	spin_lock_irqsave(&ha->work_lock, flags);
 	list_add_tail(&e->list, &ha->work_list);
 	qla2xxx_wake_dpc(ha);
-	if (!locked)
-		spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	spin_unlock_irqrestore(&ha->work_lock, flags);
 	return QLA_SUCCESS;
 }
 
@@ -2679,24 +2728,27 @@ qla2x00_post_idc_ack_work(struct scsi_qla_host *ha, uint16_t *mb)
 {
 	struct qla_work_evt *e;
 
-	e = qla2x00_alloc_work(ha, QLA_EVT_IDC_ACK, 1);
+	e = qla2x00_alloc_work(ha, QLA_EVT_IDC_ACK);
 	if (!e)
 		return QLA_FUNCTION_FAILED;
 
 	memcpy(e->u.idc_ack.mb, mb, QLA_IDC_ACK_REGS * sizeof(uint16_t));
-	return qla2x00_post_work(ha, e, 1);
+	return qla2x00_post_work(ha, e);
 }
 
 static void
 qla2x00_do_work(struct scsi_qla_host *ha)
 {
-	struct qla_work_evt *e;
+	struct qla_work_evt *e, *tmp;
+	unsigned long flags;
+	LIST_HEAD(work);
 
-	spin_lock_irq(&ha->hardware_lock);
-	while (!list_empty(&ha->work_list)) {
-		e = list_entry(ha->work_list.next, struct qla_work_evt, list);
+	spin_lock_irqsave(&ha->work_lock, flags);
+	list_splice_init(&ha->work_list, &work);
+	spin_unlock_irqrestore(&ha->work_lock, flags);
+
+	list_for_each_entry_safe(e, tmp, &work, list) {
 		list_del_init(&e->list);
-		spin_unlock_irq(&ha->hardware_lock);
 
 		switch (e->type) {
 			case QLA_EVT_IDC_ACK:
@@ -2705,9 +2757,7 @@ qla2x00_do_work(struct scsi_qla_host *ha)
 		}
 		if (e->flags & QLA_EVT_FLAG_FREE)
 			kfree(e);
-		spin_lock_irq(&ha->hardware_lock);
 	}
-	spin_unlock_irq(&ha->hardware_lock);
 }
 
 
@@ -2750,6 +2800,12 @@ qla2x00_do_dpc(void *data)
 		if (!ha->flags.init_done)
 			continue;
 
+		if (ha->flags.eeh_busy) {
+			DEBUG17(qla_printk(KERN_WARNING, ha,
+			"qla2x00_do_dpc: dpc_flags: %lx\n", ha->dpc_flags));
+			continue;
+		}
+
 		DEBUG3(printk("scsi(%ld): DPC handler\n", ha->host_no));
 
 		ha->dpc_active = 1;
@@ -2931,8 +2987,10 @@ qla2x00_do_dpc(void *data)
 void
 qla2xxx_wake_dpc(scsi_qla_host_t *ha)
 {
-	if (ha->dpc_thread)
-		wake_up_process(ha->dpc_thread);
+        struct task_struct *t = ha->dpc_thread;
+
+        if (!test_bit(UNLOADING, &ha->dpc_flags) && t)
+                wake_up_process(t);
 }
 
 /*
@@ -3009,6 +3067,11 @@ qla2x00_timer(scsi_qla_host_t *ha)
 	int		index;
 	srb_t		*sp;
 	int		t;
+	uint16_t	w;
+
+	/* Hardware read to raise pending EEH errors during mailbox waits. */
+	if (!pci_channel_offline(pha->pdev))
+		pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w);
 
 	/*
 	 * Ports - Port down timer.
@@ -3176,14 +3239,19 @@ qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
 {
 	scsi_qla_host_t *ha = pci_get_drvdata(pdev);
 
+	qla_printk(KERN_WARNING, ha, "error_detected:state %x\n", state);
+
 	switch (state) {
 	case pci_channel_io_normal:
+		ha->flags.eeh_busy = 0;
 		return PCI_ERS_RESULT_CAN_RECOVER;
 	case pci_channel_io_frozen:
+		ha->flags.eeh_busy = 1;
 		pci_disable_device(pdev);
 		return PCI_ERS_RESULT_NEED_RESET;
 	case pci_channel_io_perm_failure:
 		ha->flags.pci_channel_io_perm_failure = 1;
+		qla2x00_abort_all_cmds(ha, DID_NO_CONNECT << 16);
 		return PCI_ERS_RESULT_DISCONNECT;
 	}
 	return PCI_ERS_RESULT_NEED_RESET;
@@ -3230,7 +3298,25 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev)
 {
 	pci_ers_result_t ret = PCI_ERS_RESULT_DISCONNECT;
 	scsi_qla_host_t *ha = pci_get_drvdata(pdev);
-	int rc;
+	int rc, retries = 10;
+
+	qla_printk(KERN_WARNING, ha, "slot_reset\n");
+
+	pci_restore_state(pdev);
+
+#ifdef QL_DEBUG_LEVEL_17
+	{
+		uint8_t b;
+		uint32_t i;
+
+		printk("slot_reset_0: ");
+		for (i = 0; i < 256; i++) {
+			pci_read_config_byte(ha->pdev, i, &b);
+			printk("%s%02x", (i%16) ? " " : "\n", b);
+		}
+		printk("\n");
+	}
+#endif
 
 	rc = pci_enable_device(pdev);
 
@@ -3240,16 +3326,34 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev)
 
 		return ret;
 	}
-	pci_set_master(pdev);
 
 	if (ha->isp_ops->pci_config(ha))
 		return ret;
 
+	while (ha->flags.mbox_busy && retries--)
+		msleep(1000);
+
+#ifdef QL_DEBUG_LEVEL_17
+	{
+		uint8_t b;
+		uint32_t i;
+
+		printk("slot_reset_1: ");
+		for (i = 0; i < 256; i++) {
+			pci_read_config_byte(ha->pdev, i, &b);
+			printk("%s%02x", (i%16) ? " " : "\n", b);
+		}
+		printk("\n");
+	}
+#endif
+
 	set_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
 	if (qla2x00_abort_isp(ha)== QLA_SUCCESS)
 		ret =  PCI_ERS_RESULT_RECOVERED;
 	clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
 
+	qla_printk(KERN_WARNING, ha, "slot_reset-return:ret=%x\n",ret);
+
 	return ret;
 }
 
@@ -3259,12 +3363,16 @@ qla2xxx_pci_resume(struct pci_dev *pdev)
 	scsi_qla_host_t *ha = pci_get_drvdata(pdev);
 	int ret;
 
+	qla_printk(KERN_WARNING, ha, "pci_resume\n");
+
 	ret = qla2x00_wait_for_hba_online(ha);
 	if (ret != QLA_SUCCESS) {
 		qla_printk(KERN_ERR, ha,
 		    "the device failed to resume I/O "
 		    "from slot/link_reset");
 	}
+
+	ha->flags.eeh_busy = 0;
 }
 
 static struct pci_error_handlers qla2xxx_err_handler = {
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index edf6dce..7cdcbe4 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,9 +7,9 @@
 /*
  * Driver version
  */
-#define QLA2XXX_VERSION      "8.03.00.04.05.04-k"
+#define QLA2XXX_VERSION      "8.03.00.08.05.04-k"
 
 #define QLA_DRIVER_MAJOR_VER	8
 #define QLA_DRIVER_MINOR_VER	3
 #define QLA_DRIVER_PATCH_VER	0
-#define QLA_DRIVER_BETA_VER	4
+#define QLA_DRIVER_BETA_VER	8