summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorMartin K. Petersen <martin.petersen@oracle.com>2025-12-16 22:35:32 -0500
committerMartin K. Petersen <martin.petersen@oracle.com>2025-12-16 22:35:32 -0500
commit8334f93075dce0a4536c096a7d471ef90506a7a4 (patch)
treec07c0ceac6e15a921e1ec923b2d21a083578c839 /drivers
parent0f9c4be787f786cff0bf2183607e54a552a40cb2 (diff)
parent1732d10fa7edb611c8384ca0b841d6f79ddf5bed (diff)
Merge patch series "qla2xxx: Misc feature and bug fixes"
Nilesh Javali <njavali@marvell.com> says: Hello Martin, Please apply the qla2xxx driver load flash FW mailbox support along with miscellaneous bug fixes to the scsi tree at your earliest convenience. Link: https://patch.msgid.link/20251210101604.431868-1-njavali@marvell.com Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/scsi/qla2xxx/qla_bsg.c147
-rw-r--r--drivers/scsi/qla2xxx/qla_bsg.h12
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h30
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h5
-rw-r--r--drivers/scsi/qla2xxx/qla_gs.c41
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c232
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c19
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c88
-rw-r--r--drivers/scsi/qla2xxx/qla_nx.h1
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c3
-rw-r--r--drivers/scsi/qla2xxx/qla_sup.c29
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h8
12 files changed, 559 insertions, 56 deletions
diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
index ccfc2d26dd37..2c44a379cb23 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.c
+++ b/drivers/scsi/qla2xxx/qla_bsg.c
@@ -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),
@@ -1546,8 +1548,9 @@ qla2x00_update_optrom(struct bsg_job *bsg_job)
ha->optrom_buffer = NULL;
ha->optrom_state = QLA_SWAITING;
mutex_unlock(&ha->optrom_mutex);
- bsg_job_done(bsg_job, bsg_reply->result,
- bsg_reply->reply_payload_rcv_len);
+ if (!rval)
+ bsg_job_done(bsg_job, bsg_reply->result,
+ bsg_reply->reply_payload_rcv_len);
return rval;
}
@@ -2550,6 +2553,30 @@ qla2x00_get_flash_image_status(struct bsg_job *bsg_job)
}
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)
{
scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job));
@@ -2612,8 +2639,9 @@ qla2x00_manage_host_stats(struct bsg_job *bsg_job)
sizeof(struct ql_vnd_mng_host_stats_resp));
bsg_reply->result = DID_OK;
- bsg_job_done(bsg_job, bsg_reply->result,
- bsg_reply->reply_payload_rcv_len);
+ if (!ret)
+ bsg_job_done(bsg_job, bsg_reply->result,
+ bsg_reply->reply_payload_rcv_len);
return ret;
}
@@ -2702,8 +2730,9 @@ qla2x00_get_host_stats(struct bsg_job *bsg_job)
bsg_job->reply_payload.sg_cnt,
data, response_len);
bsg_reply->result = DID_OK;
- bsg_job_done(bsg_job, bsg_reply->result,
- bsg_reply->reply_payload_rcv_len);
+ if (!ret)
+ bsg_job_done(bsg_job, bsg_reply->result,
+ bsg_reply->reply_payload_rcv_len);
kfree(data);
host_stat_out:
@@ -2802,8 +2831,9 @@ reply:
bsg_job->reply_payload.sg_cnt, data,
response_len);
bsg_reply->result = DID_OK;
- bsg_job_done(bsg_job, bsg_reply->result,
- bsg_reply->reply_payload_rcv_len);
+ if (!ret)
+ bsg_job_done(bsg_job, bsg_reply->result,
+ bsg_reply->reply_payload_rcv_len);
tgt_stat_out:
kfree(data);
@@ -2864,8 +2894,9 @@ qla2x00_manage_host_port(struct bsg_job *bsg_job)
bsg_job->reply_payload.sg_cnt, &rsp_data,
sizeof(struct ql_vnd_mng_host_port_resp));
bsg_reply->result = DID_OK;
- bsg_job_done(bsg_job, bsg_reply->result,
- bsg_reply->reply_payload_rcv_len);
+ if (!ret)
+ bsg_job_done(bsg_job, bsg_reply->result,
+ bsg_reply->reply_payload_rcv_len);
return ret;
}
@@ -2933,6 +2964,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);
@@ -3240,9 +3277,97 @@ int qla2x00_mailbox_passthru(struct bsg_job *bsg_job)
bsg_job->reply_len = sizeof(*bsg_job->reply);
bsg_reply->result = DID_OK << 16;
- bsg_job_done(bsg_job, bsg_reply->result, bsg_reply->reply_payload_rcv_len);
+ if (!ret)
+ bsg_job_done(bsg_job, bsg_reply->result, bsg_reply->reply_payload_rcv_len);
kfree(req_data);
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);
+ if (!rval)
+ 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 d38dab0a07e8..a920c8e482bc 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 b3265952c4be..5593ad7fad27 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -1270,6 +1270,7 @@ static inline bool qla2xxx_is_valid_mbs(unsigned int mbs)
*/
#define MBC_LOAD_RAM 1 /* Load RAM. */
#define MBC_EXECUTE_FIRMWARE 2 /* Execute firmware. */
+#define MBC_LOAD_FLASH_FIRMWARE 3 /* Load flash firmware. */
#define MBC_READ_RAM_WORD 5 /* Read RAM word. */
#define MBC_MAILBOX_REGISTER_TEST 6 /* Wrap incoming mailboxes */
#define MBC_VERIFY_CHECKSUM 7 /* Verify checksum. */
@@ -1385,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
@@ -4149,6 +4170,7 @@ struct qla_hw_data {
uint32_t eeh_flush:2;
#define EEH_FLUSH_RDY 1
#define EEH_FLUSH_DONE 2
+ uint32_t secure_mcu:1;
} flags;
uint16_t max_exchg;
@@ -4414,6 +4436,8 @@ struct qla_hw_data {
((IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) &&\
(ha->zio_mode == QLA_ZIO_MODE_6))
+#define IS_QLA28XX_SECURED(ha) (IS_QLA28XX(ha) && ha->flags.secure_mcu)
+
/* HBA serial number */
uint8_t serial0;
uint8_t serial1;
@@ -5368,7 +5392,7 @@ struct edif_sa_index_entry {
struct list_head next;
};
-/* Refer to SNIA SFF 8247 */
+/* Refer to SNIA SFF 8472 */
struct sff_8247_a0 {
u8 txid; /* transceiver id */
u8 ext_txid;
@@ -5412,6 +5436,7 @@ struct sff_8247_a0 {
#define FC_SP_32 BIT_3
#define FC_SP_2 BIT_2
#define FC_SP_1 BIT_0
+#define FC_SPEED_2 BIT_1
u8 fc_sp_cc10;
u8 encode;
u8 bitrate;
@@ -5430,7 +5455,8 @@ struct sff_8247_a0 {
u8 vendor_pn[SFF_PART_NAME_LEN]; /* part number */
u8 vendor_rev[4];
u8 wavelength[2];
- u8 resv;
+#define FC_SP_64 BIT_0
+ u8 fiber_channel_speed2;
u8 cc_base;
u8 options[2]; /* offset 64 */
u8 br_max;
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 55d531c19e6b..9e328c235e39 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -345,6 +345,9 @@ extern int
qla2x00_execute_fw(scsi_qla_host_t *, uint32_t);
extern int
+qla28xx_load_flash_firmware(scsi_qla_host_t *vha);
+
+extern int
qla2x00_get_fw_version(scsi_qla_host_t *);
extern int
@@ -839,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_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index 51c7cea71f90..880cd73feaca 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -3266,9 +3266,6 @@ login_logout:
atomic_read(&fcport->state) == FCS_ONLINE) ||
do_delete) {
if (fcport->loop_id != FC_NO_LOOP_ID) {
- if (fcport->flags & FCF_FCP2_DEVICE)
- continue;
-
ql_log(ql_log_warn, vha, 0x20f0,
"%s %d %8phC post del sess\n",
__func__, __LINE__,
@@ -3535,8 +3532,8 @@ int qla_fab_async_scan(scsi_qla_host_t *vha, srb_t *sp)
if (vha->scan.scan_flags & SF_SCANNING) {
spin_unlock_irqrestore(&vha->work_lock, flags);
ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0x2012,
- "%s: scan active\n", __func__);
- return rval;
+ "%s: scan active for sp:%p\n", __func__, sp);
+ goto done_free_sp;
}
vha->scan.scan_flags |= SF_SCANNING;
if (!sp)
@@ -3701,23 +3698,25 @@ int qla_fab_async_scan(scsi_qla_host_t *vha, srb_t *sp)
return rval;
done_free_sp:
- if (sp->u.iocb_cmd.u.ctarg.req) {
- dma_free_coherent(&vha->hw->pdev->dev,
- sp->u.iocb_cmd.u.ctarg.req_allocated_size,
- sp->u.iocb_cmd.u.ctarg.req,
- sp->u.iocb_cmd.u.ctarg.req_dma);
- sp->u.iocb_cmd.u.ctarg.req = NULL;
- }
- if (sp->u.iocb_cmd.u.ctarg.rsp) {
- dma_free_coherent(&vha->hw->pdev->dev,
- sp->u.iocb_cmd.u.ctarg.rsp_allocated_size,
- sp->u.iocb_cmd.u.ctarg.rsp,
- sp->u.iocb_cmd.u.ctarg.rsp_dma);
- sp->u.iocb_cmd.u.ctarg.rsp = NULL;
- }
+ if (sp) {
+ if (sp->u.iocb_cmd.u.ctarg.req) {
+ dma_free_coherent(&vha->hw->pdev->dev,
+ sp->u.iocb_cmd.u.ctarg.req_allocated_size,
+ sp->u.iocb_cmd.u.ctarg.req,
+ sp->u.iocb_cmd.u.ctarg.req_dma);
+ sp->u.iocb_cmd.u.ctarg.req = NULL;
+ }
+ if (sp->u.iocb_cmd.u.ctarg.rsp) {
+ dma_free_coherent(&vha->hw->pdev->dev,
+ sp->u.iocb_cmd.u.ctarg.rsp_allocated_size,
+ sp->u.iocb_cmd.u.ctarg.rsp,
+ sp->u.iocb_cmd.u.ctarg.rsp_dma);
+ sp->u.iocb_cmd.u.ctarg.rsp = NULL;
+ }
- /* ref: INIT */
- kref_put(&sp->cmd_kref, qla2x00_sp_release);
+ /* ref: INIT */
+ kref_put(&sp->cmd_kref, qla2x00_sp_release);
+ }
spin_lock_irqsave(&vha->work_lock, flags);
vha->scan.scan_flags &= ~SF_SCANNING;
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index d395cbfe6802..689f909943b4 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -1859,15 +1859,6 @@ void qla2x00_handle_rscn(scsi_qla_host_t *vha, struct event_arg *ea)
case RSCN_PORT_ADDR:
fcport = qla2x00_find_fcport_by_nportid(vha, &ea->id, 1);
if (fcport) {
- if (ql2xfc2target &&
- fcport->flags & FCF_FCP2_DEVICE &&
- atomic_read(&fcport->state) == FCS_ONLINE) {
- ql_dbg(ql_dbg_disc, vha, 0x2115,
- "Delaying session delete for FCP2 portid=%06x %8phC ",
- fcport->d_id.b24, fcport->port_name);
- return;
- }
-
if (vha->hw->flags.edif_enabled && DBELL_ACTIVE(vha)) {
/*
* On ipsec start by remote port, Target port
@@ -2471,8 +2462,23 @@ qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea)
ea->sp->gen1, fcport->rscn_gen,
ea->data[0], ea->data[1], ea->iop[0], ea->iop[1]);
- if ((fcport->fw_login_state == DSC_LS_PLOGI_PEND) ||
- (fcport->fw_login_state == DSC_LS_PRLI_PEND)) {
+ if (fcport->fw_login_state == DSC_LS_PLOGI_PEND) {
+ ql_dbg(ql_dbg_disc, vha, 0x20ea,
+ "%s %d %8phC Remote is trying to login\n",
+ __func__, __LINE__, fcport->port_name);
+ /*
+ * If we get here, there is port thats already logged in,
+ * but it's state has not moved ahead. Recheck with FW on
+ * what state it is in and proceed ahead
+ */
+ if (!N2N_TOPO(vha->hw)) {
+ fcport->fw_login_state = DSC_LS_PRLI_COMP;
+ qla24xx_post_gpdb_work(vha, fcport, 0);
+ }
+ return;
+ }
+
+ if (fcport->fw_login_state == DSC_LS_PRLI_PEND) {
ql_dbg(ql_dbg_disc, vha, 0x20ea,
"%s %d %8phC Remote is trying to login\n",
__func__, __LINE__, fcport->port_name);
@@ -4074,6 +4080,22 @@ static void qla2xxx_print_sfp_info(struct scsi_qla_host *vha)
u8 str[STR_LEN], *ptr, p;
int leftover, len;
+ ql_dbg(ql_dbg_init, vha, 0x015a,
+ "SFP: %.*s -> %.*s ->%s%s%s%s%s%s%s\n",
+ (int)sizeof(a0->vendor_name), a0->vendor_name,
+ (int)sizeof(a0->vendor_pn), a0->vendor_pn,
+ a0->fc_sp_cc10 & FC_SP_2 ? a0->fiber_channel_speed2 & FC_SP_64 ?
+ " 64G" : "" : "",
+ a0->fc_sp_cc10 & FC_SP_32 ? " 32G" : "",
+ a0->fc_sp_cc10 & FC_SP_16 ? " 16G" : "",
+ a0->fc_sp_cc10 & FC_SP_8 ? " 8G" : "",
+ a0->fc_sp_cc10 & FC_SP_4 ? " 4G" : "",
+ a0->fc_sp_cc10 & FC_SP_2 ? " 2G" : "",
+ a0->fc_sp_cc10 & FC_SP_1 ? " 1G" : "");
+
+ if (!(ql2xextended_error_logging & ql_dbg_verbose))
+ return;
+
memset(str, 0, STR_LEN);
snprintf(str, SFF_VEN_NAME_LEN+1, a0->vendor_name);
ql_dbg(ql_dbg_init, vha, 0x015a,
@@ -8443,6 +8465,148 @@ bool qla24xx_risc_firmware_invalid(uint32_t *dword)
}
static int
+qla28xx_get_srisc_addr(scsi_qla_host_t *vha, uint32_t *srisc_addr,
+ uint32_t faddr)
+{
+ struct qla_hw_data *ha = vha->hw;
+ struct req_que *req = ha->req_q_map[0];
+ uint32_t *dcode;
+ int rval;
+
+ *srisc_addr = 0;
+ dcode = (uint32_t *)req->ring;
+
+ rval = qla24xx_read_flash_data(vha, dcode, faddr, 10);
+ if (rval) {
+ ql_log(ql_log_fatal, vha, 0x01aa,
+ "-> Failed to read flash addr + size .\n");
+ return QLA_FUNCTION_FAILED;
+ }
+
+ *srisc_addr = be32_to_cpu((__force __be32)dcode[2]);
+ return QLA_SUCCESS;
+}
+
+static int
+qla28xx_load_fw_template(scsi_qla_host_t *vha, uint32_t faddr)
+{
+ struct qla_hw_data *ha = vha->hw;
+ struct fwdt *fwdt = ha->fwdt;
+ struct req_que *req = ha->req_q_map[0];
+ uint32_t risc_size, risc_attr = 0;
+ uint templates, segments, fragment;
+ uint32_t *dcode;
+ ulong dlen;
+ int rval;
+ uint j;
+
+ dcode = (uint32_t *)req->ring;
+ segments = FA_RISC_CODE_SEGMENTS;
+
+ for (j = 0; j < segments; j++) {
+ rval = qla24xx_read_flash_data(vha, dcode, faddr, 10);
+ if (rval) {
+ ql_log(ql_log_fatal, vha, 0x01a1,
+ "-> Failed to read flash addr + size .\n");
+ return QLA_FUNCTION_FAILED;
+ }
+
+ risc_size = be32_to_cpu((__force __be32)dcode[3]);
+
+ if (risc_attr == 0)
+ risc_attr = be32_to_cpu((__force __be32)dcode[9]);
+
+ dlen = ha->fw_transfer_size >> 2;
+ for (fragment = 0; fragment < risc_size; fragment++) {
+ if (dlen > risc_size)
+ dlen = risc_size;
+
+ faddr += dlen;
+ risc_size -= dlen;
+ }
+ }
+
+ templates = (risc_attr & BIT_9) ? 2 : 1;
+
+ ql_dbg(ql_dbg_init, vha, 0x01a1, "-> templates = %u\n", templates);
+
+ for (j = 0; j < templates; j++, fwdt++) {
+ vfree(fwdt->template);
+ fwdt->template = NULL;
+ fwdt->length = 0;
+
+ dcode = (uint32_t *)req->ring;
+
+ rval = qla24xx_read_flash_data(vha, dcode, faddr, 7);
+ if (rval) {
+ ql_log(ql_log_fatal, vha, 0x01a2,
+ "-> Unable to read template size.\n");
+ goto failed;
+ }
+
+ risc_size = be32_to_cpu((__force __be32)dcode[2]);
+ ql_dbg(ql_dbg_init, vha, 0x01a3,
+ "-> fwdt%u template array at %#x (%#x dwords)\n",
+ j, faddr, risc_size);
+ if (!risc_size || !~risc_size) {
+ ql_dbg(ql_dbg_init, vha, 0x01a4,
+ "-> fwdt%u failed to read array\n", j);
+ goto failed;
+ }
+
+ /* skip header and ignore checksum */
+ faddr += 7;
+ risc_size -= 8;
+
+ ql_dbg(ql_dbg_init, vha, 0x01a5,
+ "-> fwdt%u template allocate template %#x words...\n",
+ j, risc_size);
+ fwdt->template = vmalloc(risc_size * sizeof(*dcode));
+ if (!fwdt->template) {
+ ql_log(ql_log_warn, vha, 0x01a6,
+ "-> fwdt%u failed allocate template.\n", j);
+ goto failed;
+ }
+
+ dcode = fwdt->template;
+ rval = qla24xx_read_flash_data(vha, dcode, faddr, risc_size);
+
+ if (rval || !qla27xx_fwdt_template_valid(dcode)) {
+ ql_log(ql_log_warn, vha, 0x01a7,
+ "-> fwdt%u failed template validate (rval %x)\n",
+ j, rval);
+ goto failed;
+ }
+
+ dlen = qla27xx_fwdt_template_size(dcode);
+ ql_dbg(ql_dbg_init, vha, 0x01a7,
+ "-> fwdt%u template size %#lx bytes (%#lx words)\n",
+ j, dlen, dlen / sizeof(*dcode));
+ if (dlen > risc_size * sizeof(*dcode)) {
+ ql_log(ql_log_warn, vha, 0x01a8,
+ "-> fwdt%u template exceeds array (%-lu bytes)\n",
+ j, dlen - risc_size * sizeof(*dcode));
+ goto failed;
+ }
+
+ fwdt->length = dlen;
+ ql_dbg(ql_dbg_init, vha, 0x01a9,
+ "-> fwdt%u loaded template ok\n", j);
+
+ faddr += risc_size + 1;
+ }
+
+ return QLA_SUCCESS;
+
+failed:
+ vfree(fwdt->template);
+ fwdt->template = NULL;
+ fwdt->length = 0;
+
+ return QLA_SUCCESS;
+}
+
+static int
qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr,
uint32_t faddr)
{
@@ -8881,16 +9045,18 @@ int
qla81xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
{
int rval;
+ uint32_t f_region = 0;
struct qla_hw_data *ha = vha->hw;
struct active_regions active_regions = { };
- if (ql2xfwloadbin == 2)
+ if (ql2xfwloadbin == 2 && !IS_QLA28XX(ha))
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).
+ * 1) If 28xxx, ROM cmd to load flash firmware.
+ * 2) Firmware residing in flash.
+ * 3) Firmware via request-firmware interface (.bin file).
+ * 4) Golden-Firmware residing in flash -- (limited operation).
*/
if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
@@ -8898,6 +9064,40 @@ qla81xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
qla27xx_get_active_image(vha, &active_regions);
+ /* For 28XXX, always load the flash firmware using rom mbx */
+ if (IS_QLA28XX_SECURED(ha)) {
+ rval = qla28xx_load_flash_firmware(vha);
+ if (rval != QLA_SUCCESS) {
+ ql_log(ql_log_fatal, vha, 0x019e,
+ "Failed to load flash firmware.\n");
+ goto exit_load_risc;
+ }
+
+ f_region =
+ (active_regions.global != QLA27XX_SECONDARY_IMAGE) ?
+ ha->flt_region_fw : ha->flt_region_fw_sec;
+
+ ql_log(ql_log_info, vha, 0x019f,
+ "Load flash firmware successful (%s).\n",
+ ((active_regions.global != QLA27XX_SECONDARY_IMAGE) ?
+ "Primary" : "Secondary"));
+
+ rval = qla28xx_get_srisc_addr(vha, srisc_addr, f_region);
+ if (rval != QLA_SUCCESS) {
+ ql_log(ql_log_warn, vha, 0x019f,
+ "failed to read srisc address\n");
+ goto exit_load_risc;
+ }
+
+ rval = qla28xx_load_fw_template(vha, f_region);
+ if (rval != QLA_SUCCESS) {
+ ql_log(ql_log_warn, vha, 0x01a0,
+ "failed to read firmware template\n");
+ }
+
+ goto exit_load_risc;
+ }
+
if (active_regions.global != QLA27XX_SECONDARY_IMAGE)
goto try_primary_fw;
@@ -8927,6 +9127,8 @@ try_blob_fw:
ql_log(ql_log_info, vha, 0x009a, "Need firmware flash update.\n");
ha->flags.running_gold_fw = 1;
+
+exit_load_risc:
return rval;
}
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index a3971afc2dd1..a4dda4fcb52c 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -1669,13 +1669,28 @@ skip_rio:
/* Port logout */
fcport = qla2x00_find_fcport_by_loopid(vha, mb[1]);
- if (!fcport)
+ if (!fcport) {
+ ql_dbg(ql_dbg_async, vha, 0x5011,
+ "Could not find fcport:%04x %04x %04x\n",
+ mb[1], mb[2], mb[3]);
break;
- if (atomic_read(&fcport->state) != FCS_ONLINE)
+ }
+
+ if (atomic_read(&fcport->state) != FCS_ONLINE) {
+ ql_dbg(ql_dbg_async, vha, 0x5012,
+ "Port state is not online State:0x%x \n",
+ atomic_read(&fcport->state));
+ ql_dbg(ql_dbg_async, vha, 0x5012,
+ "Scheduling session for deletion \n");
+ fcport->logout_on_delete = 0;
+ qlt_schedule_sess_for_deletion(fcport);
break;
+ }
+
ql_dbg(ql_dbg_async, vha, 0x508a,
"Marking port lost loopid=%04x portid=%06x.\n",
fcport->loop_id, fcport->d_id.b24);
+
if (qla_ini_mode_enabled(vha)) {
fcport->logout_on_delete = 0;
qlt_schedule_sess_for_deletion(fcport);
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 1f01576f044b..0d598be6f3ea 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -43,6 +43,7 @@ static struct rom_cmd {
} rom_cmds[] = {
{ MBC_LOAD_RAM },
{ MBC_EXECUTE_FIRMWARE },
+ { MBC_LOAD_FLASH_FIRMWARE },
{ MBC_READ_RAM_WORD },
{ MBC_MAILBOX_REGISTER_TEST },
{ MBC_VERIFY_CHECKSUM },
@@ -825,6 +826,53 @@ done:
}
/*
+ * qla2x00_load_flash_firmware
+ * Load firmware from flash.
+ *
+ * Input:
+ * vha = adapter block pointer.
+ *
+ * Returns:
+ * qla28xx local function return status code.
+ *
+ * Context:
+ * Kernel context.
+ */
+int
+qla28xx_load_flash_firmware(scsi_qla_host_t *vha)
+{
+ struct qla_hw_data *ha = vha->hw;
+ int rval = QLA_COMMAND_ERROR;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+
+ if (!IS_QLA28XX(ha))
+ return rval;
+
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x11a6,
+ "Entered %s.\n", __func__);
+
+ mcp->mb[0] = MBC_LOAD_FLASH_FIRMWARE;
+ mcp->out_mb = MBX_2 | MBX_1 | MBX_0;
+ mcp->in_mb = MBX_0;
+ mcp->tov = MBX_TOV_SECONDS;
+ mcp->flags = 0;
+ rval = qla2x00_mailbox_command(vha, mcp);
+
+ if (rval != QLA_SUCCESS) {
+ ql_dbg(ql_log_info, vha, 0x11a7,
+ "Failed=%x cmd error=%x img error=%x.\n",
+ rval, mcp->mb[1], mcp->mb[2]);
+ } else {
+ ql_dbg(ql_log_info, vha, 0x11a8,
+ "Done %s.\n", __func__);
+ }
+
+ return rval;
+}
+
+
+/*
* qla_get_exlogin_status
* Get extended login status
* uses the memory offload control/status Mailbox
@@ -7157,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;
+}
diff --git a/drivers/scsi/qla2xxx/qla_nx.h b/drivers/scsi/qla2xxx/qla_nx.h
index 5d1bdc15b75c..8e7a7f5f0adb 100644
--- a/drivers/scsi/qla2xxx/qla_nx.h
+++ b/drivers/scsi/qla2xxx/qla_nx.h
@@ -892,6 +892,7 @@ struct ct6_dsd {
#define FA_VPD_SIZE_82XX 0x400
#define FA_FLASH_LAYOUT_ADDR_82 0xFC400
+#define FA_FLASH_MCU_OFF 0x13000
/******************************************************************************
*
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 16a44c0917e1..c9aff70e7357 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -1183,7 +1183,8 @@ qla2x00_wait_for_hba_ready(scsi_qla_host_t *vha)
while ((qla2x00_reset_active(vha) || ha->dpc_active ||
ha->flags.mbox_busy) ||
test_bit(FX00_RESET_RECOVERY, &vha->dpc_flags) ||
- test_bit(FX00_TARGET_SCAN, &vha->dpc_flags)) {
+ test_bit(FX00_TARGET_SCAN, &vha->dpc_flags) ||
+ (vha->scan.scan_flags & SF_SCANNING)) {
if (test_bit(UNLOADING, &base_vha->dpc_flags))
break;
msleep(1000);
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index 9e7a407ba1b9..b6c36a8a2d60 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -1084,6 +1084,32 @@ qla2xxx_get_idc_param(scsi_qla_host_t *vha)
return;
}
+static int qla28xx_validate_mcu_signature(scsi_qla_host_t *vha)
+{
+ struct qla_hw_data *ha = vha->hw;
+ struct req_que *req = ha->req_q_map[0];
+ uint32_t *dcode = (uint32_t *)req->ring;
+ uint32_t signature[2] = {0x000c0000, 0x00050000};
+ int ret = QLA_SUCCESS;
+
+ ret = qla24xx_read_flash_data(vha, dcode, FA_FLASH_MCU_OFF >> 2, 2);
+ if (ret) {
+ ql_log(ql_log_fatal, vha, 0x01ab,
+ "-> Failed to read flash mcu signature.\n");
+ ret = QLA_FUNCTION_FAILED;
+ goto done;
+ }
+
+ ql_dbg(ql_dbg_init, vha, 0x01ac,
+ "Flash data 0x%08x 0x%08x.\n", dcode[0], dcode[1]);
+
+ if (!(dcode[0] == signature[0] && dcode[1] == signature[1]))
+ ret = QLA_FUNCTION_FAILED;
+
+done:
+ return ret;
+}
+
int
qla2xxx_get_flash_info(scsi_qla_host_t *vha)
{
@@ -1096,6 +1122,9 @@ qla2xxx_get_flash_info(scsi_qla_host_t *vha)
!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
return QLA_SUCCESS;
+ if (IS_QLA28XX(ha) && !qla28xx_validate_mcu_signature(vha))
+ ha->flags.secure_mcu = 1;
+
ret = qla2xxx_find_flt_start(vha, &flt_addr);
if (ret != QLA_SUCCESS)
return ret;
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index a491d6ee5c94..9564beafdab7 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -6,9 +6,9 @@
/*
* Driver version
*/
-#define QLA2XXX_VERSION "10.02.09.400-k"
+#define QLA2XXX_VERSION "10.02.10.100-k"
#define QLA_DRIVER_MAJOR_VER 10
-#define QLA_DRIVER_MINOR_VER 2
-#define QLA_DRIVER_PATCH_VER 9
-#define QLA_DRIVER_BETA_VER 400
+#define QLA_DRIVER_MINOR_VER 02
+#define QLA_DRIVER_PATCH_VER 10
+#define QLA_DRIVER_BETA_VER 100