Sophie

Sophie

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

kernel-2.6.18-194.11.1.el5.src.rpm

From: Marcus Barrow <mbarrow@redhat.com>
Date: Thu, 9 Apr 2009 14:07:19 -0400
Subject: [scsi] qla2xxx : updates and fixes from upstream, part 2
Message-id: 20090409180719.3930.80533.sendpatchset@file.bos.redhat.com
O-Subject: [rhel 5.4 patch] qla2xxx : updates and fixes from upstream, part 2
Bugzilla: 495092
RH-Acked-by: Pete Zaitcev <zaitcev@redhat.com>
RH-Acked-by: Tomas Henzl <thenzl@redhat.com>

BZ 495092 - qla2xxx - updates and fixes from upstream, part 2

This group of patches if the first part of update for rhel 5.4
found during QLogic and partner testing. These patches apply
and build cleanly to 2.6.18-137.

These changes, where appropriate have been pushed upstream or
are queued for upstream.

They have been tested by QLogic and partners.

 - Added abort_target for 81xx
 - Firmware load sequence for 81xx
 - Do not restrict flash read to 4K alignment
 - Extend address range of option-rom update for recent ISPs
 - Add FW reset attribute in sysfs.
 - Ignore terminate rport io & tmo callback in reset.
 - Change reset_fw to reset.
 - Serialize mbx cmds during reset also.
 - Use correct mode for reset attribute.
 - Use byte-address while reading FC boot code versions from flash
 - Correct qla_flt_location structure
 - Update drivers FW version for ISP81xx
 - For ISP81XX do not cache VPD
 - Always update FW versions and NPIV support in reset path.
 - Do not check for ISP81XX FW in qla2x00_request_fw.
 - Remove unused reqest_firmware and release_fw calls.
 - Remove compiler warnings for ull and size_t
 - Add EDC-update support

diff --git a/drivers/scsi/qla2xxx/Makefile b/drivers/scsi/qla2xxx/Makefile
index 7578c39..bcc2dfc 100644
--- a/drivers/scsi/qla2xxx/Makefile
+++ b/drivers/scsi/qla2xxx/Makefile
@@ -1,6 +1,6 @@
 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 ql8100_fw.o
+		ql2200_fw.o ql2300_fw.o ql2322_fw.o ql2400_fw.o ql2500_fw.o
 
 obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx.o
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 31fb491..28df87c 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -85,6 +85,71 @@ static struct bin_attribute sysfs_fw_dump_attr = {
 	.write = qla2x00_sysfs_write_fw_dump,
 };
 
+#define        RESET_FC_FW                     0x01
+#define        RESET_MPI                       0x02
+
+static ssize_t
+qla2x00_sysfs_write_reset(struct kobject *kobj, char *buf, loff_t off,
+    size_t count)
+{
+	struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+	    struct device, kobj)));
+	scsi_qla_host_t *pha = to_qla_parent(ha);
+	int reset_type;
+
+	reset_type = simple_strtol(buf, NULL, 10);
+	switch (reset_type) {
+	case RESET_FC_FW:
+		qla_printk(KERN_INFO, ha,
+		    "Issuing ISP abort on host%ld.\n", ha->host_no);
+		if (ha != pha) {
+			if (qla2x00_vp_abort_isp(ha)) {
+				DEBUG2(qla_printk(KERN_INFO, ha, "VPort reset failed\n"));
+			}
+		} else {
+
+			scsi_block_requests(ha->host);
+			set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+			qla2xxx_wake_dpc(ha);
+			qla2x00_wait_for_chip_reset(ha);
+			scsi_unblock_requests(ha->host);
+		}
+		break;
+	case RESET_MPI:
+		if(!IS_QLA81XX(ha) || ha != pha) {
+			qla_printk(KERN_INFO, ha,
+			    "MPI reset not supported for host%ld.\n", ha->host_no);
+			return (count);
+		}
+		qla_printk(KERN_INFO, ha,
+		    "Issuing MPI reset on host%ld.\n", ha->host_no);
+		
+		/* Make sure FC side is not in reset */
+		qla2x00_wait_for_hba_online(ha);
+		/* Issue MPI reset */
+		 scsi_block_requests(ha->host);
+
+		 if (qla81xx_restart_mpi_firmware(ha) != QLA_SUCCESS) {
+			 qla_printk(KERN_INFO, ha,
+			     "MPI reset failed for host%ld.\n", ha->host_no);
+		}		
+		 scsi_unblock_requests(ha->host);
+		break;
+	}
+	return (count);
+}
+
+static struct bin_attribute sysfs_fw_reset_attr = {
+	.attr = {
+		.name = "reset",
+		.mode = S_IWUSR,
+		.owner = THIS_MODULE,
+	},
+	.size = 0,
+	.write = qla2x00_sysfs_write_reset,
+};
+
+
 static ssize_t
 qla2x00_sysfs_read_nvram(struct kobject *kobj, char *buf, loff_t off,
     size_t count)
