diff options
author | Dan Williams <dan.j.williams@intel.com> | 2011-06-13 20:39:44 -0400 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2011-07-03 07:04:51 -0400 |
commit | 209fae14fabfd48525e5630bebbbd4ca15090c60 (patch) | |
tree | b251b9b394b3493cc15242ea31002abcb4e9bb59 /drivers/scsi/isci/request.c | |
parent | 360b03ed178a4fe3971b0a098d8feeb53333481b (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.c | 60 |
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 | */ |
2315 | static void isci_request_handle_controller_specific_errors( | 2315 | static 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 | ||
3513 | static struct isci_request *isci_request_alloc_core(struct isci_host *ihost, | 3505 | static 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 | ||
3547 | static struct isci_request *isci_request_alloc_io(struct isci_host *ihost, | 3537 | static 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 | ||
3563 | struct isci_request *isci_request_alloc_tmf(struct isci_host *ihost, | 3552 | struct 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 | ||
3578 | int isci_request_execute(struct isci_host *ihost, struct sas_task *task, | 3566 | int 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) { |