From d74181ca110e3de9d7dc4fba7f9f6026033e2e5d Mon Sep 17 00:00:00 2001 From: Manish Rangankar Date: Wed, 10 Dec 2025 15:45:57 +0530 Subject: [PATCH] scsi: qla2xxx: Add bsg interface to support firmware img validation Add new bsg interface to issue MPI passthrough sub command to validate the new flash firmware image partition. Signed-off-by: Manish Rangankar Signed-off-by: Nilesh Javali Reviewed-by: Himanshu Madhani Link: https://patch.msgid.link/20251210101604.431868-6-njavali@marvell.com Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_bsg.c | 118 +++++++++++++++++++++++++++++++++ drivers/scsi/qla2xxx/qla_bsg.h | 12 ++++ drivers/scsi/qla2xxx/qla_def.h | 20 ++++++ drivers/scsi/qla2xxx/qla_gbl.h | 2 + drivers/scsi/qla2xxx/qla_mbx.c | 40 +++++++++++ 5 files changed, 192 insertions(+) diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index ccfc2d26dd372..8afa8a4b8ccb4 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -11,6 +11,8 @@ #include #include +static int qla28xx_validate_flash_image(struct bsg_job *bsg_job); + static void qla2xxx_free_fcport_work(struct work_struct *work) { struct fc_port *fcport = container_of(work, typeof(*fcport), @@ -2549,6 +2551,30 @@ qla2x00_get_flash_image_status(struct bsg_job *bsg_job) return 0; } +static int +qla2x00_get_drv_attr(struct bsg_job *bsg_job) +{ + struct qla_drv_attr drv_attr; + struct fc_bsg_reply *bsg_reply = bsg_job->reply; + + memset(&drv_attr, 0, sizeof(struct qla_drv_attr)); + drv_attr.ext_attributes |= QLA_IMG_SET_VALID_SUPPORT; + + + sg_copy_from_buffer(bsg_job->reply_payload.sg_list, + bsg_job->reply_payload.sg_cnt, &drv_attr, + sizeof(struct qla_drv_attr)); + + bsg_reply->reply_payload_rcv_len = sizeof(struct qla_drv_attr); + bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK; + + bsg_job->reply_len = sizeof(struct fc_bsg_reply); + bsg_reply->result = DID_OK << 16; + bsg_job_done(bsg_job, bsg_reply->result, bsg_reply->reply_payload_rcv_len); + + return 0; +} + static int qla2x00_manage_host_stats(struct bsg_job *bsg_job) { @@ -2933,6 +2959,12 @@ qla2x00_process_vendor_specific(struct scsi_qla_host *vha, struct bsg_job *bsg_j case QL_VND_GET_FLASH_UPDATE_CAPS: return qla27xx_get_flash_upd_cap(bsg_job); + case QL_VND_GET_DRV_ATTR: + return qla2x00_get_drv_attr(bsg_job); + + case QL_VND_IMG_SET_VALID: + return qla28xx_validate_flash_image(bsg_job); + case QL_VND_SET_FLASH_UPDATE_CAPS: return qla27xx_set_flash_upd_cap(bsg_job); @@ -3246,3 +3278,89 @@ int qla2x00_mailbox_passthru(struct bsg_job *bsg_job) return ret; } + +static int +qla28xx_do_validate_flash_image(struct bsg_job *bsg_job, uint16_t *state) +{ + struct fc_bsg_request *bsg_request = bsg_job->request; + scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job)); + uint16_t mstate[16]; + uint16_t mpi_state = 0; + uint16_t img_idx; + int rval = QLA_SUCCESS; + + memset(mstate, 0, sizeof(mstate)); + + rval = qla2x00_get_firmware_state(vha, mstate); + if (rval != QLA_SUCCESS) { + ql_log(ql_log_warn, vha, 0xffff, + "MBC to get MPI state failed (%d)\n", rval); + rval = -EINVAL; + goto exit_flash_img; + } + + mpi_state = mstate[11]; + + if (!(mpi_state & BIT_9 && mpi_state & BIT_8 && mpi_state & BIT_15)) { + ql_log(ql_log_warn, vha, 0xffff, + "MPI firmware state failed (0x%02x)\n", mpi_state); + rval = -EINVAL; + goto exit_flash_img; + } + + rval = qla81xx_fac_semaphore_access(vha, FAC_SEMAPHORE_LOCK); + if (rval != QLA_SUCCESS) { + ql_log(ql_log_warn, vha, 0xffff, + "Unable to lock flash semaphore."); + goto exit_flash_img; + } + + img_idx = bsg_request->rqst_data.h_vendor.vendor_cmd[1]; + + rval = qla_mpipt_validate_fw(vha, img_idx, state); + if (rval != QLA_SUCCESS) { + ql_log(ql_log_warn, vha, 0xffff, + "Failed to validate Firmware image index [0x%x].\n", + img_idx); + } + + qla81xx_fac_semaphore_access(vha, FAC_SEMAPHORE_UNLOCK); + +exit_flash_img: + return rval; +} + +static int qla28xx_validate_flash_image(struct bsg_job *bsg_job) +{ + scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job)); + struct fc_bsg_reply *bsg_reply = bsg_job->reply; + struct qla_hw_data *ha = vha->hw; + uint16_t state = 0; + int rval = 0; + + if (!IS_QLA28XX(ha) || vha->vp_idx != 0) + return -EPERM; + + mutex_lock(&ha->optrom_mutex); + rval = qla28xx_do_validate_flash_image(bsg_job, &state); + if (rval) + rval = -EINVAL; + mutex_unlock(&ha->optrom_mutex); + + bsg_job->reply_len = sizeof(struct fc_bsg_reply); + + if (rval) + bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = + (state == 39) ? EXT_STATUS_IMG_SET_VALID_ERR : + EXT_STATUS_IMG_SET_CONFIG_ERR; + else + bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK; + + bsg_reply->result = DID_OK << 16; + bsg_reply->reply_payload_rcv_len = 0; + bsg_job->reply_len = sizeof(struct fc_bsg_reply); + bsg_job_done(bsg_job, bsg_reply->result, + bsg_reply->reply_payload_rcv_len); + + return QLA_SUCCESS; +} diff --git a/drivers/scsi/qla2xxx/qla_bsg.h b/drivers/scsi/qla2xxx/qla_bsg.h index d38dab0a07e83..a920c8e482bc6 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.h +++ b/drivers/scsi/qla2xxx/qla_bsg.h @@ -32,12 +32,14 @@ #define QL_VND_GET_PRIV_STATS_EX 0x1A #define QL_VND_SS_GET_FLASH_IMAGE_STATUS 0x1E #define QL_VND_EDIF_MGMT 0X1F +#define QL_VND_GET_DRV_ATTR 0x22 #define QL_VND_MANAGE_HOST_STATS 0x23 #define QL_VND_GET_HOST_STATS 0x24 #define QL_VND_GET_TGT_STATS 0x25 #define QL_VND_MANAGE_HOST_PORT 0x26 #define QL_VND_MBX_PASSTHRU 0x2B #define QL_VND_DPORT_DIAGNOSTICS_V2 0x2C +#define QL_VND_IMG_SET_VALID 0x30 /* BSG Vendor specific subcode returns */ #define EXT_STATUS_OK 0 @@ -50,6 +52,8 @@ #define EXT_STATUS_BUFFER_TOO_SMALL 16 #define EXT_STATUS_NO_MEMORY 17 #define EXT_STATUS_DEVICE_OFFLINE 22 +#define EXT_STATUS_IMG_SET_VALID_ERR 47 +#define EXT_STATUS_IMG_SET_CONFIG_ERR 48 /* * To support bidirectional iocb @@ -318,6 +322,14 @@ struct qla_active_regions { uint8_t reserved[31]; } __packed; +struct qla_drv_attr { + uint32_t attributes; + u32 ext_attributes; +#define QLA_IMG_SET_VALID_SUPPORT BIT_4 + u32 status_flags; + uint8_t reserved[20]; +} __packed; + #include "qla_edif_bsg.h" #endif diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 7e693540c4349..5593ad7fad274 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -1386,6 +1386,26 @@ static inline bool qla2xxx_is_valid_mbs(unsigned int mbs) #define HCS_WRITE_SERDES 0x3 #define HCS_READ_SERDES 0x4 +/* + * ISP2[7|8]xx mailbox commands. + */ +#define MBC_MPI_PASSTHROUGH 0x200 + +/* MBC_MPI_PASSTHROUGH */ +#define MPIPT_REQ_V1 1 +enum { + MPIPT_SUBCMD_GET_SUP_CMD = 0x10, + MPIPT_SUBCMD_GET_SUP_FEATURE, + MPIPT_SUBCMD_GET_STATUS, + MPIPT_SUBCMD_VALIDATE_FW, +}; + +enum { + MPIPT_MPI_STATUS = 1, + MPIPT_FCORE_STATUS, + MPIPT_LOCKDOWN_STATUS, +}; + /* Firmware return data sizes */ #define FCAL_MAP_SIZE 128 diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index f12b2689163de..9e328c235e399 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -842,6 +842,8 @@ extern int qla82xx_write_optrom_data(struct scsi_qla_host *, void *, extern int qla82xx_abort_isp(scsi_qla_host_t *); extern int qla82xx_restart_isp(scsi_qla_host_t *); +extern int qla_mpipt_validate_fw(scsi_qla_host_t *vha, u16 img_idx, u16 *state); + /* IOCB related functions */ extern int qla82xx_start_scsi(srb_t *); extern void qla2x00_sp_free(srb_t *sp); diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 28bb645ace670..0d598be6f3eab 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -7205,3 +7205,43 @@ int qla_mailbox_passthru(scsi_qla_host_t *vha, return rval; } + +int qla_mpipt_validate_fw(scsi_qla_host_t *vha, u16 img_idx, uint16_t *state) +{ + struct qla_hw_data *ha = vha->hw; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + int rval; + + if (!IS_QLA28XX(ha)) { + ql_dbg(ql_dbg_mbx, vha, 0xffff, "%s %d\n", __func__, __LINE__); + return QLA_FUNCTION_FAILED; + } + + if (img_idx > 1) { + ql_log(ql_log_info, vha, 0xffff, + "%s %d Invalid flash image index [%d]\n", + __func__, __LINE__, img_idx); + return QLA_INVALID_COMMAND; + } + + memset(&mc, 0, sizeof(mc)); + mcp->mb[0] = MBC_MPI_PASSTHROUGH; + mcp->mb[1] = MPIPT_SUBCMD_VALIDATE_FW; + mcp->mb[2] = img_idx; + mcp->out_mb = MBX_1|MBX_0; + mcp->in_mb = MBX_2|MBX_1|MBX_0; + + /* send mb via iocb */ + rval = qla24xx_send_mb_cmd(vha, &mc); + if (rval) { + ql_log(ql_log_info, vha, 0xffff, "%s:Failed %x (mb=%x,%x)\n", + __func__, rval, mcp->mb[0], mcp->mb[1]); + *state = mcp->mb[1]; + } else { + ql_log(ql_log_info, vha, 0xffff, "%s: mb=%x,%x,%x\n", __func__, + mcp->mb[0], mcp->mb[1], mcp->mb[2]); + } + + return rval; +} -- 2.47.3