@@ -257,12 +322,6 @@ qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj, char *buf, loff_t off,
 		if (ha->optrom_state != QLA_SWAITING)
 			break;
 
-		if (start & 0xfff) {
-			qla_printk(KERN_WARNING, ha,
-			    "Invalid start region 0x%x/0x%x.\n", start, size);
-			return -EINVAL;
-		}
-
 		ha->optrom_region_start = start;
 		ha->optrom_region_size = start + size > ha->optrom_size ?
 		    ha->optrom_size - start : size;
@@ -304,11 +363,6 @@ qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj, char *buf, loff_t off,
 		 * 	0x000000 -> 0x07ffff -- Boot code.
 		 * 	0x080000 -> 0x0fffff -- Firmware.
 		 *
-		 * ISP25xx type boards:
-		 *
-		 * 	0x000000 -> 0x07ffff -- Boot code.
-		 * 	0x080000 -> 0x0fffff -- Firmware.
-		 * 	0x120000 -> 0x12ffff -- VPD and HBA parameters.
 		 */
 		valid = 0;
 		if (ha->optrom_size == OPTROM_SIZE_2300 && start == 0)
@@ -316,8 +370,7 @@ qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj, char *buf, loff_t off,
 		else if (start == (ha->flt_region_boot * 4) ||
 		    start == (ha->flt_region_fw * 4))
 			valid = 1;
-		else if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) &&
-		    start == (ha->flt_region_vpd_nvram * 4))
+		else if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)))
 		    valid = 1;
 		if (!valid) {
 			qla_printk(KERN_WARNING, ha,
@@ -395,7 +448,10 @@ qla2x00_sysfs_read_vpd(struct kobject *kobj, char *buf, loff_t off,
 		count = size;
 	}
 
-	/* Read NVRAM data from cache. */
+	if (IS_NOCACHE_VPD_TYPE(ha))
+		ha->isp_ops->read_nvram(ha, (uint8_t *)ha->vpd, ha->vpd_base,
+		    count);
+
 	memcpy(buf, &vpd_cache[off], count);
 
 	return count;
@@ -548,7 +604,7 @@ qla2x00_sysfs_write_els(struct kobject *kobj, char *buf, loff_t off,
 
 	if (count < sizeof(request->ct_iu)) {
 		DEBUG2(qla_printk(KERN_WARNING, ha,
-		    "Passthru ELS buffer insufficient size %ld...\n", count));
+		    "Passthru ELS buffer insufficient size %zu...\n", count));
 		goto els_error0;
 	}
 
@@ -584,7 +640,7 @@ qla2x00_sysfs_write_els(struct kobject *kobj, char *buf, loff_t off,
 
 	if (count > PAGE_SIZE) {
 		DEBUG2(qla_printk(KERN_INFO, ha,
-		    "Passthru ELS request excessive size %ld...\n", count));
+		    "Passthru ELS request excessive size %zu...\n", count));
 		count = PAGE_SIZE;
 	}
 
@@ -679,7 +735,7 @@ qla2x00_sysfs_write_ct(struct kobject *kobj, char *buf, loff_t off,
 
 	if (count < sizeof(request->ct_iu)) {
 		DEBUG2(qla_printk(KERN_WARNING, ha,
-		    "Passthru CT buffer insufficient size %ld...\n", count));
+		    "Passthru CT buffer insufficient size %zu...\n", count));
 		goto ct_error0;
 	}
 
@@ -802,6 +858,138 @@ static struct bin_attribute sysfs_ct_attr = {
 	.write = qla2x00_sysfs_write_ct,
 };
 
