Sophie

Sophie

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

kernel-2.6.18-194.11.1.el5.src.rpm

From: Marcus Barrow <mbarrow@redhat.com>
Date: Fri, 17 Apr 2009 12:31:28 -0400
Subject: [scsi] qla2xxx : updates and fixes from upstream, part 4
Message-id: 20090417163128.6777.29640.sendpatchset@file.bos.redhat.com
O-Subject: [rhel 5.4 patch] qla2xxx : updates and fixes from upstream, part 4
Bugzilla: 496126
RH-Acked-by: Tomas Henzl <thenzl@redhat.com>

BZ 496126 - qla2xxx - updates and fixes from upstream, part 4

This group of patches is the fourth part of updates 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.

qla2xxx - Fourth group of updates from QIDL

 - Correct bus-reset behaviour with recent ISPs.
 - Export VLAN ID and MAC address
 - Explicitly set the execution-throttle with recent ISPs.
 - Made driver source kABI compliant with RHEL5.3 (2.6.18-128.el)
 - Don't try to 'stop' firmware if already in ROM code.
 - Correct hard-coded address of a second-port's NVRAM.
 - Export negotiated fabric-parameters for application support.
 - Export TLV data on supported ISPs
 - Fixed model description attribute for ISP 8G and above.
 - Make dcbx pointers NULL after freeing memory.
 - Updated version to 8.03.00.04.05.04-k

diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 94f657b..dc72f60 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -1011,6 +1011,55 @@ static struct bin_attribute sysfs_edc_status_attr = {
 	.read = qla2x00_sysfs_read_edc_status,
 };
 
+static ssize_t
+qla2x00_sysfs_read_dcbx_tlv(struct kobject *kobj, char *buf, loff_t off,
+    size_t count)
+{
+	struct scsi_qla_host *vha = to_qla_host(dev_to_shost(container_of(kobj,
+	    struct device, kobj)));
+
+	struct scsi_qla_host *ha = to_qla_parent(vha);
+	int rval;
+
+	if (!capable(CAP_SYS_ADMIN) || off != 0 || count > DCBX_TLV_DATA_SIZE)
+		return 0;
+
+        if (ha->dcbx_tlv)
+                goto do_read;
+        
+        ha->dcbx_tlv = dma_alloc_coherent(&ha->pdev->dev, DCBX_TLV_DATA_SIZE,
+            &ha->dcbx_tlv_dma, GFP_KERNEL);
+        if (!ha->dcbx_tlv) {
+                qla_printk(KERN_WARNING, ha,
+                    "Unable to allocate memory for DCBX TLV read-data.\n");
+                return 0;
+        }
+
+do_read:
+        memset(ha->dcbx_tlv, 0, DCBX_TLV_DATA_SIZE);
+
+        rval = qla2x00_get_dcbx_params(ha, ha->dcbx_tlv_dma,
+            DCBX_TLV_DATA_SIZE);
+        if (rval != QLA_SUCCESS) {
+                qla_printk(KERN_WARNING, ha,
+                    "Unable to read DCBX TLV data (%x).\n", rval);
+                count = 0;
+        }
+
+        memcpy(buf, ha->dcbx_tlv, count);
+
+        return count;
+}
+
+static struct bin_attribute sysfs_dcbx_tlv_attr = {
+        .attr = {
+                .name = "dcbx_tlv",
+                .mode = S_IRUSR,
+        },
+        .size = 0,
+        .read = qla2x00_sysfs_read_dcbx_tlv,
+};
+
 static struct sysfs_entry {
 	char *name;
 	struct bin_attribute *attr;
@@ -1027,6 +1076,7 @@ static struct sysfs_entry {
 	{ "reset", &sysfs_fw_reset_attr, },
 	{ "edc", &sysfs_edc_attr, 2 },
 	{ "edc_status", &sysfs_edc_status_attr, 2 },
+	{ "dcbx_tlv", &sysfs_dcbx_tlv_attr, 3 },
 	{ NULL },
 };
 
@@ -1042,6 +1092,8 @@ qla2x00_alloc_sysfs_attr(scsi_qla_host_t *ha)
 			continue;
 		if (iter->is4GBp_only == 2 && !IS_QLA25XX(ha))
 			continue;
+		if (iter->is4GBp_only == 3 && !IS_QLA81XX(ha))
+			continue;
 
 		ret = sysfs_create_bin_file(&host->shost_gendev.kobj,
 		    iter->attr);
@@ -1063,6 +1115,8 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *ha)
 			continue;
 		if (iter->is4GBp_only == 2 && !IS_QLA25XX(ha))
 			continue;
