Skip to content

Commit

Permalink
scsi: qla2xxx: Fix flash read failure
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Quinn Tran authored and Martin K. Petersen committed Jul 11, 2024
1 parent ce2065c commit 29e2220
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 46 deletions.
63 changes: 50 additions & 13 deletions drivers/scsi/qla2xxx/qla_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -8221,15 +8221,21 @@ qla28xx_get_aux_images(
struct qla27xx_image_status pri_aux_image_status, sec_aux_image_status;
bool valid_pri_image = false, valid_sec_image = false;
bool active_pri_image = false, active_sec_image = false;
int rc;

if (!ha->flt_region_aux_img_status_pri) {
ql_dbg(ql_dbg_init, vha, 0x018a, "Primary aux image not addressed\n");
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,
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);

if (qla28xx_check_aux_image_status_signature(&pri_aux_image_status)) {
Expand Down Expand Up @@ -8260,9 +8266,15 @@ qla28xx_get_aux_images(
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,
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);

if (qla28xx_check_aux_image_status_signature(&sec_aux_image_status)) {
Expand Down Expand Up @@ -8320,6 +8332,7 @@ qla27xx_get_active_image(struct scsi_qla_host *vha,
struct qla27xx_image_status pri_image_status, sec_image_status;
bool valid_pri_image = false, valid_sec_image = false;
bool active_pri_image = false, active_sec_image = false;
int rc;

if (!ha->flt_region_img_status_pri) {
ql_dbg(ql_dbg_init, vha, 0x018a, "Primary image not addressed\n");
Expand Down Expand Up @@ -8361,8 +8374,14 @@ qla27xx_get_active_image(struct scsi_qla_host *vha,
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);
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);

if (qla27xx_check_image_status_signature(&sec_image_status)) {
Expand Down Expand Up @@ -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);

dcode = (uint32_t *)req->ring;
qla24xx_read_flash_data(vha, dcode, faddr, 8);
if (qla24xx_risc_firmware_invalid(dcode)) {
rval = qla24xx_read_flash_data(vha, dcode, faddr, 8);
if (rval || qla24xx_risc_firmware_invalid(dcode)) {
ql_log(ql_log_fatal, vha, 0x008c,
"Unable to verify the integrity of flash firmware "
"image.\n");
"Unable to verify the integrity of flash firmware image (rval %x).\n", rval);
ql_log(ql_log_fatal, vha, 0x008d,
"Firmware data: %08x %08x %08x %08x.\n",
dcode[0], dcode[1], dcode[2], dcode[3]);
Expand All @@ -8452,7 +8470,12 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr,
for (j = 0; j < segments; j++) {
ql_dbg(ql_dbg_init, vha, 0x008d,
"-> 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_size = be32_to_cpu((__force __be32)dcode[3]);
if (!*srisc_addr) {
Expand All @@ -8468,7 +8491,13 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr,
ql_dbg(ql_dbg_init, vha, 0x008e,
"-> Loading fragment %u: %#x <- %#x (%#lx dwords)...\n",
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++)
dcode[i] = swab32(dcode[i]);

Expand Down Expand Up @@ -8497,7 +8526,14 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr,
fwdt->length = 0;

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]);
ql_dbg(ql_dbg_init, vha, 0x0161,
"-> fwdt%u template array at %#x (%#x dwords)\n",
Expand All @@ -8523,11 +8559,12 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr,
}

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,
"-> fwdt%u failed template validate\n", j);
"-> fwdt%u failed template validate (rval %x)\n",
j, rval);
goto failed;
}

Expand Down
108 changes: 75 additions & 33 deletions drivers/scsi/qla2xxx/qla_sup.c
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,7 @@ qla2xxx_find_flt_start(scsi_qla_host_t *vha, uint32_t *start)
struct qla_flt_location *fltl = (void *)req->ring;
uint32_t *dcode = (uint32_t *)req->ring;
uint8_t *buf = (void *)req->ring, *bcode, last_image;
int rc;

/*
* FLT-location structure resides after the last PCI region.
Expand Down Expand Up @@ -584,14 +585,24 @@ qla2xxx_find_flt_start(scsi_qla_host_t *vha, uint32_t *start)
pcihdr = 0;
do {
/* 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);
if (bcode[0x0] != 0x55 || bcode[0x1] != 0xaa)
goto end;

/* Locate PCI data structure. */
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);

/* Validate signature of PCI data structure. */
Expand All @@ -606,7 +617,12 @@ qla2xxx_find_flt_start(scsi_qla_host_t *vha, uint32_t *start)
} while (!last_image);

/* 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))
goto end;

Expand Down Expand Up @@ -2605,13 +2621,18 @@ qla24xx_read_optrom_data(struct scsi_qla_host *vha, void *buf,
uint32_t offset, uint32_t length)
{
struct qla_hw_data *ha = vha->hw;
int rc;

/* Suspend HBA. */
scsi_block_requests(vha->host);
set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);

