From: Marcus Barrow <mbarrow@redhat.com> Date: Tue, 30 Sep 2008 15:12:33 -0400 Subject: [scsi] qla2xxx: use the NPIV table to instantiate port Message-id: 20080930191233.22441.22512.sendpatchset@file.bos.redhat.com O-Subject: [rhel 5.3 patch] qla2xxx - NPIV, store virtual ports for persistence Bugzilla: 459015 RH-Acked-by: Pete Zaitcev <zaitcev@redhat.com> BZ 459015 qla2xxx - NPIV, store virtual ports for persistence [3/3] HP has a requirement to allow up to 32 Vports to be supplied via a boot code mechanism and stored in FLASH on the adapter. The driver will read these entries and instantiate these Vports during init time. These patches are upstream. qla2xxx: Add NPIV-Config Table support. >From commit 0a941c5b9a9ea2a52736ab9e8d2319385c614a85 diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index f5eb432..ac50c39 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -304,10 +304,11 @@ qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj, char *buf, loff_t off, valid = 0; if (ha->optrom_size == OPTROM_SIZE_2300 && start == 0) valid = 1; - else if (start == (FA_BOOT_CODE_ADDR*4) || - start == (FA_RISC_CODE_ADDR*4)) + else if (start == (ha->flt_region_boot * 4) || + start == (ha->flt_region_fw * 4)) valid = 1; - else if (IS_QLA25XX(ha) && start == (FA_VPD_NVRAM_ADDR*4)) + else if (IS_QLA25XX(ha) && + start == (ha->flt_region_vpd_nvram * 4)) valid = 1; if (!valid) { qla_printk(KERN_WARNING, ha, @@ -1075,34 +1076,24 @@ qla2x00_total_isp_aborts_show(struct class_device *cdev, char *buf) ha->qla_stats.total_isp_aborts); } -static ssize_t -qla24xx_vport_create(struct class_device *cdev, const char *buf, size_t count) +scsi_qla_host_t * +qla24xx_vport_create(scsi_qla_host_t *ha, uint64_t fc_wwpn, uint64_t fc_wwnn) { int ret = 0; - int cnt = count; - scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); scsi_qla_host_t *vha; - /* count may include a LF at end of string */ - if (buf[cnt-1] == '\n') - cnt--; - - /* validate we have enough characters for WWPN */ - if ((cnt != (16+1+16)) || (buf[16] != ':')) - return -EINVAL; - - ret = qla24xx_vport_create_req_sanity_check(ha, buf); + ret = qla24xx_vport_create_req_sanity_check(ha, fc_wwpn, fc_wwnn); if (ret) { DEBUG15(printk("qla24xx_vport_create_req_sanity_check failed, " "status %x\n", ret)); - return (ret); + return NULL; } - vha = qla24xx_create_vhost(ha, buf); + vha = qla24xx_create_vhost(ha, fc_wwpn, fc_wwnn); if (vha == NULL) { DEBUG15(printk ("qla24xx_create_vhost failed, vha = %p\n", vha)); - return -EINVAL; + return NULL; } atomic_set(&vha->vp_state, VP_FAILED); @@ -1139,7 +1130,7 @@ qla24xx_vport_create(struct class_device *cdev, const char *buf, size_t count) qla24xx_enable_vp(vha); - return count; + return vha; vport_create_failed_2: qla24xx_disable_vp(vha); @@ -1147,7 +1138,33 @@ vport_create_failed_2: kfree(vha->port_name); kfree(vha->node_name); scsi_host_put(vha->host); - return -EINVAL; + return NULL; +} + +static ssize_t +qla24xx_vport_create_cdev(struct class_device *cdev, const char *buf, + size_t count) +{ + int cnt = count; + scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + uint64_t fc_wwpn; + uint64_t fc_wwnn; + + /* count may include a LF at end of string */ + if (buf[cnt-1] == '\n') + cnt--; + + /* validate we have enough characters for WWPN */ + if ((cnt != (16+1+16)) || (buf[16] != ':')) + return -EINVAL; + + if (fc_parse_wwn(&buf[0], &fc_wwpn)) + return -EINVAL; + + if (fc_parse_wwn(&buf[17], &fc_wwnn)) + return -EINVAL; + + return qla24xx_vport_create(ha, fc_wwpn, fc_wwnn) ? count: -EINVAL; } static ssize_t @@ -1436,7 +1453,7 @@ static CLASS_DEVICE_ATTR(optrom_fw_version, S_IRUGO, qla2x00_optrom_fw_version_show, NULL); static CLASS_DEVICE_ATTR(total_isp_aborts, S_IRUGO, qla2x00_total_isp_aborts_show, NULL); -static CLASS_DEVICE_ATTR(vport_create, S_IWUGO, NULL, qla24xx_vport_create); +static CLASS_DEVICE_ATTR(vport_create, S_IWUGO, NULL, qla24xx_vport_create_cdev); static CLASS_DEVICE_ATTR(vport_delete, S_IWUGO, NULL, qla24xx_vport_delete); static CLASS_DEVICE_ATTR(max_npiv_vports, S_IRUGO, qla24xx_max_npiv_vports_show, NULL); @@ -1811,6 +1828,8 @@ struct fc_function_template qla2xxx_transport_functions = { .terminate_rport_io = qla2x00_terminate_rport_io, .dev_loss_tmo_callbk = qla2x00_dev_loss_tmo_callbk, .terminate_rport_io = qla2x00_terminate_rport_io, + .dev_loss_tmo_callbk = qla2x00_dev_loss_tmo_callbk, + .terminate_rport_io = qla2x00_terminate_rport_io, .get_fc_host_stats = qla2x00_get_fc_host_stats, }; diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index c455a00..391fda3 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -2312,6 +2312,7 @@ 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 uint32_t device_flags; #define DFLG_LOCAL_DEVICES BIT_0 @@ -2615,6 +2616,14 @@ typedef struct scsi_qla_host { uint32_t fdt_unprotect_sec_cmd; uint32_t fdt_protect_sec_cmd; + uint32_t flt_region_flt; + uint32_t flt_region_fdt; + uint32_t flt_region_boot; + uint32_t flt_region_fw; + uint32_t flt_region_vpd_nvram; + uint32_t flt_region_hw_event; + uint32_t flt_region_npiv_conf; + /* Needed for BEACON */ uint16_t beacon_blink_led; uint8_t beacon_color_state; diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index 4f2f83f..1f29ffb 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -789,14 +789,20 @@ struct device_reg_24xx { #define FA_RISC_CODE_ADDR 0x20000 #define FA_RISC_CODE_SEGMENTS 2 +#define FA_FLASH_DESCR_ADDR_24 0x11000 +#define FA_FLASH_LAYOUT_ADDR_24 0x11400 +#define FA_NPIV_CONF0_ADDR_24 0x16000 +#define FA_NPIV_CONF1_ADDR_24 0x17000 + #define FA_FW_AREA_ADDR 0x40000 #define FA_VPD_NVRAM_ADDR 0x48000 #define FA_FEATURE_ADDR 0x4C000 #define FA_FLASH_DESCR_ADDR 0x50000 -#define FA_HW_EVENT_ADDR 0x54000 -#define FA_BOOT_LOG_ADDR 0x58000 -#define FA_FW_DUMP0_ADDR 0x60000 -#define FA_FW_DUMP1_ADDR 0x70000 +#define FA_FLASH_LAYOUT_ADDR 0x50400 +#define FA_HW_EVENT0_ADDR 0x54000 +#define FA_HW_EVENT1_ADDR 0x54400 +#define FA_NPIV_CONF0_ADDR 0x5C000 +#define FA_NPIV_CONF1_ADDR 0x5D000 uint32_t flash_data; /* Flash/NVRAM BIOS data. */ @@ -1194,6 +1200,43 @@ struct qla_fdt_layout { uint8_t unused2[65]; }; +/* Flash Layout Table ********************************************************/ + +struct qla_flt_location { + uint8_t sig[4]; + uint32_t start_lo; + uint32_t start_hi; + uint16_t unused; + uint16_t checksum; +}; + +struct qla_flt_header { + uint16_t version; + uint16_t length; + uint16_t checksum; + uint16_t unused; +}; + +#define FLT_REG_FW 0x01 +#define FLT_REG_BOOT_CODE 0x07 +#define FLT_REG_VPD_0 0x14 +#define FLT_REG_NVRAM_0 0x15 +#define FLT_REG_VPD_1 0x16 +#define FLT_REG_NVRAM_1 0x07 +#define FLT_REG_FDT 0x1a +#define FLT_REG_FLT 0x1c +#define FLT_REG_HW_EVENT_0 0x1d +#define FLT_REG_HW_EVENT_1 0x1f +#define FLT_REG_NPIV_CONF_0 0x29 +#define FLT_REG_NPIV_CONF_1 0x2a + +struct qla_flt_region { + uint32_t code; + uint32_t size; + uint32_t start; + uint32_t end; +}; + /* 84XX Support ****************************************************/ #define MBA_ISP84XX_ALERT 0x800f /* Alert Notification. */ @@ -1318,4 +1361,23 @@ struct access_chip_rsp_84xx { }; /* End of 84XX Support ************************************************/ +/* Flash NPIV Configuration Table ********************************************/ + +struct qla_npiv_header { + uint8_t sig[2]; + uint16_t version; + uint16_t entries; + uint16_t unused[4]; + uint16_t checksum; +}; + +struct qla_npiv_entry { + uint16_t flags; + uint16_t vf_id; + uint16_t qos; + uint16_t unused1; + uint8_t port_name[WWN_SIZE]; + uint8_t node_name[WWN_SIZE]; +}; + #endif diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 0c284b3..82764a8 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -92,9 +92,10 @@ extern void qla24xx_report_id_acquisition(scsi_qla_host_t *, extern scsi_qla_host_t * qla24xx_find_vhost_by_name(scsi_qla_host_t *, uint8_t *); extern void qla2x00_do_dpc_all_vps(scsi_qla_host_t *); -extern int qla24xx_vport_create_req_sanity_check(scsi_qla_host_t *, - const char *); -extern scsi_qla_host_t * qla24xx_create_vhost(scsi_qla_host_t *, const char *); +extern int qla24xx_vport_create_req_sanity_check(scsi_qla_host_t *, uint64_t, + uint64_t); +extern scsi_qla_host_t *qla24xx_create_vhost(scsi_qla_host_t *, uint64_t, + uint64_t); extern void qla2x00_sp_compl(scsi_qla_host_t *, srb_t *); @@ -283,7 +284,6 @@ extern uint8_t *qla24xx_read_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t, uint32_t); extern int qla2x00_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t, uint32_t); -extern void qla2xxx_get_flash_info(scsi_qla_host_t *); extern int qla24xx_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t, uint32_t); extern uint8_t *qla25xx_read_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t, @@ -312,6 +312,10 @@ extern uint8_t *qla25xx_read_optrom_data(struct scsi_qla_host *, uint8_t *, extern int qla2x00_get_flash_version(scsi_qla_host_t *, void *); extern int qla24xx_get_flash_version(scsi_qla_host_t *, void *); +extern int qla2xxx_get_flash_info(scsi_qla_host_t *); + +extern void qla2xxx_flash_npiv_conf(scsi_qla_host_t *); + /* * Global Function Prototypes in qla_dbg.c source file. */ @@ -355,11 +359,11 @@ extern struct class_device_attribute *qla24xx_host_attrs[]; extern struct class_device_attribute *qla24xx_host_vport_attrs[]; struct fc_function_template; extern struct fc_function_template qla2xxx_transport_functions; -extern void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *); -extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *); extern void qla2x00_init_host_attr(scsi_qla_host_t *); extern void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *); extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *); +extern scsi_qla_host_t *qla24xx_vport_create(scsi_qla_host_t *, uint64_t, + uint64_t); /* * Global functions in qla_nlk.c diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index 0eee017..290deca 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -383,19 +383,12 @@ fc_convert_hex_char(uint8_t *nm, char *ns, int count) } int -qla24xx_vport_create_req_sanity_check(scsi_qla_host_t *ha, const char *buf) +qla24xx_vport_create_req_sanity_check(scsi_qla_host_t *ha, uint64_t fc_wwpn, + uint64_t fc_wwnn) { scsi_qla_host_t *vha; - uint64_t fc_wwpn; - uint64_t fc_wwnn; uint8_t port_name[WWN_SIZE]; - if (fc_parse_wwn(&buf[0], &fc_wwpn)) - return -EINVAL; - - if (fc_parse_wwn(&buf[17], &fc_wwnn)) - return -EINVAL; - /* Check up whether npiv supported switch presented */ if (!(ha->switch_cap & FLOGI_MID_SUPPORT)) return -EINVAL; @@ -421,12 +414,10 @@ qla24xx_vport_create_req_sanity_check(scsi_qla_host_t *ha, const char *buf) } scsi_qla_host_t * -qla24xx_create_vhost(scsi_qla_host_t *ha, const char *buf) +qla24xx_create_vhost(scsi_qla_host_t *ha, uint64_t fc_wwpn, uint64_t fc_wwnn) { scsi_qla_host_t *vha; struct Scsi_Host *host; - uint64_t fc_wwpn; - uint64_t fc_wwnn; host = scsi_host_alloc(&qla24xx_driver_vport_template, sizeof(scsi_qla_host_t)); @@ -449,12 +440,6 @@ qla24xx_create_vhost(scsi_qla_host_t *ha, const char *buf) if (!vha->port_name) goto create_vhost_failed_2; - if (fc_parse_wwn(&buf[0], &fc_wwpn)) - return NULL; - - if (fc_parse_wwn(&buf[17], &fc_wwnn)) - return NULL; - /* New host info */ u64_to_wwn(fc_wwpn, vha->port_name); u64_to_wwn(fc_wwnn, vha->node_name); diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index fbc3a55..45c7b3a 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1867,6 +1867,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ha->flags.enable_64bit_addressing ? '+': '-', ha->host_no, ha->isp_ops->fw_version_str(ha, fw_str)); + set_bit(NPIV_CONFIG_NEEDED, &ha->dpc_flags); + return 0; probe_failed: @@ -2653,6 +2655,12 @@ qla2x00_do_dpc(void *data) ha->host_no)); } + if (test_bit(NPIV_CONFIG_NEEDED, &ha->dpc_flags) && + atomic_read(&ha->loop_state) == LOOP_READY) { + clear_bit(NPIV_CONFIG_NEEDED, &ha->dpc_flags); + qla2xxx_flash_npiv_conf(ha); + } + if (!ha->interrupts_on) ha->isp_ops->enable_intrs(ha); diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index 220c5c1..11c06b6 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -686,6 +686,14 @@ qla2xxx_get_flt_info(scsi_qla_host_t *ha, uint32_t flt_addr) if (PCI_FUNC(ha->pdev->devfn)) ha->flt_region_hw_event = start; break; + case FLT_REG_NPIV_CONF_0: + if (!PCI_FUNC(ha->pdev->devfn)) + ha->flt_region_npiv_conf = start; + break; + case FLT_REG_NPIV_CONF_1: + if (PCI_FUNC(ha->pdev->devfn)) + ha->flt_region_npiv_conf = start; + break; } } goto done; @@ -700,11 +708,15 @@ no_flash_data: FA_FLASH_DESCR_ADDR; ha->flt_region_hw_event = !PCI_FUNC(ha->pdev->devfn) ? FA_HW_EVENT0_ADDR: FA_HW_EVENT1_ADDR; + ha->flt_region_npiv_conf = !PCI_FUNC(ha->pdev->devfn) ? + (IS_QLA24XX_TYPE(ha) ? FA_NPIV_CONF0_ADDR_24: FA_NPIV_CONF0_ADDR): + (IS_QLA24XX_TYPE(ha) ? FA_NPIV_CONF1_ADDR_24: FA_NPIV_CONF1_ADDR); done: DEBUG2(qla_printk(KERN_DEBUG, ha, "FLT[%s]: boot=0x%x fw=0x%x " - "vpd_nvram=0x%x fdt=0x%x flt=0x%x hwe=0x%x.\n", loc, + "vpd_nvram=0x%x fdt=0x%x flt=0x%x hwe=0x%x npiv=0x%x.\n", loc, ha->flt_region_boot, ha->flt_region_fw, ha->flt_region_vpd_nvram, - ha->flt_region_fdt, ha->flt_region_flt, ha->flt_region_hw_event)); + ha->flt_region_fdt, ha->flt_region_flt, ha->flt_region_hw_event, + ha->flt_region_npiv_conf)); } static void @@ -815,6 +827,75 @@ qla2xxx_get_flash_info(scsi_qla_host_t *ha) return QLA_SUCCESS; } +void +qla2xxx_flash_npiv_conf(scsi_qla_host_t *ha) +{ +#define NPIV_CONFIG_SIZE (16*1024) + void *data; + uint16_t *wptr; + uint16_t cnt, chksum; + struct qla_npiv_header hdr; + struct qla_npiv_entry *entry; + + ha->isp_ops->read_optrom(ha, (uint8_t *)&hdr, + ha->flt_region_npiv_conf << 2, sizeof(struct qla_npiv_header)); + if (hdr.version == __constant_cpu_to_le16(0xffff)) + return; + if (hdr.version != __constant_cpu_to_le16(1)) { + DEBUG2(qla_printk(KERN_INFO, ha, "Unsupported NPIV-Config " + "detected: version=0x%x entries=0x%x checksum=0x%x.\n", + le16_to_cpu(hdr.version), le16_to_cpu(hdr.entries), + le16_to_cpu(hdr.checksum))); + return; + } + + data = kmalloc(NPIV_CONFIG_SIZE, GFP_KERNEL); + if (!data) { + DEBUG2(qla_printk(KERN_INFO, ha, "NPIV-Config: Unable to " + "allocate memory.\n")); + return; + } + + ha->isp_ops->read_optrom(ha, (uint8_t *)data, + ha->flt_region_npiv_conf << 2, NPIV_CONFIG_SIZE); + + cnt = (sizeof(struct qla_npiv_header) + le16_to_cpu(hdr.entries) * + sizeof(struct qla_npiv_entry)) >> 1; + for (wptr = data, chksum = 0; cnt; cnt--) + chksum += le16_to_cpu(*wptr++); + if (chksum) { + DEBUG2(qla_printk(KERN_INFO, ha, "Inconsistent NPIV-Config " + "detected: version=0x%x entries=0x%x checksum=0x%x.\n", + le16_to_cpu(hdr.version), le16_to_cpu(hdr.entries), + chksum)); + goto done; + } + + entry = data + sizeof(struct qla_npiv_header); + cnt = le16_to_cpu(hdr.entries); + for ( ; cnt; cnt--, entry++) { + uint16_t flags; + uint64_t wwpn, wwnn; + + flags = le16_to_cpu(entry->flags); + if (flags == 0xffff) + continue; + if ((flags & BIT_0) == 0) + continue; + + wwpn = wwn_to_u64(entry->port_name); + wwnn = wwn_to_u64(entry->node_name); + + DEBUG2(qla_printk(KERN_DEBUG, ha, "NPIV[%02x]: wwpn=%llx " + "wwnn=%llx vf_id=0x%x qos=0x%x.\n", cnt, wwpn, wwnn, + le16_to_cpu(entry->vf_id), le16_to_cpu(entry->qos))); + + qla24xx_vport_create(ha, wwpn, wwnn); + } +done: + kfree(data); +} + static int qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, uint32_t dwords)