From: Marcus Barrow <mbarrow@redhat.com> Date: Tue, 30 Sep 2008 15:12:23 -0400 Subject: [scsi] qla2xxx: use the Flash Descriptor Table Message-id: 20080930191223.22441.5405.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 [1/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. This patch is required to support this usage of the FLASH and has the added benefit of insulating the driver from changes to memory devices during board manufacturing. Previously all changes to these parts, even among compatable parts, required driver changes. The Flash Descriptor Table (FDT) present on many recent HBAs encodes flash accessing characteristics of the flash-part used on the HBA. Use this information during flash manipulation (writes) rather than using specific hard-coded values based on queried manufacturer and device IDs. >From commit 67a7023e4a7147e476c14ee73f40c4697b7f3065 diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 37ce268..c455a00 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -2608,6 +2608,12 @@ typedef struct scsi_qla_host { uint8_t efi_revision[2]; uint8_t fcode_revision[16]; uint32_t fw_revision[4]; + uint16_t fdt_odd_index; + uint32_t fdt_wrt_disable; + uint32_t fdt_erase_cmd; + uint32_t fdt_block_size; + uint32_t fdt_unprotect_sec_cmd; + uint32_t fdt_protect_sec_cmd; /* 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 31dd1e0..4f2f83f 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -1163,6 +1163,37 @@ struct vf_evfp_entry_24xx { /* END MID Support ***********************************************************/ +/* Flash Description Table ***************************************************/ +struct qla_fdt_layout { + uint8_t sig[4]; + uint16_t version; + uint16_t len; + uint16_t checksum; + uint8_t unused1[2]; + uint8_t model[16]; + uint16_t man_id; + uint16_t id; + uint8_t flags; + uint8_t erase_cmd; + uint8_t alt_erase_cmd; + uint8_t wrt_enable_cmd; + uint8_t wrt_enable_bits; + uint8_t wrt_sts_reg_cmd; + uint8_t unprotect_sec_cmd; + uint8_t read_man_id_cmd; + uint32_t block_size; + uint32_t alt_block_size; + uint32_t flash_size; + uint32_t wrt_enable_data; + uint8_t read_id_addr_len; + uint8_t wrt_disable_bits; + uint8_t read_dev_id_len; + uint8_t chip_erase_cmd; + uint16_t read_timeout; + uint8_t protect_sec_cmd; + uint8_t unused2[65]; +}; + /* 84XX Support ****************************************************/ #define MBA_ISP84XX_ALERT 0x800f /* Alert Notification. */ diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 214b1e3..0c284b3 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -283,6 +283,7 @@ 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, diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index d74a4aa..0cc374b 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -933,6 +933,7 @@ qla2x00_setup_chip(scsi_qla_host_t *ha) &ha->fw_minor_version, &ha->fw_subminor_version, &ha->fw_attributes, &ha->fw_memory_size); + qla2xxx_get_flash_info(ha); qla2x00_resize_request_q(ha); ha->flags.npiv_supported = 0; if ((IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha)) && diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index 6dd7037..7ce5e70 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -543,15 +543,101 @@ qla24xx_get_flash_manufacturer(scsi_qla_host_t *ha, uint8_t *man_id, } } + +void +qla2xxx_get_flash_info(scsi_qla_host_t *ha) +{ +#define FLASH_BLK_SIZE_32K 0x8000 +#define FLASH_BLK_SIZE_64K 0x10000 + uint16_t cnt, chksum; + uint16_t *wptr; + struct qla_fdt_layout *fdt; + uint8_t man_id, flash_id; + + if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha)) + return; + + wptr = (uint16_t *)ha->request_ring; + fdt = (struct qla_fdt_layout *)ha->request_ring; + qla24xx_read_flash_data(ha, (uint32_t *)ha->request_ring, + FA_FLASH_DESCR_ADDR, OPTROM_BURST_SIZE >> 2); + if (*wptr == __constant_cpu_to_le16(0xffff)) + goto no_flash_data; + + for (cnt = 0, chksum = 0; cnt < sizeof(struct qla_fdt_layout) >> 1; + cnt++) + chksum += le16_to_cpu(*wptr++); + if (chksum) { + DEBUG2(qla_printk(KERN_INFO, ha, "Inconsistent FDT detected: " + "checksum=0x%x id=%c version=0x%x.\n", chksum, fdt->sig[0], + le16_to_cpu(fdt->version))); + DEBUG9(qla2x00_dump_buffer((uint8_t *)fdt, sizeof(*fdt))); + goto no_flash_data; + } + + ha->fdt_odd_index = le16_to_cpu(fdt->man_id) == 0x1f; + ha->fdt_wrt_disable = fdt->wrt_disable_bits; + ha->fdt_erase_cmd = flash_conf_to_access_addr(0x0300 | fdt->erase_cmd); + ha->fdt_block_size = le32_to_cpu(fdt->block_size); + if (fdt->unprotect_sec_cmd) { + ha->fdt_unprotect_sec_cmd = flash_conf_to_access_addr(0x0300 | + fdt->unprotect_sec_cmd); + ha->fdt_protect_sec_cmd = fdt->protect_sec_cmd ? + flash_conf_to_access_addr(0x0300 | fdt->protect_sec_cmd): + flash_conf_to_access_addr(0x0336); + } + + DEBUG2(qla_printk(KERN_DEBUG, ha, "Flash[FDT]: (0x%x/0x%x) erase=0x%x " + "pro=%x upro=%x idx=%d wrtd=0x%x blk=0x%x.\n", + le16_to_cpu(fdt->man_id), le16_to_cpu(fdt->id), ha->fdt_erase_cmd, + ha->fdt_protect_sec_cmd, ha->fdt_unprotect_sec_cmd, + ha->fdt_odd_index, ha->fdt_wrt_disable, ha->fdt_block_size)); + return; + +no_flash_data: + qla24xx_get_flash_manufacturer(ha, &man_id, &flash_id); + ha->fdt_erase_cmd = flash_conf_to_access_addr(0x03d8); + switch (man_id) { + case 0xbf: /* STT flash. */ + if (flash_id == 0x8e) + ha->fdt_block_size = FLASH_BLK_SIZE_64K; + else + ha->fdt_block_size = FLASH_BLK_SIZE_32K; + + if (flash_id == 0x80) + ha->fdt_erase_cmd = flash_conf_to_access_addr(0x0352); + break; + case 0x13: /* ST M25P80. */ + ha->fdt_block_size = FLASH_BLK_SIZE_64K; + break; + case 0x1f: /* Atmel 26DF081A. */ + ha->fdt_odd_index = 1; + ha->fdt_block_size = FLASH_BLK_SIZE_64K; + ha->fdt_erase_cmd = flash_conf_to_access_addr(0x0320); + ha->fdt_unprotect_sec_cmd = flash_conf_to_access_addr(0x0339); + ha->fdt_protect_sec_cmd = flash_conf_to_access_addr(0x0336); + break; + default: + /* Default to 64 kb sector size. */ + ha->fdt_block_size = FLASH_BLK_SIZE_64K; + break; + } + + DEBUG2(qla_printk(KERN_DEBUG, ha, "Flash[MID]: (0x%x/0x%x) erase=0x%x " + "pro=%x upro=%x idx=%d wrtd=0x%x blk=0x%x.\n", man_id, flash_id, + ha->fdt_erase_cmd, ha->fdt_protect_sec_cmd, + ha->fdt_unprotect_sec_cmd, ha->fdt_odd_index, ha->fdt_wrt_disable, + ha->fdt_block_size)); +} + static int qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, uint32_t dwords) { int ret; uint32_t liter, miter; - uint32_t sec_mask, rest_addr, conf_addr; + uint32_t sec_mask, rest_addr; uint32_t fdata, findex, cnt; - uint8_t man_id, flash_id; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; dma_addr_t optrom_dma; void *optrom = NULL; @@ -571,51 +657,28 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, } } - qla24xx_get_flash_manufacturer(ha, &man_id, &flash_id); - DEBUG9(printk("%s(%ld): Flash man_id=%d flash_id=%d\n", __func__, - ha->host_no, man_id, flash_id)); - - conf_addr = flash_conf_to_access_addr(0x03d8); - switch (man_id) { - case 0xbf: /* STT flash. */ - if (flash_id == 0x8e) { - rest_addr = 0x3fff; - sec_mask = 0x7c000; - } else { - rest_addr = 0x1fff; - sec_mask = 0x7e000; - } - if (flash_id == 0x80) - conf_addr = flash_conf_to_access_addr(0x0352); - break; - case 0x13: /* ST M25P80. */ - rest_addr = 0x3fff; - sec_mask = 0x7c000; - break; - case 0x1f: // Atmel 26DF081A - rest_addr = 0x3fff; - sec_mask = 0x7c000; - conf_addr = flash_conf_to_access_addr(0x0320); - break; - default: - /* Default to 64 kb sector size. */ - rest_addr = 0x3fff; - sec_mask = 0x7c000; - break; - } + rest_addr = (ha->fdt_block_size >> 2) - 1; + sec_mask = 0x80000 - (ha->fdt_block_size >> 2); /* Enable flash write. */ WRT_REG_DWORD(®->ctrl_status, RD_REG_DWORD(®->ctrl_status) | CSRX_FLASH_ENABLE); RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ - /* Disable flash write-protection. */ - qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0); - /* Some flash parts need an additional zero-write to clear bits.*/ - qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0); + if (ha->fdt_wrt_disable) { + /* Disable flash write-protection. */ + qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), + 0); + /* + * Some flash parts need an additional zero-write to + * clear bits. + */ + qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), + 0); + } for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) { - if (man_id == 0x1f) { + if (ha->fdt_odd_index) { findex = faddr << 2; fdata = findex & sec_mask; } else { @@ -625,13 +688,13 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, /* Are we at the beginning of a sector? */ if ((findex & rest_addr) == 0) { - /* Do sector unprotect at 4K boundry for Atmel part. */ - if (man_id == 0x1f) + /* Do sector unpretect. */ + if (ha->fdt_unprotect_sec_cmd) qla24xx_write_flash_dword(ha, - flash_conf_to_access_addr(0x0339), + ha->fdt_unprotect_sec_cmd, (fdata & 0xff00) | ((fdata << 16) & 0xff0000) | ((fdata >> 16) & 0xff)); - ret = qla24xx_write_flash_dword(ha, conf_addr, + ret = qla24xx_write_flash_dword(ha, ha->fdt_erase_cmd, (fdata & 0xff00) |((fdata << 16) & 0xff0000) | ((fdata >> 16) & 0xff)); if (ret != QLA_SUCCESS) { @@ -681,22 +744,24 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, break; } - /* Do sector protect at 4K boundry for Atmel part. */ - if (man_id == 0x1f && + /* Do sector protect. */ + if (ha->fdt_unprotect_sec_cmd && ((faddr & rest_addr) == rest_addr)) qla24xx_write_flash_dword(ha, - flash_conf_to_access_addr(0x0336), + ha->fdt_protect_sec_cmd, (fdata & 0xff00) | ((fdata << 16) & 0xff0000) | ((fdata >> 16) & 0xff)); } - /* Enable flash write-protection and wait for completion. */ - qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0x9c); - for (cnt = 300; cnt && - qla24xx_read_flash_dword(ha, - flash_conf_to_access_addr(0x005)) & BIT_0; - cnt--) { - udelay(10); + if (ha->fdt_wrt_disable) { + /* Enable flash write-protection and wait for completion. */ + qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), + ha->fdt_wrt_disable); + for (cnt = 300; cnt && + qla24xx_read_flash_dword(ha, + flash_conf_to_access_addr(0x005)) & BIT_0;cnt--) { + udelay(10); + } } /* Disable flash write. */