From b7cc176c9eb3aa6989ac099efd8bdd6d0eaa784a Mon Sep 17 00:00:00 2001 From: Joe Carnuccio Date: Thu, 20 Sep 2007 14:07:35 -0700 Subject: [PATCH] [SCSI] qla2xxx: Allow region-based flash-part accesses. Additional cleanups and Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_attr.c | 108 ++++++++++++++++++++++++++------ drivers/scsi/qla2xxx/qla_def.h | 2 + drivers/scsi/qla2xxx/qla_fw.h | 2 + drivers/scsi/qla2xxx/qla_sup.c | 4 +- 4 files changed, 96 insertions(+), 20 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 0f2a9f5d801c..8e7e00cf7e81 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -175,10 +175,10 @@ qla2x00_sysfs_read_optrom(struct kobject *kobj, if (ha->optrom_state != QLA_SREADING) return 0; - if (off > ha->optrom_size) + if (off > ha->optrom_region_size) return 0; - if (off + count > ha->optrom_size) - count = ha->optrom_size - off; + if (off + count > ha->optrom_region_size) + count = ha->optrom_region_size - off; memcpy(buf, &ha->optrom_buffer[off], count); @@ -195,10 +195,10 @@ qla2x00_sysfs_write_optrom(struct kobject *kobj, if (ha->optrom_state != QLA_SWRITING) return -EINVAL; - if (off > ha->optrom_size) + if (off > ha->optrom_region_size) return -ERANGE; - if (off + count > ha->optrom_size) - count = ha->optrom_size - off; + if (off + count > ha->optrom_region_size) + count = ha->optrom_region_size - off; memcpy(&ha->optrom_buffer[off], buf, count); @@ -222,12 +222,16 @@ qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj, { struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, struct device, kobj))); - int val; + uint32_t start = 0; + uint32_t size = ha->optrom_size; + int val, valid; if (off) return 0; - if (sscanf(buf, "%d", &val) != 1) + if (sscanf(buf, "%d:%x:%x", &val, &start, &size) < 1) + return -EINVAL; + if (start > ha->optrom_size) return -EINVAL; switch (val) { @@ -237,6 +241,11 @@ qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj, break; ha->optrom_state = QLA_SWAITING; + + DEBUG2(qla_printk(KERN_INFO, ha, + "Freeing flash region allocation -- 0x%x bytes.\n", + ha->optrom_region_size)); + vfree(ha->optrom_buffer); ha->optrom_buffer = NULL; break; @@ -244,44 +253,107 @@ qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj, if (ha->optrom_state != QLA_SWAITING) break; + if (start & 0xfff) { + qla_printk(KERN_WARNING, ha, + "Invalid start region 0x%x/0x%x.\n", start, size); + return -EINVAL; + } + + ha->optrom_region_start = start; + ha->optrom_region_size = start + size > ha->optrom_size ? + ha->optrom_size - start : size; + ha->optrom_state = QLA_SREADING; - ha->optrom_buffer = (uint8_t *)vmalloc(ha->optrom_size); + ha->optrom_buffer = vmalloc(ha->optrom_region_size); if (ha->optrom_buffer == NULL) { qla_printk(KERN_WARNING, ha, "Unable to allocate memory for optrom retrieval " - "(%x).\n", ha->optrom_size); + "(%x).\n", ha->optrom_region_size); ha->optrom_state = QLA_SWAITING; return count; } - memset(ha->optrom_buffer, 0, ha->optrom_size); - ha->isp_ops->read_optrom(ha, ha->optrom_buffer, 0, - ha->optrom_size); + DEBUG2(qla_printk(KERN_INFO, ha, + "Reading flash region -- 0x%x/0x%x.\n", + ha->optrom_region_start, ha->optrom_region_size)); + + memset(ha->optrom_buffer, 0, ha->optrom_region_size); + ha->isp_ops->read_optrom(ha, ha->optrom_buffer, + ha->optrom_region_start, ha->optrom_region_size); break; case 2: if (ha->optrom_state != QLA_SWAITING) break; + /* + * We need to be more restrictive on which FLASH regions are + * allowed to be updated via user-space. Regions accessible + * via this method include: + * + * ISP21xx/ISP22xx/ISP23xx type boards: + * + * 0x000000 -> 0x020000 -- Boot code. + * + * ISP2322/ISP24xx type boards: + * + * 0x000000 -> 0x07ffff -- Boot code. + * 0x080000 -> 0x0fffff -- Firmware. + * + * ISP25xx type boards: + * + * 0x000000 -> 0x07ffff -- Boot code. + * 0x080000 -> 0x0fffff -- Firmware. + * 0x120000 -> 0x12ffff -- VPD and HBA parameters. + */ + 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)) + valid = 1; + else if (IS_QLA25XX(ha) && start == (FA_VPD_NVRAM_ADDR*4)) + valid = 1; + if (!valid) { + qla_printk(KERN_WARNING, ha, + "Invalid start region 0x%x/0x%x.\n", start, size); + return -EINVAL; + } + + ha->optrom_region_start = start; + ha->optrom_region_size = start + size > ha->optrom_size ? + ha->optrom_size - start : size; + ha->optrom_state = QLA_SWRITING; - ha->optrom_buffer = (uint8_t *)vmalloc(ha->optrom_size); + ha->optrom_buffer = vmalloc(ha->optrom_region_size); if (ha->optrom_buffer == NULL) { qla_printk(KERN_WARNING, ha, "Unable to allocate memory for optrom update " - "(%x).\n", ha->optrom_size); + "(%x).\n", ha->optrom_region_size); ha->optrom_state = QLA_SWAITING; return count; } - memset(ha->optrom_buffer, 0, ha->optrom_size); + + DEBUG2(qla_printk(KERN_INFO, ha, + "Staging flash region write -- 0x%x/0x%x.\n", + ha->optrom_region_start, ha->optrom_region_size)); + + memset(ha->optrom_buffer, 0, ha->optrom_region_size); break; case 3: if (ha->optrom_state != QLA_SWRITING) break; - ha->isp_ops->write_optrom(ha, ha->optrom_buffer, 0, - ha->optrom_size); + DEBUG2(qla_printk(KERN_INFO, ha, + "Writing flash region -- 0x%x/0x%x.\n", + ha->optrom_region_start, ha->optrom_region_size)); + + ha->isp_ops->write_optrom(ha, ha->optrom_buffer, + ha->optrom_region_start, ha->optrom_region_size); break; + default: + count = -EINVAL; } return count; } diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 4af08561883d..e1e342889b2b 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -2478,6 +2478,8 @@ typedef struct scsi_qla_host { #define QLA_SWAITING 0 #define QLA_SREADING 1 #define QLA_SWRITING 2 + uint32_t optrom_region_start; + uint32_t optrom_region_size; /* PCI expansion ROM image information. */ #define ROM_CODE_TYPE_BIOS 0 diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index 99fe49618d61..d5344d7a8625 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -779,6 +779,8 @@ struct device_reg_24xx { #define FA_NVRAM_VPD_SIZE 0x200 #define FA_NVRAM_VPD0_ADDR 0x00 #define FA_NVRAM_VPD1_ADDR 0x100 + +#define FA_BOOT_CODE_ADDR 0x00000 /* * RISC code begins at offset 512KB * within flash. Consisting of two diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index ad3d1de51d8c..40b059fc1981 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -559,7 +559,7 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, ret = QLA_SUCCESS; /* Prepare burst-capable write on supported ISPs. */ - if (IS_QLA25XX(ha) && !(faddr & ~OPTROM_BURST_SIZE) && + if (IS_QLA25XX(ha) && !(faddr & 0xfff) && dwords > OPTROM_BURST_DWORDS) { optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, &optrom_dma, GFP_KERNEL); @@ -1824,7 +1824,7 @@ qla25xx_read_optrom_data(struct scsi_qla_host *ha, uint8_t *buf, uint8_t *pbuf; uint32_t faddr, left, burst; - if (offset & ~OPTROM_BURST_SIZE) + if (offset & 0xfff) goto slow_read; if (length < OPTROM_BURST_SIZE) goto slow_read;