aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/isci
diff options
context:
space:
mode:
authorJeff Skirvin <jeffrey.d.skirvin@intel.com>2012-03-10 00:46:46 -0500
committerDan Williams <dan.j.williams@intel.com>2012-05-17 17:33:43 -0400
commit397497dd61948b0d59d1d21812b93c97b0eeb2dd (patch)
treef156de22337932cba5d5a4dedbb80bfa0054dd4c /drivers/scsi/isci
parent87805162b6af20d2ad386a49aec13b753cca523a (diff)
isci: Check IDEV_GONE before performing abort path operations.
In the link fail path, set IDEV_GONE for every device on the domain when the last link in the port fails. In the abort path functions like isci_reset_device, make sure that there has not already been a detected domain failure with the device by checking IDEV_GONE, before performing any kind of hard reset, SMP phy control, or TMF operation. The check for IDEV_GONE makes sure that the device in the abort path really has control of the port with which it is associated. This prevents starting hard resets at incorrect times and scheduling unnecessary LUN resets for SATA devices. Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/scsi/isci')
-rw-r--r--drivers/scsi/isci/port.c23
-rw-r--r--drivers/scsi/isci/task.c55
2 files changed, 57 insertions, 21 deletions
diff --git a/drivers/scsi/isci/port.c b/drivers/scsi/isci/port.c
index da0c4e1b9b30..2fb85bf75449 100644
--- a/drivers/scsi/isci/port.c
+++ b/drivers/scsi/isci/port.c
@@ -240,9 +240,32 @@ static void isci_port_link_down(struct isci_host *isci_host,
240 struct isci_phy *isci_phy, 240 struct isci_phy *isci_phy,
241 struct isci_port *isci_port) 241 struct isci_port *isci_port)
242{ 242{
243 struct isci_remote_device *isci_device;
244
243 dev_dbg(&isci_host->pdev->dev, 245 dev_dbg(&isci_host->pdev->dev,
244 "%s: isci_port = %p\n", __func__, isci_port); 246 "%s: isci_port = %p\n", __func__, isci_port);
245 247
248 if (isci_port) {
249
250 /* check to see if this is the last phy on this port. */
251 if (isci_phy->sas_phy.port &&
252 isci_phy->sas_phy.port->num_phys == 1) {
253 /* change the state for all devices on this port. The
254 * next task sent to this device will be returned as
255 * SAS_TASK_UNDELIVERED, and the scsi mid layer will
256 * remove the target
257 */
258 list_for_each_entry(isci_device,
259 &isci_port->remote_dev_list,
260 node) {
261 dev_dbg(&isci_host->pdev->dev,
262 "%s: isci_device = %p\n",
263 __func__, isci_device);
264 set_bit(IDEV_GONE, &isci_device->flags);
265 }
266 }
267 }
268
246 /* Notify libsas of the borken link, this will trigger calls to our 269 /* Notify libsas of the borken link, this will trigger calls to our
247 * isci_port_deformed and isci_dev_gone functions. 270 * isci_port_deformed and isci_dev_gone functions.
248 */ 271 */
diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c
index 084f8f73fade..6bc74eb012c9 100644
--- a/drivers/scsi/isci/task.c
+++ b/drivers/scsi/isci/task.c
@@ -421,7 +421,7 @@ int isci_task_lu_reset(struct domain_device *dev, u8 *lun)
421 struct isci_host *ihost = dev_to_ihost(dev); 421 struct isci_host *ihost = dev_to_ihost(dev);
422 struct isci_remote_device *idev; 422 struct isci_remote_device *idev;
423 unsigned long flags; 423 unsigned long flags;
424 int ret; 424 int ret = TMF_RESP_FUNC_COMPLETE;
425 425
426 spin_lock_irqsave(&ihost->scic_lock, flags); 426 spin_lock_irqsave(&ihost->scic_lock, flags);
427 idev = isci_get_device(dev->lldd_dev); 427 idev = isci_get_device(dev->lldd_dev);
@@ -447,12 +447,12 @@ int isci_task_lu_reset(struct domain_device *dev, u8 *lun)
447 goto out; 447 goto out;
448 } 448 }
449 /* All pending I/Os have been terminated and cleaned up. */ 449 /* All pending I/Os have been terminated and cleaned up. */
450 if (dev_is_sata(dev)) { 450 if (!test_bit(IDEV_GONE, &idev->flags)) {
451 sas_ata_schedule_reset(dev); 451 if (dev_is_sata(dev))
452 ret = TMF_RESP_FUNC_COMPLETE; 452 sas_ata_schedule_reset(dev);
453 } else { 453 else
454 /* Send the task management part of the reset. */ 454 /* Send the task management part of the reset. */
455 ret = isci_task_send_lu_reset_sas(ihost, idev, lun); 455 ret = isci_task_send_lu_reset_sas(ihost, idev, lun);
456 } 456 }
457 out: 457 out:
458 isci_put_device(idev); 458 isci_put_device(idev);
@@ -512,8 +512,17 @@ int isci_task_abort_task(struct sas_task *task)
512 spin_unlock_irqrestore(&ihost->scic_lock, flags); 512 spin_unlock_irqrestore(&ihost->scic_lock, flags);
513 513
514 dev_warn(&ihost->pdev->dev, 514 dev_warn(&ihost->pdev->dev,
515 "%s: dev = %p, task = %p, old_request == %p\n", 515 "%s: dev = %p (%s%s), task = %p, old_request == %p\n",
516 __func__, idev, task, old_request); 516 __func__, idev,
517 (dev_is_sata(task->dev) ? "STP/SATA"
518 : ((dev_is_expander(task->dev))
519 ? "SMP"
520 : "SSP")),
521 ((idev) ? ((test_bit(IDEV_GONE, &idev->flags))
522 ? " IDEV_GONE"
523 : "")
524 : " <NULL>"),
525 task, old_request);
517 526
518 /* Device reset conditions signalled in task_state_flags are the 527 /* Device reset conditions signalled in task_state_flags are the
519 * responsbility of libsas to observe at the start of the error 528 * responsbility of libsas to observe at the start of the error
@@ -552,7 +561,8 @@ int isci_task_abort_task(struct sas_task *task)
552 561
553 if (task->task_proto == SAS_PROTOCOL_SMP || 562 if (task->task_proto == SAS_PROTOCOL_SMP ||
554 sas_protocol_ata(task->task_proto) || 563 sas_protocol_ata(task->task_proto) ||
555 test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags)) { 564 test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags) ||
565 test_bit(IDEV_GONE, &idev->flags)) {
556 566
557 spin_unlock_irqrestore(&ihost->scic_lock, flags); 567 spin_unlock_irqrestore(&ihost->scic_lock, flags);
558 568
@@ -561,7 +571,8 @@ int isci_task_abort_task(struct sas_task *task)
561 571
562 dev_warn(&ihost->pdev->dev, 572 dev_warn(&ihost->pdev->dev,
563 "%s: %s request" 573 "%s: %s request"
564 " or complete_in_target (%d), thus no TMF\n", 574 " or complete_in_target (%d), "
575 "or IDEV_GONE (%d), thus no TMF\n",
565 __func__, 576 __func__,
566 ((task->task_proto == SAS_PROTOCOL_SMP) 577 ((task->task_proto == SAS_PROTOCOL_SMP)
567 ? "SMP" 578 ? "SMP"
@@ -570,7 +581,8 @@ int isci_task_abort_task(struct sas_task *task)
570 : "<other>") 581 : "<other>")
571 ), 582 ),
572 test_bit(IREQ_COMPLETE_IN_TARGET, 583 test_bit(IREQ_COMPLETE_IN_TARGET,
573 &old_request->flags)); 584 &old_request->flags),
585 test_bit(IDEV_GONE, &idev->flags));
574 586
575 spin_lock_irqsave(&task->task_state_lock, flags); 587 spin_lock_irqsave(&task->task_state_lock, flags);
576 task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR | 588 task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR |
@@ -734,7 +746,7 @@ static int isci_reset_device(struct isci_host *ihost,
734 struct domain_device *dev, 746 struct domain_device *dev,
735 struct isci_remote_device *idev) 747 struct isci_remote_device *idev)
736{ 748{
737 int rc = TMF_RESP_FUNC_COMPLETE, reset_stat; 749 int rc = TMF_RESP_FUNC_COMPLETE, reset_stat = -1;
738 struct sas_phy *phy = sas_get_local_phy(dev); 750 struct sas_phy *phy = sas_get_local_phy(dev);
739 struct isci_port *iport = dev->port->lldd_port; 751 struct isci_port *iport = dev->port->lldd_port;
740 752
@@ -752,14 +764,15 @@ static int isci_reset_device(struct isci_host *ihost,
752 * primary duty of this function is to cleanup tasks, so that is the 764 * primary duty of this function is to cleanup tasks, so that is the
753 * relevant status. 765 * relevant status.
754 */ 766 */
755 767 if (!test_bit(IDEV_GONE, &idev->flags)) {
756 if (scsi_is_sas_phy_local(phy)) { 768 if (scsi_is_sas_phy_local(phy)) {
757 struct isci_phy *iphy = &ihost->phys[phy->number]; 769 struct isci_phy *iphy = &ihost->phys[phy->number];
758 770
759 reset_stat = isci_port_perform_hard_reset(ihost, iport, iphy); 771 reset_stat = isci_port_perform_hard_reset(ihost, iport,
760 } else 772 iphy);
761 reset_stat = sas_phy_reset(phy, !dev_is_sata(dev)); 773 } else
762 774 reset_stat = sas_phy_reset(phy, !dev_is_sata(dev));
775 }
763 /* Explicitly resume the RNC here, since there was no task sent. */ 776 /* Explicitly resume the RNC here, since there was no task sent. */
764 isci_remote_device_resume_from_abort(ihost, idev); 777 isci_remote_device_resume_from_abort(ihost, idev);
765 778