aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2012-06-22 02:30:48 -0400
committerJames Bottomley <JBottomley@Parallels.com>2012-07-20 03:58:50 -0400
commit5db45bdc87ce4f503947adf7896586d60c63322c (patch)
treef939bbcf1e6fc2664c54b46949eb8e5af8aa070b
parentb9d5c6b7ef570bea0d22746944d7b58fa7f17b13 (diff)
[SCSI] libsas: enforce eh strategy handlers only in eh context
The strategy handlers may be called in places that are problematic for libsas (i.e. sata resets outside of domain revalidation filtering / libata link recovery), or problematic for userspace (non-blocking ioctl to sleeping reset functions). However, these routines are also called for eh escalations and recovery of scsi_eh_prep_cmnd(), so permit them as long as we are running in the host's error handler, otherwise arrange for them to be triggered in eh_context. Signed-off-by: Dan Williams <dan.j.williams@intel.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
-rw-r--r--drivers/scsi/libsas/sas_discover.c11
-rw-r--r--drivers/scsi/libsas/sas_init.c2
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c121
-rw-r--r--include/scsi/libsas.h10
4 files changed, 140 insertions, 4 deletions
diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c
index ff497ac76cb4..b031d238eb7b 100644
--- a/drivers/scsi/libsas/sas_discover.c
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -39,6 +39,7 @@ void sas_init_dev(struct domain_device *dev)
39{ 39{
40 switch (dev->dev_type) { 40 switch (dev->dev_type) {
41 case SAS_END_DEV: 41 case SAS_END_DEV:
42 INIT_LIST_HEAD(&dev->ssp_dev.eh_list_node);
42 break; 43 break;
43 case EDGE_DEV: 44 case EDGE_DEV:
44 case FANOUT_DEV: 45 case FANOUT_DEV:
@@ -286,6 +287,8 @@ void sas_free_device(struct kref *kref)
286 287
287static void sas_unregister_common_dev(struct asd_sas_port *port, struct domain_device *dev) 288static void sas_unregister_common_dev(struct asd_sas_port *port, struct domain_device *dev)
288{ 289{
290 struct sas_ha_struct *ha = port->ha;
291
289 sas_notify_lldd_dev_gone(dev); 292 sas_notify_lldd_dev_gone(dev);
290 if (!dev->parent) 293 if (!dev->parent)
291 dev->port->port_dev = NULL; 294 dev->port->port_dev = NULL;
@@ -298,6 +301,14 @@ static void sas_unregister_common_dev(struct asd_sas_port *port, struct domain_d
298 sas_ata_end_eh(dev->sata_dev.ap); 301 sas_ata_end_eh(dev->sata_dev.ap);
299 spin_unlock_irq(&port->dev_list_lock); 302 spin_unlock_irq(&port->dev_list_lock);
300 303
304 spin_lock_irq(&ha->lock);
305 if (dev->dev_type == SAS_END_DEV &&
306 !list_empty(&dev->ssp_dev.eh_list_node)) {
307 list_del_init(&dev->ssp_dev.eh_list_node);
308 ha->eh_active--;
309 }
310 spin_unlock_irq(&ha->lock);
311
301 sas_put_device(dev); 312 sas_put_device(dev);
302} 313}
303 314
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c
index 6909fefa32c5..1bbab3d94a20 100644
--- a/drivers/scsi/libsas/sas_init.c
+++ b/drivers/scsi/libsas/sas_init.c
@@ -116,7 +116,9 @@ int sas_register_ha(struct sas_ha_struct *sas_ha)
116 set_bit(SAS_HA_REGISTERED, &sas_ha->state); 116 set_bit(SAS_HA_REGISTERED, &sas_ha->state);
117 spin_lock_init(&sas_ha->lock); 117 spin_lock_init(&sas_ha->lock);
118 mutex_init(&sas_ha->drain_mutex); 118 mutex_init(&sas_ha->drain_mutex);
119 init_waitqueue_head(&sas_ha->eh_wait_q);
119 INIT_LIST_HEAD(&sas_ha->defer_q); 120 INIT_LIST_HEAD(&sas_ha->defer_q);
121 INIT_LIST_HEAD(&sas_ha->eh_dev_q);
120 122
121 error = sas_register_phys(sas_ha); 123 error = sas_register_phys(sas_ha);
122 if (error) { 124 if (error) {
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index 52d5b0133db0..2e0e779fb3b2 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -460,14 +460,88 @@ struct sas_phy *sas_get_local_phy(struct domain_device *dev)
460} 460}
461EXPORT_SYMBOL_GPL(sas_get_local_phy); 461EXPORT_SYMBOL_GPL(sas_get_local_phy);
462 462
463static void sas_wait_eh(struct domain_device *dev)
464{
465 struct sas_ha_struct *ha = dev->port->ha;
466 DEFINE_WAIT(wait);
467
468 if (dev_is_sata(dev)) {
469 ata_port_wait_eh(dev->sata_dev.ap);
470 return;
471 }
472 retry:
473 spin_lock_irq(&ha->lock);
474
475 while (test_bit(SAS_DEV_EH_PENDING, &dev->state)) {
476 prepare_to_wait(&ha->eh_wait_q, &wait, TASK_UNINTERRUPTIBLE);
477 spin_unlock_irq(&ha->lock);
478 schedule();
479 spin_lock_irq(&ha->lock);
480 }
481 finish_wait(&ha->eh_wait_q, &wait);
482
483 spin_unlock_irq(&ha->lock);
484
485 /* make sure SCSI EH is complete */
486 if (scsi_host_in_recovery(ha->core.shost)) {
487 msleep(10);
488 goto retry;
489 }
490}
491EXPORT_SYMBOL(sas_wait_eh);
492
493static int sas_queue_reset(struct domain_device *dev, int reset_type, int lun, int wait)
494{
495 struct sas_ha_struct *ha = dev->port->ha;
496 int scheduled = 0, tries = 100;
497
498 /* ata: promote lun reset to bus reset */
499 if (dev_is_sata(dev)) {
500 sas_ata_schedule_reset(dev);
501 if (wait)
502 sas_ata_wait_eh(dev);
503 return SUCCESS;
504 }
505
506 while (!scheduled && tries--) {
507 spin_lock_irq(&ha->lock);
508 if (!test_bit(SAS_DEV_EH_PENDING, &dev->state) &&
509 !test_bit(reset_type, &dev->state)) {
510 scheduled = 1;
511 ha->eh_active++;
512 list_add_tail(&dev->ssp_dev.eh_list_node, &ha->eh_dev_q);
513 set_bit(SAS_DEV_EH_PENDING, &dev->state);
514 set_bit(reset_type, &dev->state);
515 int_to_scsilun(lun, &dev->ssp_dev.reset_lun);
516 scsi_schedule_eh(ha->core.shost);
517 }
518 spin_unlock_irq(&ha->lock);
519
520 if (wait)
521 sas_wait_eh(dev);
522
523 if (scheduled)
524 return SUCCESS;
525 }
526
527 SAS_DPRINTK("%s reset of %s failed\n",
528 reset_type == SAS_DEV_LU_RESET ? "LUN" : "Bus",
529 dev_name(&dev->rphy->dev));
530
531 return FAILED;
532}
533
463/* Attempt to send a LUN reset message to a device */ 534/* Attempt to send a LUN reset message to a device */
464int sas_eh_device_reset_handler(struct scsi_cmnd *cmd) 535int sas_eh_device_reset_handler(struct scsi_cmnd *cmd)
465{ 536{
466 struct domain_device *dev = cmd_to_domain_dev(cmd);
467 struct sas_internal *i =
468 to_sas_internal(dev->port->ha->core.shost->transportt);
469 struct scsi_lun lun;
470 int res; 537 int res;
538 struct scsi_lun lun;
539 struct Scsi_Host *host = cmd->device->host;
540 struct domain_device *dev = cmd_to_domain_dev(cmd);
541 struct sas_internal *i = to_sas_internal(host->transportt);
542
543 if (current != host->ehandler)
544 return sas_queue_reset(dev, SAS_DEV_LU_RESET, cmd->device->lun, 0);
471 545
472 int_to_scsilun(cmd->device->lun, &lun); 546 int_to_scsilun(cmd->device->lun, &lun);
473 547
@@ -486,8 +560,12 @@ int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd)
486{ 560{
487 struct domain_device *dev = cmd_to_domain_dev(cmd); 561 struct domain_device *dev = cmd_to_domain_dev(cmd);
488 struct sas_phy *phy = sas_get_local_phy(dev); 562 struct sas_phy *phy = sas_get_local_phy(dev);
563 struct Scsi_Host *host = cmd->device->host;
489 int res; 564 int res;
490 565
566 if (current != host->ehandler)
567 return sas_queue_reset(dev, SAS_DEV_RESET, 0, 0);
568
491 res = sas_phy_reset(phy, 1); 569 res = sas_phy_reset(phy, 1);
492 if (res) 570 if (res)
493 SAS_DPRINTK("Bus reset of %s failed 0x%x\n", 571 SAS_DPRINTK("Bus reset of %s failed 0x%x\n",
@@ -667,6 +745,39 @@ static void sas_eh_handle_sas_errors(struct Scsi_Host *shost, struct list_head *
667 goto out; 745 goto out;
668} 746}
669 747
748static void sas_eh_handle_resets(struct Scsi_Host *shost)
749{
750 struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost);
751 struct sas_internal *i = to_sas_internal(shost->transportt);
752
753 /* handle directed resets to sas devices */
754 spin_lock_irq(&ha->lock);
755 while (!list_empty(&ha->eh_dev_q)) {
756 struct domain_device *dev;
757 struct ssp_device *ssp;
758
759 ssp = list_entry(ha->eh_dev_q.next, typeof(*ssp), eh_list_node);
760 list_del_init(&ssp->eh_list_node);
761 dev = container_of(ssp, typeof(*dev), ssp_dev);
762 kref_get(&dev->kref);
763 WARN_ONCE(dev_is_sata(dev), "ssp reset to ata device?\n");
764
765 spin_unlock_irq(&ha->lock);
766
767 if (test_and_clear_bit(SAS_DEV_LU_RESET, &dev->state))
768 i->dft->lldd_lu_reset(dev, ssp->reset_lun.scsi_lun);
769
770 if (test_and_clear_bit(SAS_DEV_RESET, &dev->state))
771 i->dft->lldd_I_T_nexus_reset(dev);
772
773 sas_put_device(dev);
774 spin_lock_irq(&ha->lock);
775 clear_bit(SAS_DEV_EH_PENDING, &dev->state);
776 ha->eh_active--;
777 }
778 spin_unlock_irq(&ha->lock);
779}
780
670 781
671void sas_scsi_recover_host(struct Scsi_Host *shost) 782void sas_scsi_recover_host(struct Scsi_Host *shost)
672{ 783{
@@ -709,6 +820,8 @@ out:
709 if (ha->lldd_max_execute_num > 1) 820 if (ha->lldd_max_execute_num > 1)
710 wake_up_process(ha->core.queue_thread); 821 wake_up_process(ha->core.queue_thread);
711 822
823 sas_eh_handle_resets(shost);
824
712 /* now link into libata eh --- if we have any ata devices */ 825 /* now link into libata eh --- if we have any ata devices */
713 sas_ata_strategy_handler(shost); 826 sas_ata_strategy_handler(shost);
714 827
diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
index 814d8cb592ad..df9cefdf2a8e 100644
--- a/include/scsi/libsas.h
+++ b/include/scsi/libsas.h
@@ -176,10 +176,17 @@ struct sata_device {
176 u8 fis[ATA_RESP_FIS_SIZE]; 176 u8 fis[ATA_RESP_FIS_SIZE];
177}; 177};
178 178
179struct ssp_device {
180 struct list_head eh_list_node; /* pending a user requested eh action */
181 struct scsi_lun reset_lun;
182};
183
179enum { 184enum {
180 SAS_DEV_GONE, 185 SAS_DEV_GONE,
181 SAS_DEV_DESTROY, 186 SAS_DEV_DESTROY,
182 SAS_DEV_EH_PENDING, 187 SAS_DEV_EH_PENDING,
188 SAS_DEV_LU_RESET,
189 SAS_DEV_RESET,
183}; 190};
184 191
185struct domain_device { 192struct domain_device {
@@ -213,6 +220,7 @@ struct domain_device {
213 union { 220 union {
214 struct expander_device ex_dev; 221 struct expander_device ex_dev;
215 struct sata_device sata_dev; /* STP & directly attached */ 222 struct sata_device sata_dev; /* STP & directly attached */
223 struct ssp_device ssp_dev;
216 }; 224 };
217 225
218 void *lldd_dev; 226 void *lldd_dev;
@@ -389,6 +397,8 @@ struct sas_ha_struct {
389 unsigned long state; 397 unsigned long state;
390 spinlock_t lock; 398 spinlock_t lock;
391 int eh_active; 399 int eh_active;
400 wait_queue_head_t eh_wait_q;
401 struct list_head eh_dev_q;
392 402
393 struct mutex disco_mutex; 403 struct mutex disco_mutex;
394 404