aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/isci/request.c
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2011-06-13 20:39:44 -0400
committerDan Williams <dan.j.williams@intel.com>2011-07-03 07:04:51 -0400
commit209fae14fabfd48525e5630bebbbd4ca15090c60 (patch)
treeb251b9b394b3493cc15242ea31002abcb4e9bb59 /drivers/scsi/isci/request.c
parent360b03ed178a4fe3971b0a098d8feeb53333481b (diff)
isci: atomic device lookup and reference counting
We have unsafe references to remote devices that are notified to disappear at lldd_dev_gone. In order to clean this up we need a single canonical source for device lookups and stable references once a lookup succeeds. Towards that end guarantee that domain_device.lldd_dev is NULL as soon as we start the process of stopping a device. Any code path that wants to safely lookup a remote device must do so through task->dev->lldd_dev (isci_lookup_device()). For in-flight references outside of scic_lock we need reference counting to ensure that the device is not recycled before we are done with it. Simplify device back references to just scic_sds_request.target_device which is now the only permissible internal reference that is maintained relative to the reference count. There were two occasions where we wanted new i/o's to be treated as SAS_TASK_UNDELIVERED but where the domain_dev->lldd_dev link is still intact. Introduce a 'gone' flag to prevent i/o while waiting for libsas to take action on the port down event. One 'core' leftover is that we currently call scic_remote_device_destruct() from isci_remote_device_deconstruct() which is called when the 'core' says the device is stopped. It would be more natural for the final put to trigger isci_remote_device_deconstruct() but this implementation is deferred as it requires other changes. Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/scsi/isci/request.c')
-rw-r--r--drivers/scsi/isci/request.c60
1 files changed, 21 insertions, 39 deletions
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
index f0813d076c50..fd6314abeb0b 100644
--- a/drivers/scsi/isci/request.c
+++ b/drivers/scsi/isci/request.c
@@ -2313,7 +2313,7 @@ static void isci_request_set_open_reject_status(
2313 * none. 2313 * none.
2314 */ 2314 */
2315static void isci_request_handle_controller_specific_errors( 2315static void isci_request_handle_controller_specific_errors(
2316 struct isci_remote_device *isci_device, 2316 struct isci_remote_device *idev,
2317 struct isci_request *request, 2317 struct isci_request *request,
2318 struct sas_task *task, 2318 struct sas_task *task,
2319 enum service_response *response_ptr, 2319 enum service_response *response_ptr,
@@ -2353,8 +2353,7 @@ static void isci_request_handle_controller_specific_errors(
2353 * that we ignore the quiesce state, since we are 2353 * that we ignore the quiesce state, since we are
2354 * concerned about the actual device state. 2354 * concerned about the actual device state.
2355 */ 2355 */
2356 if ((isci_device->status == isci_stopping) || 2356 if (!idev)
2357 (isci_device->status == isci_stopped))
2358 *status_ptr = SAS_DEVICE_UNKNOWN; 2357 *status_ptr = SAS_DEVICE_UNKNOWN;
2359 else 2358 else
2360 *status_ptr = SAS_ABORTED_TASK; 2359 *status_ptr = SAS_ABORTED_TASK;
@@ -2367,8 +2366,7 @@ static void isci_request_handle_controller_specific_errors(
2367 /* Task in the target is not done. */ 2366 /* Task in the target is not done. */
2368 *response_ptr = SAS_TASK_UNDELIVERED; 2367 *response_ptr = SAS_TASK_UNDELIVERED;
2369 2368
2370 if ((isci_device->status == isci_stopping) || 2369 if (!idev)
2371 (isci_device->status == isci_stopped))
2372 *status_ptr = SAS_DEVICE_UNKNOWN; 2370 *status_ptr = SAS_DEVICE_UNKNOWN;
2373 else 2371 else
2374 *status_ptr = SAM_STAT_TASK_ABORTED; 2372 *status_ptr = SAM_STAT_TASK_ABORTED;
@@ -2399,8 +2397,7 @@ static void isci_request_handle_controller_specific_errors(
2399 * that we ignore the quiesce state, since we are 2397 * that we ignore the quiesce state, since we are
2400 * concerned about the actual device state. 2398 * concerned about the actual device state.
2401 */ 2399 */
2402 if ((isci_device->status == isci_stopping) || 2400 if (!idev)
2403 (isci_device->status == isci_stopped))
2404 *status_ptr = SAS_DEVICE_UNKNOWN; 2401 *status_ptr = SAS_DEVICE_UNKNOWN;
2405 else 2402 else
2406 *status_ptr = SAS_ABORTED_TASK; 2403 *status_ptr = SAS_ABORTED_TASK;
@@ -2629,7 +2626,7 @@ static void isci_request_io_request_complete(struct isci_host *isci_host,
2629 struct ssp_response_iu *resp_iu; 2626 struct ssp_response_iu *resp_iu;
2630 void *resp_buf; 2627 void *resp_buf;
2631 unsigned long task_flags; 2628 unsigned long task_flags;
2632 struct isci_remote_device *isci_device = request->isci_device; 2629 struct isci_remote_device *idev = isci_lookup_device(task->dev);
2633 enum service_response response = SAS_TASK_UNDELIVERED; 2630 enum service_response response = SAS_TASK_UNDELIVERED;
2634 enum exec_status status = SAS_ABORTED_TASK; 2631 enum exec_status status = SAS_ABORTED_TASK;
2635 enum isci_request_status request_status; 2632 enum isci_request_status request_status;
@@ -2672,9 +2669,7 @@ static void isci_request_io_request_complete(struct isci_host *isci_host,
2672 * that we ignore the quiesce state, since we are 2669 * that we ignore the quiesce state, since we are
2673 * concerned about the actual device state. 2670 * concerned about the actual device state.
2674 */ 2671 */
2675 if ((isci_device->status == isci_stopping) 2672 if (!idev)
2676 || (isci_device->status == isci_stopped)
2677 )
2678 status = SAS_DEVICE_UNKNOWN; 2673 status = SAS_DEVICE_UNKNOWN;
2679 else 2674 else
2680 status = SAS_ABORTED_TASK; 2675 status = SAS_ABORTED_TASK;
@@ -2697,8 +2692,7 @@ static void isci_request_io_request_complete(struct isci_host *isci_host,
2697 request->complete_in_target = true; 2692 request->complete_in_target = true;
2698 response = SAS_TASK_UNDELIVERED; 2693 response = SAS_TASK_UNDELIVERED;
2699 2694
2700 if ((isci_device->status == isci_stopping) || 2695 if (!idev)
2701 (isci_device->status == isci_stopped))
2702 /* The device has been /is being stopped. Note that 2696 /* The device has been /is being stopped. Note that
2703 * we ignore the quiesce state, since we are 2697 * we ignore the quiesce state, since we are
2704 * concerned about the actual device state. 2698 * concerned about the actual device state.
@@ -2728,8 +2722,7 @@ static void isci_request_io_request_complete(struct isci_host *isci_host,
2728 * that we ignore the quiesce state, since we are 2722 * that we ignore the quiesce state, since we are
2729 * concerned about the actual device state. 2723 * concerned about the actual device state.
2730 */ 2724 */
2731 if ((isci_device->status == isci_stopping) || 2725 if (!idev)
2732 (isci_device->status == isci_stopped))
2733 status = SAS_DEVICE_UNKNOWN; 2726 status = SAS_DEVICE_UNKNOWN;
2734 else 2727 else
2735 status = SAS_ABORTED_TASK; 2728 status = SAS_ABORTED_TASK;
@@ -2861,8 +2854,7 @@ static void isci_request_io_request_complete(struct isci_host *isci_host,
2861 * that we ignore the quiesce state, since we are 2854 * that we ignore the quiesce state, since we are
2862 * concerned about the actual device state. 2855 * concerned about the actual device state.
2863 */ 2856 */
2864 if ((isci_device->status == isci_stopping) || 2857 if (!idev)
2865 (isci_device->status == isci_stopped))
2866 status = SAS_DEVICE_UNKNOWN; 2858 status = SAS_DEVICE_UNKNOWN;
2867 else 2859 else
2868 status = SAS_ABORTED_TASK; 2860 status = SAS_ABORTED_TASK;
@@ -2873,7 +2865,7 @@ static void isci_request_io_request_complete(struct isci_host *isci_host,
2873 case SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR: 2865 case SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR:
2874 2866
2875 isci_request_handle_controller_specific_errors( 2867 isci_request_handle_controller_specific_errors(
2876 isci_device, request, task, &response, &status, 2868 idev, request, task, &response, &status,
2877 &complete_to_host); 2869 &complete_to_host);
2878 2870
2879 break; 2871 break;
@@ -2902,8 +2894,7 @@ static void isci_request_io_request_complete(struct isci_host *isci_host,
2902 2894
2903 /* Fail the I/O so it can be retried. */ 2895 /* Fail the I/O so it can be retried. */
2904 response = SAS_TASK_UNDELIVERED; 2896 response = SAS_TASK_UNDELIVERED;
2905 if ((isci_device->status == isci_stopping) || 2897 if (!idev)
2906 (isci_device->status == isci_stopped))
2907 status = SAS_DEVICE_UNKNOWN; 2898 status = SAS_DEVICE_UNKNOWN;
2908 else 2899 else
2909 status = SAS_ABORTED_TASK; 2900 status = SAS_ABORTED_TASK;
@@ -2926,8 +2917,7 @@ static void isci_request_io_request_complete(struct isci_host *isci_host,
2926 * that we ignore the quiesce state, since we are 2917 * that we ignore the quiesce state, since we are
2927 * concerned about the actual device state. 2918 * concerned about the actual device state.
2928 */ 2919 */
2929 if ((isci_device->status == isci_stopping) || 2920 if (!idev)
2930 (isci_device->status == isci_stopped))
2931 status = SAS_DEVICE_UNKNOWN; 2921 status = SAS_DEVICE_UNKNOWN;
2932 else 2922 else
2933 status = SAS_ABORTED_TASK; 2923 status = SAS_ABORTED_TASK;
@@ -2953,8 +2943,10 @@ static void isci_request_io_request_complete(struct isci_host *isci_host,
2953 2943
2954 /* complete the io request to the core. */ 2944 /* complete the io request to the core. */
2955 scic_controller_complete_io(&isci_host->sci, 2945 scic_controller_complete_io(&isci_host->sci,
2956 &isci_device->sci, 2946 request->sci.target_device,
2957 &request->sci); 2947 &request->sci);
2948 isci_put_device(idev);
2949
2958 /* set terminated handle so it cannot be completed or 2950 /* set terminated handle so it cannot be completed or
2959 * terminated again, and to cause any calls into abort 2951 * terminated again, and to cause any calls into abort
2960 * task to recognize the already completed case. 2952 * task to recognize the already completed case.
@@ -3511,7 +3503,6 @@ static enum sci_status isci_io_request_build(
3511} 3503}
3512 3504
3513static struct isci_request *isci_request_alloc_core(struct isci_host *ihost, 3505static struct isci_request *isci_request_alloc_core(struct isci_host *ihost,
3514 struct isci_remote_device *idev,
3515 gfp_t gfp_flags) 3506 gfp_t gfp_flags)
3516{ 3507{
3517 dma_addr_t handle; 3508 dma_addr_t handle;
@@ -3528,7 +3519,6 @@ static struct isci_request *isci_request_alloc_core(struct isci_host *ihost,
3528 spin_lock_init(&ireq->state_lock); 3519 spin_lock_init(&ireq->state_lock);
3529 ireq->request_daddr = handle; 3520 ireq->request_daddr = handle;
3530 ireq->isci_host = ihost; 3521 ireq->isci_host = ihost;
3531 ireq->isci_device = idev;
3532 ireq->io_request_completion = NULL; 3522 ireq->io_request_completion = NULL;
3533 ireq->terminated = false; 3523 ireq->terminated = false;
3534 3524
@@ -3546,12 +3536,11 @@ static struct isci_request *isci_request_alloc_core(struct isci_host *ihost,
3546 3536
3547static struct isci_request *isci_request_alloc_io(struct isci_host *ihost, 3537static struct isci_request *isci_request_alloc_io(struct isci_host *ihost,
3548 struct sas_task *task, 3538 struct sas_task *task,
3549 struct isci_remote_device *idev,
3550 gfp_t gfp_flags) 3539 gfp_t gfp_flags)
3551{ 3540{
3552 struct isci_request *ireq; 3541 struct isci_request *ireq;
3553 3542
3554 ireq = isci_request_alloc_core(ihost, idev, gfp_flags); 3543 ireq = isci_request_alloc_core(ihost, gfp_flags);
3555 if (ireq) { 3544 if (ireq) {
3556 ireq->ttype_ptr.io_task_ptr = task; 3545 ireq->ttype_ptr.io_task_ptr = task;
3557 ireq->ttype = io_task; 3546 ireq->ttype = io_task;
@@ -3562,12 +3551,11 @@ static struct isci_request *isci_request_alloc_io(struct isci_host *ihost,
3562 3551
3563struct isci_request *isci_request_alloc_tmf(struct isci_host *ihost, 3552struct isci_request *isci_request_alloc_tmf(struct isci_host *ihost,
3564 struct isci_tmf *isci_tmf, 3553 struct isci_tmf *isci_tmf,
3565 struct isci_remote_device *idev,
3566 gfp_t gfp_flags) 3554 gfp_t gfp_flags)
3567{ 3555{
3568 struct isci_request *ireq; 3556 struct isci_request *ireq;
3569 3557
3570 ireq = isci_request_alloc_core(ihost, idev, gfp_flags); 3558 ireq = isci_request_alloc_core(ihost, gfp_flags);
3571 if (ireq) { 3559 if (ireq) {
3572 ireq->ttype_ptr.tmf_task_ptr = isci_tmf; 3560 ireq->ttype_ptr.tmf_task_ptr = isci_tmf;
3573 ireq->ttype = tmf_task; 3561 ireq->ttype = tmf_task;
@@ -3575,21 +3563,16 @@ struct isci_request *isci_request_alloc_tmf(struct isci_host *ihost,
3575 return ireq; 3563 return ireq;
3576} 3564}
3577 3565
3578int isci_request_execute(struct isci_host *ihost, struct sas_task *task, 3566int isci_request_execute(struct isci_host *ihost, struct isci_remote_device *idev,
3579 gfp_t gfp_flags) 3567 struct sas_task *task, gfp_t gfp_flags)
3580{ 3568{
3581 enum sci_status status = SCI_FAILURE_UNSUPPORTED_PROTOCOL; 3569 enum sci_status status = SCI_FAILURE_UNSUPPORTED_PROTOCOL;
3582 struct scic_sds_remote_device *sci_dev;
3583 struct isci_remote_device *idev;
3584 struct isci_request *ireq; 3570 struct isci_request *ireq;
3585 unsigned long flags; 3571 unsigned long flags;
3586 int ret = 0; 3572 int ret = 0;
3587 3573
3588 idev = task->dev->lldd_dev;
3589 sci_dev = &idev->sci;
3590
3591 /* do common allocation and init of request object. */ 3574 /* do common allocation and init of request object. */
3592 ireq = isci_request_alloc_io(ihost, task, idev, gfp_flags); 3575 ireq = isci_request_alloc_io(ihost, task, gfp_flags);
3593 if (!ireq) 3576 if (!ireq)
3594 goto out; 3577 goto out;
3595 3578
@@ -3605,8 +3588,7 @@ int isci_request_execute(struct isci_host *ihost, struct sas_task *task,
3605 spin_lock_irqsave(&ihost->scic_lock, flags); 3588 spin_lock_irqsave(&ihost->scic_lock, flags);
3606 3589
3607 /* send the request, let the core assign the IO TAG. */ 3590 /* send the request, let the core assign the IO TAG. */
3608 status = scic_controller_start_io(&ihost->sci, sci_dev, 3591 status = scic_controller_start_io(&ihost->sci, &idev->sci, &ireq->sci,
3609 &ireq->sci,
3610 SCI_CONTROLLER_INVALID_IO_TAG); 3592 SCI_CONTROLLER_INVALID_IO_TAG);
3611 if (status != SCI_SUCCESS && 3593 if (status != SCI_SUCCESS &&
3612 status != SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED) { 3594 status != SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED) {