+static ssize_t
+qla2x00_sysfs_write_edc(struct kobject *kobj, char *buf, loff_t off,
+    size_t count)
+{
+	struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+	    struct device, kobj)));
+	uint16_t dev, adr, opt, len;
+	int rval;
+
+	ha->edc_data_len = 0;
+
+	if (!capable(CAP_SYS_ADMIN) || off != 0 || count < 8)
+		return 0;
+
+	if (!ha->edc_data) {
+		ha->edc_data = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
+		    &ha->edc_data_dma);
+		if (!ha->edc_data) {
+			DEBUG2(qla_printk(KERN_INFO, ha,
+			    "Unable to allocate memory for EDC write.\n"));
+			return 0;
+		}
+	}
+
+	dev = le16_to_cpup((void *)&buf[0]);
+	adr = le16_to_cpup((void *)&buf[2]);
+	opt = le16_to_cpup((void *)&buf[4]);
+	len = le16_to_cpup((void *)&buf[6]);
+
+	if (!(opt & BIT_0))
+		if (len == 0 || len > DMA_POOL_SIZE || len > count - 8)
+			return -EINVAL;
+
+	memcpy(ha->edc_data, &buf[8], len);
+
+	rval = qla2x00_write_edc(ha, dev, adr, ha->edc_data_dma,
+	    ha->edc_data, len, opt);
+	if (rval != QLA_SUCCESS) {
+		DEBUG2(qla_printk(KERN_INFO, ha,
+		    "Unable to write EDC (%x) %02x:%02x:%04x:%02x:%02x.\n",
+		    rval, dev, adr, opt, len, *buf));
+		return 0;
+	}
+
+	return count;
+}
+
+static struct bin_attribute sysfs_edc_attr = {
+	.attr = {
+		.name = "edc",
+		.mode = S_IWUSR,
+	},
+	.size = 0,
+	.write = qla2x00_sysfs_write_edc,
+};
+
+static ssize_t
+qla2x00_sysfs_write_edc_status(struct kobject *kobj, char *buf, loff_t off,
+    size_t count)
+{
+	struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+	    struct device, kobj)));
+	uint16_t dev, adr, opt, len;
+	int rval;
+
+	ha->edc_data_len = 0;
+
+	if (!capable(CAP_SYS_ADMIN) || off != 0 || count < 8)
+		return 0;
+
+	if (!ha->edc_data) {
+		ha->edc_data = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
+		    &ha->edc_data_dma);
+		if (!ha->edc_data) {
+			DEBUG2(qla_printk(KERN_INFO, ha,
+			    "Unable to allocate memory for EDC status.\n"));
+			return 0;
+		}
+	}
+
+	dev = le16_to_cpup((void *)&buf[0]);
+	adr = le16_to_cpup((void *)&buf[2]);
+	opt = le16_to_cpup((void *)&buf[4]);
+	len = le16_to_cpup((void *)&buf[6]);
+
+	if (!(opt & BIT_0))
+		if (len == 0 || len > DMA_POOL_SIZE)
+			return -EINVAL;
+
+	memset(ha->edc_data, 0, len);
+	rval = qla2x00_read_edc(ha, dev, adr, ha->edc_data_dma,
+	    ha->edc_data, len, opt);
+	if (rval != QLA_SUCCESS) {
+		DEBUG2(qla_printk(KERN_INFO, ha,
+		    "Unable to write EDC status (%x) %02x:%02x:%04x:%02x.\n",
+		    rval, dev, adr, opt, len));
+		return 0;
+	}
+
+	ha->edc_data_len = len;
+
+	return count;
+}
+
+static ssize_t
+qla2x00_sysfs_read_edc_status(struct kobject *kobj, char *buf, loff_t off,
+    size_t count)
+{
+	struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+	    struct device, kobj)));
+
+	if (!capable(CAP_SYS_ADMIN) || off != 0 || count == 0)
+		return 0;
+
+	if (!ha->edc_data || ha->edc_data_len == 0 || ha->edc_data_len > count)
+		return -EINVAL;
+
+	memcpy(buf, ha->edc_data, ha->edc_data_len);
+
+	return ha->edc_data_len;
+}
+
+static struct bin_attribute sysfs_edc_status_attr = {
+	.attr = {
+		.name = "edc_status",
+		.mode = S_IRUSR | S_IWUSR,
+	},
+	.size = 0,
+	.write = qla2x00_sysfs_write_edc_status,
+	.read = qla2x00_sysfs_read_edc_status,
+};
+
 static struct sysfs_entry {
 	char *name;
 	struct bin_attribute *attr;
@@ -815,6 +1003,9 @@ static struct sysfs_entry {
 	{ "sfp", &sysfs_sfp_attr, 1 },
 	{ "els", &sysfs_els_attr, 1 },
 	{ "ct", &sysfs_ct_attr, },
+	{ "reset", &sysfs_fw_reset_attr, },
+	{ "edc", &sysfs_edc_attr, 2 },
+	{ "edc_status", &sysfs_edc_status_attr, 2 },
 	{ NULL },
 };
 
@@ -828,6 +1019,8 @@ qla2x00_alloc_sysfs_attr(scsi_qla_host_t *ha)
 	for (iter = bin_file_entries; iter->name; iter++) {
 		if (iter->is4GBp_only && !IS_FWI2_CAPABLE(ha))
 			continue;
+		if (iter->is4GBp_only == 2 && !IS_QLA25XX(ha))
+			continue;
 
 		ret = sysfs_create_bin_file(&host->shost_gendev.kobj,
 		    iter->attr);
@@ -847,6 +1040,8 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *ha)
 	for (iter = bin_file_entries; iter->name; iter++) {
 		if (iter->is4GBp_only && !IS_FWI2_CAPABLE(ha))
 			continue;
+		if (iter->is4GBp_only == 2 && !IS_QLA25XX(ha))
+			continue;
 
 		sysfs_remove_bin_file(&host->shost_gendev.kobj,
 		    iter->attr);
@@ -1769,11 +1964,18 @@ qla2x00_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
 static void
 qla2x00_dev_loss_tmo_callbk(struct fc_rport *rport)
 {
+	scsi_qla_host_t *ha = NULL;
 	struct Scsi_Host *host = rport_to_shost(rport);
 	fc_port_t *fcport = *(fc_port_t **)rport->dd_data;
 
 	if (!fcport)
 		return;
+
+	ha = to_qla_parent(fcport->ha);
+	if (test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags)) {
+		return ;
+	}
+
 	/*
 	 * At this point all fcport's software-states are cleared.  Perform any
 	 * final cleanup of firmware resources (PCBs and XCBs).
@@ -1800,10 +2002,16 @@ qla2x00_dev_loss_tmo_callbk(struct fc_rport *rport)
 static void
 qla2x00_terminate_rport_io(struct fc_rport *rport)
 {
+	scsi_qla_host_t *ha = NULL;
 	fc_port_t *fcport = *(fc_port_t **)rport->dd_data;
 
 	if (!fcport)
 		return;
+
+	ha = to_qla_parent(fcport->ha);
+	if (test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags)) {
+		return ;
+	}
 	/*
 	 * At this point all fcport's software-states are cleared.  Perform any
 	 * final cleanup of firmware resources (PCBs and XCBs).
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 38d5029..32e0038 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -696,6 +696,7 @@ typedef struct {
 #define MBC_GET_TIMEOUT_PARAMS		0x22	/* Get FW timeouts. */
 #define MBC_TRACE_CONTROL		0x27	/* Trace control command. */
 #define MBC_GEN_SYSTEM_ERROR		0x2a	/* Generate System Error. */
+#define MBC_WRITE_SFP			0x30	/* Write SFP Data. */
 #define MBC_READ_SFP			0x31	/* Read SFP Data. */
 #define MBC_SET_TIMEOUT_PARAMS		0x32	/* Set FW timeouts. */
 #define MBC_MID_INITIALIZE_FIRMWARE	0x48	/* MID Initialize firmware. */
@@ -706,6 +707,7 @@ typedef struct {
 #define MBC_GET_LINK_PRIV_STATS		0x6d	/* Get link & private data. */
 #define MBC_SET_VENDOR_ID		0x76	/* Set Vendor ID. */
 #define MBC_IDC_ACK			0x101   /* Ack IDC */
+#define MBC_RESTART_MPI_FW      	0x03d	/* Reset MPI */
 
 #define TC_ENABLE			4
 #define TC_DISABLE			5
@@ -2292,6 +2294,7 @@ typedef struct scsi_qla_host {
 		uint32_t        npiv_supported          :1;
 		uint32_t        pci_channel_io_perm_failure          :1;
 		uint32_t        chip_reset_done         :1;
+		uint32_t        running_gold_fw		:1;
 	} flags;
 
 	atomic_t	loop_state;
@@ -2393,6 +2396,7 @@ typedef struct scsi_qla_host {
 #define IS_QLA24XX_TYPE(ha)    (IS_QLA24XX(ha) || IS_QLA54XX(ha) || \
 				IS_QLA84XX(ha))
 #define IS_QLA81XX(ha)	(IS_QLA8001(ha))
+#define IS_NOCACHE_VPD_TYPE(ha)	(IS_QLA81XX(ha))
 
 #define IS_IIDMA_CAPABLE(ha)	((ha)->device_type & DT_IIDMA)
 #define IS_FWI2_CAPABLE(ha)	((ha)->device_type & DT_FWI2)
@@ -2527,6 +2531,10 @@ typedef struct scsi_qla_host {
 	void			*sfp_data;
 	dma_addr_t		sfp_data_dma;
 
+	uint8_t		*edc_data;
+	dma_addr_t	edc_data_dma;
+	uint16_t	edc_data_len;
+
 	struct task_struct	*dpc_thread;
 	uint8_t dpc_active;                  /* DPC routine is active */
 
@@ -2656,6 +2664,7 @@ typedef struct scsi_qla_host {
 	uint32_t	flt_region_fw;
 	uint32_t	flt_region_vpd_nvram;
 	uint32_t	flt_region_npiv_conf;
+	uint32_t	flt_region_gold_fw;
 
 	/* Needed for BEACON */
 	uint16_t	beacon_blink_led;
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
index 309c7b7..16b4bf8 100644
--- a/drivers/scsi/qla2xxx/qla_fw.h
+++ b/drivers/scsi/qla2xxx/qla_fw.h
@@ -1204,9 +1204,10 @@ struct qla_fdt_layout {
 
 struct qla_flt_location {
 	uint8_t sig[4];
-	uint32_t start_lo;
-	uint32_t start_hi;
-	uint16_t unused;
+	uint16_t start_lo;
+	uint16_t start_hi;
+	uint8_t version;
+	uint8_t unused[5];
 	uint16_t checksum;
 };
 
@@ -1229,6 +1230,7 @@ struct qla_flt_header {
 #define FLT_REG_HW_EVENT_1	0x1f
 #define FLT_REG_NPIV_CONF_0	0x29
 #define FLT_REG_NPIV_CONF_1	0x2a
+#define FLT_REG_GOLD_FW		0x2f
 
 struct qla_flt_region {
 	uint32_t code;
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 22cee28..00c16ad 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -34,6 +34,7 @@ extern void qla24xx_update_fw_options(scsi_qla_host_t *);
 extern void qla81xx_update_fw_options(scsi_qla_host_t *);
 extern int qla2x00_load_risc(struct scsi_qla_host *, uint32_t *);
 extern int qla24xx_load_risc(scsi_qla_host_t *, uint32_t *);
+extern int qla81xx_load_risc(scsi_qla_host_t *, uint32_t *);
 
 extern int qla2x00_loop_resync(scsi_qla_host_t *);
 
@@ -55,6 +56,7 @@ extern void qla2x00_try_to_stop_firmware(scsi_qla_host_t *);
 extern void qla84xx_put_chip(struct scsi_qla_host *);
 
 extern int qla2x00_post_idc_ack_work(struct scsi_qla_host *, uint16_t *);
+extern int qla81xx_restart_mpi_firmware(scsi_qla_host_t *);
 
 /*
  * Global Data in qla_os.c source file.
@@ -258,6 +260,14 @@ extern int
 qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t, uint16_t);
 
 extern int
+qla2x00_read_edc(scsi_qla_host_t *, uint16_t, uint16_t, dma_addr_t,
+    uint8_t *, uint16_t, uint16_t);
+
+extern int
+qla2x00_write_edc(scsi_qla_host_t *, uint16_t, uint16_t, dma_addr_t,
+    uint8_t *, uint16_t, uint16_t);
+
+extern int
 qla2x00_set_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t *);
 
 extern int qla84xx_verify_chip(struct scsi_qla_host *, uint16_t *);
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 404d31e..e1be63b 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -935,6 +935,7 @@ static int
 qla2x00_setup_chip(scsi_qla_host_t *ha)
 {
 	int rval;
+	uint16_t fw_major_version;
 	uint32_t srisc_address = 0;
 
 	/* Load firmware sequences */
@@ -951,14 +952,16 @@ qla2x00_setup_chip(scsi_qla_host_t *ha)
 
 			rval = qla2x00_execute_fw(ha, srisc_address);
 			/* Retrieve firmware information. */
-			if (rval == QLA_SUCCESS && ha->fw_major_version == 0) {
+			if (rval == QLA_SUCCESS) {
+				fw_major_version = ha->fw_major_version;
+			
 				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);
-				qla2x00_resize_request_q(ha);
+
 				ha->flags.npiv_supported = 0;
 				if ((IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) ||
 				    IS_QLA84XX(ha) || IS_QLA81XX(ha)) &&
@@ -971,8 +974,12 @@ qla2x00_setup_chip(scsi_qla_host_t *ha)
 						    MIN_MULTI_ID_FABRIC - 1;
 				}
 
-				if (ql2xallocfwdump)
-					qla2x00_alloc_fw_dump(ha);
+				if (fw_major_version == 0) {
+					qla2x00_resize_request_q(ha);
+
+					if (ql2xallocfwdump)
+						qla2x00_alloc_fw_dump(ha);
+				}
 			}
 		} else {
 			DEBUG2(printk(KERN_INFO
@@ -3641,11 +3648,11 @@ qla24xx_nvram_config(scsi_qla_host_t *ha)
 }
 
 static int
-qla24xx_load_risc_flash(scsi_qla_host_t *ha, uint32_t *srisc_addr)
+qla24xx_load_risc_flash(scsi_qla_host_t *ha, uint32_t *srisc_addr,
+    uint32_t faddr)
 {
 	int	rval;
 	int	segments, fragment;
-	uint32_t faddr;
 	uint32_t *dcode, dlen;
 	uint32_t risc_addr;
 	uint32_t risc_size;
@@ -3654,7 +3661,6 @@ qla24xx_load_risc_flash(scsi_qla_host_t *ha, uint32_t *srisc_addr)
 	rval = QLA_SUCCESS;
 
 	segments = FA_RISC_CODE_SEGMENTS;
-	faddr = ha->flt_region_fw;
 	dcode = (uint32_t *)ha->request_ring;
 	*srisc_addr = 0;
 
@@ -3825,7 +3831,7 @@ fail_fw_integrity:
 }
 
 int
-qla24xx_load_risc(scsi_qla_host_t *ha, uint32_t *srisc_addr)
+qla24xx_load_risc_blob(scsi_qla_host_t *ha, uint32_t *srisc_addr)
 {
 	int	rval;
 	int	segments, fragment;
@@ -3843,10 +3849,7 @@ qla24xx_load_risc(scsi_qla_host_t *ha, uint32_t *srisc_addr)
 		qla_printk(KERN_ERR, ha, "Firmware images can be retrieved "
 		    "from: " QLA_FW_URL ".\n");
 
-		/* Try to load RISC code from flash. */
-		qla_printk(KERN_ERR, ha, "Attempting to load (potentially "
-		    "outdated) firmware from flash.\n");
-		return qla24xx_load_risc_flash(ha, srisc_addr);
+		return QLA_FUNCTION_FAILED;
 	}
 
 	rval = QLA_SUCCESS;
@@ -3933,6 +3936,52 @@ fail_fw_integrity:
 	return QLA_FUNCTION_FAILED;
 }
 
+int
+qla24xx_load_risc(scsi_qla_host_t *ha, uint32_t *srisc_addr)
+{
+	int rval;
+
+        /*
+         * FW Load priority:
+         * 1) Firmware via request-firmware interface (.bin file with driver).
+         * 2) Firmware residing in flash.
+         */
+        rval = qla24xx_load_risc_blob(ha, srisc_addr);
+        if (rval == QLA_SUCCESS)
+                return rval;
+
+        return qla24xx_load_risc_flash(ha, srisc_addr, ha->flt_region_fw);
+}
+
+int
+qla81xx_load_risc(scsi_qla_host_t *ha, uint32_t *srisc_addr)
+{
+        int rval;
+
+        /*
+         * FW Load priority:
+         * 1) Operational firmware residing in flash.
+         * 2) Golden firmware residing in flash.
+         */
+        rval = qla24xx_load_risc_flash(ha, srisc_addr, ha->flt_region_fw);
+        if (rval == QLA_SUCCESS)
+                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");
+	}
+	return rval;
+}
+
 void
 qla2x00_try_to_stop_firmware(scsi_qla_host_t *ha)
 {
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index a007cce..34ee8de 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -57,7 +57,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
 	 * seconds. This is to serialize actual issuing of mailbox cmds during
 	 * non ISP abort time.
 	 */
-	if (!abort_active && !ha->flags.pci_channel_io_perm_failure) {
+	if (!ha->flags.pci_channel_io_perm_failure) {
 		if (!wait_for_completion_timeout(&ha->mbx_cmd_comp,
 		    mcp->tov * HZ)) {
 			/* Timeout occurred. Return error. */
@@ -262,8 +262,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
 	}
 
 	/* Allow next mbx cmd to come in. */
-	if (!abort_active)
-		complete(&ha->mbx_cmd_comp);
+	complete(&ha->mbx_cmd_comp);
 
 	if (rval) {
 		DEBUG2_3_11(printk("%s(%ld): **** FAILED. mbx0=%x, mbx1=%x, "
@@ -2966,3 +2965,108 @@ qla81xx_idc_ack(scsi_qla_host_t *vha, uint16_t *mb)
 
 	return rval;
 }
+
+int
+qla81xx_restart_mpi_firmware(scsi_qla_host_t *ha)
+{
+	int rval = 0;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+
+	DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+
+	mcp->mb[0] = MBC_RESTART_MPI_FW;
+	mcp->out_mb = MBX_0;
+	mcp->in_mb = MBX_0|MBX_1;
+	mcp->tov = MBX_TOV_SECONDS;
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(ha, mcp);
+
+	if (rval != QLA_SUCCESS) {
+		DEBUG2_3_11(printk("%s(%ld): failed=%x (mb[0]=0x%x mb[1]=0x%x).\n", 
+					__func__, ha->host_no, rval, mcp->mb[0], mcp->mb[1]));
+	} else {
+		DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
+	}
+
+	return rval;
+}
+
+ 
+int
+qla2x00_read_edc(scsi_qla_host_t *ha, uint16_t dev, uint16_t adr,
+     dma_addr_t sfp_dma, uint8_t *sfp, uint16_t len, uint16_t opt)
+{
+	int rval;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+
+	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+
+	mcp->mb[0] = MBC_READ_SFP;
+	mcp->mb[1] = dev;
+	mcp->mb[2] = MSW(sfp_dma);
+	mcp->mb[3] = LSW(sfp_dma);
+	mcp->mb[6] = MSW(MSD(sfp_dma));
+	mcp->mb[7] = LSW(MSD(sfp_dma));
+	mcp->mb[8] = len;
+	mcp->mb[9] = adr;
+	mcp->mb[10] = opt;
+	mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->in_mb = MBX_0;
+	mcp->tov = MBX_TOV_SECONDS;
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(ha, mcp);
+
+	if (opt & BIT_0)
+		if (sfp)
+			*sfp = mcp->mb[8];
+
+	if (rval != QLA_SUCCESS) {
+		DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__,
+		    ha->host_no, rval, mcp->mb[0]));
+	} else {
+		DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
+	}
+
+	return rval;
+}
+ 
+int
+qla2x00_write_edc(scsi_qla_host_t *ha, uint16_t dev, uint16_t adr,
+    dma_addr_t sfp_dma, uint8_t *sfp, uint16_t len, uint16_t opt)
+{
+	int rval;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+
+	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+
+	if (opt & BIT_0)
+		if (sfp)
+			len = *sfp;
+
+	mcp->mb[0] = MBC_WRITE_SFP;
+	mcp->mb[1] = dev;
+	mcp->mb[2] = MSW(sfp_dma);
+	mcp->mb[3] = LSW(sfp_dma);
+	mcp->mb[6] = MSW(MSD(sfp_dma));
+	mcp->mb[7] = LSW(MSD(sfp_dma));
+	mcp->mb[8] = len;
+	mcp->mb[9] = adr;
+	mcp->mb[10] = opt;
+	mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->in_mb = MBX_0;
+	mcp->tov = MBX_TOV_SECONDS;
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(ha, mcp);
+
+	if (rval != QLA_SUCCESS) {
+		DEBUG2_3_11(printk("%s(%ld): failed=%x (%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.h b/drivers/scsi/qla2xxx/qla_nlnk.h
index 0a1ea3a..91ff73f 100644
--- a/drivers/scsi/qla2xxx/qla_nlnk.h
+++ b/drivers/scsi/qla2xxx/qla_nlnk.h
@@ -132,7 +132,7 @@ struct msg_update_fw {
 struct qla_fc_msg {
 
 	uint64_t magic;
-#define QL_FC_NL_MAGIC	0x107784DDFCAB1FC1
+#define QL_FC_NL_MAGIC	0x107784DDFCAB1FC1ULL
 	uint16_t host_no;
 	uint16_t vmsg_datalen;
 
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index e006599..c4968a4 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -67,6 +67,12 @@ MODULE_PARM_DESC(ql2xextended_error_logging,
 		"Option to enable extended error logging, "
 		"Default is 0 - no logging. 1 - log errors.");
 
+int ql2xdevdiscgoldfw = 0;
+module_param(ql2xdevdiscgoldfw, int, S_IRUGO|S_IRUSR);
+MODULE_PARM_DESC(ql2xdevdiscgoldfw,
+		"Option to enable device discovery with golden firmware "
+		"Applicable to ISP81XX based CNA only. "
+		"Default is 0 - no discovery. 1 - discover device.");
 
 static void qla2x00_free_device(scsi_qla_host_t *);
 
@@ -1496,13 +1502,14 @@ static struct isp_operations qla81xx_isp_ops = {
 	.reset_adapter		= qla24xx_reset_adapter,
 	.nvram_config		= qla81xx_nvram_config,
 	.update_fw_options	= qla81xx_update_fw_options,
-	.load_risc		= qla24xx_load_risc,
+	.load_risc		= qla81xx_load_risc,
 	.pci_info_str		= qla24xx_pci_info_str,
 	.fw_version_str		= qla24xx_fw_version_str,
 	.intr_handler		= qla24xx_intr_handler,
 	.enable_intrs		= qla24xx_enable_intrs,
 	.disable_intrs		= qla24xx_disable_intrs,
 	.abort_command		= qla24xx_abort_command,
+	.abort_target		= qla24xx_abort_target,
 	.fabric_login		= qla24xx_login_fabric,
 	.fabric_logout		= qla24xx_fabric_logout,
 	.calc_req_entries	= NULL,
@@ -1675,6 +1682,8 @@ qla2xxx_scan_start(struct Scsi_Host *shost)
 {
 	scsi_qla_host_t *ha = (scsi_qla_host_t *)shost->hostdata;
 
+	if (ha->flags.running_gold_fw && !ql2xdevdiscgoldfw)
+		return;
 	set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
 	set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
 	set_bit(RSCN_UPDATE, &ha->dpc_flags);
@@ -1887,16 +1896,18 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 		goto probe_failed;
 	}
 
-	/*
-	 * Startup the kernel thread for this host adapter
-	 */
-	ha->dpc_thread = kthread_create(qla2x00_do_dpc, ha,
-			"%s_dpc", ha->host_str);
-	if (IS_ERR(ha->dpc_thread)) {
-		qla_printk(KERN_WARNING, ha,
-		    "Unable to start DPC thread!\n");
-		ret = PTR_ERR(ha->dpc_thread);
-		goto probe_failed;
+        if (!ha->flags.running_gold_fw || ql2xdevdiscgoldfw) {
+		/*
+		 * Startup the kernel thread for this host adapter
+		 */
+		ha->dpc_thread = kthread_create(qla2x00_do_dpc, ha,
+				"%s_dpc", ha->host_str);
+		if (IS_ERR(ha->dpc_thread)) {
+			qla_printk(KERN_WARNING, ha,
+			    "Unable to start DPC thread!\n");
+			ret = PTR_ERR(ha->dpc_thread);
+			goto probe_failed;
+		}
 	}
 
 	host->this_id = 255;
@@ -2474,6 +2485,9 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
 	if (ha->sfp_data)
 		dma_pool_free(ha->s_dma_pool, ha->sfp_data, ha->sfp_data_dma);
 
+	if (ha->edc_data)
+		dma_pool_free(ha->s_dma_pool, ha->edc_data, ha->edc_data_dma);
+
 	if (ha->ms_iocb)
 		dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma);
 
@@ -3062,19 +3076,16 @@ qla2x00_timer(scsi_qla_host_t *ha)
 
 /* Firmware interface routines. */
 
-#define FW_BLOBS	7
+#define FW_BLOBS	6
 #define FW_ISP21XX	0
 #define FW_ISP22XX	1
 #define FW_ISP2300	2
 #define FW_ISP2322	3
 #define FW_ISP24XX	4
 #define FW_ISP25XX	5
-#define FW_ISP81XX	6
-
-static DECLARE_MUTEX(qla_fw_lock);
 
 extern struct firmware ql2100_fw, ql2200_fw, ql2300_fw, ql2322_fw, ql2400_fw,
-       ql2500_fw, ql8100_fw;
+       ql2500_fw;
 
 static struct fw_blob qla_fw_blobs[FW_BLOBS] = {
 	{ .name = "ql2100_fw.bin", .segs = { 0x1000, 0 }, .fw = &ql2100_fw },
@@ -3083,7 +3094,6 @@ static struct fw_blob qla_fw_blobs[FW_BLOBS] = {
 	{ .name = "ql2322_fw.bin", .segs = { 0x800, 0x1c000, 0x1e000, 0 }, .fw = &ql2322_fw },
 	{ .name = "ql2400_fw.bin", .fw = &ql2400_fw },
 	{ .name = "ql2500_fw.bin", .fw = &ql2500_fw },
-	{ .name = "ql8100_fw.bin", .fw = &ql8100_fw },
 };
 
 struct fw_blob *
@@ -3104,40 +3114,10 @@ qla2x00_request_firmware(scsi_qla_host_t *ha)
 		blob = &qla_fw_blobs[FW_ISP24XX];
 	} else if (IS_QLA25XX(ha)) {
 		blob = &qla_fw_blobs[FW_ISP25XX];
-	} else if (IS_QLA81XX(ha)) {
-		blob = &qla_fw_blobs[FW_ISP81XX];
-	}
-
-
-	down(&qla_fw_lock);
-	if (blob->fw)
-		goto out;
-
-	if (request_firmware(&blob->fw, blob->name, &ha->pdev->dev)) {
-		DEBUG2(printk("scsi(%ld): Failed to load firmware image "
-		    "(%s).\n", ha->host_no, blob->name));
-		blob->fw = NULL;
-		blob = NULL;
-		goto out;
 	}
-
-out:
-	up(&qla_fw_lock);
 	return blob;
 }
 
-static void
-qla2x00_release_firmware(void)
-{
-	int idx;
-
-	down(&qla_fw_lock);
-	for (idx = 0; idx < FW_BLOBS; idx++)
-		if (qla_fw_blobs[idx].fw)
-			release_firmware(qla_fw_blobs[idx].fw);
-	up(&qla_fw_lock);
-}
-
 static pci_ers_result_t
 qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
 {
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index fb8f4a7..3a793b3 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -707,6 +707,9 @@ qla2xxx_get_flt_info(scsi_qla_host_t *ha, uint32_t flt_addr)
 			if (PCI_FUNC(ha->pdev->devfn) & 1)
 				ha->flt_region_npiv_conf = start;
 			break;
+		case FLT_REG_GOLD_FW:
+			ha->flt_region_gold_fw = start;
+			break;
 		}
 	}
 	goto done;
@@ -2476,7 +2479,7 @@ qla24xx_get_flash_version(scsi_qla_host_t *ha, void *mbuf)
 	dcode = mbuf;
 
 	/* Begin with first PCI expansion ROM header. */
-	pcihdr = ha->flt_region_boot;
+	pcihdr = ha->flt_region_boot << 2;
 	last_image = 1;
 	do {
 		/* Verify PCI expansion ROM header. */