]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
scsi: qla2xxx: Add bsg interface to support firmware img validation
authorManish Rangankar <mrangankar@marvell.com>
Wed, 10 Dec 2025 10:15:57 +0000 (15:45 +0530)
committerMartin K. Petersen <martin.petersen@oracle.com>
Wed, 17 Dec 2025 03:34:22 +0000 (22:34 -0500)
Add new bsg interface to issue MPI passthrough sub command to validate
the new flash firmware image partition.

Signed-off-by: Manish Rangankar <mrangankar@marvell.com>
Signed-off-by: Nilesh Javali <njavali@marvell.com>
Reviewed-by: Himanshu Madhani <hmadhani2024@gmail.com>
Link: https://patch.msgid.link/20251210101604.431868-6-njavali@marvell.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/qla2xxx/qla_bsg.c
drivers/scsi/qla2xxx/qla_bsg.h
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_gbl.h
drivers/scsi/qla2xxx/qla_mbx.c

index ccfc2d26dd37255516df78c232fc618f2cc3b3fb..8afa8a4b8ccb4b87fdf214847088d3ddea90e348 100644 (file)
@@ -11,6 +11,8 @@
 #include <linux/delay.h>
 #include <linux/bsg-lib.h>
 
+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;
+}
index d38dab0a07e83357b8bbf522e5398312b0793d9d..a920c8e482bc6810e1c9427504e078fb2d8d94db 100644 (file)
 #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
index 7e693540c4349f2b54c5fb139ee2fd5119d4650c..5593ad7fad274bfef04656668e9f7f4a971d1fce 100644 (file)
@@ -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
 
index f12b2689163ded77a57d9de811d89a5f60d33804..9e328c235e39933a67b86d94b5186de18fe82bad 100644 (file)
@@ -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);
index 28bb645ace670534d204f36b3d81312a4ef364a4..0d598be6f3eabc5ddf580c40bc5cd37fbdb169d0 100644 (file)
@@ -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;
+}