+		if (iter->is4GBp_only == 3 && !IS_QLA81XX(ha))
+			continue;
 
 		sysfs_remove_bin_file(&host->shost_gendev.kobj,
 		    iter->attr);
@@ -1747,6 +1801,38 @@ qla2x00_flash_block_size_show(struct class_device *cdev, char *buf)
 	return snprintf(buf, PAGE_SIZE, "0x%x\n", ha->fdt_block_size);
 }
 
+static ssize_t
+qla2x00_vlan_id_show(struct class_device *cdev, char *buf)
+{
+	scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+
+        if (!IS_QLA81XX(ha))
+                return snprintf(buf, PAGE_SIZE, "\n");
+
+        return snprintf(buf, PAGE_SIZE, "%d\n", ha->fcoe_vlan_id);
+}
+
+static ssize_t
+qla2x00_vn_port_mac_address_show(struct class_device *cdev, char *buf)
+{
+	scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+
+        if (!IS_QLA81XX(ha))
+                return snprintf(buf, PAGE_SIZE, "\n");
+
+        return snprintf(buf, PAGE_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x\n",
+            ha->fcoe_vn_port_mac[5], ha->fcoe_vn_port_mac[4],
+            ha->fcoe_vn_port_mac[3], ha->fcoe_vn_port_mac[2],
+            ha->fcoe_vn_port_mac[1], ha->fcoe_vn_port_mac[0]);
+}
+
+static ssize_t
+qla2x00_fabric_param_show(struct class_device *cdev, char *buf)
+{
+	scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+
+        return snprintf(buf, PAGE_SIZE, "%d\n", ha->switch_cap);
+}
 
 static CLASS_DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show,
 	NULL);
