From 7011e8aafe8c8fcc1c6f8bfcc6796f4530428e13 Mon Sep 17 00:00:00 2001 From: Gulam Mohamed Date: Mon, 1 Dec 2025 11:07:16 +0000 Subject: [PATCH 01/78] scsi: target: core: Add emulation for REPORT IDENTIFYING INFORMATION Add emulation for REPORT IDENTIFYING INFORMATION command using the configfs file 'pd_text_id_info' in target core module. The configfs file is created in /sys/kernel/config/target/core// /wwn/. An emulation function, spc_emulate_report_id_info(), is defined to return the identification string based on the contents of 'pd_text_id_info'. The details of the REPORT IDENTIFYING INFORMATION command is defined in section 6.32 of SPC4. [mkp: checkpatch tweaks] Signed-off-by: Gulam Mohamed Reviewed-by: John Garry Link: https://patch.msgid.link/20251201110716.227588-1-gulam.mohamed@oracle.com Signed-off-by: Martin K. Petersen --- drivers/target/target_core_configfs.c | 50 ++++++++++++++++ drivers/target/target_core_spc.c | 86 +++++++++++++++++++++++++++ include/target/target_core_base.h | 4 ++ 3 files changed, 140 insertions(+) diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index f7868b41c5e6..eb5bc3f1673b 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -1741,6 +1741,54 @@ static ssize_t target_wwn_vpd_protocol_identifier_show(struct config_item *item, return len; } +static ssize_t target_wwn_pd_text_id_info_show(struct config_item *item, + char *page) +{ + return sysfs_emit(page, "%s\n", &to_t10_wwn(item)->pd_text_id_info[0]); +} + +static ssize_t target_wwn_pd_text_id_info_store(struct config_item *item, + const char *page, size_t count) +{ + struct t10_wwn *t10_wwn = to_t10_wwn(item); + struct se_device *dev = t10_wwn->t10_dev; + + /* +2 to allow for a trailing (stripped) '\n' and null-terminator */ + unsigned char buf[PD_TEXT_ID_INFO_LEN + 2]; + char *stripped; + + /* + * Check to see if any active exports exist. If they do exist, fail + * here as changing this information on the fly (underneath the + * initiator side OS dependent multipath code) could cause negative + * effects. + */ + if (dev->export_count) { + pr_err("Unable to set the peripheral device text id info while active %d exports exist\n", + dev->export_count); + return -EINVAL; + } + + if (strscpy(buf, page, sizeof(buf)) < 0) + return -EOVERFLOW; + + /* Strip any newline added from userspace. */ + stripped = strstrip(buf); + if (strlen(stripped) >= PD_TEXT_ID_INFO_LEN) { + pr_err("Emulated peripheral device text id info exceeds PD_TEXT_ID_INFO_LEN: " __stringify(PD_TEXT_ID_INFO_LEN "\n")); + return -EOVERFLOW; + } + + BUILD_BUG_ON(sizeof(dev->t10_wwn.pd_text_id_info) != PD_TEXT_ID_INFO_LEN); + strscpy(dev->t10_wwn.pd_text_id_info, stripped, + sizeof(dev->t10_wwn.pd_text_id_info)); + + pr_debug("Target_Core_ConfigFS: Set emulated peripheral dev text id info:" + " %s\n", dev->t10_wwn.pd_text_id_info); + + return count; +} + /* * Generic wrapper for dumping VPD identifiers by association. */ @@ -1797,6 +1845,7 @@ CONFIGFS_ATTR_RO(target_wwn_, vpd_protocol_identifier); CONFIGFS_ATTR_RO(target_wwn_, vpd_assoc_logical_unit); CONFIGFS_ATTR_RO(target_wwn_, vpd_assoc_target_port); CONFIGFS_ATTR_RO(target_wwn_, vpd_assoc_scsi_target_device); +CONFIGFS_ATTR(target_wwn_, pd_text_id_info); static struct configfs_attribute *target_core_dev_wwn_attrs[] = { &target_wwn_attr_vendor_id, @@ -1808,6 +1857,7 @@ static struct configfs_attribute *target_core_dev_wwn_attrs[] = { &target_wwn_attr_vpd_assoc_logical_unit, &target_wwn_attr_vpd_assoc_target_port, &target_wwn_attr_vpd_assoc_scsi_target_device, + &target_wwn_attr_pd_text_id_info, NULL, }; diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index fe2b888bcb43..f20bc6ea019b 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -25,6 +25,8 @@ #include "target_core_ua.h" #include "target_core_xcopy.h" +#define PD_TEXT_ID_INFO_HDR_LEN 4 + static void spc_fill_alua_data(struct se_lun *lun, unsigned char *buf) { struct t10_alua_tg_pt_gp *tg_pt_gp; @@ -1999,6 +2001,18 @@ static const struct target_opcode_descriptor tcm_opcode_report_supp_opcodes = { .enabled = spc_rsoc_enabled, }; +static struct target_opcode_descriptor tcm_opcode_report_identifying_information = { + .support = SCSI_SUPPORT_FULL, + .serv_action_valid = 1, + .opcode = MAINTENANCE_IN, + .service_action = MI_REPORT_IDENTIFYING_INFORMATION, + .cdb_size = 12, + .usage_bits = {MAINTENANCE_IN, MI_REPORT_IDENTIFYING_INFORMATION, + 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, SCSI_CONTROL_MASK}, +}; + static bool tcm_is_set_tpg_enabled(const struct target_opcode_descriptor *descr, struct se_cmd *cmd) { @@ -2086,6 +2100,7 @@ static const struct target_opcode_descriptor *tcm_supported_opcodes[] = { &tcm_opcode_report_target_pgs, &tcm_opcode_report_supp_opcodes, &tcm_opcode_set_tpg, + &tcm_opcode_report_identifying_information, }; static int @@ -2303,6 +2318,72 @@ out: return ret; } +static sense_reason_t +spc_fill_pd_text_id_info(struct se_cmd *cmd, u8 *cdb) +{ + struct se_device *dev = cmd->se_dev; + unsigned char *buf; + unsigned char *rbuf; + u32 buf_len; + u16 data_len; + + buf_len = get_unaligned_be32(&cdb[6]); + if (buf_len < PD_TEXT_ID_INFO_HDR_LEN) + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + + data_len = strlen(dev->t10_wwn.pd_text_id_info); + if (data_len > 0) + /* trailing null */ + data_len += 1; + + data_len = data_len + PD_TEXT_ID_INFO_HDR_LEN; + + if (data_len < buf_len) + buf_len = data_len; + + buf = kzalloc(buf_len, GFP_KERNEL); + if (!buf) { + pr_err("Unable to allocate response buffer for IDENTITY INFO\n"); + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + } + + scnprintf(&buf[PD_TEXT_ID_INFO_HDR_LEN], buf_len - PD_TEXT_ID_INFO_HDR_LEN, "%s", + dev->t10_wwn.pd_text_id_info); + + put_unaligned_be16(data_len, &buf[2]); + + rbuf = transport_kmap_data_sg(cmd); + if (!rbuf) { + pr_err("transport_kmap_data_sg() failed in %s\n", __func__); + kfree(buf); + return TCM_OUT_OF_RESOURCES; + } + + memcpy(rbuf, buf, buf_len); + transport_kunmap_data_sg(cmd); + kfree(buf); + + target_complete_cmd_with_length(cmd, SAM_STAT_GOOD, buf_len); + return TCM_NO_SENSE; +} + +static sense_reason_t +spc_emulate_report_id_info(struct se_cmd *cmd) +{ + u8 *cdb = cmd->t_task_cdb; + sense_reason_t rc; + + switch ((cdb[10] >> 1)) { + case 2: + rc = spc_fill_pd_text_id_info(cmd, cdb); + break; + default: + return TCM_UNSUPPORTED_SCSI_OPCODE; + } + + return rc; +} + sense_reason_t spc_parse_cdb(struct se_cmd *cmd, unsigned int *size) { @@ -2442,6 +2523,11 @@ spc_parse_cdb(struct se_cmd *cmd, unsigned int *size) MI_REPORT_SUPPORTED_OPERATION_CODES) cmd->execute_cmd = spc_emulate_report_supp_op_codes; + if ((cdb[1] & 0x1f) == + MI_REPORT_IDENTIFYING_INFORMATION) { + cmd->execute_cmd = + spc_emulate_report_id_info; + } *size = get_unaligned_be32(&cdb[6]); } else { /* diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 7016d93fa383..b62d5fcce950 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -108,6 +108,9 @@ #define SE_MODE_PAGE_BUF 512 #define SE_SENSE_BUF 96 +/* Peripheral Device Text Identification Information */ +#define PD_TEXT_ID_INFO_LEN 256 + enum target_submit_type { /* Use the fabric driver's default submission type */ TARGET_FABRIC_DEFAULT_SUBMIT, @@ -348,6 +351,7 @@ struct t10_wwn { struct se_device *t10_dev; struct config_group t10_wwn_group; struct list_head t10_vpd_list; + char pd_text_id_info[PD_TEXT_ID_INFO_LEN]; }; struct t10_pr_registration { From e642331c942003f58dba6e33c8ee93402211b7b6 Mon Sep 17 00:00:00 2001 From: vamshi gajjela Date: Thu, 11 Dec 2025 19:02:27 +0530 Subject: [PATCH 02/78] scsi: ufs: core: mcq: Use ufshcd_rmwl() instead of open-coding it Currently, ufshcd_mcq_enable_esi() manually implements a read-modify-write sequence using ufshcd_readl() and ufshcd_writel(). It also utilizes a hardcoded magic number (0x2) for the enable bit. Use ufshcd_rmwl() helper, replace the magic number with the ESI_ENABLE macro to improve code readability. No functional change intended. Signed-off-by: vamshi gajjela Reviewed-by: Bart Van Assche Link: https://patch.msgid.link/20251211133227.4159394-1-vamshigajjela@google.com Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufs-mcq.c | 3 +-- include/ufs/ufshci.h | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/ufs/core/ufs-mcq.c b/drivers/ufs/core/ufs-mcq.c index 9ab91b4c05b0..64c234096e23 100644 --- a/drivers/ufs/core/ufs-mcq.c +++ b/drivers/ufs/core/ufs-mcq.c @@ -431,8 +431,7 @@ void ufshcd_mcq_disable(struct ufs_hba *hba) void ufshcd_mcq_enable_esi(struct ufs_hba *hba) { - ufshcd_writel(hba, ufshcd_readl(hba, REG_UFS_MEM_CFG) | 0x2, - REG_UFS_MEM_CFG); + ufshcd_rmwl(hba, ESI_ENABLE, ESI_ENABLE, REG_UFS_MEM_CFG); } EXPORT_SYMBOL_GPL(ufshcd_mcq_enable_esi); diff --git a/include/ufs/ufshci.h b/include/ufs/ufshci.h index d36df24242a3..806fdaf52bd9 100644 --- a/include/ufs/ufshci.h +++ b/include/ufs/ufshci.h @@ -288,6 +288,7 @@ enum { /* REG_UFS_MEM_CFG - Global Config Registers 300h */ #define MCQ_MODE_SELECT BIT(0) +#define ESI_ENABLE BIT(1) /* CQISy - CQ y Interrupt Status Register */ #define UFSHCD_MCQ_CQIS_TAIL_ENT_PUSH_STS 0x1 From a743b120227a371f37c46738d91cc7a9691dbcf6 Mon Sep 17 00:00:00 2001 From: John Garry Date: Thu, 13 Nov 2025 13:36:40 +0000 Subject: [PATCH 03/78] scsi: scsi_debug: Stop printing extra function name in debug logs The driver defines as follows pr_fmt: #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ ...meaning that we already get the function name added in any debug statements. Remove using of __func__ in debug logs to avoid the duplication. For instances of where the function name was being printed, add some verbose comment to avoid using "" (which would be a bit silly). It would be nicer to stop using pr_fmt(), but that would mean rewriting approx 100 debug statements to have a sensible and clear message. Signed-off-by: John Garry Link: https://patch.msgid.link/20251113133645.2898748-2-john.g.garry@oracle.com Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_debug.c | 101 +++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 56 deletions(-) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 1f2a53ba5dd9..19ebfb2b67e1 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -1371,8 +1371,7 @@ static void mk_sense_invalid_fld(struct scsi_cmnd *scp, sbuff = scp->sense_buffer; if (!sbuff) { - sdev_printk(KERN_ERR, scp->device, - "%s: sense_buffer is NULL\n", __func__); + sdev_printk(KERN_ERR, scp->device, "sense_buffer is NULL\n"); return; } asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST; @@ -1404,8 +1403,7 @@ static void mk_sense_invalid_fld(struct scsi_cmnd *scp, static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq) { if (!scp->sense_buffer) { - sdev_printk(KERN_ERR, scp->device, - "%s: sense_buffer is NULL\n", __func__); + sdev_printk(KERN_ERR, scp->device, "sense_buffer is NULL\n"); return; } memset(scp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); @@ -1423,8 +1421,7 @@ static void mk_sense_info_tape(struct scsi_cmnd *scp, int key, int asc, int asq, unsigned int information, unsigned char tape_flags) { if (!scp->sense_buffer) { - sdev_printk(KERN_ERR, scp->device, - "%s: sense_buffer is NULL\n", __func__); + sdev_printk(KERN_ERR, scp->device, "sense_buffer is NULL\n"); return; } memset(scp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); @@ -1452,15 +1449,12 @@ static int scsi_debug_ioctl(struct scsi_device *dev, unsigned int cmd, { if (sdebug_verbose) { if (0x1261 == cmd) - sdev_printk(KERN_INFO, dev, - "%s: BLKFLSBUF [0x1261]\n", __func__); + sdev_printk(KERN_INFO, dev, "BLKFLSBUF [0x1261]\n"); else if (0x5331 == cmd) sdev_printk(KERN_INFO, dev, - "%s: CDROM_GET_CAPABILITY [0x5331]\n", - __func__); + "CDROM_GET_CAPABILITY [0x5331]\n"); else - sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n", - __func__, cmd); + sdev_printk(KERN_INFO, dev, "cmd=0x%x\n", cmd); } return -EINVAL; /* return -ENOTTY; // correct return but upsets fdisk */ @@ -1664,8 +1658,8 @@ static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr, act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents, arr, arr_len, skip); - pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n", - __func__, off_dst, scsi_bufflen(scp), act_len, + pr_debug("off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n", + off_dst, scsi_bufflen(scp), act_len, scsi_get_resid(scp)); n = scsi_bufflen(scp) - (off_dst + act_len); scsi_set_resid(scp, min_t(u32, scsi_get_resid(scp), n)); @@ -3188,8 +3182,8 @@ static int resp_mode_select(struct scsi_cmnd *scp, return DID_ERROR << 16; else if (sdebug_verbose && (res < param_len)) sdev_printk(KERN_INFO, scp->device, - "%s: cdb indicated=%d, IO sent=%d bytes\n", - __func__, param_len, res); + "cdb indicated=%d, IO sent=%d bytes\n", + param_len, res); md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2); bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6); off = (mselect6 ? 4 : 8); @@ -5133,8 +5127,7 @@ static int resp_write_scat(struct scsi_cmnd *scp, if (lbdof == 0) { if (sdebug_verbose) sdev_printk(KERN_INFO, scp->device, - "%s: %s: LB Data Offset field bad\n", - my_name, __func__); + "%s: LB Data Offset field bad\n", my_name); mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); return illegal_condition_result; } @@ -5142,8 +5135,7 @@ static int resp_write_scat(struct scsi_cmnd *scp, if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) { if (sdebug_verbose) sdev_printk(KERN_INFO, scp->device, - "%s: %s: LBA range descriptors don't fit\n", - my_name, __func__); + "%s: LBA range descriptors don't fit\n", my_name); mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); return illegal_condition_result; } @@ -5152,8 +5144,8 @@ static int resp_write_scat(struct scsi_cmnd *scp, return SCSI_MLQUEUE_HOST_BUSY; if (sdebug_verbose) sdev_printk(KERN_INFO, scp->device, - "%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n", - my_name, __func__, lbdof_blen); + "%s: Fetch header+scatter_list, lbdof_blen=%u\n", + my_name, lbdof_blen); res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen); if (res == -1) { ret = DID_ERROR << 16; @@ -5170,8 +5162,8 @@ static int resp_write_scat(struct scsi_cmnd *scp, num = get_unaligned_be32(up + 8); if (sdebug_verbose) sdev_printk(KERN_INFO, scp->device, - "%s: %s: k=%d LBA=0x%llx num=%u sg_off=%u\n", - my_name, __func__, k, lba, num, sg_off); + "%s: k=%d LBA=0x%llx num=%u sg_off=%u\n", + my_name, k, lba, num, sg_off); if (num == 0) continue; ret = check_device_access_params(scp, lba, num, true); @@ -5183,8 +5175,8 @@ static int resp_write_scat(struct scsi_cmnd *scp, if ((cum_lb + num) > bt_len) { if (sdebug_verbose) sdev_printk(KERN_INFO, scp->device, - "%s: %s: sum of blocks > data provided\n", - my_name, __func__); + "%s: sum of blocks > data provided\n", + my_name); mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC, 0); ret = illegal_condition_result; @@ -5876,8 +5868,8 @@ static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) goto cleanup; } else if (sdebug_verbose && (ret < (a_num * lb_size))) { sdev_printk(KERN_INFO, scp->device, - "%s: %s: cdb indicated=%u, IO sent=%d bytes\n", - my_name, __func__, a_num * lb_size, ret); + "%s: cdb indicated=%u, IO sent=%d bytes\n", + my_name, a_num * lb_size, ret); } if (is_bytchk3) { for (j = 1, off = lb_size; j < vnum; ++j, off += lb_size) @@ -6685,14 +6677,14 @@ static int scsi_debug_sdev_configure(struct scsi_device *sdp, devip->debugfs_entry = debugfs_create_dir(dev_name(&sdp->sdev_dev), sdebug_debugfs_root); if (IS_ERR_OR_NULL(devip->debugfs_entry)) - pr_info("%s: failed to create debugfs directory for device %s\n", - __func__, dev_name(&sdp->sdev_gendev)); + pr_info("failed to create debugfs directory for device %s\n", + dev_name(&sdp->sdev_gendev)); dentry = debugfs_create_file("error", 0600, devip->debugfs_entry, sdp, &sdebug_error_fops); if (IS_ERR_OR_NULL(dentry)) - pr_info("%s: failed to create error file for device %s\n", - __func__, dev_name(&sdp->sdev_gendev)); + pr_info("failed to create error file for device %s\n", + dev_name(&sdp->sdev_gendev)); return 0; } @@ -6880,7 +6872,7 @@ static int scsi_debug_abort(struct scsi_cmnd *SCpnt) if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) sdev_printk(KERN_INFO, SCpnt->device, - "%s: command%s found\n", __func__, + "command%s found\n", aborted ? "" : " not"); @@ -6968,7 +6960,7 @@ static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt) ++num_dev_resets; if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) - sdev_printk(KERN_INFO, sdp, "%s\n", __func__); + sdev_printk(KERN_INFO, sdp, "doing device reset"); scsi_debug_stop_all_queued(sdp); if (devip) { @@ -7008,7 +7000,7 @@ static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt) ++num_target_resets; if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) - sdev_printk(KERN_INFO, sdp, "%s\n", __func__); + sdev_printk(KERN_INFO, sdp, "doing target reset\n"); list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { if (devip->target == sdp->id) { @@ -7021,7 +7013,7 @@ static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt) if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) sdev_printk(KERN_INFO, sdp, - "%s: %d device(s) found in target\n", __func__, k); + "%d device(s) found in target\n", k); if (sdebug_fail_target_reset(SCpnt)) { scmd_printk(KERN_INFO, SCpnt, "fail target reset 0x%x\n", @@ -7042,7 +7034,7 @@ static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt) ++num_bus_resets; if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) - sdev_printk(KERN_INFO, sdp, "%s\n", __func__); + sdev_printk(KERN_INFO, sdp, "doing bus reset\n"); list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); @@ -7053,7 +7045,7 @@ static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt) if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) sdev_printk(KERN_INFO, sdp, - "%s: %d device(s) found in host\n", __func__, k); + "%d device(s) found in host\n", k); return SUCCESS; } @@ -7065,7 +7057,7 @@ static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt) ++num_host_resets; if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) - sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__); + sdev_printk(KERN_INFO, SCpnt->device, "doing host reset\n"); mutex_lock(&sdebug_host_list_mutex); list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { list_for_each_entry(devip, &sdbg_host->dev_info_list, @@ -7080,7 +7072,7 @@ static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt) stop_all_queued(); if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) sdev_printk(KERN_INFO, SCpnt->device, - "%s: %d device(s) found\n", __func__, k); + "%d device(s) found\n", k); return SUCCESS; } @@ -7231,8 +7223,8 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, scsi_result = device_qfull_result; if (unlikely(SDEBUG_OPT_Q_NOISE & sdebug_opts)) - sdev_printk(KERN_INFO, sdp, "%s: num_in_q=%d +1, status: TASK SET FULL\n", - __func__, num_in_q); + sdev_printk(KERN_INFO, sdp, "num_in_q=%d +1, status: TASK SET FULL\n", + num_in_q); } } @@ -7258,8 +7250,8 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, } if (unlikely(sdebug_verbose && cmnd->result)) - sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n", - __func__, cmnd->result); + sdev_printk(KERN_INFO, sdp, "non-zero result=0x%x\n", + cmnd->result); if (delta_jiff > 0 || ndelay > 0) { ktime_t kt; @@ -8697,7 +8689,7 @@ static int __init scsi_debug_init(void) sdebug_debugfs_root = debugfs_create_dir("scsi_debug", NULL); if (IS_ERR_OR_NULL(sdebug_debugfs_root)) - pr_info("%s: failed to create initial debugfs directory\n", __func__); + pr_info("failed to create initial debugfs directory\n"); for (k = 0; k < hosts_to_add; k++) { if (want_store && k == 0) { @@ -8813,7 +8805,7 @@ static int sdebug_add_store(void) if (unlikely(res < 0)) { xa_unlock_irqrestore(per_store_ap, iflags); kfree(sip); - pr_warn("%s: xa_alloc() errno=%d\n", __func__, -res); + pr_warn("xa_alloc() errno=%d\n", -res); return res; } sdeb_most_recent_idx = n_idx; @@ -8870,7 +8862,7 @@ static int sdebug_add_store(void) return (int)n_idx; err: sdebug_erase_store((int)n_idx, sip); - pr_warn("%s: failed, errno=%d\n", __func__, -res); + pr_warn("failed, errno=%d\n", -res); return res; } @@ -8929,7 +8921,7 @@ clean: put_device(&sdbg_host->dev); else kfree(sdbg_host); - pr_warn("%s: failed, errno=%d\n", __func__, -error); + pr_warn("failed, errno=%d\n", -error); return error; } @@ -8997,7 +8989,7 @@ static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth) if (qdepth > SDEBUG_CANQUEUE) { qdepth = SDEBUG_CANQUEUE; - pr_warn("%s: requested qdepth [%d] exceeds canqueue [%d], trim\n", __func__, + pr_warn("requested qdepth [%d] exceeds canqueue [%d], trim\n", qdepth, SDEBUG_CANQUEUE); } if (qdepth < 1) @@ -9009,7 +9001,7 @@ static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth) mutex_unlock(&sdebug_host_list_mutex); if (SDEBUG_OPT_Q_NOISE & sdebug_opts) - sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d\n", __func__, qdepth); + sdev_printk(KERN_INFO, sdev, "qdepth=%d\n", qdepth); return sdev->queue_depth; } @@ -9282,8 +9274,7 @@ static void scsi_debug_abort_cmd(struct Scsi_Host *shost, struct scsi_cmnd *scp) bool res = false; if (!to_be_aborted_scmd) { - pr_err("%s: command with tag %#x not found\n", __func__, - unique_tag); + pr_err("command with tag %#x not found\n", unique_tag); return; } @@ -9291,11 +9282,9 @@ static void scsi_debug_abort_cmd(struct Scsi_Host *shost, struct scsi_cmnd *scp) res = scsi_debug_stop_cmnd(to_be_aborted_scmd); if (res) - pr_info("%s: aborted command with tag %#x\n", - __func__, unique_tag); + pr_info("aborted command with tag %#x\n", unique_tag); else - pr_err("%s: failed to abort command with tag %#x\n", - __func__, unique_tag); + pr_err("failed to abort command with tag %#x\n", unique_tag); set_host_byte(scp, res ? DID_OK : DID_ERROR); } From 559ae7a26b105f9e0b1279b3ab8029623592e900 Mon Sep 17 00:00:00 2001 From: John Garry Date: Thu, 13 Nov 2025 13:36:41 +0000 Subject: [PATCH 04/78] scsi: scsi_debug: Stop using READ/WRITE_ONCE() when accessing sdebug_defer.defer_t Using READ/WRITE_ONCE() means that the read or write is not torn by the compiler. READ/WRITE_ONCE() is always used when accessing sdebug_defer.defer_t. However, we also guard the access in a spinlock when accessing that member, and spinlock already guarantees no tearing, so stop using READ/WRITE_ONCE(). Signed-off-by: John Garry Link: https://patch.msgid.link/20251113133645.2898748-3-john.g.garry@oracle.com Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_debug.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 19ebfb2b67e1..cbe15a76a98b 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -6726,7 +6726,7 @@ static bool scsi_debug_stop_cmnd(struct scsi_cmnd *cmnd) { struct sdebug_scsi_cmd *sdsc = scsi_cmd_priv(cmnd); struct sdebug_defer *sd_dp = &sdsc->sd_dp; - enum sdeb_defer_type defer_t = READ_ONCE(sd_dp->defer_t); + enum sdeb_defer_type defer_t = sd_dp->defer_t; lockdep_assert_held(&sdsc->lock); @@ -7288,12 +7288,12 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, if (polled) { spin_lock_irqsave(&sdsc->lock, flags); sd_dp->cmpl_ts = ktime_add(ns_to_ktime(ns_from_boot), kt); - WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_POLL); + sd_dp->defer_t = SDEB_DEFER_POLL; spin_unlock_irqrestore(&sdsc->lock, flags); } else { /* schedule the invocation of scsi_done() for a later time */ spin_lock_irqsave(&sdsc->lock, flags); - WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_HRT); + sd_dp->defer_t = SDEB_DEFER_HRT; hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED); /* * The completion handler will try to grab sqcp->lock, @@ -7317,11 +7317,11 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, if (polled) { spin_lock_irqsave(&sdsc->lock, flags); sd_dp->cmpl_ts = ns_to_ktime(ns_from_boot); - WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_POLL); + sd_dp->defer_t = SDEB_DEFER_POLL; spin_unlock_irqrestore(&sdsc->lock, flags); } else { spin_lock_irqsave(&sdsc->lock, flags); - WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_WQ); + sd_dp->defer_t = SDEB_DEFER_WQ; schedule_work(&sd_dp->ew.work); spin_unlock_irqrestore(&sdsc->lock, flags); } @@ -9125,7 +9125,7 @@ static bool sdebug_blk_mq_poll_iter(struct request *rq, void *opaque) spin_lock_irqsave(&sdsc->lock, flags); sd_dp = &sdsc->sd_dp; - if (READ_ONCE(sd_dp->defer_t) != SDEB_DEFER_POLL) { + if (sd_dp->defer_t != SDEB_DEFER_POLL) { spin_unlock_irqrestore(&sdsc->lock, flags); return true; } From a8cf5c1bee0fe1b3a829118d636d4f1ea6b408b0 Mon Sep 17 00:00:00 2001 From: John Garry Date: Thu, 13 Nov 2025 13:36:42 +0000 Subject: [PATCH 05/78] scsi: scsi_debug: Drop NULL scsi_cmnd check in sdebug_q_cmd_complete() The scp pointer cannot be NULL, as it is evaluated from container_of() and pointer offsets (so remove the check in sdebug_q_cmd_complete()). Signed-off-by: John Garry Link: https://patch.msgid.link/20251113133645.2898748-4-john.g.garry@oracle.com Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_debug.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index cbe15a76a98b..9f17e9c49cb5 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -6396,11 +6396,6 @@ static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp) atomic_inc(&sdebug_miss_cpus); } - if (!scp) { - pr_err("scmd=NULL\n"); - return; - } - spin_lock_irqsave(&sdsc->lock, flags); aborted = sd_dp->aborted; if (unlikely(aborted)) From 1a56e63c82161fca8f8d93b0ce5ce66c7c7d6b6d Mon Sep 17 00:00:00 2001 From: "Yury Norov (NVIDIA)" Date: Fri, 5 Dec 2025 18:58:08 -0500 Subject: [PATCH 06/78] scsi: lpfc: Rework lpfc_sli4_fcf_rr_next_index_get() The function opencodes for_each_set_bit_wrap(). Use it, and while there switch from goto-driven codeflow to more high-level constructions. Signed-off-by: Yury Norov (NVIDIA) Reviewed-by: Justin Tee Link: https://patch.msgid.link/20251205235808.358258-1-yury.norov@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_sli.c | 62 +++++++++++------------------------- 1 file changed, 18 insertions(+), 44 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 73d77cfab5f8..734af3d039f8 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -20432,62 +20432,36 @@ lpfc_check_next_fcf_pri_level(struct lpfc_hba *phba) uint16_t lpfc_sli4_fcf_rr_next_index_get(struct lpfc_hba *phba) { - uint16_t next_fcf_index; + uint16_t next; -initial_priority: - /* Search start from next bit of currently registered FCF index */ - next_fcf_index = phba->fcf.current_rec.fcf_indx; + do { + for_each_set_bit_wrap(next, phba->fcf.fcf_rr_bmask, + LPFC_SLI4_FCF_TBL_INDX_MAX, phba->fcf.current_rec.fcf_indx) { + if (next == phba->fcf.current_rec.fcf_indx) + continue; -next_priority: - /* Determine the next fcf index to check */ - next_fcf_index = (next_fcf_index + 1) % LPFC_SLI4_FCF_TBL_INDX_MAX; - next_fcf_index = find_next_bit(phba->fcf.fcf_rr_bmask, - LPFC_SLI4_FCF_TBL_INDX_MAX, - next_fcf_index); + if (!(phba->fcf.fcf_pri[next].fcf_rec.flag & LPFC_FCF_FLOGI_FAILED)) { + lpfc_printf_log(phba, KERN_INFO, LOG_FIP, + "2845 Get next roundrobin failover FCF (x%x)\n", next); + return next; + } - /* Wrap around condition on phba->fcf.fcf_rr_bmask */ - if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) { - /* - * If we have wrapped then we need to clear the bits that - * have been tested so that we can detect when we should - * change the priority level. - */ - next_fcf_index = find_first_bit(phba->fcf.fcf_rr_bmask, - LPFC_SLI4_FCF_TBL_INDX_MAX); - } + if (list_is_singular(&phba->fcf.fcf_pri_list)) + return LPFC_FCOE_FCF_NEXT_NONE; + } - - /* Check roundrobin failover list empty condition */ - if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX || - next_fcf_index == phba->fcf.current_rec.fcf_indx) { /* * If next fcf index is not found check if there are lower * Priority level fcf's in the fcf_priority list. * Set up the rr_bmask with all of the avaiable fcf bits * at that level and continue the selection process. */ - if (lpfc_check_next_fcf_pri_level(phba)) - goto initial_priority; - lpfc_printf_log(phba, KERN_WARNING, LOG_FIP, - "2844 No roundrobin failover FCF available\n"); + } while (lpfc_check_next_fcf_pri_level(phba)); - return LPFC_FCOE_FCF_NEXT_NONE; - } + lpfc_printf_log(phba, KERN_WARNING, LOG_FIP, + "2844 No roundrobin failover FCF available\n"); - if (next_fcf_index < LPFC_SLI4_FCF_TBL_INDX_MAX && - phba->fcf.fcf_pri[next_fcf_index].fcf_rec.flag & - LPFC_FCF_FLOGI_FAILED) { - if (list_is_singular(&phba->fcf.fcf_pri_list)) - return LPFC_FCOE_FCF_NEXT_NONE; - - goto next_priority; - } - - lpfc_printf_log(phba, KERN_INFO, LOG_FIP, - "2845 Get next roundrobin failover FCF (x%x)\n", - next_fcf_index); - - return next_fcf_index; + return LPFC_FCOE_FCF_NEXT_NONE; } /** From bd2bc528691e11ea945fbac485eb84c102a521d8 Mon Sep 17 00:00:00 2001 From: Sarah Catania Date: Wed, 10 Dec 2025 16:16:57 -0800 Subject: [PATCH 07/78] scsi: scsi_transport_fc: Introduce encryption group in fc_rport attribute Introduce a new structure for reporting an encrypted session over an fc_rport. The encryption group is added as an attribute in struct fc_rport and reports information in fc_encryption_info. This structure contains a status member variable, which stores a bit value indicating an encrypted session. Signed-off-by: Sarah Catania Signed-off-by: Justin Tee Link: https://patch.msgid.link/20251211001659.138635-2-justintee8345@gmail.com Signed-off-by: Martin K. Petersen --- drivers/base/transport_class.c | 8 ++++++ drivers/scsi/scsi_transport_fc.c | 42 ++++++++++++++++++++++++++++++++ include/linux/transport_class.h | 1 + include/scsi/scsi_transport_fc.h | 12 +++++++++ 4 files changed, 63 insertions(+) diff --git a/drivers/base/transport_class.c b/drivers/base/transport_class.c index 09ee2a1e35bb..69c6ac2e8263 100644 --- a/drivers/base/transport_class.c +++ b/drivers/base/transport_class.c @@ -169,6 +169,12 @@ static int transport_add_class_device(struct attribute_container *cont, goto err_del; } + if (tcont->encryption) { + error = sysfs_create_group(&classdev->kobj, tcont->encryption); + if (error) + goto err_del; + } + return 0; err_del: @@ -244,6 +250,8 @@ static int transport_remove_classdev(struct attribute_container *cont, if (tclass->remove != anon_transport_dummy_function) { if (tcont->statistics) sysfs_remove_group(&classdev->kobj, tcont->statistics); + if (tcont->encryption) + sysfs_remove_group(&classdev->kobj, tcont->encryption); attribute_container_class_device_del(classdev); } diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 987befb02408..b95c46a346fb 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -1328,6 +1328,46 @@ store_fc_rport_fast_io_fail_tmo(struct device *dev, static FC_DEVICE_ATTR(rport, fast_io_fail_tmo, S_IRUGO | S_IWUSR, show_fc_rport_fast_io_fail_tmo, store_fc_rport_fast_io_fail_tmo); +#define fc_rport_encryption(name) \ +static ssize_t fc_rport_encinfo_##name(struct device *cd, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + struct fc_rport *rport = transport_class_to_rport(cd); \ + struct Scsi_Host *shost = rport_to_shost(rport); \ + struct fc_internal *i = to_fc_internal(shost->transportt); \ + struct fc_encryption_info *info; \ + ssize_t ret = -ENOENT; \ + u32 data; \ + \ + if (i->f->get_fc_rport_enc_info) { \ + info = (i->f->get_fc_rport_enc_info)(rport); \ + if (info) { \ + data = info->name; \ + if (!strcmp(#name, "status")) { \ + ret = scnprintf(buf, \ + FC_RPORT_ENCRYPTION_STATUS_MAX_LEN, \ + "%s\n", \ + data ? "Encrypted" : "Unencrypted"); \ + } \ + } \ + } \ + return ret; \ +} \ +static FC_DEVICE_ATTR(rport, encryption_##name, 0444, fc_rport_encinfo_##name, NULL) \ + +fc_rport_encryption(status); + +static struct attribute *fc_rport_encryption_attrs[] = { + &device_attr_rport_encryption_status.attr, + NULL +}; + +static struct attribute_group fc_rport_encryption_group = { + .name = "encryption", + .attrs = fc_rport_encryption_attrs, +}; + #define fc_rport_fpin_statistic(name) \ static ssize_t fc_rport_fpinstat_##name(struct device *cd, \ struct device_attribute *attr, \ @@ -2633,6 +2673,8 @@ fc_attach_transport(struct fc_function_template *ft) i->rport_attr_cont.ac.attrs = &i->rport_attrs[0]; i->rport_attr_cont.ac.class = &fc_rport_class.class; i->rport_attr_cont.ac.match = fc_rport_match; + if (ft->get_fc_rport_enc_info) + i->rport_attr_cont.encryption = &fc_rport_encryption_group; i->rport_attr_cont.statistics = &fc_rport_statistics_group; transport_container_register(&i->rport_attr_cont); diff --git a/include/linux/transport_class.h b/include/linux/transport_class.h index 2efc271a96fa..a009d66db15a 100644 --- a/include/linux/transport_class.h +++ b/include/linux/transport_class.h @@ -56,6 +56,7 @@ struct anon_transport_class cls = { \ struct transport_container { struct attribute_container ac; const struct attribute_group *statistics; + const struct attribute_group *encryption; }; #define attribute_container_to_transport_container(x) \ diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h index b908aacfef48..9f30625aa0d3 100644 --- a/include/scsi/scsi_transport_fc.h +++ b/include/scsi/scsi_transport_fc.h @@ -317,6 +317,15 @@ struct fc_fpin_stats { u64 cn_device_specific; }; +#define FC_RPORT_ENCRYPTION_STATUS_MAX_LEN 14 +/* + * Encryption Information + */ +struct fc_encryption_info { + /* Encryption Status */ + u8 status; +}; + /* Macro for use in defining Remote Port attributes */ #define FC_RPORT_ATTR(_name,_mode,_show,_store) \ struct device_attribute dev_attr_rport_##_name = \ @@ -364,6 +373,7 @@ struct fc_rport { /* aka fc_starget_attrs */ u64 port_name; u32 port_id; u32 roles; + struct fc_encryption_info enc_info; enum fc_port_state port_state; /* Will only be ONLINE or UNKNOWN */ u32 scsi_target_id; u32 fast_io_fail_tmo; @@ -691,6 +701,8 @@ struct fc_function_template { struct fc_host_statistics * (*get_fc_host_stats)(struct Scsi_Host *); void (*reset_fc_host_stats)(struct Scsi_Host *); + struct fc_encryption_info * (*get_fc_rport_enc_info)(struct fc_rport *); + int (*issue_fc_host_lip)(struct Scsi_Host *); void (*dev_loss_tmo_callbk)(struct fc_rport *); From e2dacf8e5e33e9d268874882ad1e0d307f693db0 Mon Sep 17 00:00:00 2001 From: Sarah Catania Date: Wed, 10 Dec 2025 16:16:58 -0800 Subject: [PATCH 08/78] scsi: lpfc: Add support for reporting encryption events Support logging encryption events in both point-to-point and fabric topologies. A new LOG_ENCRYPTION flag is defined for reporting encryption related events for HBAs that support the FEDIF feature. Encryption information is stored in each NDLP object, which is determined during the discovery stage after PLOGI completes. For reporting encryption information to upper layers, the .get_fc_rport_enc_info routine is implemented in lpfc_get_enc_info(). This allows encryption status to be reported through fc_remote_ports sysfs. Debugfs is also updated to report encryption information for all NDLP objects. Signed-off-by: Sarah Catania Signed-off-by: Justin Tee Link: https://patch.msgid.link/20251211001659.138635-3-justintee8345@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_attr.c | 40 ++++++++++++++++++++++ drivers/scsi/lpfc/lpfc_debugfs.c | 7 ++++ drivers/scsi/lpfc/lpfc_disc.h | 7 ++++ drivers/scsi/lpfc/lpfc_els.c | 57 ++++++++++++++++++++++++++++++++ drivers/scsi/lpfc/lpfc_hbadisc.c | 1 + drivers/scsi/lpfc/lpfc_hw4.h | 11 +++++- drivers/scsi/lpfc/lpfc_init.c | 5 +++ drivers/scsi/lpfc/lpfc_logmsg.h | 3 +- drivers/scsi/lpfc/lpfc_sli4.h | 4 +++ 9 files changed, 133 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 33582d48ec09..4af5c069635a 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -6979,6 +6979,42 @@ lpfc_reset_stats(struct Scsi_Host *shost) return; } +/** + * lpfc_get_enc_info - Return encryption information about the session for + * a given remote port. + * @rport: ptr to fc_rport from scsi transport fc + * + * Given an rport object, iterate through the fc_nodes list to find node + * corresponding with rport. Pass the encryption information from the node to + * rport's encryption attribute for reporting to upper layers. Information is + * passed through nlp_enc_info struct which contains encryption status. + * + * Returns: + * - Address of rport's fc_encryption_info struct + * - NULL when not found + **/ +static struct fc_encryption_info * +lpfc_get_enc_info(struct fc_rport *rport) +{ + struct Scsi_Host *shost = rport_to_shost(rport); + struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; + struct fc_encryption_info *ef = NULL; + struct lpfc_nodelist *ndlp, *next_ndlp; + unsigned long iflags; + + spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags); + list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { + if (ndlp->rport && ndlp->rport == rport) { + ef = &rport->enc_info; + ef->status = ndlp->nlp_enc_info.status; + break; + } + } + spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags); + return ef; +} + + /* * The LPFC driver treats linkdown handling as target loss events so there * are no sysfs handlers for link_down_tmo. @@ -7196,6 +7232,8 @@ struct fc_function_template lpfc_transport_functions = { .get_fc_host_stats = lpfc_get_stats, .reset_fc_host_stats = lpfc_reset_stats, + .get_fc_rport_enc_info = lpfc_get_enc_info, + .dd_fcrport_size = sizeof(struct lpfc_rport_data), .show_rport_maxframe_size = 1, .show_rport_supported_classes = 1, @@ -7265,6 +7303,8 @@ struct fc_function_template lpfc_vport_transport_functions = { .get_fc_host_stats = lpfc_get_stats, .reset_fc_host_stats = lpfc_reset_stats, + .get_fc_rport_enc_info = lpfc_get_enc_info, + .dd_fcrport_size = sizeof(struct lpfc_rport_data), .show_rport_maxframe_size = 1, .show_rport_supported_classes = 1, diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index 92b5b2dbe847..646f88c776f5 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -872,6 +872,13 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) ndlp->nlp_rpi); len += scnprintf(buf+len, size-len, "flag:x%08lx ", ndlp->nlp_flag); + if (ndlp->nlp_enc_info.status) { + len += scnprintf(buf + len, + size - len, "ENCRYPTED"); + len += scnprintf(buf + len, size - len, + ndlp->nlp_enc_info.level + ? "(CNSA2.0) " : "(CNSA1.0) "); + } if (!ndlp->nlp_type) len += scnprintf(buf+len, size-len, "UNKNOWN_TYPE "); if (ndlp->nlp_type & NLP_FC_NODE) diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h index 51cb8571c049..de0adeecf668 100644 --- a/drivers/scsi/lpfc/lpfc_disc.h +++ b/drivers/scsi/lpfc/lpfc_disc.h @@ -77,6 +77,11 @@ struct lpfc_node_rrqs { unsigned long xri_bitmap[XRI_BITMAP_ULONGS]; }; +struct lpfc_enc_info { + u8 status; /* encryption status for session */ + u8 level; /* CNSA encryption level */ +}; + enum lpfc_fc4_xpt_flags { NLP_XPT_REGD = 0x1, SCSI_XPT_REGD = 0x2, @@ -138,6 +143,8 @@ struct lpfc_nodelist { uint8_t vmid_support; /* destination VMID support */ #define NLP_NVME_NSLER 0x1 /* NVME NSLER device */ + struct lpfc_enc_info nlp_enc_info; /* Encryption information struct */ + struct timer_list nlp_delayfunc; /* Used for delayed ELS cmds */ struct lpfc_hba *phba; struct fc_rport *rport; /* scsi_transport_fc port structure */ diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 02b6d31b9ad9..32da3c23c7f4 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -2014,6 +2014,58 @@ lpfc_cmpl_els_rrq(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_nlp_put(ndlp); return; } + +/** + * lpfc_check_encryption - Reports an ndlp's encryption information + * @phba: pointer to lpfc hba data structure. + * @ndlp: pointer to a node-list data structure. + * @cmdiocb: pointer to lpfc command iocbq data structure. + * @rspiocb: pointer to lpfc response iocbq data structure. + * + * This routine is called in the completion callback function for issuing + * or receiving a Port Login (PLOGI) command. In a PLOGI completion, if FEDIF + * is supported, encryption information will be provided in completion status + * data. If @phba supports FEDIF, a log message containing encryption + * information will be logged. Encryption status is also saved for encryption + * reporting with upper layer through the rport encryption attribute. + **/ +static void +lpfc_check_encryption(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, + struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) +{ + struct lpfc_vport *vport = cmdiocb->vport; + u32 did = ndlp->nlp_DID; + struct lpfc_enc_info *nlp_enc_info = &ndlp->nlp_enc_info; + char enc_status[FC_RPORT_ENCRYPTION_STATUS_MAX_LEN] = {0}; + char enc_level[8] = "N/A"; + u8 encryption; + + if (phba->sli4_hba.encryption_support && + ((did & Fabric_DID_MASK) != Fabric_DID_MASK)) { + encryption = bf_get(lpfc_wcqe_c_enc, + &rspiocb->wcqe_cmpl); + nlp_enc_info->status = encryption; + + strscpy(enc_status, encryption ? "Encrypted" : "Unencrypted", + sizeof(enc_status)); + + if (encryption) { + nlp_enc_info->level = bf_get(lpfc_wcqe_c_enc_lvl, + &rspiocb->wcqe_cmpl); + strscpy(enc_level, nlp_enc_info->level ? "CNSA2.0" : + "CNSA1.0", + sizeof(enc_level)); + } + + lpfc_printf_vlog(vport, KERN_INFO, LOG_ENCRYPTION, + "0924 DID:x%06x %s Session " + "Established, Encryption Level:%s " + "rpi:x%x\n", + ndlp->nlp_DID, enc_status, enc_level, + ndlp->nlp_rpi); + } +} + /** * lpfc_cmpl_els_plogi - Completion callback function for plogi * @phba: pointer to lpfc hba data structure. @@ -2153,6 +2205,8 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, goto out; ndlp = lpfc_plogi_confirm_nport(phba, prsp->virt, ndlp); + lpfc_check_encryption(phba, ndlp, cmdiocb, rspiocb); + sp = (struct serv_parm *)((u8 *)prsp->virt + sizeof(u32)); @@ -5407,6 +5461,9 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, goto out; } + if (!ulp_status && test_bit(NLP_RCV_PLOGI, &ndlp->nlp_flag)) + lpfc_check_encryption(phba, ndlp, cmdiocb, rspiocb); + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, "ELS rsp cmpl: status:x%x/x%x did:x%x", ulp_status, ulp_word4, did); diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index bb803f32bc1b..1aeebdc08073 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -5340,6 +5340,7 @@ out: clear_bit(NLP_NPR_ADISC, &ndlp->nlp_flag); if (acc_plogi) clear_bit(NLP_LOGO_ACC, &ndlp->nlp_flag); + memset(&ndlp->nlp_enc_info, 0, sizeof(ndlp->nlp_enc_info)); return 1; } clear_bit(NLP_LOGO_ACC, &ndlp->nlp_flag); diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index a7f7ed86d2b0..c000474c3066 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -437,6 +437,12 @@ struct lpfc_wcqe_complete { #define lpfc_wcqe_c_cmf_bw_MASK 0x0FFFFFFF #define lpfc_wcqe_c_cmf_bw_WORD total_data_placed uint32_t parameter; +#define lpfc_wcqe_c_enc_SHIFT 31 +#define lpfc_wcqe_c_enc_MASK 0x00000001 +#define lpfc_wcqe_c_enc_WORD parameter +#define lpfc_wcqe_c_enc_lvl_SHIFT 30 +#define lpfc_wcqe_c_enc_lvl_MASK 0x00000001 +#define lpfc_wcqe_c_enc_lvl_WORD parameter #define lpfc_wcqe_c_bg_edir_SHIFT 5 #define lpfc_wcqe_c_bg_edir_MASK 0x00000001 #define lpfc_wcqe_c_bg_edir_WORD parameter @@ -2942,7 +2948,10 @@ struct lpfc_mbx_read_config { #define lpfc_mbx_rd_conf_topology_SHIFT 24 #define lpfc_mbx_rd_conf_topology_MASK 0x000000FF #define lpfc_mbx_rd_conf_topology_WORD word2 - uint32_t rsvd_3; + uint32_t word3; +#define lpfc_mbx_rd_conf_fedif_SHIFT 6 +#define lpfc_mbx_rd_conf_fedif_MASK 0x00000001 +#define lpfc_mbx_rd_conf_fedif_WORD word3 uint32_t word4; #define lpfc_mbx_rd_conf_e_d_tov_SHIFT 0 #define lpfc_mbx_rd_conf_e_d_tov_MASK 0x0000FFFF diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index b1460b16dd91..a116a16c4a6f 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -9999,6 +9999,11 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) (phba->sli4_hba.max_cfg_param.max_vpi - 1) : 0; phba->max_vports = phba->max_vpi; + if (bf_get(lpfc_mbx_rd_conf_fedif, rd_config)) + phba->sli4_hba.encryption_support = true; + else + phba->sli4_hba.encryption_support = false; + /* Next decide on FPIN or Signal E2E CGN support * For congestion alarms and warnings valid combination are: * 1. FPIN alarms / FPIN warnings diff --git a/drivers/scsi/lpfc/lpfc_logmsg.h b/drivers/scsi/lpfc/lpfc_logmsg.h index 59bd2bafc73f..e00d101d548c 100644 --- a/drivers/scsi/lpfc/lpfc_logmsg.h +++ b/drivers/scsi/lpfc/lpfc_logmsg.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2025 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2009 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -47,6 +47,7 @@ #define LOG_RSVD1 0x01000000 /* Reserved */ #define LOG_RSVD2 0x02000000 /* Reserved */ #define LOG_CGN_MGMT 0x04000000 /* Congestion Mgmt events */ +#define LOG_ENCRYPTION 0x40000000 /* EDIF Encryption events. */ #define LOG_TRACE_EVENT 0x80000000 /* Dmp the DBG log on this err */ #define LOG_ALL_MSG 0x7fffffff /* LOG all messages */ diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index fd6dab157887..ee58383492b2 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -888,6 +888,10 @@ struct lpfc_sli4_hba { #define LPFC_FP_EQ_MAX_INTR_SEC 10000 uint32_t intr_enable; + + /* Indicates whether SLI Port supports FEDIF */ + bool encryption_support; + struct lpfc_bmbx bmbx; struct lpfc_max_cfg_param max_cfg_param; uint16_t extents_in_use; /* must allocate resource extents. */ From 6211644253153e4a86892112121ea597d02b5e12 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Wed, 10 Dec 2025 16:16:59 -0800 Subject: [PATCH 09/78] scsi: lpfc: Update lpfc version to 14.4.0.13 Update lpfc version to 14.4.0.13 Signed-off-by: Justin Tee Link: https://patch.msgid.link/20251211001659.138635-4-justintee8345@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index f3dada5bf7c1..c4ca8bf5843a 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -20,7 +20,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "14.4.0.12" +#define LPFC_DRIVER_VERSION "14.4.0.13" #define LPFC_DRIVER_NAME "lpfc" /* Used for SLI 2/3 */ From 6b553f2a5c840d38fe2f658bbe18365d40554361 Mon Sep 17 00:00:00 2001 From: Ranjan Kumar Date: Thu, 13 Nov 2025 21:07:05 +0530 Subject: [PATCH 10/78] scsi: mpt3sas: Added no_turs flag to device unblock logic Add a "no_turs" flag to _scsih_ublock_io_all_device() to optionally skip TEST UNIT READY (TUR) checks while unblocking devices. This is used after broadcast events where sending TURs is not required. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202510310216.gerpzbxP-lkp@intel.com/ Signed-off-by: Ranjan Kumar Link: https://patch.msgid.link/20251113153712.31850-2-ranjan.kumar@broadcom.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_scsih.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 7092d0debef3..013b10348ec4 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -3825,11 +3825,12 @@ _scsih_internal_device_unblock(struct scsi_device *sdev, /** * _scsih_ublock_io_all_device - unblock every device * @ioc: per adapter object + * @no_turs: flag to disable TEST UNIT READY checks during device unblocking * * change the device state from block to running */ static void -_scsih_ublock_io_all_device(struct MPT3SAS_ADAPTER *ioc) +_scsih_ublock_io_all_device(struct MPT3SAS_ADAPTER *ioc, u8 no_turs) { struct MPT3SAS_DEVICE *sas_device_priv_data; struct scsi_device *sdev; @@ -3841,6 +3842,13 @@ _scsih_ublock_io_all_device(struct MPT3SAS_ADAPTER *ioc) if (!sas_device_priv_data->block) continue; + if (no_turs) { + sdev_printk(KERN_WARNING, sdev, "device_unblocked handle(0x%04x)\n", + sas_device_priv_data->sas_target->handle); + _scsih_internal_device_unblock(sdev, sas_device_priv_data); + continue; + } + dewtprintk(ioc, sdev_printk(KERN_INFO, sdev, "device_running, handle(0x%04x)\n", sas_device_priv_data->sas_target->handle)); @@ -8810,7 +8818,7 @@ _scsih_sas_broadcast_primitive_event(struct MPT3SAS_ADAPTER *ioc, ioc->broadcast_aen_busy = 0; if (!ioc->shost_recovery) - _scsih_ublock_io_all_device(ioc); + _scsih_ublock_io_all_device(ioc, 1); mutex_unlock(&ioc->tm_cmds.mutex); } @@ -10344,7 +10352,7 @@ _scsih_remove_unresponding_devices(struct MPT3SAS_ADAPTER *ioc) ioc_info(ioc, "removing unresponding devices: complete\n"); /* unblock devices */ - _scsih_ublock_io_all_device(ioc); + _scsih_ublock_io_all_device(ioc, 0); } static void From aee682fad6cdd9e3482b52fab727f50bc0227fae Mon Sep 17 00:00:00 2001 From: Ranjan Kumar Date: Thu, 13 Nov 2025 21:07:06 +0530 Subject: [PATCH 11/78] scsi: mpt3sas: Improve device discovery and readiness handling for slow devices Introduce a new module parameter "issue_scsi_cmd_to_bringup_drive" (default=1) which allows overriding the driver's behavior of issuing SCSI TEST_UNIT_READY/START_UNIT commands to bring devices to READY state during unblock. Improve device discovery and I/O unblocking reliability by adding robust device readiness checks and separate callback handling for discovery I/O. This introduces new helper routines for SCSI command execution and readiness determination, ensuring smoother recovery and initialization for slow or transient devices. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202510310924.crvtELzs-lkp@intel.com/ Signed-off-by: Ranjan Kumar Link: https://patch.msgid.link/20251113153712.31850-4-ranjan.kumar@broadcom.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.c | 6 +- drivers/scsi/mpt3sas/mpt3sas_base.h | 4 + drivers/scsi/mpt3sas/mpt3sas_scsih.c | 1126 +++++++++++++++++++++++++- 3 files changed, 1119 insertions(+), 17 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 0d652db8fe24..5ff31ce0c960 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -1564,6 +1564,8 @@ _base_get_cb_idx(struct MPT3SAS_ADAPTER *ioc, u16 smid) int i; u16 ctl_smid = ioc->scsiio_depth - INTERNAL_SCSIIO_CMDS_COUNT + 1; u8 cb_idx = 0xFF; + u16 discovery_smid = + ioc->shost->can_queue + INTERNAL_SCSIIO_FOR_DISCOVERY; if (smid < ioc->hi_priority_smid) { struct scsiio_tracker *st; @@ -1572,8 +1574,10 @@ _base_get_cb_idx(struct MPT3SAS_ADAPTER *ioc, u16 smid) st = _get_st_from_smid(ioc, smid); if (st) cb_idx = st->cb_idx; - } else if (smid == ctl_smid) + } else if (smid < discovery_smid) cb_idx = ioc->ctl_cb_idx; + else + cb_idx = ioc->scsih_cb_idx; } else if (smid < ioc->internal_smid) { i = smid - ioc->hi_priority_smid; cb_idx = ioc->hpr_lookup[i].cb_idx; diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index e6a6f21d309b..de37fa5ac073 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -147,6 +147,7 @@ #define INTERNAL_CMDS_COUNT 10 /* reserved cmds */ /* reserved for issuing internally framed scsi io cmds */ #define INTERNAL_SCSIIO_CMDS_COUNT 3 +#define INTERNAL_SCSIIO_FOR_DISCOVERY 2 #define MPI3_HIM_MASK 0xFFFFFFFF /* mask every bit*/ @@ -480,6 +481,7 @@ struct MPT3SAS_DEVICE { u32 flags; u8 configured_lun; u8 block; + u8 deleted; u8 tlr_snoop_check; u8 ignore_delay_remove; /* Iopriority Command Handling */ @@ -577,7 +579,9 @@ struct _sas_device { u8 chassis_slot; u8 is_chassis_slot_valid; u8 connector_name[5]; + u8 ssd_device; struct kref refcount; + u8 port_type; struct hba_port *port; struct sas_rphy *rphy; diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 013b10348ec4..3eb6c51ac91e 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -61,6 +61,8 @@ #define PCIE_CHANNEL 2 +#define MPT3_MAX_LUNS (255) + /* forward proto's */ static void _scsih_expander_node_remove(struct MPT3SAS_ADAPTER *ioc, struct _sas_node *sas_expander); @@ -70,13 +72,23 @@ static void _scsih_remove_device(struct MPT3SAS_ADAPTER *ioc, struct _sas_device *sas_device); static int _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 retry_count, u8 is_pd); -static int _scsih_pcie_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle); +static int _scsih_pcie_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, + u8 retry_count); static void _scsih_pcie_device_remove_from_sml(struct MPT3SAS_ADAPTER *ioc, struct _pcie_device *pcie_device); static void _scsih_pcie_check_device(struct MPT3SAS_ADAPTER *ioc, u16 handle); static u8 _scsih_check_for_pending_tm(struct MPT3SAS_ADAPTER *ioc, u16 smid); static void _scsih_complete_devices_scanning(struct MPT3SAS_ADAPTER *ioc); +static enum device_responsive_state +_scsih_wait_for_target_to_become_ready(struct MPT3SAS_ADAPTER *ioc, u16 handle, + u8 retry_count, u8 is_pd, u8 tr_timeout, u8 tr_method); +static enum device_responsive_state +_scsih_ata_pass_thru_idd(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 *is_ssd_device, + u8 tr_timeout, u8 tr_method); +static enum device_responsive_state +_scsih_wait_for_device_to_become_ready(struct MPT3SAS_ADAPTER *ioc, u16 handle, + u8 retry_count, u8 is_pd, int lun, u8 tr_timeout, u8 tr_method); /* global parameters */ LIST_HEAD(mpt3sas_ioc_list); @@ -159,6 +171,15 @@ module_param(enable_sdev_max_qd, bool, 0444); MODULE_PARM_DESC(enable_sdev_max_qd, "Enable sdev max qd as can_queue, def=disabled(0)"); +/* + * permit overriding the SCSI command issuing capability of + * the driver to bring the drive to READY state + */ +static int issue_scsi_cmd_to_bringup_drive = 1; +module_param(issue_scsi_cmd_to_bringup_drive, int, 0444); +MODULE_PARM_DESC(issue_scsi_cmd_to_bringup_drive, "allow host driver to\n" + "issue SCSI commands to bring the drive to READY state, default=1 "); + static int multipath_on_hba = -1; module_param(multipath_on_hba, int, 0); MODULE_PARM_DESC(multipath_on_hba, @@ -177,6 +198,24 @@ MODULE_PARM_DESC(host_tagset_enable, static struct raid_template *mpt3sas_raid_template; static struct raid_template *mpt2sas_raid_template; +/** + * enum device_responsive_state - responsive state + * @DEVICE_READY: device is ready to be added + * @DEVICE_RETRY: device can be retried later + * @DEVICE_RETRY_UA: retry unit attentions + * @DEVICE_START_UNIT: requires start unit + * @DEVICE_STOP_UNIT: requires stop unit + * @DEVICE_ERROR: device reported some fatal error + * + */ +enum device_responsive_state { + DEVICE_READY, + DEVICE_RETRY, + DEVICE_RETRY_UA, + DEVICE_START_UNIT, + DEVICE_STOP_UNIT, + DEVICE_ERROR, +}; /** * struct sense_info - common structure for obtaining sense keys @@ -205,6 +244,9 @@ struct sense_info { /** * struct fw_event_work - firmware event struct + * @retries: retry count for processing the event + * @delayed_work_active: flag indicating if delayed work is active + * @delayed_work: delayed work item for deferred event handling * @list: link list framework * @work: work object (ioc->fault_reset_work_q) * @ioc: per adapter object @@ -219,6 +261,9 @@ struct sense_info { * This object stored on ioc->fw_event_list. */ struct fw_event_work { + u8 *retries; + u8 delayed_work_active; + struct delayed_work delayed_work; struct list_head list; struct work_struct work; @@ -955,6 +1000,7 @@ _scsih_sas_device_remove(struct MPT3SAS_ADAPTER *ioc, sas_device_put(sas_device); } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + } /** @@ -2528,6 +2574,8 @@ scsih_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim) char *r_level = ""; u16 handle, volume_handle = 0; u64 volume_wwid = 0; + enum device_responsive_state retval; + u8 count = 0; qdepth = 1; sas_device_priv_data = sdev->hostdata; @@ -2686,6 +2734,7 @@ scsih_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim) pcie_device_put(pcie_device); spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); + mpt3sas_scsih_change_queue_depth(sdev, qdepth); lim->virt_boundary_mask = ioc->page_size - 1; return 0; @@ -2737,9 +2786,16 @@ scsih_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim) sas_device_put(sas_device); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (!ssp_target) + if (!ssp_target) { _scsih_display_sata_capabilities(ioc, handle, sdev); + do { + retval = _scsih_ata_pass_thru_idd(ioc, handle, + &sas_device->ssd_device, 30, 0); + } while ((retval == DEVICE_RETRY || retval == DEVICE_RETRY_UA) + && count++ < 3); + } + mpt3sas_scsih_change_queue_depth(sdev, qdepth); @@ -3842,7 +3898,7 @@ _scsih_ublock_io_all_device(struct MPT3SAS_ADAPTER *ioc, u8 no_turs) if (!sas_device_priv_data->block) continue; - if (no_turs) { + if ((no_turs) || (!issue_scsi_cmd_to_bringup_drive)) { sdev_printk(KERN_WARNING, sdev, "device_unblocked handle(0x%04x)\n", sas_device_priv_data->sas_target->handle); _scsih_internal_device_unblock(sdev, sas_device_priv_data); @@ -3856,6 +3912,137 @@ _scsih_ublock_io_all_device(struct MPT3SAS_ADAPTER *ioc, u8 no_turs) } } +/** + * _scsih_ublock_io_device_wait - unblock IO for target + * @ioc: per adapter object + * @sas_address: sas address + * @port: hba port entry + * + * make sure device is reponsponding before unblocking + */ +static void +_scsih_ublock_io_device_wait(struct MPT3SAS_ADAPTER *ioc, u64 sas_address, + struct hba_port *port) +{ + struct MPT3SAS_DEVICE *sas_device_priv_data; + struct MPT3SAS_TARGET *sas_target; + enum device_responsive_state rc; + struct scsi_device *sdev; + int host_reset_completion_count; + struct _sas_device *sas_device; + struct _pcie_device *pcie_device; + u8 tr_timeout = 30; + u8 tr_method = 0; + + /* moving devices from SDEV_OFFLINE to SDEV_BLOCK */ + shost_for_each_device(sdev, ioc->shost) { + sas_device_priv_data = sdev->hostdata; + if (!sas_device_priv_data) + continue; + sas_target = sas_device_priv_data->sas_target; + if (!sas_target) + continue; + if (sas_target->sas_address != sas_address || + sas_target->port != port) + continue; + if (sdev->sdev_state == SDEV_OFFLINE) { + sas_device_priv_data->block = 1; + sas_device_priv_data->deleted = 0; + scsi_device_set_state(sdev, SDEV_RUNNING); + scsi_internal_device_block_nowait(sdev); + } + } + + /* moving devices from SDEV_BLOCK to SDEV_RUNNING state */ + shost_for_each_device(sdev, ioc->shost) { + sas_device_priv_data = sdev->hostdata; + if (!sas_device_priv_data) + continue; + sas_target = sas_device_priv_data->sas_target; + if (!sas_target) + continue; + if (sas_target->sas_address != sas_address || + sas_target->port != port) + continue; + if (!sas_device_priv_data->block) + continue; + + do { + host_reset_completion_count = 0; + pcie_device = mpt3sas_get_pdev_by_handle(ioc, sas_target->handle); + if (pcie_device && (!ioc->tm_custom_handling) && + (!(mpt3sas_scsih_is_pcie_scsi_device(pcie_device->device_info)))) { + tr_timeout = pcie_device->reset_timeout; + tr_method = MPI26_SCSITASKMGMT_MSGFLAGS_PROTOCOL_LVL_RST_PCIE; + } + rc = _scsih_wait_for_device_to_become_ready(ioc, + sas_target->handle, 0, (sas_target->flags & + MPT_TARGET_FLAGS_RAID_COMPONENT), sdev->lun, tr_timeout, tr_method); + if (rc == DEVICE_RETRY || rc == DEVICE_START_UNIT || + rc == DEVICE_STOP_UNIT || rc == DEVICE_RETRY_UA) { + do { + msleep(500); + host_reset_completion_count++; + } while (rc == DEVICE_RETRY && + ioc->shost_recovery); + if (host_reset_completion_count > 1) { + rc = _scsih_wait_for_device_to_become_ready(ioc, + sas_target->handle, 0, (sas_target->flags & + MPT_TARGET_FLAGS_RAID_COMPONENT), sdev->lun, + tr_timeout, tr_method); + if (rc == DEVICE_RETRY || rc == DEVICE_START_UNIT || + rc == DEVICE_STOP_UNIT || rc == DEVICE_RETRY_UA) + msleep(500); + } + continue; + } + if (pcie_device) + pcie_device_put(pcie_device); + } while ((rc == DEVICE_RETRY || rc == DEVICE_START_UNIT || + rc == DEVICE_STOP_UNIT || rc == DEVICE_RETRY_UA)); + + sas_device_priv_data->block = 0; + if (rc != DEVICE_READY) + sas_device_priv_data->deleted = 1; + scsi_internal_device_unblock_nowait(sdev, SDEV_RUNNING); + + if (rc != DEVICE_READY) { + sdev_printk(KERN_WARNING, sdev, + "%s: device_offlined, handle(0x%04x)\n", + __func__, sas_device_priv_data->sas_target->handle); + + sas_device = mpt3sas_get_sdev_by_handle(ioc, + sas_device_priv_data->sas_target->handle); + if (sas_device) { + _scsih_display_enclosure_chassis_info(NULL, sas_device, sdev, NULL); + sas_device_put(sas_device); + } else { + pcie_device = mpt3sas_get_pdev_by_handle(ioc, + sas_device_priv_data->sas_target->handle); + if (pcie_device) { + if (pcie_device->enclosure_handle != 0) + sdev_printk(KERN_INFO, sdev, + "device_offlined, enclosure logical id(0x%016llx),\n" + " slot(%d)\n", (unsigned long long) + pcie_device->enclosure_logical_id, + pcie_device->slot); + if (pcie_device->connector_name[0] != '\0') + sdev_printk(KERN_WARNING, sdev, + "device_offlined, enclosure level(0x%04x),\n" + "connector name( %s)\n", + pcie_device->enclosure_level, + pcie_device->connector_name); + pcie_device_put(pcie_device); + } + } + scsi_device_set_state(sdev, SDEV_OFFLINE); + } else { + sdev_printk(KERN_WARNING, sdev, + "device_unblocked, handle(0x%04x)\n", + sas_device_priv_data->sas_target->handle); + } + } +} /** * _scsih_ublock_io_device - prepare device to be deleted @@ -7116,10 +7303,769 @@ _scsih_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) return 1; } +/** + * _scsi_send_scsi_io - send internal SCSI_IO to target + * @ioc: per adapter object + * @transfer_packet: packet describing the transfer + * @tr_timeout: Target Reset Timeout + * @tr_method: Target Reset Method + * Context: user + * + * Returns 0 for success, non-zero for failure. + */ +static int +_scsi_send_scsi_io(struct MPT3SAS_ADAPTER *ioc, struct _scsi_io_transfer + *transfer_packet, u8 tr_timeout, u8 tr_method) +{ + Mpi2SCSIIOReply_t *mpi_reply; + Mpi2SCSIIORequest_t *mpi_request; + u16 smid; + u8 issue_reset = 0; + int rc; + void *priv_sense; + u32 mpi_control; + void *psge; + dma_addr_t data_out_dma = 0; + dma_addr_t data_in_dma = 0; + size_t data_in_sz = 0; + size_t data_out_sz = 0; + u16 handle; + u8 retry_count = 0, host_reset_count = 0; + int tm_return_code; + if (ioc->pci_error_recovery) { + pr_info("%s: pci error recovery in progress!\n", __func__); + return -EFAULT; + } + if (ioc->shost_recovery) { + pr_info("%s: host recovery in progress!\n", __func__); + return -EAGAIN; + } -#define MPT3_MAX_LUNS (255) + handle = transfer_packet->handle; + if (handle == MPT3SAS_INVALID_DEVICE_HANDLE) { + pr_info("%s: no device!\n", __func__); + return -EFAULT; + } + + mutex_lock(&ioc->scsih_cmds.mutex); + + if (ioc->scsih_cmds.status != MPT3_CMD_NOT_USED) { + pr_err("%s: scsih_cmd in use\n", __func__); + rc = -EAGAIN; + goto out; + } + + retry_loop: + if (test_bit(handle, ioc->device_remove_in_progress)) { + pr_info("%s: device removal in progress\n", __func__); + rc = -EFAULT; + goto out; + } + + ioc->scsih_cmds.status = MPT3_CMD_PENDING; + + rc = mpt3sas_wait_for_ioc(ioc, 10); + if (rc) + goto out; + + /* Use second reserved smid for discovery related IOs */ + smid = ioc->shost->can_queue + INTERNAL_SCSIIO_FOR_DISCOVERY; + + rc = 0; + mpi_request = mpt3sas_base_get_msg_frame(ioc, smid); + ioc->scsih_cmds.smid = smid; + memset(mpi_request, 0, sizeof(Mpi2SCSIIORequest_t)); + if (transfer_packet->is_raid) + mpi_request->Function = MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH; + else + mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; + mpi_request->DevHandle = cpu_to_le16(handle); + + switch (transfer_packet->dir) { + case DMA_TO_DEVICE: + mpi_control = MPI2_SCSIIO_CONTROL_WRITE; + data_out_dma = transfer_packet->data_dma; + data_out_sz = transfer_packet->data_length; + break; + case DMA_FROM_DEVICE: + mpi_control = MPI2_SCSIIO_CONTROL_READ; + data_in_dma = transfer_packet->data_dma; + data_in_sz = transfer_packet->data_length; + break; + case DMA_BIDIRECTIONAL: + mpi_control = MPI2_SCSIIO_CONTROL_BIDIRECTIONAL; + /* TODO - is BIDI support needed ?? */ + WARN_ON_ONCE(true); + break; + default: + case DMA_NONE: + mpi_control = MPI2_SCSIIO_CONTROL_NODATATRANSFER; + break; + } + + psge = &mpi_request->SGL; + ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, data_in_dma, + data_in_sz); + + mpi_request->Control = cpu_to_le32(mpi_control | + MPI2_SCSIIO_CONTROL_SIMPLEQ); + mpi_request->DataLength = cpu_to_le32(transfer_packet->data_length); + mpi_request->MsgFlags = MPI2_SCSIIO_MSGFLAGS_SYSTEM_SENSE_ADDR; + mpi_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE; + mpi_request->SenseBufferLowAddress = + mpt3sas_base_get_sense_buffer_dma(ioc, smid); + priv_sense = mpt3sas_base_get_sense_buffer(ioc, smid); + mpi_request->SGLOffset0 = offsetof(Mpi2SCSIIORequest_t, SGL) / 4; + mpi_request->IoFlags = cpu_to_le16(transfer_packet->cdb_length); + int_to_scsilun(transfer_packet->lun, (struct scsi_lun *) + mpi_request->LUN); + memcpy(mpi_request->CDB.CDB32, transfer_packet->cdb, + transfer_packet->cdb_length); + init_completion(&ioc->scsih_cmds.done); + if (likely(mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST)) + ioc->put_smid_scsi_io(ioc, smid, handle); + else + ioc->put_smid_default(ioc, smid); + wait_for_completion_timeout(&ioc->scsih_cmds.done, + transfer_packet->timeout*HZ); + if (!(ioc->scsih_cmds.status & MPT3_CMD_COMPLETE)) { + mpt3sas_check_cmd_timeout(ioc, + ioc->scsih_cmds.status, mpi_request, + sizeof(Mpi2SCSIIORequest_t)/4, issue_reset); + goto issue_target_reset; + } + if (ioc->scsih_cmds.status & MPT3_CMD_REPLY_VALID) { + transfer_packet->valid_reply = 1; + mpi_reply = ioc->scsih_cmds.reply; + transfer_packet->sense_length = + le32_to_cpu(mpi_reply->SenseCount); + if (transfer_packet->sense_length) + memcpy(transfer_packet->sense, priv_sense, + transfer_packet->sense_length); + transfer_packet->transfer_length = + le32_to_cpu(mpi_reply->TransferCount); + transfer_packet->ioc_status = + le16_to_cpu(mpi_reply->IOCStatus) & + MPI2_IOCSTATUS_MASK; + transfer_packet->scsi_state = mpi_reply->SCSIState; + transfer_packet->scsi_status = mpi_reply->SCSIStatus; + transfer_packet->log_info = + le32_to_cpu(mpi_reply->IOCLogInfo); + } + goto out; + + issue_target_reset: + if (issue_reset) { + pr_info("issue target reset: handle (0x%04x)\n", handle); + tm_return_code = + mpt3sas_scsih_issue_locked_tm(ioc, handle, + 0xFFFFFFFF, 0xFFFFFFFF, 0, + MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, smid, 0, + tr_timeout, tr_method); + + if (tm_return_code == SUCCESS) { + pr_info("target reset completed: handle (0x%04x)\n", handle); + /* If the command is successfully aborted due to + * target reset TM then do up to three retries else + * command will be terminated by the host reset TM and + * hence retry once. + */ + if (((ioc->scsih_cmds.status & MPT3_CMD_COMPLETE) && + retry_count++ < 3) || + ((ioc->scsih_cmds.status & MPT3_CMD_RESET) && + host_reset_count++ == 0)) { + pr_info("issue retry: handle (0x%04x)\n", handle); + goto retry_loop; + } + } else + pr_info("target reset didn't complete: handle(0x%04x)\n", handle); + rc = -EFAULT; + } else + rc = -EAGAIN; + + out: + ioc->scsih_cmds.status = MPT3_CMD_NOT_USED; + mutex_unlock(&ioc->scsih_cmds.mutex); + return rc; +} + +/** + * _scsih_determine_disposition - + * @ioc: per adapter object + * @transfer_packet: packet describing the transfer + * Context: user + * + * Determines if an internal generated scsi_io is good data, or + * whether it needs to be retried or treated as an error. + * + * Returns device_responsive_state + */ +static enum device_responsive_state +_scsih_determine_disposition(struct MPT3SAS_ADAPTER *ioc, + struct _scsi_io_transfer *transfer_packet) +{ + static enum device_responsive_state rc; + struct sense_info sense_info = {0, 0, 0}; + u8 check_sense = 0; + char *desc = NULL; + + if (!transfer_packet->valid_reply) + return DEVICE_READY; + + switch (transfer_packet->ioc_status) { + case MPI2_IOCSTATUS_BUSY: + case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES: + case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED: + case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR: + case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED: + rc = DEVICE_RETRY; + break; + case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED: + if (transfer_packet->log_info == 0x31170000) { + rc = DEVICE_RETRY; + break; + } + if (transfer_packet->cdb[0] == REPORT_LUNS) + rc = DEVICE_READY; + else + rc = DEVICE_RETRY; + break; + case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN: + case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR: + case MPI2_IOCSTATUS_SUCCESS: + if (!transfer_packet->scsi_state && + !transfer_packet->scsi_status) { + rc = DEVICE_READY; + break; + } + if (transfer_packet->scsi_state & + MPI2_SCSI_STATE_AUTOSENSE_VALID) { + rc = DEVICE_ERROR; + check_sense = 1; + break; + } + if (transfer_packet->scsi_state & + (MPI2_SCSI_STATE_AUTOSENSE_FAILED | + MPI2_SCSI_STATE_NO_SCSI_STATUS | + MPI2_SCSI_STATE_TERMINATED)) { + rc = DEVICE_RETRY; + break; + } + if (transfer_packet->scsi_status >= + MPI2_SCSI_STATUS_BUSY) { + rc = DEVICE_RETRY; + break; + } + rc = DEVICE_READY; + break; + case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR: + if (transfer_packet->scsi_state & + MPI2_SCSI_STATE_TERMINATED) + rc = DEVICE_RETRY; + else + rc = DEVICE_ERROR; + break; + case MPI2_IOCSTATUS_INSUFFICIENT_POWER: + default: + rc = DEVICE_ERROR; + break; + } + + if (check_sense) { + _scsih_normalize_sense(transfer_packet->sense, &sense_info); + if (sense_info.skey == UNIT_ATTENTION) + rc = DEVICE_RETRY_UA; + else if (sense_info.skey == NOT_READY) { + /* medium isn't present */ + if (sense_info.asc == 0x3a) + rc = DEVICE_READY; + /* LOGICAL UNIT NOT READY */ + else if (sense_info.asc == 0x04) { + if (sense_info.ascq == 0x03 || + sense_info.ascq == 0x0b || + sense_info.ascq == 0x0c) { + rc = DEVICE_ERROR; + } else + rc = DEVICE_START_UNIT; + } + /* LOGICAL UNIT HAS NOT SELF-CONFIGURED YET */ + else if (sense_info.asc == 0x3e && !sense_info.ascq) + rc = DEVICE_START_UNIT; + } else if (sense_info.skey == ILLEGAL_REQUEST && + transfer_packet->cdb[0] == REPORT_LUNS) { + rc = DEVICE_READY; + } else if (sense_info.skey == MEDIUM_ERROR) { + + /* medium is corrupt, lets add the device so + * users can collect some info as needed + */ + + if (sense_info.asc == 0x31) + rc = DEVICE_READY; + } else if (sense_info.skey == HARDWARE_ERROR) { + /* Defect List Error, still add the device */ + if (sense_info.asc == 0x19) + rc = DEVICE_READY; + } + } + + if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) { + switch (rc) { + case DEVICE_READY: + desc = "ready"; + break; + case DEVICE_RETRY: + desc = "retry"; + break; + case DEVICE_RETRY_UA: + desc = "retry_ua"; + break; + case DEVICE_START_UNIT: + desc = "start_unit"; + break; + case DEVICE_STOP_UNIT: + desc = "stop_unit"; + break; + case DEVICE_ERROR: + desc = "error"; + break; + } + + pr_info("ioc_status(0x%04x),\n" + "loginfo(0x%08x), scsi_status(0x%02x),\n" + "scsi_state(0x%02x), rc(%s)\n", + transfer_packet->ioc_status, + transfer_packet->log_info, transfer_packet->scsi_status, + transfer_packet->scsi_state, desc); + + if (check_sense) + pr_info("\t[sense_key,asc,ascq]:\n" + "[0x%02x,0x%02x,0x%02x]\n", + sense_info.skey, sense_info.asc, sense_info.ascq); + } + return rc; +} + +/** + * _scsih_report_luns - send REPORT_LUNS to target + * @ioc: per adapter object + * @handle: expander handle + * @data: report luns data payload + * @data_length: length of data in bytes + * @retry_count: Requeue count + * @is_pd: is this hidden raid component + * @tr_timeout: Target Reset Timeout + * @tr_method: Target Reset Method + * Context: user + * + * Returns device_responsive_state + */ +static enum device_responsive_state +_scsih_report_luns(struct MPT3SAS_ADAPTER *ioc, u16 handle, void *data, + u32 data_length, u8 retry_count, u8 is_pd, u8 tr_timeout, u8 tr_method) +{ + struct _scsi_io_transfer *transfer_packet; + enum device_responsive_state rc; + void *lun_data; + int return_code; + int retries; + + lun_data = NULL; + transfer_packet = kzalloc(sizeof(struct _scsi_io_transfer), GFP_KERNEL); + if (!transfer_packet) { + + ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + rc = DEVICE_RETRY; + goto out; + } + + lun_data = dma_alloc_coherent(&ioc->pdev->dev, data_length, + &transfer_packet->data_dma, GFP_ATOMIC); + if (!lun_data) { + + ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + rc = DEVICE_RETRY; + goto out; + } + + for (retries = 0; retries < 4; retries++) { + rc = DEVICE_ERROR; + ioc_info(ioc, "REPORT_LUNS: handle(0x%04x),\n" + "retries(%d)\n", handle, retries); + memset(lun_data, 0, data_length); + transfer_packet->handle = handle; + transfer_packet->dir = DMA_FROM_DEVICE; + transfer_packet->data_length = data_length; + transfer_packet->cdb_length = 12; + transfer_packet->cdb[0] = REPORT_LUNS; + transfer_packet->cdb[6] = (data_length >> 24) & 0xFF; + transfer_packet->cdb[7] = (data_length >> 16) & 0xFF; + transfer_packet->cdb[8] = (data_length >> 8) & 0xFF; + transfer_packet->cdb[9] = data_length & 0xFF; + transfer_packet->timeout = 30; + transfer_packet->is_raid = is_pd; + + return_code = _scsi_send_scsi_io(ioc, transfer_packet, tr_timeout, tr_method); + switch (return_code) { + case 0: + rc = _scsih_determine_disposition(ioc, transfer_packet); + if (rc == DEVICE_READY) { + memcpy(data, lun_data, data_length); + goto out; + } else if (rc == DEVICE_ERROR) + goto out; + break; + case -EAGAIN: + rc = DEVICE_RETRY; + break; + case -EFAULT: + default: + ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + goto out; + } + } + out: + + if (lun_data) + dma_free_coherent(&ioc->pdev->dev, data_length, lun_data, + transfer_packet->data_dma); + kfree(transfer_packet); + + if ((rc == DEVICE_RETRY || rc == DEVICE_START_UNIT || + rc == DEVICE_RETRY_UA)) + rc = DEVICE_ERROR; + + return rc; +} + +/** + * _scsih_start_unit - send START_UNIT to target + * @ioc: per adapter object + * @handle: expander handle + * @lun: lun number + * @is_pd: is this hidden raid component + * @tr_timeout: Target Reset Timeout + * @tr_method: Target Reset Method + * Context: user + * + * Returns device_responsive_state + */ +static enum device_responsive_state +_scsih_start_unit(struct MPT3SAS_ADAPTER *ioc, u16 handle, u32 lun, u8 is_pd, + u8 tr_timeout, u8 tr_method) +{ + struct _scsi_io_transfer *transfer_packet; + enum device_responsive_state rc; + int return_code; + + transfer_packet = kzalloc(sizeof(struct _scsi_io_transfer), GFP_KERNEL); + if (!transfer_packet) { + + pr_info("failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + rc = DEVICE_RETRY; + goto out; + } + + rc = DEVICE_READY; + transfer_packet->handle = handle; + transfer_packet->dir = DMA_NONE; + transfer_packet->lun = lun; + transfer_packet->cdb_length = 6; + transfer_packet->cdb[0] = START_STOP; + transfer_packet->cdb[1] = 1; + transfer_packet->cdb[4] = 1; + transfer_packet->timeout = 30; + transfer_packet->is_raid = is_pd; + + pr_info("START_UNIT: handle(0x%04x), lun(%d)\n", handle, lun); + + return_code = _scsi_send_scsi_io(ioc, transfer_packet, tr_timeout, tr_method); + switch (return_code) { + case 0: + rc = _scsih_determine_disposition(ioc, transfer_packet); + break; + case -EAGAIN: + rc = DEVICE_RETRY; + break; + case -EFAULT: + default: + pr_err("failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + rc = DEVICE_ERROR; + break; + } + out: + kfree(transfer_packet); + return rc; +} + +/** + * _scsih_test_unit_ready - send TUR to target + * @ioc: per adapter object + * @handle: expander handle + * @lun: lun number + * @is_pd: is this hidden raid component + * @tr_timeout: Target Reset timeout value for Pcie devie + * @tr_method: pcie device Target reset method + * Context: user + * + * Returns device_responsive_state + */ +static enum device_responsive_state +_scsih_test_unit_ready(struct MPT3SAS_ADAPTER *ioc, u16 handle, u32 lun, + u8 is_pd, u8 tr_timeout, u8 tr_method) +{ + struct _scsi_io_transfer *transfer_packet; + enum device_responsive_state rc; + int return_code; + int sata_init_failure = 0; + + transfer_packet = kzalloc(sizeof(struct _scsi_io_transfer), GFP_KERNEL); + if (!transfer_packet) { + + pr_info("failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + rc = DEVICE_RETRY; + goto out; + } + + rc = DEVICE_READY; + transfer_packet->handle = handle; + transfer_packet->dir = DMA_NONE; + transfer_packet->lun = lun; + transfer_packet->cdb_length = 6; + transfer_packet->cdb[0] = TEST_UNIT_READY; + transfer_packet->timeout = 30; + transfer_packet->is_raid = is_pd; + + sata_init_retry: + pr_info("TEST_UNIT_READY: handle(0x%04x) lun(%d)\n", handle, lun); + + return_code = _scsi_send_scsi_io(ioc, transfer_packet, tr_timeout, tr_method); + switch (return_code) { + case 0: + rc = _scsih_determine_disposition(ioc, transfer_packet); + if (rc == DEVICE_RETRY && + transfer_packet->log_info == 0x31111000) { + if (!sata_init_failure++) { + pr_info("SATA Initialization Timeout sending a retry\n"); + rc = DEVICE_READY; + goto sata_init_retry; + } else { + pr_err("SATA Initialization Failed\n"); + rc = DEVICE_ERROR; + } + } + break; + case -EAGAIN: + rc = DEVICE_RETRY; + break; + case -EFAULT: + default: + pr_err("failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + rc = DEVICE_ERROR; + break; + } + out: + kfree(transfer_packet); + return rc; +} + +/** + * _scsih_ata_pass_thru_idd - obtain SATA device Identify Device Data + * @ioc: per adapter object + * @handle: device handle + * @is_ssd_device : is this SATA SSD device + * @tr_timeout: Target Reset Timeout + * @tr_method: Target Reset Method + * Context: user + * + * Returns device_responsive_state + */ +static enum device_responsive_state +_scsih_ata_pass_thru_idd(struct MPT3SAS_ADAPTER *ioc, u16 handle, + u8 *is_ssd_device, u8 tr_timeout, u8 tr_method) +{ + struct _scsi_io_transfer *transfer_packet; + enum device_responsive_state rc; + u16 *idd_data; + int return_code; + u32 data_length; + + idd_data = NULL; + transfer_packet = kzalloc(sizeof(struct _scsi_io_transfer), GFP_KERNEL); + if (!transfer_packet) { + + ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + rc = DEVICE_RETRY; + goto out; + } + data_length = 512; + idd_data = dma_alloc_coherent(&ioc->pdev->dev, data_length, + &transfer_packet->data_dma, GFP_ATOMIC); + if (!idd_data) { + + ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + rc = DEVICE_RETRY; + goto out; + } + rc = DEVICE_READY; + memset(idd_data, 0, data_length); + transfer_packet->handle = handle; + transfer_packet->dir = DMA_FROM_DEVICE; + transfer_packet->data_length = data_length; + transfer_packet->cdb_length = 12; + transfer_packet->cdb[0] = ATA_12; + transfer_packet->cdb[1] = 0x8; + transfer_packet->cdb[2] = 0xd; + transfer_packet->cdb[3] = 0x1; + transfer_packet->cdb[9] = 0xec; + transfer_packet->timeout = 30; + + return_code = _scsi_send_scsi_io(ioc, transfer_packet, 30, 0); + switch (return_code) { + case 0: + rc = _scsih_determine_disposition(ioc, transfer_packet); + if (rc == DEVICE_READY) { + // Check if nominal media rotation rate is set to 1 i.e. SSD device + if (idd_data[217] == 1) + *is_ssd_device = 1; + } + break; + case -EAGAIN: + rc = DEVICE_RETRY; + break; + case -EFAULT: + default: + + ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + rc = DEVICE_ERROR; + break; + } + + out: + if (idd_data) { + dma_free_coherent(&ioc->pdev->dev, data_length, idd_data, + transfer_packet->data_dma); + } + kfree(transfer_packet); + return rc; +} + +/** + * _scsih_wait_for_device_to_become_ready - handle busy devices + * @ioc: per adapter object + * @handle: expander handle + * @retry_count: number of times this event has been retried + * @is_pd: is this hidden raid component + * @lun: lun number + * @tr_timeout: Target Reset Timeout + * @tr_method: Target Reset Method + * + * Some devices spend too much time in busy state, queue event later + * + * Return the device_responsive_state. + */ + +static enum device_responsive_state +_scsih_wait_for_device_to_become_ready(struct MPT3SAS_ADAPTER *ioc, u16 handle, + u8 retry_count, u8 is_pd, int lun, u8 tr_timeout, u8 tr_method) +{ + enum device_responsive_state rc; + + if (ioc->pci_error_recovery) + return DEVICE_ERROR; + + if (ioc->shost_recovery) + return DEVICE_RETRY; + + rc = _scsih_test_unit_ready(ioc, handle, lun, is_pd, tr_timeout, tr_method); + if (rc == DEVICE_READY || rc == DEVICE_ERROR) + return rc; + else if (rc == DEVICE_START_UNIT) { + rc = _scsih_start_unit(ioc, handle, lun, is_pd, tr_timeout, tr_method); + if (rc == DEVICE_ERROR) + return rc; + rc = _scsih_test_unit_ready(ioc, handle, lun, is_pd, tr_timeout, tr_method); + } + + if ((rc == DEVICE_RETRY || rc == DEVICE_START_UNIT || + rc == DEVICE_RETRY_UA)) + rc = DEVICE_ERROR; + return rc; +} + +static inline int mpt_scsilun_to_int(struct scsi_lun *scsilun) +{ + return scsilun_to_int(scsilun); +} + +/** + * _scsih_wait_for_target_to_become_ready - handle busy devices + * @ioc: per adapter object + * @handle: expander handle + * @retry_count: number of times this event has been retried + * @is_pd: is this hidden raid component + * @tr_timeout: Target Reset timeout value + * @tr_method: Target Reset method Hot/Protocol level. + * + * Some devices spend too much time in busy state, queue event later + * + * Return the device_responsive_state. + */ +static enum device_responsive_state +_scsih_wait_for_target_to_become_ready(struct MPT3SAS_ADAPTER *ioc, u16 handle, + u8 retry_count, u8 is_pd, u8 tr_timeout, u8 tr_method) +{ + enum device_responsive_state rc; + struct scsi_lun *lun_data; + u32 length, num_luns; + u8 *data; + int lun; + struct scsi_lun *lunp; + + lun_data = kcalloc(MPT3_MAX_LUNS, sizeof(struct scsi_lun), GFP_KERNEL); + if (!lun_data) { + + ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + return DEVICE_RETRY; + } + + rc = _scsih_report_luns(ioc, handle, lun_data, + MPT3_MAX_LUNS * sizeof(struct scsi_lun), retry_count, is_pd, + tr_timeout, tr_method); + + if (rc != DEVICE_READY) + goto out; + + /* some debug bits*/ + data = (u8 *)lun_data; + length = ((data[0] << 24) | (data[1] << 16) | + (data[2] << 8) | (data[3] << 0)); + + num_luns = (length / sizeof(struct scsi_lun)); + + lunp = &lun_data[1]; + lun = (num_luns) ? mpt_scsilun_to_int(&lun_data[1]) : 0; + rc = _scsih_wait_for_device_to_become_ready(ioc, handle, retry_count, + is_pd, lun, tr_timeout, tr_method); + + if (rc == DEVICE_ERROR) { + struct scsi_lun *lunq; + + for (lunq = lunp++; lunq <= &lun_data[num_luns]; lunq++) { + + rc = _scsih_wait_for_device_to_become_ready(ioc, handle, + retry_count, is_pd, mpt_scsilun_to_int(lunq), + tr_timeout, tr_method); + if (rc != DEVICE_ERROR) + goto out; + } + } +out: + kfree(lun_data); + return rc; +} /** @@ -7247,8 +8193,8 @@ _scsih_check_device(struct MPT3SAS_ADAPTER *ioc, sas_device->handle, handle); sas_target_priv_data->handle = handle; sas_device->handle = handle; - if (le16_to_cpu(sas_device_pg0.Flags) & - MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID) { + if ((le16_to_cpu(sas_device_pg0.Flags) & MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID) + && (ioc->hba_mpi_version_belonged != MPI2_VERSION)) { sas_device->enclosure_level = sas_device_pg0.EnclosureLevel; memcpy(sas_device->connector_name, @@ -7290,7 +8236,11 @@ _scsih_check_device(struct MPT3SAS_ADAPTER *ioc, goto out_unlock; spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - _scsih_ublock_io_device(ioc, sas_address, port); + + if (issue_scsi_cmd_to_bringup_drive) + _scsih_ublock_io_device_wait(ioc, sas_address, port); + else + _scsih_ublock_io_device(ioc, sas_address, port); if (sas_device) sas_device_put(sas_device); @@ -7306,7 +8256,7 @@ out_unlock: * _scsih_add_device - creating sas device object * @ioc: per adapter object * @handle: sas device handle - * @phy_num: phy number end device attached to + * @retry_count: number of times this event has been retried * @is_pd: is this hidden raid component * * Creating end device object, stored in ioc->sas_device_list. @@ -7314,16 +8264,18 @@ out_unlock: * Return: 0 for success, non-zero for failure. */ static int -_scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num, +_scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 retry_count, u8 is_pd) { Mpi2ConfigReply_t mpi_reply; Mpi2SasDevicePage0_t sas_device_pg0; struct _sas_device *sas_device; struct _enclosure_node *enclosure_dev = NULL; + enum device_responsive_state rc; u32 ioc_status; u64 sas_address; u32 device_info; + u8 connector_name[5]; u8 port_id; if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, @@ -7379,6 +8331,48 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num, sas_device_pg0.EnclosureHandle); } + /* + * Wait for device that is becoming ready + * queue request later if device is busy. + */ + if ((!ioc->wait_for_discovery_to_complete) && + (issue_scsi_cmd_to_bringup_drive)) { + ioc_info(ioc, "detecting: handle(0x%04x),\n" + "sas_address(0x%016llx), phy(%d)\n", handle, + (unsigned long long)sas_address, sas_device_pg0.PhyNum); + rc = _scsih_wait_for_target_to_become_ready(ioc, handle, + retry_count, is_pd, 30, 0); + if (rc != DEVICE_READY) { + if (le16_to_cpu(sas_device_pg0.EnclosureHandle) != 0) + dewtprintk(ioc, ioc_info(ioc, "%s:\n" + "device not ready: slot(%d)\n", __func__, + le16_to_cpu(sas_device_pg0.Slot))); + if ((le16_to_cpu(sas_device_pg0.Flags) & + MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID) && + (ioc->hba_mpi_version_belonged != MPI2_VERSION)) { + memcpy(connector_name, + sas_device_pg0.ConnectorName, 4); + connector_name[4] = '\0'; + dewtprintk(ioc, ioc_info(ioc, "%s:\n" + "device not ready:\n" + "enclosure level(0x%04x),\n" + "connector name( %s)\n", __func__, + sas_device_pg0.EnclosureLevel, connector_name)); + } + + if ((enclosure_dev) && (le16_to_cpu(enclosure_dev->pg0.Flags) & + MPI2_SAS_ENCLS0_FLAGS_CHASSIS_SLOT_VALID)) + ioc_info(ioc, "chassis slot(0x%04x)\n", + enclosure_dev->pg0.ChassisSlot); + + if (rc == DEVICE_RETRY || rc == DEVICE_START_UNIT || + rc == DEVICE_STOP_UNIT || rc == DEVICE_RETRY_UA) + return 1; + else if (rc == DEVICE_ERROR) + return 0; + } + } + sas_device = kzalloc(sizeof(struct _sas_device), GFP_KERNEL); if (!sas_device) { @@ -7594,10 +8588,12 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event) { int i; + int rc; u16 parent_handle, handle; u16 reason_code; u8 phy_number, max_phys; struct _sas_node *sas_expander; + struct _sas_device *sas_device; u64 sas_address; unsigned long flags; u8 link_rate, prev_link_rate; @@ -7664,6 +8660,13 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc, MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT) && (reason_code != MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING)) continue; + if (fw_event->delayed_work_active && (reason_code == + MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING)) { + dewtprintk(ioc, ioc_info(ioc, "ignoring\n" + "Targ not responding event phy in re-queued event processing\n")); + continue; + } + handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle); if (!handle) continue; @@ -7687,9 +8690,32 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc, _scsih_check_device(ioc, sas_address, handle, phy_number, link_rate); + /* This code after this point handles the test case + * where a device has been added, however its returning + * BUSY for sometime. Then before the Device Missing + * Delay expires and the device becomes READY, the + * device is removed and added back. + */ + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = __mpt3sas_get_sdev_by_handle(ioc, + handle); + spin_unlock_irqrestore(&ioc->sas_device_lock, + flags); + + if (sas_device) { + sas_device_put(sas_device); + break; + } + if (!test_bit(handle, ioc->pend_os_device_add)) break; + dewtprintk(ioc, ioc_info(ioc, "handle(0x%04x) device not found: convert\n" + "event to a device add\n", handle)); + event_data->PHY[i].PhyStatus &= 0xF0; + event_data->PHY[i].PhyStatus |= + MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED; + fallthrough; case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED: @@ -7700,7 +8726,16 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc, mpt3sas_transport_update_links(ioc, sas_address, handle, phy_number, link_rate, port); - _scsih_add_device(ioc, handle, phy_number, 0); + if (link_rate < MPI2_SAS_NEG_LINK_RATE_1_5) + break; + + rc = _scsih_add_device(ioc, handle, + fw_event->retries[i], 0); + if (rc) /* retry due to busy device */ + fw_event->retries[i]++; + else /* mark entry vacant */ + event_data->PHY[i].PhyStatus |= + MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT; break; case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING: @@ -8086,7 +9121,10 @@ _scsih_pcie_check_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); pcie_device_put(pcie_device); - _scsih_ublock_io_device(ioc, wwid, NULL); + if (issue_scsi_cmd_to_bringup_drive) + _scsih_ublock_io_device_wait(ioc, wwid, NULL); + else + _scsih_ublock_io_device(ioc, wwid, NULL); return; } @@ -8095,19 +9133,24 @@ _scsih_pcie_check_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) * _scsih_pcie_add_device - creating pcie device object * @ioc: per adapter object * @handle: pcie device handle + * @retry_count: number of times this event has been retried * * Creating end device object, stored in ioc->pcie_device_list. * * Return: 1 means queue the event later, 0 means complete the event */ static int -_scsih_pcie_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) +_scsih_pcie_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 retry_count) { Mpi26PCIeDevicePage0_t pcie_device_pg0; Mpi26PCIeDevicePage2_t pcie_device_pg2; Mpi2ConfigReply_t mpi_reply; struct _pcie_device *pcie_device; struct _enclosure_node *enclosure_dev; + enum device_responsive_state rc; + u8 connector_name[5]; + u8 tr_timeout = 30; + u8 tr_method = 0; u32 ioc_status; u64 wwid; @@ -8175,6 +9218,53 @@ _scsih_pcie_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) __LINE__, __func__); return 0; } + + if (!ioc->tm_custom_handling) { + tr_method = MPI26_SCSITASKMGMT_MSGFLAGS_PROTOCOL_LVL_RST_PCIE; + if (pcie_device_pg2.ControllerResetTO) + tr_timeout = pcie_device_pg2.ControllerResetTO; + + } + } + + /* + * Wait for device that is becoming ready + * queue request later if device is busy. + */ + if ((!ioc->wait_for_discovery_to_complete) && + (issue_scsi_cmd_to_bringup_drive) && + (pcie_device_pg0.AccessStatus != + MPI26_PCIEDEV0_ASTATUS_DEVICE_BLOCKED)) { + ioc_info(ioc, "detecting: handle(0x%04x),\n" + "wwid(0x%016llx), port(%d)\n", handle, + (unsigned long long)wwid, pcie_device_pg0.PortNum); + + rc = _scsih_wait_for_target_to_become_ready(ioc, handle, + retry_count, 0, tr_timeout, tr_method); + if (rc != DEVICE_READY) { + if (le16_to_cpu(pcie_device_pg0.EnclosureHandle) != 0) + dewtprintk(ioc, ioc_info(ioc, "%s:\n" + "device not ready: slot(%d)\n", + __func__, + le16_to_cpu(pcie_device_pg0.Slot))); + + if (le32_to_cpu(pcie_device_pg0.Flags) & + MPI26_PCIEDEV0_FLAGS_ENCL_LEVEL_VALID) { + memcpy(connector_name, + pcie_device_pg0.ConnectorName, 4); + connector_name[4] = '\0'; + dewtprintk(ioc, ioc_info(ioc, "%s: device not ready: enclosure\n" + "level(0x%04x), connector name( %s)\n", __func__, + pcie_device_pg0.EnclosureLevel, + connector_name)); + } + + if (rc == DEVICE_RETRY || rc == DEVICE_START_UNIT || + rc == DEVICE_STOP_UNIT || rc == DEVICE_RETRY_UA) + return 1; + else if (rc == DEVICE_ERROR) + return 0; + } } pcie_device = kzalloc(sizeof(struct _pcie_device), GFP_KERNEL); @@ -8365,7 +9455,7 @@ _scsih_pcie_topology_change_event(struct MPT3SAS_ADAPTER *ioc, } /* handle siblings events */ - for (i = 0; i < event_data->NumEntries; i++) { + for (i = 0 ; i < event_data->NumEntries; i++) { if (fw_event->ignore) { dewtprintk(ioc, ioc_info(ioc, "ignoring switch event\n")); @@ -8426,8 +9516,11 @@ _scsih_pcie_topology_change_event(struct MPT3SAS_ADAPTER *ioc, if (link_rate < MPI26_EVENT_PCIE_TOPO_PI_RATE_2_5) break; - rc = _scsih_pcie_add_device(ioc, handle); - if (!rc) { + rc = _scsih_pcie_add_device(ioc, handle, fw_event->retries[i]); + if (rc) {/* retry due to busy device */ + + fw_event->retries[i]++; + } else { /* mark entry vacant */ /* TODO This needs to be reviewed and fixed, * we dont have an entry @@ -10632,7 +11725,8 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) } retry_count = 0; parent_handle = le16_to_cpu(pcie_device_pg0.ParentDevHandle); - _scsih_pcie_add_device(ioc, handle); + while (_scsih_pcie_add_device(ioc, handle, retry_count++)) + ssleep(1); ioc_info(ioc, "\tAFTER adding pcie end device: handle (0x%04x), wwid(0x%016llx)\n", handle, (u64)le64_to_cpu(pcie_device_pg0.WWID)); From ad59571931072e6f77b2bfa7d7fdc564dad6f331 Mon Sep 17 00:00:00 2001 From: Ranjan Kumar Date: Thu, 13 Nov 2025 21:07:08 +0530 Subject: [PATCH 12/78] scsi: mpt3sas: Add firmware event requeue support for busy devices Add support to requeue SAS/PCIe topology change events when devices are busy or not ready. Introduce delayed work with retry counters so events are retried instead of dropped, improving device discovery by retrying transient failures instead of dropping events. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202510311720.NiDwRLwp-lkp@intel.com/ Signed-off-by: Ranjan Kumar Link: https://patch.msgid.link/20251113153712.31850-5-ranjan.kumar@broadcom.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_scsih.c | 130 +++++++++++++++++++++++---- 1 file changed, 112 insertions(+), 18 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 3eb6c51ac91e..eb04ca5e0043 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -89,6 +89,7 @@ _scsih_ata_pass_thru_idd(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 *is_ssd_dev static enum device_responsive_state _scsih_wait_for_device_to_become_ready(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 retry_count, u8 is_pd, int lun, u8 tr_timeout, u8 tr_method); +static void _firmware_event_work_delayed(struct work_struct *work); /* global parameters */ LIST_HEAD(mpt3sas_ioc_list); @@ -275,11 +276,16 @@ struct fw_event_work { u16 event; struct kref refcount; char event_data[] __aligned(4); + }; static void fw_event_work_free(struct kref *r) { - kfree(container_of(r, struct fw_event_work, refcount)); + struct fw_event_work *fw_work; + + fw_work = container_of(r, struct fw_event_work, refcount); + kfree(fw_work->retries); + kfree(fw_work); } static void fw_event_work_get(struct fw_event_work *fw_work) @@ -3651,6 +3657,37 @@ _scsih_fw_event_del_from_list(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work spin_unlock_irqrestore(&ioc->fw_event_lock, flags); } +/** + * _scsih_fw_event_requeue - requeue an event + * @ioc: per adapter object + * @fw_event: object describing the event + * @delay: time in milliseconds to wait before retrying the event + * + * Context: This function will acquire ioc->fw_event_lock. + * + * Return nothing. + */ +static void +_scsih_fw_event_requeue(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work + *fw_event, unsigned long delay) +{ + unsigned long flags; + + if (ioc->firmware_event_thread == NULL) + return; + + spin_lock_irqsave(&ioc->fw_event_lock, flags); + fw_event_work_get(fw_event); + list_add_tail(&fw_event->list, &ioc->fw_event_list); + if (!fw_event->delayed_work_active) { + fw_event->delayed_work_active = 1; + INIT_DELAYED_WORK(&fw_event->delayed_work, + _firmware_event_work_delayed); + } + queue_delayed_work(ioc->firmware_event_thread, &fw_event->delayed_work, + msecs_to_jiffies(delay)); + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); +} /** * mpt3sas_send_trigger_data_event - send event for processing trigger data @@ -8589,6 +8626,7 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc, { int i; int rc; + int requeue_event; u16 parent_handle, handle; u16 reason_code; u8 phy_number, max_phys; @@ -8643,7 +8681,7 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc, spin_unlock_irqrestore(&ioc->sas_node_lock, flags); /* handle siblings events */ - for (i = 0; i < event_data->NumEntries; i++) { + for (i = 0, requeue_event = 0; i < event_data->NumEntries; i++) { if (fw_event->ignore) { dewtprintk(ioc, ioc_info(ioc, "ignoring expander event\n")); @@ -8663,7 +8701,14 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc, if (fw_event->delayed_work_active && (reason_code == MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING)) { dewtprintk(ioc, ioc_info(ioc, "ignoring\n" - "Targ not responding event phy in re-queued event processing\n")); + "Target not responding event phy in re-queued event processing\n")); + continue; + } + + if (fw_event->delayed_work_active && (reason_code == + MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING)) { + dewtprintk(ioc, ioc_info(ioc, "ignoring Target not responding\n" + "event phy in re-queued event processing\n")); continue; } @@ -8714,7 +8759,7 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc, "event to a device add\n", handle)); event_data->PHY[i].PhyStatus &= 0xF0; event_data->PHY[i].PhyStatus |= - MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED; + MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED; fallthrough; @@ -8731,11 +8776,13 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc, rc = _scsih_add_device(ioc, handle, fw_event->retries[i], 0); - if (rc) /* retry due to busy device */ + if (rc) {/* retry due to busy device */ fw_event->retries[i]++; - else /* mark entry vacant */ + requeue_event = 1; + } else {/* mark entry vacant */ event_data->PHY[i].PhyStatus |= - MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT; + MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT; + } break; case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING: @@ -8750,7 +8797,7 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc, sas_expander) mpt3sas_expander_remove(ioc, sas_address, port); - return 0; + return requeue_event; } /** @@ -9428,7 +9475,7 @@ _scsih_pcie_topology_change_event_debug(struct MPT3SAS_ADAPTER *ioc, * Context: user. * */ -static void +static int _scsih_pcie_topology_change_event(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event) { @@ -9438,6 +9485,7 @@ _scsih_pcie_topology_change_event(struct MPT3SAS_ADAPTER *ioc, u8 link_rate, prev_link_rate; unsigned long flags; int rc; + int requeue_event; Mpi26EventDataPCIeTopologyChangeList_t *event_data = (Mpi26EventDataPCIeTopologyChangeList_t *) fw_event->event_data; struct _pcie_device *pcie_device; @@ -9447,22 +9495,22 @@ _scsih_pcie_topology_change_event(struct MPT3SAS_ADAPTER *ioc, if (ioc->shost_recovery || ioc->remove_host || ioc->pci_error_recovery) - return; + return 0; if (fw_event->ignore) { dewtprintk(ioc, ioc_info(ioc, "ignoring switch event\n")); - return; + return 0; } /* handle siblings events */ - for (i = 0 ; i < event_data->NumEntries; i++) { + for (i = 0, requeue_event = 0; i < event_data->NumEntries; i++) { if (fw_event->ignore) { dewtprintk(ioc, ioc_info(ioc, "ignoring switch event\n")); - return; + return 0; } if (ioc->remove_host || ioc->pci_error_recovery) - return; + return 0; reason_code = event_data->PortEntry[i].PortStatus; handle = le16_to_cpu(event_data->PortEntry[i].AttachedDevHandle); @@ -9518,8 +9566,8 @@ _scsih_pcie_topology_change_event(struct MPT3SAS_ADAPTER *ioc, rc = _scsih_pcie_add_device(ioc, handle, fw_event->retries[i]); if (rc) {/* retry due to busy device */ - fw_event->retries[i]++; + requeue_event = 1; } else { /* mark entry vacant */ /* TODO This needs to be reviewed and fixed, @@ -9535,11 +9583,12 @@ _scsih_pcie_topology_change_event(struct MPT3SAS_ADAPTER *ioc, break; } } + return requeue_event; } /** * _scsih_pcie_device_status_change_event_debug - debug for device event - * @ioc: ? + * @ioc: per adapter object * @event_data: event data payload * Context: user. */ @@ -11870,7 +11919,11 @@ _mpt3sas_fw_work(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event) _scsih_turn_on_pfa_led(ioc, fw_event->device_handle); break; case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST: - _scsih_sas_topology_change_event(ioc, fw_event); + if (_scsih_sas_topology_change_event(ioc, fw_event)) { + _scsih_fw_event_requeue(ioc, fw_event, 1000); + ioc->current_event = NULL; + return; + } break; case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE: if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) @@ -11910,7 +11963,11 @@ _mpt3sas_fw_work(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event) _scsih_pcie_enumeration_event(ioc, fw_event); break; case MPI2_EVENT_PCIE_TOPOLOGY_CHANGE_LIST: - _scsih_pcie_topology_change_event(ioc, fw_event); + if (_scsih_pcie_topology_change_event(ioc, fw_event)) { + _scsih_fw_event_requeue(ioc, fw_event, 1000); + ioc->current_event = NULL; + return; + } break; } out: @@ -11935,6 +11992,15 @@ _firmware_event_work(struct work_struct *work) _mpt3sas_fw_work(fw_event->ioc, fw_event); } +static void +_firmware_event_work_delayed(struct work_struct *work) +{ + struct fw_event_work *fw_event = container_of(work, + struct fw_event_work, delayed_work.work); + + _mpt3sas_fw_work(fw_event->ioc, fw_event); +} + /** * mpt3sas_scsih_event_callback - firmware event handler (called at ISR time) * @ioc: per adapter object @@ -12115,6 +12181,34 @@ mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, return 1; } + if (event == MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST) { + Mpi2EventDataSasTopologyChangeList_t *topo_event_data = + (Mpi2EventDataSasTopologyChangeList_t *) + mpi_reply->EventData; + fw_event->retries = kzalloc(topo_event_data->NumEntries, + GFP_ATOMIC); + if (!fw_event->retries) { + + ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + kfree(fw_event->event_data); + fw_event_work_put(fw_event); + return 1; + } + } + + if (event == MPI2_EVENT_PCIE_TOPOLOGY_CHANGE_LIST) { + Mpi26EventDataPCIeTopologyChangeList_t *topo_event_data = + (Mpi26EventDataPCIeTopologyChangeList_t *) mpi_reply->EventData; + fw_event->retries = kzalloc(topo_event_data->NumEntries, + GFP_ATOMIC); + if (!fw_event->retries) { + + ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + fw_event_work_put(fw_event); + return 1; + } + } + memcpy(fw_event->event_data, mpi_reply->EventData, sz); fw_event->ioc = ioc; fw_event->VF_ID = mpi_reply->VF_ID; From 72340fecd0c8449dcef1fd07199b0476728aae72 Mon Sep 17 00:00:00 2001 From: Ranjan Kumar Date: Thu, 13 Nov 2025 21:07:09 +0530 Subject: [PATCH 13/78] scsi: mpt3sas: Add configurable command retry limit for slow-to-respond devices Add a new module parameter "command_retry_count" to control the number of retries during device discovery and readiness checks, improving reliability for slow or transient SAS/PCIe devices. Signed-off-by: Ranjan Kumar Link: https://patch.msgid.link/20251113153712.31850-6-ranjan.kumar@broadcom.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_scsih.c | 84 ++++++++++++++++++++++++++-- 1 file changed, 78 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index eb04ca5e0043..ac69a5abe2e2 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -195,6 +195,11 @@ module_param(host_tagset_enable, int, 0444); MODULE_PARM_DESC(host_tagset_enable, "Shared host tagset enable/disable Default: enable(1)"); +static int command_retry_count = 144; +module_param(command_retry_count, int, 0444); +MODULE_PARM_DESC(command_retry_count, "Device discovery TUR command retry\n" + "count: (default=144)"); + /* raid transport support */ static struct raid_template *mpt3sas_raid_template; static struct raid_template *mpt2sas_raid_template; @@ -3927,11 +3932,24 @@ _scsih_ublock_io_all_device(struct MPT3SAS_ADAPTER *ioc, u8 no_turs) { struct MPT3SAS_DEVICE *sas_device_priv_data; struct scsi_device *sdev; + struct MPT3SAS_TARGET *sas_target; + enum device_responsive_state rc; + struct _sas_device *sas_device = NULL; + struct _pcie_device *pcie_device = NULL; + int count = 0; + u8 tr_method = 0; + u8 tr_timeout = 30; + shost_for_each_device(sdev, ioc->shost) { sas_device_priv_data = sdev->hostdata; if (!sas_device_priv_data) continue; + + sas_target = sas_device_priv_data->sas_target; + if (!sas_target || sas_target->deleted) + continue; + if (!sas_device_priv_data->block) continue; @@ -3942,10 +3960,62 @@ _scsih_ublock_io_all_device(struct MPT3SAS_ADAPTER *ioc, u8 no_turs) continue; } - dewtprintk(ioc, sdev_printk(KERN_INFO, sdev, - "device_running, handle(0x%04x)\n", - sas_device_priv_data->sas_target->handle)); + do { + pcie_device = mpt3sas_get_pdev_by_handle(ioc, sas_target->handle); + if (pcie_device && (!ioc->tm_custom_handling) && + (!(mpt3sas_scsih_is_pcie_scsi_device(pcie_device->device_info)))) { + tr_timeout = pcie_device->reset_timeout; + tr_method = MPI26_SCSITASKMGMT_MSGFLAGS_PROTOCOL_LVL_RST_PCIE; + } + rc = _scsih_wait_for_device_to_become_ready(ioc, + sas_target->handle, 0, (sas_target->flags & + MPT_TARGET_FLAGS_RAID_COMPONENT), sdev->lun, tr_timeout, tr_method); + if (rc == DEVICE_RETRY || rc == DEVICE_START_UNIT || + rc == DEVICE_STOP_UNIT || rc == DEVICE_RETRY_UA) + ssleep(1); + if (pcie_device) + pcie_device_put(pcie_device); + } while ((rc == DEVICE_RETRY || rc == DEVICE_START_UNIT || + rc == DEVICE_STOP_UNIT || rc == DEVICE_RETRY_UA) + && count++ < command_retry_count); + sas_device_priv_data->block = 0; + if (rc != DEVICE_READY) + sas_device_priv_data->deleted = 1; + _scsih_internal_device_unblock(sdev, sas_device_priv_data); + + if (rc != DEVICE_READY) { + sdev_printk(KERN_WARNING, sdev, "%s: device_offlined,\n" + "handle(0x%04x)\n", + __func__, sas_device_priv_data->sas_target->handle); + scsi_device_set_state(sdev, SDEV_OFFLINE); + sas_device = mpt3sas_get_sdev_by_addr(ioc, + sas_device_priv_data->sas_target->sas_address, + sas_device_priv_data->sas_target->port); + if (sas_device) { + _scsih_display_enclosure_chassis_info(NULL, sas_device, sdev, NULL); + sas_device_put(sas_device); + } else { + pcie_device = mpt3sas_get_pdev_by_wwid(ioc, + sas_device_priv_data->sas_target->sas_address); + if (pcie_device) { + if (pcie_device->enclosure_handle != 0) + sdev_printk(KERN_INFO, sdev, "enclosure logical id\n" + "(0x%016llx), slot(%d)\n", (unsigned long long) + pcie_device->enclosure_logical_id, + pcie_device->slot); + if (pcie_device->connector_name[0] != '\0') + sdev_printk(KERN_INFO, sdev, "enclosure level(0x%04x),\n" + " connector name( %s)\n", + pcie_device->enclosure_level, + pcie_device->connector_name); + pcie_device_put(pcie_device); + } + } + } else + sdev_printk(KERN_WARNING, sdev, "device_unblocked,\n" + "handle(0x%04x)\n", + sas_device_priv_data->sas_target->handle); } } @@ -3970,6 +4040,7 @@ _scsih_ublock_io_device_wait(struct MPT3SAS_ADAPTER *ioc, u64 sas_address, struct _pcie_device *pcie_device; u8 tr_timeout = 30; u8 tr_method = 0; + int count = 0; /* moving devices from SDEV_OFFLINE to SDEV_BLOCK */ shost_for_each_device(sdev, ioc->shost) { @@ -4036,7 +4107,8 @@ _scsih_ublock_io_device_wait(struct MPT3SAS_ADAPTER *ioc, u64 sas_address, if (pcie_device) pcie_device_put(pcie_device); } while ((rc == DEVICE_RETRY || rc == DEVICE_START_UNIT || - rc == DEVICE_STOP_UNIT || rc == DEVICE_RETRY_UA)); + rc == DEVICE_STOP_UNIT || rc == DEVICE_RETRY_UA) + && count++ <= command_retry_count); sas_device_priv_data->block = 0; if (rc != DEVICE_READY) @@ -7771,7 +7843,7 @@ _scsih_report_luns(struct MPT3SAS_ADAPTER *ioc, u16 handle, void *data, kfree(transfer_packet); if ((rc == DEVICE_RETRY || rc == DEVICE_START_UNIT || - rc == DEVICE_RETRY_UA)) + rc == DEVICE_RETRY_UA) && retry_count >= command_retry_count) rc = DEVICE_ERROR; return rc; @@ -8027,7 +8099,7 @@ _scsih_wait_for_device_to_become_ready(struct MPT3SAS_ADAPTER *ioc, u16 handle, } if ((rc == DEVICE_RETRY || rc == DEVICE_START_UNIT || - rc == DEVICE_RETRY_UA)) + rc == DEVICE_RETRY_UA) && retry_count >= command_retry_count) rc = DEVICE_ERROR; return rc; } From 39680c59f10c899e9533a3635b1a201f38461ba0 Mon Sep 17 00:00:00 2001 From: Ranjan Kumar Date: Thu, 13 Nov 2025 21:07:10 +0530 Subject: [PATCH 14/78] scsi: mpt3sas: Fixed the W=1 compilation warning Fix W=1 compilation warnings. Signed-off-by: Ranjan Kumar Link: https://patch.msgid.link/20251113153712.31850-7-ranjan.kumar@broadcom.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 5ff31ce0c960..e4e22cb0e277 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -843,7 +843,7 @@ mpt3sas_base_start_watchdog(struct MPT3SAS_ADAPTER *ioc) /* initialize fault polling */ INIT_DELAYED_WORK(&ioc->fault_reset_work, _base_fault_reset_work); - snprintf(ioc->fault_reset_work_q_name, + scnprintf(ioc->fault_reset_work_q_name, sizeof(ioc->fault_reset_work_q_name), "poll_%s%d_status", ioc->driver_name, ioc->id); ioc->fault_reset_work_q = alloc_ordered_workqueue( @@ -3178,7 +3178,7 @@ _base_request_irq(struct MPT3SAS_ADAPTER *ioc, u8 index) if (index >= ioc->iopoll_q_start_index) { qid = index - ioc->iopoll_q_start_index; - snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d-mq-poll%d", + scnprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d-mq-poll%d", ioc->driver_name, ioc->id, qid); reply_q->is_iouring_poll_q = 1; ioc->io_uring_poll_queues[qid].reply_q = reply_q; @@ -3187,10 +3187,10 @@ _base_request_irq(struct MPT3SAS_ADAPTER *ioc, u8 index) if (ioc->msix_enable) - snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d-msix%d", + scnprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d-msix%d", ioc->driver_name, ioc->id, index); else - snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d", + scnprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d", ioc->driver_name, ioc->id); r = request_irq(pci_irq_vector(pdev, index), _base_interrupt, IRQF_SHARED, reply_q->name, reply_q); From 0f9c4be787f786cff0bf2183607e54a552a40cb2 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 13 Nov 2025 10:17:30 -0800 Subject: [PATCH 15/78] scsi: core: Introduce an enumeration type for the SCSI_MLQUEUE constants Multiple functions in the SCSI core accept an 'int reason' argument. The 'int' type of these arguments doesn't make it clear what values are acceptable for these arguments. Document which values are supported for these arguments by introducing the enumeration type scsi_qc_status. 'qc' in the type name stands for 'queuecommand' since the values passed as the 'reason' argument are the .queuecommand() return values. Cc: John Garry Cc: Hannes Reinecke Signed-off-by: Bart Van Assche Link: https://patch.msgid.link/20251113181730.1109331-1-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_lib.c | 11 ++++++----- drivers/scsi/scsi_priv.h | 3 ++- include/scsi/scsi.h | 13 ++++++++----- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 93031326ac3e..3b860b369692 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -76,7 +76,7 @@ int scsi_init_sense_cache(struct Scsi_Host *shost) } static void -scsi_set_blocked(struct scsi_cmnd *cmd, int reason) +scsi_set_blocked(struct scsi_cmnd *cmd, enum scsi_qc_status reason) { struct Scsi_Host *host = cmd->device->host; struct scsi_device *device = cmd->device; @@ -139,7 +139,8 @@ static void scsi_mq_requeue_cmd(struct scsi_cmnd *cmd, unsigned long msecs) * for a requeue after completion, which should only occur in this * file. */ -static void __scsi_queue_insert(struct scsi_cmnd *cmd, int reason, bool unbusy) +static void __scsi_queue_insert(struct scsi_cmnd *cmd, + enum scsi_qc_status reason, bool unbusy) { struct scsi_device *device = cmd->device; @@ -179,7 +180,7 @@ static void __scsi_queue_insert(struct scsi_cmnd *cmd, int reason, bool unbusy) * Context: This could be called either from an interrupt context or a normal * process context. */ -void scsi_queue_insert(struct scsi_cmnd *cmd, int reason) +void scsi_queue_insert(struct scsi_cmnd *cmd, enum scsi_qc_status reason) { __scsi_queue_insert(cmd, reason, true); } @@ -1577,7 +1578,7 @@ static void scsi_complete(struct request *rq) * Return: nonzero return request was rejected and device's queue needs to be * plugged. */ -static int scsi_dispatch_cmd(struct scsi_cmnd *cmd) +static enum scsi_qc_status scsi_dispatch_cmd(struct scsi_cmnd *cmd) { struct Scsi_Host *host = cmd->device->host; int rtn = 0; @@ -1826,7 +1827,7 @@ static blk_status_t scsi_queue_rq(struct blk_mq_hw_ctx *hctx, struct Scsi_Host *shost = sdev->host; struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(req); blk_status_t ret; - int reason; + enum scsi_qc_status reason; WARN_ON_ONCE(cmd->budget_token < 0); diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index d07ec15d6c00..7a193cc04e5b 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -102,7 +102,8 @@ void scsi_eh_done(struct scsi_cmnd *scmd); /* scsi_lib.c */ extern void scsi_device_unbusy(struct scsi_device *sdev, struct scsi_cmnd *cmd); -extern void scsi_queue_insert(struct scsi_cmnd *cmd, int reason); +extern void scsi_queue_insert(struct scsi_cmnd *cmd, + enum scsi_qc_status reason); extern void scsi_io_completion(struct scsi_cmnd *, unsigned int); extern void scsi_run_host_queues(struct Scsi_Host *shost); extern void scsi_requeue_run_queue(struct work_struct *work); diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h index 96b350366670..08ac3200b4a4 100644 --- a/include/scsi/scsi.h +++ b/include/scsi/scsi.h @@ -106,12 +106,15 @@ enum scsi_disposition { }; /* - * Midlevel queue return values. + * Status values returned by the .queuecommand() callback if a command has not + * been queued. */ -#define SCSI_MLQUEUE_HOST_BUSY 0x1055 -#define SCSI_MLQUEUE_DEVICE_BUSY 0x1056 -#define SCSI_MLQUEUE_EH_RETRY 0x1057 -#define SCSI_MLQUEUE_TARGET_BUSY 0x1058 +enum scsi_qc_status { + SCSI_MLQUEUE_HOST_BUSY = 0x1055, + SCSI_MLQUEUE_DEVICE_BUSY = 0x1056, + SCSI_MLQUEUE_EH_RETRY = 0x1057, + SCSI_MLQUEUE_TARGET_BUSY = 0x1058, +}; /* * Use these to separate status msg and our bytes From 7411f1875a6055abe16e72fa5fc1b731cbfc7d76 Mon Sep 17 00:00:00 2001 From: Himanshu Madhani Date: Wed, 10 Dec 2025 15:45:53 +0530 Subject: [PATCH 16/78] scsi: qla2xxx: Add Speed in SFP print information Print additional information about the speed while displaying SFP information. Signed-off-by: Himanshu Madhani Signed-off-by: Nilesh Javali Reviewed-by: Himanshu Madhani Link: https://patch.msgid.link/20251210101604.431868-2-njavali@marvell.com Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_init.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index d395cbfe6802..29dabcaada33 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -4074,6 +4074,20 @@ 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\n", + (int)sizeof(a0->vendor_name), a0->vendor_name, + (int)sizeof(a0->vendor_pn), a0->vendor_pn, + 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, From 21ab087cae5000dd084dfb21d0a4d6086f79c445 Mon Sep 17 00:00:00 2001 From: Manish Rangankar Date: Wed, 10 Dec 2025 15:45:54 +0530 Subject: [PATCH 17/78] scsi: qla2xxx: Add support for 64G SFP speed Incorrect speed info is shown in driver logs for 64G SFP. Add support for 64G SFP speed as per SFF-8472 specification. Signed-off-by: Manish Rangankar Signed-off-by: Nilesh Javali Reviewed-by: Himanshu Madhani Link: https://patch.msgid.link/20251210101604.431868-3-njavali@marvell.com Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_def.h | 6 ++++-- drivers/scsi/qla2xxx/qla_init.c | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index b3265952c4be..e44b51c5a3eb 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -5368,7 +5368,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 +5412,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 +5431,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_init.c b/drivers/scsi/qla2xxx/qla_init.c index 29dabcaada33..3aba4e86618f 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -4075,9 +4075,11 @@ static void qla2xxx_print_sfp_info(struct scsi_qla_host *vha) int leftover, len; ql_dbg(ql_dbg_init, vha, 0x015a, - "SFP: %.*s -> %.*s ->%s%s%s%s%s%s\n", + "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" : "", From b99b04b12214ff5e4a01575c3c6612ae79bc5e76 Mon Sep 17 00:00:00 2001 From: Manish Rangankar Date: Wed, 10 Dec 2025 15:45:55 +0530 Subject: [PATCH 18/78] scsi: qla2xxx: Add load flash firmware mailbox support for 28xxx For 28xxx adaptor Load flash firmware mailbox load the operational firmware from flash, and also validate the checksum. Driver does not need to load the operational firmware anymore, but it still need to read fwdt from flash to build and allocate firmware dump template. Remove request_firmware() support for 28xxx adapter. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202512031128.XsuvzBv1-lkp@intel.com/ Signed-off-by: Manish Rangankar Signed-off-by: Nilesh Javali Reviewed-by: Himanshu Madhani Link: https://patch.msgid.link/20251210101604.431868-4-njavali@marvell.com Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_def.h | 1 + drivers/scsi/qla2xxx/qla_gbl.h | 3 + drivers/scsi/qla2xxx/qla_init.c | 188 +++++++++++++++++++++++++++++++- drivers/scsi/qla2xxx/qla_mbx.c | 48 ++++++++ 4 files changed, 236 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index e44b51c5a3eb..04bc69bb11b1 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. */ diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 55d531c19e6b..f12b2689163d 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -344,6 +344,9 @@ qla2x00_dump_ram(scsi_qla_host_t *, dma_addr_t, uint32_t, uint32_t); 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 *); diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 3aba4e86618f..5183ff813487 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -8458,6 +8458,148 @@ bool qla24xx_risc_firmware_invalid(uint32_t *dword) !(~dword[4] | ~dword[5] | ~dword[6] | ~dword[7]); } +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) @@ -8897,16 +9039,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)) @@ -8914,6 +9058,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(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; @@ -8943,6 +9121,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_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 1f01576f044b..28bb645ace67 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 }, @@ -824,6 +825,53 @@ done: return rval; } +/* + * 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 From 478b152ab309a3fb94f4955ac661a38c7f150101 Mon Sep 17 00:00:00 2001 From: Manish Rangankar Date: Wed, 10 Dec 2025 15:45:56 +0530 Subject: [PATCH 19/78] scsi: qla2xxx: Validate MCU signature before executing MBC 03h FC firmware does not come online during on-the-fly upgrade i.e. on soft reset. To limit Load flash firmware, i.e. MBC 3 changes, validate MCU signature before executing MBC 03h Signed-off-by: Manish Rangankar Signed-off-by: Nilesh Javali Reviewed-by: Himanshu Madhani Link: https://patch.msgid.link/20251210101604.431868-5-njavali@marvell.com Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_def.h | 3 +++ drivers/scsi/qla2xxx/qla_init.c | 2 +- drivers/scsi/qla2xxx/qla_nx.h | 1 + drivers/scsi/qla2xxx/qla_sup.c | 29 +++++++++++++++++++++++++++++ 4 files changed, 34 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 04bc69bb11b1..7e693540c434 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -4150,6 +4150,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; @@ -4415,6 +4416,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; diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 5183ff813487..9729e32012aa 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -9059,7 +9059,7 @@ 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(ha)) { + if (IS_QLA28XX_SECURED(ha)) { rval = qla28xx_load_flash_firmware(vha); if (rval != QLA_SUCCESS) { ql_log(ql_log_fatal, vha, 0x019e, 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_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; From d74181ca110e3de9d7dc4fba7f9f6026033e2e5d Mon Sep 17 00:00:00 2001 From: Manish Rangankar Date: Wed, 10 Dec 2025 15:45:57 +0530 Subject: [PATCH 20/78] 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 ccfc2d26dd37..8afa8a4b8ccb 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 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 7e693540c434..5593ad7fad27 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 f12b2689163d..9e328c235e39 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 28bb645ace67..0d598be6f3ea 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; +} From b0335ee4fb94832a4ef68774ca7e7b33b473c7a6 Mon Sep 17 00:00:00 2001 From: Shreyas Deodhar Date: Wed, 10 Dec 2025 15:45:58 +0530 Subject: [PATCH 21/78] scsi: qla2xxx: Allow recovery for tape devices Tape device doesn't show up after RSCNs. To fix this, remove tape device specific checks which allows recovery of tape devices. Fixes: 44c57f205876 ("scsi: qla2xxx: Changes to support FCP2 Target") Cc: stable@vger.kernel.org Signed-off-by: Shreyas Deodhar Signed-off-by: Nilesh Javali Reviewed-by: Himanshu Madhani Link: https://patch.msgid.link/20251210101604.431868-7-njavali@marvell.com Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_gs.c | 3 --- drivers/scsi/qla2xxx/qla_init.c | 9 --------- 2 files changed, 12 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 51c7cea71f90..02a52c215797 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__, diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 9729e32012aa..6ce3a492ad6f 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 From 8890bf450e0b6b283f48ac619fca5ac2f14ddd62 Mon Sep 17 00:00:00 2001 From: Anil Gurumurthy Date: Wed, 10 Dec 2025 15:45:59 +0530 Subject: [PATCH 22/78] scsi: qla2xxx: Delay module unload while fabric scan in progress System crash seen during load/unload test in a loop. [105954.384919] RBP: ffff914589838dc0 R08: 0000000000000000 R09: 0000000000000086 [105954.384920] R10: 000000000000000f R11: ffffa31240904be5 R12: ffff914605f868e0 [105954.384921] R13: ffff914605f86910 R14: 0000000000008010 R15: 00000000ddb7c000 [105954.384923] FS: 0000000000000000(0000) GS:ffff9163fec40000(0000) knlGS:0000000000000000 [105954.384925] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [105954.384926] CR2: 000055d31ce1d6a0 CR3: 0000000119f5e001 CR4: 0000000000770ee0 [105954.384928] PKRU: 55555554 [105954.384929] Call Trace: [105954.384931] [105954.384934] qla24xx_sp_unmap+0x1f3/0x2a0 [qla2xxx] [105954.384962] ? qla_async_scan_sp_done+0x114/0x1f0 [qla2xxx] [105954.384980] ? qla24xx_els_ct_entry+0x4de/0x760 [qla2xxx] [105954.384999] ? __wake_up_common+0x80/0x190 [105954.385004] ? qla24xx_process_response_queue+0xc2/0xaa0 [qla2xxx] [105954.385023] ? qla24xx_msix_rsp_q+0x44/0xb0 [qla2xxx] [105954.385040] ? __handle_irq_event_percpu+0x3d/0x190 [105954.385044] ? handle_irq_event+0x58/0xb0 [105954.385046] ? handle_edge_irq+0x93/0x240 [105954.385050] ? __common_interrupt+0x41/0xa0 [105954.385055] ? common_interrupt+0x3e/0xa0 [105954.385060] ? asm_common_interrupt+0x22/0x40 The root cause of this was that there was a free (dma_free_attrs) in the interrupt context. There was a device discovery/fabric scan in progress. A module unload was issued which set the UNLOADING flag. As part of the discovery, after receiving an interrupt a work queue was scheduled (which involved a work to be queued). Since the UNLOADING flag is set, the work item was not allocated and the mapped memory had to be freed. The free occurred in interrupt context leading to system crash. Delay the driver unload until the fabric scan is complete to avoid the crash. Reported-by: kernel test robot Reported-by: Dan Carpenter Closes: https://lore.kernel.org/all/202512090414.07Waorz0-lkp@intel.com/ Fixes: 783e0dc4f66a ("qla2xxx: Check for device state before unloading the driver.") Cc: stable@vger.kernel.org Signed-off-by: Anil Gurumurthy Signed-off-by: Nilesh Javali Reviewed-by: Himanshu Madhani Link: https://patch.msgid.link/20251210101604.431868-8-njavali@marvell.com Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_os.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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); From 7adbd2b7809066c75f0433e5e2a8e114b429f30f Mon Sep 17 00:00:00 2001 From: Anil Gurumurthy Date: Wed, 10 Dec 2025 15:46:00 +0530 Subject: [PATCH 23/78] scsi: qla2xxx: Free sp in error path to fix system crash System crash seen during load/unload test in a loop, [61110.449331] qla2xxx [0000:27:00.0]-0042:0: Disabled MSI-X. [61110.467494] ============================================================================= [61110.467498] BUG qla2xxx_srbs (Tainted: G OE -------- --- ): Objects remaining in qla2xxx_srbs on __kmem_cache_shutdown() [61110.467501] ----------------------------------------------------------------------------- [61110.467502] Slab 0x000000000ffc8162 objects=51 used=1 fp=0x00000000e25d3d85 flags=0x57ffffc0010200(slab|head|node=1|zone=2|lastcpupid=0x1fffff) [61110.467509] CPU: 53 PID: 455206 Comm: rmmod Kdump: loaded Tainted: G OE -------- --- 5.14.0-284.11.1.el9_2.x86_64 #1 [61110.467513] Hardware name: HPE ProLiant DL385 Gen10 Plus v2/ProLiant DL385 Gen10 Plus v2, BIOS A42 08/17/2023 [61110.467515] Call Trace: [61110.467516] [61110.467519] dump_stack_lvl+0x34/0x48 [61110.467526] slab_err.cold+0x53/0x67 [61110.467534] __kmem_cache_shutdown+0x16e/0x320 [61110.467540] kmem_cache_destroy+0x51/0x160 [61110.467544] qla2x00_module_exit+0x93/0x99 [qla2xxx] [61110.467607] ? __do_sys_delete_module.constprop.0+0x178/0x280 [61110.467613] ? syscall_trace_enter.constprop.0+0x145/0x1d0 [61110.467616] ? do_syscall_64+0x5c/0x90 [61110.467619] ? exc_page_fault+0x62/0x150 [61110.467622] ? entry_SYSCALL_64_after_hwframe+0x63/0xcd [61110.467626] [61110.467627] Disabling lock debugging due to kernel taint [61110.467635] Object 0x0000000026f7e6e6 @offset=16000 [61110.467639] ------------[ cut here ]------------ [61110.467639] kmem_cache_destroy qla2xxx_srbs: Slab cache still has objects when called from qla2x00_module_exit+0x93/0x99 [qla2xxx] [61110.467659] WARNING: CPU: 53 PID: 455206 at mm/slab_common.c:520 kmem_cache_destroy+0x14d/0x160 [61110.467718] CPU: 53 PID: 455206 Comm: rmmod Kdump: loaded Tainted: G B OE -------- --- 5.14.0-284.11.1.el9_2.x86_64 #1 [61110.467720] Hardware name: HPE ProLiant DL385 Gen10 Plus v2/ProLiant DL385 Gen10 Plus v2, BIOS A42 08/17/2023 [61110.467721] RIP: 0010:kmem_cache_destroy+0x14d/0x160 [61110.467724] Code: 99 7d 07 00 48 89 ef e8 e1 6a 07 00 eb b3 48 8b 55 60 48 8b 4c 24 20 48 c7 c6 70 fc 66 90 48 c7 c7 f8 ef a1 90 e8 e1 ed 7c 00 <0f> 0b eb 93 c3 cc cc cc cc 66 2e 0f 1f 84 00 00 00 00 00 55 48 89 [61110.467725] RSP: 0018:ffffa304e489fe80 EFLAGS: 00010282 [61110.467727] RAX: 0000000000000000 RBX: ffffffffc0d9a860 RCX: 0000000000000027 [61110.467729] RDX: ffff8fd5ff9598a8 RSI: 0000000000000001 RDI: ffff8fd5ff9598a0 [61110.467730] RBP: ffff8fb6aaf78700 R08: 0000000000000000 R09: 0000000100d863b7 [61110.467731] R10: ffffa304e489fd20 R11: ffffffff913bef48 R12: 0000000040002000 [61110.467731] R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000 [61110.467733] FS: 00007f64c89fb740(0000) GS:ffff8fd5ff940000(0000) knlGS:0000000000000000 [61110.467734] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [61110.467735] CR2: 00007f0f02bfe000 CR3: 00000020ad6dc005 CR4: 0000000000770ee0 [61110.467736] PKRU: 55555554 [61110.467737] Call Trace: [61110.467738] [61110.467739] qla2x00_module_exit+0x93/0x99 [qla2xxx] [61110.467755] ? __do_sys_delete_module.constprop.0+0x178/0x280 Free sp in the error path to fix the crash. Fixes: f352eeb75419 ("scsi: qla2xxx: Add ability to use GPNFT/GNNFT for RSCN handling") Cc: stable@vger.kernel.org Signed-off-by: Anil Gurumurthy Signed-off-by: Nilesh Javali Reviewed-by: Himanshu Madhani Link: https://patch.msgid.link/20251210101604.431868-9-njavali@marvell.com Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_gs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 02a52c215797..e5ebb9c5b650 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -3532,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) From b6df15aec8c3441357d4da0eaf4339eb20f5999f Mon Sep 17 00:00:00 2001 From: Anil Gurumurthy Date: Wed, 10 Dec 2025 15:46:01 +0530 Subject: [PATCH 24/78] scsi: qla2xxx: Validate sp before freeing associated memory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit System crash with the following signature [154563.214890] nvme nvme2: NVME-FC{1}: controller connect complete [154564.169363] qla2xxx [0000:b0:00.1]-3002:2: nvme: Sched: Set ZIO exchange threshold to 3. [154564.169405] qla2xxx [0000:b0:00.1]-ffffff:2: SET ZIO Activity exchange threshold to 5. [154565.539974] qla2xxx [0000:b0:00.1]-5013:2: RSCN database changed – 0078 0080 0000. [154565.545744] qla2xxx [0000:b0:00.1]-5013:2: RSCN database changed – 0078 00a0 0000. [154565.545857] qla2xxx [0000:b0:00.1]-11a2:2: FEC=enabled (data rate). [154565.552760] qla2xxx [0000:b0:00.1]-11a2:2: FEC=enabled (data rate). [154565.553079] BUG: kernel NULL pointer dereference, address: 00000000000000f8 [154565.553080] #PF: supervisor read access in kernel mode [154565.553082] #PF: error_code(0x0000) - not-present page [154565.553084] PGD 80000010488ab067 P4D 80000010488ab067 PUD 104978a067 PMD 0 [154565.553089] Oops: 0000 1 PREEMPT SMP PTI [154565.553092] CPU: 10 PID: 858 Comm: qla2xxx_2_dpc Kdump: loaded Tainted: G OE ------- --- 5.14.0-503.11.1.el9_5.x86_64 #1 [154565.553096] Hardware name: HPE Synergy 660 Gen10/Synergy 660 Gen10 Compute Module, BIOS I43 09/30/2024 [154565.553097] RIP: 0010:qla_fab_async_scan.part.0+0x40b/0x870 [qla2xxx] [154565.553141] Code: 00 00 e8 58 a3 ec d4 49 89 e9 ba 12 20 00 00 4c 89 e6 49 c7 c0 00 ee a8 c0 48 c7 c1 66 c0 a9 c0 bf 00 80 00 10 e8 15 69 00 00 <4c> 8b 8d f8 00 00 00 4d 85 c9 74 35 49 8b 84 24 00 19 00 00 48 8b [154565.553143] RSP: 0018:ffffb4dbc8aebdd0 EFLAGS: 00010286 [154565.553145] RAX: 0000000000000000 RBX: ffff8ec2cf0908d0 RCX: 0000000000000002 [154565.553147] RDX: 0000000000000000 RSI: ffffffffc0a9c896 RDI: ffffb4dbc8aebd47 [154565.553148] RBP: 0000000000000000 R08: ffffb4dbc8aebd45 R09: 0000000000ffff0a [154565.553150] R10: 0000000000000000 R11: 000000000000000f R12: ffff8ec2cf0908d0 [154565.553151] R13: ffff8ec2cf090900 R14: 0000000000000102 R15: ffff8ec2cf084000 [154565.553152] FS: 0000000000000000(0000) GS:ffff8ed27f800000(0000) knlGS:0000000000000000 [154565.553154] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [154565.553155] CR2: 00000000000000f8 CR3: 000000113ae0a005 CR4: 00000000007706f0 [154565.553157] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [154565.553158] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [154565.553159] PKRU: 55555554 [154565.553160] Call Trace: [154565.553162] [154565.553165] ? show_trace_log_lvl+0x1c4/0x2df [154565.553172] ? show_trace_log_lvl+0x1c4/0x2df [154565.553177] ? qla_fab_async_scan.part.0+0x40b/0x870 [qla2xxx] [154565.553215] ? __die_body.cold+0x8/0xd [154565.553218] ? page_fault_oops+0x134/0x170 [154565.553223] ? snprintf+0x49/0x70 [154565.553229] ? exc_page_fault+0x62/0x150 [154565.553238] ? asm_exc_page_fault+0x22/0x30 Check for sp being non NULL before freeing any associated memory Fixes: a4239945b8ad ("scsi: qla2xxx: Add switch command to simplify fabric discovery") Cc: stable@vger.kernel.org Signed-off-by: Anil Gurumurthy Signed-off-by: Nilesh Javali Reviewed-by: Himanshu Madhani Link: https://patch.msgid.link/20251210101604.431868-10-njavali@marvell.com Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_gs.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index e5ebb9c5b650..880cd73feaca 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -3698,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; From 42b2dab4340d39b71334151e10c6d7d9b0040ffa Mon Sep 17 00:00:00 2001 From: Anil Gurumurthy Date: Wed, 10 Dec 2025 15:46:02 +0530 Subject: [PATCH 25/78] scsi: qla2xxx: Query FW again before proceeding with login Issue occurred during a continuous reboot test of several thousand iterations specific to a fabric topo with dual mode target where it sends a PLOGI/PRLI and then sends a LOGO. The initiator was also in the process of discovery and sent a PLOGI to the switch. It then queried a list of ports logged in via mbx 75h and the GPDB response indicated that the target was logged in. This caused a mismatch in the states between the driver and FW. Requery the FW for the state and proceed with the rest of discovery process. Fixes: a4239945b8ad ("scsi: qla2xxx: Add switch command to simplify fabric discovery") Cc: stable@vger.kernel.org Signed-off-by: Anil Gurumurthy Signed-off-by: Nilesh Javali Reviewed-by: Himanshu Madhani Link: https://patch.msgid.link/20251210101604.431868-11-njavali@marvell.com Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_init.c | 19 +++++++++++++++++-- drivers/scsi/qla2xxx/qla_isr.c | 19 +++++++++++++++++-- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 6ce3a492ad6f..689f909943b4 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -2462,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); 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); From c2c68225b1456f4d0d393b5a8778d51bb0d5b1d0 Mon Sep 17 00:00:00 2001 From: Anil Gurumurthy Date: Wed, 10 Dec 2025 15:46:03 +0530 Subject: [PATCH 26/78] scsi: qla2xxx: Fix bsg_done() causing double free Kernel panic observed on system, [5353358.825191] BUG: unable to handle page fault for address: ff5f5e897b024000 [5353358.825194] #PF: supervisor write access in kernel mode [5353358.825195] #PF: error_code(0x0002) - not-present page [5353358.825196] PGD 100006067 P4D 0 [5353358.825198] Oops: 0002 [#1] PREEMPT SMP NOPTI [5353358.825200] CPU: 5 PID: 2132085 Comm: qlafwupdate.sub Kdump: loaded Tainted: G W L ------- --- 5.14.0-503.34.1.el9_5.x86_64 #1 [5353358.825203] Hardware name: HPE ProLiant DL360 Gen11/ProLiant DL360 Gen11, BIOS 2.44 01/17/2025 [5353358.825204] RIP: 0010:memcpy_erms+0x6/0x10 [5353358.825211] RSP: 0018:ff591da8f4f6b710 EFLAGS: 00010246 [5353358.825212] RAX: ff5f5e897b024000 RBX: 0000000000007090 RCX: 0000000000001000 [5353358.825213] RDX: 0000000000001000 RSI: ff591da8f4fed090 RDI: ff5f5e897b024000 [5353358.825214] RBP: 0000000000010000 R08: ff5f5e897b024000 R09: 0000000000000000 [5353358.825215] R10: ff46cf8c40517000 R11: 0000000000000001 R12: 0000000000008090 [5353358.825216] R13: ff591da8f4f6b720 R14: 0000000000001000 R15: 0000000000000000 [5353358.825218] FS: 00007f1e88d47740(0000) GS:ff46cf935f940000(0000) knlGS:0000000000000000 [5353358.825219] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [5353358.825220] CR2: ff5f5e897b024000 CR3: 0000000231532004 CR4: 0000000000771ef0 [5353358.825221] PKRU: 55555554 [5353358.825222] Call Trace: [5353358.825223] [5353358.825224] ? show_trace_log_lvl+0x1c4/0x2df [5353358.825229] ? show_trace_log_lvl+0x1c4/0x2df [5353358.825232] ? sg_copy_buffer+0xc8/0x110 [5353358.825236] ? __die_body.cold+0x8/0xd [5353358.825238] ? page_fault_oops+0x134/0x170 [5353358.825242] ? kernelmode_fixup_or_oops+0x84/0x110 [5353358.825244] ? exc_page_fault+0xa8/0x150 [5353358.825247] ? asm_exc_page_fault+0x22/0x30 [5353358.825252] ? memcpy_erms+0x6/0x10 [5353358.825253] sg_copy_buffer+0xc8/0x110 [5353358.825259] qla2x00_process_vendor_specific+0x652/0x1320 [qla2xxx] [5353358.825317] qla24xx_bsg_request+0x1b2/0x2d0 [qla2xxx] Most routines in qla_bsg.c call bsg_done() only for success cases. However a few invoke it for failure case as well leading to a double free. Validate before calling bsg_done(). Cc: stable@vger.kernel.org Signed-off-by: Anil Gurumurthy Signed-off-by: Nilesh Javali Reviewed-by: Himanshu Madhani Link: https://patch.msgid.link/20251210101604.431868-12-njavali@marvell.com Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_bsg.c | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index 8afa8a4b8ccb..2c44a379cb23 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -1548,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; } @@ -2638,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; } @@ -2728,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: @@ -2828,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); @@ -2890,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; } @@ -3272,7 +3277,8 @@ 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); @@ -3359,8 +3365,9 @@ static int qla28xx_validate_flash_image(struct bsg_job *bsg_job) 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); + if (!rval) + bsg_job_done(bsg_job, bsg_reply->result, + bsg_reply->reply_payload_rcv_len); return QLA_SUCCESS; } From 1732d10fa7edb611c8384ca0b841d6f79ddf5bed Mon Sep 17 00:00:00 2001 From: Nilesh Javali Date: Wed, 10 Dec 2025 15:46:04 +0530 Subject: [PATCH 27/78] scsi: qla2xxx: Update version to 10.02.10.100-k Signed-off-by: Nilesh Javali Reviewed-by: Himanshu Madhani Link: https://patch.msgid.link/20251210101604.431868-13-njavali@marvell.com Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_version.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 From 8e8e8e7e8406e96a0189e116eb04f67f776f947f Mon Sep 17 00:00:00 2001 From: ReBeating Date: Fri, 26 Dec 2025 11:19:36 +0800 Subject: [PATCH 28/78] scsi: target: sbp: Potential integer overflow in sbp_make_tpg() The variable tpgt in sbp_make_tpg() is defined as unsigned long and is assigned to tpgt->tport_tpgt, which is defined as u16. This may cause an integer overflow when tpgt is greater than USHRT_MAX (65535). I haven't tried to trigger it myself, but it is possible to trigger it by calling sbp_make_tpg() with a large value for tpgt. Modify the type of tpgt to match tpgt->tport_tpgt and adjusted the relevant code accordingly. This patch is similar to commit 59c816c1f24d ("vhost/scsi: potential memory corruption"). Signed-off-by: ReBeating Link: https://patch.msgid.link/20251226031936.852-1-rebeating@163.com Signed-off-by: Martin K. Petersen --- drivers/target/sbp/sbp_target.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 9f167ff8da7b..09120a538a40 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -1960,12 +1960,12 @@ static struct se_portal_group *sbp_make_tpg(struct se_wwn *wwn, container_of(wwn, struct sbp_tport, tport_wwn); struct sbp_tpg *tpg; - unsigned long tpgt; + u16 tpgt; int ret; if (strstr(name, "tpgt_") != name) return ERR_PTR(-EINVAL); - if (kstrtoul(name + 5, 10, &tpgt) || tpgt > UINT_MAX) + if (kstrtou16(name + 5, 10, &tpgt)) return ERR_PTR(-EINVAL); if (tport->tpg) { From ae62d62b1c740f7a5ea72082dc28f30ebf6b134d Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Mon, 29 Dec 2025 12:35:01 +0100 Subject: [PATCH 29/78] scsi: target: Constify struct configfs_item_operations and configfs_group_operations 'struct configfs_item_operations' and 'configfs_group_operations' are not modified in this driver. Constifying these structures moves some data to a read-only section, so increases overall security, especially when the structure holds some function pointers. On a x86_64, with allmodconfig: Before: ====== text data bss dec hex filename 151831 80058 4832 236721 39cb1 drivers/target/target_core_configfs.o 45200 16658 0 61858 f1a2 drivers/target/target_core_fabric_configfs.o After: ===== text data bss dec hex filename 152599 79290 4832 236721 39cb1 drivers/target/target_core_configfs.o 46352 15506 0 61858 f1a2 drivers/target/target_core_fabric_configfs.o Signed-off-by: Christophe JAILLET Link: https://patch.msgid.link/a0f25237ae86b8c4dd7a3876c4ed2dc3de200173.1767008082.git.christophe.jaillet@wanadoo.fr Signed-off-by: Martin K. Petersen --- drivers/target/target_core_configfs.c | 18 ++++++------ drivers/target/target_core_fabric_configfs.c | 30 ++++++++++---------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index eb5bc3f1673b..b27a3b8dd767 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -288,7 +288,7 @@ static void target_core_deregister_fabric( config_item_put(item); } -static struct configfs_group_operations target_core_fabric_group_ops = { +static const struct configfs_group_operations target_core_fabric_group_ops = { .make_group = &target_core_register_fabric, .drop_item = &target_core_deregister_fabric, }; @@ -2860,7 +2860,7 @@ static void target_core_alua_lu_gp_release(struct config_item *item) core_alua_free_lu_gp(lu_gp); } -static struct configfs_item_operations target_core_alua_lu_gp_ops = { +static const struct configfs_item_operations target_core_alua_lu_gp_ops = { .release = target_core_alua_lu_gp_release, }; @@ -2917,7 +2917,7 @@ static void target_core_alua_drop_lu_gp( config_item_put(item); } -static struct configfs_group_operations target_core_alua_lu_gps_group_ops = { +static const struct configfs_group_operations target_core_alua_lu_gps_group_ops = { .make_group = &target_core_alua_create_lu_gp, .drop_item = &target_core_alua_drop_lu_gp, }; @@ -3290,7 +3290,7 @@ static void target_core_alua_tg_pt_gp_release(struct config_item *item) core_alua_free_tg_pt_gp(tg_pt_gp); } -static struct configfs_item_operations target_core_alua_tg_pt_gp_ops = { +static const struct configfs_item_operations target_core_alua_tg_pt_gp_ops = { .release = target_core_alua_tg_pt_gp_release, }; @@ -3348,7 +3348,7 @@ static void target_core_alua_drop_tg_pt_gp( config_item_put(item); } -static struct configfs_group_operations target_core_alua_tg_pt_gps_group_ops = { +static const struct configfs_group_operations target_core_alua_tg_pt_gps_group_ops = { .make_group = &target_core_alua_create_tg_pt_gp, .drop_item = &target_core_alua_drop_tg_pt_gp, }; @@ -3389,7 +3389,7 @@ static void target_core_stat_rmdir( return; } -static struct configfs_group_operations target_core_stat_group_ops = { +static const struct configfs_group_operations target_core_stat_group_ops = { .make_group = &target_core_stat_mkdir, .drop_item = &target_core_stat_rmdir, }; @@ -3516,7 +3516,7 @@ static void target_core_drop_subdev( mutex_unlock(&hba->hba_access_mutex); } -static struct configfs_group_operations target_core_hba_group_ops = { +static const struct configfs_group_operations target_core_hba_group_ops = { .make_group = target_core_make_subdev, .drop_item = target_core_drop_subdev, }; @@ -3595,7 +3595,7 @@ static struct configfs_attribute *target_core_hba_attrs[] = { NULL, }; -static struct configfs_item_operations target_core_hba_item_ops = { +static const struct configfs_item_operations target_core_hba_item_ops = { .release = target_core_hba_release, }; @@ -3676,7 +3676,7 @@ static void target_core_call_delhbafromtarget( config_item_put(item); } -static struct configfs_group_operations target_core_group_ops = { +static const struct configfs_group_operations target_core_group_ops = { .make_group = target_core_call_addhbatotarget, .drop_item = target_core_call_delhbafromtarget, }; diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index 13159928e365..59713e9be10a 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -59,7 +59,7 @@ static void target_fabric_setup_##_name##_cit(struct target_fabric_configfs *tf) pr_debug("Setup generic %s\n", __stringify(_name)); \ } -static struct configfs_item_operations target_fabric_port_item_ops; +static const struct configfs_item_operations target_fabric_port_item_ops; /* Start of tfc_tpg_mappedlun_cit */ @@ -219,7 +219,7 @@ static void target_fabric_mappedlun_release(struct config_item *item) core_dev_free_initiator_node_lun_acl(se_tpg, lacl); } -static struct configfs_item_operations target_fabric_mappedlun_item_ops = { +static const struct configfs_item_operations target_fabric_mappedlun_item_ops = { .release = target_fabric_mappedlun_release, .allow_link = target_fabric_mappedlun_link, .drop_link = target_fabric_mappedlun_unlink, @@ -246,7 +246,7 @@ static void target_core_mappedlun_stat_rmdir( return; } -static struct configfs_group_operations target_fabric_mappedlun_stat_group_ops = { +static const struct configfs_group_operations target_fabric_mappedlun_stat_group_ops = { .make_group = target_core_mappedlun_stat_mkdir, .drop_item = target_core_mappedlun_stat_rmdir, }; @@ -345,11 +345,11 @@ static void target_fabric_nacl_base_release(struct config_item *item) core_tpg_del_initiator_node_acl(se_nacl); } -static struct configfs_item_operations target_fabric_nacl_base_item_ops = { +static const struct configfs_item_operations target_fabric_nacl_base_item_ops = { .release = target_fabric_nacl_base_release, }; -static struct configfs_group_operations target_fabric_nacl_base_group_ops = { +static const struct configfs_group_operations target_fabric_nacl_base_group_ops = { .make_group = target_fabric_make_mappedlun, .drop_item = target_fabric_drop_mappedlun, }; @@ -433,7 +433,7 @@ static void target_fabric_drop_nodeacl( config_item_put(item); } -static struct configfs_group_operations target_fabric_nacl_group_ops = { +static const struct configfs_group_operations target_fabric_nacl_group_ops = { .make_group = target_fabric_make_nodeacl, .drop_item = target_fabric_drop_nodeacl, }; @@ -454,7 +454,7 @@ static void target_fabric_np_base_release(struct config_item *item) tf->tf_ops->fabric_drop_np(se_tpg_np); } -static struct configfs_item_operations target_fabric_np_base_item_ops = { +static const struct configfs_item_operations target_fabric_np_base_item_ops = { .release = target_fabric_np_base_release, }; @@ -499,7 +499,7 @@ static void target_fabric_drop_np( config_item_put(item); } -static struct configfs_group_operations target_fabric_np_group_ops = { +static const struct configfs_group_operations target_fabric_np_group_ops = { .make_group = &target_fabric_make_np, .drop_item = &target_fabric_drop_np, }; @@ -700,7 +700,7 @@ static void target_fabric_port_release(struct config_item *item) call_rcu(&lun->rcu_head, target_tpg_free_lun); } -static struct configfs_item_operations target_fabric_port_item_ops = { +static const struct configfs_item_operations target_fabric_port_item_ops = { .release = target_fabric_port_release, .allow_link = target_fabric_port_link, .drop_link = target_fabric_port_unlink, @@ -726,7 +726,7 @@ static void target_core_port_stat_rmdir( return; } -static struct configfs_group_operations target_fabric_port_stat_group_ops = { +static const struct configfs_group_operations target_fabric_port_stat_group_ops = { .make_group = target_core_port_stat_mkdir, .drop_item = target_core_port_stat_rmdir, }; @@ -787,7 +787,7 @@ static void target_fabric_drop_lun( config_item_put(item); } -static struct configfs_group_operations target_fabric_lun_group_ops = { +static const struct configfs_group_operations target_fabric_lun_group_ops = { .make_group = &target_fabric_make_lun, .drop_item = &target_fabric_drop_lun, }; @@ -812,7 +812,7 @@ static void target_fabric_tpg_release(struct config_item *item) tf->tf_ops->fabric_drop_tpg(se_tpg); } -static struct configfs_item_operations target_fabric_tpg_base_item_ops = { +static const struct configfs_item_operations target_fabric_tpg_base_item_ops = { .release = target_fabric_tpg_release, }; @@ -998,11 +998,11 @@ static void target_fabric_release_wwn(struct config_item *item) tf->tf_ops->fabric_drop_wwn(wwn); } -static struct configfs_item_operations target_fabric_tpg_item_ops = { +static const struct configfs_item_operations target_fabric_tpg_item_ops = { .release = target_fabric_release_wwn, }; -static struct configfs_group_operations target_fabric_tpg_group_ops = { +static const struct configfs_group_operations target_fabric_tpg_group_ops = { .make_group = target_fabric_make_tpg, .drop_item = target_fabric_drop_tpg, }; @@ -1144,7 +1144,7 @@ static void target_fabric_drop_wwn( config_item_put(item); } -static struct configfs_group_operations target_fabric_wwn_group_ops = { +static const struct configfs_group_operations target_fabric_wwn_group_ops = { .make_group = target_fabric_make_wwn, .drop_item = target_fabric_drop_wwn, }; From 7d42bcea57ae139e2ed754425cc5fc44e260c890 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 19 Dec 2025 10:25:30 +0100 Subject: [PATCH 30/78] scsi: core: Pass a struct scsi_driver to scsi_{,un}register_driver() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This aligns with what other subsystems do, reduces boilerplate a bit for device drivers and is less error prone. Reviewed-by: Peter Wang Signed-off-by: Uwe Kleine-König Reviewed-by: Bart Van Assche Link: https://patch.msgid.link/ac17fdea58e384cb514c639306d48ce0005820b0.1766133330.git.u.kleine-koenig@baylibre.com Signed-off-by: Martin K. Petersen --- drivers/scsi/ch.c | 4 ++-- drivers/scsi/scsi_sysfs.c | 4 +++- drivers/scsi/sd.c | 4 ++-- drivers/scsi/ses.c | 4 ++-- drivers/scsi/sr.c | 4 ++-- drivers/scsi/st.c | 4 ++-- drivers/ufs/core/ufshcd.c | 4 ++-- include/scsi/scsi_driver.h | 4 ++-- 8 files changed, 17 insertions(+), 15 deletions(-) diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index fa07a6f54003..f2b63e4b9b99 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c @@ -1014,7 +1014,7 @@ static int __init init_ch_module(void) SCSI_CHANGER_MAJOR); goto fail1; } - rc = scsi_register_driver(&ch_template.gendrv); + rc = scsi_register_driver(&ch_template); if (rc < 0) goto fail2; return 0; @@ -1028,7 +1028,7 @@ static int __init init_ch_module(void) static void __exit exit_ch_module(void) { - scsi_unregister_driver(&ch_template.gendrv); + scsi_unregister_driver(&ch_template); unregister_chrdev(SCSI_CHANGER_MAJOR, "ch"); class_unregister(&ch_sysfs_class); idr_destroy(&ch_index_idr); diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 99eb0a30df61..db0ba68f2e6e 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -1554,8 +1554,10 @@ restart: } EXPORT_SYMBOL(scsi_remove_target); -int __scsi_register_driver(struct device_driver *drv, struct module *owner) +int __scsi_register_driver(struct scsi_driver *sdrv, struct module *owner) { + struct device_driver *drv = &sdrv->gendrv; + drv->bus = &scsi_bus_type; drv->owner = owner; diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index f50b92e63201..6ea6ee2830a4 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -4417,7 +4417,7 @@ static int __init init_sd(void) goto err_out_class; } - err = scsi_register_driver(&sd_template.gendrv); + err = scsi_register_driver(&sd_template); if (err) goto err_out_driver; @@ -4444,7 +4444,7 @@ static void __exit exit_sd(void) SCSI_LOG_HLQUEUE(3, printk("exit_sd: exiting sd driver\n")); - scsi_unregister_driver(&sd_template.gendrv); + scsi_unregister_driver(&sd_template); mempool_destroy(sd_page_pool); class_unregister(&sd_disk_class); diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index 2c61624cb4b0..f8f5164f3de2 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c @@ -921,7 +921,7 @@ static int __init ses_init(void) if (err) return err; - err = scsi_register_driver(&ses_template.gendrv); + err = scsi_register_driver(&ses_template); if (err) goto out_unreg; @@ -934,7 +934,7 @@ static int __init ses_init(void) static void __exit ses_exit(void) { - scsi_unregister_driver(&ses_template.gendrv); + scsi_unregister_driver(&ses_template); scsi_unregister_interface(&ses_interface); } diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index add13e306898..2f6bb6355186 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -1001,7 +1001,7 @@ static int __init init_sr(void) rc = register_blkdev(SCSI_CDROM_MAJOR, "sr"); if (rc) return rc; - rc = scsi_register_driver(&sr_template.gendrv); + rc = scsi_register_driver(&sr_template); if (rc) unregister_blkdev(SCSI_CDROM_MAJOR, "sr"); @@ -1010,7 +1010,7 @@ static int __init init_sr(void) static void __exit exit_sr(void) { - scsi_unregister_driver(&sr_template.gendrv); + scsi_unregister_driver(&sr_template); unregister_blkdev(SCSI_CDROM_MAJOR, "sr"); } diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 168f25e4aaa3..45622cfce926 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -4576,7 +4576,7 @@ static int __init init_st(void) goto err_class; } - err = scsi_register_driver(&st_template.gendrv); + err = scsi_register_driver(&st_template); if (err) goto err_chrdev; @@ -4592,7 +4592,7 @@ err_class: static void __exit exit_st(void) { - scsi_unregister_driver(&st_template.gendrv); + scsi_unregister_driver(&st_template); unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0), ST_MAX_TAPE_ENTRIES); class_unregister(&st_sysfs_class); diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 80c0b49f30b0..da1e89e95d07 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -11240,7 +11240,7 @@ static int __init ufshcd_core_init(void) ufs_debugfs_init(); - ret = scsi_register_driver(&ufs_dev_wlun_template.gendrv); + ret = scsi_register_driver(&ufs_dev_wlun_template); if (ret) ufs_debugfs_exit(); return ret; @@ -11249,7 +11249,7 @@ static int __init ufshcd_core_init(void) static void __exit ufshcd_core_exit(void) { ufs_debugfs_exit(); - scsi_unregister_driver(&ufs_dev_wlun_template.gendrv); + scsi_unregister_driver(&ufs_dev_wlun_template); } module_init(ufshcd_core_init); diff --git a/include/scsi/scsi_driver.h b/include/scsi/scsi_driver.h index c0e89996bdb3..40aba9a9349a 100644 --- a/include/scsi/scsi_driver.h +++ b/include/scsi/scsi_driver.h @@ -25,9 +25,9 @@ struct scsi_driver { #define scsi_register_driver(drv) \ __scsi_register_driver(drv, THIS_MODULE) -int __scsi_register_driver(struct device_driver *, struct module *); +int __scsi_register_driver(struct scsi_driver *, struct module *); #define scsi_unregister_driver(drv) \ - driver_unregister(drv); + driver_unregister(&(drv)->gendrv); extern int scsi_register_interface(struct class_interface *); #define scsi_unregister_interface(intf) \ From f7d4f1bf5724e52de049c619beddd53c62206624 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 19 Dec 2025 10:25:31 +0100 Subject: [PATCH 31/78] scsi: core: sysfs: Make use of bus callbacks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce a bus-specific probe, remove and shutdown function. For now this only allows to get rid of a cast of the generic device to a SCSI device in the drivers and changes the remove prototype to return void---a non-zero return value is ignored anyhow. The objective is to get rid of users of struct device_driver callbacks .probe(), .remove() and .shutdown() to eventually remove these. Until all SCSI drivers are converted, this results in a runtime warning about the drivers needing an update because there is a bus probe function and a driver probe function. The in-tree drivers are fixed by the following commits. Signed-off-by: Uwe Kleine-König Reviewed-by: Peter Wang Reviewed-by: Bart Van Assche Link: https://patch.msgid.link/a54e363a3fd2054fb924afd7df44bca7f444b5f1.1766133330.git.u.kleine-koenig@baylibre.com Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_sysfs.c | 73 ++++++++++++++++++++++++++++++++++++-- include/scsi/scsi_driver.h | 3 ++ 2 files changed, 74 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index db0ba68f2e6e..6b8c5c05f294 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -554,10 +554,48 @@ static int scsi_bus_uevent(const struct device *dev, struct kobj_uevent_env *env return 0; } +static int scsi_bus_probe(struct device *dev) +{ + struct scsi_device *sdp = to_scsi_device(dev); + struct scsi_driver *drv = to_scsi_driver(dev->driver); + + if (drv->probe) + return drv->probe(sdp); + else + return 0; +} + +static void scsi_bus_remove(struct device *dev) +{ + struct scsi_device *sdp = to_scsi_device(dev); + struct scsi_driver *drv = to_scsi_driver(dev->driver); + + if (drv->remove) + drv->remove(sdp); +} + +static void scsi_bus_shutdown(struct device *dev) +{ + struct scsi_device *sdp = to_scsi_device(dev); + struct scsi_driver *drv; + + if (!dev->driver) + return; + + drv = to_scsi_driver(dev->driver); + + if (drv->shutdown) + drv->shutdown(sdp); +} + + const struct bus_type scsi_bus_type = { - .name = "scsi", - .match = scsi_bus_match, + .name = "scsi", + .match = scsi_bus_match, .uevent = scsi_bus_uevent, + .probe = scsi_bus_probe, + .remove = scsi_bus_remove, + .shutdown = scsi_bus_shutdown, #ifdef CONFIG_PM .pm = &scsi_bus_pm_ops, #endif @@ -1554,6 +1592,30 @@ restart: } EXPORT_SYMBOL(scsi_remove_target); +static int scsi_legacy_probe(struct scsi_device *sdp) +{ + struct device *dev = &sdp->sdev_gendev; + struct device_driver *driver = dev->driver; + + return driver->probe(dev); +} + +static void scsi_legacy_remove(struct scsi_device *sdp) +{ + struct device *dev = &sdp->sdev_gendev; + struct device_driver *driver = dev->driver; + + driver->remove(dev); +} + +static void scsi_legacy_shutdown(struct scsi_device *sdp) +{ + struct device *dev = &sdp->sdev_gendev; + struct device_driver *driver = dev->driver; + + driver->shutdown(dev); +} + int __scsi_register_driver(struct scsi_driver *sdrv, struct module *owner) { struct device_driver *drv = &sdrv->gendrv; @@ -1561,6 +1623,13 @@ int __scsi_register_driver(struct scsi_driver *sdrv, struct module *owner) drv->bus = &scsi_bus_type; drv->owner = owner; + if (!sdrv->probe && drv->probe) + sdrv->probe = scsi_legacy_probe; + if (!sdrv->remove && drv->remove) + sdrv->remove = scsi_legacy_remove; + if (!sdrv->shutdown && drv->shutdown) + sdrv->shutdown = scsi_legacy_shutdown; + return driver_register(drv); } EXPORT_SYMBOL(__scsi_register_driver); diff --git a/include/scsi/scsi_driver.h b/include/scsi/scsi_driver.h index 40aba9a9349a..249cea724abd 100644 --- a/include/scsi/scsi_driver.h +++ b/include/scsi/scsi_driver.h @@ -12,6 +12,9 @@ struct request; struct scsi_driver { struct device_driver gendrv; + int (*probe)(struct scsi_device *); + void (*remove)(struct scsi_device *); + void (*shutdown)(struct scsi_device *); int (*resume)(struct device *); void (*rescan)(struct device *); blk_status_t (*init_command)(struct scsi_cmnd *); From fba333569c8a59928e9e6bb4e20cc6151daeaff8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 19 Dec 2025 10:25:32 +0100 Subject: [PATCH 32/78] scsi: ch: Convert to SCSI bus methods MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SCSI subsystem has implemented dedicated callbacks for probe, remove and shutdown. Make use of them. This fixes a runtime warning about the driver needing to be converted to the bus probe method. Signed-off-by: Uwe Kleine-König Reviewed-by: Bart Van Assche Link: https://patch.msgid.link/b36de11cbc32265a52264da5c813dd6e1abd21fd.1766133330.git.u.kleine-koenig@baylibre.com Signed-off-by: Martin K. Petersen --- drivers/scsi/ch.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index f2b63e4b9b99..b6ca23a29ef5 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c @@ -894,9 +894,9 @@ static long ch_ioctl(struct file *file, /* ------------------------------------------------------------------------ */ -static int ch_probe(struct device *dev) +static int ch_probe(struct scsi_device *sd) { - struct scsi_device *sd = to_scsi_device(dev); + struct device *dev = &sd->sdev_gendev; struct device *class_dev; int ret; scsi_changer *ch; @@ -967,8 +967,9 @@ free_ch: return ret; } -static int ch_remove(struct device *dev) +static void ch_remove(struct scsi_device *sd) { + struct device *dev = &sd->sdev_gendev; scsi_changer *ch = dev_get_drvdata(dev); spin_lock(&ch_index_lock); @@ -979,15 +980,14 @@ static int ch_remove(struct device *dev) device_destroy(&ch_sysfs_class, MKDEV(SCSI_CHANGER_MAJOR, ch->minor)); scsi_device_put(ch->device); kref_put(&ch->ref, ch_destroy); - return 0; } static struct scsi_driver ch_template = { - .gendrv = { + .probe = ch_probe, + .remove = ch_remove, + .gendrv = { .name = "ch", .owner = THIS_MODULE, - .probe = ch_probe, - .remove = ch_remove, }, }; From 63b541f054e7147f5a19fcd964677c189bad7cff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 19 Dec 2025 10:25:33 +0100 Subject: [PATCH 33/78] scsi: sd: Convert to SCSI bus methods MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SCSI subsystem has implemented dedicated callbacks for probe, remove and shutdown. Make use of them. This fixes a runtime warning about the driver needing to be converted to the bus probe method. Signed-off-by: Uwe Kleine-König Reviewed-by: Bart Van Assche Link: https://patch.msgid.link/8ad5a00c2ad2a64b81350ae3fab02fbe430f306d.1766133330.git.u.kleine-koenig@baylibre.com Signed-off-by: Martin K. Petersen --- drivers/scsi/sd.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 6ea6ee2830a4..dc7eac6211bc 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -108,7 +108,7 @@ static void sd_config_write_same(struct scsi_disk *sdkp, struct queue_limits *lim); static void sd_revalidate_disk(struct gendisk *); static void sd_unlock_native_capacity(struct gendisk *disk); -static void sd_shutdown(struct device *); +static void sd_shutdown(struct scsi_device *); static void scsi_disk_release(struct device *cdev); static DEFINE_IDA(sd_index_ida); @@ -3935,7 +3935,7 @@ static int sd_format_disk_name(char *prefix, int index, char *buf, int buflen) * sd_probe - called during driver initialization and whenever a * new scsi device is attached to the system. It is called once * for each scsi device (not just disks) present. - * @dev: pointer to device object + * @sdp: pointer to device object * * Returns 0 if successful (or not interested in this scsi device * (e.g. scanner)); 1 when there is an error. @@ -3949,9 +3949,9 @@ static int sd_format_disk_name(char *prefix, int index, char *buf, int buflen) * Assume sd_probe is not re-entrant (for time being) * Also think about sd_probe() and sd_remove() running coincidentally. **/ -static int sd_probe(struct device *dev) +static int sd_probe(struct scsi_device *sdp) { - struct scsi_device *sdp = to_scsi_device(dev); + struct device *dev = &sdp->sdev_gendev; struct scsi_disk *sdkp; struct gendisk *gd; int index; @@ -4091,15 +4091,16 @@ static int sd_probe(struct device *dev) * sd_remove - called whenever a scsi disk (previously recognized by * sd_probe) is detached from the system. It is called (potentially * multiple times) during sd module unload. - * @dev: pointer to device object + * @sdp: pointer to device object * * Note: this function is invoked from the scsi mid-level. * This function potentially frees up a device name (e.g. /dev/sdc) * that could be re-used by a subsequent sd_probe(). * This function is not called when the built-in sd driver is "exit-ed". **/ -static int sd_remove(struct device *dev) +static void sd_remove(struct scsi_device *sdp) { + struct device *dev = &sdp->sdev_gendev; struct scsi_disk *sdkp = dev_get_drvdata(dev); scsi_autopm_get_device(sdkp->device); @@ -4107,10 +4108,9 @@ static int sd_remove(struct device *dev) device_del(&sdkp->disk_dev); del_gendisk(sdkp->disk); if (!sdkp->suspended) - sd_shutdown(dev); + sd_shutdown(sdp); put_disk(sdkp->disk); - return 0; } static void scsi_disk_release(struct device *dev) @@ -4197,8 +4197,9 @@ static int sd_start_stop_device(struct scsi_disk *sdkp, int start) * the normal SCSI command structure. Wait for the command to * complete. */ -static void sd_shutdown(struct device *dev) +static void sd_shutdown(struct scsi_device *sdp) { + struct device *dev = &sdp->sdev_gendev; struct scsi_disk *sdkp = dev_get_drvdata(dev); if (!sdkp) @@ -4368,12 +4369,12 @@ static const struct dev_pm_ops sd_pm_ops = { }; static struct scsi_driver sd_template = { + .probe = sd_probe, + .remove = sd_remove, + .shutdown = sd_shutdown, .gendrv = { .name = "sd", - .probe = sd_probe, .probe_type = PROBE_PREFER_ASYNCHRONOUS, - .remove = sd_remove, - .shutdown = sd_shutdown, .pm = &sd_pm_ops, }, .rescan = sd_rescan, From a71d5deea6e95b6155ea22e5db6feb92634307b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 19 Dec 2025 10:25:34 +0100 Subject: [PATCH 34/78] scsi: ses: Convert to SCSI bus methods MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SCSI subsystem has implemented dedicated callbacks for probe, remove and shutdown. Make use of them. This fixes a runtime warning about the driver needing to be converted to the bus probe method. There is no need for an empty remove callback, no remove callback has the same semantics. So instead of converting the remove callback, drop it. Signed-off-by: Uwe Kleine-König Reviewed-by: Bart Van Assche Link: https://patch.msgid.link/7124bf21c02a116bca13940e40e97373fd776590.1766133330.git.u.kleine-koenig@baylibre.com Signed-off-by: Martin K. Petersen --- drivers/scsi/ses.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index f8f5164f3de2..789b170da652 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c @@ -42,9 +42,8 @@ static bool ses_page2_supported(struct enclosure_device *edev) return (ses_dev->page2 != NULL); } -static int ses_probe(struct device *dev) +static int ses_probe(struct scsi_device *sdev) { - struct scsi_device *sdev = to_scsi_device(dev); int err = -ENODEV; if (sdev->type != TYPE_ENCLOSURE) @@ -847,11 +846,6 @@ page2_not_supported: return err; } -static int ses_remove(struct device *dev) -{ - return 0; -} - static void ses_intf_remove_component(struct scsi_device *sdev) { struct enclosure_device *edev, *prev = NULL; @@ -906,10 +900,9 @@ static struct class_interface ses_interface = { }; static struct scsi_driver ses_template = { + .probe = ses_probe, .gendrv = { .name = "ses", - .probe = ses_probe, - .remove = ses_remove, }, }; From 9ccda35df7d5cf46649d02696278c7cd4464a16d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 19 Dec 2025 10:25:35 +0100 Subject: [PATCH 35/78] scsi: sr: Convert to SCSI bus methods MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SCSI subsystem has implemented dedicated callbacks for probe, remove and shutdown. Make use of them. This fixes a runtime warning about the driver needing to be converted to the bus probe method. Signed-off-by: Uwe Kleine-König Reviewed-by: Bart Van Assche Link: https://patch.msgid.link/ff6e8421f9efa84be3c37a11637aa435899160bf.1766133330.git.u.kleine-koenig@baylibre.com Signed-off-by: Martin K. Petersen --- drivers/scsi/sr.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 2f6bb6355186..1fb85f548955 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -82,8 +82,8 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_WORM); CDC_CD_R|CDC_CD_RW|CDC_DVD|CDC_DVD_R|CDC_DVD_RAM|CDC_GENERIC_PACKET| \ CDC_MRW|CDC_MRW_W|CDC_RAM) -static int sr_probe(struct device *); -static int sr_remove(struct device *); +static int sr_probe(struct scsi_device *); +static void sr_remove(struct scsi_device *); static blk_status_t sr_init_command(struct scsi_cmnd *SCpnt); static int sr_done(struct scsi_cmnd *); static int sr_runtime_suspend(struct device *dev); @@ -93,10 +93,10 @@ static const struct dev_pm_ops sr_pm_ops = { }; static struct scsi_driver sr_template = { + .probe = sr_probe, + .remove = sr_remove, .gendrv = { .name = "sr", - .probe = sr_probe, - .remove = sr_remove, .pm = &sr_pm_ops, }, .init_command = sr_init_command, @@ -616,9 +616,9 @@ static void sr_release(struct cdrom_device_info *cdi) { } -static int sr_probe(struct device *dev) +static int sr_probe(struct scsi_device *sdev) { - struct scsi_device *sdev = to_scsi_device(dev); + struct device *dev = &sdev->sdev_gendev; struct gendisk *disk; struct scsi_cd *cd; int minor, error; @@ -982,16 +982,15 @@ out_put_request: return ret; } -static int sr_remove(struct device *dev) +static void sr_remove(struct scsi_device *sdev) { + struct device *dev = &sdev->sdev_gendev; struct scsi_cd *cd = dev_get_drvdata(dev); scsi_autopm_get_device(cd->device); del_gendisk(cd->disk); put_disk(cd->disk); - - return 0; } static int __init init_sr(void) From 4bc2205be4609b7a224c78e12852a672cbf80d3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 19 Dec 2025 10:25:36 +0100 Subject: [PATCH 36/78] scsi: st: Convert to SCSI bus methods MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SCSI subsystem has implemented dedicated callbacks for probe, remove and shutdown. Make use of them. This fixes a runtime warning about the driver needing to be converted to the bus probe method. Signed-off-by: Uwe Kleine-König Reviewed-by: Bart Van Assche Link: https://patch.msgid.link/6da44731f77e8fdcd18e5f438643d58c98945db4.1766133330.git.u.kleine-koenig@baylibre.com Signed-off-by: Martin K. Petersen --- drivers/scsi/st.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 45622cfce926..40d88bbb4388 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -202,14 +202,14 @@ static int sgl_map_user_pages(struct st_buffer *, const unsigned int, unsigned long, size_t, int); static int sgl_unmap_user_pages(struct st_buffer *, const unsigned int, int); -static int st_probe(struct device *); -static int st_remove(struct device *); +static int st_probe(struct scsi_device *); +static void st_remove(struct scsi_device *); static struct scsi_driver st_template = { + .probe = st_probe, + .remove = st_remove, .gendrv = { .name = "st", - .probe = st_probe, - .remove = st_remove, .groups = st_drv_groups, }, }; @@ -4342,9 +4342,9 @@ static void remove_cdevs(struct scsi_tape *tape) } } -static int st_probe(struct device *dev) +static int st_probe(struct scsi_device *SDp) { - struct scsi_device *SDp = to_scsi_device(dev); + struct device *dev = &SDp->sdev_gendev; struct scsi_tape *tpnt = NULL; struct st_modedef *STm; struct st_partstat *STps; @@ -4499,12 +4499,13 @@ out: }; -static int st_remove(struct device *dev) +static void st_remove(struct scsi_device *SDp) { + struct device *dev = &SDp->sdev_gendev; struct scsi_tape *tpnt = dev_get_drvdata(dev); int index = tpnt->index; - scsi_autopm_get_device(to_scsi_device(dev)); + scsi_autopm_get_device(SDp); remove_cdevs(tpnt); mutex_lock(&st_ref_mutex); @@ -4513,7 +4514,6 @@ static int st_remove(struct device *dev) spin_lock(&st_index_lock); idr_remove(&st_index_idr, index); spin_unlock(&st_index_lock); - return 0; } /** From 44859905375ff4d739cca2113408336a90ed227d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 19 Dec 2025 10:25:37 +0100 Subject: [PATCH 37/78] scsi: ufs: core: Convert to SCSI bus methods MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SCSI subsystem has implemented dedicated callbacks for probe, remove and shutdown. Make use of them. This fixes a runtime warning about the driver needing to be converted to the bus probe method. Reviewed-by: Peter Wang Signed-off-by: Uwe Kleine-König Reviewed-by: Bart Van Assche Link: https://patch.msgid.link/69f17c7d4f8f587e2a56e3ea268d441d98a6a895.1766133330.git.u.kleine-koenig@baylibre.com Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index da1e89e95d07..78669c205568 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -10525,9 +10525,8 @@ int ufshcd_runtime_resume(struct device *dev) EXPORT_SYMBOL(ufshcd_runtime_resume); #endif /* CONFIG_PM */ -static void ufshcd_wl_shutdown(struct device *dev) +static void ufshcd_wl_shutdown(struct scsi_device *sdev) { - struct scsi_device *sdev = to_scsi_device(dev); struct ufs_hba *hba = shost_priv(sdev->host); down(&hba->host_sem); @@ -11133,9 +11132,9 @@ static int ufshcd_wl_poweroff(struct device *dev) } #endif -static int ufshcd_wl_probe(struct device *dev) +static int ufshcd_wl_probe(struct scsi_device *sdev) { - struct scsi_device *sdev = to_scsi_device(dev); + struct device *dev = &sdev->sdev_gendev; if (!is_device_wlun(sdev)) return -ENODEV; @@ -11147,10 +11146,11 @@ static int ufshcd_wl_probe(struct device *dev) return 0; } -static int ufshcd_wl_remove(struct device *dev) +static void ufshcd_wl_remove(struct scsi_device *sdev) { + struct device *dev = &sdev->sdev_gendev; + pm_runtime_forbid(dev); - return 0; } static const struct dev_pm_ops ufshcd_wl_pm_ops = { @@ -11223,12 +11223,12 @@ static void ufshcd_check_header_layout(void) * Hence register a scsi driver for ufs wluns only. */ static struct scsi_driver ufs_dev_wlun_template = { + .probe = ufshcd_wl_probe, + .remove = ufshcd_wl_remove, + .shutdown = ufshcd_wl_shutdown, .gendrv = { .name = "ufs_device_wlun", - .probe = ufshcd_wl_probe, - .remove = ufshcd_wl_remove, .pm = &ufshcd_wl_pm_ops, - .shutdown = ufshcd_wl_shutdown, }, }; From 8d0aecdebc0f3c123221e67d2f64ff0982f76cb3 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 6 Jan 2026 11:57:22 -0700 Subject: [PATCH 38/78] scsi: mpi3mr: Simplify the workqueue allocation code Let alloc_ordered_workqueue() format the workqueue name instead of calling scnprintf() explicitly. Compile-tested only. Cc: Chandrakanth Patil Signed-off-by: Bart Van Assche Link: https://patch.msgid.link/20260106185723.2526901-1-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr.h | 2 -- drivers/scsi/mpi3mr/mpi3mr_fw.c | 5 +---- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index 31d68c151b20..82f4ae87d6bc 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -1076,7 +1076,6 @@ struct scmd_priv { * @fwevt_worker_thread: Firmware event worker thread * @fwevt_lock: Firmware event lock * @fwevt_list: Firmware event list - * @watchdog_work_q_name: Fault watchdog worker thread name * @watchdog_work_q: Fault watchdog worker thread * @watchdog_work: Fault watchdog work * @watchdog_lock: Fault watchdog lock @@ -1265,7 +1264,6 @@ struct mpi3mr_ioc { spinlock_t fwevt_lock; struct list_head fwevt_list; - char watchdog_work_q_name[50]; struct workqueue_struct *watchdog_work_q; struct delayed_work watchdog_work; spinlock_t watchdog_lock; diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index 8fe6e0bf342e..b564fe5980a6 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -2878,11 +2878,8 @@ void mpi3mr_start_watchdog(struct mpi3mr_ioc *mrioc) return; INIT_DELAYED_WORK(&mrioc->watchdog_work, mpi3mr_watchdog_work); - snprintf(mrioc->watchdog_work_q_name, - sizeof(mrioc->watchdog_work_q_name), "watchdog_%s%d", mrioc->name, - mrioc->id); mrioc->watchdog_work_q = alloc_ordered_workqueue( - "%s", WQ_MEM_RECLAIM, mrioc->watchdog_work_q_name); + "watchdog_%s%d", WQ_MEM_RECLAIM, mrioc->name, mrioc->id); if (!mrioc->watchdog_work_q) { ioc_err(mrioc, "%s: failed (line=%d)\n", __func__, __LINE__); return; From bf286f5558bfade5b746646b8b94685648f4b49a Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 6 Jan 2026 11:56:54 -0700 Subject: [PATCH 39/78] scsi: mpt3sas: Simplify the workqueue allocation code Let alloc_ordered_workqueue() format the workqueue name instead of calling scnprintf() explicitly. Compile-tested only. Cc: Ranjan Kumar Signed-off-by: Bart Van Assche Link: https://patch.msgid.link/20260106185655.2526800-1-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.c | 5 +---- drivers/scsi/mpt3sas/mpt3sas_base.h | 6 ++---- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index e4e22cb0e277..2f2183f405c9 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -843,11 +843,8 @@ mpt3sas_base_start_watchdog(struct MPT3SAS_ADAPTER *ioc) /* initialize fault polling */ INIT_DELAYED_WORK(&ioc->fault_reset_work, _base_fault_reset_work); - scnprintf(ioc->fault_reset_work_q_name, - sizeof(ioc->fault_reset_work_q_name), "poll_%s%d_status", - ioc->driver_name, ioc->id); ioc->fault_reset_work_q = alloc_ordered_workqueue( - "%s", WQ_MEM_RECLAIM, ioc->fault_reset_work_q_name); + "poll_%s%d_status", WQ_MEM_RECLAIM, ioc->driver_name, ioc->id); if (!ioc->fault_reset_work_q) { ioc_err(ioc, "%s: failed (line=%d)\n", __func__, __LINE__); return; diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index de37fa5ac073..d4597d058705 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -1163,9 +1163,8 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc); * @mask_interrupts: ignore interrupt * @pci_access_mutex: Mutex to synchronize ioctl, sysfs show path and * pci resource handling - * @fault_reset_work_q_name: fw fault work queue - * @fault_reset_work_q: "" - * @fault_reset_work: "" + * @fault_reset_work_q: fw fault workqueue + * @fault_reset_work: fw fault work * @firmware_event_thread: fw event work queue * @fw_event_lock: * @fw_event_list: list of fw events @@ -1349,7 +1348,6 @@ struct MPT3SAS_ADAPTER { u8 mask_interrupts; /* fw fault handler */ - char fault_reset_work_q_name[20]; struct workqueue_struct *fault_reset_work_q; struct delayed_work fault_reset_work; From 309b23a1553acdc6b8534682ee1782c9598e0e2e Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 6 Jan 2026 12:00:17 -0700 Subject: [PATCH 40/78] scsi: ufs: core: Improve the documentation of UFS data frames In source code comments, use terminology that comes from the JEDEC UFS standard. This makes it easier to compare the UFS driver code with the JEDEC UFS standard. Add static_assert() statements that verify the size of data structures defined in the UFS standard. Signed-off-by: Bart Van Assche Link: https://patch.msgid.link/20260106190017.2527978-1-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- include/uapi/scsi/scsi_bsg_ufs.h | 17 ++++++++--------- include/ufs/ufs.h | 5 ++++- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/include/uapi/scsi/scsi_bsg_ufs.h b/include/uapi/scsi/scsi_bsg_ufs.h index 8c29e498ef98..06f88d1b1876 100644 --- a/include/uapi/scsi/scsi_bsg_ufs.h +++ b/include/uapi/scsi/scsi_bsg_ufs.h @@ -94,16 +94,15 @@ struct utp_upiu_header { }; /** - * struct utp_upiu_query - upiu request buffer structure for - * query request. - * @opcode: command to perform B-0 - * @idn: a value that indicates the particular type of data B-1 - * @index: Index to further identify data B-2 - * @selector: Index to further identify data B-3 + * struct utp_upiu_query - QUERY REQUEST UPIU structure. + * @opcode: query function to perform B-0 + * @idn: descriptor or attribute identification number B-1 + * @index: Index that further identifies which data to access B-2 + * @selector: Index that further identifies which data to access B-3 * @reserved_osf: spec reserved field B-4,5 - * @length: number of descriptor bytes to read/write B-6,7 - * @value: Attribute value to be written DW-5 - * @reserved: spec reserved DW-6,7 + * @length: number of descriptor bytes to read or write B-6,7 + * @value: if @opcode == UPIU_QUERY_OPCODE_WRITE_ATTR, the value to be written B-6,7 + * @reserved: reserved for future use DW-6,7 */ struct utp_upiu_query { __u8 opcode; diff --git a/include/ufs/ufs.h b/include/ufs/ufs.h index ab8f6c07b5a2..602aa34c9822 100644 --- a/include/ufs/ufs.h +++ b/include/ufs/ufs.h @@ -21,6 +21,7 @@ * in this header file of the size of struct utp_upiu_header. */ static_assert(sizeof(struct utp_upiu_header) == 12); +static_assert(sizeof(struct utp_upiu_query) == 20); #define GENERAL_UPIU_REQUEST_SIZE (sizeof(struct utp_upiu_req)) #define QUERY_DESC_MAX_SIZE 255 @@ -561,7 +562,7 @@ enum ufs_dev_pwr_mode { #define UFS_WB_BUF_REMAIN_PERCENT(val) ((val) / 10) /** - * struct utp_cmd_rsp - Response UPIU structure + * struct utp_cmd_rsp - RESPONSE UPIU structure * @residual_transfer_count: Residual transfer count DW-3 * @reserved: Reserved double words DW-4 to DW-7 * @sense_data_len: Sense data length DW-8 U16 @@ -574,6 +575,8 @@ struct utp_cmd_rsp { u8 sense_data[UFS_SENSE_SIZE]; }; +static_assert(sizeof(struct utp_cmd_rsp) == 40); + /** * struct utp_upiu_rsp - general upiu response structure * @header: UPIU header structure DW-0 to DW-2 From 202d5dadd3a0fada6aa756c9fdeb2062aad89f79 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 9 Jan 2026 12:51:01 -0800 Subject: [PATCH 41/78] scsi: ufs: core: Only call scsi_host_busy() after the SCSI host has been added scsi_host_busy() iterates over the host tag set. The host tag set is initialized by scsi_mq_setup_tags(). The latter function is called by scsi_add_host(). Hence only call scsi_host_busy() after the SCSI host has been added. This patch prepares for reverting commit a0b7780602b1 ("scsi: core: Fix a regression triggered by scsi_host_busy()"). Reviewed-by: John Garry Signed-off-by: Bart Van Assche Link: https://patch.msgid.link/20260109205104.496478-2-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 80c0b49f30b0..5f694f95fd86 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -283,7 +283,8 @@ static bool ufshcd_has_pending_tasks(struct ufs_hba *hba) static bool ufshcd_is_ufs_dev_busy(struct ufs_hba *hba) { - return scsi_host_busy(hba->host) || ufshcd_has_pending_tasks(hba); + return (hba->scsi_host_added && scsi_host_busy(hba->host)) || + ufshcd_has_pending_tasks(hba); } static const struct ufs_dev_quirk ufs_fixups[] = { @@ -678,7 +679,8 @@ static void ufshcd_print_host_state(struct ufs_hba *hba) dev_err(hba->dev, "UFS Host state=%d\n", hba->ufshcd_state); dev_err(hba->dev, "%d outstanding reqs, tasks=0x%lx\n", - scsi_host_busy(hba->host), hba->outstanding_tasks); + hba->scsi_host_added ? scsi_host_busy(hba->host) : 0, + hba->outstanding_tasks); dev_err(hba->dev, "saved_err=0x%x, saved_uic_err=0x%x\n", hba->saved_err, hba->saved_uic_err); dev_err(hba->dev, "Device power mode=%d, UIC link state=%d\n", From e60b579720993bd813dbfe77411ab63e721fe189 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 9 Jan 2026 12:51:02 -0800 Subject: [PATCH 42/78] scsi: core: Revert "Fix a regression triggered by scsi_host_busy()" Revert commit a0b7780602b1 ("scsi: core: Fix a regression triggered by scsi_host_busy()") because all scsi_host_busy() calls now happen after the corresponding SCSI host has been added. Signed-off-by: Bart Van Assche Reviewed-by: John Garry Link: https://patch.msgid.link/20260109205104.496478-3-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/scsi/hosts.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 1b3fbd328277..e047747d4ecf 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -626,9 +626,8 @@ int scsi_host_busy(struct Scsi_Host *shost) { int cnt = 0; - if (shost->tag_set.ops) - blk_mq_tagset_busy_iter(&shost->tag_set, - scsi_host_check_in_flight, &cnt); + blk_mq_tagset_busy_iter(&shost->tag_set, + scsi_host_check_in_flight, &cnt); return cnt; } EXPORT_SYMBOL(scsi_host_busy); From 07959ef517b853e834eadd0647d3860252af8f99 Mon Sep 17 00:00:00 2001 From: Peter Griffin Date: Fri, 9 Jan 2026 11:40:14 +0000 Subject: [PATCH 43/78] scsi: ufs: exynos: Call phy_notify_state() from hibern8 callbacks Notify the UFS phy of the hibern8 link state so that it can program the appropriate values. Signed-off-by: Peter Griffin Reviewed-by: Bart Van Assche Link: https://patch.msgid.link/20260109-ufs-exynos-phy_notify_pmstate-v3-1-7eb692e271af@linaro.org Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-exynos.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/ufs/host/ufs-exynos.c b/drivers/ufs/host/ufs-exynos.c index 70d195179eba..76fee3a79c77 100644 --- a/drivers/ufs/host/ufs-exynos.c +++ b/drivers/ufs/host/ufs-exynos.c @@ -1568,12 +1568,17 @@ static void exynos_ufs_pre_hibern8(struct ufs_hba *hba, enum uic_cmd_dme cmd) { struct exynos_ufs *ufs = ufshcd_get_variant(hba); struct exynos_ufs_uic_attr *attr = ufs->drv_data->uic_attr; + static const union phy_notify phystate = { + .ufs_state = PHY_UFS_HIBERN8_EXIT + }; if (cmd == UIC_CMD_DME_HIBER_EXIT) { if (ufs->opts & EXYNOS_UFS_OPT_BROKEN_AUTO_CLK_CTRL) exynos_ufs_disable_auto_ctrl_hcc(ufs); exynos_ufs_ungate_clks(ufs); + phy_notify_state(ufs->phy, phystate); + if (ufs->opts & EXYNOS_UFS_OPT_USE_SW_HIBERN8_TIMER) { static const unsigned int granularity_tbl[] = { 1, 4, 8, 16, 32, 100 @@ -1600,12 +1605,17 @@ static void exynos_ufs_pre_hibern8(struct ufs_hba *hba, enum uic_cmd_dme cmd) static void exynos_ufs_post_hibern8(struct ufs_hba *hba, enum uic_cmd_dme cmd) { struct exynos_ufs *ufs = ufshcd_get_variant(hba); + static const union phy_notify phystate = { + .ufs_state = PHY_UFS_HIBERN8_ENTER + }; if (cmd == UIC_CMD_DME_HIBER_ENTER) { ufs->entry_hibern8_t = ktime_get(); exynos_ufs_gate_clks(ufs); if (ufs->opts & EXYNOS_UFS_OPT_BROKEN_AUTO_CLK_CTRL) exynos_ufs_enable_auto_ctrl_hcc(ufs); + + phy_notify_state(ufs->phy, phystate); } } From 695df7ea6099aadc11fac8d510e4b7c5839508e3 Mon Sep 17 00:00:00 2001 From: Keoseong Park Date: Fri, 26 Dec 2025 13:28:25 +0900 Subject: [PATCH 44/78] scsi: ufs: core: Handle sentinel value for dHIDAvailableSize JEDEC UFS spec defines 0xFFFFFFFF for dHIDAvailableSize as indicating no valid fragmented size information. Returning the raw value can mislead userspace. Return -ENODATA instead when the value is unavailable. Signed-off-by: Keoseong Park Reviewed-by: Peter Wang Reviewed-by: Bart Van Assche Link: https://patch.msgid.link/20251226042825epcms2p6f02ba12fa97ff4a69c00f6fb9ff55603@epcms2p6 Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufs-sysfs.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/ufs/core/ufs-sysfs.c b/drivers/ufs/core/ufs-sysfs.c index b33f8656edb5..1017dd3ae5d3 100644 --- a/drivers/ufs/core/ufs-sysfs.c +++ b/drivers/ufs/core/ufs-sysfs.c @@ -1847,6 +1847,7 @@ static ssize_t defrag_trigger_store(struct device *dev, static DEVICE_ATTR_WO(defrag_trigger); +#define UFS_HID_AVAILABLE_SIZE_INVALID 0xFFFFFFFFU static ssize_t fragmented_size_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1859,6 +1860,9 @@ static ssize_t fragmented_size_show(struct device *dev, if (ret) return ret; + if (value == UFS_HID_AVAILABLE_SIZE_INVALID) + return -ENODATA; + return sysfs_emit(buf, "%u\n", value); } From 4f39a4870a59971797be86fed72423b83b6b4e00 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 14 Jan 2026 09:50:49 -0800 Subject: [PATCH 45/78] scsi: sd: Move the sd_remove() function definition Move the sd_remove() function definition such that the sd_shutdown() forward declaration can be removed. Reviewed-by: Damien Le Moal Reviewed-by: Himanshu Madhani Reviewed-by: Johannes Thumshirn Signed-off-by: Bart Van Assche Link: https://patch.msgid.link/20260114175054.4118163-2-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/scsi/sd.c | 53 +++++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index dc7eac6211bc..b30c50693372 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -108,7 +108,6 @@ static void sd_config_write_same(struct scsi_disk *sdkp, struct queue_limits *lim); static void sd_revalidate_disk(struct gendisk *); static void sd_unlock_native_capacity(struct gendisk *disk); -static void sd_shutdown(struct scsi_device *); static void scsi_disk_release(struct device *cdev); static DEFINE_IDA(sd_index_ida); @@ -4087,32 +4086,6 @@ static int sd_probe(struct scsi_device *sdp) return error; } -/** - * sd_remove - called whenever a scsi disk (previously recognized by - * sd_probe) is detached from the system. It is called (potentially - * multiple times) during sd module unload. - * @sdp: pointer to device object - * - * Note: this function is invoked from the scsi mid-level. - * This function potentially frees up a device name (e.g. /dev/sdc) - * that could be re-used by a subsequent sd_probe(). - * This function is not called when the built-in sd driver is "exit-ed". - **/ -static void sd_remove(struct scsi_device *sdp) -{ - struct device *dev = &sdp->sdev_gendev; - struct scsi_disk *sdkp = dev_get_drvdata(dev); - - scsi_autopm_get_device(sdkp->device); - - device_del(&sdkp->disk_dev); - del_gendisk(sdkp->disk); - if (!sdkp->suspended) - sd_shutdown(sdp); - - put_disk(sdkp->disk); -} - static void scsi_disk_release(struct device *dev) { struct scsi_disk *sdkp = to_scsi_disk(dev); @@ -4226,6 +4199,32 @@ static void sd_shutdown(struct scsi_device *sdp) } } +/** + * sd_remove - called whenever a scsi disk (previously recognized by + * sd_probe) is detached from the system. It is called (potentially + * multiple times) during sd module unload. + * @sdp: pointer to device object + * + * Note: this function is invoked from the scsi mid-level. + * This function potentially frees up a device name (e.g. /dev/sdc) + * that could be re-used by a subsequent sd_probe(). + * This function is not called when the built-in sd driver is "exit-ed". + **/ +static void sd_remove(struct scsi_device *sdp) +{ + struct device *dev = &sdp->sdev_gendev; + struct scsi_disk *sdkp = dev_get_drvdata(dev); + + scsi_autopm_get_device(sdkp->device); + + device_del(&sdkp->disk_dev); + del_gendisk(sdkp->disk); + if (!sdkp->suspended) + sd_shutdown(sdp); + + put_disk(sdkp->disk); +} + static inline bool sd_do_start_stop(struct scsi_device *sdev, bool runtime) { return (sdev->manage_system_start_stop && !runtime) || From c0daf4836114fcbdf64bf817cab00b75ce712945 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 14 Jan 2026 09:50:50 -0800 Subject: [PATCH 46/78] scsi: sd: Move the sd_config_discard() function definition Move the sd_config_discard() function definition such that its forward declaration can be removed. Reviewed-by: Damien Le Moal Reviewed-by: Himanshu Madhani Reviewed-by: Johannes Thumshirn Signed-off-by: Bart Van Assche Link: https://patch.msgid.link/20260114175054.4118163-3-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/scsi/sd.c | 114 +++++++++++++++++++++++----------------------- 1 file changed, 56 insertions(+), 58 deletions(-) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index b30c50693372..28444c81bf82 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -102,8 +102,6 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_ZBC); #define SD_MINORS 16 -static void sd_config_discard(struct scsi_disk *sdkp, struct queue_limits *lim, - unsigned int mode); static void sd_config_write_same(struct scsi_disk *sdkp, struct queue_limits *lim); static void sd_revalidate_disk(struct gendisk *); @@ -120,6 +118,62 @@ static const char *sd_cache_types[] = { "write back, no read (daft)" }; +static void sd_disable_discard(struct scsi_disk *sdkp) +{ + sdkp->provisioning_mode = SD_LBP_DISABLE; + blk_queue_disable_discard(sdkp->disk->queue); +} + +static void sd_config_discard(struct scsi_disk *sdkp, struct queue_limits *lim, + unsigned int mode) +{ + unsigned int logical_block_size = sdkp->device->sector_size; + unsigned int max_blocks = 0; + + lim->discard_alignment = sdkp->unmap_alignment * logical_block_size; + lim->discard_granularity = max(sdkp->physical_block_size, + sdkp->unmap_granularity * logical_block_size); + sdkp->provisioning_mode = mode; + + switch (mode) { + + case SD_LBP_FULL: + case SD_LBP_DISABLE: + break; + + case SD_LBP_UNMAP: + max_blocks = min_not_zero(sdkp->max_unmap_blocks, + (u32)SD_MAX_WS16_BLOCKS); + break; + + case SD_LBP_WS16: + if (sdkp->device->unmap_limit_for_ws) + max_blocks = sdkp->max_unmap_blocks; + else + max_blocks = sdkp->max_ws_blocks; + + max_blocks = min_not_zero(max_blocks, (u32)SD_MAX_WS16_BLOCKS); + break; + + case SD_LBP_WS10: + if (sdkp->device->unmap_limit_for_ws) + max_blocks = sdkp->max_unmap_blocks; + else + max_blocks = sdkp->max_ws_blocks; + + max_blocks = min_not_zero(max_blocks, (u32)SD_MAX_WS10_BLOCKS); + break; + + case SD_LBP_ZERO: + max_blocks = min_not_zero(sdkp->max_ws_blocks, + (u32)SD_MAX_WS10_BLOCKS); + break; + } + + lim->max_hw_discard_sectors = max_blocks * + (logical_block_size >> SECTOR_SHIFT); +} + static void sd_set_flush_flag(struct scsi_disk *sdkp, struct queue_limits *lim) { @@ -865,62 +919,6 @@ static unsigned char sd_setup_protect_cmnd(struct scsi_cmnd *scmd, return protect; } -static void sd_disable_discard(struct scsi_disk *sdkp) -{ - sdkp->provisioning_mode = SD_LBP_DISABLE; - blk_queue_disable_discard(sdkp->disk->queue); -} - -static void sd_config_discard(struct scsi_disk *sdkp, struct queue_limits *lim, - unsigned int mode) -{ - unsigned int logical_block_size = sdkp->device->sector_size; - unsigned int max_blocks = 0; - - lim->discard_alignment = sdkp->unmap_alignment * logical_block_size; - lim->discard_granularity = max(sdkp->physical_block_size, - sdkp->unmap_granularity * logical_block_size); - sdkp->provisioning_mode = mode; - - switch (mode) { - - case SD_LBP_FULL: - case SD_LBP_DISABLE: - break; - - case SD_LBP_UNMAP: - max_blocks = min_not_zero(sdkp->max_unmap_blocks, - (u32)SD_MAX_WS16_BLOCKS); - break; - - case SD_LBP_WS16: - if (sdkp->device->unmap_limit_for_ws) - max_blocks = sdkp->max_unmap_blocks; - else - max_blocks = sdkp->max_ws_blocks; - - max_blocks = min_not_zero(max_blocks, (u32)SD_MAX_WS16_BLOCKS); - break; - - case SD_LBP_WS10: - if (sdkp->device->unmap_limit_for_ws) - max_blocks = sdkp->max_unmap_blocks; - else - max_blocks = sdkp->max_ws_blocks; - - max_blocks = min_not_zero(max_blocks, (u32)SD_MAX_WS10_BLOCKS); - break; - - case SD_LBP_ZERO: - max_blocks = min_not_zero(sdkp->max_ws_blocks, - (u32)SD_MAX_WS10_BLOCKS); - break; - } - - lim->max_hw_discard_sectors = max_blocks * - (logical_block_size >> SECTOR_SHIFT); -} - static void *sd_set_special_bvec(struct request *rq, unsigned int data_len) { struct page *page; From 3899cff5056f417071c74371a4a9744225823a40 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 14 Jan 2026 09:50:51 -0800 Subject: [PATCH 47/78] scsi: sd: Move the scsi_disk_release() function definition Move the scsi_disk_release() function definition such that its forward declaration can be removed. Reviewed-by: Damien Le Moal Reviewed-by: Himanshu Madhani Reviewed-by: Johannes Thumshirn Signed-off-by: Bart Van Assche Link: https://patch.msgid.link/20260114175054.4118163-4-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/scsi/sd.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 28444c81bf82..0d07f3734257 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -106,7 +106,6 @@ static void sd_config_write_same(struct scsi_disk *sdkp, struct queue_limits *lim); static void sd_revalidate_disk(struct gendisk *); static void sd_unlock_native_capacity(struct gendisk *disk); -static void scsi_disk_release(struct device *cdev); static DEFINE_IDA(sd_index_ida); @@ -751,6 +750,17 @@ static struct attribute *sd_disk_attrs[] = { }; ATTRIBUTE_GROUPS(sd_disk); +static void scsi_disk_release(struct device *dev) +{ + struct scsi_disk *sdkp = to_scsi_disk(dev); + + ida_free(&sd_index_ida, sdkp->index); + put_device(&sdkp->device->sdev_gendev); + free_opal_dev(sdkp->opal_dev); + + kfree(sdkp); +} + static struct class sd_disk_class = { .name = "scsi_disk", .dev_release = scsi_disk_release, @@ -4084,17 +4094,6 @@ static int sd_probe(struct scsi_device *sdp) return error; } -static void scsi_disk_release(struct device *dev) -{ - struct scsi_disk *sdkp = to_scsi_disk(dev); - - ida_free(&sd_index_ida, sdkp->index); - put_device(&sdkp->device->sdev_gendev); - free_opal_dev(sdkp->opal_dev); - - kfree(sdkp); -} - static int sd_start_stop_device(struct scsi_disk *sdkp, int start) { unsigned char cmd[6] = { START_STOP }; /* START_VALID */ From 6e07e5333cc3154e042a5e7de073459765616fa7 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 14 Jan 2026 09:50:52 -0800 Subject: [PATCH 48/78] scsi: sd: Move the sd_fops definition Move the sd_fops definition such that the sd_unlock_native_capacity() forward declaration can be removed. Reviewed-by: Damien Le Moal Reviewed-by: Himanshu Madhani Reviewed-by: Johannes Thumshirn Signed-off-by: Bart Van Assche Link: https://patch.msgid.link/20260114175054.4118163-5-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/scsi/sd.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 0d07f3734257..1dae8a02c446 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -105,7 +105,6 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_ZBC); static void sd_config_write_same(struct scsi_disk *sdkp, struct queue_limits *lim); static void sd_revalidate_disk(struct gendisk *); -static void sd_unlock_native_capacity(struct gendisk *disk); static DEFINE_IDA(sd_index_ida); @@ -2184,21 +2183,6 @@ static void scsi_disk_free_disk(struct gendisk *disk) put_device(&sdkp->disk_dev); } -static const struct block_device_operations sd_fops = { - .owner = THIS_MODULE, - .open = sd_open, - .release = sd_release, - .ioctl = sd_ioctl, - .getgeo = sd_getgeo, - .compat_ioctl = blkdev_compat_ptr_ioctl, - .check_events = sd_check_events, - .unlock_native_capacity = sd_unlock_native_capacity, - .report_zones = sd_zbc_report_zones, - .get_unique_id = sd_get_unique_id, - .free_disk = scsi_disk_free_disk, - .pr_ops = &sd_pr_ops, -}; - /** * sd_eh_reset - reset error handling callback * @scmd: sd-issued command that has failed @@ -3892,6 +3876,21 @@ static void sd_unlock_native_capacity(struct gendisk *disk) sdev->host->hostt->unlock_native_capacity(sdev); } +static const struct block_device_operations sd_fops = { + .owner = THIS_MODULE, + .open = sd_open, + .release = sd_release, + .ioctl = sd_ioctl, + .getgeo = sd_getgeo, + .compat_ioctl = blkdev_compat_ptr_ioctl, + .check_events = sd_check_events, + .unlock_native_capacity = sd_unlock_native_capacity, + .report_zones = sd_zbc_report_zones, + .get_unique_id = sd_get_unique_id, + .free_disk = scsi_disk_free_disk, + .pr_ops = &sd_pr_ops, +}; + /** * sd_format_disk_name - format disk name * @prefix: name prefix - ie. "sd" for SCSI disks From cb429866a8259705e4dec104585bfba517f2ebc2 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 14 Jan 2026 09:50:53 -0800 Subject: [PATCH 49/78] scsi: sd: Do not split error messages Make it easier to find these error messages with grep. This patch has been created as follows: * Delete all occurrences of the following regular expression: "[[:blank:]]*\\*\n[[:blank:]]*" * Split long lines manually where necessary. Reviewed-by: Damien Le Moal Reviewed-by: Himanshu Madhani Reviewed-by: Johannes Thumshirn Signed-off-by: Bart Van Assche Link: https://patch.msgid.link/20260114175054.4118163-6-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/scsi/sd.c | 55 +++++++++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 31 deletions(-) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 1dae8a02c446..d76996d6cbc9 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1682,9 +1682,10 @@ static int sd_ioctl(struct block_device *bdev, blk_mode_t mode, struct scsi_device *sdp = sdkp->device; void __user *p = (void __user *)arg; int error; - - SCSI_LOG_IOCTL(1, sd_printk(KERN_INFO, sdkp, "sd_ioctl: disk=%s, " - "cmd=0x%x\n", disk->disk_name, cmd)); + + SCSI_LOG_IOCTL(1, sd_printk(KERN_INFO, sdkp, + "sd_ioctl: disk=%s, cmd=0x%x\n", + disk->disk_name, cmd)); if (bdev_is_partition(bdev) && !capable(CAP_SYS_RAWIO)) return -ENOIOCTLCMD; @@ -2593,8 +2594,8 @@ static int sd_read_protection_type(struct scsi_disk *sdkp, unsigned char *buffer type = ((buffer[12] >> 1) & 7) + 1; /* P_TYPE 0 = Type 1 */ if (type > T10_PI_TYPE3_PROTECTION) { - sd_printk(KERN_ERR, sdkp, "formatted with unsupported" \ - " protection type %u. Disabling disk!\n", + sd_printk(KERN_ERR, sdkp, + "formatted with unsupported protection type %u. Disabling disk!\n", type); sdkp->protection_type = 0; return -ENODEV; @@ -2871,8 +2872,8 @@ sd_read_capacity(struct scsi_disk *sdkp, struct queue_limits *lim, if ((sizeof(sdkp->capacity) > 4) && (sdkp->capacity > 0xffffffffULL)) { int old_sector_size = sector_size; - sd_printk(KERN_NOTICE, sdkp, "Very big device. " - "Trying to use READ CAPACITY(16).\n"); + sd_printk(KERN_NOTICE, sdkp, + "Very big device. Trying to use READ CAPACITY(16).\n"); sector_size = read_capacity_16(sdkp, sdp, lim, buffer); if (sector_size < 0) { sd_printk(KERN_NOTICE, sdkp, @@ -2898,17 +2899,17 @@ sd_read_capacity(struct scsi_disk *sdkp, struct queue_limits *lim, */ if (sdp->fix_capacity || (sdp->guess_capacity && (sdkp->capacity & 0x01))) { - sd_printk(KERN_INFO, sdkp, "Adjusting the sector count " - "from its reported value: %llu\n", - (unsigned long long) sdkp->capacity); + sd_printk(KERN_INFO, sdkp, + "Adjusting the sector count from its reported value: %llu\n", + (unsigned long long) sdkp->capacity); --sdkp->capacity; } got_data: if (sector_size == 0) { sector_size = 512; - sd_printk(KERN_NOTICE, sdkp, "Sector size 0 reported, " - "assuming 512.\n"); + sd_printk(KERN_NOTICE, sdkp, + "Sector size 0 reported, assuming 512.\n"); } if (sector_size != 512 && @@ -3113,8 +3114,9 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer) if (len < 3) goto bad_sense; else if (len > SD_BUF_SIZE) { - sd_first_printk(KERN_NOTICE, sdkp, "Truncating mode parameter " - "data from %d to %d bytes\n", len, SD_BUF_SIZE); + sd_first_printk(KERN_NOTICE, sdkp, + "Truncating mode parameter data from %d to %d bytes\n", + len, SD_BUF_SIZE); len = SD_BUF_SIZE; } if (modepage == 0x3F && sdp->use_192_bytes_for_3f) @@ -3137,8 +3139,7 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer) */ if (len - offset <= 2) { sd_first_printk(KERN_ERR, sdkp, - "Incomplete mode parameter " - "data\n"); + "Incomplete mode parameter data\n"); goto defaults; } else { modepage = page_code; @@ -3153,8 +3154,7 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer) offset += 2 + buffer[offset+1]; else { sd_first_printk(KERN_ERR, sdkp, - "Incomplete mode " - "parameter data\n"); + "Incomplete mode parameter data\n"); goto defaults; } } @@ -3617,8 +3617,7 @@ static bool sd_validate_min_xfer_size(struct scsi_disk *sdkp) if (min_xfer_bytes & (sdkp->physical_block_size - 1)) { sd_first_printk(KERN_WARNING, sdkp, - "Preferred minimum I/O size %u bytes not a " \ - "multiple of physical block size (%u bytes)\n", + "Preferred minimum I/O size %u bytes not a multiple of physical block size (%u bytes)\n", min_xfer_bytes, sdkp->physical_block_size); sdkp->min_xfer_blocks = 0; return false; @@ -3648,41 +3647,35 @@ static bool sd_validate_opt_xfer_size(struct scsi_disk *sdkp, if (sdkp->opt_xfer_blocks > dev_max) { sd_first_printk(KERN_WARNING, sdkp, - "Optimal transfer size %u logical blocks " \ - "> dev_max (%u logical blocks)\n", + "Optimal transfer size %u logical blocks > dev_max (%u logical blocks)\n", sdkp->opt_xfer_blocks, dev_max); return false; } if (sdkp->opt_xfer_blocks > SD_DEF_XFER_BLOCKS) { sd_first_printk(KERN_WARNING, sdkp, - "Optimal transfer size %u logical blocks " \ - "> sd driver limit (%u logical blocks)\n", + "Optimal transfer size %u logical blocks > sd driver limit (%u logical blocks)\n", sdkp->opt_xfer_blocks, SD_DEF_XFER_BLOCKS); return false; } if (opt_xfer_bytes < PAGE_SIZE) { sd_first_printk(KERN_WARNING, sdkp, - "Optimal transfer size %u bytes < " \ - "PAGE_SIZE (%u bytes)\n", + "Optimal transfer size %u bytes < PAGE_SIZE (%u bytes)\n", opt_xfer_bytes, (unsigned int)PAGE_SIZE); return false; } if (min_xfer_bytes && opt_xfer_bytes % min_xfer_bytes) { sd_first_printk(KERN_WARNING, sdkp, - "Optimal transfer size %u bytes not a " \ - "multiple of preferred minimum block " \ - "size (%u bytes)\n", + "Optimal transfer size %u bytes not a multiple of preferred minimum block size (%u bytes)\n", opt_xfer_bytes, min_xfer_bytes); return false; } if (opt_xfer_bytes & (sdkp->physical_block_size - 1)) { sd_first_printk(KERN_WARNING, sdkp, - "Optimal transfer size %u bytes not a " \ - "multiple of physical block size (%u bytes)\n", + "Optimal transfer size %u bytes not a multiple of physical block size (%u bytes)\n", opt_xfer_bytes, sdkp->physical_block_size); return false; } From 1bf0febfb2621d30c36af05f0f5e47e01a8bf060 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 15 Jan 2026 13:03:37 -0800 Subject: [PATCH 50/78] scsi: aha152x: Return SCSI_MLQUEUE_HOST_BUSY instead of 0x2003 .queuecommand() implementations are expected to return a SCSI_MLQUEUE_* value. Return SCSI_MLQUEUE_HOST_BUSY from aha152x_internal_queue() instead of 0x2003. This patch doesn't change any functionality since scsi_dispatch_cmd() converts all return values other than SCSI_MLQUEUE_* into SCSI_MLQUEUE_HOST_BUSY. Cc: Juergen E. Fischer Signed-off-by: Bart Van Assche Reviewed-by: John Garry Link: https://patch.msgid.link/20260115210357.2501991-2-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/scsi/aha152x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index 182aa80ec4c6..f7879c81d9cb 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -939,13 +939,13 @@ static int aha152x_internal_queue(struct scsi_cmnd *SCpnt, if (acp->phase & (resetting | check_condition)) { if (!SCpnt->host_scribble || SCSEM(SCpnt) || SCNEXT(SCpnt)) { scmd_printk(KERN_ERR, SCpnt, "cannot reuse command\n"); - return FAILED; + return SCSI_MLQUEUE_HOST_BUSY; } } else { SCpnt->host_scribble = kmalloc(sizeof(struct aha152x_scdata), GFP_ATOMIC); if(!SCpnt->host_scribble) { scmd_printk(KERN_ERR, SCpnt, "allocation failed\n"); - return FAILED; + return SCSI_MLQUEUE_HOST_BUSY; } } From a9fe8cab1283f55dbe1dd8b176e70992623e4dc2 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 15 Jan 2026 13:03:38 -0800 Subject: [PATCH 51/78] scsi: megaraid: Return SCSI_MLQUEUE_HOST_BUSY instead of 1 .queuecommand() implementations are expected to return a SCSI_MLQUEUE_* value. Return SCSI_MLQUEUE_HOST_BUSY from megaraid_queue_lck() instead of 1. This patch doesn't change any functionality since scsi_dispatch_cmd() converts all return values other than SCSI_MLQUEUE_* into SCSI_MLQUEUE_HOST_BUSY. Cc: Kashyap Desai Cc: Sumit Saxena Cc: Shivasharan S Cc: Chandrakanth patil Cc: megaraidlinux.pdl@broadcom.com Signed-off-by: Bart Van Assche Link: https://patch.msgid.link/20260115210357.2501991-3-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index a00622c0c526..54ed0ba3f48a 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -640,7 +640,7 @@ mega_build_cmd(adapter_t *adapter, struct scsi_cmnd *cmd, int *busy) } if(!(scb = mega_allocate_scb(adapter, cmd))) { - *busy = 1; + *busy = SCSI_MLQUEUE_HOST_BUSY; return NULL; } @@ -688,7 +688,7 @@ mega_build_cmd(adapter_t *adapter, struct scsi_cmnd *cmd, int *busy) /* Allocate a SCB and initialize passthru */ if(!(scb = mega_allocate_scb(adapter, cmd))) { - *busy = 1; + *busy = SCSI_MLQUEUE_HOST_BUSY; return NULL; } pthru = scb->pthru; @@ -730,7 +730,7 @@ mega_build_cmd(adapter_t *adapter, struct scsi_cmnd *cmd, int *busy) /* Allocate a SCB and initialize mailbox */ if(!(scb = mega_allocate_scb(adapter, cmd))) { - *busy = 1; + *busy = SCSI_MLQUEUE_HOST_BUSY; return NULL; } mbox = (mbox_t *)scb->raw_mbox; @@ -870,7 +870,7 @@ mega_build_cmd(adapter_t *adapter, struct scsi_cmnd *cmd, int *busy) /* Allocate a SCB and initialize mailbox */ if(!(scb = mega_allocate_scb(adapter, cmd))) { - *busy = 1; + *busy = SCSI_MLQUEUE_HOST_BUSY; return NULL; } @@ -898,7 +898,7 @@ mega_build_cmd(adapter_t *adapter, struct scsi_cmnd *cmd, int *busy) else { /* Allocate a SCB and initialize passthru */ if(!(scb = mega_allocate_scb(adapter, cmd))) { - *busy = 1; + *busy = SCSI_MLQUEUE_HOST_BUSY; return NULL; } From a784911099b1602db1074377dd2ac9c76296b5e3 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 15 Jan 2026 13:03:39 -0800 Subject: [PATCH 52/78] scsi: megaraid_sas: Return SCSI_MLQUEUE_HOST_BUSY instead of 1 .queuecommand() implementations are expected to return a SCSI_MLQUEUE_* value. Return SCSI_MLQUEUE_HOST_BUSY from megaraid_queue_command_lck() instead of 1. This patch doesn't change any functionality since scsi_dispatch_cmd() converts all return values other than SCSI_MLQUEUE_* into SCSI_MLQUEUE_HOST_BUSY. Cc: Kashyap Desai Cc: Sumit Saxena Cc: Shivasharan S Cc: Chandrakanth patil Cc: megaraidlinux.pdl@broadcom.com Signed-off-by: Bart Van Assche Link: https://patch.msgid.link/20260115210357.2501991-4-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_mbox.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c index b610cad83321..722d3b5acea3 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.c +++ b/drivers/scsi/megaraid/megaraid_mbox.c @@ -1516,7 +1516,7 @@ megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy) if (!(scb = megaraid_alloc_scb(adapter, scp))) { scp->result = (DID_ERROR << 16); - *busy = 1; + *busy = SCSI_MLQUEUE_HOST_BUSY; return NULL; } @@ -1599,7 +1599,7 @@ megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy) /* Allocate a SCB and initialize passthru */ if (!(scb = megaraid_alloc_scb(adapter, scp))) { scp->result = (DID_ERROR << 16); - *busy = 1; + *busy = SCSI_MLQUEUE_HOST_BUSY; return NULL; } @@ -1644,7 +1644,7 @@ megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy) */ if (!(scb = megaraid_alloc_scb(adapter, scp))) { scp->result = (DID_ERROR << 16); - *busy = 1; + *busy = SCSI_MLQUEUE_HOST_BUSY; return NULL; } ccb = (mbox_ccb_t *)scb->ccb; @@ -1740,7 +1740,7 @@ megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy) */ if (!(scb = megaraid_alloc_scb(adapter, scp))) { scp->result = (DID_ERROR << 16); - *busy = 1; + *busy = SCSI_MLQUEUE_HOST_BUSY; return NULL; } @@ -1808,7 +1808,7 @@ megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy) // Allocate a SCB and initialize passthru if (!(scb = megaraid_alloc_scb(adapter, scp))) { scp->result = (DID_ERROR << 16); - *busy = 1; + *busy = SCSI_MLQUEUE_HOST_BUSY; return NULL; } From 5612404d026d349278e6eb3b1ee55bd60b38ae3c Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 15 Jan 2026 13:03:40 -0800 Subject: [PATCH 53/78] scsi: qla2xxx: Declare qla2xxx_mqueuecommand() static Prevent that a later patch that modifies the qla2xxx_mqueuecommand() declaration triggers the following checkpatch warning: "externs should be avoided in .c files". Cc: Nilesh Javali Cc: GR-QLogic-Storage-Upstream@marvell.com Signed-off-by: Bart Van Assche Reviewed-by: John Garry Link: https://patch.msgid.link/20260115210357.2501991-5-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_os.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index c9aff70e7357..fb0b689cbacd 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -402,7 +402,7 @@ static int qla2x00_mem_alloc(struct qla_hw_data *, uint16_t, uint16_t, struct req_que **, struct rsp_que **); static void qla2x00_free_fw_dump(struct qla_hw_data *); static void qla2x00_mem_free(struct qla_hw_data *); -int qla2xxx_mqueuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd, +static int qla2xxx_mqueuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd, struct qla_qpair *qpair); /* -------------------------------------------------------------------------- */ @@ -981,7 +981,7 @@ qc24_fail_command: } /* For MQ supported I/O */ -int +static int qla2xxx_mqueuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd, struct qla_qpair *qpair) { From 0db3f51839fe703173966f34a4327e3a0c7cc089 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 15 Jan 2026 13:03:41 -0800 Subject: [PATCH 54/78] scsi: Change the return type of the .queuecommand() callback In clang version 21.1 and later the -Wimplicit-enum-enum-cast warning option has been introduced. This warning is enabled by default and can be used to catch .queuecommand() implementations that return another value than 0 or one of the SCSI_MLQUEUE_* constants. Hence this patch that changes the return type of the .queuecommand() implementations from 'int' into 'enum scsi_qc_status'. No functionality has been changed. Cc: Damien Le Moal Cc: John Garry Signed-off-by: Bart Van Assche Link: https://patch.msgid.link/20260115210357.2501991-6-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- Documentation/scsi/scsi_mid_low_api.rst | 3 ++- drivers/ata/libata-scsi.c | 8 +++++--- drivers/ata/libata.h | 3 ++- drivers/firewire/sbp2.c | 7 ++++--- drivers/infiniband/ulp/srp/ib_srp.c | 3 ++- drivers/message/fusion/mptfc.c | 7 ++++--- drivers/message/fusion/mptsas.c | 4 ++-- drivers/message/fusion/mptscsih.c | 3 +-- drivers/message/fusion/mptscsih.h | 2 +- drivers/message/fusion/mptspi.c | 4 ++-- drivers/s390/scsi/zfcp_scsi.c | 4 ++-- drivers/scsi/3w-9xxx.c | 2 +- drivers/scsi/3w-sas.c | 8 +++++--- drivers/scsi/3w-xxxx.c | 2 +- drivers/scsi/53c700.c | 6 +++--- drivers/scsi/BusLogic.c | 2 +- drivers/scsi/BusLogic.h | 3 ++- drivers/scsi/NCR5380.c | 4 ++-- drivers/scsi/a100u2w.c | 2 +- drivers/scsi/aacraid/linit.c | 4 ++-- drivers/scsi/advansys.c | 5 +++-- drivers/scsi/aha152x.c | 4 ++-- drivers/scsi/aha1542.c | 3 ++- drivers/scsi/aha1740.c | 2 +- drivers/scsi/aic7xxx/aic79xx_osm.c | 12 ++++++------ drivers/scsi/aic7xxx/aic7xxx_osm.c | 4 ++-- drivers/scsi/arcmsr/arcmsr_hba.c | 5 +++-- drivers/scsi/arm/acornscsi.c | 2 +- drivers/scsi/arm/fas216.c | 11 ++++++----- drivers/scsi/arm/fas216.h | 11 +++++++---- drivers/scsi/atp870u.c | 2 +- drivers/scsi/bfa/bfad_im.c | 5 +++-- drivers/scsi/bnx2fc/bnx2fc.h | 3 ++- drivers/scsi/bnx2fc/bnx2fc_io.c | 4 ++-- drivers/scsi/csiostor/csio_scsi.c | 4 ++-- drivers/scsi/dc395x.c | 2 +- drivers/scsi/esas2r/esas2r.h | 3 ++- drivers/scsi/esas2r/esas2r_main.c | 3 ++- drivers/scsi/esp_scsi.c | 2 +- drivers/scsi/fdomain.c | 3 ++- drivers/scsi/fnic/fnic.h | 3 ++- drivers/scsi/fnic/fnic_scsi.c | 3 ++- drivers/scsi/hpsa.c | 6 ++++-- drivers/scsi/hptiop.c | 2 +- drivers/scsi/ibmvscsi/ibmvfc.c | 3 ++- drivers/scsi/ibmvscsi/ibmvscsi.c | 9 +++++---- drivers/scsi/imm.c | 2 +- drivers/scsi/initio.c | 2 +- drivers/scsi/ipr.c | 4 ++-- drivers/scsi/ips.c | 4 ++-- drivers/scsi/libfc/fc_fcp.c | 3 ++- drivers/scsi/libiscsi.c | 3 ++- drivers/scsi/libsas/sas_scsi_host.c | 3 ++- drivers/scsi/lpfc/lpfc_scsi.c | 8 ++++---- drivers/scsi/mac53c94.c | 2 +- drivers/scsi/megaraid.c | 7 ++++--- drivers/scsi/megaraid.h | 6 ++++-- drivers/scsi/megaraid/megaraid_mbox.c | 13 ++++++++----- drivers/scsi/megaraid/megaraid_sas_base.c | 4 ++-- drivers/scsi/mesh.c | 2 +- drivers/scsi/mpi3mr/mpi3mr_os.c | 4 ++-- drivers/scsi/mpt3sas/mpt3sas_scsih.c | 4 ++-- drivers/scsi/mvumi.c | 4 ++-- drivers/scsi/myrb.c | 12 ++++++------ drivers/scsi/myrs.c | 4 ++-- drivers/scsi/ncr53c8xx.c | 2 +- drivers/scsi/nsp32.c | 5 +++-- drivers/scsi/pcmcia/nsp_cs.c | 2 +- drivers/scsi/pcmcia/nsp_cs.h | 3 ++- drivers/scsi/pcmcia/sym53c500_cs.c | 2 +- drivers/scsi/pmcraid.c | 4 ++-- drivers/scsi/ppa.c | 2 +- drivers/scsi/ps3rom.c | 2 +- drivers/scsi/qedf/qedf.h | 4 ++-- drivers/scsi/qedf/qedf_io.c | 4 ++-- drivers/scsi/qla1280.c | 18 ++++++++++-------- drivers/scsi/qla2xxx/qla_os.c | 13 +++++++------ drivers/scsi/qla4xxx/ql4_os.c | 6 ++++-- drivers/scsi/qlogicfas408.c | 2 +- drivers/scsi/qlogicfas408.h | 3 ++- drivers/scsi/qlogicpti.c | 2 +- drivers/scsi/scsi_debug.c | 9 +++++---- drivers/scsi/smartpqi/smartpqi_init.c | 3 ++- drivers/scsi/snic/snic.h | 3 ++- drivers/scsi/snic/snic_scsi.c | 4 ++-- drivers/scsi/stex.c | 2 +- drivers/scsi/storvsc_drv.c | 3 ++- drivers/scsi/sym53c8xx_2/sym_glue.c | 2 +- drivers/scsi/virtio_scsi.c | 4 ++-- drivers/scsi/vmw_pvscsi.c | 2 +- drivers/scsi/wd33c93.c | 2 +- drivers/scsi/wd33c93.h | 3 ++- drivers/scsi/wd719x.c | 3 ++- drivers/scsi/xen-scsifront.c | 4 ++-- drivers/target/loopback/tcm_loop.c | 3 ++- drivers/ufs/core/ufshcd.c | 7 ++++--- drivers/usb/image/microtek.c | 6 +++--- drivers/usb/storage/scsiglue.c | 2 +- drivers/usb/storage/uas.c | 2 +- include/linux/libata.h | 3 ++- include/scsi/libfc.h | 3 ++- include/scsi/libiscsi.h | 3 ++- include/scsi/libsas.h | 3 ++- include/scsi/scsi_host.h | 12 ++++++++---- 104 files changed, 255 insertions(+), 195 deletions(-) diff --git a/Documentation/scsi/scsi_mid_low_api.rst b/Documentation/scsi/scsi_mid_low_api.rst index 634f5c28a849..7f59dff43eb5 100644 --- a/Documentation/scsi/scsi_mid_low_api.rst +++ b/Documentation/scsi/scsi_mid_low_api.rst @@ -903,7 +903,8 @@ Details:: * * Defined in: LLD **/ - int queuecommand(struct Scsi_Host *shost, struct scsi_cmnd * scp) + enum scsi_qc_status queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *scp) /** diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 721d3f270c8e..2967a2900317 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -4309,7 +4309,8 @@ static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd) return NULL; } -int __ata_scsi_queuecmd(struct scsi_cmnd *scmd, struct ata_device *dev) +enum scsi_qc_status __ata_scsi_queuecmd(struct scsi_cmnd *scmd, + struct ata_device *dev) { struct ata_port *ap = dev->link->ap; u8 scsi_op = scmd->cmnd[0]; @@ -4383,12 +4384,13 @@ int __ata_scsi_queuecmd(struct scsi_cmnd *scmd, struct ata_device *dev) * Return value from __ata_scsi_queuecmd() if @cmd can be queued, * 0 otherwise. */ -int ata_scsi_queuecmd(struct Scsi_Host *shost, struct scsi_cmnd *cmd) +enum scsi_qc_status ata_scsi_queuecmd(struct Scsi_Host *shost, + struct scsi_cmnd *cmd) { struct ata_port *ap; struct ata_device *dev; struct scsi_device *scsidev = cmd->device; - int rc = 0; + enum scsi_qc_status rc = 0; unsigned long irq_flags; ap = ata_shost_to_port(shost); diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 0e7ecac73680..0e48bd1c0c20 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -164,7 +164,8 @@ extern int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, void ata_scsi_sdev_config(struct scsi_device *sdev); int ata_scsi_dev_config(struct scsi_device *sdev, struct queue_limits *lim, struct ata_device *dev); -int __ata_scsi_queuecmd(struct scsi_cmnd *scmd, struct ata_device *dev); +enum scsi_qc_status __ata_scsi_queuecmd(struct scsi_cmnd *scmd, + struct ata_device *dev); /* libata-eh.c */ extern unsigned int ata_internal_cmd_timeout(struct ata_device *dev, u8 cmd); diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c index 1a19828114cf..bb1a510b6423 100644 --- a/drivers/firewire/sbp2.c +++ b/drivers/firewire/sbp2.c @@ -1440,13 +1440,14 @@ static int sbp2_map_scatterlist(struct sbp2_command_orb *orb, /* SCSI stack integration */ -static int sbp2_scsi_queuecommand(struct Scsi_Host *shost, - struct scsi_cmnd *cmd) +static enum scsi_qc_status sbp2_scsi_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *cmd) { struct sbp2_logical_unit *lu = cmd->device->hostdata; struct fw_device *device = target_parent_device(lu->tgt); + enum scsi_qc_status retval = SCSI_MLQUEUE_HOST_BUSY; struct sbp2_command_orb *orb; - int generation, retval = SCSI_MLQUEUE_HOST_BUSY; + int generation; orb = kzalloc(sizeof(*orb), GFP_ATOMIC); if (orb == NULL) diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 23ed2fc688f0..c4291071deb9 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -2148,7 +2148,8 @@ static void srp_handle_qp_err(struct ib_cq *cq, struct ib_wc *wc, target->qp_in_error = true; } -static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd) +static enum scsi_qc_status srp_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *scmnd) { struct request *rq = scsi_cmd_to_rq(scmnd); struct srp_target_port *target = host_to_target(shost); diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index 8f587c0efd9d..cd52db6fe76c 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c @@ -97,7 +97,8 @@ static u8 mptfcInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; static int mptfc_target_alloc(struct scsi_target *starget); static int mptfc_sdev_init(struct scsi_device *sdev); -static int mptfc_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *SCpnt); +static enum scsi_qc_status mptfc_qcmd(struct Scsi_Host *shost, + struct scsi_cmnd *SCpnt); static void mptfc_target_destroy(struct scsi_target *starget); static void mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout); static void mptfc_remove(struct pci_dev *pdev); @@ -676,8 +677,8 @@ mptfc_sdev_init(struct scsi_device *sdev) return 0; } -static int -mptfc_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *SCpnt) +static enum scsi_qc_status mptfc_qcmd(struct Scsi_Host *shost, + struct scsi_cmnd *SCpnt) { struct mptfc_rport_info *ri; struct fc_rport *rport = starget_to_rport(scsi_target(SCpnt->device)); diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 185c08eab4ca..5276bdb7acc2 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -1920,8 +1920,8 @@ mptsas_sdev_init(struct scsi_device *sdev) return 0; } -static int -mptsas_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *SCpnt) +static enum scsi_qc_status mptsas_qcmd(struct Scsi_Host *shost, + struct scsi_cmnd *SCpnt) { MPT_SCSI_HOST *hd; MPT_ADAPTER *ioc; diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index 3304f8824cf7..ec6edcc4ef56 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -1309,8 +1309,7 @@ int mptscsih_show_info(struct seq_file *m, struct Scsi_Host *host) * * Returns 0. (rtn value discarded by linux scsi mid-layer) */ -int -mptscsih_qcmd(struct scsi_cmnd *SCpnt) +enum scsi_qc_status mptscsih_qcmd(struct scsi_cmnd *SCpnt) { MPT_SCSI_HOST *hd; MPT_FRAME_HDR *mf; diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h index f9678d48100c..ac3f56801c92 100644 --- a/drivers/message/fusion/mptscsih.h +++ b/drivers/message/fusion/mptscsih.h @@ -113,7 +113,7 @@ extern int mptscsih_resume(struct pci_dev *pdev); #endif extern int mptscsih_show_info(struct seq_file *, struct Scsi_Host *); extern const char * mptscsih_info(struct Scsi_Host *SChost); -extern int mptscsih_qcmd(struct scsi_cmnd *SCpnt); +extern enum scsi_qc_status mptscsih_qcmd(struct scsi_cmnd *SCpnt); extern int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, u64 lun, int ctx2abort, ulong timeout); extern void mptscsih_sdev_destroy(struct scsi_device *device); diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c index a3901fbfac4f..14707d19fbbd 100644 --- a/drivers/message/fusion/mptspi.c +++ b/drivers/message/fusion/mptspi.c @@ -774,8 +774,8 @@ static int mptspi_sdev_configure(struct scsi_device *sdev, return 0; } -static int -mptspi_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *SCpnt) +static enum scsi_qc_status mptspi_qcmd(struct Scsi_Host *shost, + struct scsi_cmnd *SCpnt) { struct _MPT_SCSI_HOST *hd = shost_priv(shost); VirtDevice *vdevice = SCpnt->device->hostdata; diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 141476ea21bb..634bd8dceedd 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -63,8 +63,8 @@ static void zfcp_scsi_command_fail(struct scsi_cmnd *scpnt, int result) scsi_done(scpnt); } -static -int zfcp_scsi_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scpnt) +static enum scsi_qc_status zfcp_scsi_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *scpnt) { struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scpnt->device); struct fc_rport *rport = starget_to_rport(scsi_target(scpnt->device)); diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index a377a6f6900a..e64a9a18ec6e 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c @@ -1746,7 +1746,7 @@ out: } /* End twa_scsi_eh_reset() */ /* This is the main scsi queue function to handle scsi opcodes */ -static int twa_scsi_queue_lck(struct scsi_cmnd *SCpnt) +static enum scsi_qc_status twa_scsi_queue_lck(struct scsi_cmnd *SCpnt) { void (*done)(struct scsi_cmnd *) = scsi_done; int request_id, retval; diff --git a/drivers/scsi/3w-sas.c b/drivers/scsi/3w-sas.c index e319be7d369c..fde12475b712 100644 --- a/drivers/scsi/3w-sas.c +++ b/drivers/scsi/3w-sas.c @@ -1453,11 +1453,13 @@ out: } /* End twl_scsi_eh_reset() */ /* This is the main scsi queue function to handle scsi opcodes */ -static int twl_scsi_queue_lck(struct scsi_cmnd *SCpnt) +static enum scsi_qc_status twl_scsi_queue_lck(struct scsi_cmnd *SCpnt) { + TW_Device_Extension *tw_dev = + (TW_Device_Extension *)SCpnt->device->host->hostdata; void (*done)(struct scsi_cmnd *) = scsi_done; - int request_id, retval; - TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata; + enum scsi_qc_status retval; + int request_id; /* If we are resetting due to timed out ioctl, report as busy */ if (test_bit(TW_IN_RESET, &tw_dev->flags)) { diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index 0306a228c702..c68678fa72c1 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -1920,7 +1920,7 @@ static int tw_scsiop_test_unit_ready_complete(TW_Device_Extension *tw_dev, int r } /* End tw_scsiop_test_unit_ready_complete() */ /* This is the main scsi queue function to handle scsi opcodes */ -static int tw_scsi_queue_lck(struct scsi_cmnd *SCpnt) +static enum scsi_qc_status tw_scsi_queue_lck(struct scsi_cmnd *SCpnt) { void (*done)(struct scsi_cmnd *) = scsi_done; unsigned char *command = SCpnt->cmnd; diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c index 71b7ac027f48..860538c6f8cb 100644 --- a/drivers/scsi/53c700.c +++ b/drivers/scsi/53c700.c @@ -152,8 +152,8 @@ MODULE_LICENSE("GPL"); /* This is the script */ #include "53c700_d.h" - -STATIC int NCR_700_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *); +STATIC enum scsi_qc_status NCR_700_queuecommand(struct Scsi_Host *h, + struct scsi_cmnd *); STATIC int NCR_700_abort(struct scsi_cmnd * SCpnt); STATIC int NCR_700_host_reset(struct scsi_cmnd * SCpnt); STATIC void NCR_700_chip_setup(struct Scsi_Host *host); @@ -1751,7 +1751,7 @@ NCR_700_intr(int irq, void *dev_id) return IRQ_RETVAL(handled); } -static int NCR_700_queuecommand_lck(struct scsi_cmnd *SCp) +static enum scsi_qc_status NCR_700_queuecommand_lck(struct scsi_cmnd *SCp) { struct NCR_700_Host_Parameters *hostdata = (struct NCR_700_Host_Parameters *)SCp->device->host->hostdata[0]; diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c index a86d780d1ba4..865fcbac8fa1 100644 --- a/drivers/scsi/BusLogic.c +++ b/drivers/scsi/BusLogic.c @@ -2877,7 +2877,7 @@ static int blogic_hostreset(struct scsi_cmnd *SCpnt) Outgoing Mailbox for execution by the associated Host Adapter. */ -static int blogic_qcmd_lck(struct scsi_cmnd *command) +static enum scsi_qc_status blogic_qcmd_lck(struct scsi_cmnd *command) { void (*comp_cb)(struct scsi_cmnd *) = scsi_done; struct blogic_adapter *adapter = diff --git a/drivers/scsi/BusLogic.h b/drivers/scsi/BusLogic.h index 79de815e33b0..24697a5bedc8 100644 --- a/drivers/scsi/BusLogic.h +++ b/drivers/scsi/BusLogic.h @@ -1272,7 +1272,8 @@ static inline void blogic_incszbucket(unsigned int *cmdsz_buckets, */ static const char *blogic_drvr_info(struct Scsi_Host *); -static int blogic_qcmd(struct Scsi_Host *h, struct scsi_cmnd *); +static enum scsi_qc_status blogic_qcmd(struct Scsi_Host *h, + struct scsi_cmnd *command); static int blogic_diskparam(struct scsi_device *, struct gendisk *, sector_t, int *); static int blogic_sdev_configure(struct scsi_device *, struct queue_limits *lim); diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index 0e10502660de..006dcf981218 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -555,8 +555,8 @@ static void complete_cmd(struct Scsi_Host *instance, * main coroutine is not running, it is restarted. */ -static int NCR5380_queue_command(struct Scsi_Host *instance, - struct scsi_cmnd *cmd) +static enum scsi_qc_status NCR5380_queue_command(struct Scsi_Host *instance, + struct scsi_cmnd *cmd) { struct NCR5380_hostdata *hostdata = shost_priv(instance); struct NCR5380_cmd *ncmd = NCR5380_to_ncmd(cmd); diff --git a/drivers/scsi/a100u2w.c b/drivers/scsi/a100u2w.c index a8979f9e30ff..4365b896f5c4 100644 --- a/drivers/scsi/a100u2w.c +++ b/drivers/scsi/a100u2w.c @@ -909,7 +909,7 @@ static int inia100_build_scb(struct orc_host * host, struct orc_scb * scb, struc * block, build the host specific scb structures and if there is room * queue the command down to the controller */ -static int inia100_queue_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status inia100_queue_lck(struct scsi_cmnd *cmd) { struct orc_scb *scb; struct orc_host *host; /* Point to Host adapter control block */ diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 82c6e7c7cdaf..ea468666159a 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -237,8 +237,8 @@ static struct aac_driver_ident aac_drivers[] = { * TODO: unify with aac_scsi_cmd(). */ -static int aac_queuecommand(struct Scsi_Host *shost, - struct scsi_cmnd *cmd) +static enum scsi_qc_status aac_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *cmd) { aac_priv(cmd)->owner = AAC_OWNER_LOWLEVEL; diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 06223b5ee6da..08bddac49757 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -8462,10 +8462,11 @@ static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp) * This function always returns 0. Command return status is saved * in the 'scp' result field. */ -static int advansys_queuecommand_lck(struct scsi_cmnd *scp) +static enum scsi_qc_status advansys_queuecommand_lck(struct scsi_cmnd *scp) { struct Scsi_Host *shost = scp->device->host; - int asc_res, result = 0; + enum scsi_qc_status result = 0; + int asc_res; ASC_STATS(shost, queuecommand); diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index f7879c81d9cb..e3ccb6bb62c0 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -924,7 +924,7 @@ static int setup_expected_interrupts(struct Scsi_Host *shpnt) /* * Queue a command and setup interrupts for a free bus. */ -static int aha152x_internal_queue(struct scsi_cmnd *SCpnt, +static enum scsi_qc_status aha152x_internal_queue(struct scsi_cmnd *SCpnt, struct completion *complete, int phase) { struct aha152x_cmd_priv *acp = aha152x_priv(SCpnt); @@ -995,7 +995,7 @@ static int aha152x_internal_queue(struct scsi_cmnd *SCpnt, * queue a command * */ -static int aha152x_queue_lck(struct scsi_cmnd *SCpnt) +static enum scsi_qc_status aha152x_queue_lck(struct scsi_cmnd *SCpnt) { return aha152x_internal_queue(SCpnt, NULL, 0); } diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c index 371e8300f029..fd766282d4a4 100644 --- a/drivers/scsi/aha1542.c +++ b/drivers/scsi/aha1542.c @@ -411,7 +411,8 @@ static irqreturn_t aha1542_interrupt(int irq, void *dev_id) } } -static int aha1542_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd) +static enum scsi_qc_status aha1542_queuecommand(struct Scsi_Host *sh, + struct scsi_cmnd *cmd) { struct aha1542_cmd *acmd = scsi_cmd_priv(cmd); struct aha1542_hostdata *aha1542 = shost_priv(sh); diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c index b234621f6b37..c435769359f2 100644 --- a/drivers/scsi/aha1740.c +++ b/drivers/scsi/aha1740.c @@ -319,7 +319,7 @@ static irqreturn_t aha1740_intr_handle(int irq, void *dev_id) return IRQ_RETVAL(handled); } -static int aha1740_queuecommand_lck(struct scsi_cmnd *SCpnt) +static enum scsi_qc_status aha1740_queuecommand_lck(struct scsi_cmnd *SCpnt) { void (*done)(struct scsi_cmnd *) = scsi_done; unchar direction; diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index c3d1b9dd24ae..c8b6dc48300a 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -359,7 +359,7 @@ static void ahd_linux_initialize_scsi_bus(struct ahd_softc *ahd); static u_int ahd_linux_user_tagdepth(struct ahd_softc *ahd, struct ahd_devinfo *devinfo); static void ahd_linux_device_queue_depth(struct scsi_device *); -static int ahd_linux_run_command(struct ahd_softc*, +static enum scsi_qc_status ahd_linux_run_command(struct ahd_softc*, struct ahd_linux_device *, struct scsi_cmnd *); static void ahd_linux_setup_tag_info_global(char *p); @@ -577,11 +577,11 @@ ahd_linux_info(struct Scsi_Host *host) /* * Queue an SCB to the controller. */ -static int ahd_linux_queue_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status ahd_linux_queue_lck(struct scsi_cmnd *cmd) { - struct ahd_softc *ahd; - struct ahd_linux_device *dev = scsi_transport_device_data(cmd->device); - int rtn = SCSI_MLQUEUE_HOST_BUSY; + struct ahd_linux_device *dev = scsi_transport_device_data(cmd->device); + enum scsi_qc_status rtn = SCSI_MLQUEUE_HOST_BUSY; + struct ahd_softc *ahd; ahd = *(struct ahd_softc **)cmd->device->host->hostdata; @@ -1535,7 +1535,7 @@ ahd_linux_device_queue_depth(struct scsi_device *sdev) } } -static int +static enum scsi_qc_status ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev, struct scsi_cmnd *cmd) { diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index 8b2b98666d61..c71f80f8fa34 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -519,11 +519,11 @@ ahc_linux_info(struct Scsi_Host *host) /* * Queue an SCB to the controller. */ -static int ahc_linux_queue_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status ahc_linux_queue_lck(struct scsi_cmnd *cmd) { struct ahc_softc *ahc; struct ahc_linux_device *dev = scsi_transport_device_data(cmd->device); - int rtn = SCSI_MLQUEUE_HOST_BUSY; + enum scsi_qc_status rtn = SCSI_MLQUEUE_HOST_BUSY; unsigned long flags; ahc = *(struct ahc_softc **)cmd->device->host->hostdata; diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index f0c5a30ce51b..8aa948f06cac 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -113,7 +113,8 @@ static int arcmsr_abort(struct scsi_cmnd *); static int arcmsr_bus_reset(struct scsi_cmnd *); static int arcmsr_bios_param(struct scsi_device *sdev, struct gendisk *disk, sector_t capacity, int *info); -static int arcmsr_queue_command(struct Scsi_Host *h, struct scsi_cmnd *cmd); +static enum scsi_qc_status arcmsr_queue_command(struct Scsi_Host *h, + struct scsi_cmnd *cmd); static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id); static int __maybe_unused arcmsr_suspend(struct device *dev); @@ -3312,7 +3313,7 @@ static void arcmsr_handle_virtual_command(struct AdapterControlBlock *acb, } } -static int arcmsr_queue_command_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status arcmsr_queue_command_lck(struct scsi_cmnd *cmd) { struct Scsi_Host *host = cmd->device->host; struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c index ef21b85cf014..79d7d7336b6a 100644 --- a/drivers/scsi/arm/acornscsi.c +++ b/drivers/scsi/arm/acornscsi.c @@ -2408,7 +2408,7 @@ acornscsi_intr(int irq, void *dev_id) * Params : cmd - SCSI command * Returns : 0, or < 0 on error. */ -static int acornscsi_queuecmd_lck(struct scsi_cmnd *SCpnt) +static enum scsi_qc_status acornscsi_queuecmd_lck(struct scsi_cmnd *SCpnt) { struct scsi_pointer *scsi_pointer = arm_scsi_pointer(SCpnt); void (*done)(struct scsi_cmnd *) = scsi_done; diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c index b1a749ab18f8..fccfacaaf1d5 100644 --- a/drivers/scsi/arm/fas216.c +++ b/drivers/scsi/arm/fas216.c @@ -2202,11 +2202,12 @@ no_command: * Returns: 0 on success, else error. * Notes: io_request_lock is held, interrupts are disabled. */ -static int fas216_queue_command_internal(struct scsi_cmnd *SCpnt, - void (*done)(struct scsi_cmnd *)) +static enum scsi_qc_status +fas216_queue_command_internal(struct scsi_cmnd *SCpnt, + void (*done)(struct scsi_cmnd *)) { FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata; - int result; + enum scsi_qc_status result; fas216_checkmagic(info); @@ -2243,7 +2244,7 @@ static int fas216_queue_command_internal(struct scsi_cmnd *SCpnt, return result; } -static int fas216_queue_command_lck(struct scsi_cmnd *SCpnt) +static enum scsi_qc_status fas216_queue_command_lck(struct scsi_cmnd *SCpnt) { return fas216_queue_command_internal(SCpnt, scsi_done); } @@ -2273,7 +2274,7 @@ static void fas216_internal_done(struct scsi_cmnd *SCpnt) * Returns: scsi result code. * Notes: io_request_lock is held, interrupts are disabled. */ -static int fas216_noqueue_command_lck(struct scsi_cmnd *SCpnt) +static enum scsi_qc_status fas216_noqueue_command_lck(struct scsi_cmnd *SCpnt) { FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata; diff --git a/drivers/scsi/arm/fas216.h b/drivers/scsi/arm/fas216.h index 08113277a2a9..29f710f9cb51 100644 --- a/drivers/scsi/arm/fas216.h +++ b/drivers/scsi/arm/fas216.h @@ -338,21 +338,24 @@ extern int fas216_init (struct Scsi_Host *instance); */ extern int fas216_add (struct Scsi_Host *instance, struct device *dev); -/* Function: int fas216_queue_command(struct Scsi_Host *h, struct scsi_cmnd *SCpnt) +/* Function: enum scsi_qc_status fas216_queue_command(struct Scsi_Host *h, struct scsi_cmnd *SCpnt) * Purpose : queue a command for adapter to process. * Params : h - host adapter * : SCpnt - Command to queue * Returns : 0 - success, else error */ -extern int fas216_queue_command(struct Scsi_Host *h, struct scsi_cmnd *SCpnt); +extern enum scsi_qc_status fas216_queue_command(struct Scsi_Host *h, + struct scsi_cmnd *SCpnt); -/* Function: int fas216_noqueue_command(struct Scsi_Host *h, struct scsi_cmnd *SCpnt) +/* Function: enum scsi_qc_status fas216_noqueue_command(struct Scsi_Host *h, + * struct scsi_cmnd *SCpnt) * Purpose : queue a command for adapter to process, and process it to completion. * Params : h - host adapter * : SCpnt - Command to queue * Returns : 0 - success, else error */ -extern int fas216_noqueue_command(struct Scsi_Host *, struct scsi_cmnd *); +extern enum scsi_qc_status fas216_noqueue_command(struct Scsi_Host *h, + struct scsi_cmnd *SCpnt); /* Function: irqreturn_t fas216_intr (FAS216_Info *info) * Purpose : handle interrupts from the interface to progress a command diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c index df6f40b51deb..67459d81f479 100644 --- a/drivers/scsi/atp870u.c +++ b/drivers/scsi/atp870u.c @@ -617,7 +617,7 @@ static irqreturn_t atp870u_intr_handle(int irq, void *dev_id) * * Queue a command to the ATP queue. Called with the host lock held. */ -static int atp870u_queuecommand_lck(struct scsi_cmnd *req_p) +static enum scsi_qc_status atp870u_queuecommand_lck(struct scsi_cmnd *req_p) { void (*done)(struct scsi_cmnd *) = scsi_done; unsigned char c; diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c index f56e008ee52b..6c84982c4726 100644 --- a/drivers/scsi/bfa/bfad_im.c +++ b/drivers/scsi/bfa/bfad_im.c @@ -24,7 +24,8 @@ DEFINE_IDR(bfad_im_port_index); struct scsi_transport_template *bfad_im_scsi_transport_template; struct scsi_transport_template *bfad_im_scsi_vport_transport_template; static void bfad_im_itnim_work_handler(struct work_struct *work); -static int bfad_im_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *cmnd); +static enum scsi_qc_status bfad_im_queuecommand(struct Scsi_Host *h, + struct scsi_cmnd *cmnd); static int bfad_im_sdev_init(struct scsi_device *sdev); static void bfad_im_fc_rport_add(struct bfad_im_port_s *im_port, struct bfad_itnim_s *itnim); @@ -1199,7 +1200,7 @@ bfad_im_itnim_work_handler(struct work_struct *work) /* * Scsi_Host template entry, queue a SCSI command to the BFAD. */ -static int bfad_im_queuecommand_lck(struct scsi_cmnd *cmnd) +static enum scsi_qc_status bfad_im_queuecommand_lck(struct scsi_cmnd *cmnd) { void (*done)(struct scsi_cmnd *) = scsi_done; struct bfad_im_port_s *im_port = diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h index 6d47a4d8eed6..8c8968ec8cb4 100644 --- a/drivers/scsi/bnx2fc/bnx2fc.h +++ b/drivers/scsi/bnx2fc/bnx2fc.h @@ -498,7 +498,8 @@ static inline struct bnx2fc_priv *bnx2fc_priv(struct scsi_cmnd *cmd) struct bnx2fc_cmd *bnx2fc_cmd_alloc(struct bnx2fc_rport *tgt); struct bnx2fc_cmd *bnx2fc_elstm_alloc(struct bnx2fc_rport *tgt, int type); void bnx2fc_cmd_release(struct kref *ref); -int bnx2fc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc_cmd); +enum scsi_qc_status bnx2fc_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *sc_cmd); int bnx2fc_send_fw_fcoe_init_msg(struct bnx2fc_hba *hba); int bnx2fc_send_fw_fcoe_destroy_msg(struct bnx2fc_hba *hba); int bnx2fc_send_session_ofld_req(struct fcoe_port *port, diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c index 33057908f147..90b2b54c549a 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_io.c +++ b/drivers/scsi/bnx2fc/bnx2fc_io.c @@ -1836,8 +1836,8 @@ static void bnx2fc_parse_fcp_rsp(struct bnx2fc_cmd *io_req, * * This is the IO strategy routine, called by SCSI-ML **/ -int bnx2fc_queuecommand(struct Scsi_Host *host, - struct scsi_cmnd *sc_cmd) +enum scsi_qc_status bnx2fc_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *sc_cmd) { struct fc_lport *lport = shost_priv(host); struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device)); diff --git a/drivers/scsi/csiostor/csio_scsi.c b/drivers/scsi/csiostor/csio_scsi.c index 34bde6650fae..c29bf2807e31 100644 --- a/drivers/scsi/csiostor/csio_scsi.c +++ b/drivers/scsi/csiostor/csio_scsi.c @@ -1775,8 +1775,8 @@ csio_scsi_cbfn(struct csio_hw *hw, struct csio_ioreq *req) * - Kicks off the SCSI state machine for this IO. * - Returns busy status on error. */ -static int -csio_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmnd) +static enum scsi_qc_status csio_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *cmnd) { struct csio_lnode *ln = shost_priv(host); struct csio_hw *hw = csio_lnode_to_hw(ln); diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index 386c8359e1cc..9dc499c89d3e 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -873,7 +873,7 @@ static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb, * and is expected to be held on return. * */ -static int dc395x_queue_command_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status dc395x_queue_command_lck(struct scsi_cmnd *cmd) { void (*done)(struct scsi_cmnd *) = scsi_done; struct DeviceCtlBlk *dcb; diff --git a/drivers/scsi/esas2r/esas2r.h b/drivers/scsi/esas2r/esas2r.h index c48275d53aef..a763edd05fe4 100644 --- a/drivers/scsi/esas2r/esas2r.h +++ b/drivers/scsi/esas2r/esas2r.h @@ -968,7 +968,8 @@ int esas2r_ioctl_handler(void *hostdata, unsigned int cmd, void __user *arg); int esas2r_ioctl(struct scsi_device *dev, unsigned int cmd, void __user *arg); u8 handle_hba_ioctl(struct esas2r_adapter *a, struct atto_ioctl *ioctl_hba); -int esas2r_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd); +enum scsi_qc_status esas2r_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *cmd); int esas2r_show_info(struct seq_file *m, struct Scsi_Host *sh); long esas2r_proc_ioctl(struct file *fp, unsigned int cmd, unsigned long arg); diff --git a/drivers/scsi/esas2r/esas2r_main.c b/drivers/scsi/esas2r/esas2r_main.c index be6bf518eb7c..fdcffc871d19 100644 --- a/drivers/scsi/esas2r/esas2r_main.c +++ b/drivers/scsi/esas2r/esas2r_main.c @@ -818,7 +818,8 @@ static u32 get_physaddr_from_sgc(struct esas2r_sg_context *sgc, u64 *addr) return len; } -int esas2r_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) +enum scsi_qc_status esas2r_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *cmd) { struct esas2r_adapter *a = (struct esas2r_adapter *)cmd->device->host->hostdata; diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c index 802718ffad84..05647ccc3c8a 100644 --- a/drivers/scsi/esp_scsi.c +++ b/drivers/scsi/esp_scsi.c @@ -952,7 +952,7 @@ static void esp_event_queue_full(struct esp *esp, struct esp_cmd_entry *ent) scsi_track_queue_full(dev, lp->num_tagged - 1); } -static int esp_queuecommand_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status esp_queuecommand_lck(struct scsi_cmnd *cmd) { struct scsi_device *dev = cmd->device; struct esp *esp = shost_priv(dev->host); diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c index c0b2a980db34..22fbb0222f07 100644 --- a/drivers/scsi/fdomain.c +++ b/drivers/scsi/fdomain.c @@ -402,7 +402,8 @@ static irqreturn_t fdomain_irq(int irq, void *dev_id) return IRQ_HANDLED; } -static int fdomain_queue(struct Scsi_Host *sh, struct scsi_cmnd *cmd) +static enum scsi_qc_status fdomain_queue(struct Scsi_Host *sh, + struct scsi_cmnd *cmd) { struct scsi_pointer *scsi_pointer = fdomain_scsi_pointer(cmd); struct fdomain *fd = shost_priv(cmd->device->host); diff --git a/drivers/scsi/fnic/fnic.h b/drivers/scsi/fnic/fnic.h index 1199d701c3f5..42237eb3222f 100644 --- a/drivers/scsi/fnic/fnic.h +++ b/drivers/scsi/fnic/fnic.h @@ -503,7 +503,8 @@ void fnic_free_rq_buf(struct vnic_rq *rq, struct vnic_rq_buf *buf); void fnic_flush_tx(struct work_struct *work); void fnic_update_mac_locked(struct fnic *, u8 *new); -int fnic_queuecommand(struct Scsi_Host *, struct scsi_cmnd *); +enum scsi_qc_status fnic_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *sc); int fnic_abort_cmd(struct scsi_cmnd *); int fnic_device_reset(struct scsi_cmnd *); int fnic_eh_host_reset_handler(struct scsi_cmnd *sc); diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c index 75b29a018d1f..29d7aca06958 100644 --- a/drivers/scsi/fnic/fnic_scsi.c +++ b/drivers/scsi/fnic/fnic_scsi.c @@ -454,7 +454,8 @@ static inline int fnic_queue_wq_copy_desc(struct fnic *fnic, return 0; } -int fnic_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *sc) +enum scsi_qc_status fnic_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *sc) { struct request *const rq = scsi_cmd_to_rq(sc); uint32_t mqtag = 0; diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 3654b12c5d5a..3e235dbfb67a 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -276,7 +276,8 @@ static void hpsa_free_cmd_pool(struct ctlr_info *h); #define VPD_PAGE (1 << 8) #define HPSA_SIMPLE_ERROR_BITS 0x03 -static int hpsa_scsi_queue_command(struct Scsi_Host *h, struct scsi_cmnd *cmd); +static enum scsi_qc_status hpsa_scsi_queue_command(struct Scsi_Host *h, + struct scsi_cmnd *cmd); static void hpsa_scan_start(struct Scsi_Host *); static int hpsa_scan_finished(struct Scsi_Host *sh, unsigned long elapsed_time); @@ -5667,7 +5668,8 @@ static void hpsa_command_resubmit_worker(struct work_struct *work) } /* Running in struct Scsi_Host->host_lock less mode */ -static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) +static enum scsi_qc_status hpsa_scsi_queue_command(struct Scsi_Host *sh, + struct scsi_cmnd *cmd) { struct ctlr_info *h; struct hpsa_scsi_dev_t *dev; diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c index 21f1d9871a33..7083c14c5302 100644 --- a/drivers/scsi/hptiop.c +++ b/drivers/scsi/hptiop.c @@ -993,7 +993,7 @@ static int hptiop_reset_comm_mvfrey(struct hptiop_hba *hba) return 0; } -static int hptiop_queuecommand_lck(struct scsi_cmnd *scp) +static enum scsi_qc_status hptiop_queuecommand_lck(struct scsi_cmnd *scp) { struct Scsi_Host *host = scp->device->host; struct hptiop_hba *hba = (struct hptiop_hba *)host->hostdata; diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index 228daffb286d..1c370d11b6dd 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -1960,7 +1960,8 @@ static struct ibmvfc_cmd *ibmvfc_init_vfc_cmd(struct ibmvfc_event *evt, struct s * Returns: * 0 on success / other on failure **/ -static int ibmvfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) +static enum scsi_qc_status ibmvfc_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *cmnd) { struct ibmvfc_host *vhost = shost_priv(shost); struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device)); diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 3d65a498b701..200debd6f7e8 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -868,9 +868,10 @@ static void ibmvscsi_timeout(struct timer_list *t) * Returns the value returned from ibmvscsi_send_crq(). (Zero for success) * Note that this routine assumes that host_lock is held for synchronization */ -static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, - struct ibmvscsi_host_data *hostdata, - unsigned long timeout) +static enum scsi_qc_status +ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, + struct ibmvscsi_host_data *hostdata, + unsigned long timeout) { __be64 *crq_as_u64 = (__be64 *)&evt_struct->crq; int request_status = 0; @@ -1040,7 +1041,7 @@ static inline u16 lun_from_dev(struct scsi_device *dev) * @cmnd: struct scsi_cmnd to be executed * @done: Callback function to be called when cmd is completed */ -static int ibmvscsi_queuecommand_lck(struct scsi_cmnd *cmnd) +static enum scsi_qc_status ibmvscsi_queuecommand_lck(struct scsi_cmnd *cmnd) { void (*done)(struct scsi_cmnd *) = scsi_done; struct srp_cmd *srp_cmd; diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c index 45b0e33293a5..da7aaac10a73 100644 --- a/drivers/scsi/imm.c +++ b/drivers/scsi/imm.c @@ -925,7 +925,7 @@ static int imm_engine(imm_struct *dev, struct scsi_cmnd *const cmd) return 0; } -static int imm_queuecommand_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status imm_queuecommand_lck(struct scsi_cmnd *cmd) { imm_struct *dev = imm_dev(cmd->device->host); diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c index ed34ad92c807..06fbe85dccfa 100644 --- a/drivers/scsi/initio.c +++ b/drivers/scsi/initio.c @@ -2606,7 +2606,7 @@ static void initio_build_scb(struct initio_host * host, struct scsi_ctrl_blk * c * zero if successful or indicate a host busy condition if not (which * will cause the mid layer to call us again later with the command) */ -static int i91u_queuecommand_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status i91u_queuecommand_lck(struct scsi_cmnd *cmd) { struct initio_host *host = (struct initio_host *) cmd->device->host->hostdata; struct scsi_ctrl_blk *cmnd; diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index dbd58a7e7bc1..c0487ce38d8d 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -6242,8 +6242,8 @@ static void ipr_scsi_done(struct ipr_cmnd *ipr_cmd) * SCSI_MLQUEUE_DEVICE_BUSY if device is busy * SCSI_MLQUEUE_HOST_BUSY if host is busy **/ -static int ipr_queuecommand(struct Scsi_Host *shost, - struct scsi_cmnd *scsi_cmd) +static enum scsi_qc_status ipr_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *scsi_cmd) { struct ipr_ioa_cfg *ioa_cfg; struct ipr_resource_entry *res; diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c index 3393a288fd23..e2dce28a11c6 100644 --- a/drivers/scsi/ips.c +++ b/drivers/scsi/ips.c @@ -230,7 +230,7 @@ module_param(ips, charp, 0); */ static int ips_eh_abort(struct scsi_cmnd *); static int ips_eh_reset(struct scsi_cmnd *); -static int ips_queue(struct Scsi_Host *, struct scsi_cmnd *); +static enum scsi_qc_status ips_queue(struct Scsi_Host *, struct scsi_cmnd *); static const char *ips_info(struct Scsi_Host *); static irqreturn_t do_ipsintr(int, void *); static int ips_hainit(ips_ha_t *); @@ -1017,7 +1017,7 @@ static int ips_eh_reset(struct scsi_cmnd *SC) /* Linux obtains io_request_lock before calling this function */ /* */ /****************************************************************************/ -static int ips_queue_lck(struct scsi_cmnd *SC) +static enum scsi_qc_status ips_queue_lck(struct scsi_cmnd *SC) { void (*done)(struct scsi_cmnd *) = scsi_done; ips_ha_t *ha; diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index 31d08c115521..2f93f6c65a86 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -1854,7 +1854,8 @@ static inline int fc_fcp_lport_queue_ready(struct fc_lport *lport) * * This is the i/o strategy routine, called by the SCSI layer. */ -int fc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *sc_cmd) +enum scsi_qc_status fc_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *sc_cmd) { struct fc_lport *lport = shost_priv(shost); struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device)); diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index c9f410c50978..25857d6ed6e8 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1747,7 +1747,8 @@ enum { FAILURE_SESSION_NOT_READY, }; -int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc) +enum scsi_qc_status iscsi_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *sc) { struct iscsi_cls_session *cls_session; struct iscsi_host *ihost; diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index ffa5b49aaf08..58ee74562332 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -157,7 +157,8 @@ static struct sas_task *sas_create_task(struct scsi_cmnd *cmd, return task; } -int sas_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) +enum scsi_qc_status sas_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *cmd) { struct sas_internal *i = to_sas_internal(host->transportt); struct domain_device *dev = cmd_to_domain_dev(cmd); diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 6d9d8c196936..df64948e55ee 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -5233,8 +5233,8 @@ static char *lpfc_is_command_vm_io(struct scsi_cmnd *cmd) * 0 - Success * SCSI_MLQUEUE_HOST_BUSY - Block all devices served by this host temporarily. **/ -static int -lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) +static enum scsi_qc_status lpfc_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *cmnd) { struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; @@ -6743,8 +6743,8 @@ lpfc_disable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, return false; } -static int -lpfc_no_command(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) +static enum scsi_qc_status lpfc_no_command(struct Scsi_Host *shost, + struct scsi_cmnd *cmnd) { return SCSI_MLQUEUE_HOST_BUSY; } diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c index 377dcab32cd8..49f856be2e51 100644 --- a/drivers/scsi/mac53c94.c +++ b/drivers/scsi/mac53c94.c @@ -66,7 +66,7 @@ static irqreturn_t do_mac53c94_interrupt(int, void *); static void cmd_done(struct fsc_state *, int result); static void set_dma_cmds(struct fsc_state *, struct scsi_cmnd *); -static int mac53c94_queue_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status mac53c94_queue_lck(struct scsi_cmnd *cmd) { struct fsc_state *state; diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 54ed0ba3f48a..6b088bb049cc 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -372,11 +372,11 @@ mega_runpendq(adapter_t *adapter) * * The command queuing entry point for the mid-layer. */ -static int megaraid_queue_lck(struct scsi_cmnd *scmd) +static enum scsi_qc_status megaraid_queue_lck(struct scsi_cmnd *scmd) { adapter_t *adapter; scb_t *scb; - int busy=0; + enum scsi_qc_status busy = 0; unsigned long flags; adapter = (adapter_t *)scmd->device->host->hostdata; @@ -518,7 +518,8 @@ mega_get_ldrv_num(adapter_t *adapter, struct scsi_cmnd *cmd, int channel) * boot settings. */ static scb_t * -mega_build_cmd(adapter_t *adapter, struct scsi_cmnd *cmd, int *busy) +mega_build_cmd(adapter_t *adapter, struct scsi_cmnd *cmd, + enum scsi_qc_status *busy) { mega_passthru *pthru; scb_t *scb; diff --git a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h index d6bfd26a8843..ecbaa0a0ab51 100644 --- a/drivers/scsi/megaraid.h +++ b/drivers/scsi/megaraid.h @@ -962,8 +962,10 @@ static int mega_query_adapter(adapter_t *); static int issue_scb(adapter_t *, scb_t *); static int mega_setup_mailbox(adapter_t *); -static int megaraid_queue (struct Scsi_Host *, struct scsi_cmnd *); -static scb_t * mega_build_cmd(adapter_t *, struct scsi_cmnd *, int *); +static enum scsi_qc_status megaraid_queue(struct Scsi_Host *, + struct scsi_cmnd *); +static scb_t *mega_build_cmd(adapter_t *, struct scsi_cmnd *, + enum scsi_qc_status *); static void __mega_runpendq(adapter_t *); static int issue_scb_block(adapter_t *, u_char *); diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c index 722d3b5acea3..b6a32bb0bd19 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.c +++ b/drivers/scsi/megaraid/megaraid_mbox.c @@ -109,8 +109,10 @@ static int megaraid_mbox_fire_sync_cmd(adapter_t *); static void megaraid_mbox_display_scb(adapter_t *, scb_t *); static void megaraid_mbox_setup_device_map(adapter_t *); -static int megaraid_queue_command(struct Scsi_Host *, struct scsi_cmnd *); -static scb_t *megaraid_mbox_build_cmd(adapter_t *, struct scsi_cmnd *, int *); +static enum scsi_qc_status megaraid_queue_command(struct Scsi_Host *, + struct scsi_cmnd *); +static scb_t *megaraid_mbox_build_cmd(adapter_t *, struct scsi_cmnd *, + enum scsi_qc_status *); static void megaraid_mbox_runpendq(adapter_t *, scb_t *); static void megaraid_mbox_prepare_pthru(adapter_t *, scb_t *, struct scsi_cmnd *); @@ -1434,12 +1436,12 @@ mbox_post_cmd(adapter_t *adapter, scb_t *scb) * * Queue entry point for mailbox based controllers. */ -static int megaraid_queue_command_lck(struct scsi_cmnd *scp) +static enum scsi_qc_status megaraid_queue_command_lck(struct scsi_cmnd *scp) { void (*done)(struct scsi_cmnd *) = scsi_done; adapter_t *adapter; scb_t *scb; - int if_busy; + enum scsi_qc_status if_busy; adapter = SCP2ADAPTER(scp); scp->result = 0; @@ -1477,7 +1479,8 @@ static DEF_SCSI_QCMD(megaraid_queue_command) * firmware. We also complete certain commands without sending them to firmware. */ static scb_t * -megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy) +megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, + enum scsi_qc_status *busy) { mraid_device_t *rdev = ADAP2RAIDDEV(adapter); int channel; diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index abbbc4b36cd1..52894e892a92 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -1781,8 +1781,8 @@ out_return_cmd: * @shost: adapter SCSI host * @scmd: SCSI command to be queued */ -static int -megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd) +static enum scsi_qc_status megasas_queue_command(struct Scsi_Host *shost, + struct scsi_cmnd *scmd) { struct megasas_instance *instance; struct MR_PRIV_DEVICE *mr_device_priv_data; diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c index 768b85eecc8f..dc1402b321da 100644 --- a/drivers/scsi/mesh.c +++ b/drivers/scsi/mesh.c @@ -1625,7 +1625,7 @@ static void cmd_complete(struct mesh_state *ms) * Called by midlayer with host locked to queue a new * request */ -static int mesh_queue_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status mesh_queue_lck(struct scsi_cmnd *cmd) { struct mesh_state *ms; diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index d4ca878d0886..7212459d5c4a 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -5029,8 +5029,8 @@ inline bool mpi3mr_allow_scmd_to_fw(struct scsi_cmnd *scmd) * SCSI_MLQUEUE_DEVICE_BUSY when the device is busy. * SCSI_MLQUEUE_HOST_BUSY when the host queue is full. */ -static int mpi3mr_qcmd(struct Scsi_Host *shost, - struct scsi_cmnd *scmd) +static enum scsi_qc_status mpi3mr_qcmd(struct Scsi_Host *shost, + struct scsi_cmnd *scmd) { struct mpi3mr_ioc *mrioc = shost_priv(shost); struct mpi3mr_stgt_priv_data *stgt_priv_data; diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index ac69a5abe2e2..26a13b622c95 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -5422,8 +5422,8 @@ _scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status) * SCSI_MLQUEUE_DEVICE_BUSY if the device queue is full, or * SCSI_MLQUEUE_HOST_BUSY if the entire host queue is full */ -static int -scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd) +static enum scsi_qc_status scsih_qcmd(struct Scsi_Host *shost, + struct scsi_cmnd *scmd) { struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); struct MPT3SAS_DEVICE *sas_device_priv_data; diff --git a/drivers/scsi/mvumi.c b/drivers/scsi/mvumi.c index bdc2f2f17753..cda8bd083a38 100644 --- a/drivers/scsi/mvumi.c +++ b/drivers/scsi/mvumi.c @@ -2077,8 +2077,8 @@ error: * @shost: Scsi host to queue command on * @scmd: SCSI command to be queued */ -static int mvumi_queue_command(struct Scsi_Host *shost, - struct scsi_cmnd *scmd) +static enum scsi_qc_status mvumi_queue_command(struct Scsi_Host *shost, + struct scsi_cmnd *scmd) { struct mvumi_cmd *cmd; struct mvumi_hba *mhba; diff --git a/drivers/scsi/myrb.c b/drivers/scsi/myrb.c index b8453c0333dc..efeacb9ffd7c 100644 --- a/drivers/scsi/myrb.c +++ b/drivers/scsi/myrb.c @@ -1260,8 +1260,8 @@ static int myrb_host_reset(struct scsi_cmnd *scmd) return SUCCESS; } -static int myrb_pthru_queuecommand(struct Scsi_Host *shost, - struct scsi_cmnd *scmd) +static enum scsi_qc_status myrb_pthru_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *scmd) { struct request *rq = scsi_cmd_to_rq(scmd); struct myrb_hba *cb = shost_priv(shost); @@ -1416,8 +1416,8 @@ static void myrb_read_capacity(struct myrb_hba *cb, struct scsi_cmnd *scmd, scsi_sg_copy_from_buffer(scmd, data, 8); } -static int myrb_ldev_queuecommand(struct Scsi_Host *shost, - struct scsi_cmnd *scmd) +static enum scsi_qc_status myrb_ldev_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *scmd) { struct myrb_hba *cb = shost_priv(shost); struct myrb_cmdblk *cmd_blk = scsi_cmd_priv(scmd); @@ -1603,8 +1603,8 @@ submit: return 0; } -static int myrb_queuecommand(struct Scsi_Host *shost, - struct scsi_cmnd *scmd) +static enum scsi_qc_status myrb_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *scmd) { struct scsi_device *sdev = scmd->device; diff --git a/drivers/scsi/myrs.c b/drivers/scsi/myrs.c index a58abd796603..7e8bb533c669 100644 --- a/drivers/scsi/myrs.c +++ b/drivers/scsi/myrs.c @@ -1581,8 +1581,8 @@ static void myrs_mode_sense(struct myrs_hba *cs, struct scsi_cmnd *scmd, scsi_sg_copy_from_buffer(scmd, modes, mode_len); } -static int myrs_queuecommand(struct Scsi_Host *shost, - struct scsi_cmnd *scmd) +static enum scsi_qc_status myrs_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *scmd) { struct request *rq = scsi_cmd_to_rq(scmd); struct myrs_hba *cs = shost_priv(shost); diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c index 34ba9b137789..4a255aafed80 100644 --- a/drivers/scsi/ncr53c8xx.c +++ b/drivers/scsi/ncr53c8xx.c @@ -7852,7 +7852,7 @@ static int ncr53c8xx_sdev_configure(struct scsi_device *device, return 0; } -static int ncr53c8xx_queue_command_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status ncr53c8xx_queue_command_lck(struct scsi_cmnd *cmd) { struct ncr_cmd_priv *cmd_priv = scsi_cmd_priv(cmd); void (*done)(struct scsi_cmnd *) = scsi_done; diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c index abc4ce9eae74..e893d5677241 100644 --- a/drivers/scsi/nsp32.c +++ b/drivers/scsi/nsp32.c @@ -185,7 +185,8 @@ static void __exit exit_nsp32 (void); static int nsp32_show_info (struct seq_file *, struct Scsi_Host *); static int nsp32_detect (struct pci_dev *pdev); -static int nsp32_queuecommand(struct Scsi_Host *, struct scsi_cmnd *); +static enum scsi_qc_status nsp32_queuecommand(struct Scsi_Host *, + struct scsi_cmnd *); static const char *nsp32_info (struct Scsi_Host *); static int nsp32_release (struct Scsi_Host *); @@ -905,7 +906,7 @@ static int nsp32_setup_sg_table(struct scsi_cmnd *SCpnt) return TRUE; } -static int nsp32_queuecommand_lck(struct scsi_cmnd *SCpnt) +static enum scsi_qc_status nsp32_queuecommand_lck(struct scsi_cmnd *SCpnt) { void (*done)(struct scsi_cmnd *) = scsi_done; nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index a5a1406a2bde..fb3a1b43d8bd 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -186,7 +186,7 @@ static void nsp_scsi_done(struct scsi_cmnd *SCpnt) scsi_done(SCpnt); } -static int nsp_queuecommand_lck(struct scsi_cmnd *const SCpnt) +static enum scsi_qc_status nsp_queuecommand_lck(struct scsi_cmnd *const SCpnt) { struct scsi_pointer *scsi_pointer = nsp_priv(SCpnt); #ifdef NSP_DEBUG diff --git a/drivers/scsi/pcmcia/nsp_cs.h b/drivers/scsi/pcmcia/nsp_cs.h index e1ee8ef90ad3..12e58386bb8f 100644 --- a/drivers/scsi/pcmcia/nsp_cs.h +++ b/drivers/scsi/pcmcia/nsp_cs.h @@ -294,7 +294,8 @@ static struct Scsi_Host *nsp_detect (struct scsi_host_template *sht); static const char *nsp_info (struct Scsi_Host *shpnt); static int nsp_show_info (struct seq_file *m, struct Scsi_Host *host); -static int nsp_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *SCpnt); +static enum scsi_qc_status nsp_queuecommand(struct Scsi_Host *h, + struct scsi_cmnd *SCpnt); /* Error handler */ /*static int nsp_eh_abort (struct scsi_cmnd *SCpnt);*/ diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c index a3b505240351..8f56f7277dee 100644 --- a/drivers/scsi/pcmcia/sym53c500_cs.c +++ b/drivers/scsi/pcmcia/sym53c500_cs.c @@ -544,7 +544,7 @@ SYM53C500_info(struct Scsi_Host *SChost) return (info_msg); } -static int SYM53C500_queue_lck(struct scsi_cmnd *SCpnt) +static enum scsi_qc_status SYM53C500_queue_lck(struct scsi_cmnd *SCpnt) { struct sym53c500_cmd_priv *scp = scsi_cmd_priv(SCpnt); int i; diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index 33f403e307eb..cf163e63054b 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -3242,14 +3242,14 @@ static int pmcraid_build_ioadl( * SCSI_MLQUEUE_DEVICE_BUSY if device is busy * SCSI_MLQUEUE_HOST_BUSY if host is busy */ -static int pmcraid_queuecommand_lck(struct scsi_cmnd *scsi_cmd) +static enum scsi_qc_status pmcraid_queuecommand_lck(struct scsi_cmnd *scsi_cmd) { struct pmcraid_instance *pinstance; struct pmcraid_resource_entry *res; struct pmcraid_ioarcb *ioarcb; + enum scsi_qc_status rc = 0; struct pmcraid_cmd *cmd; u32 fw_version; - int rc = 0; pinstance = (struct pmcraid_instance *)scsi_cmd->device->host->hostdata; diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c index ea682f3044b6..ddcef40789e5 100644 --- a/drivers/scsi/ppa.c +++ b/drivers/scsi/ppa.c @@ -816,7 +816,7 @@ static int ppa_engine(ppa_struct *dev, struct scsi_cmnd *cmd) return 0; } -static int ppa_queuecommand_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status ppa_queuecommand_lck(struct scsi_cmnd *cmd) { ppa_struct *dev = ppa_dev(cmd->device->host); diff --git a/drivers/scsi/ps3rom.c b/drivers/scsi/ps3rom.c index 92fe5c5c5bb0..a9c727d22931 100644 --- a/drivers/scsi/ps3rom.c +++ b/drivers/scsi/ps3rom.c @@ -201,7 +201,7 @@ static int ps3rom_write_request(struct ps3_storage_device *dev, return 0; } -static int ps3rom_queuecommand_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status ps3rom_queuecommand_lck(struct scsi_cmnd *cmd) { struct ps3rom_private *priv = shost_priv(cmd->device->host); struct ps3_storage_device *dev = priv->dev; diff --git a/drivers/scsi/qedf/qedf.h b/drivers/scsi/qedf/qedf.h index 98afdfe63600..5b330a3203e1 100644 --- a/drivers/scsi/qedf/qedf.h +++ b/drivers/scsi/qedf/qedf.h @@ -487,8 +487,8 @@ extern uint qedf_debug; extern struct qedf_cmd_mgr *qedf_cmd_mgr_alloc(struct qedf_ctx *qedf); extern void qedf_cmd_mgr_free(struct qedf_cmd_mgr *cmgr); -extern int qedf_queuecommand(struct Scsi_Host *host, - struct scsi_cmnd *sc_cmd); +extern enum scsi_qc_status qedf_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *sc_cmd); extern void qedf_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb); extern u8 *qedf_get_src_mac(struct fc_lport *lport); extern void qedf_fip_recv(struct qedf_ctx *qedf, struct sk_buff *skb); diff --git a/drivers/scsi/qedf/qedf_io.c b/drivers/scsi/qedf/qedf_io.c index fcfc3bed02c6..d12c47be016e 100644 --- a/drivers/scsi/qedf/qedf_io.c +++ b/drivers/scsi/qedf/qedf_io.c @@ -930,8 +930,8 @@ int qedf_post_io_req(struct qedf_rport *fcport, struct qedf_ioreq *io_req) return false; } -int -qedf_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc_cmd) +enum scsi_qc_status qedf_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *sc_cmd) { struct fc_lport *lport = shost_priv(host); struct qedf_ctx *qedf = lport_priv(lport); diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 26c312a48a19..cdd6fe002c32 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -406,9 +406,11 @@ static int qla1280_device_reset(struct scsi_qla_host *, int, int); static int qla1280_abort_command(struct scsi_qla_host *, struct srb *, int); static int qla1280_abort_isp(struct scsi_qla_host *); #ifdef QLA_64BIT_PTR -static int qla1280_64bit_start_scsi(struct scsi_qla_host *, struct srb *); +static enum scsi_qc_status qla1280_64bit_start_scsi(struct scsi_qla_host *, + struct srb *); #else -static int qla1280_32bit_start_scsi(struct scsi_qla_host *, struct srb *); +static enum scsi_qc_status qla1280_32bit_start_scsi(struct scsi_qla_host *, + struct srb *); #endif static void qla1280_nv_write(struct scsi_qla_host *, uint16_t); static void qla1280_poll(struct scsi_qla_host *); @@ -682,12 +684,12 @@ qla1280_info(struct Scsi_Host *host) * handling). Unfortunately, it sometimes calls the scheduler in interrupt * context which is a big NO! NO!. **************************************************************************/ -static int qla1280_queuecommand_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status qla1280_queuecommand_lck(struct scsi_cmnd *cmd) { struct Scsi_Host *host = cmd->device->host; struct scsi_qla_host *ha = (struct scsi_qla_host *)host->hostdata; struct srb *sp = scsi_cmd_priv(cmd); - int status; + enum scsi_qc_status status; sp->cmd = cmd; sp->flags = 0; @@ -2730,7 +2732,7 @@ qla1280_marker(struct scsi_qla_host *ha, int bus, int id, int lun, u8 type) * 0 = success, was able to issue command. */ #ifdef QLA_64BIT_PTR -static int +static enum scsi_qc_status qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) { struct device_reg __iomem *reg = ha->iobase; @@ -2738,7 +2740,7 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) cmd_a64_entry_t *pkt; __le32 *dword_ptr; dma_addr_t dma_handle; - int status = 0; + enum scsi_qc_status status = 0; int cnt; int req_cnt; int seg_cnt; @@ -2984,14 +2986,14 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) * Returns: * 0 = success, was able to issue command. */ -static int +static enum scsi_qc_status qla1280_32bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) { struct device_reg __iomem *reg = ha->iobase; struct scsi_cmnd *cmd = sp->cmd; struct cmd_entry *pkt; __le32 *dword_ptr; - int status = 0; + enum scsi_qc_status status = 0; int cnt; int req_cnt; int seg_cnt; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index fb0b689cbacd..08d2dcf6d7da 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -402,8 +402,9 @@ static int qla2x00_mem_alloc(struct qla_hw_data *, uint16_t, uint16_t, struct req_que **, struct rsp_que **); static void qla2x00_free_fw_dump(struct qla_hw_data *); static void qla2x00_mem_free(struct qla_hw_data *); -static int qla2xxx_mqueuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd, - struct qla_qpair *qpair); +static enum scsi_qc_status qla2xxx_mqueuecommand(struct Scsi_Host *host, + struct scsi_cmnd *cmd, + struct qla_qpair *qpair); /* -------------------------------------------------------------------------- */ static void qla_init_base_qpair(struct scsi_qla_host *vha, struct req_que *req, @@ -858,8 +859,8 @@ void qla2xxx_qpair_sp_compl(srb_t *sp, int res) complete(comp); } -static int -qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) +static enum scsi_qc_status qla2xxx_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *cmd) { scsi_qla_host_t *vha = shost_priv(host); fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; @@ -981,9 +982,9 @@ qc24_fail_command: } /* For MQ supported I/O */ -static int +static enum scsi_qc_status qla2xxx_mqueuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd, - struct qla_qpair *qpair) + struct qla_qpair *qpair) { scsi_qla_host_t *vha = shost_priv(host); fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 97329c97332f..71bb96ca33b4 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -155,7 +155,8 @@ static int qla4xxx_get_host_stats(struct Scsi_Host *shost, char *buf, int len); /* * SCSI host template entry points */ -static int qla4xxx_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *cmd); +static enum scsi_qc_status qla4xxx_queuecommand(struct Scsi_Host *h, + struct scsi_cmnd *cmd); static int qla4xxx_eh_abort(struct scsi_cmnd *cmd); static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd); static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd); @@ -4107,7 +4108,8 @@ void qla4xxx_srb_compl(struct kref *ref) * completion handling). Unfortunately, it sometimes calls the scheduler * in interrupt context which is a big NO! NO!. **/ -static int qla4xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) +static enum scsi_qc_status qla4xxx_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *cmd) { struct scsi_qla_host *ha = to_qla_host(host); struct ddb_entry *ddb_entry = cmd->device->hostdata; diff --git a/drivers/scsi/qlogicfas408.c b/drivers/scsi/qlogicfas408.c index 1ce469b7db99..d36293bc2717 100644 --- a/drivers/scsi/qlogicfas408.c +++ b/drivers/scsi/qlogicfas408.c @@ -464,7 +464,7 @@ irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id) * Queued command */ -static int qlogicfas408_queuecommand_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status qlogicfas408_queuecommand_lck(struct scsi_cmnd *cmd) { void (*done)(struct scsi_cmnd *) = scsi_done; struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd); diff --git a/drivers/scsi/qlogicfas408.h b/drivers/scsi/qlogicfas408.h index 83ef86c71f2f..a589c7656f57 100644 --- a/drivers/scsi/qlogicfas408.h +++ b/drivers/scsi/qlogicfas408.h @@ -104,7 +104,8 @@ struct qlogicfas408_priv { #define get_priv_by_host(x) (struct qlogicfas408_priv *)&((x)->hostdata[0]) irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id); -int qlogicfas408_queuecommand(struct Scsi_Host *h, struct scsi_cmnd * cmd); +enum scsi_qc_status qlogicfas408_queuecommand(struct Scsi_Host *h, + struct scsi_cmnd *cmd); int qlogicfas408_biosparam(struct scsi_device * disk, struct gendisk *unused, sector_t capacity, int ip[]); diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c index c9984ef57f26..ea0a2b5a0a42 100644 --- a/drivers/scsi/qlogicpti.c +++ b/drivers/scsi/qlogicpti.c @@ -1015,7 +1015,7 @@ static int qlogicpti_sdev_configure(struct scsi_device *sdev, * * "This code must fly." -davem */ -static int qlogicpti_queuecommand_lck(struct scsi_cmnd *Cmnd) +static enum scsi_qc_status qlogicpti_queuecommand_lck(struct scsi_cmnd *Cmnd) { void (*done)(struct scsi_cmnd *) = scsi_done; struct Scsi_Host *host = Cmnd->device->host; diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 9f17e9c49cb5..b8c1c77e9c78 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -9284,8 +9284,9 @@ static void scsi_debug_abort_cmd(struct Scsi_Host *shost, struct scsi_cmnd *scp) set_host_byte(scp, res ? DID_OK : DID_ERROR); } -static int scsi_debug_process_reserved_command(struct Scsi_Host *shost, - struct scsi_cmnd *scp) +static enum scsi_qc_status +scsi_debug_process_reserved_command(struct Scsi_Host *shost, + struct scsi_cmnd *scp) { struct sdebug_internal_cmd *internal_cmd = scsi_cmd_priv(scp); @@ -9303,8 +9304,8 @@ static int scsi_debug_process_reserved_command(struct Scsi_Host *shost, return 0; } -static int scsi_debug_queuecommand(struct Scsi_Host *shost, - struct scsi_cmnd *scp) +static enum scsi_qc_status scsi_debug_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *scp) { u8 sdeb_i; struct scsi_device *sdp = scp->device; diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index fe549e2b7c94..36834768fec1 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -6047,7 +6047,8 @@ static bool pqi_is_parity_write_stream(struct pqi_ctrl_info *ctrl_info, return false; } -static int pqi_scsi_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd) +static enum scsi_qc_status pqi_scsi_queue_command(struct Scsi_Host *shost, + struct scsi_cmnd *scmd) { int rc; struct pqi_ctrl_info *ctrl_info; diff --git a/drivers/scsi/snic/snic.h b/drivers/scsi/snic/snic.h index 32f5a34b6987..ebaf6d63a59b 100644 --- a/drivers/scsi/snic/snic.h +++ b/drivers/scsi/snic/snic.h @@ -362,7 +362,8 @@ void snic_glob_cleanup(void); extern struct workqueue_struct *snic_event_queue; extern const struct attribute_group *snic_host_groups[]; -int snic_queuecommand(struct Scsi_Host *, struct scsi_cmnd *); +enum scsi_qc_status snic_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *sc); int snic_abort_cmd(struct scsi_cmnd *); int snic_device_reset(struct scsi_cmnd *); int snic_host_reset(struct scsi_cmnd *); diff --git a/drivers/scsi/snic/snic_scsi.c b/drivers/scsi/snic/snic_scsi.c index 84973f0f771e..c6af3b8d2523 100644 --- a/drivers/scsi/snic/snic_scsi.c +++ b/drivers/scsi/snic/snic_scsi.c @@ -315,8 +315,8 @@ issue_sc_end: * Routine to send a scsi cdb to LLD * Called with host_lock held and interrupts disabled */ -int -snic_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *sc) +enum scsi_qc_status snic_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *sc) { struct snic_tgt *tgt = NULL; struct snic *snic = shost_priv(shost); diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c index 93c223e0a777..5a3f6fe22ae9 100644 --- a/drivers/scsi/stex.c +++ b/drivers/scsi/stex.c @@ -593,7 +593,7 @@ stex_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim) return 0; } -static int stex_queuecommand_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status stex_queuecommand_lck(struct scsi_cmnd *cmd) { void (*done)(struct scsi_cmnd *) = scsi_done; struct st_hba *hba; diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 6e4112143c76..19e18939d3a5 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -1714,7 +1714,8 @@ static bool storvsc_scsi_cmd_ok(struct scsi_cmnd *scmnd) return allowed; } -static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) +static enum scsi_qc_status storvsc_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *scmnd) { int ret; struct hv_host_device *host_dev = shost_priv(host); diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c index 57637a81776d..27e22acaf1a7 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.c +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c @@ -485,7 +485,7 @@ void sym_log_bus_error(struct Scsi_Host *shost) * queuecommand method. Entered with the host adapter lock held and * interrupts disabled. */ -static int sym53c8xx_queue_command_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status sym53c8xx_queue_command_lck(struct scsi_cmnd *cmd) { struct sym_hcb *np = SYM_SOFTC_PTR(cmd); struct sym_ucmd *ucp = SYM_UCMD_PTR(cmd); diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c index 96a69edddbe5..6b1d8bcd06b9 100644 --- a/drivers/scsi/virtio_scsi.c +++ b/drivers/scsi/virtio_scsi.c @@ -561,8 +561,8 @@ static struct virtio_scsi_vq *virtscsi_pick_vq_mq(struct virtio_scsi *vscsi, return &vscsi->req_vqs[hwq]; } -static int virtscsi_queuecommand(struct Scsi_Host *shost, - struct scsi_cmnd *sc) +static enum scsi_qc_status virtscsi_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *sc) { struct virtio_scsi *vscsi = shost_priv(shost); struct virtio_scsi_vq *req_vq = virtscsi_pick_vq_mq(vscsi, sc); diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c index 32242d86cf5b..11f86c76f391 100644 --- a/drivers/scsi/vmw_pvscsi.c +++ b/drivers/scsi/vmw_pvscsi.c @@ -771,7 +771,7 @@ static int pvscsi_queue_ring(struct pvscsi_adapter *adapter, return 0; } -static int pvscsi_queue_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status pvscsi_queue_lck(struct scsi_cmnd *cmd) { struct Scsi_Host *host = cmd->device->host; struct pvscsi_adapter *adapter = shost_priv(host); diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c index dd1fef9226f2..1e49d0402f0b 100644 --- a/drivers/scsi/wd33c93.c +++ b/drivers/scsi/wd33c93.c @@ -302,7 +302,7 @@ calc_sync_msg(unsigned int period, unsigned int offset, unsigned int fast, msg[1] = offset; } -static int wd33c93_queuecommand_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status wd33c93_queuecommand_lck(struct scsi_cmnd *cmd) { struct scsi_pointer *scsi_pointer = WD33C93_scsi_pointer(cmd); struct WD33C93_hostdata *hostdata; diff --git a/drivers/scsi/wd33c93.h b/drivers/scsi/wd33c93.h index e5e4254b1477..e1e98280aad1 100644 --- a/drivers/scsi/wd33c93.h +++ b/drivers/scsi/wd33c93.h @@ -332,7 +332,8 @@ static inline struct scsi_pointer *WD33C93_scsi_pointer(struct scsi_cmnd *cmd) void wd33c93_init (struct Scsi_Host *instance, const wd33c93_regs regs, dma_setup_t setup, dma_stop_t stop, int clock_freq); int wd33c93_abort (struct scsi_cmnd *cmd); -int wd33c93_queuecommand (struct Scsi_Host *h, struct scsi_cmnd *cmd); +enum scsi_qc_status wd33c93_queuecommand(struct Scsi_Host *h, + struct scsi_cmnd *cmd); void wd33c93_intr (struct Scsi_Host *instance); int wd33c93_show_info(struct seq_file *, struct Scsi_Host *); int wd33c93_write_info(struct Scsi_Host *, char *, int); diff --git a/drivers/scsi/wd719x.c b/drivers/scsi/wd719x.c index 0c9987828774..830d40f57f6a 100644 --- a/drivers/scsi/wd719x.c +++ b/drivers/scsi/wd719x.c @@ -204,7 +204,8 @@ static void wd719x_finish_cmd(struct wd719x_scb *scb, int result) } /* Build a SCB and send it to the card */ -static int wd719x_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd) +static enum scsi_qc_status wd719x_queuecommand(struct Scsi_Host *sh, + struct scsi_cmnd *cmd) { int i, count_sg; unsigned long flags; diff --git a/drivers/scsi/xen-scsifront.c b/drivers/scsi/xen-scsifront.c index 924025305753..bf36c07c2b47 100644 --- a/drivers/scsi/xen-scsifront.c +++ b/drivers/scsi/xen-scsifront.c @@ -603,8 +603,8 @@ static void scsifront_return(struct vscsifrnt_info *info) wake_up(&info->wq_pause); } -static int scsifront_queuecommand(struct Scsi_Host *shost, - struct scsi_cmnd *sc) +static enum scsi_qc_status scsifront_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *sc) { struct vscsifrnt_info *info = shost_priv(shost); struct vscsifrnt_shadow *shadow = scsi_cmd_priv(sc); diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 01a8e349dc4d..0821a149573e 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -165,7 +165,8 @@ out_done: * ->queuecommand can be and usually is called from interrupt context, so * defer the actual submission to a workqueue. */ -static int tcm_loop_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *sc) +static enum scsi_qc_status tcm_loop_queuecommand(struct Scsi_Host *sh, + struct scsi_cmnd *sc) { struct tcm_loop_cmd *tl_cmd = scsi_cmd_priv(sc); diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 057678f4c50a..0369043ca010 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -3033,7 +3033,8 @@ static int ufshcd_init_cmd_priv(struct Scsi_Host *host, struct scsi_cmnd *cmd) * * Return: 0 for success, non-zero in case of failure. */ -static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) +static enum scsi_qc_status ufshcd_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *cmd) { struct ufs_hba *hba = shost_priv(host); int tag = scsi_cmd_to_rq(cmd)->tag; @@ -3113,8 +3114,8 @@ out: return err; } -static int ufshcd_queue_reserved_command(struct Scsi_Host *host, - struct scsi_cmnd *cmd) +static enum scsi_qc_status ufshcd_queue_reserved_command(struct Scsi_Host *host, + struct scsi_cmnd *cmd) { struct ufshcd_lrb *lrbp = scsi_cmd_priv(cmd); struct request *rq = scsi_cmd_to_rq(cmd); diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c index 934ec5310fb9..82859374f302 100644 --- a/drivers/usb/image/microtek.c +++ b/drivers/usb/image/microtek.c @@ -355,8 +355,8 @@ static int mts_scsi_host_reset(struct scsi_cmnd *srb) return result ? FAILED : SUCCESS; } -static int -mts_scsi_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *srb); +static enum scsi_qc_status mts_scsi_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *srb); static void mts_transfer_cleanup( struct urb *transfer ); static void mts_do_sg(struct urb * transfer); @@ -559,7 +559,7 @@ mts_build_transfer_context(struct scsi_cmnd *srb, struct mts_desc* desc) desc->context.data_pipe = pipe; } -static int mts_scsi_queuecommand_lck(struct scsi_cmnd *srb) +static enum scsi_qc_status mts_scsi_queuecommand_lck(struct scsi_cmnd *srb) { mts_scsi_cmnd_callback callback = scsi_done; struct mts_desc* desc = (struct mts_desc*)(srb->device->host->hostdata[0]); diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index d2f476e48d0c..97de28e85562 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -357,7 +357,7 @@ static int target_alloc(struct scsi_target *starget) /* queue a command */ /* This is always called with scsi_lock(host) held */ -static int queuecommand_lck(struct scsi_cmnd *srb) +static enum scsi_qc_status queuecommand_lck(struct scsi_cmnd *srb) { void (*done)(struct scsi_cmnd *) = scsi_done; struct us_data *us = host_to_us(srb->device->host); diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index 73b1981cb1d5..ac3c0b919fdd 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -636,7 +636,7 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd, return 0; } -static int uas_queuecommand_lck(struct scsi_cmnd *cmnd) +static enum scsi_qc_status uas_queuecommand_lck(struct scsi_cmnd *cmnd) { struct scsi_device *sdev = cmnd->device; struct uas_dev_info *devinfo = sdev->hostdata; diff --git a/include/linux/libata.h b/include/linux/libata.h index 39534fafa36a..44117814d672 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1150,7 +1150,8 @@ extern int ata_scsi_ioctl(struct scsi_device *dev, unsigned int cmd, #else #define ATA_SCSI_COMPAT_IOCTL /* empty */ #endif -extern int ata_scsi_queuecmd(struct Scsi_Host *h, struct scsi_cmnd *cmd); +extern enum scsi_qc_status ata_scsi_queuecmd(struct Scsi_Host *h, + struct scsi_cmnd *cmd); #if IS_REACHABLE(CONFIG_ATA) bool ata_scsi_dma_need_drain(struct request *rq); #else diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index 183d9fd50d2d..be0ffe1e3395 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -959,7 +959,8 @@ void fc_fcp_destroy(struct fc_lport *); /* * SCSI INTERACTION LAYER *****************************/ -int fc_queuecommand(struct Scsi_Host *, struct scsi_cmnd *); +enum scsi_qc_status fc_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *cmnd); int fc_eh_abort(struct scsi_cmnd *); int fc_eh_device_reset(struct scsi_cmnd *); int fc_eh_host_reset(struct scsi_cmnd *); diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h index 7282555adfd5..3d765c77bcd9 100644 --- a/include/scsi/libiscsi.h +++ b/include/scsi/libiscsi.h @@ -392,7 +392,8 @@ extern int iscsi_eh_abort(struct scsi_cmnd *sc); extern int iscsi_eh_recover_target(struct scsi_cmnd *sc); extern int iscsi_eh_session_reset(struct scsi_cmnd *sc); extern int iscsi_eh_device_reset(struct scsi_cmnd *sc); -extern int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc); +extern enum scsi_qc_status iscsi_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *sc); extern enum scsi_timeout_action iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc); /* diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index a0635b128d7a..e76f5744941b 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -689,7 +689,8 @@ extern void sas_suspend_ha(struct sas_ha_struct *sas_ha); int sas_phy_reset(struct sas_phy *phy, int hard_reset); int sas_phy_enable(struct sas_phy *phy, int enable); -extern int sas_queuecommand(struct Scsi_Host *, struct scsi_cmnd *); +extern enum scsi_qc_status sas_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *cmd); extern int sas_target_alloc(struct scsi_target *); int sas_sdev_configure(struct scsi_device *dev, struct queue_limits *lim); extern int sas_change_queue_depth(struct scsi_device *, int new_depth); diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index e87cf7eadd26..f6e12565a81d 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -84,13 +84,15 @@ struct scsi_host_template { * * STATUS: REQUIRED */ - int (* queuecommand)(struct Scsi_Host *, struct scsi_cmnd *); + enum scsi_qc_status (*queuecommand)(struct Scsi_Host *, + struct scsi_cmnd *); /* * Queue a reserved command (BLK_MQ_REQ_RESERVED). The .queuecommand() * documentation also applies to the .queue_reserved_command() callback. */ - int (*queue_reserved_command)(struct Scsi_Host *, struct scsi_cmnd *); + enum scsi_qc_status (*queue_reserved_command)(struct Scsi_Host *, + struct scsi_cmnd *); /* * The commit_rqs function is used to trigger a hardware @@ -525,10 +527,12 @@ struct scsi_host_template { * */ #define DEF_SCSI_QCMD(func_name) \ - int func_name(struct Scsi_Host *shost, struct scsi_cmnd *cmd) \ + enum scsi_qc_status func_name(struct Scsi_Host *shost, \ + struct scsi_cmnd *cmd) \ { \ unsigned long irq_flags; \ - int rc; \ + enum scsi_qc_status rc; \ + \ spin_lock_irqsave(shost->host_lock, irq_flags); \ rc = func_name##_lck(cmd); \ spin_unlock_irqrestore(shost->host_lock, irq_flags); \ From 7f386b05f994fc08d4e73c0c91b76ab47da36250 Mon Sep 17 00:00:00 2001 From: Ram Kumar Dwivedi Date: Tue, 13 Jan 2026 13:30:43 +0530 Subject: [PATCH 55/78] scsi: MAINTAINERS: Broaden UFS Qualcomm binding file pattern Update the file pattern for UFS Qualcomm devicetree bindings to match all files under 'Documentation/devicetree/bindings/ufs/qcom*' instead of only 'qcom,ufs.yaml'. This ensures maintainers are correctly notified for any related binding changes. Acked-by: Dmitry Baryshkov Reviewed-by: Manivannan Sadhasivam Signed-off-by: Ram Kumar Dwivedi Link: https://patch.msgid.link/20260113080046.284089-2-ram.dwivedi@oss.qualcomm.com Signed-off-by: Martin K. Petersen --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 5b11839cba9d..70292bd3ed71 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -26803,7 +26803,7 @@ M: Manivannan Sadhasivam L: linux-arm-msm@vger.kernel.org L: linux-scsi@vger.kernel.org S: Maintained -F: Documentation/devicetree/bindings/ufs/qcom,ufs.yaml +F: Documentation/devicetree/bindings/ufs/qcom* F: drivers/ufs/host/ufs-qcom* UNIVERSAL FLASH STORAGE HOST CONTROLLER DRIVER RENESAS HOOKS From e2725ed2a7fb5f5f468020a52bd9ffc54caa7c8c Mon Sep 17 00:00:00 2001 From: Ram Kumar Dwivedi Date: Tue, 13 Jan 2026 13:30:44 +0530 Subject: [PATCH 56/78] scsi: ufs: dt-bindings: Document bindings for SA8255P UFS Host Controller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document the device tree bindings for UFS host controller on Qualcomm SA8255P platform which integrates firmware-managed resources. The platform firmware implements the SCMI server and manages resources such as the PHY, clocks, regulators and resets via the SCMI power protocol. As a result, the OS-visible DT only describes the controller’s MMIO, interrupt, IOMMU and power-domain interfaces. The generic "qcom,ufshc" and "jedec,ufs-2.0" compatible strings are removed from the binding, since this firmware managed design won't be compatible with the drivers doing full resource management. Co-developed-by: Anjana Hari Signed-off-by: Anjana Hari Signed-off-by: Ram Kumar Dwivedi Reviewed-by: Krzysztof Kozlowski Acked-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20260113080046.284089-3-ram.dwivedi@oss.qualcomm.com Signed-off-by: Martin K. Petersen --- .../bindings/ufs/qcom,sa8255p-ufshc.yaml | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 Documentation/devicetree/bindings/ufs/qcom,sa8255p-ufshc.yaml diff --git a/Documentation/devicetree/bindings/ufs/qcom,sa8255p-ufshc.yaml b/Documentation/devicetree/bindings/ufs/qcom,sa8255p-ufshc.yaml new file mode 100644 index 000000000000..75fae9f1eba7 --- /dev/null +++ b/Documentation/devicetree/bindings/ufs/qcom,sa8255p-ufshc.yaml @@ -0,0 +1,56 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/ufs/qcom,sa8255p-ufshc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm SA8255P UFS Host Controller + +maintainers: + - Ram Kumar Dwivedi + +properties: + compatible: + const: qcom,sa8255p-ufshc + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + iommus: + maxItems: 1 + + dma-coherent: true + + power-domains: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + - power-domains + - iommus + - dma-coherent + +allOf: + - $ref: ufs-common.yaml + +unevaluatedProperties: false + +examples: + - | + #include + + ufshc@1d84000 { + compatible = "qcom,sa8255p-ufshc"; + reg = <0x01d84000 0x3000>; + interrupts = ; + lanes-per-direction = <2>; + + iommus = <&apps_smmu 0x100 0x0>; + power-domains = <&scmi3_pd 0>; + dma-coherent; + }; From 26c06d0baeb7999e44cf6717fc12d58a359eba99 Mon Sep 17 00:00:00 2001 From: Ram Kumar Dwivedi Date: Tue, 13 Jan 2026 13:30:45 +0530 Subject: [PATCH 57/78] scsi: ufs: core: Enforce minimum PM level for sysfs configuration Some UFS platforms only support a limited subset of power levels. Currently, the sysfs interface allows users to set any PM level without validating the minimum supported value. If an unsupported level is selected, suspend may fail. Introduce an pm_lvl_min field in the ufs_hba structure and use it to clamp the PM level requested via sysfs so that only supported levels are accepted. Platforms that require a minimum PM level can set this field during probe. Signed-off-by: Ram Kumar Dwivedi Reviewed-by: Manivannan Sadhasivam Reviewed-by: Bart Van Assche Link: https://patch.msgid.link/20260113080046.284089-4-ram.dwivedi@oss.qualcomm.com Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufs-sysfs.c | 2 +- include/ufs/ufshcd.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/ufs/core/ufs-sysfs.c b/drivers/ufs/core/ufs-sysfs.c index b33f8656edb5..02e5468ad49d 100644 --- a/drivers/ufs/core/ufs-sysfs.c +++ b/drivers/ufs/core/ufs-sysfs.c @@ -141,7 +141,7 @@ static inline ssize_t ufs_sysfs_pm_lvl_store(struct device *dev, if (kstrtoul(buf, 0, &value)) return -EINVAL; - if (value >= UFS_PM_LVL_MAX) + if (value >= UFS_PM_LVL_MAX || value < hba->pm_lvl_min) return -EINVAL; if (ufs_pm_lvl_states[value].dev_state == UFS_DEEPSLEEP_PWR_MODE && diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index 19154228780b..a64c19563b03 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -834,6 +834,7 @@ enum ufshcd_mcq_opr { * @uic_link_state: active state of the link to the UFS device. * @rpm_lvl: desired UFS power management level during runtime PM. * @spm_lvl: desired UFS power management level during system PM. + * @pm_lvl_min: minimum supported power management level. * @pm_op_in_progress: whether or not a PM operation is in progress. * @ahit: value of Auto-Hibernate Idle Timer register. * @outstanding_tasks: Bits representing outstanding task requests @@ -972,6 +973,7 @@ struct ufs_hba { enum ufs_pm_level rpm_lvl; /* Desired UFS power management level during system PM */ enum ufs_pm_level spm_lvl; + enum ufs_pm_level pm_lvl_min; int pm_op_in_progress; /* Auto-Hibernate Idle Timer register value */ From ad44cf1b2845303285fec8bb25a02d0d0f103a82 Mon Sep 17 00:00:00 2001 From: Ram Kumar Dwivedi Date: Tue, 13 Jan 2026 13:30:46 +0530 Subject: [PATCH 58/78] scsi: ufs: ufs-qcom: Add support for firmware-managed resource abstraction Add a compatible string for SA8255p platforms where resources such as PHY, clocks, regulators, and resets are managed by firmware through an SCMI server. Use the SCMI power protocol to abstract these resources and invoke power operations via runtime PM APIs (pm_runtime_get/put_sync). Introduce vendor operations (vops) for SA8255p targets to enable SCMI- based resource control. In this model, capabilities like clock scaling and gating are not yet supported; these will be added incrementally. Co-developed-by: Anjana Hari Signed-off-by: Anjana Hari Co-developed-by: Shazad Hussain Signed-off-by: Shazad Hussain Signed-off-by: Ram Kumar Dwivedi Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20260113080046.284089-5-ram.dwivedi@oss.qualcomm.com Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 156 +++++++++++++++++++++++++++++++++++- drivers/ufs/host/ufs-qcom.h | 1 + 2 files changed, 156 insertions(+), 1 deletion(-) diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 8ebee0cc5313..375fd24ba458 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -619,6 +620,27 @@ static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba, return err; } +static int ufs_qcom_fw_managed_hce_enable_notify(struct ufs_hba *hba, + enum ufs_notify_change_status status) +{ + struct ufs_qcom_host *host = ufshcd_get_variant(hba); + + switch (status) { + case PRE_CHANGE: + ufs_qcom_select_unipro_mode(host); + break; + case POST_CHANGE: + ufs_qcom_enable_hw_clk_gating(hba); + ufs_qcom_ice_enable(host); + break; + default: + dev_err(hba->dev, "Invalid status %d\n", status); + return -EINVAL; + } + + return 0; +} + /** * ufs_qcom_cfg_timers - Configure ufs qcom cfg timers * @@ -789,6 +811,33 @@ static int ufs_qcom_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) return ufs_qcom_ice_resume(host); } +static int ufs_qcom_fw_managed_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op, + enum ufs_notify_change_status status) +{ + struct ufs_qcom_host *host = ufshcd_get_variant(hba); + + if (status == PRE_CHANGE) + return 0; + + pm_runtime_put_sync(hba->dev); + + return ufs_qcom_ice_suspend(host); +} + +static int ufs_qcom_fw_managed_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) +{ + struct ufs_qcom_host *host = ufshcd_get_variant(hba); + int err; + + err = pm_runtime_resume_and_get(hba->dev); + if (err) { + dev_err(hba->dev, "PM runtime resume failed: %d\n", err); + return err; + } + + return ufs_qcom_ice_resume(host); +} + static void ufs_qcom_dev_ref_clk_ctrl(struct ufs_qcom_host *host, bool enable) { if (host->dev_ref_clk_ctrl_mmio && @@ -1421,6 +1470,54 @@ static void ufs_qcom_exit(struct ufs_hba *hba) phy_exit(host->generic_phy); } +static int ufs_qcom_fw_managed_init(struct ufs_hba *hba) +{ + struct device *dev = hba->dev; + struct ufs_qcom_host *host; + int err; + + host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL); + if (!host) + return -ENOMEM; + + host->hba = hba; + ufshcd_set_variant(hba, host); + + ufs_qcom_get_controller_revision(hba, &host->hw_ver.major, + &host->hw_ver.minor, &host->hw_ver.step); + + err = ufs_qcom_ice_init(host); + if (err) + goto out_variant_clear; + + ufs_qcom_get_default_testbus_cfg(host); + err = ufs_qcom_testbus_config(host); + if (err) + /* Failure is non-fatal */ + dev_warn(dev, "Failed to configure the testbus %d\n", err); + + hba->caps |= UFSHCD_CAP_WB_EN; + + ufs_qcom_advertise_quirks(hba); + host->hba->quirks &= ~UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH; + + hba->spm_lvl = hba->rpm_lvl = hba->pm_lvl_min = UFS_PM_LVL_5; + + ufs_qcom_set_host_params(hba); + ufs_qcom_parse_gear_limits(hba); + + return 0; + +out_variant_clear: + ufshcd_set_variant(hba, NULL); + return err; +} + +static void ufs_qcom_fw_managed_exit(struct ufs_hba *hba) +{ + pm_runtime_put_sync(hba->dev); +} + /** * ufs_qcom_set_clk_40ns_cycles - Configure 40ns clk cycles * @@ -1950,6 +2047,37 @@ static int ufs_qcom_device_reset(struct ufs_hba *hba) return 0; } +/** + * ufs_qcom_fw_managed_device_reset - Reset UFS device under FW-managed design + * @hba: pointer to UFS host bus adapter + * + * In the firmware-managed reset model, the power domain is powered on by genpd + * before the UFS controller driver probes. For subsequent resets (such as + * suspend/resume or recovery), the UFS driver must explicitly invoke PM runtime + * + * Return: 0 on success or a negative error code on failure. + */ +static int ufs_qcom_fw_managed_device_reset(struct ufs_hba *hba) +{ + static bool is_boot = true; + int err; + + /* Skip reset on cold boot; perform it on subsequent calls */ + if (is_boot) { + is_boot = false; + return 0; + } + + pm_runtime_put_sync(hba->dev); + err = pm_runtime_resume_and_get(hba->dev); + if (err < 0) { + dev_err(hba->dev, "PM runtime resume failed: %d\n", err); + return err; + } + + return 0; +} + static void ufs_qcom_config_scaling_param(struct ufs_hba *hba, struct devfreq_dev_profile *p, struct devfreq_simple_ondemand_data *d) @@ -2229,6 +2357,20 @@ static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = { .freq_to_gear_speed = ufs_qcom_freq_to_gear_speed, }; +static const struct ufs_hba_variant_ops ufs_hba_qcom_sa8255p_vops = { + .name = "qcom-sa8255p", + .init = ufs_qcom_fw_managed_init, + .exit = ufs_qcom_fw_managed_exit, + .hce_enable_notify = ufs_qcom_fw_managed_hce_enable_notify, + .pwr_change_notify = ufs_qcom_pwr_change_notify, + .apply_dev_quirks = ufs_qcom_apply_dev_quirks, + .fixup_dev_quirks = ufs_qcom_fixup_dev_quirks, + .suspend = ufs_qcom_fw_managed_suspend, + .resume = ufs_qcom_fw_managed_resume, + .dbg_register_dump = ufs_qcom_dump_dbg_regs, + .device_reset = ufs_qcom_fw_managed_device_reset, +}; + /** * ufs_qcom_probe - probe routine of the driver * @pdev: pointer to Platform device handle @@ -2239,9 +2381,16 @@ static int ufs_qcom_probe(struct platform_device *pdev) { int err; struct device *dev = &pdev->dev; + const struct ufs_hba_variant_ops *vops; + const struct ufs_qcom_drvdata *drvdata = device_get_match_data(dev); + + if (drvdata && drvdata->vops) + vops = drvdata->vops; + else + vops = &ufs_hba_qcom_vops; /* Perform generic probe */ - err = ufshcd_pltfrm_init(pdev, &ufs_hba_qcom_vops); + err = ufshcd_pltfrm_init(pdev, vops); if (err) return dev_err_probe(dev, err, "ufshcd_pltfrm_init() failed\n"); @@ -2269,10 +2418,15 @@ static const struct ufs_qcom_drvdata ufs_qcom_sm8550_drvdata = { .no_phy_retention = true, }; +static const struct ufs_qcom_drvdata ufs_qcom_sa8255p_drvdata = { + .vops = &ufs_hba_qcom_sa8255p_vops +}; + static const struct of_device_id ufs_qcom_of_match[] __maybe_unused = { { .compatible = "qcom,ufshc" }, { .compatible = "qcom,sm8550-ufshc", .data = &ufs_qcom_sm8550_drvdata }, { .compatible = "qcom,sm8650-ufshc", .data = &ufs_qcom_sm8550_drvdata }, + { .compatible = "qcom,sa8255p-ufshc", .data = &ufs_qcom_sa8255p_drvdata }, {}, }; MODULE_DEVICE_TABLE(of, ufs_qcom_of_match); diff --git a/drivers/ufs/host/ufs-qcom.h b/drivers/ufs/host/ufs-qcom.h index 380d02333d38..1111ab34da01 100644 --- a/drivers/ufs/host/ufs-qcom.h +++ b/drivers/ufs/host/ufs-qcom.h @@ -313,6 +313,7 @@ struct ufs_qcom_host { struct ufs_qcom_drvdata { enum ufshcd_quirks quirks; bool no_phy_retention; + const struct ufs_hba_variant_ops *vops; }; static inline u32 From 24de8b1d243b86678e92f7d0fd9d9a2954728b97 Mon Sep 17 00:00:00 2001 From: Ranjan Kumar Date: Fri, 16 Jan 2026 11:37:12 +0530 Subject: [PATCH 59/78] scsi: mpi3mr: Add module parameter to control threaded IRQ polling Add a module parameter to enable or disable threaded IRQ polling in the driver. The default behavior remains unchanged with polling enabled. When disabled, completion processing is kept entirely in the hard IRQ context, avoiding the threaded polling path. Signed-off-by: Ranjan Kumar Link: https://patch.msgid.link/20260116060719.32937-2-ranjan.kumar@broadcom.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr_fw.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index 8fe6e0bf342e..869e525f3e73 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -21,6 +21,10 @@ static int mpi3mr_check_op_admin_proc(struct mpi3mr_ioc *mrioc); static int poll_queues; module_param(poll_queues, int, 0444); MODULE_PARM_DESC(poll_queues, "Number of queues for io_uring poll mode. (Range 1 - 126)"); +static bool threaded_isr_poll = true; +module_param(threaded_isr_poll, bool, 0444); +MODULE_PARM_DESC(threaded_isr_poll, + "Enablement of IRQ polling thread (default=true)"); #if defined(writeq) && defined(CONFIG_64BIT) static inline void mpi3mr_writeq(__u64 b, void __iomem *addr, @@ -595,7 +599,8 @@ int mpi3mr_process_op_reply_q(struct mpi3mr_ioc *mrioc, * Exit completion loop to avoid CPU lockup * Ensure remaining completion happens from threaded ISR. */ - if (num_op_reply > mrioc->max_host_ios) { + if ((num_op_reply > mrioc->max_host_ios) && + (threaded_isr_poll == true)) { op_reply_q->enable_irq_poll = true; break; } @@ -692,7 +697,7 @@ static irqreturn_t mpi3mr_isr(int irq, void *privdata) * If more IOs are expected, schedule IRQ polling thread. * Otherwise exit from ISR. */ - if (!intr_info->op_reply_q) + if ((threaded_isr_poll == false) || !intr_info->op_reply_q) return ret; if (!intr_info->op_reply_q->enable_irq_poll || From d0d19250ed81907eac707be8221eb31e5b96b647 Mon Sep 17 00:00:00 2001 From: Ranjan Kumar Date: Fri, 16 Jan 2026 11:37:13 +0530 Subject: [PATCH 60/78] scsi: mpi3mr: Rename log data save helper to reflect threaded/BH context Log data events can be processed from BH and threaded contexts. Rename the save helper to document its intended usage and improve readability of the event handling flow. Signed-off-by: Ranjan Kumar Link: https://patch.msgid.link/20260116060719.32937-3-ranjan.kumar@broadcom.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr.h | 2 +- drivers/scsi/mpi3mr/mpi3mr_app.c | 4 ++-- drivers/scsi/mpi3mr/mpi3mr_os.c | 7 ++++++- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index 31d68c151b20..611a51a353c9 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -1508,7 +1508,7 @@ void mpi3mr_pel_get_seqnum_complete(struct mpi3mr_ioc *mrioc, struct mpi3mr_drv_cmd *drv_cmd); int mpi3mr_pel_get_seqnum_post(struct mpi3mr_ioc *mrioc, struct mpi3mr_drv_cmd *drv_cmd); -void mpi3mr_app_save_logdata(struct mpi3mr_ioc *mrioc, char *event_data, +void mpi3mr_app_save_logdata_th(struct mpi3mr_ioc *mrioc, char *event_data, u16 event_data_size); struct mpi3mr_enclosure_node *mpi3mr_enclosure_find_by_handle( struct mpi3mr_ioc *mrioc, u16 handle); diff --git a/drivers/scsi/mpi3mr/mpi3mr_app.c b/drivers/scsi/mpi3mr/mpi3mr_app.c index 0e5478d62580..37cca0573ddc 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_app.c +++ b/drivers/scsi/mpi3mr/mpi3mr_app.c @@ -2920,7 +2920,7 @@ out: } /** - * mpi3mr_app_save_logdata - Save Log Data events + * mpi3mr_app_save_logdata_th - Save Log Data events * @mrioc: Adapter instance reference * @event_data: event data associated with log data event * @event_data_size: event data size to copy @@ -2932,7 +2932,7 @@ out: * * Return:Nothing */ -void mpi3mr_app_save_logdata(struct mpi3mr_ioc *mrioc, char *event_data, +void mpi3mr_app_save_logdata_th(struct mpi3mr_ioc *mrioc, char *event_data, u16 event_data_size) { u32 index = mrioc->logdata_buf_idx, sz; diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index d4ca878d0886..028a3a1a6be0 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -1962,7 +1962,7 @@ static void mpi3mr_pcietopochg_evt_bh(struct mpi3mr_ioc *mrioc, static void mpi3mr_logdata_evt_bh(struct mpi3mr_ioc *mrioc, struct mpi3mr_fwevt *fwevt) { - mpi3mr_app_save_logdata(mrioc, fwevt->event_data, + mpi3mr_app_save_logdata_th(mrioc, fwevt->event_data, fwevt->event_data_size); } @@ -3058,6 +3058,11 @@ void mpi3mr_os_handle_events(struct mpi3mr_ioc *mrioc, } case MPI3_EVENT_DEVICE_INFO_CHANGED: case MPI3_EVENT_LOG_DATA: + + sz = event_reply->event_data_length * 4; + mpi3mr_app_save_logdata_th(mrioc, + (char *)event_reply->event_data, sz); + break; case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE: case MPI3_EVENT_ENCL_DEVICE_ADDED: { From 7a67d9262288f40ceec1de9d2def8368ea44134b Mon Sep 17 00:00:00 2001 From: Ranjan Kumar Date: Fri, 16 Jan 2026 11:37:14 +0530 Subject: [PATCH 61/78] scsi: mpi3mr: Avoid redundant diag-fault resets Update reset handling to invoke diag-save only for diag-fault resets. Skip issuing a diagnostic reset if the IOC is already in FAULT state, preventing repeated fault handling and improving reset stability. Signed-off-by: Ranjan Kumar Link: https://patch.msgid.link/20260116060719.32937-4-ranjan.kumar@broadcom.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr_fw.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index 869e525f3e73..178738850541 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -1707,6 +1707,8 @@ static int mpi3mr_issue_reset(struct mpi3mr_ioc *mrioc, u16 reset_type, MPI3MR_RESET_REASON_OSTYPE_SHIFT) | (mrioc->facts.ioc_num << MPI3MR_RESET_REASON_IOCNUM_SHIFT) | reset_reason); writel(reset_reason, &mrioc->sysif_regs->scratchpad[0]); + if (reset_type == MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT) + mpi3mr_set_diagsave(mrioc); writel(host_diagnostic | reset_type, &mrioc->sysif_regs->host_diagnostic); switch (reset_type) { @@ -5404,6 +5406,7 @@ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc, { int retval = 0, i; unsigned long flags; + enum mpi3mr_iocstate ioc_state; u32 host_diagnostic, timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10; union mpi3mr_trigger_data trigger_data; @@ -5462,7 +5465,6 @@ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc, mrioc->io_admin_reset_sync = 1; if (snapdump) { - mpi3mr_set_diagsave(mrioc); retval = mpi3mr_issue_reset(mrioc, MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason); if (!retval) { @@ -5564,8 +5566,13 @@ out: if (mrioc->pel_enabled) atomic64_inc(&event_counter); } else { - mpi3mr_issue_reset(mrioc, - MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason); + dprint_reset(mrioc, + "soft_reset_handler failed, marking controller as unrecoverable\n"); + ioc_state = mpi3mr_get_iocstate(mrioc); + + if (ioc_state != MRIOC_STATE_FAULT) + mpi3mr_issue_reset(mrioc, + MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason); mrioc->device_refresh_on = 0; mrioc->unrecoverable = 1; mrioc->reset_in_progress = 0; From c273c14b0294f11ce45afc4da2e8f91ab3f07270 Mon Sep 17 00:00:00 2001 From: Ranjan Kumar Date: Fri, 16 Jan 2026 11:37:15 +0530 Subject: [PATCH 62/78] scsi: mpi3mr: Use negotiated link rate from DevicePage0 Firmware populates the negotiated SAS link rate in DevicePage0 during device discovery. Update mpi3mr to cache this value while initializing the target device. When available, the cached link rate is used instead of issuing additional SAS PHY or expander PHY page reads. If the DevicePage0 value is missing or invalid, the driver falls back to the existing PHY-based mechanism. Signed-off-by: Ranjan Kumar Link: https://patch.msgid.link/20260116060719.32937-5-ranjan.kumar@broadcom.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h | 2 + drivers/scsi/mpi3mr/mpi3mr.h | 2 + drivers/scsi/mpi3mr/mpi3mr_os.c | 89 ++++++++++++++++++++++++++ drivers/scsi/mpi3mr/mpi3mr_transport.c | 30 +++++---- 4 files changed, 111 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h b/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h index 8c8bfbbdd34e..67d72b82cbe0 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h @@ -2314,6 +2314,8 @@ struct mpi3_device0_sas_sata_format { u8 attached_phy_identifier; u8 max_port_connections; u8 zone_group; + u8 reserved10[3]; + u8 negotiated_link_rate; }; #define MPI3_DEVICE0_SASSATA_FLAGS_WRITE_SAME_UNMAP_NCQ (0x0400) diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index 611a51a353c9..590c017acf25 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -643,6 +643,7 @@ struct mpi3mr_enclosure_node { * @dev_info: Device information bits * @phy_id: Phy identifier provided in device page 0 * @attached_phy_id: Attached phy identifier provided in device page 0 + * @negotiated_link_rate: Negotiated link rate from device page 0 * @sas_transport_attached: Is this device exposed to transport * @pend_sas_rphy_add: Flag to check device is in process of add * @hba_port: HBA port entry @@ -654,6 +655,7 @@ struct tgt_dev_sas_sata { u16 dev_info; u8 phy_id; u8 attached_phy_id; + u8 negotiated_link_rate; u8 sas_transport_attached; u8 pend_sas_rphy_add; struct mpi3mr_hba_port *hba_port; diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index 028a3a1a6be0..2fce5bfb7204 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -1138,6 +1138,89 @@ static void mpi3mr_refresh_tgtdevs(struct mpi3mr_ioc *mrioc) } } +/** + * mpi3mr_debug_dump_devpg0 - Dump device page0 + * @mrioc: Adapter instance reference + * @dev_pg0: Device page 0. + * + * Prints pertinent details of the device page 0. + * + * Return: Nothing. + */ +static void +mpi3mr_debug_dump_devpg0(struct mpi3mr_ioc *mrioc, struct mpi3_device_page0 *dev_pg0) +{ + ioc_info(mrioc, + "device_pg0: handle(0x%04x), perst_id(%d), wwid(0x%016llx), encl_handle(0x%04x), slot(%d)\n", + le16_to_cpu(dev_pg0->dev_handle), + le16_to_cpu(dev_pg0->persistent_id), + le64_to_cpu(dev_pg0->wwid), le16_to_cpu(dev_pg0->enclosure_handle), + le16_to_cpu(dev_pg0->slot)); + ioc_info(mrioc, "device_pg0: access_status(0x%02x), flags(0x%04x), device_form(0x%02x), queue_depth(%d)\n", + dev_pg0->access_status, le16_to_cpu(dev_pg0->flags), + dev_pg0->device_form, le16_to_cpu(dev_pg0->queue_depth)); + ioc_info(mrioc, "device_pg0: parent_handle(0x%04x), iounit_port(%d)\n", + le16_to_cpu(dev_pg0->parent_dev_handle), dev_pg0->io_unit_port); + + switch (dev_pg0->device_form) { + case MPI3_DEVICE_DEVFORM_SAS_SATA: + { + + struct mpi3_device0_sas_sata_format *sasinf = + &dev_pg0->device_specific.sas_sata_format; + ioc_info(mrioc, + "device_pg0: sas_sata: sas_address(0x%016llx),flags(0x%04x),\n" + "device_info(0x%04x), phy_num(%d), attached_phy_id(%d),negotiated_link_rate(0x%02x)\n", + le64_to_cpu(sasinf->sas_address), + le16_to_cpu(sasinf->flags), + le16_to_cpu(sasinf->device_info), sasinf->phy_num, + sasinf->attached_phy_identifier, sasinf->negotiated_link_rate); + break; + } + case MPI3_DEVICE_DEVFORM_PCIE: + { + + struct mpi3_device0_pcie_format *pcieinf = + &dev_pg0->device_specific.pcie_format; + ioc_info(mrioc, + "device_pg0: pcie: port_num(%d), device_info(0x%04x), mdts(%d), page_sz(0x%02x)\n", + pcieinf->port_num, le16_to_cpu(pcieinf->device_info), + le32_to_cpu(pcieinf->maximum_data_transfer_size), + pcieinf->page_size); + ioc_info(mrioc, + "device_pg0: pcie: abort_timeout(%d), reset_timeout(%d) capabilities (0x%08x)\n", + pcieinf->nvme_abort_to, pcieinf->controller_reset_to, + le32_to_cpu(pcieinf->capabilities)); + break; + } + case MPI3_DEVICE_DEVFORM_VD: + { + + struct mpi3_device0_vd_format *vdinf = + &dev_pg0->device_specific.vd_format; + + ioc_info(mrioc, + "device_pg0: vd: state(0x%02x), raid_level(%d), flags(0x%04x),\n" + "device_info(0x%04x) abort_timeout(%d), reset_timeout(%d)\n", + vdinf->vd_state, vdinf->raid_level, + le16_to_cpu(vdinf->flags), + le16_to_cpu(vdinf->device_info), + vdinf->vd_abort_to, vdinf->vd_reset_to); + ioc_info(mrioc, + "device_pg0: vd: tg_id(%d), high(%dMiB), low(%dMiB), qd_reduction_factor(%d)\n", + vdinf->io_throttle_group, + le16_to_cpu(vdinf->io_throttle_group_high), + le16_to_cpu(vdinf->io_throttle_group_low), + ((le16_to_cpu(vdinf->flags) & + MPI3_DEVICE0_VD_FLAGS_IO_THROTTLE_GROUP_QD_MASK) >> 12)); + break; + + } + default: + break; + } +} + /** * mpi3mr_update_tgtdev - DevStatusChange evt bottomhalf * @mrioc: Adapter instance reference @@ -1159,6 +1242,10 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc, struct mpi3mr_enclosure_node *enclosure_dev = NULL; u8 prot_mask = 0; + if (mrioc->logging_level & + (MPI3_DEBUG_EVENT | MPI3_DEBUG_EVENT_WORK_TASK)) + mpi3mr_debug_dump_devpg0(mrioc, dev_pg0); + tgtdev->perst_id = le16_to_cpu(dev_pg0->persistent_id); tgtdev->dev_handle = le16_to_cpu(dev_pg0->dev_handle); tgtdev->dev_type = dev_pg0->device_form; @@ -1237,6 +1324,8 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc, tgtdev->dev_spec.sas_sata_inf.phy_id = sasinf->phy_num; tgtdev->dev_spec.sas_sata_inf.attached_phy_id = sasinf->attached_phy_identifier; + tgtdev->dev_spec.sas_sata_inf.negotiated_link_rate = + sasinf->negotiated_link_rate; if ((dev_info & MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_MASK) != MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_END_DEVICE) tgtdev->is_hidden = 1; diff --git a/drivers/scsi/mpi3mr/mpi3mr_transport.c b/drivers/scsi/mpi3mr/mpi3mr_transport.c index d70f002d6487..101161554ef1 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_transport.c +++ b/drivers/scsi/mpi3mr/mpi3mr_transport.c @@ -2284,11 +2284,11 @@ void mpi3mr_expander_remove(struct mpi3mr_ioc *mrioc, u64 sas_address, * @mrioc: Adapter instance reference * @tgtdev: Target device * - * This function identifies whether the target device is - * attached directly or through expander and issues sas phy - * page0 or expander phy page1 and gets the link rate, if there - * is any failure in reading the pages then this returns link - * rate of 1.5. + * This function first tries to use the link rate from DevicePage0 + * (populated by firmware during device discovery). If the cached + * value is not available or invalid, it falls back to reading from + * sas phy page0 or expander phy page1. + * * * Return: logical link rate. */ @@ -2301,6 +2301,14 @@ static u8 mpi3mr_get_sas_negotiated_logical_linkrate(struct mpi3mr_ioc *mrioc, u32 phynum_handle; u16 ioc_status; + /* First, try to use link rate from DevicePage0 (populated by firmware) */ + if (tgtdev->dev_spec.sas_sata_inf.negotiated_link_rate >= + MPI3_SAS_NEG_LINK_RATE_1_5) { + link_rate = tgtdev->dev_spec.sas_sata_inf.negotiated_link_rate; + goto out; + } + + /* Fallback to reading from phy pages if DevicePage0 value not available */ phy_number = tgtdev->dev_spec.sas_sata_inf.phy_id; if (!(tgtdev->devpg0_flag & MPI3_DEVICE0_FLAGS_ATT_METHOD_DIR_ATTACHED)) { phynum_handle = ((phy_number<> - MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT; + link_rate = expander_pg1.negotiated_link_rate; goto out; } if (mpi3mr_cfg_get_sas_phy_pg0(mrioc, &ioc_status, &phy_pg0, @@ -2335,11 +2341,11 @@ static u8 mpi3mr_get_sas_negotiated_logical_linkrate(struct mpi3mr_ioc *mrioc, __FILE__, __LINE__, __func__); goto out; } - link_rate = (phy_pg0.negotiated_link_rate & - MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >> - MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT; + link_rate = phy_pg0.negotiated_link_rate; + out: - return link_rate; + return ((link_rate & MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >> + MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT); } /** From d0654335d90053f0573db293b60a93d855748f83 Mon Sep 17 00:00:00 2001 From: Ranjan Kumar Date: Fri, 16 Jan 2026 11:37:16 +0530 Subject: [PATCH 63/78] scsi: mpi3mr: Update MPI Headers to revision 39 Update MPI Headers to revision 39. Signed-off-by: Ranjan Kumar Link: https://patch.msgid.link/20260116060719.32937-6-ranjan.kumar@broadcom.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h | 90 ++++++++++++++++++- drivers/scsi/mpi3mr/mpi/mpi30_image.h | 102 +++++++++++++++++++++- drivers/scsi/mpi3mr/mpi/mpi30_init.h | 2 +- drivers/scsi/mpi3mr/mpi/mpi30_ioc.h | 1 + drivers/scsi/mpi3mr/mpi/mpi30_pci.h | 2 +- drivers/scsi/mpi3mr/mpi/mpi30_sas.h | 2 +- drivers/scsi/mpi3mr/mpi/mpi30_tool.h | 6 +- drivers/scsi/mpi3mr/mpi/mpi30_transport.h | 4 +- 8 files changed, 197 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h b/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h index 67d72b82cbe0..33dd303c97bb 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* - * Copyright 2017-2023 Broadcom Inc. All rights reserved. + * Copyright 2017-2026 Broadcom Inc. All rights reserved. */ #ifndef MPI30_CNFG_H #define MPI30_CNFG_H 1 @@ -1037,6 +1037,7 @@ struct mpi3_io_unit_page5 { #define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SATA_SSD_SHIFT (2) #define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SAS_SSD_MASK (0x0003) #define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SAS_SSD_SHIFT (0) +#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_HDD_SPINDOWN_ENABLE (0x8000) #define MPI3_IOUNIT5_FLAGS_SATAPUIS_MASK (0x0c) #define MPI3_IOUNIT5_FLAGS_SATAPUIS_NOT_SUPPORTED (0x00) #define MPI3_IOUNIT5_FLAGS_SATAPUIS_OS_CONTROLLED (0x04) @@ -1074,7 +1075,8 @@ struct mpi3_io_unit_page8 { u8 current_key_encryption_algo; u8 key_digest_hash_algo; union mpi3_version_union current_svn; - __le32 reserved14; + __le16 pending_svn_time; + __le16 reserved16; __le32 current_key[128]; union mpi3_iounit8_digest digest[MPI3_IOUNIT8_DIGEST_MAX]; }; @@ -1406,6 +1408,7 @@ struct mpi3_driver_page1 { }; #define MPI3_DRIVER1_PAGEVERSION (0x00) +#define MPI3_DRIVER1_FLAGS_DEVICE_SHUTDOWN_ON_UNLOAD_DISABLE (0x0001) #ifndef MPI3_DRIVER2_TRIGGER_MAX #define MPI3_DRIVER2_TRIGGER_MAX (1) #endif @@ -1561,7 +1564,9 @@ struct mpi3_security1_key_record { u8 consumer; __le16 key_data_size; __le32 additional_key_data; - __le32 reserved08[2]; + u8 library_version; + u8 reserved09[3]; + __le32 reserved0c; union mpi3_security1_key_data key_data; }; @@ -1614,6 +1619,85 @@ struct mpi3_security_page2 { u8 reserved9d[3]; struct mpi3_security2_trusted_root trusted_root[MPI3_SECURITY2_TRUSTED_ROOT_MAX]; }; + +struct mpi3_security_page3 { + struct mpi3_config_page_header header; + __le16 key_data_length; + __le16 reserved0a; + u8 key_number; + u8 reserved0d[3]; + union mpi3_security_mac mac; + union mpi3_security_nonce nonce; + __le32 reserved90[12]; + u8 flags; + u8 consumer; + __le16 key_data_size; + __le32 additional_key_data; + u8 library_version; + u8 reserved_c9[3]; + __le32 reserved_cc; + u8 key_data[]; +}; + +#define MPI3_SECURITY3_PAGEVERSION (0x00) +#define MPI3_SECURITY3_FLAGS_TYPE_MASK (0x0f) +#define MPI3_SECURITY3_FLAGS_TYPE_SHIFT (0) +#define MPI3_SECURITY3_FLAGS_TYPE_NOT_VALID (0) +#define MPI3_SECURITY3_FLAGS_TYPE_MLDSA_PRIVATE (1) +#define MPI3_SECURITY3_FLAGS_TYPE_MLDSA_PUBLIC (2) +struct mpi3_security_page10 { + struct mpi3_config_page_header header; + __le32 reserved08[2]; + union mpi3_security_mac mac; + union mpi3_security_nonce nonce; + __le64 current_token_nonce; + __le64 previous_token_nonce; + __le32 reserved_a0[8]; + u8 diagnostic_auth_id[64]; +}; +#define MPI3_SECURITY10_PAGEVERSION (0x00) + +struct mpi3_security_page11 { + struct mpi3_config_page_header header; + u8 flags; + u8 reserved09[3]; + __le32 reserved0c; + __le32 diagnostic_token_length; + __le32 reserved14[3]; + u8 diagnostic_token[]; +}; +#define MPI3_SECURITY11_PAGEVERSION (0x00) +#define MPI3_SECURITY11_FLAGS_TOKEN_ENABLED (0x01) + +struct mpi3_security12_diag_feature { + __le32 feature_identifier; + u8 feature_size; + u8 feature_type; + __le16 reserved06; + u8 status; + u8 section; + __le16 reserved0a; + __le32 reserved0c; + u8 feature_data[64]; +}; +#define MPI3_SECURITY12_DIAG_FEATURE_STATUS_MASK (0x03) +#define MPI3_SECURITY12_DIAG_FEATURE_STATUS_SHIFT (0) +#define MPI3_SECURITY12_DIAG_FEATURE_STATUS_UNKNOWN (0x00) +#define MPI3_SECURITY12_DIAG_FEATURE_STATUS_DISABLED (0x01) +#define MPI3_SECURITY12_DIAG_FEATURE_STATUS_ENABLED (0x02) +#define MPI3_SECURITY12_DIAG_FEATURE_SECTION_PROTECTED (0x00) +#define MPI3_SECURITY12_DIAG_FEATURE_SECTION_UNPROTECTED (0x01) +#define MPI3_SECURITY12_DIAG_FEATURE_SECTION_PAYLOAD (0x02) +#define MPI3_SECURITY12_DIAG_FEATURE_SECTION_SIGNATURE (0x03) +struct mpi3_security_page12 { + struct mpi3_config_page_header header; + __le32 reserved08[2]; + u8 num_diag_features; + u8 reserved11[3]; + __le32 reserved14[3]; + struct mpi3_security12_diag_feature diag_feature[]; +}; + #define MPI3_SECURITY2_PAGEVERSION (0x00) struct mpi3_sas_io_unit0_phy_data { u8 io_unit_port; diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_image.h b/drivers/scsi/mpi3mr/mpi/mpi30_image.h index 8d824107a678..62ddf094d46c 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_image.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_image.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* - * Copyright 2018-2023 Broadcom Inc. All rights reserved. + * Copyright 2018-2026 Broadcom Inc. All rights reserved. */ #ifndef MPI30_IMAGE_H #define MPI30_IMAGE_H 1 @@ -135,7 +135,7 @@ struct mpi3_ci_manifest_mpi { __le32 package_version_string_offset; __le32 package_build_date_string_offset; __le32 package_build_time_string_offset; - __le32 reserved4c; + __le32 diag_authorization_key_offset; __le32 diag_authorization_identifier[16]; struct mpi3_ci_manifest_mpi_comp_image_ref component_image_ref[MPI3_CI_MANIFEST_MPI_MAX]; }; @@ -148,16 +148,112 @@ struct mpi3_ci_manifest_mpi { #define MPI3_CI_MANIFEST_MPI_RELEASE_LEVEL_GCA (0x50) #define MPI3_CI_MANIFEST_MPI_RELEASE_LEVEL_POINT (0x60) #define MPI3_CI_MANIFEST_MPI_FLAGS_DIAG_AUTHORIZATION (0x01) +#define MPI3_CI_MANIFEST_MPI_FLAGS_DIAG_AUTH_ANCHOR_MASK (0x06) +#define MPI3_CI_MANIFEST_MPI_FLAGS_DIAG_AUTH_ANCHOR_SHIFT (1) +#define MPI3_CI_MANIFEST_MPI_FLAGS_DIAG_AUTH_ANCHOR_IDENTIFIER (0x00) +#define MPI3_CI_MANIFEST_MPI_FLAGS_DIAG_AUTH_ANCHOR_KEY_OFFSET (0x02) #define MPI3_CI_MANIFEST_MPI_SUBSYSTEMID_IGNORED (0xffff) #define MPI3_CI_MANIFEST_MPI_PKG_VER_STR_OFF_UNSPECIFIED (0x00000000) #define MPI3_CI_MANIFEST_MPI_PKG_BUILD_DATE_STR_OFF_UNSPECIFIED (0x00000000) #define MPI3_CI_MANIFEST_MPI_PKG_BUILD_TIME_STR_OFF_UNSPECIFIED (0x00000000) + +struct mpi3_sb_manifest_ci_digest { + __le32 signature1; + __le32 reserved04[2]; + u8 hash_algorithm; + u8 reserved09[3]; + struct mpi3_comp_image_version component_image_version; + __le32 component_image_version_string_offset; + __le32 digest[16]; +}; + +struct mpi3_sb_manifest_ci_ref_element { + u8 num_ci_digests; + u8 reserved01[3]; + struct mpi3_sb_manifest_ci_digest ci_digest[]; +}; + +struct mpi3_sb_manifest_embedded_key_element { + __le32 reserved00[3]; + u8 key_algorithm; + u8 flags; + __le16 public_key_size; + __le32 start_tag; + __le32 public_key[]; +}; + +#define MPI3_SB_MANIFEST_EMBEDDED_KEY_FLAGS_KEYINDEX_MASK (0x03) +#define MPI3_SB_MANIFEST_EMBEDDED_KEY_FLAGS_KEYINDEX_STRT (0x00) +#define MPI3_SB_MANIFEST_EMBEDDED_KEY_FLAGS_KEYINDEX_K2GO (0x01) +#define MPI3_SB_MANIFEST_EMBEDDED_KEY_STARTTAG_STRT (0x54525453) +#define MPI3_SB_MANIFEST_EMBEDDED_KEY_STARTTAG_K2GO (0x4f47324b) +#define MPI3_SB_MANIFEST_EMBEDDED_KEY_ENDTAG_STOP (0x504f5453) +#define MPI3_SB_MANIFEST_EMBEDDED_KEY_ENDTAG_K2ST (0x5453324b) + +struct mpi3_sb_manifest_diag_key_element { + __le32 reserved00[3]; + u8 key_algorithm; + u8 flags; + __le16 public_key_size; + __le32 public_key[]; +}; + +#define MPI3_SB_MANIFEST_DIAG_KEY_FLAGS_KEYINDEX_MASK (0x03) +#define MPI3_SB_MANIFEST_DIAG_KEY_FLAGS_KEYSELECT_FW_KEY (0x04) +union mpi3_sb_manifest_element_data { + struct mpi3_sb_manifest_ci_ref_element ci_ref; + struct mpi3_sb_manifest_embedded_key_element embed_key; + struct mpi3_sb_manifest_diag_key_element diag_key; + __le32 dword; +}; +struct mpi3_sb_manifest_element { + u8 manifest_element_form; + u8 reserved01[3]; + union mpi3_sb_manifest_element_data form_specific[]; +}; +#define MPI3_SB_MANIFEST_ELEMENT_FORM_CI_REFS (0x01) +#define MPI3_SB_MANIFEST_ELEMENT_FORM_EMBED_KEY (0x02) +#define MPI3_SB_MANIFEST_ELEMENT_FORM_DIAG_KEY (0x03) +struct mpi3_sb_manifest_mpi { + u8 manifest_type; + u8 reserved01[3]; + __le32 reserved04[3]; + u8 reserved10; + u8 release_level; + __le16 reserved12; + __le16 reserved14; + __le16 flags; + __le32 reserved18[2]; + __le16 vendor_id; + __le16 device_id; + __le16 subsystem_vendor_id; + __le16 subsystem_id; + __le32 reserved28[2]; + union mpi3_version_union package_security_version; + __le32 reserved34; + struct mpi3_comp_image_version package_version; + __le32 package_version_string_offset; + __le32 package_build_date_string_offset; + __le32 package_build_time_string_offset; + __le32 component_image_references_offset; + __le32 embedded_key0offset; + __le32 embedded_key1offset; + __le32 diag_authorization_key_offset; + __le32 reserved5c[9]; + struct mpi3_sb_manifest_element manifest_elements[]; +}; + union mpi3_ci_manifest { struct mpi3_ci_manifest_mpi mpi; + struct mpi3_sb_manifest_mpi sb_mpi; __le32 dword[1]; }; -#define MPI3_CI_MANIFEST_TYPE_MPI (0x00) +#define MPI3_SB_MANIFEST_APU_IMMEDIATE_DEFER_APU_ENABLE (0x01) + +#define MPI3_CI_MANIFEST_TYPE_MPI (0x00) +#define MPI3_CI_MANIFEST_TYPE_SB (0x01) + struct mpi3_extended_image_header { u8 image_type; u8 reserved01[3]; diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_init.h b/drivers/scsi/mpi3mr/mpi/mpi30_init.h index bbef5bac92ed..745e1101ebf4 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_init.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_init.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* - * Copyright 2016-2023 Broadcom Inc. All rights reserved. + * Copyright 2016-2026 Broadcom Inc. All rights reserved. */ #ifndef MPI30_INIT_H #define MPI30_INIT_H 1 diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h b/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h index b42933fcd423..76dc18684be1 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h @@ -661,6 +661,7 @@ struct mpi3_event_data_diag_buffer_status_change { #define MPI3_EVENT_DIAG_BUFFER_STATUS_CHANGE_RC_RELEASED (0x01) #define MPI3_EVENT_DIAG_BUFFER_STATUS_CHANGE_RC_PAUSED (0x02) #define MPI3_EVENT_DIAG_BUFFER_STATUS_CHANGE_RC_RESUMED (0x03) +#define MPI3_EVENT_DIAG_BUFFER_STATUS_CHANGE_RC_CLEARED (0x04) #define MPI3_PEL_LOCALE_FLAGS_NON_BLOCKING_BOOT_EVENT (0x0200) #define MPI3_PEL_LOCALE_FLAGS_BLOCKING_BOOT_EVENT (0x0100) #define MPI3_PEL_LOCALE_FLAGS_PCIE (0x0080) diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_pci.h b/drivers/scsi/mpi3mr/mpi/mpi30_pci.h index 4eeb11c3c73e..3092dfe6d952 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_pci.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_pci.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* - * Copyright 2016-2023 Broadcom Inc. All rights reserved. + * Copyright 2016-2026 Broadcom Inc. All rights reserved. * */ #ifndef MPI30_PCI_H diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_sas.h b/drivers/scsi/mpi3mr/mpi/mpi30_sas.h index 190b06508b00..f86da445df1e 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_sas.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_sas.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* - * Copyright 2016-2023 Broadcom Inc. All rights reserved. + * Copyright 2016-2026 Broadcom Inc. All rights reserved. */ #ifndef MPI30_SAS_H #define MPI30_SAS_H 1 diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_tool.h b/drivers/scsi/mpi3mr/mpi/mpi30_tool.h index 50a65b16a818..72d3e6bc52ec 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_tool.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_tool.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* - * Copyright 2016-2024 Broadcom Inc. All rights reserved. + * Copyright 2016-2026 Broadcom Inc. All rights reserved. */ #ifndef MPI30_TOOL_H #define MPI30_TOOL_H 1 @@ -8,6 +8,10 @@ #define MPI3_DIAG_BUFFER_TYPE_TRACE (0x01) #define MPI3_DIAG_BUFFER_TYPE_FW (0x02) #define MPI3_DIAG_BUFFER_ACTION_RELEASE (0x01) +#define MPI3_DIAG_BUFFER_ACTION_PAUSE (0x02) +#define MPI3_DIAG_BUFFER_ACTION_RESUME (0x03) +#define MPI3_DIAG_BUFFER_ACTION_CLEAR (0x04) + #define MPI3_DIAG_BUFFER_POST_MSGFLAGS_SEGMENTED (0x01) struct mpi3_diag_buffer_post_request { diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_transport.h b/drivers/scsi/mpi3mr/mpi/mpi30_transport.h index 28ab2efb3baa..290a1f5c2924 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_transport.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_transport.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* - * Copyright 2016-2023 Broadcom Inc. All rights reserved. + * Copyright 2016-2026 Broadcom Inc. All rights reserved. */ #ifndef MPI30_TRANSPORT_H #define MPI30_TRANSPORT_H 1 @@ -18,7 +18,7 @@ union mpi3_version_union { #define MPI3_VERSION_MAJOR (3) #define MPI3_VERSION_MINOR (0) -#define MPI3_VERSION_UNIT (37) +#define MPI3_VERSION_UNIT (39) #define MPI3_VERSION_DEV (0) #define MPI3_DEVHANDLE_INVALID (0xffff) struct mpi3_sysif_oper_queue_indexes { From ec54b348f274fdd2bd32bbe74de6d62ae1a10a18 Mon Sep 17 00:00:00 2001 From: Ranjan Kumar Date: Fri, 16 Jan 2026 11:37:17 +0530 Subject: [PATCH 64/78] scsi: mpi3mr: Record and report controller firmware faults Capture and retain firmware fault codes and extended fault information whenever the controller enters a fault state. Maintain a persistent firmware fault counter, expose it via sysfs, and generate uevents to aid userspace diagnostics and failure analysis. Co-developed-by: Salomon Dushimirimana Signed-off-by: Salomon Dushimirimana Signed-off-by: Ranjan Kumar Link: https://patch.msgid.link/20260116060719.32937-7-ranjan.kumar@broadcom.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr.h | 8 +++ drivers/scsi/mpi3mr/mpi3mr_app.c | 24 +++++++ drivers/scsi/mpi3mr/mpi3mr_fw.c | 103 +++++++++++++++++++++++++++++++ 3 files changed, 135 insertions(+) diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index 590c017acf25..58db60e13c13 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -1137,6 +1137,10 @@ struct scmd_priv { * @default_qcount: Total Default queues * @active_poll_qcount: Currently active poll queue count * @requested_poll_qcount: User requested poll queue count + * @fault_during_init: Indicates a firmware fault occurred during initialization + * @saved_fault_code: Firmware fault code captured at the time of failure + * @saved_fault_info: Additional firmware-provided fault information + * @fwfault_counter: Count of firmware faults detected by the driver * @bsg_dev: BSG device structure * @bsg_queue: Request queue for BSG device * @stop_bsgs: Stop BSG request flag @@ -1340,6 +1344,10 @@ struct mpi3mr_ioc { u16 default_qcount; u16 active_poll_qcount; u16 requested_poll_qcount; + u8 fault_during_init; + u32 saved_fault_code; + u32 saved_fault_info[3]; + u64 fwfault_counter; struct device bsg_dev; struct request_queue *bsg_queue; diff --git a/drivers/scsi/mpi3mr/mpi3mr_app.c b/drivers/scsi/mpi3mr/mpi3mr_app.c index 37cca0573ddc..1353a8ff9c85 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_app.c +++ b/drivers/scsi/mpi3mr/mpi3mr_app.c @@ -3255,6 +3255,29 @@ adp_state_show(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR_RO(adp_state); +/** + * fwfault_count_show() - SysFS callback to show firmware fault count + * @dev: class device + * @attr: Device attribute + * @buf: Buffer to copy data into + * + * Displays the total number of firmware faults detected by the driver + * since the controller was initialized. + * + * Return: Number of bytes written to @buf + */ + +static ssize_t +fwfault_count_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct mpi3mr_ioc *mrioc = shost_priv(shost); + + return snprintf(buf, PAGE_SIZE, "%llu\n", mrioc->fwfault_counter); +} +static DEVICE_ATTR_RO(fwfault_count); + static struct attribute *mpi3mr_host_attrs[] = { &dev_attr_version_fw.attr, &dev_attr_fw_queue_depth.attr, @@ -3263,6 +3286,7 @@ static struct attribute *mpi3mr_host_attrs[] = { &dev_attr_reply_qfull_count.attr, &dev_attr_logging_level.attr, &dev_attr_adp_state.attr, + &dev_attr_fwfault_count.attr, NULL, }; diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index 178738850541..0d7515e7144b 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -1108,6 +1108,31 @@ void mpi3mr_print_fault_info(struct mpi3mr_ioc *mrioc) } } +/** + * mpi3mr_save_fault_info - Save fault information + * @mrioc: Adapter instance reference + * + * Save the controller fault information if there is a + * controller fault. + * + * Return: Nothing. + */ +static void mpi3mr_save_fault_info(struct mpi3mr_ioc *mrioc) +{ + u32 ioc_status, i; + + ioc_status = readl(&mrioc->sysif_regs->ioc_status); + + if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) { + mrioc->saved_fault_code = readl(&mrioc->sysif_regs->fault) & + MPI3_SYSIF_FAULT_CODE_MASK; + for (i = 0; i < 3; i++) { + mrioc->saved_fault_info[i] = + readl(&mrioc->sysif_regs->fault_info[i]); + } + } +} + /** * mpi3mr_get_iocstate - Get IOC State * @mrioc: Adapter instance reference @@ -1249,6 +1274,60 @@ out_failed: mpi3mr_free_ioctl_dma_memory(mrioc); } +/** + * mpi3mr_fault_uevent_emit - Emit uevent for any controller + * fault + * @mrioc: Pointer to the mpi3mr_ioc structure for the controller instance + * + * This function is invoked when the controller undergoes any + * type of fault. + */ + +static void mpi3mr_fault_uevent_emit(struct mpi3mr_ioc *mrioc) +{ + struct kobj_uevent_env *env; + int ret; + + env = kzalloc(sizeof(*env), GFP_KERNEL); + if (!env) + return; + + ret = add_uevent_var(env, "DRIVER=%s", mrioc->driver_name); + if (ret) + goto out_free; + + ret = add_uevent_var(env, "IOC_ID=%u", mrioc->id); + if (ret) + goto out_free; + + ret = add_uevent_var(env, "FAULT_CODE=0x%08x", + mrioc->saved_fault_code); + if (ret) + goto out_free; + + ret = add_uevent_var(env, "FAULT_INFO0=0x%08x", + mrioc->saved_fault_info[0]); + if (ret) + goto out_free; + + ret = add_uevent_var(env, "FAULT_INFO1=0x%08x", + mrioc->saved_fault_info[1]); + if (ret) + goto out_free; + + ret = add_uevent_var(env, "FAULT_INFO2=0x%08x", + mrioc->saved_fault_info[2]); + if (ret) + goto out_free; + + kobject_uevent_env(&mrioc->shost->shost_gendev.kobj, + KOBJ_CHANGE, env->envp); + +out_free: + kfree(env); + +} + /** * mpi3mr_clear_reset_history - clear reset history * @mrioc: Adapter instance reference @@ -1480,6 +1559,10 @@ retry_bring_ioc_ready: if (ioc_state == MRIOC_STATE_FAULT) { timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10; mpi3mr_print_fault_info(mrioc); + mpi3mr_save_fault_info(mrioc); + mrioc->fault_during_init = 1; + mrioc->fwfault_counter++; + do { host_diagnostic = readl(&mrioc->sysif_regs->host_diagnostic); @@ -2577,6 +2660,9 @@ void mpi3mr_check_rh_fault_ioc(struct mpi3mr_ioc *mrioc, u32 reason_code) mpi3mr_set_trigger_data_in_all_hdb(mrioc, MPI3MR_HDB_TRIGGER_TYPE_FAULT, &trigger_data, 0); mpi3mr_print_fault_info(mrioc); + mpi3mr_save_fault_info(mrioc); + mrioc->fault_during_init = 1; + mrioc->fwfault_counter++; return; } @@ -2594,6 +2680,10 @@ void mpi3mr_check_rh_fault_ioc(struct mpi3mr_ioc *mrioc, u32 reason_code) break; msleep(100); } while (--timeout); + + mpi3mr_save_fault_info(mrioc); + mrioc->fault_during_init = 1; + mrioc->fwfault_counter++; } /** @@ -2770,6 +2860,11 @@ static void mpi3mr_watchdog_work(struct work_struct *work) union mpi3mr_trigger_data trigger_data; u16 reset_reason = MPI3MR_RESET_FROM_FAULT_WATCH; + if (mrioc->fault_during_init) { + mpi3mr_fault_uevent_emit(mrioc); + mrioc->fault_during_init = 0; + } + if (mrioc->reset_in_progress || mrioc->pci_err_recovery) return; @@ -2842,6 +2937,10 @@ static void mpi3mr_watchdog_work(struct work_struct *work) goto schedule_work; } + mpi3mr_save_fault_info(mrioc); + mpi3mr_fault_uevent_emit(mrioc); + mrioc->fwfault_counter++; + switch (trigger_data.fault) { case MPI3_SYSIF_FAULT_CODE_COMPLETE_RESET_NEEDED: case MPI3_SYSIF_FAULT_CODE_POWER_CYCLE_REQUIRED: @@ -5478,6 +5577,10 @@ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc, break; msleep(100); } while (--timeout); + + mpi3mr_save_fault_info(mrioc); + mpi3mr_fault_uevent_emit(mrioc); + mrioc->fwfault_counter++; mpi3mr_set_trigger_data_in_all_hdb(mrioc, MPI3MR_HDB_TRIGGER_TYPE_FAULT, &trigger_data, 0); } From 8612d94348f4209b71917b771f24c0013aed6a29 Mon Sep 17 00:00:00 2001 From: Ranjan Kumar Date: Fri, 16 Jan 2026 11:37:18 +0530 Subject: [PATCH 65/78] scsi: mpi3mr: Fixed the W=1 compilation warning Fixed W=1 compilation warnings Signed-off-by: Ranjan Kumar Link: https://patch.msgid.link/20260116060719.32937-8-ranjan.kumar@broadcom.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr_fw.c | 6 +++--- drivers/scsi/mpi3mr/mpi3mr_os.c | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index 0d7515e7144b..1b0fcaf6369a 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -776,8 +776,8 @@ static inline int mpi3mr_request_irq(struct mpi3mr_ioc *mrioc, u16 index) intr_info->msix_index = index; intr_info->op_reply_q = NULL; - snprintf(intr_info->name, MPI3MR_NAME_LENGTH, "%s%d-msix%d", - mrioc->driver_name, mrioc->id, index); + scnprintf(intr_info->name, MPI3MR_NAME_LENGTH, + "%.32s%d-msix%u", mrioc->driver_name, mrioc->id, index); #ifndef CONFIG_PREEMPT_RT retval = request_threaded_irq(pci_irq_vector(pdev, index), mpi3mr_isr, @@ -1789,7 +1789,7 @@ static int mpi3mr_issue_reset(struct mpi3mr_ioc *mrioc, u16 reset_type, scratch_pad0 = ((MPI3MR_RESET_REASON_OSTYPE_LINUX << MPI3MR_RESET_REASON_OSTYPE_SHIFT) | (mrioc->facts.ioc_num << MPI3MR_RESET_REASON_IOCNUM_SHIFT) | reset_reason); - writel(reset_reason, &mrioc->sysif_regs->scratchpad[0]); + writel(scratch_pad0, &mrioc->sysif_regs->scratchpad[0]); if (reset_type == MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT) mpi3mr_set_diagsave(mrioc); writel(host_diagnostic | reset_type, diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index 2fce5bfb7204..3b46275788c6 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -5475,8 +5475,10 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (retval < 0) goto id_alloc_failed; mrioc->id = (u8)retval; - sprintf(mrioc->driver_name, "%s", MPI3MR_DRIVER_NAME); - sprintf(mrioc->name, "%s%d", mrioc->driver_name, mrioc->id); + strscpy(mrioc->driver_name, MPI3MR_DRIVER_NAME, + sizeof(mrioc->driver_name)); + scnprintf(mrioc->name, sizeof(mrioc->name), + "%s%u", mrioc->driver_name, mrioc->id); INIT_LIST_HEAD(&mrioc->list); spin_lock(&mrioc_list_lock); list_add_tail(&mrioc->list, &mrioc_list); From 943e9049e84a8ff379534ed8945a929cec722a5a Mon Sep 17 00:00:00 2001 From: Ranjan Kumar Date: Fri, 16 Jan 2026 11:37:19 +0530 Subject: [PATCH 66/78] scsi: mpi3mr: Driver version update to 8.17.0.3.50 Update driver version to 8.17.0.3.50 Signed-off-by: Ranjan Kumar Link: https://patch.msgid.link/20260116060719.32937-9-ranjan.kumar@broadcom.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index 58db60e13c13..3c70f570ee0c 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -56,8 +56,8 @@ extern struct list_head mrioc_list; extern int prot_mask; extern atomic64_t event_counter; -#define MPI3MR_DRIVER_VERSION "8.15.0.5.51" -#define MPI3MR_DRIVER_RELDATE "18-November-2025" +#define MPI3MR_DRIVER_VERSION "8.17.0.3.50" +#define MPI3MR_DRIVER_RELDATE "09-January-2026" #define MPI3MR_DRIVER_NAME "mpi3mr" #define MPI3MR_DRIVER_LICENSE "GPL" From 267345b6d1dc3467c5d57d6bbe833107baa00dbc Mon Sep 17 00:00:00 2001 From: Marco Crivellari Date: Tue, 13 Jan 2026 15:57:09 +0100 Subject: [PATCH 67/78] scsi: qla4xxx: Add WQ_PERCPU to alloc_workqueue() users MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This continues the effort to refactor workqueue APIs, which began with the introduction of new workqueues and a new alloc_workqueue() flag in: commit 128ea9f6ccfb ("workqueue: Add system_percpu_wq and system_dfl_wq") commit 930c2ea566af ("workqueue: Add new WQ_PERCPU flag") The refactoring is going to alter the default behavior of alloc_workqueue() to be unbound by default. With the introduction of the WQ_PERCPU flag (equivalent to !WQ_UNBOUND), any alloc_workqueue() caller that doesn’t explicitly specify WQ_UNBOUND must now use WQ_PERCPU. For more details see the Link tag below. In order to keep alloc_workqueue() behavior identical, explicitly request WQ_PERCPU. Link: https://lore.kernel.org/all/20250221112003.1dSuoGyc@linutronix.de/ Suggested-by: Tejun Heo Signed-off-by: Marco Crivellari Link: https://patch.msgid.link/20260113145711.242316-2-marco.crivellari@suse.com Signed-off-by: Martin K. Petersen --- drivers/scsi/qla4xxx/ql4_os.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 97329c97332f..125967e5c548 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -8819,7 +8819,7 @@ skip_retry_init: } INIT_WORK(&ha->dpc_work, qla4xxx_do_dpc); - ha->task_wq = alloc_workqueue("qla4xxx_%lu_task", WQ_MEM_RECLAIM, 1, + ha->task_wq = alloc_workqueue("qla4xxx_%lu_task", WQ_MEM_RECLAIM | WQ_PERCPU, 1, ha->host_no); if (!ha->task_wq) { ql4_printk(KERN_WARNING, ha, "Unable to start task thread!\n"); From e4c7c844fae0ebfae6e84ae0dab135306ba4da1b Mon Sep 17 00:00:00 2001 From: Marco Crivellari Date: Tue, 13 Jan 2026 15:57:10 +0100 Subject: [PATCH 68/78] scsi: qla2xxx: Add WQ_PERCPU to alloc_workqueue() users MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This continues the effort to refactor workqueue APIs, which began with the introduction of new workqueues and a new alloc_workqueue() flag in: commit 128ea9f6ccfb ("workqueue: Add system_percpu_wq and system_dfl_wq") commit 930c2ea566af ("workqueue: Add new WQ_PERCPU flag") The refactoring is going to alter the default behavior of alloc_workqueue() to be unbound by default. With the introduction of the WQ_PERCPU flag (equivalent to !WQ_UNBOUND), any alloc_workqueue() caller that doesn’t explicitly specify WQ_UNBOUND must now use WQ_PERCPU. For more details see the Link tag below. In order to keep alloc_workqueue() behavior identical, explicitly request WQ_PERCPU. Link: https://lore.kernel.org/all/20250221112003.1dSuoGyc@linutronix.de/ Suggested-by: Tejun Heo Signed-off-by: Marco Crivellari Link: https://patch.msgid.link/20260113145711.242316-3-marco.crivellari@suse.com Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/tcm_qla2xxx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 2fff68935338..b00ae7a664da 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -1901,7 +1901,7 @@ static int tcm_qla2xxx_register_configfs(void) goto out_fabric; tcm_qla2xxx_free_wq = alloc_workqueue("tcm_qla2xxx_free", - WQ_MEM_RECLAIM, 0); + WQ_MEM_RECLAIM | WQ_PERCPU, 0); if (!tcm_qla2xxx_free_wq) { ret = -ENOMEM; goto out_fabric_npiv; From e6b42979ea61370a2046bacee63e6ec0ac033280 Mon Sep 17 00:00:00 2001 From: Marco Crivellari Date: Tue, 13 Jan 2026 15:57:11 +0100 Subject: [PATCH 69/78] scsi: qla2xxx: target: Add WQ_PERCPU to alloc_workqueue() users MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This continues the effort to refactor workqueue APIs, which began with the introduction of new workqueues and a new alloc_workqueue() flag in: commit 128ea9f6ccfb ("workqueue: Add system_percpu_wq and system_dfl_wq") commit 930c2ea566af ("workqueue: Add new WQ_PERCPU flag") The refactoring is going to alter the default behavior of alloc_workqueue() to be unbound by default. With the introduction of the WQ_PERCPU flag (equivalent to !WQ_UNBOUND), any alloc_workqueue() caller that doesn’t explicitly specify WQ_UNBOUND must now use WQ_PERCPU. For more details see the Link tag below. In order to keep alloc_workqueue() behavior identical, explicitly request WQ_PERCPU. Link: https://lore.kernel.org/all/20250221112003.1dSuoGyc@linutronix.de/ Suggested-by: Tejun Heo Signed-off-by: Marco Crivellari Link: https://patch.msgid.link/20260113145711.242316-4-marco.crivellari@suse.com Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_target.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index d772136984c9..ef3a5fac2b48 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -8390,7 +8390,7 @@ int __init qlt_init(void) goto out_plogi_cachep; } - qla_tgt_wq = alloc_workqueue("qla_tgt_wq", 0, 0); + qla_tgt_wq = alloc_workqueue("qla_tgt_wq", WQ_PERCPU, 0); if (!qla_tgt_wq) { ql_log(ql_log_fatal, NULL, 0xe06f, "alloc_workqueue for qla_tgt_wq failed\n"); From 4d0538dd5d7e21b4615fbc81424b0fae0b12a9fb Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 16 Jan 2026 10:07:51 -0800 Subject: [PATCH 70/78] scsi: ufs: core: Use a host-wide tagset in SDB mode In single-doorbell (SDB) mode there is only a single request queue. Hence, it doesn't matter whether or not the SCSI host tagset is configured as host-wide. Configure the host tagset as host-wide in SDB mode because this enables a simplification of the hot path. Signed-off-by: Bart Van Assche Reviewed-by: Peter Wang Link: https://patch.msgid.link/20260116180800.3085233-1-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufs-mcq.c | 2 -- drivers/ufs/core/ufshcd-priv.h | 7 +------ drivers/ufs/core/ufshcd.c | 1 + 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/ufs/core/ufs-mcq.c b/drivers/ufs/core/ufs-mcq.c index 64c234096e23..18a95b728633 100644 --- a/drivers/ufs/core/ufs-mcq.c +++ b/drivers/ufs/core/ufs-mcq.c @@ -444,7 +444,6 @@ EXPORT_SYMBOL_GPL(ufshcd_mcq_config_esi); int ufshcd_mcq_init(struct ufs_hba *hba) { - struct Scsi_Host *host = hba->host; struct ufs_hw_queue *hwq; int ret, i; @@ -478,7 +477,6 @@ int ufshcd_mcq_init(struct ufs_hba *hba) mutex_init(&hwq->sq_mutex); } - host->host_tagset = 1; return 0; } diff --git a/drivers/ufs/core/ufshcd-priv.h b/drivers/ufs/core/ufshcd-priv.h index 4259f499382f..7d6d19361af9 100644 --- a/drivers/ufs/core/ufshcd-priv.h +++ b/drivers/ufs/core/ufshcd-priv.h @@ -374,12 +374,7 @@ static inline bool ufs_is_valid_unit_desc_lun(struct ufs_dev_info *dev_info, u8 */ static inline struct scsi_cmnd *ufshcd_tag_to_cmd(struct ufs_hba *hba, u32 tag) { - /* - * Host-wide tags are enabled in MCQ mode only. See also the - * host->host_tagset assignment in ufs-mcq.c. - */ - struct blk_mq_tags *tags = hba->host->tag_set.shared_tags ?: - hba->host->tag_set.tags[0]; + struct blk_mq_tags *tags = hba->host->tag_set.shared_tags; struct request *rq = blk_mq_tag_to_rq(tags, tag); if (WARN_ON_ONCE(!rq)) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 0369043ca010..66223d290853 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -9321,6 +9321,7 @@ static const struct scsi_host_template ufshcd_driver_template = { .max_segment_size = PRDT_DATA_BYTE_COUNT_MAX, .max_sectors = SZ_1M / SECTOR_SIZE, .max_host_blocked = 1, + .host_tagset = true, .track_queue_depth = 1, .skip_settle_delay = 1, .sdev_groups = ufshcd_driver_groups, From 1508301d4a47212faec673d63359241146993acf Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 23 Jan 2026 12:36:53 +0100 Subject: [PATCH 71/78] scsi: efct: Use IRQF_ONESHOT and default primary handler There is no added value in efct_intr_msix() compared to irq_default_primary_handler(). Using a threaded interrupt without a dedicated primary handler mandates the IRQF_ONESHOT flag to mask the interrupt source while the threaded handler is active. Otherwise the interrupt can fire again before the threaded handler had a chance to run. Use the default primary interrupt handler by specifying NULL and set IRQF_ONESHOT so the interrupt source is masked until the secondary handler is done. Cc: Ram Vegesna Cc: James E.J. Bottomley Cc: Martin K. Petersen Cc: linux-scsi@vger.kernel.org Cc: target-devel@vger.kernel.org Fixes: 4df84e846624 ("scsi: elx: efct: Driver initialization routines") Signed-off-by: Sebastian Andrzej Siewior Link: https://patch.msgid.link/20260123113708.416727-8-bigeasy@linutronix.de Signed-off-by: Martin K. Petersen --- drivers/scsi/elx/efct/efct_driver.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/scsi/elx/efct/efct_driver.c b/drivers/scsi/elx/efct/efct_driver.c index 1bd42f7db177..528399f725d4 100644 --- a/drivers/scsi/elx/efct/efct_driver.c +++ b/drivers/scsi/elx/efct/efct_driver.c @@ -415,12 +415,6 @@ efct_intr_thread(int irq, void *handle) return IRQ_HANDLED; } -static irqreturn_t -efct_intr_msix(int irq, void *handle) -{ - return IRQ_WAKE_THREAD; -} - static int efct_setup_msix(struct efct *efct, u32 num_intrs) { @@ -450,7 +444,7 @@ efct_setup_msix(struct efct *efct, u32 num_intrs) intr_ctx->index = i; rc = request_threaded_irq(pci_irq_vector(efct->pci, i), - efct_intr_msix, efct_intr_thread, 0, + NULL, efct_intr_thread, IRQF_ONESHOT, EFCT_DRIVER_NAME, intr_ctx); if (rc) { dev_err(&efct->pci->dev, From f8ef441811ec413717f188f63d99182f30f0f08e Mon Sep 17 00:00:00 2001 From: Thomas Yen Date: Fri, 30 Jan 2026 00:51:51 +0800 Subject: [PATCH 72/78] scsi: ufs: core: Flush exception handling work when RPM level is zero Ensure that the exception event handling work is explicitly flushed during suspend when the runtime power management level is set to UFS_PM_LVL_0. When the RPM level is zero, the device power mode and link state both remain active. Previously, the UFS core driver bypassed flushing exception event handling jobs in this configuration. This created a race condition where the driver could attempt to access the host controller to handle an exception after the system had already entered a deep power-down state, resulting in a system crash. Explicitly flush this work and disable auto BKOPs before the suspend callback proceeds. This guarantees that pending exception tasks complete and prevents illegal hardware access during the power-down sequence. Fixes: 57d104c153d3 ("ufs: add UFS power management support") Signed-off-by: Thomas Yen Cc: Stable Tree Reviewed-by: Peter Wang Reviewed-by: Bart Van Assche Link: https://patch.msgid.link/20260129165156.956601-1-thomasyen@google.com Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 66223d290853..8349fe2090db 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -9998,6 +9998,8 @@ static int __ufshcd_wl_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) if (req_dev_pwr_mode == UFS_ACTIVE_PWR_MODE && req_link_state == UIC_LINK_ACTIVE_STATE) { + ufshcd_disable_auto_bkops(hba); + flush_work(&hba->eeh_work); goto vops_suspend; } From 21a16f0f02263db5a1bc4739036abca698b8808f Mon Sep 17 00:00:00 2001 From: Guixin Liu Date: Fri, 30 Jan 2026 16:02:07 +0800 Subject: [PATCH 73/78] scsi: mpi3mr: Make driver probing asynchronous Speed up the boot process by using the asynchronous probing feature supported by the kernel. Set the PROBE_PREFER_ASYNCHRONOUS flag in the device_driver structure so that the driver core probes in parallel. Signed-off-by: Guixin Liu Reviewed-by: Damien Le Moal Link: https://patch.msgid.link/20260130080207.90053-1-kanie@linux.alibaba.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr_os.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index e697ae6b7871..8e5abf620718 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -6079,7 +6079,10 @@ static struct pci_driver mpi3mr_pci_driver = { .remove = mpi3mr_remove, .shutdown = mpi3mr_shutdown, .err_handler = &mpi3mr_err_handler, - .driver.pm = &mpi3mr_pm_ops, + .driver = { + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + .pm = &mpi3mr_pm_ops, + }, }; static ssize_t event_counter_show(struct device_driver *dd, char *buf) From 41b37312bd9722af77ec7817ccf22d7a4880c289 Mon Sep 17 00:00:00 2001 From: Zilin Guan Date: Sat, 31 Jan 2026 09:36:41 +0000 Subject: [PATCH 74/78] scsi: smartpqi: Fix memory leak in pqi_report_phys_luns() pqi_report_phys_luns() fails to release the rpl_list buffer when encountering an unsupported data format or when the allocation for rpl_16byte_wwid_list fails. These early returns bypass the cleanup logic, leading to memory leaks. Consolidate the error handling by adding an out_free_rpl_list label and use goto statements to ensure rpl_list is consistently freed on failure. Compile tested only. Issue found using a prototype static analysis tool and code review. Fixes: 28ca6d876c5a ("scsi: smartpqi: Add extended report physical LUNs") Signed-off-by: Zilin Guan Tested-by: Don Brace Acked-by: Don Brace Link: https://patch.msgid.link/20260131093641.1008117-1-zilin@seu.edu.cn Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi_init.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index 36834768fec1..6f859f0d2046 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -1241,7 +1241,8 @@ static inline int pqi_report_phys_luns(struct pqi_ctrl_info *ctrl_info, void **b dev_err(&ctrl_info->pci_dev->dev, "RPL returned unsupported data format %u\n", rpl_response_format); - return -EINVAL; + rc = -EINVAL; + goto out_free_rpl_list; } else { dev_warn(&ctrl_info->pci_dev->dev, "RPL returned extended format 2 instead of 4\n"); @@ -1253,8 +1254,10 @@ static inline int pqi_report_phys_luns(struct pqi_ctrl_info *ctrl_info, void **b rpl_16byte_wwid_list = kmalloc(struct_size(rpl_16byte_wwid_list, lun_entries, num_physicals), GFP_KERNEL); - if (!rpl_16byte_wwid_list) - return -ENOMEM; + if (!rpl_16byte_wwid_list) { + rc = -ENOMEM; + goto out_free_rpl_list; + } put_unaligned_be32(num_physicals * sizeof(struct report_phys_lun_16byte_wwid), &rpl_16byte_wwid_list->header.list_length); @@ -1275,6 +1278,10 @@ static inline int pqi_report_phys_luns(struct pqi_ctrl_info *ctrl_info, void **b *buffer = rpl_16byte_wwid_list; return 0; + +out_free_rpl_list: + kfree(rpl_list); + return rc; } static inline int pqi_report_logical_luns(struct pqi_ctrl_info *ctrl_info, void **buffer) From 9672ed3de7d772ceddd713c769c05e832fc69bae Mon Sep 17 00:00:00 2001 From: Keita Morisaki Date: Mon, 2 Feb 2026 11:45:26 +0900 Subject: [PATCH 75/78] scsi: ufs: mediatek: Fix page faults in ufs_mtk_clk_scale() trace event The ufs_mtk_clk_scale() trace event currently stores the address of the name string directly via __field(const char *, name). This pointer may become invalid after the module is unloaded, causing page faults when the trace buffer is subsequently accessed. This can occur because the MediaTek UFS driver can be configured as a loadable module (tristate in Kconfig), meaning the name string passed to the trace event may reside in module memory that becomes invalid after module unload. Fix this by using __string() and __assign_str() to copy the string contents into the ring buffer instead of storing the pointer. This ensures the trace data remains valid regardless of module state. This change increases the memory usage for each ftrace entry by a few bytes (clock names are typically 7-15 characters like "ufs_sel" or "ufs_sel_max_src") compared to storing an 8-byte pointer. Note that this change does not affect anything unless all of the following conditions are met: - CONFIG_SCSI_UFS_MEDIATEK is enabled - ftrace tracing is enabled - The ufs_mtk_clk_scale event is enabled in ftrace Signed-off-by: Keita Morisaki Reviewed-by: Peter Wang Link: https://patch.msgid.link/20260202024526.122515-1-keita.morisaki@tier4.jp Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-mediatek-trace.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/ufs/host/ufs-mediatek-trace.h b/drivers/ufs/host/ufs-mediatek-trace.h index b5f2ec314074..0df8ac843379 100644 --- a/drivers/ufs/host/ufs-mediatek-trace.h +++ b/drivers/ufs/host/ufs-mediatek-trace.h @@ -33,19 +33,19 @@ TRACE_EVENT(ufs_mtk_clk_scale, TP_ARGS(name, scale_up, clk_rate), TP_STRUCT__entry( - __field(const char*, name) + __string(name, name) __field(bool, scale_up) __field(unsigned long, clk_rate) ), TP_fast_assign( - __entry->name = name; + __assign_str(name); __entry->scale_up = scale_up; __entry->clk_rate = clk_rate; ), TP_printk("ufs: clk (%s) scaled %s @ %lu", - __entry->name, + __get_str(name), __entry->scale_up ? "up" : "down", __entry->clk_rate) ); From bbb8d98fb4536594cb104fd630ea0f7dce3771d6 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 2 Feb 2026 10:50:18 +0100 Subject: [PATCH 76/78] scsi: ufs: host: mediatek: Require CONFIG_PM The added print statement from a recent fix causes the driver to fail building when CONFIG_PM is disabled: drivers/ufs/host/ufs-mediatek.c: In function 'ufs_mtk_resume': drivers/ufs/host/ufs-mediatek.c:1890:40: error: 'struct dev_pm_info' has no member named 'request' 1890 | hba->dev->power.request, It seems unlikely that the driver can work at all without CONFIG_PM, so just add a dependency and remove the existing ifdef checks, rather than adding another ifdef. Fixes: 15ef3f5aa822 ("scsi: ufs: host: mediatek: Enhance recovery on resume failure") Signed-off-by: Arnd Bergmann Reviewed-by: AngeloGioacchino Del Regno Link: https://patch.msgid.link/20260202095052.1232703-1-arnd@kernel.org Signed-off-by: Martin K. Petersen --- drivers/ufs/host/Kconfig | 1 + drivers/ufs/host/ufs-mediatek.c | 12 +++--------- include/ufs/ufshcd.h | 4 ---- 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/drivers/ufs/host/Kconfig b/drivers/ufs/host/Kconfig index 7d5117b2dab4..964ae70e7390 100644 --- a/drivers/ufs/host/Kconfig +++ b/drivers/ufs/host/Kconfig @@ -72,6 +72,7 @@ config SCSI_UFS_QCOM config SCSI_UFS_MEDIATEK tristate "Mediatek specific hooks to UFS controller platform driver" depends on SCSI_UFSHCD_PLATFORM && ARCH_MEDIATEK + depends on PM depends on RESET_CONTROLLER select PHY_MTK_UFS select RESET_TI_SYSCON diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c index ecbbf52bf734..05892b9ac528 100644 --- a/drivers/ufs/host/ufs-mediatek.c +++ b/drivers/ufs/host/ufs-mediatek.c @@ -2437,7 +2437,6 @@ static void ufs_mtk_remove(struct platform_device *pdev) ufshcd_pltfrm_remove(pdev); } -#ifdef CONFIG_PM_SLEEP static int ufs_mtk_system_suspend(struct device *dev) { struct ufs_hba *hba = dev_get_drvdata(dev); @@ -2484,9 +2483,7 @@ out: return ret; } -#endif -#ifdef CONFIG_PM static int ufs_mtk_runtime_suspend(struct device *dev) { struct ufs_hba *hba = dev_get_drvdata(dev); @@ -2525,13 +2522,10 @@ static int ufs_mtk_runtime_resume(struct device *dev) return ufshcd_runtime_resume(dev); } -#endif static const struct dev_pm_ops ufs_mtk_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(ufs_mtk_system_suspend, - ufs_mtk_system_resume) - SET_RUNTIME_PM_OPS(ufs_mtk_runtime_suspend, - ufs_mtk_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(ufs_mtk_system_suspend, ufs_mtk_system_resume) + RUNTIME_PM_OPS(ufs_mtk_runtime_suspend, ufs_mtk_runtime_resume, NULL) .prepare = ufshcd_suspend_prepare, .complete = ufshcd_resume_complete, }; @@ -2541,7 +2535,7 @@ static struct platform_driver ufs_mtk_pltform = { .remove = ufs_mtk_remove, .driver = { .name = "ufshcd-mtk", - .pm = &ufs_mtk_pm_ops, + .pm = pm_ptr(&ufs_mtk_pm_ops), .of_match_table = ufs_mtk_of_match, }, }; diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index a64c19563b03..8563b6648976 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -1344,17 +1344,13 @@ static inline void *ufshcd_get_variant(struct ufs_hba *hba) return hba->priv; } -#ifdef CONFIG_PM extern int ufshcd_runtime_suspend(struct device *dev); extern int ufshcd_runtime_resume(struct device *dev); -#endif -#ifdef CONFIG_PM_SLEEP extern int ufshcd_system_suspend(struct device *dev); extern int ufshcd_system_resume(struct device *dev); extern int ufshcd_system_freeze(struct device *dev); extern int ufshcd_system_thaw(struct device *dev); extern int ufshcd_system_restore(struct device *dev); -#endif extern int ufshcd_dme_reset(struct ufs_hba *hba); extern int ufshcd_dme_enable(struct ufs_hba *hba); From e17f0d4cc006265dd92129db4bf9da3a2e4a4f66 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 3 Feb 2026 17:33:15 +0100 Subject: [PATCH 77/78] scsi: buslogic: Reduce stack usage Some randconfig builds run into excessive stack usage with gcc-14 or higher, which use __attribute__((cold)) where earlier versions did not do that: drivers/scsi/BusLogic.c: In function 'blogic_init': drivers/scsi/BusLogic.c:2398:1: error: the frame size of 1680 bytes is larger than 1536 bytes [-Werror=frame-larger-than=] The problem is that a lot of code gets inlined into blogic_init() here. Two functions stick out, but they are a bit different: - blogic_init_probeinfo_list() actually uses a few hundred bytes of kernel stack, which is a problem in combination with other functions that also do. Marking this one as noinline means that the stack slots get get reused between function calls - blogic_reportconfig() has a few large variables, but whenever it is not inlined into its caller, the compiler is actually smart enough to reuse stack slots for these automatically, so marking it as noinline saves most of the stack space by itself. The combination of both of these should avoid the problem entirely. Signed-off-by: Arnd Bergmann Link: https://patch.msgid.link/20260203163321.2598593-1-arnd@kernel.org Signed-off-by: Martin K. Petersen --- drivers/scsi/BusLogic.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c index 865fcbac8fa1..49929d0339fa 100644 --- a/drivers/scsi/BusLogic.c +++ b/drivers/scsi/BusLogic.c @@ -920,7 +920,8 @@ static int __init blogic_init_fp_probeinfo(struct blogic_adapter *adapter) a particular probe order. */ -static void __init blogic_init_probeinfo_list(struct blogic_adapter *adapter) +static noinline_for_stack void __init +blogic_init_probeinfo_list(struct blogic_adapter *adapter) { /* If a PCI BIOS is present, interrogate it for MultiMaster and @@ -1690,7 +1691,8 @@ common: blogic_reportconfig reports the configuration of Host Adapter. */ -static bool __init blogic_reportconfig(struct blogic_adapter *adapter) +static noinline_for_stack bool __init +blogic_reportconfig(struct blogic_adapter *adapter) { unsigned short alltgt_mask = (1 << adapter->maxdev) - 1; unsigned short sync_ok, fast_ok; From 1982257570b84dc33753d536dd969fd357a014e9 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 29 Jan 2026 15:53:32 +0000 Subject: [PATCH 78/78] scsi: csiostor: Fix dereference of null pointer rn The error exit path when rn is NULL ends up deferencing the null pointer rn via the use of the macro CSIO_INC_STATS. Fix this by adding a new error return path label after the use of the macro to avoid the deference. Fixes: a3667aaed569 ("[SCSI] csiostor: Chelsio FCoE offload driver") Signed-off-by: Colin Ian King Link: https://patch.msgid.link/20260129155332.196338-1-colin.i.king@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/csiostor/csio_scsi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/csiostor/csio_scsi.c b/drivers/scsi/csiostor/csio_scsi.c index c29bf2807e31..05137784f369 100644 --- a/drivers/scsi/csiostor/csio_scsi.c +++ b/drivers/scsi/csiostor/csio_scsi.c @@ -2074,7 +2074,7 @@ csio_eh_lun_reset_handler(struct scsi_cmnd *cmnd) struct csio_scsi_level_data sld; if (!rn) - goto fail; + goto fail_ret; csio_dbg(hw, "Request to reset LUN:%llu (ssni:0x%x tgtid:%d)\n", cmnd->device->lun, rn->flowid, rn->scsi_id); @@ -2220,6 +2220,7 @@ fail_ret_ioreq: csio_put_scsi_ioreq_lock(hw, scsim, ioreq); fail: CSIO_INC_STATS(rn, n_lun_rst_fail); +fail_ret: return FAILED; }