/* 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. */
clear_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
Expand Down Expand Up @@ -3412,7 +3433,7 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
struct active_regions active_regions = { };

if (IS_P3P_TYPE(ha))
return ret;
return QLA_SUCCESS;

if (!mbuf)
return QLA_FUNCTION_FAILED;
Expand All @@ -3432,20 +3453,31 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)

do {
/* 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);
if (memcmp(bcode, "\x55\xaa", 2)) {
/* No signature */
ql_log(ql_log_fatal, vha, 0x0059,
"No matching ROM signature.\n");
ret = QLA_FUNCTION_FAILED;
break;
return QLA_FUNCTION_FAILED;
}

/* Locate PCI data structure. */
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);

/* Validate signature of PCI data structure. */
Expand All @@ -3454,8 +3486,7 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
ql_log(ql_log_fatal, vha, 0x005a,
"PCI data struct not found pcir_adr=%x.\n", pcids);
ql_dump_buffer(ql_dbg_init, vha, 0x0059, dcode, 32);
ret = QLA_FUNCTION_FAILED;
break;
return QLA_FUNCTION_FAILED;
}

/* Read version */
Expand Down Expand Up @@ -3507,20 +3538,26 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
faddr = ha->flt_region_fw_sec;
}

qla24xx_read_flash_data(vha, dcode, faddr, 8);
if (qla24xx_risc_firmware_invalid(dcode)) {
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);
ret = qla24xx_read_flash_data(vha, dcode, faddr, 8);
if (ret) {
ql_log(ql_log_info, vha, 0x019e,
"Unable to read FW version (%x).\n", ret);
return ret;
} else {
for (i = 0; i < 4; i++)
ha->fw_revision[i] =
if (qla24xx_risc_firmware_invalid(dcode)) {
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]);
ql_dbg(ql_dbg_init, vha, 0x0060,
"Firmware revision (flash) %u.%u.%u (%x).\n",
ha->fw_revision[0], ha->fw_revision[1],
ha->fw_revision[2], ha->fw_revision[3]);
ql_dbg(ql_dbg_init, vha, 0x0060,
"Firmware revision (flash) %u.%u.%u (%x).\n",
ha->fw_revision[0], ha->fw_revision[1],
ha->fw_revision[2], ha->fw_revision[3]);
}
}

/* Check for golden firmware and get version if available */
Expand All @@ -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));
faddr = ha->flt_region_gold_fw;
qla24xx_read_flash_data(vha, dcode, ha->flt_region_gold_fw, 8);
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);
ret = qla24xx_read_flash_data(vha, dcode, ha->flt_region_gold_fw, 8);
if (ret) {
ql_log(ql_log_info, vha, 0x019f,
"Unable to read Gold FW version (%x).\n", ret);
return ret;
}

for (i = 0; i < 4; i++)
ha->gold_fw_version[i] =
be32_to_cpu((__force __be32)dcode[4+i]);
} 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]);
}
return ret;
}

Expand Down

0 comments on commit 29e2220

Please sign in to comment.