@@ -1802,6 +1888,12 @@ static CLASS_DEVICE_ATTR(phy_version, S_IRUGO,
 
 static CLASS_DEVICE_ATTR(flash_block_size, S_IRUGO,
 	qla2x00_flash_block_size_show, NULL);
+static CLASS_DEVICE_ATTR(vlan_id, S_IRUGO, qla2x00_vlan_id_show, NULL);
+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);
+
 
 struct class_device_attribute *qla2x00_host_attrs[] = {
 	&class_device_attr_driver_version,
@@ -1850,6 +1942,9 @@ struct class_device_attribute *qla24xx_host_attrs[] = {
 	&class_device_attr_mpi_version,
 	&class_device_attr_phy_version,
 	&class_device_attr_flash_block_size,
+	&class_device_attr_vlan_id,
+	&class_device_attr_vn_port_mac_address,
+	&class_device_attr_fabric_param,
 	NULL,
 };
 
@@ -1881,6 +1976,9 @@ struct class_device_attribute *qla24xx_host_vport_attrs[] = {
 	&class_device_attr_vport_last_state,
 	&class_device_attr_mpi_version,
 	&class_device_attr_phy_version,
+	&class_device_attr_vlan_id,
+	&class_device_attr_vn_port_mac_address,
+	&class_device_attr_fabric_param,
 	NULL,
 };
 
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 48379d9..e6f1af0 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -654,6 +654,7 @@ typedef struct {
 #define MBC_DIAGNOSTIC_LOOP_BACK	0x45	/* Diagnostic loop back. */
 #define MBC_ONLINE_SELF_TEST		0x46	/* Online self-test. */
 #define MBC_ENHANCED_GET_PORT_DATABASE	0x47	/* Get port database + login */
+#define MBC_GET_DCBX_PARAMS		0x51	/* DCBX TLVs */
 #define MBC_RESET_LINK_STATUS		0x52	/* Reset Link Error Status */
 #define MBC_IOCB_COMMAND_A64		0x54	/* Execute IOCB command (64) */
 #define MBC_SEND_RNID_ELS		0x57	/* Send RNID ELS request */
@@ -2555,6 +2556,10 @@ typedef struct scsi_qla_host {
 	dma_addr_t	edc_data_dma;
 	uint16_t	edc_data_len;
 
+#define DCBX_TLV_DATA_SIZE PAGE_SIZE
+	void		*dcbx_tlv;
+	dma_addr_t	dcbx_tlv_dma;
+
 	struct task_struct	*dpc_thread;
 	uint8_t dpc_active;                  /* DPC routine is active */
 
@@ -2617,6 +2622,7 @@ typedef struct scsi_qla_host {
 #define RISC_START_ADDRESS_2100 0x1000
 #define RISC_START_ADDRESS_2300 0x800
 #define RISC_START_ADDRESS_2400 0x100000
+	uint16_t	fw_xcb_count;
 
 	uint16_t	fw_options[16];		/* slots: 1,2,3,10,11 */
 	uint8_t		fw_seriallink_options[4];
@@ -2642,12 +2648,17 @@ typedef struct scsi_qla_host {
 
 	uint8_t		model_number[16+1];
 #define BINZERO		"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
-	char		*model_desc;
+	char		model_desc[80];
 	uint8_t		adapter_id[16+1];
 
 	uint8_t		*node_name;
 	uint8_t		*port_name;
 	uint8_t		fabric_node_name[WWN_SIZE];
+
+        uint16_t        fcoe_vlan_id;
+        uint16_t        fcoe_fcf_idx;
+        uint8_t         fcoe_vn_port_mac[6];
+
 	uint32_t    isp_abort_cnt;
 
 	/* Option ROM information. */
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
index bccb724..cb40a78 100644
--- a/drivers/scsi/qla2xxx/qla_fw.h
+++ b/drivers/scsi/qla2xxx/qla_fw.h
@@ -1683,7 +1683,7 @@ struct ex_init_cb_81xx {
 #define FA_VPD0_ADDR_81         0xD0000
 #define FA_VPD1_ADDR_81         0xD0400
 #define FA_NVRAM0_ADDR_81       0xD0080
-#define FA_NVRAM1_ADDR_81       0xD0480
+#define FA_NVRAM1_ADDR_81       0xD0180
 #define FA_FEATURE_ADDR_81	0xD4000
 #define FA_FLASH_DESCR_ADDR_81	0xD8000
 #define FA_FLASH_LAYOUT_ADDR_81	0xD8400
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index f66d35c..c576cad 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -58,6 +58,7 @@ 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 *);
 extern int qla81xx_get_xgmac_stats(scsi_qla_host_t *, uint32_t, dma_addr_t);
+extern int qla2x00_get_dcbx_params(scsi_qla_host_t *, dma_addr_t, uint16_t);
 
 /*
  * Global Data in qla_os.c source file.
@@ -344,6 +345,8 @@ extern int qla2xxx_get_flash_info(scsi_qla_host_t *);
 
 extern void qla2xxx_flash_npiv_conf(scsi_qla_host_t *);
 
+extern int qla2xxx_get_vpd_field(scsi_qla_host_t *, char *, char *, size_t);
+
 /*
  * Global Function Prototypes in qla_dbg.c source file.
  */
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 569f3f2..50f07d1 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -289,6 +289,7 @@ qla24xx_pci_config(scsi_qla_host_t *ha)
 	uint32_t d;
 	unsigned long flags = 0;
 	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+	int pcix_cmd_reg, pcie_dctl_reg;
 
 	pci_set_master(ha->pdev);
 	ret = pci_set_mwi(ha->pdev);
@@ -301,12 +302,28 @@ qla24xx_pci_config(scsi_qla_host_t *ha)
 	pci_write_config_byte(ha->pdev, PCI_LATENCY_TIMER, 0x80);
 
 	/* PCI-X -- adjust Maximum Memory Read Byte Count (2048). */
-	if (pci_find_capability(ha->pdev, PCI_CAP_ID_PCIX))
-		pcix_set_mmrbc(ha->pdev, 2048);
+	pcix_cmd_reg = pci_find_capability(ha->pdev, PCI_CAP_ID_PCIX);
+	if (pcix_cmd_reg) {
+		uint16_t pcix_cmd;
+
+		pcix_cmd_reg += PCI_X_CMD;
+		pci_read_config_word(ha->pdev, pcix_cmd_reg, &pcix_cmd);
+		pcix_cmd &= ~PCI_X_CMD_MAX_READ;
+		pcix_cmd |= 0x0008;
+		pci_write_config_word(ha->pdev, pcix_cmd_reg, pcix_cmd);
+	}
 
 	/* PCIe -- adjust Maximum Read Request Size (2048). */
-	if (pci_find_capability(ha->pdev, PCI_CAP_ID_EXP))
-		pcie_set_readrq(ha->pdev, 2048);
+	pcie_dctl_reg = pci_find_capability(ha->pdev, PCI_CAP_ID_EXP);
+	if (pcie_dctl_reg) {
+		uint16_t pcie_dctl;
+
+		pcie_dctl_reg += PCI_EXP_DEVCTL;
+		pci_read_config_word(ha->pdev, pcie_dctl_reg, &pcie_dctl);
+		pcie_dctl &= ~PCI_EXP_DEVCTL_READRQ;
+		pcie_dctl |= 0x4000;
+		pci_write_config_word(ha->pdev, pcie_dctl_reg, pcie_dctl);
+	}
 
 	/* Reset expansion ROM address decode enable */
 	pci_read_config_dword(ha->pdev, PCI_ROM_ADDRESS, &d);
@@ -334,6 +351,7 @@ qla25xx_pci_config(scsi_qla_host_t *ha)
 {
 	uint16_t w, mwi;
 	uint32_t d;
+	int pcie_dctl_reg;
 
 	pci_set_master(ha->pdev);
 	mwi = 0;
@@ -346,8 +364,16 @@ qla25xx_pci_config(scsi_qla_host_t *ha)
 	pci_write_config_word(ha->pdev, PCI_COMMAND, w);
 
 	/* PCIe -- adjust Maximum Read Request Size (2048). */
-	if (pci_find_capability(ha->pdev, PCI_CAP_ID_EXP))
-		pcie_set_readrq(ha->pdev, 2048);
+	pcie_dctl_reg = pci_find_capability(ha->pdev, PCI_CAP_ID_EXP);
+	if (pcie_dctl_reg) {
+		uint16_t pcie_dctl;
+
+		pcie_dctl_reg += PCI_EXP_DEVCTL;
+		pci_read_config_word(ha->pdev, pcie_dctl_reg, &pcie_dctl);
+		pcie_dctl &= ~PCI_EXP_DEVCTL_READRQ;
+		pcie_dctl |= 0x4000;
+		pci_write_config_word(ha->pdev, pcie_dctl_reg, pcie_dctl);
+	}
 
 	/* Reset expansion ROM address decode enable */
 	pci_read_config_dword(ha->pdev, PCI_ROM_ADDRESS, &d);
@@ -891,8 +917,8 @@ qla2x00_resize_request_q(scsi_qla_host_t *ha)
 		return;
 
 	/* Retrieve IOCB counts available to the firmware. */
-	rval = qla2x00_get_resource_cnts(ha, NULL, NULL, NULL, &fw_iocb_cnt,
-	    &ha->max_npiv_vports);
+	rval = qla2x00_get_resource_cnts(ha, NULL, &ha->fw_xcb_count, NULL,
+	    &fw_iocb_cnt, &ha->max_npiv_vports);
 	if (rval)
 		return;
 	/* No point in continuing if current settings are sufficient. */
@@ -1235,7 +1261,11 @@ qla2x00_init_rings(scsi_qla_host_t *ha)
 		mid_init_cb->count = cpu_to_le16(ha->max_npiv_vports);	
 	}
 
-	mid_init_cb->options = __constant_cpu_to_le16(BIT_1);
+	if (IS_FWI2_CAPABLE(ha)) {
+		mid_init_cb->options = __constant_cpu_to_le16(BIT_1);
+		mid_init_cb->init_cb.execution_throttle =
+		    cpu_to_le16(ha->fw_xcb_count);
+	}
 
 	rval = qla2x00_init_firmware(ha, ha->init_cb_size);
 	if (rval) {
@@ -1492,6 +1522,7 @@ qla2x00_set_model_info(scsi_qla_host_t *ha, uint8_t *model, size_t len, char *de
 {
 	char *st, *en;
 	uint16_t index;
+	int use_tbl = !IS_QLA25XX(ha) && !IS_QLA81XX(ha);
 
 	if (memcmp(model, BINZERO, len) != 0) {
 		strncpy(ha->model_number, model, len);
@@ -1504,20 +1535,30 @@ qla2x00_set_model_info(scsi_qla_host_t *ha, uint8_t *model, size_t len, char *de
 		}
 
 		index = (ha->pdev->subsystem_device & 0xff);
-		if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
+		if (use_tbl &&
+		    ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
 		    index < QLA_MODEL_NAMES)
-			ha->model_desc = qla2x00_model_name[index * 2 + 1];
+			strncpy(ha->model_desc,
+                            qla2x00_model_name[index * 2 + 1],
+                            sizeof(ha->model_desc) - 1);
 	} else {
 		index = (ha->pdev->subsystem_device & 0xff);
-		if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
+		if (use_tbl &&
+		    ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
 		    index < QLA_MODEL_NAMES) {
 			strcpy(ha->model_number,
 			    qla2x00_model_name[index * 2]);
-			ha->model_desc = qla2x00_model_name[index * 2 + 1];
+			strncpy(ha->model_desc,
+                            qla2x00_model_name[index * 2 + 1],
+                            sizeof(ha->model_desc) - 1);
 		} else {
 			strcpy(ha->model_number, def);
 		}
 	}
+
+	if (IS_FWI2_CAPABLE(ha))
+		qla2xxx_get_vpd_field(ha, "\x82", ha->model_desc,
+		    sizeof(ha->model_desc));
 }
 
 /*
@@ -4012,7 +4053,7 @@ qla2x00_try_to_stop_firmware(scsi_qla_host_t *ha)
 
 	ret = qla2x00_stop_firmware(ha);
 	for (retries = 5; ret != QLA_SUCCESS && ret != QLA_FUNCTION_TIMEOUT &&
-	    retries ; retries--) {
+	    ret != QLA_INVALID_COMMAND && retries ; retries--) {
 		ha->isp_ops->reset_chip(ha);
 		if (ha->isp_ops->chip_diag(ha) != QLA_SUCCESS)
 			continue;
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index dd8e7df..c997a9e 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -893,6 +893,9 @@ qla2x00_get_adapter_id(scsi_qla_host_t *ha, uint16_t *id, uint8_t *al_pa,
 	mcp->mb[9] = ha->vp_idx;
 	mcp->out_mb = MBX_9|MBX_0;
 	mcp->in_mb = MBX_9|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+	if (IS_QLA81XX(ha))
+		mcp->in_mb |= MBX_13|MBX_12|MBX_11|MBX_10;
+
 	mcp->tov = 30;
 	mcp->flags = 0;
 	rval = qla2x00_mailbox_command(ha, mcp);
@@ -915,6 +918,17 @@ qla2x00_get_adapter_id(scsi_qla_host_t *ha, uint16_t *id, uint8_t *al_pa,
 		/*EMPTY*/
 		DEBUG11(printk("qla2x00_get_adapter_id(%ld): done.\n",
 		    ha->host_no));
+		if (IS_QLA81XX(ha)) {
+                        ha->fcoe_vlan_id = mcp->mb[9] & 0xfff;
+                        ha->fcoe_fcf_idx = mcp->mb[10];
+                        ha->fcoe_vn_port_mac[5] = mcp->mb[11] >> 8;
+                        ha->fcoe_vn_port_mac[4] = mcp->mb[11] & 0xff;
+                        ha->fcoe_vn_port_mac[3] = mcp->mb[12] >> 8;
+                        ha->fcoe_vn_port_mac[2] = mcp->mb[12] & 0xff;
+                        ha->fcoe_vn_port_mac[1] = mcp->mb[13] >> 8;
+                        ha->fcoe_vn_port_mac[0] = mcp->mb[13] & 0xff;
+                }
+
 	}
 
 	return rval;
@@ -2383,6 +2397,8 @@ qla2x00_stop_firmware(scsi_qla_host_t *ha)
 	if (rval != QLA_SUCCESS) {
 		DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
 		    ha->host_no, rval));
+		if (mcp->mb[0] == MBS_INVALID_COMMAND)
+			rval = QLA_INVALID_COMMAND;
 	} else {
 		DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
 	}
@@ -3217,3 +3233,40 @@ qla81xx_fac_erase_sector(scsi_qla_host_t *ha, uint32_t start, uint32_t finish)
         return rval;
 }
 
+int
+qla2x00_get_dcbx_params(scsi_qla_host_t *ha, dma_addr_t tlv_dma,
+    uint16_t size)
+{
+        int rval;
+        mbx_cmd_t mc;
+        mbx_cmd_t *mcp = &mc;
+
+        if (!IS_QLA81XX(ha))
+                return QLA_FUNCTION_FAILED;
+
+        DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+
+        mcp->mb[0] = MBC_GET_DCBX_PARAMS;
+        mcp->mb[1] = 0;
+        mcp->mb[2] = MSW(tlv_dma);
+        mcp->mb[3] = LSW(tlv_dma);
+        mcp->mb[6] = MSW(MSD(tlv_dma));
+        mcp->mb[7] = LSW(MSD(tlv_dma));
+        mcp->mb[8] = size;
+        mcp->out_mb = MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+        mcp->in_mb = MBX_2|MBX_1|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 mb[0]=0x%x "
+                    "mb[1]=0x%x mb[2]=0x%x.\n", __func__, ha->host_no, rval,
+                    mcp->mb[0], mcp->mb[1], mcp->mb[2]));
+        } else {
+                DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
+        }
+
+        return rval;
+}
+ 
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 6ad44ea..16eb173 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -1159,7 +1159,7 @@ qla2x00_loop_reset(scsi_qla_host_t *ha)
 	int ret;
 	struct fc_port *fcport;
 
-	if (ha->flags.enable_lip_full_login) {
+	if (ha->flags.enable_lip_full_login && !IS_QLA81XX(ha)) {
 		ret = qla2x00_full_login_lip(ha);
 		if (ret != QLA_SUCCESS) {
 			DEBUG2_3(printk("%s(%ld): bus_reset failed: "
@@ -2531,6 +2531,10 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
 		    (ha->request_q_length + 1) * sizeof(request_t),
 		    ha->request_ring, ha->request_dma);
 
+	if (ha->dcbx_tlv)
+		dma_free_coherent(&ha->pdev->dev, DCBX_TLV_DATA_SIZE,
+		    ha->dcbx_tlv, ha->dcbx_tlv_dma);
+
 	ha->ex_init_cb = NULL;
 	ha->ex_init_cb_dma = 0;
 	ha->eft = NULL;
@@ -2545,6 +2549,8 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
 	ha->ms_iocb_dma = 0;
 	ha->init_cb = NULL;
 	ha->init_cb_dma = 0;
+	ha->dcbx_tlv = NULL;
+	ha->dcbx_tlv_dma = 0;
 
 	ha->s_dma_pool = NULL;
 
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index 4ab6f05..a96bd14 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -2636,3 +2636,49 @@ qla24xx_get_flash_version(scsi_qla_host_t *ha, void *mbuf)
 
 	return ret;
 }
+
+static int
+qla2xxx_is_vpd_valid(uint8_t *pos, uint8_t *end)
+{
+        if (pos >= end || *pos != 0x82)
+                return 0;
+
+        pos += 3 + pos[1];
+        if (pos >= end || *pos != 0x90)
+                return 0;
+
+        pos += 3 + pos[1];
+        if (pos >= end || *pos != 0x78)
+                return 0;
+
+        return 1;
+}
+
+int
+qla2xxx_get_vpd_field(scsi_qla_host_t *ha, char *key, char *str, size_t size)
+{
+        uint8_t *pos = ha->vpd;
+        uint8_t *end = pos + ha->vpd_size;
+        int len = 0;
+
+        if (!IS_FWI2_CAPABLE(ha) || !qla2xxx_is_vpd_valid(pos, end))
+                return 0;
+
+        while (pos < end && *pos != 0x78) {
+                len = (*pos == 0x82) ? pos[1] : pos[2];
+
+                if (!strncmp(pos, key, strlen(key)))
+                        break;
+
+                if (*pos != 0x90 && *pos != 0x91)
+                        pos += len;
+
+                pos += 3;
+        }
+
+        if (pos < end - len && *pos != 0x78)
+                return snprintf(str, size, "%.*s", len, pos + 3);
+
+        return 0;
+}
+
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index 710b9c1..edf6dce 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.03.05.04-k"
+#define QLA2XXX_VERSION      "8.03.00.04.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	3
+#define QLA_DRIVER_BETA_VER	4