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