Skip to content

Commit

Permalink
Merge tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/g…
Browse files Browse the repository at this point in the history
…it/jejb/scsi

Pull SCSI fixes from James Bottomley:
 "Small drivers fixes, except for ufs which has two large updates, one
  for exposing the device level feature, which is a new addition to the
  device spec and the other reworking the exynos driver to fix coherence
  issues on some android phones"

* tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi:
  scsi: megaraid_sas: Driver version update to 07.734.00.00-rc1
  scsi: megaraid_sas: Block zero-length ATA VPD inquiry
  scsi: scsi_transport_srp: Replace min/max nesting with clamp()
  scsi: ufs: core: Add device level exception support
  scsi: ufs: core: Rename ufshcd_wb_presrv_usrspc_keep_vcc_on()
  scsi: smartpqi: Use is_kdump_kernel() to check for kdump
  scsi: pm80xx: Set phy_attached to zero when device is gone
  scsi: ufs: exynos: gs101: Put UFS device in reset on .suspend()
  scsi: ufs: exynos: Move phy calls to .exit() callback
  scsi: ufs: exynos: Enable PRDT pre-fetching with UFSHCD_CAP_CRYPTO
  scsi: ufs: exynos: Ensure consistent phy reference counts
  scsi: ufs: exynos: Disable iocc if dma-coherent property isn't set
  scsi: ufs: exynos: Move UFS shareability value to drvdata
  scsi: ufs: exynos: Ensure pre_link() executes before exynos_ufs_phy_init()
  scsi: iscsi: Fix missing scsi_host_put() in error path
  scsi: ufs: core: Fix a race condition related to device commands
  scsi: hisi_sas: Fix I/O errors caused by hardware port ID changes
  scsi: hisi_sas: Enable force phy when SATA disk directly connected
  • Loading branch information
Linus Torvalds committed Apr 17, 2025
2 parents ec4c6d1 + a1af6f1 commit 7adf8b1
Show file tree
Hide file tree
Showing 18 changed files with 299 additions and 67 deletions.
32 changes: 32 additions & 0 deletions Documentation/ABI/testing/sysfs-driver-ufs
Original file line number Diff line number Diff line change
Expand Up @@ -1604,3 +1604,35 @@ Description:
prevent the UFS from frequently performing clock gating/ungating.

The attribute is read/write.

What: /sys/bus/platform/drivers/ufshcd/*/device_lvl_exception_count
What: /sys/bus/platform/devices/*.ufs/device_lvl_exception_count
Date: March 2025
Contact: Bao D. Nguyen <quic_nguyenb@quicinc.com>
Description:
This attribute is applicable to ufs devices compliant to the
JEDEC specifications version 4.1 or later. The
device_lvl_exception_count is a counter indicating the number of
times the device level exceptions have occurred since the last
time this variable is reset. Writing a 0 value to this
attribute will reset the device_lvl_exception_count. If the
device_lvl_exception_count reads a positive value, the user
application should read the device_lvl_exception_id attribute to
know more information about the exception.

The attribute is read/write.

What: /sys/bus/platform/drivers/ufshcd/*/device_lvl_exception_id
What: /sys/bus/platform/devices/*.ufs/device_lvl_exception_id
Date: March 2025
Contact: Bao D. Nguyen <quic_nguyenb@quicinc.com>
Description:
Reading the device_lvl_exception_id returns the
qDeviceLevelExceptionID attribute of the ufs device JEDEC
specification version 4.1. The definition of the
qDeviceLevelExceptionID is the ufs device vendor specific
implementation. Refer to the device manufacturer datasheet for
more information on the meaning of the qDeviceLevelExceptionID
attribute value.

The attribute is read only.
20 changes: 20 additions & 0 deletions drivers/scsi/hisi_sas/hisi_sas_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -935,8 +935,28 @@ static void hisi_sas_phyup_work_common(struct work_struct *work,
container_of(work, typeof(*phy), works[event]);
struct hisi_hba *hisi_hba = phy->hisi_hba;
struct asd_sas_phy *sas_phy = &phy->sas_phy;
struct asd_sas_port *sas_port = sas_phy->port;
struct hisi_sas_port *port = phy->port;
struct device *dev = hisi_hba->dev;
struct domain_device *port_dev;
int phy_no = sas_phy->id;

if (!test_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags) &&
sas_port && port && (port->id != phy->port_id)) {
dev_info(dev, "phy%d's hw port id changed from %d to %llu\n",
phy_no, port->id, phy->port_id);
port_dev = sas_port->port_dev;
if (port_dev && !dev_is_expander(port_dev->dev_type)) {
/*
* Set the device state to gone to block
* sending IO to the device.
*/
set_bit(SAS_DEV_GONE, &port_dev->state);
hisi_sas_notify_phy_event(phy, HISI_PHYE_LINK_RESET);
return;
}
}

