libsas: Don't issue commands to devices that have been hot-removed
Subsystems (2)
PATCH 1/1 libsas: Don't issue commands to devices that have been hot-removed
From: Darrick J. Wong <[email protected]>
sd will get hung up issuing commands to flush write cache if a SAS device behind the expander is unplugged without warning. Change libsas to reject commands to domain devices that have already gone away.
[[email protected]: removed setting ->gone in sas_deform_port() to
permit sync cache commands at module removal]
linux-scsi-reference: <[email protected]>
--- drivers/scsi/libsas/sas_ata.c | 4 ++++ drivers/scsi/libsas/sas_expander.c | 3 +++ drivers/scsi/libsas/sas_scsi_host.c | 7 +++++++ include/scsi/libsas.h | 1 + 4 files changed, 15 insertions(+), 0 deletions(-)
drivers/scsi/libsas/sas_ata.c +4 -0
@@ -162,6 +162,10 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)unsigned int xfer =0 ;unsigned int si; +/* If the device fell off, no sense in issuing commands */ +if (dev->gone) +return AC_ERR_SYSTEM ; + task =sas_alloc_task (GFP_ATOMIC );if (!task)return AC_ERR_SYSTEM ;
drivers/scsi/libsas/sas_expander.c +3 -0
@@ -1724,6 +1724,7 @@ static void sas_unregister_ex_tree(struct domain_device *dev)struct domain_device *child, *n;list_for_each_entry_safe (child, n, &ex->children, siblings) { + child->gone =1 ;if (child->dev_type ==EDGE_DEV || child->dev_type ==FANOUT_DEV )sas_unregister_ex_tree (child);
@@ -1744,6 +1745,7 @@ static void sas_unregister_devs_sas_addr(struct domain_device *parent, &ex_dev->children, siblings) {if (SAS_ADDR (child->sas_addr) ==SAS_ADDR (phy->attached_sas_addr)) { + child->gone =1 ;if (child->dev_type ==EDGE_DEV || child->dev_type ==FANOUT_DEV )sas_unregister_ex_tree (child);
@@ -1752,6 +1754,7 @@ static void sas_unregister_devs_sas_addr(struct domain_device *parent,break ; } } + parent->gone =1 ;sas_disable_routing (parent, phy->attached_sas_addr); }memset (phy->attached_sas_addr,0 ,SAS_ADDR_SIZE );
drivers/scsi/libsas/sas_scsi_host.c +7 -0
@@ -228,6 +228,13 @@ int sas_queuecommand(struct scsi_cmnd *cmd, goto out; } +/* If the device fell off, no sense in issuing commands */ +if (dev->gone) { + cmd->result =DID_BAD_TARGET <<16 ; +scsi_done (cmd); + goto out; + } + res = -ENOMEM ; task =sas_create_task (cmd, dev,GFP_ATOMIC );if (!task)
include/scsi/libsas.h +1 -0
@@ -205,6 +205,7 @@ struct domain_device { };void *lldd_dev; +int gone; };struct sas_discovery_event {
RE: [PATCH] libsas: Don't issue commands to devices that have beenhot-removed
[PATCH] libsas: Don't issue commands to devices that have beenhot-removed
From: Darrick J. Wong <[email protected]>
sd will get hung up issuing commands to flush write cache if a SAS device behind the expander is unplugged without warning. Change libsas to reject commands to domain devices that have already gone away.
[[email protected]: removed setting ->gone in sas_deform_port() to
permit sync cache commands at module removal]
linux-scsi-reference: <[email protected]>
--- drivers/scsi/libsas/sas_ata.c | 4 ++++ drivers/scsi/libsas/sas_expander.c | 3 +++ drivers/scsi/libsas/sas_scsi_host.c | 7 +++++++ include/scsi/libsas.h | 1 + 4 files changed, 15 insertions(+), 0 deletions(-)
drivers/scsi/libsas/sas_ata.c +0 -0
@@ -162,6 +162,10 @@ static unsigned int sas_ata_qc_issue(struct
ata_queued_cmd *qc)
unsigned int xfer = 0;
unsigned int si;
+ /* If the device fell off, no sense in issuing commands */
+ if (dev->gone)
+ return AC_ERR_SYSTEM;
+
task = sas_alloc_task(GFP_ATOMIC);
if (!task)
return AC_ERR_SYSTEM;
(quoted diff) +0 -0
b/drivers/scsi/libsas/sas_expander.c
index 83dd507..61d81f8 100644
drivers/scsi/libsas/sas_expander.c +0 -0
@@ -1724,6 +1724,7 @@ static void sas_unregister_ex_tree(struct
domain_device *dev)
struct domain_device *child, *n;
list_for_each_entry_safe(child, n, &ex->children, siblings) {
+ child->gone = 1;
if (child->dev_type == EDGE_DEV ||
child->dev_type == FANOUT_DEV)
sas_unregister_ex_tree(child);
@@ -1744,6 +1745,7 @@ static void sas_unregister_devs_sas_addr(struct domain_device *parent,
&ex_dev->children, siblings) {
if (SAS_ADDR(child->sas_addr) ==
SAS_ADDR(phy->attached_sas_addr)) {
+ child->gone = 1;
if (child->dev_type == EDGE_DEV ||
child->dev_type == FANOUT_DEV)
sas_unregister_ex_tree(child);
@@ -1752,6 +1754,7 @@ static void sas_unregister_devs_sas_addr(struct domain_device *parent,
break;
}
}
+ parent->gone = 1;
sas_disable_routing(parent, phy->attached_sas_addr);
}
memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE);
(quoted diff) +0 -0
b/drivers/scsi/libsas/sas_scsi_host.c
index f0cfba9..1787bd2 100644
drivers/scsi/libsas/sas_scsi_host.c +7 -0
@@ -228,6 +228,13 @@ int sas_queuecommand(struct scsi_cmnd *cmd, goto out; } +/* If the device fell off, no sense in issuing commands */ +if (dev->gone) { + cmd->result =DID_BAD_TARGET <<16 ; +scsi_done (cmd); + goto out; + } + res = -ENOMEM ; task =sas_create_task (cmd, dev,GFP_ATOMIC );if (!task)
include/scsi/libsas.h +1 -0
@@ -205,6 +205,7 @@ struct domain_device { };void *lldd_dev; +int gone; };
[Jack]This one looks good to me! Thanks