diff options
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/isci/port.c | 23 | ||||
-rw-r--r-- | drivers/scsi/isci/task.c | 55 |
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 | ||