From cbc8eb67da11a4972834f61fe4729f4c037a17c9 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Wed, 3 Jun 2009 09:55:17 -0700 Subject: [SCSI] qla2xxx: Fallback to 'golden-firmware' operation on supported ISPs. In case the onboard firmware is unable to be read or loaded for operation, attempt to fallback to a limited-operational firmware image stored in a different flash region. This will allow a user to reflash and correct a board with proper operational firmware. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_def.h | 2 ++ drivers/scsi/qla2xxx/qla_fw.h | 1 + drivers/scsi/qla2xxx/qla_init.c | 33 +++++++++++++++++++++++++-------- drivers/scsi/qla2xxx/qla_os.c | 7 +++++++ drivers/scsi/qla2xxx/qla_sup.c | 3 +++ 5 files changed, 38 insertions(+), 8 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 4e846ae928a..88ddae0e2b8 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -2223,6 +2223,7 @@ struct qla_hw_data { uint32_t fac_supported :1; uint32_t chip_reset_done :1; uint32_t port0 :1; + uint32_t running_gold_fw :1; } flags; /* This spinlock is used to protect "io transactions", you must @@ -2523,6 +2524,7 @@ struct qla_hw_data { uint32_t flt_region_vpd; uint32_t flt_region_nvram; uint32_t flt_region_npiv_conf; + uint32_t flt_region_gold_fw; /* 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 152d16c77f3..9e56d4a4cb7 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -1241,6 +1241,7 @@ struct qla_flt_header { #define FLT_REG_HW_EVENT_1 0x1f #define FLT_REG_NPIV_CONF_0 0x29 #define FLT_REG_NPIV_CONF_1 0x2a +#define FLT_REG_GOLD_FW 0x2f struct qla_flt_region { uint32_t code; diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index a7abc103548..34e6508bbab 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -3806,11 +3806,11 @@ qla24xx_nvram_config(scsi_qla_host_t *vha) } static int -qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr) +qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr, + uint32_t faddr) { int rval = QLA_SUCCESS; int segments, fragment; - uint32_t faddr; uint32_t *dcode, dlen; uint32_t risc_addr; uint32_t risc_size; @@ -3819,12 +3819,11 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr) struct req_que *req = ha->req_q_map[0]; qla_printk(KERN_INFO, ha, - "FW: Loading from flash (%x)...\n", ha->flt_region_fw); + "FW: Loading from flash (%x)...\n", faddr); rval = QLA_SUCCESS; segments = FA_RISC_CODE_SEGMENTS; - faddr = ha->flt_region_fw; dcode = (uint32_t *)req->ring; *srisc_addr = 0; @@ -4124,27 +4123,45 @@ qla24xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr) if (rval == QLA_SUCCESS) return rval; - return qla24xx_load_risc_flash(vha, srisc_addr); + return qla24xx_load_risc_flash(vha, srisc_addr, + vha->hw->flt_region_fw); } int qla81xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr) { int rval; + struct qla_hw_data *ha = vha->hw; if (ql2xfwloadbin == 2) - return qla24xx_load_risc(vha, srisc_addr); + goto try_blob_fw; /* * FW Load priority: * 1) Firmware residing in flash. * 2) Firmware via request-firmware interface (.bin file). + * 3) Golden-Firmware residing in flash -- limited operation. */ - rval = qla24xx_load_risc_flash(vha, srisc_addr); + rval = qla24xx_load_risc_flash(vha, srisc_addr, ha->flt_region_fw); if (rval == QLA_SUCCESS) return rval; - return qla24xx_load_risc_blob(vha, srisc_addr); +try_blob_fw: + rval = qla24xx_load_risc_blob(vha, srisc_addr); + if (rval == QLA_SUCCESS || !ha->flt_region_gold_fw) + return rval; + + qla_printk(KERN_ERR, ha, + "FW: Attempting to fallback to golden firmware...\n"); + rval = qla24xx_load_risc_flash(vha, srisc_addr, ha->flt_region_gold_fw); + if (rval != QLA_SUCCESS) + return rval; + + qla_printk(KERN_ERR, ha, + "FW: Please update operational firmware...\n"); + ha->flags.running_gold_fw = 1; + + return rval; } void diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 181ed971a2f..128b3d5c966 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1690,6 +1690,9 @@ qla2xxx_scan_start(struct Scsi_Host *shost) { scsi_qla_host_t *vha = shost_priv(shost); + if (vha->hw->flags.running_gold_fw) + return; + set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); set_bit(RSCN_UPDATE, &vha->dpc_flags); @@ -1962,6 +1965,9 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) "Can't create queues, falling back to single" " queue mode\n"); + if (ha->flags.running_gold_fw) + goto skip_dpc; + /* * Startup the kernel thread for this host adapter */ @@ -1974,6 +1980,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) goto probe_failed; } +skip_dpc: list_add_tail(&base_vha->list, &ha->vp_list); base_vha->host->irq = ha->pdev->irq; diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index e239203f19f..6260505dceb 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -728,6 +728,9 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr) if (!ha->flags.port0) ha->flt_region_npiv_conf = start; break; + case FLT_REG_GOLD_FW: + ha->flt_region_gold_fw = start; + break; } } goto done; -- cgit v1.2.3