diff options
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_sup.c')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_sup.c | 98 |
1 files changed, 96 insertions, 2 deletions
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index 6de1e3bc62a8..e2432ef1ecea 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 @@ -814,6 +826,88 @@ 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; + + if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha)) + return; + + 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; + struct fc_vport_identifiers vid; + struct fc_vport *vport; + + flags = le16_to_cpu(entry->flags); + if (flags == 0xffff) + continue; + if ((flags & BIT_0) == 0) + continue; + + memset(&vid, 0, sizeof(vid)); + vid.roles = FC_PORT_ROLE_FCP_INITIATOR; + vid.vport_type = FC_PORTTYPE_NPIV; + vid.disable = false; + vid.port_name = wwn_to_u64(entry->port_name); + vid.node_name = 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, vid.port_name, + vid.node_name, le16_to_cpu(entry->vf_id), + le16_to_cpu(entry->qos))); + + vport = fc_vport_create(ha->host, 0, &vid); + if (!vport) + qla_printk(KERN_INFO, ha, "NPIV-Config: Failed to " + "create vport [%02x]: wwpn=%llx wwnn=%llx.\n", cnt, + vid.port_name, vid.node_name); + } +done: + kfree(data); +} + static void qla24xx_unprotect_flash(scsi_qla_host_t *ha) { |