From b8ef3204f460912a46659cdc74d237adbe705053 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Fri, 6 Aug 2010 03:02:37 -0500 Subject: [SCSI] fc class: add fc host default default dev loss setting This patch adds a fc_host setting to store the default dev_loss_tmo. It is used if the driver has a callack to get the value from the LLD. If the callback is not set, then we use the fc class module default value. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- include/scsi/scsi_transport_fc.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include/scsi') diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h index 87d81b3ce564..9f98fca9b763 100644 --- a/include/scsi/scsi_transport_fc.h +++ b/include/scsi/scsi_transport_fc.h @@ -496,6 +496,7 @@ struct fc_host_attrs { u64 fabric_name; char symbolic_name[FC_SYMBOLIC_NAME_SIZE]; char system_hostname[FC_SYMBOLIC_NAME_SIZE]; + u32 def_dev_loss_tmo; /* Private (Transport-managed) Attributes */ enum fc_tgtid_binding_type tgtid_bind_type; @@ -580,6 +581,8 @@ struct fc_host_attrs { (((struct fc_host_attrs *)(x)->shost_data)->devloss_work_q_name) #define fc_host_devloss_work_q(x) \ (((struct fc_host_attrs *)(x)->shost_data)->devloss_work_q) +#define fc_host_def_dev_loss_tmo(x) \ + (((struct fc_host_attrs *)(x)->shost_data)->def_dev_loss_tmo) struct fc_bsg_buffer { @@ -640,6 +643,7 @@ struct fc_function_template { void (*get_host_fabric_name)(struct Scsi_Host *); void (*get_host_symbolic_name)(struct Scsi_Host *); void (*set_host_system_hostname)(struct Scsi_Host *); + void (*get_host_def_dev_loss_tmo)(struct Scsi_Host *); struct fc_host_statistics * (*get_fc_host_stats)(struct Scsi_Host *); void (*reset_fc_host_stats)(struct Scsi_Host *); -- cgit v1.2.3-59-g8ed1b From 43ca910a9c90566308f39f51ac03a55f94a5f83c Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 15 Sep 2010 16:52:32 -0500 Subject: [SCSI] fc class: add fc host dev loss sysfs file This adds a fc host dev loss sysfs file. Instead of calling into the driver using the get_host_def_dev_loss_tmo callback, we allow drivers to init the dev loss like is done for other fc host params, and then the fc class will handle updating the value if the user writes to the new sysfs file. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/scsi_transport_fc.c | 124 +++++++++++++++++++++++++++------------ include/scsi/scsi_transport_fc.h | 7 +-- 2 files changed, 91 insertions(+), 40 deletions(-) (limited to 'include/scsi') diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 78486d540652..998c01be3234 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -52,6 +52,25 @@ static int fc_bsg_rportadd(struct Scsi_Host *, struct fc_rport *); static void fc_bsg_remove(struct request_queue *); static void fc_bsg_goose_queue(struct fc_rport *); +/* + * Module Parameters + */ + +/* + * dev_loss_tmo: the default number of seconds that the FC transport + * should insulate the loss of a remote port. + * The maximum will be capped by the value of SCSI_DEVICE_BLOCK_MAX_TIMEOUT. + */ +static unsigned int fc_dev_loss_tmo = 60; /* seconds */ + +module_param_named(dev_loss_tmo, fc_dev_loss_tmo, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(dev_loss_tmo, + "Maximum number of seconds that the FC transport should" + " insulate the loss of a remote port. Once this value is" + " exceeded, the scsi target is removed. Value should be" + " between 1 and SCSI_DEVICE_BLOCK_MAX_TIMEOUT if" + " fast_io_fail_tmo is not set."); + /* * Redefine so that we can have same named attributes in the * sdev/starget/host objects. @@ -408,6 +427,7 @@ static int fc_host_setup(struct transport_container *tc, struct device *dev, if (!fc_host->work_q) return -ENOMEM; + fc_host->dev_loss_tmo = fc_dev_loss_tmo; snprintf(fc_host->devloss_work_q_name, sizeof(fc_host->devloss_work_q_name), "fc_dl_%d", shost->host_no); @@ -461,25 +481,6 @@ static DECLARE_TRANSPORT_CLASS(fc_vport_class, NULL, NULL); -/* - * Module Parameters - */ - -/* - * dev_loss_tmo: the default number of seconds that the FC transport - * should insulate the loss of a remote port. - * The maximum will be capped by the value of SCSI_DEVICE_BLOCK_MAX_TIMEOUT. - */ -static unsigned int fc_dev_loss_tmo = 60; /* seconds */ - -module_param_named(dev_loss_tmo, fc_dev_loss_tmo, uint, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(dev_loss_tmo, - "Maximum number of seconds that the FC transport should" - " insulate the loss of a remote port. Once this value is" - " exceeded, the scsi target is removed. Value should be" - " between 1 and SCSI_DEVICE_BLOCK_MAX_TIMEOUT if" - " fast_io_fail_tmo is not set."); - /* * Netlink Infrastructure */ @@ -830,24 +831,32 @@ static FC_DEVICE_ATTR(rport, supported_classes, S_IRUGO, /* * dev_loss_tmo attribute */ -fc_rport_show_function(dev_loss_tmo, "%d\n", 20, ) -static ssize_t -store_fc_rport_dev_loss_tmo(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static int fc_str_to_dev_loss(const char *buf, unsigned long *val) +{ + char *cp; + + *val = simple_strtoul(buf, &cp, 0); + if ((*cp && (*cp != '\n')) || (*val < 0)) + return -EINVAL; + /* + * Check for overflow; dev_loss_tmo is u32 + */ + if (*val > UINT_MAX) + return -EINVAL; + + return 0; +} + +static int fc_rport_set_dev_loss_tmo(struct fc_rport *rport, + unsigned long val) { - unsigned long val; - struct fc_rport *rport = transport_class_to_rport(dev); struct Scsi_Host *shost = rport_to_shost(rport); struct fc_internal *i = to_fc_internal(shost->transportt); - char *cp; + if ((rport->port_state == FC_PORTSTATE_BLOCKED) || (rport->port_state == FC_PORTSTATE_DELETED) || (rport->port_state == FC_PORTSTATE_NOTPRESENT)) return -EBUSY; - val = simple_strtoul(buf, &cp, 0); - if ((*cp && (*cp != '\n')) || (val < 0)) - return -EINVAL; - /* * Check for overflow; dev_loss_tmo is u32 */ @@ -863,6 +872,25 @@ store_fc_rport_dev_loss_tmo(struct device *dev, struct device_attribute *attr, return -EINVAL; i->f->set_rport_dev_loss_tmo(rport, val); + return 0; +} + +fc_rport_show_function(dev_loss_tmo, "%d\n", 20, ) +static ssize_t +store_fc_rport_dev_loss_tmo(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fc_rport *rport = transport_class_to_rport(dev); + unsigned long val; + int rc; + + rc = fc_str_to_dev_loss(buf, &val); + if (rc) + return rc; + + rc = fc_rport_set_dev_loss_tmo(rport, val); + if (rc) + return rc; return count; } static FC_DEVICE_ATTR(rport, dev_loss_tmo, S_IRUGO | S_IWUSR, @@ -1608,8 +1636,35 @@ store_fc_private_host_issue_lip(struct device *dev, static FC_DEVICE_ATTR(host, issue_lip, S_IWUSR, NULL, store_fc_private_host_issue_lip); -fc_private_host_rd_attr(npiv_vports_inuse, "%u\n", 20); +static ssize_t +store_fc_private_host_dev_loss_tmo(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct Scsi_Host *shost = transport_class_to_shost(dev); + struct fc_host_attrs *fc_host = shost_to_fc_host(shost); + struct fc_rport *rport; + unsigned long val, flags; + int rc; + + rc = fc_str_to_dev_loss(buf, &val); + if (rc) + return rc; + + fc_host_dev_loss_tmo(shost) = val; + spin_lock_irqsave(shost->host_lock, flags); + list_for_each_entry(rport, &fc_host->rports, peers) + fc_rport_set_dev_loss_tmo(rport, val); + spin_unlock_irqrestore(shost->host_lock, flags); + return count; +} +fc_private_host_show_function(dev_loss_tmo, "%d\n", 20, ); +static FC_DEVICE_ATTR(host, dev_loss_tmo, S_IRUGO | S_IWUSR, + show_fc_host_dev_loss_tmo, + store_fc_private_host_dev_loss_tmo); + +fc_private_host_rd_attr(npiv_vports_inuse, "%u\n", 20); /* * Host Statistics Management @@ -2165,6 +2220,7 @@ fc_attach_transport(struct fc_function_template *ft) SETUP_HOST_ATTRIBUTE_RW(system_hostname); /* Transport-managed attributes */ + SETUP_PRIVATE_HOST_ATTRIBUTE_RW(dev_loss_tmo); SETUP_PRIVATE_HOST_ATTRIBUTE_RW(tgtid_bind_type); if (ft->issue_fc_host_lip) SETUP_PRIVATE_HOST_ATTRIBUTE_RW(issue_lip); @@ -2525,11 +2581,7 @@ fc_rport_create(struct Scsi_Host *shost, int channel, rport->maxframe_size = -1; rport->supported_classes = FC_COS_UNSPECIFIED; - if (fci->f->get_host_def_dev_loss_tmo) { - fci->f->get_host_def_dev_loss_tmo(shost); - rport->dev_loss_tmo = fc_host_def_dev_loss_tmo(shost); - } else - rport->dev_loss_tmo = fc_dev_loss_tmo; + rport->dev_loss_tmo = fc_host->dev_loss_tmo; memcpy(&rport->node_name, &ids->node_name, sizeof(rport->node_name)); memcpy(&rport->port_name, &ids->port_name, sizeof(rport->port_name)); rport->port_id = ids->port_id; diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h index 9f98fca9b763..59816fe31e68 100644 --- a/include/scsi/scsi_transport_fc.h +++ b/include/scsi/scsi_transport_fc.h @@ -496,7 +496,7 @@ struct fc_host_attrs { u64 fabric_name; char symbolic_name[FC_SYMBOLIC_NAME_SIZE]; char system_hostname[FC_SYMBOLIC_NAME_SIZE]; - u32 def_dev_loss_tmo; + u32 dev_loss_tmo; /* Private (Transport-managed) Attributes */ enum fc_tgtid_binding_type tgtid_bind_type; @@ -581,8 +581,8 @@ struct fc_host_attrs { (((struct fc_host_attrs *)(x)->shost_data)->devloss_work_q_name) #define fc_host_devloss_work_q(x) \ (((struct fc_host_attrs *)(x)->shost_data)->devloss_work_q) -#define fc_host_def_dev_loss_tmo(x) \ - (((struct fc_host_attrs *)(x)->shost_data)->def_dev_loss_tmo) +#define fc_host_dev_loss_tmo(x) \ + (((struct fc_host_attrs *)(x)->shost_data)->dev_loss_tmo) struct fc_bsg_buffer { @@ -643,7 +643,6 @@ struct fc_function_template { void (*get_host_fabric_name)(struct Scsi_Host *); void (*get_host_symbolic_name)(struct Scsi_Host *); void (*set_host_system_hostname)(struct Scsi_Host *); - void (*get_host_def_dev_loss_tmo)(struct Scsi_Host *); struct fc_host_statistics * (*get_fc_host_stats)(struct Scsi_Host *); void (*reset_fc_host_stats)(struct Scsi_Host *); -- cgit v1.2.3-59-g8ed1b From 56dd2c0691a5a387b7b05835fe547dc6fade9407 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Fri, 1 Oct 2010 13:55:47 -0700 Subject: [SCSI] libsas: Don't issue commands to devices that have been hot-removed 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. [maciej.trela@intel.com: removed setting ->gone in sas_deform_port() to permit sync cache commands at module removal] Signed-off-by: Darrick J. Wong Tested-by: Haipao Fan Signed-off-by: Maciej Trela Signed-off-by: Dan Williams Signed-off-by: James Bottomley --- 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(+) (limited to 'include/scsi') diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index ddbade7beec9..e1a395b438ee 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -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; diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 83dd5070a15c..61d81f858a5a 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -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); diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index f0cfba9a1fc8..1787bd2eb4a6 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -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) diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index d06e13be717b..3dec1949f69c 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -205,6 +205,7 @@ struct domain_device { }; void *lldd_dev; + int gone; }; struct sas_discovery_event { -- cgit v1.2.3-59-g8ed1b