scsi: qla2xxx: Fix flash read failure

Link up failure is observed as a result of flash read failure.  Current
code does not check flash read return code where it relies on FW checksum
to detect the problem.

Add check of flash read failure to detect the problem sooner.

Reported-by: kernel test robot <lkp@intel.com>
Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
Closes: https://lore.kernel.org/all/202406210815.rPDRDMBi-lkp@intel.com/
Cc: stable@vger.kernel.org
Signed-off-by: Quinn Tran <qutran@marvell.com>
Signed-off-by: Nilesh Javali <njavali@marvell.com>
Link: https://lore.kernel.org/r/20240710171057.35066-6-njavali@marvell.com
Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Quinn Tran 2024-07-10 22:40:51 +05:30 committed by Martin K. Petersen
parent ce2065c4cc
commit 29e222085d
2 changed files with 125 additions and 46 deletions

View File

@ -8221,15 +8221,21 @@ qla28xx_get_aux_images(
struct qla27xx_image_status pri_aux_image_status, sec_aux_image_status; struct qla27xx_image_status pri_aux_image_status, sec_aux_image_status;
bool valid_pri_image = false, valid_sec_image = false; bool valid_pri_image = false, valid_sec_image = false;
bool active_pri_image = false, active_sec_image = false; bool active_pri_image = false, active_sec_image = false;
int rc;
if (!ha->flt_region_aux_img_status_pri) { if (!ha->flt_region_aux_img_status_pri) {
ql_dbg(ql_dbg_init, vha, 0x018a, "Primary aux image not addressed\n"); ql_dbg(ql_dbg_init, vha, 0x018a, "Primary aux image not addressed\n");
goto check_sec_image; goto check_sec_image;
} }
qla24xx_read_flash_data(vha, (uint32_t *)&pri_aux_image_status, rc = qla24xx_read_flash_data(vha, (uint32_t *)&pri_aux_image_status,
ha->flt_region_aux_img_status_pri, ha->flt_region_aux_img_status_pri,
sizeof(pri_aux_image_status) >> 2); sizeof(pri_aux_image_status) >> 2);
if (rc) {
ql_log(ql_log_info, vha, 0x01a1,
"Unable to read Primary aux image(%x).\n", rc);
goto check_sec_image;
}
qla27xx_print_image(vha, "Primary aux image", &pri_aux_image_status); qla27xx_print_image(vha, "Primary aux image", &pri_aux_image_status);
if (qla28xx_check_aux_image_status_signature(&pri_aux_image_status)) { if (qla28xx_check_aux_image_status_signature(&pri_aux_image_status)) {
@ -8260,9 +8266,15 @@ qla28xx_get_aux_images(
goto check_valid_image; goto check_valid_image;
} }
qla24xx_read_flash_data(vha, (uint32_t *)&sec_aux_image_status, rc = qla24xx_read_flash_data(vha, (uint32_t *)&sec_aux_image_status,
ha->flt_region_aux_img_status_sec, ha->flt_region_aux_img_status_sec,
sizeof(sec_aux_image_status) >> 2); sizeof(sec_aux_image_status) >> 2);
if (rc) {
ql_log(ql_log_info, vha, 0x01a2,
"Unable to read Secondary aux image(%x).\n", rc);
goto check_valid_image;
}
qla27xx_print_image(vha, "Secondary aux image", &sec_aux_image_status); qla27xx_print_image(vha, "Secondary aux image", &sec_aux_image_status);
if (qla28xx_check_aux_image_status_signature(&sec_aux_image_status)) { if (qla28xx_check_aux_image_status_signature(&sec_aux_image_status)) {
@ -8320,6 +8332,7 @@ qla27xx_get_active_image(struct scsi_qla_host *vha,
struct qla27xx_image_status pri_image_status, sec_image_status; struct qla27xx_image_status pri_image_status, sec_image_status;
bool valid_pri_image = false, valid_sec_image = false; bool valid_pri_image = false, valid_sec_image = false;
bool active_pri_image = false, active_sec_image = false; bool active_pri_image = false, active_sec_image = false;
int rc;
if (!ha->flt_region_img_status_pri) { if (!ha->flt_region_img_status_pri) {
ql_dbg(ql_dbg_init, vha, 0x018a, "Primary image not addressed\n"); ql_dbg(ql_dbg_init, vha, 0x018a, "Primary image not addressed\n");
@ -8361,8 +8374,14 @@ qla27xx_get_active_image(struct scsi_qla_host *vha,
goto check_valid_image; goto check_valid_image;
} }
qla24xx_read_flash_data(vha, (uint32_t *)(&sec_image_status), rc = qla24xx_read_flash_data(vha, (uint32_t *)(&sec_image_status),
ha->flt_region_img_status_sec, sizeof(sec_image_status) >> 2); ha->flt_region_img_status_sec, sizeof(sec_image_status) >> 2);
if (rc) {
ql_log(ql_log_info, vha, 0x01a3,
"Unable to read Secondary image status(%x).\n", rc);
goto check_valid_image;
}
qla27xx_print_image(vha, "Secondary image", &sec_image_status); qla27xx_print_image(vha, "Secondary image", &sec_image_status);
if (qla27xx_check_image_status_signature(&sec_image_status)) { if (qla27xx_check_image_status_signature(&sec_image_status)) {
@ -8434,11 +8453,10 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr,
"FW: Loading firmware from flash (%x).\n", faddr); "FW: Loading firmware from flash (%x).\n", faddr);
dcode = (uint32_t *)req->ring; dcode = (uint32_t *)req->ring;
qla24xx_read_flash_data(vha, dcode, faddr, 8); rval = qla24xx_read_flash_data(vha, dcode, faddr, 8);
if (qla24xx_risc_firmware_invalid(dcode)) { if (rval || qla24xx_risc_firmware_invalid(dcode)) {
ql_log(ql_log_fatal, vha, 0x008c, ql_log(ql_log_fatal, vha, 0x008c,
"Unable to verify the integrity of flash firmware " "Unable to verify the integrity of flash firmware image (rval %x).\n", rval);
"image.\n");
ql_log(ql_log_fatal, vha, 0x008d, ql_log(ql_log_fatal, vha, 0x008d,
"Firmware data: %08x %08x %08x %08x.\n", "Firmware data: %08x %08x %08x %08x.\n",
dcode[0], dcode[1], dcode[2], dcode[3]); dcode[0], dcode[1], dcode[2], dcode[3]);
@ -8452,7 +8470,12 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr,
for (j = 0; j < segments; j++) { for (j = 0; j < segments; j++) {
ql_dbg(ql_dbg_init, vha, 0x008d, ql_dbg(ql_dbg_init, vha, 0x008d,
"-> Loading segment %u...\n", j); "-> Loading segment %u...\n", j);
qla24xx_read_flash_data(vha, dcode, faddr, 10); rval = qla24xx_read_flash_data(vha, dcode, faddr, 10);
if (rval) {
ql_log(ql_log_fatal, vha, 0x016a,
"-> Unable to read segment addr + size .\n");
return QLA_FUNCTION_FAILED;
}
risc_addr = be32_to_cpu((__force __be32)dcode[2]); risc_addr = be32_to_cpu((__force __be32)dcode[2]);
risc_size = be32_to_cpu((__force __be32)dcode[3]); risc_size = be32_to_cpu((__force __be32)dcode[3]);
if (!*srisc_addr) { if (!*srisc_addr) {
@ -8468,7 +8491,13 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr,
ql_dbg(ql_dbg_init, vha, 0x008e, ql_dbg(ql_dbg_init, vha, 0x008e,
"-> Loading fragment %u: %#x <- %#x (%#lx dwords)...\n", "-> Loading fragment %u: %#x <- %#x (%#lx dwords)...\n",
fragment, risc_addr, faddr, dlen); fragment, risc_addr, faddr, dlen);
qla24xx_read_flash_data(vha, dcode, faddr, dlen); rval = qla24xx_read_flash_data(vha, dcode, faddr, dlen);
if (rval) {
ql_log(ql_log_fatal, vha, 0x016b,
"-> Unable to read fragment(faddr %#x dlen %#lx).\n",
faddr, dlen);
return QLA_FUNCTION_FAILED;
}
for (i = 0; i < dlen; i++) for (i = 0; i < dlen; i++)
dcode[i] = swab32(dcode[i]); dcode[i] = swab32(dcode[i]);
@ -8497,7 +8526,14 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr,
fwdt->length = 0; fwdt->length = 0;
dcode = (uint32_t *)req->ring; dcode = (uint32_t *)req->ring;
qla24xx_read_flash_data(vha, dcode, faddr, 7);
rval = qla24xx_read_flash_data(vha, dcode, faddr, 7);
if (rval) {
ql_log(ql_log_fatal, vha, 0x016c,
"-> Unable to read template size.\n");
goto failed;
}
risc_size = be32_to_cpu((__force __be32)dcode[2]); risc_size = be32_to_cpu((__force __be32)dcode[2]);
ql_dbg(ql_dbg_init, vha, 0x0161, ql_dbg(ql_dbg_init, vha, 0x0161,
"-> fwdt%u template array at %#x (%#x dwords)\n", "-> fwdt%u template array at %#x (%#x dwords)\n",
@ -8523,11 +8559,12 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr,
} }
dcode = fwdt->template; dcode = fwdt->template;
qla24xx_read_flash_data(vha, dcode, faddr, risc_size); rval = qla24xx_read_flash_data(vha, dcode, faddr, risc_size);
if (!qla27xx_fwdt_template_valid(dcode)) { if (rval || !qla27xx_fwdt_template_valid(dcode)) {
ql_log(ql_log_warn, vha, 0x0165, ql_log(ql_log_warn, vha, 0x0165,
"-> fwdt%u failed template validate\n", j); "-> fwdt%u failed template validate (rval %x)\n",
j, rval);
goto failed; goto failed;
} }

View File

@ -555,6 +555,7 @@ qla2xxx_find_flt_start(scsi_qla_host_t *vha, uint32_t *start)
struct qla_flt_location *fltl = (void *)req->ring; struct qla_flt_location *fltl = (void *)req->ring;
uint32_t *dcode = (uint32_t *)req->ring; uint32_t *dcode = (uint32_t *)req->ring;
uint8_t *buf = (void *)req->ring, *bcode, last_image; uint8_t *buf = (void *)req->ring, *bcode, last_image;
int rc;
/* /*
* FLT-location structure resides after the last PCI region. * FLT-location structure resides after the last PCI region.
@ -584,14 +585,24 @@ qla2xxx_find_flt_start(scsi_qla_host_t *vha, uint32_t *start)
pcihdr = 0; pcihdr = 0;
do { do {
/* Verify PCI expansion ROM header. */ /* Verify PCI expansion ROM header. */
qla24xx_read_flash_data(vha, dcode, pcihdr >> 2, 0x20); rc = qla24xx_read_flash_data(vha, dcode, pcihdr >> 2, 0x20);
if (rc) {
ql_log(ql_log_info, vha, 0x016d,
"Unable to read PCI Expansion Rom Header (%x).\n", rc);
return QLA_FUNCTION_FAILED;
}
bcode = buf + (pcihdr % 4); bcode = buf + (pcihdr % 4);
if (bcode[0x0] != 0x55 || bcode[0x1] != 0xaa) if (bcode[0x0] != 0x55 || bcode[0x1] != 0xaa)
goto end; goto end;
/* Locate PCI data structure. */ /* Locate PCI data structure. */
pcids = pcihdr + ((bcode[0x19] << 8) | bcode[0x18]); pcids = pcihdr + ((bcode[0x19] << 8) | bcode[0x18]);
qla24xx_read_flash_data(vha, dcode, pcids >> 2, 0x20); rc = qla24xx_read_flash_data(vha, dcode, pcids >> 2, 0x20);
if (rc) {
ql_log(ql_log_info, vha, 0x0179,
"Unable to read PCI Data Structure (%x).\n", rc);
return QLA_FUNCTION_FAILED;
}
bcode = buf + (pcihdr % 4); bcode = buf + (pcihdr % 4);
/* Validate signature of PCI data structure. */ /* Validate signature of PCI data structure. */
@ -606,7 +617,12 @@ qla2xxx_find_flt_start(scsi_qla_host_t *vha, uint32_t *start)
} while (!last_image); } while (!last_image);
/* Now verify FLT-location structure. */ /* Now verify FLT-location structure. */
qla24xx_read_flash_data(vha, dcode, pcihdr >> 2, sizeof(*fltl) >> 2); rc = qla24xx_read_flash_data(vha, dcode, pcihdr >> 2, sizeof(*fltl) >> 2);
if (rc) {
ql_log(ql_log_info, vha, 0x017a,
"Unable to read FLT (%x).\n", rc);
return QLA_FUNCTION_FAILED;
}
if (memcmp(fltl->sig, "QFLT", 4)) if (memcmp(fltl->sig, "QFLT", 4))
goto end; goto end;
@ -2605,13 +2621,18 @@ qla24xx_read_optrom_data(struct scsi_qla_host *vha, void *buf,
uint32_t offset, uint32_t length) uint32_t offset, uint32_t length)
{ {
struct qla_hw_data *ha = vha->hw; struct qla_hw_data *ha = vha->hw;
int rc;
/* Suspend HBA. */ /* Suspend HBA. */
scsi_block_requests(vha->host); scsi_block_requests(vha->host);
set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags); set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
/* Go with read. */ /* Go with read. */
qla24xx_read_flash_data(vha, buf, offset >> 2, length >> 2); rc = qla24xx_read_flash_data(vha, buf, offset >> 2, length >> 2);
if (rc) {
ql_log(ql_log_info, vha, 0x01a0,
"Unable to perform optrom read(%x).\n", rc);
}
/* Resume HBA. */ /* Resume HBA. */
clear_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags); clear_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
@ -3412,7 +3433,7 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
struct active_regions active_regions = { }; struct active_regions active_regions = { };
if (IS_P3P_TYPE(ha)) if (IS_P3P_TYPE(ha))
return ret; return QLA_SUCCESS;
if (!mbuf) if (!mbuf)
return QLA_FUNCTION_FAILED; return QLA_FUNCTION_FAILED;
@ -3432,20 +3453,31 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
do { do {
/* Verify PCI expansion ROM header. */ /* Verify PCI expansion ROM header. */
qla24xx_read_flash_data(vha, dcode, pcihdr >> 2, 0x20); ret = qla24xx_read_flash_data(vha, dcode, pcihdr >> 2, 0x20);
if (ret) {
ql_log(ql_log_info, vha, 0x017d,
"Unable to read PCI EXP Rom Header(%x).\n", ret);
return QLA_FUNCTION_FAILED;
}
bcode = mbuf + (pcihdr % 4); bcode = mbuf + (pcihdr % 4);
if (memcmp(bcode, "\x55\xaa", 2)) { if (memcmp(bcode, "\x55\xaa", 2)) {
/* No signature */ /* No signature */
ql_log(ql_log_fatal, vha, 0x0059, ql_log(ql_log_fatal, vha, 0x0059,
"No matching ROM signature.\n"); "No matching ROM signature.\n");
ret = QLA_FUNCTION_FAILED; return QLA_FUNCTION_FAILED;
break;
} }
/* Locate PCI data structure. */ /* Locate PCI data structure. */
pcids = pcihdr + ((bcode[0x19] << 8) | bcode[0x18]); pcids = pcihdr + ((bcode[0x19] << 8) | bcode[0x18]);
qla24xx_read_flash_data(vha, dcode, pcids >> 2, 0x20); ret = qla24xx_read_flash_data(vha, dcode, pcids >> 2, 0x20);
if (ret) {
ql_log(ql_log_info, vha, 0x018e,
"Unable to read PCI Data Structure (%x).\n", ret);
return QLA_FUNCTION_FAILED;
}
bcode = mbuf + (pcihdr % 4); bcode = mbuf + (pcihdr % 4);
/* Validate signature of PCI data structure. */ /* Validate signature of PCI data structure. */
@ -3454,8 +3486,7 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
ql_log(ql_log_fatal, vha, 0x005a, ql_log(ql_log_fatal, vha, 0x005a,
"PCI data struct not found pcir_adr=%x.\n", pcids); "PCI data struct not found pcir_adr=%x.\n", pcids);
ql_dump_buffer(ql_dbg_init, vha, 0x0059, dcode, 32); ql_dump_buffer(ql_dbg_init, vha, 0x0059, dcode, 32);
ret = QLA_FUNCTION_FAILED; return QLA_FUNCTION_FAILED;
break;
} }
/* Read version */ /* Read version */
@ -3507,20 +3538,26 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
faddr = ha->flt_region_fw_sec; faddr = ha->flt_region_fw_sec;
} }
qla24xx_read_flash_data(vha, dcode, faddr, 8); ret = qla24xx_read_flash_data(vha, dcode, faddr, 8);
if (qla24xx_risc_firmware_invalid(dcode)) { if (ret) {
ql_log(ql_log_warn, vha, 0x005f, ql_log(ql_log_info, vha, 0x019e,
"Unrecognized fw revision at %x.\n", "Unable to read FW version (%x).\n", ret);
ha->flt_region_fw * 4); return ret;
ql_dump_buffer(ql_dbg_init, vha, 0x005f, dcode, 32);
} else { } else {
for (i = 0; i < 4; i++) if (qla24xx_risc_firmware_invalid(dcode)) {
ha->fw_revision[i] = ql_log(ql_log_warn, vha, 0x005f,
"Unrecognized fw revision at %x.\n",
ha->flt_region_fw * 4);
ql_dump_buffer(ql_dbg_init, vha, 0x005f, dcode, 32);
} else {
for (i = 0; i < 4; i++)
ha->fw_revision[i] =
be32_to_cpu((__force __be32)dcode[4+i]); be32_to_cpu((__force __be32)dcode[4+i]);
ql_dbg(ql_dbg_init, vha, 0x0060, ql_dbg(ql_dbg_init, vha, 0x0060,
"Firmware revision (flash) %u.%u.%u (%x).\n", "Firmware revision (flash) %u.%u.%u (%x).\n",
ha->fw_revision[0], ha->fw_revision[1], ha->fw_revision[0], ha->fw_revision[1],
ha->fw_revision[2], ha->fw_revision[3]); ha->fw_revision[2], ha->fw_revision[3]);
}
} }
/* Check for golden firmware and get version if available */ /* Check for golden firmware and get version if available */
@ -3531,18 +3568,23 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
memset(ha->gold_fw_version, 0, sizeof(ha->gold_fw_version)); memset(ha->gold_fw_version, 0, sizeof(ha->gold_fw_version));
faddr = ha->flt_region_gold_fw; faddr = ha->flt_region_gold_fw;
qla24xx_read_flash_data(vha, dcode, ha->flt_region_gold_fw, 8); ret = qla24xx_read_flash_data(vha, dcode, ha->flt_region_gold_fw, 8);
if (qla24xx_risc_firmware_invalid(dcode)) { if (ret) {
ql_log(ql_log_warn, vha, 0x0056, ql_log(ql_log_info, vha, 0x019f,
"Unrecognized golden fw at %#x.\n", faddr); "Unable to read Gold FW version (%x).\n", ret);
ql_dump_buffer(ql_dbg_init, vha, 0x0056, dcode, 32);
return ret; return ret;
} else {
if (qla24xx_risc_firmware_invalid(dcode)) {
ql_log(ql_log_warn, vha, 0x0056,
"Unrecognized golden fw at %#x.\n", faddr);
ql_dump_buffer(ql_dbg_init, vha, 0x0056, dcode, 32);
return QLA_FUNCTION_FAILED;
}
for (i = 0; i < 4; i++)
ha->gold_fw_version[i] =
be32_to_cpu((__force __be32)dcode[4+i]);
} }
for (i = 0; i < 4; i++)
ha->gold_fw_version[i] =
be32_to_cpu((__force __be32)dcode[4+i]);
return ret; return ret;
} }