phy->wait_phyup_cnt = 0;
if (phy->identify.target_port_protocols == SAS_PROTOCOL_SSP)
hisi_hba->hw->sl_notify_ssp(hisi_hba, phy_no);
Expand Down
9 changes: 7 additions & 2 deletions drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
Original file line number Diff line number Diff line change
Expand Up @@ -2501,17 +2501,22 @@ static void prep_ata_v2_hw(struct hisi_hba *hisi_hba,
struct hisi_sas_port *port = to_hisi_sas_port(sas_port);
struct sas_ata_task *ata_task = &task->ata_task;
struct sas_tmf_task *tmf = slot->tmf;
int phy_id;
u8 *buf_cmd;
int has_data = 0, hdr_tag = 0;
u32 dw0, dw1 = 0, dw2 = 0;

/* create header */
/* dw0 */
dw0 = port->id << CMD_HDR_PORT_OFF;
if (parent_dev && dev_is_expander(parent_dev->dev_type))
if (parent_dev && dev_is_expander(parent_dev->dev_type)) {
dw0 |= 3 << CMD_HDR_CMD_OFF;
else
} else {
phy_id = device->phy->identify.phy_identifier;
dw0 |= (1U << phy_id) << CMD_HDR_PHY_ID_OFF;
dw0 |= CMD_HDR_FORCE_PHY_MSK;
dw0 |= 4 << CMD_HDR_CMD_OFF;
}

if (tmf && ata_task->force_phy) {
dw0 |= CMD_HDR_FORCE_PHY_MSK;
Expand Down
14 changes: 12 additions & 2 deletions drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,10 @@
#define CMD_HDR_RESP_REPORT_MSK (0x1 << CMD_HDR_RESP_REPORT_OFF)
#define CMD_HDR_TLR_CTRL_OFF 6
#define CMD_HDR_TLR_CTRL_MSK (0x3 << CMD_HDR_TLR_CTRL_OFF)
#define CMD_HDR_PHY_ID_OFF 8
#define CMD_HDR_PHY_ID_MSK (0x1ff << CMD_HDR_PHY_ID_OFF)
#define CMD_HDR_FORCE_PHY_OFF 17
#define CMD_HDR_FORCE_PHY_MSK (0x1U << CMD_HDR_FORCE_PHY_OFF)
#define CMD_HDR_PORT_OFF 18
#define CMD_HDR_PORT_MSK (0xf << CMD_HDR_PORT_OFF)
#define CMD_HDR_PRIORITY_OFF 27
Expand Down Expand Up @@ -1429,15 +1433,21 @@ static void prep_ata_v3_hw(struct hisi_hba *hisi_hba,
struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
struct asd_sas_port *sas_port = device->port;
struct hisi_sas_port *port = to_hisi_sas_port(sas_port);
int phy_id;
u8 *buf_cmd;
int has_data = 0, hdr_tag = 0;
u32 dw1 = 0, dw2 = 0;

hdr->dw0 = cpu_to_le32(port->id << CMD_HDR_PORT_OFF);
if (parent_dev && dev_is_expander(parent_dev->dev_type))
if (parent_dev && dev_is_expander(parent_dev->dev_type)) {
hdr->dw0 |= cpu_to_le32(3 << CMD_HDR_CMD_OFF);
else
} else {
phy_id = device->phy->identify.phy_identifier;
hdr->dw0 |= cpu_to_le32((1U << phy_id)
<< CMD_HDR_PHY_ID_OFF);
hdr->dw0 |= CMD_HDR_FORCE_PHY_MSK;
hdr->dw0 |= cpu_to_le32(4U << CMD_HDR_CMD_OFF);
}

switch (task->data_dir) {
case DMA_TO_DEVICE:
Expand Down
4 changes: 2 additions & 2 deletions drivers/scsi/megaraid/megaraid_sas.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
/*
* MegaRAID SAS Driver meta data
*/
#define MEGASAS_VERSION "07.727.03.00-rc1"
#define MEGASAS_RELDATE "Oct 03, 2023"
#define MEGASAS_VERSION "07.734.00.00-rc1"
#define MEGASAS_RELDATE "Apr 03, 2025"

#define MEGASAS_MSIX_NAME_LEN 32

Expand Down
9 changes: 7 additions & 2 deletions drivers/scsi/megaraid/megaraid_sas_base.c
Original file line number Diff line number Diff line change
Expand Up @@ -2103,6 +2103,9 @@ static int megasas_sdev_configure(struct scsi_device *sdev,
/* This sdev property may change post OCR */
megasas_set_dynamic_target_properties(sdev, lim, is_target_prop);

if (!MEGASAS_IS_LOGICAL(sdev))
sdev->no_vpd_size = 1;

mutex_unlock(&instance->reset_mutex);

return 0;
Expand Down Expand Up @@ -3662,8 +3665,10 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,

case MFI_STAT_SCSI_IO_FAILED:
case MFI_STAT_LD_INIT_IN_PROGRESS:
cmd->scmd->result =
(DID_ERROR << 16) | hdr->scsi_status;
if (hdr->scsi_status == 0xf0)
cmd->scmd->result = (DID_ERROR << 16) | SAM_STAT_CHECK_CONDITION;
else
cmd->scmd->result = (DID_ERROR << 16) | hdr->scsi_status;
break;

case MFI_STAT_SCSI_DONE_WITH_ERROR:
Expand Down
5 changes: 4 additions & 1 deletion drivers/scsi/megaraid/megaraid_sas_fusion.c
Original file line number Diff line number Diff line change
Expand Up @@ -2043,7 +2043,10 @@ map_cmd_status(struct fusion_context *fusion,

case MFI_STAT_SCSI_IO_FAILED:
case MFI_STAT_LD_INIT_IN_PROGRESS:
scmd->result = (DID_ERROR << 16) | ext_status;
if (ext_status == 0xf0)
scmd->result = (DID_ERROR << 16) | SAM_STAT_CHECK_CONDITION;
else
scmd->result = (DID_ERROR << 16) | ext_status;
break;

case MFI_STAT_SCSI_DONE_WITH_ERROR:
Expand Down
1 change: 1 addition & 0 deletions drivers/scsi/pm8001/pm8001_sas.c
Original file line number Diff line number Diff line change
Expand Up @@ -766,6 +766,7 @@ static void pm8001_dev_gone_notify(struct domain_device *dev)
spin_lock_irqsave(&pm8001_ha->lock, flags);
}
PM8001_CHIP_DISP->dereg_dev_req(pm8001_ha, device_id);
pm8001_ha->phy[pm8001_dev->attached_phy].phy_attached = 0;
pm8001_free_dev(pm8001_dev);
} else {
pm8001_dbg(pm8001_ha, DISC, "Found dev has gone.\n");
Expand Down
7 changes: 5 additions & 2 deletions drivers/scsi/scsi_transport_iscsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -3182,11 +3182,14 @@ iscsi_set_host_param(struct iscsi_transport *transport,
}

/* see similar check in iscsi_if_set_param() */
if (strlen(data) > ev->u.set_host_param.len)
return -EINVAL;
if (strlen(data) > ev->u.set_host_param.len) {
err = -EINVAL;
goto out;
}

err = transport->set_host_param(shost, ev->u.set_host_param.param,
data, ev->u.set_host_param.len);
out:
scsi_host_put(shost);
return err;
}
Expand Down
2 changes: 1 addition & 1 deletion drivers/scsi/scsi_transport_srp.c
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ static void srp_reconnect_work(struct work_struct *work)
"reconnect attempt %d failed (%d)\n",
++rport->failed_reconnects, res);
delay = rport->reconnect_delay *
min(100, max(1, rport->failed_reconnects - 10));
clamp(rport->failed_reconnects - 10, 1, 100);
if (delay > 0)
queue_delayed_work(system_long_wq,
&rport->reconnect_work, delay * HZ);
Expand Down
13 changes: 7 additions & 6 deletions drivers/scsi/smartpqi/smartpqi_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <linux/bcd.h>
#include <linux/reboot.h>
#include <linux/cciss_ioctl.h>
#include <linux/crash_dump.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
Expand Down Expand Up @@ -5246,7 +5247,7 @@ static void pqi_calculate_io_resources(struct pqi_ctrl_info *ctrl_info)
ctrl_info->error_buffer_length =
ctrl_info->max_io_slots * PQI_ERROR_BUFFER_ELEMENT_LENGTH;

if (reset_devices)
if (is_kdump_kernel())
max_transfer_size = min(ctrl_info->max_transfer_size,
PQI_MAX_TRANSFER_SIZE_KDUMP);
else
Expand Down Expand Up @@ -5275,7 +5276,7 @@ static void pqi_calculate_queue_resources(struct pqi_ctrl_info *ctrl_info)
u16 num_elements_per_iq;
u16 num_elements_per_oq;

if (reset_devices) {
if (is_kdump_kernel()) {
num_queue_groups = 1;
} else {
int num_cpus;
Expand Down Expand Up @@ -8288,12 +8289,12 @@ static int pqi_ctrl_init(struct pqi_ctrl_info *ctrl_info)
u32 product_id;

if (reset_devices) {
if (pqi_is_fw_triage_supported(ctrl_info)) {
if (is_kdump_kernel() && pqi_is_fw_triage_supported(ctrl_info)) {
rc = sis_wait_for_fw_triage_completion(ctrl_info);
if (rc)
return rc;
}
if (sis_is_ctrl_logging_supported(ctrl_info)) {
if (is_kdump_kernel() && sis_is_ctrl_logging_supported(ctrl_info)) {
sis_notify_kdump(ctrl_info);
rc = sis_wait_for_ctrl_logging_completion(ctrl_info);
if (rc)
Expand Down Expand Up @@ -8344,7 +8345,7 @@ static int pqi_ctrl_init(struct pqi_ctrl_info *ctrl_info)
ctrl_info->product_id = (u8)product_id;
ctrl_info->product_revision = (u8)(product_id >> 8);

if (reset_devices) {
if (is_kdump_kernel()) {
if (ctrl_info->max_outstanding_requests >
PQI_MAX_OUTSTANDING_REQUESTS_KDUMP)
ctrl_info->max_outstanding_requests =
Expand Down Expand Up @@ -8480,7 +8481,7 @@ static int pqi_ctrl_init(struct pqi_ctrl_info *ctrl_info)
if (rc)
return rc;

if (ctrl_info->ctrl_logging_supported && !reset_devices) {
if (ctrl_info->ctrl_logging_supported && !is_kdump_kernel()) {
pqi_host_setup_buffer(ctrl_info, &ctrl_info->ctrl_log_memory, PQI_CTRL_LOG_TOTAL_SIZE, PQI_CTRL_LOG_MIN_SIZE);
pqi_host_memory_update(ctrl_info, &ctrl_info->ctrl_log_memory, PQI_VENDOR_GENERAL_CTRL_LOG_MEMORY_UPDATE);
}
Expand Down
54 changes: 54 additions & 0 deletions drivers/ufs/core/ufs-sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,56 @@ static ssize_t critical_health_show(struct device *dev,
return sysfs_emit(buf, "%d\n", hba->critical_health_count);
}

static ssize_t device_lvl_exception_count_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct ufs_hba *hba = dev_get_drvdata(dev);

if (hba->dev_info.wspecversion < 0x410)
return -EOPNOTSUPP;

return sysfs_emit(buf, "%u\n", atomic_read(&hba->dev_lvl_exception_count));
}

static ssize_t device_lvl_exception_count_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct ufs_hba *hba = dev_get_drvdata(dev);
unsigned int value;

if (kstrtouint(buf, 0, &value))
return -EINVAL;

/* the only supported usecase is to reset the dev_lvl_exception_count */
if (value)
return -EINVAL;

atomic_set(&hba->dev_lvl_exception_count, 0);

return count;
}

static ssize_t device_lvl_exception_id_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct ufs_hba *hba = dev_get_drvdata(dev);
u64 exception_id;
int err;

ufshcd_rpm_get_sync(hba);
err = ufshcd_read_device_lvl_exception_id(hba, &exception_id);
ufshcd_rpm_put_sync(hba);

if (err)
return err;

hba->dev_lvl_exception_id = exception_id;
return sysfs_emit(buf, "%llu\n", exception_id);
}

static DEVICE_ATTR_RW(rpm_lvl);
static DEVICE_ATTR_RO(rpm_target_dev_state);
static DEVICE_ATTR_RO(rpm_target_link_state);
Expand All @@ -479,6 +529,8 @@ static DEVICE_ATTR_RW(wb_flush_threshold);
static DEVICE_ATTR_RW(rtc_update_ms);
static DEVICE_ATTR_RW(pm_qos_enable);
static DEVICE_ATTR_RO(critical_health);
static DEVICE_ATTR_RW(device_lvl_exception_count);
static DEVICE_ATTR_RO(device_lvl_exception_id);

static struct attribute *ufs_sysfs_ufshcd_attrs[] = {
&dev_attr_rpm_lvl.attr,
Expand All @@ -494,6 +546,8 @@ static struct attribute *ufs_sysfs_ufshcd_attrs[] = {
&dev_attr_rtc_update_ms.attr,
&dev_attr_pm_qos_enable.attr,
&dev_attr_critical_health.attr,
&dev_attr_device_lvl_exception_count.attr,
&dev_attr_device_lvl_exception_id.attr,
NULL
};

Expand Down
1 change: 1 addition & 0 deletions drivers/ufs/core/ufshcd-priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba,
enum query_opcode desc_op);

int ufshcd_wb_toggle(struct ufs_hba *hba, bool enable);
int ufshcd_read_device_lvl_exception_id(struct ufs_hba *hba, u64 *exception_id);

/* Wrapper functions for safely calling variant operations */
static inline const char *ufshcd_get_var_name(struct ufs_hba *hba)
Expand Down
Loading

0 comments on commit 7adf8b1

Please sign in to comment.