SCSI misc on 20251214
The only core fix is in doc; all the others are in drivers, with the biggest impacts in libsas being the rollback on error handling and in ufs coming from a couple of error handling fixes, one causing a crash if it's activated before scanning and the other fixing W-LUN resumption. Signed-off-by: James E.J. Bottomley <James.Bottomley@HansenPartnership.com> -----BEGIN PGP SIGNATURE----- iLgEABMIAGAWIQTnYEDbdso9F2cI+arnQslM7pishQUCaT4RWBsUgAAAAAAEAA5t YW51MiwyLjUrMS4xMSwyLDImHGphbWVzLmJvdHRvbWxleUBoYW5zZW5wYXJ0bmVy c2hpcC5jb20ACgkQ50LJTO6YrIVfSgEA23oY0kPjLLkNj4KAjLoWVPmZ/5efKw49 m6YUwfvzTS8BAIq4eFHVecwAM8FAe9NwuOKgO5d9u6epAy6wzBeP2jly =cpHq -----END PGP SIGNATURE----- Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi Pull SCSI fixes from James Bottomley: "The only core fix is in doc; all the others are in drivers, with the biggest impacts in libsas being the rollback on error handling and in ufs coming from a couple of error handling fixes, one causing a crash if it's activated before scanning and the other fixing W-LUN resumption" * tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: scsi: ufs: qcom: Fix confusing cleanup.h syntax scsi: libsas: Add rollback handling when an error occurs scsi: device_handler: Return error pointer in scsi_dh_attached_handler_name() scsi: ufs: core: Fix a deadlock in the frequency scaling code scsi: ufs: core: Fix an error handler crash scsi: Revert "scsi: libsas: Fix exp-attached device scan after probe failure scanned in again after probe failed" scsi: ufs: core: Fix RPMB link error by reversing Kconfig dependencies scsi: qla4xxx: Use time conversion macros scsi: qla2xxx: Enable/disable IRQD_NO_BALANCING during reset scsi: ipr: Enable/disable IRQD_NO_BALANCING during reset scsi: imm: Fix use-after-free bug caused by unfinished delayed work scsi: target: sbp: Remove KMSG_COMPONENT macro scsi: core: Correct documentation for scsi_device_quiesce() scsi: mpi3mr: Prevent duplicate SAS/SATA device entries in channel 1 scsi: target: Reset t_task_cdb pointer in error case scsi: ufs: core: Fix EH failure after W-LUN resume errorpull/1354/merge
commit
6a1636e066
|
|
@ -950,6 +950,19 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps
|
||||||
|
|
||||||
q = bdev_get_queue(p->path.dev->bdev);
|
q = bdev_get_queue(p->path.dev->bdev);
|
||||||
attached_handler_name = scsi_dh_attached_handler_name(q, GFP_KERNEL);
|
attached_handler_name = scsi_dh_attached_handler_name(q, GFP_KERNEL);
|
||||||
|
if (IS_ERR(attached_handler_name)) {
|
||||||
|
if (PTR_ERR(attached_handler_name) == -ENODEV) {
|
||||||
|
if (m->hw_handler_name) {
|
||||||
|
DMERR("hardware handlers are only allowed for SCSI devices");
|
||||||
|
kfree(m->hw_handler_name);
|
||||||
|
m->hw_handler_name = NULL;
|
||||||
|
}
|
||||||
|
attached_handler_name = NULL;
|
||||||
|
} else {
|
||||||
|
r = PTR_ERR(attached_handler_name);
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (attached_handler_name || m->hw_handler_name) {
|
if (attached_handler_name || m->hw_handler_name) {
|
||||||
INIT_DELAYED_WORK(&p->activate_path, activate_path_work);
|
INIT_DELAYED_WORK(&p->activate_path, activate_path_work);
|
||||||
r = setup_scsi_dh(p->path.dev->bdev, m, &attached_handler_name, &ti->error);
|
r = setup_scsi_dh(p->path.dev->bdev, m, &attached_handler_name, &ti->error);
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,6 @@ config PHANTOM
|
||||||
|
|
||||||
config RPMB
|
config RPMB
|
||||||
tristate "RPMB partition interface"
|
tristate "RPMB partition interface"
|
||||||
depends on MMC || SCSI_UFSHCD
|
|
||||||
help
|
help
|
||||||
Unified RPMB unit interface for RPMB capable devices such as eMMC and
|
Unified RPMB unit interface for RPMB capable devices such as eMMC and
|
||||||
UFS. Provides interface for in-kernel security controllers to access
|
UFS. Provides interface for in-kernel security controllers to access
|
||||||
|
|
|
||||||
|
|
@ -1260,6 +1260,7 @@ static void imm_detach(struct parport *pb)
|
||||||
imm_struct *dev;
|
imm_struct *dev;
|
||||||
list_for_each_entry(dev, &imm_hosts, list) {
|
list_for_each_entry(dev, &imm_hosts, list) {
|
||||||
if (dev->dev->port == pb) {
|
if (dev->dev->port == pb) {
|
||||||
|
disable_delayed_work_sync(&dev->imm_tq);
|
||||||
list_del_init(&dev->list);
|
list_del_init(&dev->list);
|
||||||
scsi_remove_host(dev->host);
|
scsi_remove_host(dev->host);
|
||||||
scsi_host_put(dev->host);
|
scsi_host_put(dev->host);
|
||||||
|
|
|
||||||
|
|
@ -61,8 +61,8 @@
|
||||||
#include <linux/hdreg.h>
|
#include <linux/hdreg.h>
|
||||||
#include <linux/reboot.h>
|
#include <linux/reboot.h>
|
||||||
#include <linux/stringify.h>
|
#include <linux/stringify.h>
|
||||||
|
#include <linux/irq.h>
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
#include <asm/irq.h>
|
|
||||||
#include <asm/processor.h>
|
#include <asm/processor.h>
|
||||||
#include <scsi/scsi.h>
|
#include <scsi/scsi.h>
|
||||||
#include <scsi/scsi_host.h>
|
#include <scsi/scsi_host.h>
|
||||||
|
|
@ -7843,6 +7843,30 @@ static int ipr_dump_mailbox_wait(struct ipr_cmnd *ipr_cmd)
|
||||||
return IPR_RC_JOB_RETURN;
|
return IPR_RC_JOB_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ipr_set_affinity_nobalance
|
||||||
|
* @ioa_cfg: ipr_ioa_cfg struct for an ipr device
|
||||||
|
* @flag: bool
|
||||||
|
* true: ensable "IRQ_NO_BALANCING" bit for msix interrupt
|
||||||
|
* false: disable "IRQ_NO_BALANCING" bit for msix interrupt
|
||||||
|
* Description: This function will be called to disable/enable
|
||||||
|
* "IRQ_NO_BALANCING" to avoid irqbalance daemon
|
||||||
|
* kicking in during adapter reset.
|
||||||
|
**/
|
||||||
|
static void ipr_set_affinity_nobalance(struct ipr_ioa_cfg *ioa_cfg, bool flag)
|
||||||
|
{
|
||||||
|
int irq, i;
|
||||||
|
|
||||||
|
for (i = 0; i < ioa_cfg->nvectors; i++) {
|
||||||
|
irq = pci_irq_vector(ioa_cfg->pdev, i);
|
||||||
|
|
||||||
|
if (flag)
|
||||||
|
irq_set_status_flags(irq, IRQ_NO_BALANCING);
|
||||||
|
else
|
||||||
|
irq_clear_status_flags(irq, IRQ_NO_BALANCING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ipr_reset_restore_cfg_space - Restore PCI config space.
|
* ipr_reset_restore_cfg_space - Restore PCI config space.
|
||||||
* @ipr_cmd: ipr command struct
|
* @ipr_cmd: ipr command struct
|
||||||
|
|
@ -7866,6 +7890,7 @@ static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd)
|
||||||
return IPR_RC_JOB_CONTINUE;
|
return IPR_RC_JOB_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ipr_set_affinity_nobalance(ioa_cfg, false);
|
||||||
ipr_fail_all_ops(ioa_cfg);
|
ipr_fail_all_ops(ioa_cfg);
|
||||||
|
|
||||||
if (ioa_cfg->sis64) {
|
if (ioa_cfg->sis64) {
|
||||||
|
|
@ -7945,6 +7970,7 @@ static int ipr_reset_start_bist(struct ipr_cmnd *ipr_cmd)
|
||||||
rc = pci_write_config_byte(ioa_cfg->pdev, PCI_BIST, PCI_BIST_START);
|
rc = pci_write_config_byte(ioa_cfg->pdev, PCI_BIST, PCI_BIST_START);
|
||||||
|
|
||||||
if (rc == PCIBIOS_SUCCESSFUL) {
|
if (rc == PCIBIOS_SUCCESSFUL) {
|
||||||
|
ipr_set_affinity_nobalance(ioa_cfg, true);
|
||||||
ipr_cmd->job_step = ipr_reset_bist_done;
|
ipr_cmd->job_step = ipr_reset_bist_done;
|
||||||
ipr_reset_start_timer(ipr_cmd, IPR_WAIT_FOR_BIST_TIMEOUT);
|
ipr_reset_start_timer(ipr_cmd, IPR_WAIT_FOR_BIST_TIMEOUT);
|
||||||
rc = IPR_RC_JOB_RETURN;
|
rc = IPR_RC_JOB_RETURN;
|
||||||
|
|
|
||||||
|
|
@ -141,6 +141,7 @@ Undo_event_q:
|
||||||
Undo_ports:
|
Undo_ports:
|
||||||
sas_unregister_ports(sas_ha);
|
sas_unregister_ports(sas_ha);
|
||||||
Undo_phys:
|
Undo_phys:
|
||||||
|
sas_unregister_phys(sas_ha);
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *dev);
|
||||||
void sas_scsi_recover_host(struct Scsi_Host *shost);
|
void sas_scsi_recover_host(struct Scsi_Host *shost);
|
||||||
|
|
||||||
int sas_register_phys(struct sas_ha_struct *sas_ha);
|
int sas_register_phys(struct sas_ha_struct *sas_ha);
|
||||||
|
void sas_unregister_phys(struct sas_ha_struct *sas_ha);
|
||||||
|
|
||||||
struct asd_sas_event *sas_alloc_event(struct asd_sas_phy *phy, gfp_t gfp_flags);
|
struct asd_sas_event *sas_alloc_event(struct asd_sas_phy *phy, gfp_t gfp_flags);
|
||||||
void sas_free_event(struct asd_sas_event *event);
|
void sas_free_event(struct asd_sas_event *event);
|
||||||
|
|
@ -145,20 +146,6 @@ static inline void sas_fail_probe(struct domain_device *dev, const char *func, i
|
||||||
func, dev->parent ? "exp-attached" :
|
func, dev->parent ? "exp-attached" :
|
||||||
"direct-attached",
|
"direct-attached",
|
||||||
SAS_ADDR(dev->sas_addr), err);
|
SAS_ADDR(dev->sas_addr), err);
|
||||||
|
|
||||||
/*
|
|
||||||
* If the device probe failed, the expander phy attached address
|
|
||||||
* needs to be reset so that the phy will not be treated as flutter
|
|
||||||
* in the next revalidation
|
|
||||||
*/
|
|
||||||
if (dev->parent && !dev_is_expander(dev->dev_type)) {
|
|
||||||
struct sas_phy *phy = dev->phy;
|
|
||||||
struct domain_device *parent = dev->parent;
|
|
||||||
struct ex_phy *ex_phy = &parent->ex_dev.ex_phy[phy->number];
|
|
||||||
|
|
||||||
memset(ex_phy->attached_sas_addr, 0, SAS_ADDR_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
sas_unregister_dev(dev->port, dev);
|
sas_unregister_dev(dev->port, dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -116,6 +116,7 @@ static void sas_phye_shutdown(struct work_struct *work)
|
||||||
int sas_register_phys(struct sas_ha_struct *sas_ha)
|
int sas_register_phys(struct sas_ha_struct *sas_ha)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
int err;
|
||||||
|
|
||||||
/* Now register the phys. */
|
/* Now register the phys. */
|
||||||
for (i = 0; i < sas_ha->num_phys; i++) {
|
for (i = 0; i < sas_ha->num_phys; i++) {
|
||||||
|
|
@ -132,8 +133,10 @@ int sas_register_phys(struct sas_ha_struct *sas_ha)
|
||||||
phy->frame_rcvd_size = 0;
|
phy->frame_rcvd_size = 0;
|
||||||
|
|
||||||
phy->phy = sas_phy_alloc(&sas_ha->shost->shost_gendev, i);
|
phy->phy = sas_phy_alloc(&sas_ha->shost->shost_gendev, i);
|
||||||
if (!phy->phy)
|
if (!phy->phy) {
|
||||||
return -ENOMEM;
|
err = -ENOMEM;
|
||||||
|
goto rollback;
|
||||||
|
}
|
||||||
|
|
||||||
phy->phy->identify.initiator_port_protocols =
|
phy->phy->identify.initiator_port_protocols =
|
||||||
phy->iproto;
|
phy->iproto;
|
||||||
|
|
@ -146,10 +149,34 @@ int sas_register_phys(struct sas_ha_struct *sas_ha)
|
||||||
phy->phy->maximum_linkrate = SAS_LINK_RATE_UNKNOWN;
|
phy->phy->maximum_linkrate = SAS_LINK_RATE_UNKNOWN;
|
||||||
phy->phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
|
phy->phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
|
||||||
|
|
||||||
sas_phy_add(phy->phy);
|
err = sas_phy_add(phy->phy);
|
||||||
|
if (err) {
|
||||||
|
sas_phy_free(phy->phy);
|
||||||
|
goto rollback;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
rollback:
|
||||||
|
for (i-- ; i >= 0 ; i--) {
|
||||||
|
struct asd_sas_phy *phy = sas_ha->sas_phy[i];
|
||||||
|
|
||||||
|
sas_phy_delete(phy->phy);
|
||||||
|
sas_phy_free(phy->phy);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sas_unregister_phys(struct sas_ha_struct *sas_ha)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0 ; i < sas_ha->num_phys ; i++) {
|
||||||
|
struct asd_sas_phy *phy = sas_ha->sas_phy[i];
|
||||||
|
|
||||||
|
sas_phy_delete(phy->phy);
|
||||||
|
sas_phy_free(phy->phy);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const work_func_t sas_phy_event_fns[PHY_NUM_EVENTS] = {
|
const work_func_t sas_phy_event_fns[PHY_NUM_EVENTS] = {
|
||||||
|
|
|
||||||
|
|
@ -56,8 +56,8 @@ extern struct list_head mrioc_list;
|
||||||
extern int prot_mask;
|
extern int prot_mask;
|
||||||
extern atomic64_t event_counter;
|
extern atomic64_t event_counter;
|
||||||
|
|
||||||
#define MPI3MR_DRIVER_VERSION "8.15.0.5.50"
|
#define MPI3MR_DRIVER_VERSION "8.15.0.5.51"
|
||||||
#define MPI3MR_DRIVER_RELDATE "12-August-2025"
|
#define MPI3MR_DRIVER_RELDATE "18-November-2025"
|
||||||
|
|
||||||
#define MPI3MR_DRIVER_NAME "mpi3mr"
|
#define MPI3MR_DRIVER_NAME "mpi3mr"
|
||||||
#define MPI3MR_DRIVER_LICENSE "GPL"
|
#define MPI3MR_DRIVER_LICENSE "GPL"
|
||||||
|
|
|
||||||
|
|
@ -1184,6 +1184,8 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc,
|
||||||
if (is_added == true)
|
if (is_added == true)
|
||||||
tgtdev->io_throttle_enabled =
|
tgtdev->io_throttle_enabled =
|
||||||
(flags & MPI3_DEVICE0_FLAGS_IO_THROTTLING_REQUIRED) ? 1 : 0;
|
(flags & MPI3_DEVICE0_FLAGS_IO_THROTTLING_REQUIRED) ? 1 : 0;
|
||||||
|
if (!mrioc->sas_transport_enabled)
|
||||||
|
tgtdev->non_stl = 1;
|
||||||
|
|
||||||
switch (flags & MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_MASK) {
|
switch (flags & MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_MASK) {
|
||||||
case MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_256_LB:
|
case MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_256_LB:
|
||||||
|
|
@ -4844,7 +4846,7 @@ static int mpi3mr_target_alloc(struct scsi_target *starget)
|
||||||
spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
|
spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
|
||||||
if (starget->channel == mrioc->scsi_device_channel) {
|
if (starget->channel == mrioc->scsi_device_channel) {
|
||||||
tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id);
|
tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id);
|
||||||
if (tgt_dev && !tgt_dev->is_hidden) {
|
if (tgt_dev && !tgt_dev->is_hidden && tgt_dev->non_stl) {
|
||||||
scsi_tgt_priv_data->starget = starget;
|
scsi_tgt_priv_data->starget = starget;
|
||||||
scsi_tgt_priv_data->dev_handle = tgt_dev->dev_handle;
|
scsi_tgt_priv_data->dev_handle = tgt_dev->dev_handle;
|
||||||
scsi_tgt_priv_data->perst_id = tgt_dev->perst_id;
|
scsi_tgt_priv_data->perst_id = tgt_dev->perst_id;
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
#include <linux/crash_dump.h>
|
#include <linux/crash_dump.h>
|
||||||
#include <linux/trace_events.h>
|
#include <linux/trace_events.h>
|
||||||
#include <linux/trace.h>
|
#include <linux/trace.h>
|
||||||
|
#include <linux/irq.h>
|
||||||
|
|
||||||
#include <scsi/scsi_tcq.h>
|
#include <scsi/scsi_tcq.h>
|
||||||
#include <scsi/scsicam.h>
|
#include <scsi/scsicam.h>
|
||||||
|
|
@ -7776,6 +7777,31 @@ static void qla_pci_error_cleanup(scsi_qla_host_t *vha)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* qla2xxx_set_affinity_nobalance
|
||||||
|
* @pdev: pci_dev struct for a qla2xxx device
|
||||||
|
* @flag: bool
|
||||||
|
* true: enable "IRQ_NO_BALANCING" bit for msix interrupt
|
||||||
|
* false: disable "IRQ_NO_BALANCING" bit for msix interrupt
|
||||||
|
* Description: This function will be called to disable/enable
|
||||||
|
* "IRQ_NO_BALANCING" to avoid irqbalance daemon
|
||||||
|
* kicking in during adapter reset.
|
||||||
|
**/
|
||||||
|
|
||||||
|
static void qla2xxx_set_affinity_nobalance(struct pci_dev *pdev, bool flag)
|
||||||
|
{
|
||||||
|
int irq, i;
|
||||||
|
|
||||||
|
for (i = 0; i < QLA_BASE_VECTORS; i++) {
|
||||||
|
irq = pci_irq_vector(pdev, i);
|
||||||
|
|
||||||
|
if (flag)
|
||||||
|
irq_set_status_flags(irq, IRQ_NO_BALANCING);
|
||||||
|
else
|
||||||
|
irq_clear_status_flags(irq, IRQ_NO_BALANCING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static pci_ers_result_t
|
static pci_ers_result_t
|
||||||
qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
|
qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
|
||||||
{
|
{
|
||||||
|
|
@ -7794,6 +7820,8 @@ qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qla2xxx_set_affinity_nobalance(pdev, false);
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case pci_channel_io_normal:
|
case pci_channel_io_normal:
|
||||||
qla_pci_set_eeh_busy(vha);
|
qla_pci_set_eeh_busy(vha);
|
||||||
|
|
@ -7930,6 +7958,8 @@ exit_slot_reset:
|
||||||
ql_dbg(ql_dbg_aer, base_vha, 0x900e,
|
ql_dbg(ql_dbg_aer, base_vha, 0x900e,
|
||||||
"Slot Reset returning %x.\n", ret);
|
"Slot Reset returning %x.\n", ret);
|
||||||
|
|
||||||
|
qla2xxx_set_affinity_nobalance(pdev, true);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1552,7 +1552,7 @@ static int qla4_82xx_cmdpeg_ready(struct scsi_qla_host *ha, int pegtune_val)
|
||||||
(val == PHAN_INITIALIZE_ACK))
|
(val == PHAN_INITIALIZE_ACK))
|
||||||
return 0;
|
return 0;
|
||||||
set_current_state(TASK_UNINTERRUPTIBLE);
|
set_current_state(TASK_UNINTERRUPTIBLE);
|
||||||
schedule_timeout(500);
|
schedule_timeout(msecs_to_jiffies(500));
|
||||||
|
|
||||||
} while (--retries);
|
} while (--retries);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -353,7 +353,8 @@ EXPORT_SYMBOL_GPL(scsi_dh_attach);
|
||||||
* that may have a device handler attached
|
* that may have a device handler attached
|
||||||
* @gfp - the GFP mask used in the kmalloc() call when allocating memory
|
* @gfp - the GFP mask used in the kmalloc() call when allocating memory
|
||||||
*
|
*
|
||||||
* Returns name of attached handler, NULL if no handler is attached.
|
* Returns name of attached handler, NULL if no handler is attached, or
|
||||||
|
* and error pointer if an error occurred.
|
||||||
* Caller must take care to free the returned string.
|
* Caller must take care to free the returned string.
|
||||||
*/
|
*/
|
||||||
const char *scsi_dh_attached_handler_name(struct request_queue *q, gfp_t gfp)
|
const char *scsi_dh_attached_handler_name(struct request_queue *q, gfp_t gfp)
|
||||||
|
|
@ -363,10 +364,11 @@ const char *scsi_dh_attached_handler_name(struct request_queue *q, gfp_t gfp)
|
||||||
|
|
||||||
sdev = scsi_device_from_queue(q);
|
sdev = scsi_device_from_queue(q);
|
||||||
if (!sdev)
|
if (!sdev)
|
||||||
return NULL;
|
return ERR_PTR(-ENODEV);
|
||||||
|
|
||||||
if (sdev->handler)
|
if (sdev->handler)
|
||||||
handler_name = kstrdup(sdev->handler->name, gfp);
|
handler_name = kstrdup(sdev->handler->name, gfp) ? :
|
||||||
|
ERR_PTR(-ENOMEM);
|
||||||
put_device(&sdev->sdev_gendev);
|
put_device(&sdev->sdev_gendev);
|
||||||
return handler_name;
|
return handler_name;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2801,7 +2801,7 @@ EXPORT_SYMBOL_GPL(sdev_evt_send_simple);
|
||||||
*
|
*
|
||||||
* Must be called with user context, may sleep.
|
* Must be called with user context, may sleep.
|
||||||
*
|
*
|
||||||
* Returns zero if unsuccessful or an error if not.
|
* Returns zero if successful or an error if not.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
scsi_device_quiesce(struct scsi_device *sdev)
|
scsi_device_quiesce(struct scsi_device *sdev)
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,7 @@
|
||||||
* Copyright (C) 2011 Chris Boot <bootc@bootc.net>
|
* Copyright (C) 2011 Chris Boot <bootc@bootc.net>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define KMSG_COMPONENT "sbp_target"
|
#define pr_fmt(fmt) "sbp_target: " fmt
|
||||||
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
|
|
||||||
|
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
|
|
||||||
|
|
@ -1524,6 +1524,7 @@ target_cmd_init_cdb(struct se_cmd *cmd, unsigned char *cdb, gfp_t gfp)
|
||||||
if (scsi_command_size(cdb) > sizeof(cmd->__t_task_cdb)) {
|
if (scsi_command_size(cdb) > sizeof(cmd->__t_task_cdb)) {
|
||||||
cmd->t_task_cdb = kzalloc(scsi_command_size(cdb), gfp);
|
cmd->t_task_cdb = kzalloc(scsi_command_size(cdb), gfp);
|
||||||
if (!cmd->t_task_cdb) {
|
if (!cmd->t_task_cdb) {
|
||||||
|
cmd->t_task_cdb = &cmd->__t_task_cdb[0];
|
||||||
pr_err("Unable to allocate cmd->t_task_cdb"
|
pr_err("Unable to allocate cmd->t_task_cdb"
|
||||||
" %u > sizeof(cmd->__t_task_cdb): %lu ops\n",
|
" %u > sizeof(cmd->__t_task_cdb): %lu ops\n",
|
||||||
scsi_command_size(cdb),
|
scsi_command_size(cdb),
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
menuconfig SCSI_UFSHCD
|
menuconfig SCSI_UFSHCD
|
||||||
tristate "Universal Flash Storage Controller"
|
tristate "Universal Flash Storage Controller"
|
||||||
depends on SCSI && SCSI_DMA
|
depends on SCSI && SCSI_DMA
|
||||||
|
depends on RPMB || !RPMB
|
||||||
select PM_DEVFREQ
|
select PM_DEVFREQ
|
||||||
select DEVFREQ_GOV_SIMPLE_ONDEMAND
|
select DEVFREQ_GOV_SIMPLE_ONDEMAND
|
||||||
select NLS
|
select NLS
|
||||||
|
|
|
||||||
|
|
@ -1455,15 +1455,14 @@ out:
|
||||||
static void ufshcd_clock_scaling_unprepare(struct ufs_hba *hba, int err)
|
static void ufshcd_clock_scaling_unprepare(struct ufs_hba *hba, int err)
|
||||||
{
|
{
|
||||||
up_write(&hba->clk_scaling_lock);
|
up_write(&hba->clk_scaling_lock);
|
||||||
|
mutex_unlock(&hba->wb_mutex);
|
||||||
|
blk_mq_unquiesce_tagset(&hba->host->tag_set);
|
||||||
|
mutex_unlock(&hba->host->scan_mutex);
|
||||||
|
|
||||||
/* Enable Write Booster if current gear requires it else disable it */
|
/* Enable Write Booster if current gear requires it else disable it */
|
||||||
if (ufshcd_enable_wb_if_scaling_up(hba) && !err)
|
if (ufshcd_enable_wb_if_scaling_up(hba) && !err)
|
||||||
ufshcd_wb_toggle(hba, hba->pwr_info.gear_rx >= hba->clk_scaling.wb_gear);
|
ufshcd_wb_toggle(hba, hba->pwr_info.gear_rx >= hba->clk_scaling.wb_gear);
|
||||||
|
|
||||||
mutex_unlock(&hba->wb_mutex);
|
|
||||||
|
|
||||||
blk_mq_unquiesce_tagset(&hba->host->tag_set);
|
|
||||||
mutex_unlock(&hba->host->scan_mutex);
|
|
||||||
ufshcd_release(hba);
|
ufshcd_release(hba);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -6504,6 +6503,11 @@ static void ufshcd_clk_scaling_suspend(struct ufs_hba *hba, bool suspend)
|
||||||
|
|
||||||
static void ufshcd_err_handling_prepare(struct ufs_hba *hba)
|
static void ufshcd_err_handling_prepare(struct ufs_hba *hba)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* A WLUN resume failure could potentially lead to the HBA being
|
||||||
|
* runtime suspended, so take an extra reference on hba->dev.
|
||||||
|
*/
|
||||||
|
pm_runtime_get_sync(hba->dev);
|
||||||
ufshcd_rpm_get_sync(hba);
|
ufshcd_rpm_get_sync(hba);
|
||||||
if (pm_runtime_status_suspended(&hba->ufs_device_wlun->sdev_gendev) ||
|
if (pm_runtime_status_suspended(&hba->ufs_device_wlun->sdev_gendev) ||
|
||||||
hba->is_sys_suspended) {
|
hba->is_sys_suspended) {
|
||||||
|
|
@ -6543,6 +6547,7 @@ static void ufshcd_err_handling_unprepare(struct ufs_hba *hba)
|
||||||
if (ufshcd_is_clkscaling_supported(hba))
|
if (ufshcd_is_clkscaling_supported(hba))
|
||||||
ufshcd_clk_scaling_suspend(hba, false);
|
ufshcd_clk_scaling_suspend(hba, false);
|
||||||
ufshcd_rpm_put(hba);
|
ufshcd_rpm_put(hba);
|
||||||
|
pm_runtime_put(hba->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool ufshcd_err_handling_should_stop(struct ufs_hba *hba)
|
static inline bool ufshcd_err_handling_should_stop(struct ufs_hba *hba)
|
||||||
|
|
@ -6557,28 +6562,42 @@ static inline bool ufshcd_err_handling_should_stop(struct ufs_hba *hba)
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
static void ufshcd_recover_pm_error(struct ufs_hba *hba)
|
static void ufshcd_recover_pm_error(struct ufs_hba *hba)
|
||||||
{
|
{
|
||||||
|
struct scsi_target *starget = hba->ufs_device_wlun->sdev_target;
|
||||||
struct Scsi_Host *shost = hba->host;
|
struct Scsi_Host *shost = hba->host;
|
||||||
struct scsi_device *sdev;
|
struct scsi_device *sdev;
|
||||||
struct request_queue *q;
|
struct request_queue *q;
|
||||||
int ret;
|
bool resume_sdev_queues = false;
|
||||||
|
|
||||||
hba->is_sys_suspended = false;
|
hba->is_sys_suspended = false;
|
||||||
/*
|
|
||||||
* Set RPM status of wlun device to RPM_ACTIVE,
|
|
||||||
* this also clears its runtime error.
|
|
||||||
*/
|
|
||||||
ret = pm_runtime_set_active(&hba->ufs_device_wlun->sdev_gendev);
|
|
||||||
|
|
||||||
/* hba device might have a runtime error otherwise */
|
/*
|
||||||
if (ret)
|
* Ensure the parent's error status is cleared before proceeding
|
||||||
ret = pm_runtime_set_active(hba->dev);
|
* to the child, as the parent must be active to activate the child.
|
||||||
|
*/
|
||||||
|
if (hba->dev->power.runtime_error) {
|
||||||
|
/* hba->dev has no functional parent thus simplily set RPM_ACTIVE */
|
||||||
|
pm_runtime_set_active(hba->dev);
|
||||||
|
resume_sdev_queues = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hba->ufs_device_wlun->sdev_gendev.power.runtime_error) {
|
||||||
|
/*
|
||||||
|
* starget, parent of wlun, might be suspended if wlun resume failed.
|
||||||
|
* Make sure parent is resumed before set child (wlun) active.
|
||||||
|
*/
|
||||||
|
pm_runtime_get_sync(&starget->dev);
|
||||||
|
pm_runtime_set_active(&hba->ufs_device_wlun->sdev_gendev);
|
||||||
|
pm_runtime_put_sync(&starget->dev);
|
||||||
|
resume_sdev_queues = true;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If wlun device had runtime error, we also need to resume those
|
* If wlun device had runtime error, we also need to resume those
|
||||||
* consumer scsi devices in case any of them has failed to be
|
* consumer scsi devices in case any of them has failed to be
|
||||||
* resumed due to supplier runtime resume failure. This is to unblock
|
* resumed due to supplier runtime resume failure. This is to unblock
|
||||||
* blk_queue_enter in case there are bios waiting inside it.
|
* blk_queue_enter in case there are bios waiting inside it.
|
||||||
*/
|
*/
|
||||||
if (!ret) {
|
if (resume_sdev_queues) {
|
||||||
shost_for_each_device(sdev, shost) {
|
shost_for_each_device(sdev, shost) {
|
||||||
q = sdev->request_queue;
|
q = sdev->request_queue;
|
||||||
if (q->dev && (q->rpm_status == RPM_SUSPENDED ||
|
if (q->dev && (q->rpm_status == RPM_SUSPENDED ||
|
||||||
|
|
@ -6679,19 +6698,22 @@ static void ufshcd_err_handler(struct work_struct *work)
|
||||||
hba->saved_uic_err, hba->force_reset,
|
hba->saved_uic_err, hba->force_reset,
|
||||||
ufshcd_is_link_broken(hba) ? "; link is broken" : "");
|
ufshcd_is_link_broken(hba) ? "; link is broken" : "");
|
||||||
|
|
||||||
/*
|
if (hba->ufs_device_wlun) {
|
||||||
* Use ufshcd_rpm_get_noresume() here to safely perform link recovery
|
/*
|
||||||
* even if an error occurs during runtime suspend or runtime resume.
|
* Use ufshcd_rpm_get_noresume() here to safely perform link
|
||||||
* This avoids potential deadlocks that could happen if we tried to
|
* recovery even if an error occurs during runtime suspend or
|
||||||
* resume the device while a PM operation is already in progress.
|
* runtime resume. This avoids potential deadlocks that could
|
||||||
*/
|
* happen if we tried to resume the device while a PM operation
|
||||||
ufshcd_rpm_get_noresume(hba);
|
* is already in progress.
|
||||||
if (hba->pm_op_in_progress) {
|
*/
|
||||||
ufshcd_link_recovery(hba);
|
ufshcd_rpm_get_noresume(hba);
|
||||||
|
if (hba->pm_op_in_progress) {
|
||||||
|
ufshcd_link_recovery(hba);
|
||||||
|
ufshcd_rpm_put(hba);
|
||||||
|
return;
|
||||||
|
}
|
||||||
ufshcd_rpm_put(hba);
|
ufshcd_rpm_put(hba);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
ufshcd_rpm_put(hba);
|
|
||||||
|
|
||||||
down(&hba->host_sem);
|
down(&hba->host_sem);
|
||||||
spin_lock_irqsave(hba->host->host_lock, flags);
|
spin_lock_irqsave(hba->host->host_lock, flags);
|
||||||
|
|
|
||||||
|
|
@ -1769,10 +1769,9 @@ static void ufs_qcom_dump_testbus(struct ufs_hba *hba)
|
||||||
{
|
{
|
||||||
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
|
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
|
||||||
int i, j, nminor = 0, testbus_len = 0;
|
int i, j, nminor = 0, testbus_len = 0;
|
||||||
u32 *testbus __free(kfree) = NULL;
|
|
||||||
char *prefix;
|
char *prefix;
|
||||||
|
|
||||||
testbus = kmalloc_array(256, sizeof(u32), GFP_KERNEL);
|
u32 *testbus __free(kfree) = kmalloc_array(256, sizeof(u32), GFP_KERNEL);
|
||||||
if (!testbus)
|
if (!testbus)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -1794,13 +1793,12 @@ static void ufs_qcom_dump_testbus(struct ufs_hba *hba)
|
||||||
static int ufs_qcom_dump_regs(struct ufs_hba *hba, size_t offset, size_t len,
|
static int ufs_qcom_dump_regs(struct ufs_hba *hba, size_t offset, size_t len,
|
||||||
const char *prefix, void __iomem *base)
|
const char *prefix, void __iomem *base)
|
||||||
{
|
{
|
||||||
u32 *regs __free(kfree) = NULL;
|
|
||||||
size_t pos;
|
size_t pos;
|
||||||
|
|
||||||
if (offset % 4 != 0 || len % 4 != 0)
|
if (offset % 4 != 0 || len % 4 != 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
regs = kzalloc(len, GFP_ATOMIC);
|
u32 *regs __free(kfree) = kzalloc(len, GFP_ATOMIC);
|
||||||
if (!regs)
|
if (!regs)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue