diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c index 742534c99386..0986a6e2a6ae 100644 --- a/drivers/scsi/device_handler/scsi_dh_rdac.c +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c @@ -450,14 +450,14 @@ static int initialize_controller(struct scsi_device *sdev, spin_lock(&list_lock); h->ctlr = get_controller(index, array_name, array_id, sdev); - if (!h->ctlr) + if (!h->ctlr) { err = SCSI_DH_RES_TEMP_UNAVAIL; - else { + } else { h->sdev = sdev; list_add_rcu(&h->node, &h->ctlr->dh_list); + err = SCSI_DH_OK; } spin_unlock(&list_lock); - err = SCSI_DH_OK; } return err; } diff --git a/drivers/scsi/leapraid/leapraid_os.c b/drivers/scsi/leapraid/leapraid_os.c index da597eb99377..749e50366dbc 100644 --- a/drivers/scsi/leapraid/leapraid_os.c +++ b/drivers/scsi/leapraid/leapraid_os.c @@ -935,22 +935,16 @@ static int leapraid_init_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *scmd) { struct leapraid_adapter *adapter = shost_priv(shost); - struct leapraid_io_req_tracker *io_tracker; - io_tracker = scsi_cmd_priv(scmd); - leapraid_internal_init_cmd_priv(adapter, io_tracker); - - return 0; + return leapraid_internal_init_cmd_priv(adapter, scsi_cmd_priv(scmd)); } static int leapraid_exit_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *scmd) { struct leapraid_adapter *adapter = shost_priv(shost); - struct leapraid_io_req_tracker *io_tracker; - io_tracker = scsi_cmd_priv(scmd); - leapraid_internal_exit_cmd_priv(adapter, io_tracker); + leapraid_internal_exit_cmd_priv(adapter, scsi_cmd_priv(scmd)); return 0; } diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index d6e16707fd97..e78383df619c 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -83,6 +83,7 @@ extern atomic64_t event_counter; #define MPI3MR_ADMIN_REPLY_Q_SIZE (8 * MPI3MR_PAGE_SIZE_4K) #define MPI3MR_ADMIN_REQ_FRAME_SZ 128 #define MPI3MR_ADMIN_REPLY_FRAME_SZ 16 +#define MPI3MR_MIN_REPLY_FRAME_SZ_DWORDS 16 /* 64 bytes */ /* Operational queue management definitions */ #define MPI3MR_OP_REQ_Q_QD 512 diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index f0d3cd398dd0..60a92366e590 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -3261,6 +3261,7 @@ static int mpi3mr_issue_iocfacts(struct mpi3mr_ioc *mrioc, struct mpi3_ioc_facts_data *facts_data) { struct mpi3_ioc_facts_request iocfacts_req; + u16 reply_frame_size; void *data = NULL; dma_addr_t data_dma; u32 data_len = sizeof(*facts_data); @@ -3318,6 +3319,23 @@ static int mpi3mr_issue_iocfacts(struct mpi3mr_ioc *mrioc, goto out_unlock; } memcpy(facts_data, (u8 *)data, data_len); + + reply_frame_size = le16_to_cpu(facts_data->reply_frame_size); + /* + * Validate reply_frame_size: + * - Must be at least 16 dwords (64 bytes) to accommodate fixed reply + * structures and avoid underflow/divide-by-zero in logdata sizing. + * - Must not exceed U16_MAX / 4 to prevent integer overflow. + */ + if (reply_frame_size < MPI3MR_MIN_REPLY_FRAME_SZ_DWORDS || + reply_frame_size > (U16_MAX / 4)) { + ioc_err(mrioc, "Invalid reply_frame_size %u (must be %u..%u dwords)\n", + reply_frame_size, MPI3MR_MIN_REPLY_FRAME_SZ_DWORDS, + (unsigned int)(U16_MAX / 4)); + retval = -EINVAL; + goto out_unlock; + } + mpi3mr_process_factsdata(mrioc, facts_data); out_unlock: mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; diff --git a/drivers/scsi/scsi_bsg.c b/drivers/scsi/scsi_bsg.c index e4a65d7a2374..3cf1caad02f7 100644 --- a/drivers/scsi/scsi_bsg.c +++ b/drivers/scsi/scsi_bsg.c @@ -43,9 +43,17 @@ static void scsi_bsg_uring_task_cb(struct io_tw_req tw_req, io_tw_token_t tw) if (pdu->bio) ret = blk_rq_unmap_user(pdu->bio); + /* + * If the request is being canceled, e.g. because the submitting task + * has exited, this may run from a kworker or in a different task, so + * don't copy the sense data to the submitter's address. + */ + if (unlikely(tw.cancel)) + ret = -ECANCELED; + if (scsi_status_is_check_condition(scmd->result)) { driver_status = DRIVER_SENSE; - if (pdu->response_addr) + if (pdu->response_addr && !tw.cancel) sense_len_wr = min_t(unsigned int, pdu->max_response_len, scmd->sense_len); } diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c index 8cbf171e6fab..06f4e3fcda1d 100644 --- a/drivers/scsi/sd_zbc.c +++ b/drivers/scsi/sd_zbc.c @@ -222,7 +222,7 @@ int sd_zbc_report_zones(struct gendisk *disk, sector_t sector, { struct scsi_disk *sdkp = scsi_disk(disk); sector_t lba = sectors_to_logical(sdkp->device, sector); - unsigned int nr, i; + unsigned int nr, i, max_in_buf; unsigned char *buf; u64 zone_length, start_lba; size_t offset, buflen = 0; @@ -241,13 +241,18 @@ int sd_zbc_report_zones(struct gendisk *disk, sector_t sector, if (!buf) return -ENOMEM; + max_in_buf = (buflen - ZBC_REPORT_ZONES_HEADER_SIZE) / + ZBC_ZONE_DESCRIPTOR_SIZE; + while (zone_idx < nr_zones && lba < sdkp->capacity) { ret = sd_zbc_do_report_zones(sdkp, buf, buflen, lba, true); if (ret) goto out; offset = 0; - nr = min(nr_zones, get_unaligned_be32(&buf[0]) / 64); + nr = min3(nr_zones - zone_idx, + get_unaligned_be32(&buf[0]) / ZBC_ZONE_DESCRIPTOR_SIZE, + max_in_buf); if (!nr) break; diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 124ff269b8e7..03d618cd7672 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -1518,25 +1518,6 @@ __iscsit_check_dataout_hdr(struct iscsit_conn *conn, void *buf, if (hdr->flags & ISCSI_FLAG_CMD_FINAL) iscsit_stop_dataout_timer(cmd); - return iscsit_dump_data_payload(conn, payload_length, 1); - } - } else { - /* - * For the normal solicited data path: - * - * Check for a delayed TASK_ABORTED status and dump any - * incoming data out payload if one exists. Also, when the - * ISCSI_FLAG_CMD_FINAL is set to denote the end of the current - * data out sequence, we decrement outstanding_r2ts. Once - * outstanding_r2ts reaches zero, go ahead and send the delayed - * TASK_ABORTED status. - */ - if (se_cmd->transport_state & CMD_T_ABORTED) { - if (hdr->flags & ISCSI_FLAG_CMD_FINAL && - --cmd->outstanding_r2ts < 1) { - iscsit_stop_dataout_timer(cmd); - target_complete_cmd(se_cmd, SAM_STAT_TASK_ABORTED); - } return iscsit_dump_data_payload(conn, payload_length, 1); } diff --git a/drivers/target/iscsi/iscsi_target_erl1.c b/drivers/target/iscsi/iscsi_target_erl1.c index d8ca06e697d6..44b851e4a602 100644 --- a/drivers/target/iscsi/iscsi_target_erl1.c +++ b/drivers/target/iscsi/iscsi_target_erl1.c @@ -908,8 +908,6 @@ int iscsit_execute_cmd(struct iscsit_cmd *cmd, int ooo) return 0; } spin_unlock_bh(&cmd->istate_lock); - if (cmd->se_cmd.transport_state & CMD_T_ABORTED) - return 0; return transport_send_check_condition_and_sense(se_cmd, cmd->sense_reason, 0); } @@ -927,9 +925,6 @@ int iscsit_execute_cmd(struct iscsit_cmd *cmd, int ooo) if (!(cmd->cmd_flags & ICF_NON_IMMEDIATE_UNSOLICITED_DATA)) { - if (cmd->se_cmd.transport_state & CMD_T_ABORTED) - return 0; - iscsit_set_dataout_sequence_values(cmd); conn->conn_transport->iscsit_get_dataout(conn, cmd, false); } @@ -942,9 +937,6 @@ int iscsit_execute_cmd(struct iscsit_cmd *cmd, int ooo) if ((cmd->data_direction == DMA_TO_DEVICE) && !(cmd->cmd_flags & ICF_NON_IMMEDIATE_UNSOLICITED_DATA)) { - if (cmd->se_cmd.transport_state & CMD_T_ABORTED) - return 0; - iscsit_set_unsolicited_dataout(cmd); } return target_submit(&cmd->se_cmd); diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c index b03ed154ca34..ccd468e26fb9 100644 --- a/drivers/target/iscsi/iscsi_target_nego.c +++ b/drivers/target/iscsi/iscsi_target_nego.c @@ -982,9 +982,6 @@ static int iscsi_target_handle_csg_one(struct iscsit_conn *conn, struct iscsi_lo if (iscsi_target_check_first_request(conn, login) < 0) return -1; - if (iscsi_target_check_for_existing_instances(conn, login) < 0) - return -1; - ret = iscsi_encode_text_output( PHASE_OPERATIONAL|PHASE_DECLARATIVE, SENDER_TARGET, @@ -1008,6 +1005,9 @@ static int iscsi_target_handle_csg_one(struct iscsit_conn *conn, struct iscsi_lo return -1; } + if (iscsi_target_check_for_existing_instances(conn, login) < 0) + return -1; + if (!iscsi_check_negotiated_keys(conn->param_list)) if ((login_req->flags & ISCSI_FLAG_LOGIN_NEXT_STAGE3) && (login_req->flags & ISCSI_FLAG_LOGIN_TRANSIT)) diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 140154d93c43..17386c96de13 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -1081,8 +1081,15 @@ int core_alua_do_port_transition( return -EINVAL; local_lu_gp_mem = l_dev->dev_alua_lu_gp_mem; + if (!local_lu_gp_mem) + return -ENODEV; + spin_lock(&local_lu_gp_mem->lu_gp_mem_lock); lu_gp = local_lu_gp_mem->lu_gp; + if (!lu_gp) { + spin_unlock(&local_lu_gp_mem->lu_gp_mem_lock); + return -ENODEV; + } atomic_inc(&lu_gp->lu_gp_ref_cnt); spin_unlock(&local_lu_gp_mem->lu_gp_mem_lock); /* diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 2b19a956007b..385b84bcbfb2 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -2126,8 +2126,8 @@ static match_table_t tokens = { {Opt_initiator_sid, "initiator_sid=%s"}, {Opt_sa_res_key, "sa_res_key=%s"}, {Opt_res_holder, "res_holder=%d"}, - {Opt_res_type, "res_type=%d"}, - {Opt_res_scope, "res_scope=%d"}, + {Opt_res_type, "res_type=%x"}, + {Opt_res_scope, "res_scope=%x"}, {Opt_res_all_tg_pt, "res_all_tg_pt=%d"}, {Opt_mapped_lun, "mapped_lun=%u"}, {Opt_target_fabric, "target_fabric=%s"}, @@ -2229,13 +2229,13 @@ static ssize_t target_pr_res_aptpl_metadata_store(struct config_item *item, res_holder = arg; break; case Opt_res_type: - ret = match_int(args, &arg); + ret = match_hex(args, &arg); if (ret) goto out; type = (u8)arg; break; case Opt_res_scope: - ret = match_int(args, &arg); + ret = match_hex(args, &arg); if (ret) goto out; break; @@ -2547,6 +2547,14 @@ static ssize_t target_dev_alua_lu_gp_store(struct config_item *item, spin_lock(&lu_gp_mem->lu_gp_mem_lock); lu_gp = lu_gp_mem->lu_gp; + if (!lu_gp && !lu_gp_new) { + /* + * The LU group association has already been cleared, so + * there is nothing left to do. + */ + spin_unlock(&lu_gp_mem->lu_gp_mem_lock); + return count; + } if (lu_gp) { /* * Clearing an existing lu_gp association, and replacing diff --git a/drivers/ufs/core/ufs-debugfs.c b/drivers/ufs/core/ufs-debugfs.c index 9f83628f3e2c..44a1a9692324 100644 --- a/drivers/ufs/core/ufs-debugfs.c +++ b/drivers/ufs/core/ufs-debugfs.c @@ -70,12 +70,18 @@ token_context_lock(ufs_debugfs); static int ufs_debugfs_get_user_access(struct ufs_hba *hba) __cond_acquires(0, ufs_debugfs) { + int err; + down(&hba->host_sem); if (!ufshcd_is_user_access_allowed(hba)) { up(&hba->host_sem); return -EBUSY; } - ufshcd_rpm_get_sync(hba); + err = ufshcd_rpm_resume_and_get(hba); + if (err) { + up(&hba->host_sem); + return err; + } __acquire(ufs_debugfs); return 0; } diff --git a/drivers/ufs/core/ufs-hwmon.c b/drivers/ufs/core/ufs-hwmon.c index aa0b60a0ee8a..2b9673d92573 100644 --- a/drivers/ufs/core/ufs-hwmon.c +++ b/drivers/ufs/core/ufs-hwmon.c @@ -61,7 +61,11 @@ static int ufs_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 return -EBUSY; } - ufshcd_rpm_get_sync(hba); + err = ufshcd_rpm_resume_and_get(hba); + if (err) { + up(&hba->host_sem); + return err; + } switch (attr) { case hwmon_temp_enable: @@ -113,7 +117,11 @@ static int ufs_hwmon_write(struct device *dev, enum hwmon_sensor_types type, u32 return -EBUSY; } - ufshcd_rpm_get_sync(hba); + err = ufshcd_rpm_resume_and_get(hba); + if (err) { + up(&hba->host_sem); + return err; + } if (val == 1) err = ufshcd_update_ee_usr_mask(hba, MASK_EE_URGENT_TEMP, 0); diff --git a/drivers/ufs/core/ufs-mcq.c b/drivers/ufs/core/ufs-mcq.c index 25e392f8ede2..005a70462473 100644 --- a/drivers/ufs/core/ufs-mcq.c +++ b/drivers/ufs/core/ufs-mcq.c @@ -554,6 +554,23 @@ static int ufshcd_mcq_sq_start(struct ufs_hba *hba, struct ufs_hw_queue *hwq) return err; } +/* + * Reap the CQ directly so that progress does not depend on interrupt + * delivery. ufshcd_compl_one_cqe() updates the OCS under cq_lock before + * calling scsi_done(). Holding cq_lock while reading the OCS makes sure that + * the completion has finished once the updated OCS is observed, even if the + * CQE was reaped by the interrupt handler. + */ +static enum utp_ocs ufshcd_mcq_poll_ocs(struct ufs_hba *hba, + struct ufs_hw_queue *hwq, + struct ufshcd_lrb *lrbp) +{ + ufshcd_mcq_poll_cqe_lock(hba, hwq); + + guard(spinlock_irqsave)(&hwq->cq_lock); + return lrbp->utr_descriptor_ptr->header.ocs; +} + /** * ufshcd_mcq_sq_cleanup - Clean up submission queue resources * associated with the pending command. @@ -613,6 +630,23 @@ int ufshcd_mcq_sq_cleanup(struct ufs_hba *hba, int task_tag) __func__, id, FIELD_GET(SQ_ICU_ERR_CODE_MASK, readl(reg))); + /* + * For device management commands, there is no order guaranteed between + * OCS update and CUS update, which is why we need to wait here. SCSI + * commands are excluded because the OCS in their UTRD is not updated + * from the CQE. + */ + if (!err && blk_mq_is_reserved_rq(rq)) { + enum utp_ocs ocs; + + err = read_poll_timeout(ufshcd_mcq_poll_ocs, ocs, + ocs != OCS_INVALID_COMMAND_STATUS, 20, + MCQ_POLL_US, false, hba, hwq, lrbp); + if (err) + dev_err(hba->dev, "%s: OCS not updated. hwq=%d, tag=%d err=%d\n", + __func__, id, task_tag, err); + } + if (ufshcd_mcq_sq_start(hba, hwq)) err = -ETIMEDOUT; diff --git a/drivers/ufs/core/ufs-sysfs.c b/drivers/ufs/core/ufs-sysfs.c index cf49ad0258e1..19b62cf52410 100644 --- a/drivers/ufs/core/ufs-sysfs.c +++ b/drivers/ufs/core/ufs-sysfs.c @@ -250,13 +250,19 @@ EXPORT_SYMBOL_GPL(ufshcd_us_to_ahit); static int ufshcd_read_hci_reg(struct ufs_hba *hba, u32 *val, unsigned int reg) { + int ret; + down(&hba->host_sem); if (!ufshcd_is_user_access_allowed(hba)) { up(&hba->host_sem); return -EBUSY; } - ufshcd_rpm_get_sync(hba); + ret = ufshcd_rpm_resume_and_get(hba); + if (ret) { + up(&hba->host_sem); + return ret; + } ufshcd_hold(hba); *val = ufshcd_readl(hba, reg); ufshcd_release(hba); @@ -350,7 +356,9 @@ static ssize_t wb_on_store(struct device *dev, struct device_attribute *attr, goto out; } - ufshcd_rpm_get_sync(hba); + res = ufshcd_rpm_resume_and_get(hba); + if (res) + goto out; res = ufshcd_wb_toggle(hba, wb_enable); ufshcd_rpm_put_sync(hba); out: @@ -421,7 +429,9 @@ static ssize_t enable_wb_buf_flush_store(struct device *dev, goto out; } - ufshcd_rpm_get_sync(hba); + res = ufshcd_rpm_resume_and_get(hba); + if (res) + goto out; res = ufshcd_wb_toggle_buf_flush(hba, enable_wb_buf_flush); ufshcd_rpm_put_sync(hba); @@ -490,7 +500,9 @@ static ssize_t wb_resize_enable_store(struct device *dev, goto out; } - ufshcd_rpm_get_sync(hba); + res = ufshcd_rpm_resume_and_get(hba); + if (res) + goto out; res = ufshcd_wb_set_resize_en(hba, mode); ufshcd_rpm_put_sync(hba); @@ -598,7 +610,9 @@ static ssize_t device_lvl_exception_id_show(struct device *dev, if (hba->dev_info.wspecversion < 0x410) return -EOPNOTSUPP; - ufshcd_rpm_get_sync(hba); + err = ufshcd_rpm_resume_and_get(hba); + if (err) + return err; err = ufshcd_query_attr_qword(hba, UPIU_QUERY_OPCODE_READ_ATTR, QUERY_ATTR_IDN_DEV_LVL_EXCEPTION_ID, 0, 0, &exception_id); @@ -1101,7 +1115,9 @@ static ssize_t ufs_sysfs_read_desc_param(struct ufs_hba *hba, goto out; } - ufshcd_rpm_get_sync(hba); + ret = ufshcd_rpm_resume_and_get(hba); + if (ret) + goto out; ret = ufshcd_read_desc_param(hba, desc_id, desc_index, param_offset, desc_buf, param_size); ufshcd_rpm_put_sync(hba); @@ -1482,7 +1498,12 @@ static ssize_t _name##_show(struct device *dev, \ up(&hba->host_sem); \ return -ENOMEM; \ } \ - ufshcd_rpm_get_sync(hba); \ + ret = ufshcd_rpm_resume_and_get(hba); \ + if (ret) { \ + kfree(desc_buf); \ + up(&hba->host_sem); \ + return ret; \ + } \ ret = ufshcd_query_descriptor_retry(hba, \ UPIU_QUERY_OPCODE_READ_DESC, QUERY_DESC_IDN_DEVICE, \ 0, 0, desc_buf, &desc_len); \ @@ -1548,7 +1569,9 @@ static ssize_t _name##_show(struct device *dev, \ } \ if (ufshcd_is_wb_flags(QUERY_FLAG_IDN##_uname)) \ index = ufshcd_wb_get_query_index(hba); \ - ufshcd_rpm_get_sync(hba); \ + ret = ufshcd_rpm_resume_and_get(hba); \ + if (ret) \ + goto out; \ ret = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_READ_FLAG, \ QUERY_FLAG_IDN##_uname, index, &flag); \ ufshcd_rpm_put_sync(hba); \ @@ -1608,7 +1631,9 @@ static ssize_t max_number_of_rtt_show(struct device *dev, return -EBUSY; } - ufshcd_rpm_get_sync(hba); + ret = ufshcd_rpm_resume_and_get(hba); + if (ret) + goto out; ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR, QUERY_ATTR_IDN_MAX_NUM_OF_RTT, 0, 0, &rtt); ufshcd_rpm_put_sync(hba); @@ -1648,7 +1673,9 @@ static ssize_t max_number_of_rtt_store(struct device *dev, goto out; } - ufshcd_rpm_get_sync(hba); + ret = ufshcd_rpm_resume_and_get(hba); + if (ret) + goto out; memflags = memalloc_noio_save(); shost_for_each_device(sdev, hba->host) @@ -1700,7 +1727,11 @@ static int wb_read_resize_attrs(struct ufs_hba *hba, } index = ufshcd_wb_get_query_index(hba); - ufshcd_rpm_get_sync(hba); + ret = ufshcd_rpm_resume_and_get(hba); + if (ret) { + up(&hba->host_sem); + return ret; + } ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR, idn, index, 0, attr_val); ufshcd_rpm_put_sync(hba); @@ -1760,7 +1791,9 @@ static ssize_t _name##_show(struct device *dev, \ } \ if (ufshcd_is_wb_attrs(QUERY_ATTR_IDN##_uname)) \ index = ufshcd_wb_get_query_index(hba); \ - ufshcd_rpm_get_sync(hba); \ + ret = ufshcd_rpm_resume_and_get(hba); \ + if (ret) \ + goto out; \ if (ufshcd_is_qword_attr(QUERY_ATTR_IDN##_uname)) \ ret = ufshcd_query_attr_qword(hba, \ UPIU_QUERY_OPCODE_READ_ATTR, \ @@ -1848,7 +1881,11 @@ static int hid_query_attr(struct ufs_hba *hba, enum query_opcode opcode, return -EBUSY; } - ufshcd_rpm_get_sync(hba); + ret = ufshcd_rpm_resume_and_get(hba); + if (ret) { + up(&hba->host_sem); + return ret; + } ret = ufshcd_query_attr(hba, opcode, idn, 0, 0, attr_val); ufshcd_rpm_put_sync(hba); @@ -2121,7 +2158,9 @@ static ssize_t dyn_cap_needed_attribute_show(struct device *dev, goto out; } - ufshcd_rpm_get_sync(hba); + ret = ufshcd_rpm_resume_and_get(hba); + if (ret) + goto out; ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR, QUERY_ATTR_IDN_DYN_CAP_NEEDED, lun, 0, &value); ufshcd_rpm_put_sync(hba); diff --git a/drivers/ufs/core/ufs_bsg.c b/drivers/ufs/core/ufs_bsg.c index baf6ae917d36..8df1a2c6abf6 100644 --- a/drivers/ufs/core/ufs_bsg.c +++ b/drivers/ufs/core/ufs_bsg.c @@ -150,7 +150,9 @@ static int ufs_bsg_request(struct bsg_job *job) goto out_complete; } - ufshcd_rpm_get_sync(hba); + ret = ufshcd_rpm_resume_and_get(hba); + if (ret) + goto out_complete; msgcode = bsg_request->msgcode; switch (msgcode) { diff --git a/drivers/ufs/core/ufshcd-priv.h b/drivers/ufs/core/ufshcd-priv.h index e55c2a02c1f5..99f654b79035 100644 --- a/drivers/ufs/core/ufshcd-priv.h +++ b/drivers/ufs/core/ufshcd-priv.h @@ -388,6 +388,11 @@ static inline int ufshcd_rpm_get_sync(struct ufs_hba *hba) return pm_runtime_get_sync(&hba->ufs_device_wlun->sdev_gendev); } +static inline int ufshcd_rpm_resume_and_get(struct ufs_hba *hba) +{ + return pm_runtime_resume_and_get(&hba->ufs_device_wlun->sdev_gendev); +} + static inline int ufshcd_rpm_get_if_active(struct ufs_hba *hba) { return pm_runtime_get_if_active(&hba->ufs_device_wlun->sdev_gendev); diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index fd52deb72d21..ddc953b45ce9 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -1864,7 +1864,9 @@ static ssize_t ufshcd_clkscale_enable_store(struct device *dev, if (value == hba->clk_scaling.is_enabled) goto out; - ufshcd_rpm_get_sync(hba); + err = ufshcd_rpm_resume_and_get(hba); + if (err) + goto out; ufshcd_hold(hba); hba->clk_scaling.is_enabled = value; @@ -3390,7 +3392,7 @@ static int ufshcd_issue_dev_cmd(struct ufs_hba *hba, struct scsi_cmnd *cmd, struct request *rq = scsi_cmd_to_rq(cmd); blk_status_t sts; - rq->timeout = timeout; + rq->timeout = msecs_to_jiffies(timeout); sts = blk_execute_rq(rq, true); if (sts != BLK_STS_OK) return blk_status_to_errno(sts); @@ -4792,7 +4794,8 @@ void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit) WRITE_ONCE(hba->ahit, ahit); if (!pm_runtime_suspended(&hba->ufs_device_wlun->sdev_gendev)) { - ufshcd_rpm_get_sync(hba); + if (ufshcd_rpm_resume_and_get(hba)) + return; ufshcd_hold(hba); /* * Serialize with the host driver's AHIT control. Skip the @@ -8064,11 +8067,15 @@ static void ufshcd_set_req_abort_skip(struct ufs_hba *hba, unsigned long bitmap) * @hba: Pointer to adapter instance * @tag: Tag of the task to be aborted * - * Abort the pending command in device by sending UFS_ABORT_TASK task management - * command, and in host controller by clearing the door-bell register. There can - * be race between controller sending the command to the device while abort is - * issued. To avoid that, first issue UFS_QUERY_TASK to check if the command is - * really issued and then try to abort it. + * Abort the pending SCSI command in device by sending UFS_ABORT_TASK task + * management command, and in host controller by clearing the door-bell + * register. There can be race between controller sending the command to the + * device while abort is issued. To avoid that, first issue UFS_QUERY_TASK to + * check if the command is really issued and then try to abort it. + * + * Device management commands are not SCSI commands, so no task management + * function is issued for them; only the command is cleared in the host + * controller. * * Return: zero on success, non-zero on failure. */ @@ -8085,6 +8092,9 @@ int ufshcd_try_to_abort_task(struct ufs_hba *hba, int tag) lrbp = scsi_cmd_priv(cmd); + if (!ufshcd_is_scsi_cmd(cmd)) + goto clear_cmd; + for (poll_cnt = 100; poll_cnt; poll_cnt--) { err = ufshcd_issue_tm_cmd(hba, lrbp->lun, tag, UFS_QUERY_TASK, &resp); @@ -8130,6 +8140,7 @@ int ufshcd_try_to_abort_task(struct ufs_hba *hba, int tag) return err; } +clear_cmd: err = ufshcd_clear_cmd(hba, tag); if (err) dev_err(hba->dev, "%s: Failed clearing cmd at tag %d, err %d\n", @@ -8223,10 +8234,7 @@ static int ufshcd_abort(struct scsi_cmnd *cmd) goto release; } - if (blk_mq_is_reserved_rq(rq)) - err = ufshcd_clear_cmd(hba, tag); - else - err = ufshcd_try_to_abort_task(hba, tag); + err = ufshcd_try_to_abort_task(hba, tag); if (err) { dev_err(hba->dev, "%s: failed with err %d\n", __func__, err); ufshcd_set_req_abort_skip(hba, hba->outstanding_reqs); @@ -10651,8 +10659,14 @@ static int __ufshcd_wl_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) out: if (ret) ufshcd_update_evt_hist(hba, UFS_EVT_WL_RES_ERR, (u32)ret); - hba->clk_gating.is_suspended = false; - ufshcd_release(hba); + /* + * A failed runtime resume leaves the W-LUN RPM_SUSPENDED, so keep + * is_suspended and the suspend hold for the next resume. + */ + if (!ret || pm_op != UFS_RUNTIME_PM) { + hba->clk_gating.is_suspended = false; + ufshcd_release(hba); + } hba->pm_op_in_progress = false; return ret; } diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 27c87e62f8e9..47fc785612ad 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -2413,7 +2413,9 @@ static void ufs_qcom_write_msi_msg(struct msi_desc *desc, struct msi_msg *msg) { struct device *dev = msi_desc_to_dev(desc); struct ufs_hba *hba = dev_get_drvdata(dev); + struct ufs_qcom_host *host = ufshcd_get_variant(hba); + host->esi_msg = *msg; ufshcd_mcq_config_esi(hba, msg); } @@ -2441,8 +2443,10 @@ static int ufs_qcom_config_esi(struct ufs_hba *hba) struct ufs_qcom_irq *qi; int nr_irqs, ret; - if (host->esi_enabled) - return 0; + if (host->esi_enabled) { + ufshcd_mcq_config_esi(hba, &host->esi_msg); + goto enable; + } /* * 1. We only handle CQs as of now. @@ -2480,12 +2484,14 @@ static int ufs_qcom_config_esi(struct ufs_hba *hba) } } + host->esi_enabled = true; + +enable: if (host->hw_ver.major >= 6) { ufshcd_rmwl(hba, ESI_VEC_MASK, FIELD_PREP(ESI_VEC_MASK, MAX_ESI_VEC - 1), REG_UFS_CFG3); } ufshcd_mcq_enable_esi(hba); - host->esi_enabled = true; return 0; } diff --git a/drivers/ufs/host/ufs-qcom.h b/drivers/ufs/host/ufs-qcom.h index 944b2e532a09..d2647695abe3 100644 --- a/drivers/ufs/host/ufs-qcom.h +++ b/drivers/ufs/host/ufs-qcom.h @@ -5,6 +5,7 @@ #ifndef UFS_QCOM_H_ #define UFS_QCOM_H_ +#include #include #include #include @@ -360,6 +361,7 @@ struct ufs_qcom_host { u32 phy_gear; bool esi_enabled; + struct msi_msg esi_msg; u32 saved_tx_eq_g1_setting; u32 boot_spare_cfg; diff --git a/drivers/ufs/host/ufs-rockchip.c b/drivers/ufs/host/ufs-rockchip.c index bac68f238e1c..87308c9b1070 100644 --- a/drivers/ufs/host/ufs-rockchip.c +++ b/drivers/ufs/host/ufs-rockchip.c @@ -82,6 +82,7 @@ static int ufs_rockchip_rk3576_phy_init(struct ufs_hba *hba) ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_LINERESET_PVALUE2, SEL_RX_LANE0 + i), 0x02); ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_LINERESET_OPTION, SEL_RX_LANE0 + i), 0xf6); ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_POWER_SAVING_CTRL, SEL_RX_LANE0 + i), 0x69); + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_SAVE_DET_CTRL, SEL_RX_LANE0 + i), 0x18); } /* disable the mphy DME_SET cfg */ diff --git a/include/scsi/scsi_proto.h b/include/scsi/scsi_proto.h index 9c7d31aa6bae..0ee0cf3200d0 100644 --- a/include/scsi/scsi_proto.h +++ b/include/scsi/scsi_proto.h @@ -371,6 +371,9 @@ enum zbc_zone_reporting_options { #define ZBC_REPORT_ZONE_PARTIAL 0x80 +#define ZBC_REPORT_ZONES_HEADER_SIZE 64 +#define ZBC_ZONE_DESCRIPTOR_SIZE 64 + /* Zone types of REPORT ZONES zone descriptors */ enum zbc_zone_type { ZBC_ZONE_TYPE_CONV = 0x1,