diff options
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/isci/remote_device.c | 27 | ||||
-rw-r--r-- | drivers/scsi/isci/remote_device.h | 1 | ||||
-rw-r--r-- | drivers/scsi/isci/request.c | 27 | ||||
-rw-r--r-- | drivers/scsi/isci/request.h | 9 | ||||
-rw-r--r-- | drivers/scsi/isci/task.c | 16 |
5 files changed, 73 insertions, 7 deletions
diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c index 9f45c2ba7307..c5ce0f0f3645 100644 --- a/drivers/scsi/isci/remote_device.c +++ b/drivers/scsi/isci/remote_device.c | |||
@@ -68,17 +68,39 @@ | |||
68 | * @isci_host: This parameter specifies the isci host object. | 68 | * @isci_host: This parameter specifies the isci host object. |
69 | * @isci_device: This parameter specifies the remote device | 69 | * @isci_device: This parameter specifies the remote device |
70 | * | 70 | * |
71 | * scic_lock is held on entrance to this function. | ||
71 | */ | 72 | */ |
72 | static void isci_remote_device_not_ready(struct isci_host *ihost, | 73 | static void isci_remote_device_not_ready(struct isci_host *ihost, |
73 | struct isci_remote_device *idev, u32 reason) | 74 | struct isci_remote_device *idev, u32 reason) |
74 | { | 75 | { |
76 | struct isci_request * ireq; | ||
77 | |||
75 | dev_dbg(&ihost->pdev->dev, | 78 | dev_dbg(&ihost->pdev->dev, |
76 | "%s: isci_device = %p\n", __func__, idev); | 79 | "%s: isci_device = %p\n", __func__, idev); |
77 | 80 | ||
78 | if (reason == SCIC_REMOTE_DEVICE_NOT_READY_STOP_REQUESTED) | 81 | switch (reason) { |
82 | case SCIC_REMOTE_DEVICE_NOT_READY_STOP_REQUESTED: | ||
79 | set_bit(IDEV_GONE, &idev->flags); | 83 | set_bit(IDEV_GONE, &idev->flags); |
80 | else | 84 | break; |
85 | case SCIC_REMOTE_DEVICE_NOT_READY_SATA_SDB_ERROR_FIS_RECEIVED: | ||
86 | set_bit(IDEV_IO_NCQERROR, &idev->flags); | ||
87 | |||
88 | /* Kill all outstanding requests for the device. */ | ||
89 | list_for_each_entry(ireq, &idev->reqs_in_process, dev_node) { | ||
90 | |||
91 | dev_dbg(&ihost->pdev->dev, | ||
92 | "%s: isci_device = %p request = %p\n", | ||
93 | __func__, idev, ireq); | ||
94 | |||
95 | scic_controller_terminate_request(&ihost->sci, | ||
96 | &idev->sci, | ||
97 | &ireq->sci); | ||
98 | } | ||
99 | /* Fall through into the default case... */ | ||
100 | default: | ||
81 | clear_bit(IDEV_IO_READY, &idev->flags); | 101 | clear_bit(IDEV_IO_READY, &idev->flags); |
102 | break; | ||
103 | } | ||
82 | } | 104 | } |
83 | 105 | ||
84 | /** | 106 | /** |
@@ -94,6 +116,7 @@ static void isci_remote_device_ready(struct isci_host *ihost, struct isci_remote | |||
94 | dev_dbg(&ihost->pdev->dev, | 116 | dev_dbg(&ihost->pdev->dev, |
95 | "%s: idev = %p\n", __func__, idev); | 117 | "%s: idev = %p\n", __func__, idev); |
96 | 118 | ||
119 | clear_bit(IDEV_IO_NCQERROR, &idev->flags); | ||
97 | set_bit(IDEV_IO_READY, &idev->flags); | 120 | set_bit(IDEV_IO_READY, &idev->flags); |
98 | if (test_and_clear_bit(IDEV_START_PENDING, &idev->flags)) | 121 | if (test_and_clear_bit(IDEV_START_PENDING, &idev->flags)) |
99 | wake_up(&ihost->eventq); | 122 | wake_up(&ihost->eventq); |
diff --git a/drivers/scsi/isci/remote_device.h b/drivers/scsi/isci/remote_device.h index cde595078f6d..0d9e37fe734f 100644 --- a/drivers/scsi/isci/remote_device.h +++ b/drivers/scsi/isci/remote_device.h | |||
@@ -136,6 +136,7 @@ struct isci_remote_device { | |||
136 | #define IDEV_EH 3 | 136 | #define IDEV_EH 3 |
137 | #define IDEV_GONE 4 | 137 | #define IDEV_GONE 4 |
138 | #define IDEV_IO_READY 5 | 138 | #define IDEV_IO_READY 5 |
139 | #define IDEV_IO_NCQERROR 6 | ||
139 | unsigned long flags; | 140 | unsigned long flags; |
140 | struct kref kref; | 141 | struct kref kref; |
141 | struct isci_port *isci_port; | 142 | struct isci_port *isci_port; |
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c index 1043fed2a40a..08a7340b33bf 100644 --- a/drivers/scsi/isci/request.c +++ b/drivers/scsi/isci/request.c | |||
@@ -3587,9 +3587,30 @@ int isci_request_execute(struct isci_host *ihost, struct isci_remote_device *ide | |||
3587 | 3587 | ||
3588 | spin_lock_irqsave(&ihost->scic_lock, flags); | 3588 | spin_lock_irqsave(&ihost->scic_lock, flags); |
3589 | 3589 | ||
3590 | /* send the request, let the core assign the IO TAG. */ | 3590 | if (test_bit(IDEV_IO_NCQERROR, &idev->flags)) { |
3591 | status = scic_controller_start_io(&ihost->sci, &idev->sci, &ireq->sci, | 3591 | |
3592 | SCI_CONTROLLER_INVALID_IO_TAG); | 3592 | if (isci_task_is_ncq_recovery(task)) { |
3593 | |||
3594 | /* The device is in an NCQ recovery state. Issue the | ||
3595 | * request on the task side. Note that it will | ||
3596 | * complete on the I/O request side because the | ||
3597 | * request was built that way (ie. | ||
3598 | * ireq->is_task_management_request is false). | ||
3599 | */ | ||
3600 | status = scic_controller_start_task(&ihost->sci, | ||
3601 | &idev->sci, | ||
3602 | &ireq->sci, | ||
3603 | SCI_CONTROLLER_INVALID_IO_TAG); | ||
3604 | } else { | ||
3605 | status = SCI_FAILURE; | ||
3606 | } | ||
3607 | } else { | ||
3608 | |||
3609 | /* send the request, let the core assign the IO TAG. */ | ||
3610 | status = scic_controller_start_io(&ihost->sci, &idev->sci, | ||
3611 | &ireq->sci, | ||
3612 | SCI_CONTROLLER_INVALID_IO_TAG); | ||
3613 | } | ||
3593 | if (status != SCI_SUCCESS && | 3614 | if (status != SCI_SUCCESS && |
3594 | status != SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED) { | 3615 | status != SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED) { |
3595 | dev_warn(&ihost->pdev->dev, | 3616 | dev_warn(&ihost->pdev->dev, |
diff --git a/drivers/scsi/isci/request.h b/drivers/scsi/isci/request.h index 7c8b59a7c02c..9130f22a63b8 100644 --- a/drivers/scsi/isci/request.h +++ b/drivers/scsi/isci/request.h | |||
@@ -687,4 +687,13 @@ scic_task_request_construct_sata(struct scic_sds_request *sci_req); | |||
687 | void | 687 | void |
688 | scic_stp_io_request_set_ncq_tag(struct scic_sds_request *sci_req, u16 ncq_tag); | 688 | scic_stp_io_request_set_ncq_tag(struct scic_sds_request *sci_req, u16 ncq_tag); |
689 | void scic_sds_smp_request_copy_response(struct scic_sds_request *sci_req); | 689 | void scic_sds_smp_request_copy_response(struct scic_sds_request *sci_req); |
690 | |||
691 | static inline int isci_task_is_ncq_recovery(struct sas_task *task) | ||
692 | { | ||
693 | return (sas_protocol_ata(task->task_proto) && | ||
694 | task->ata_task.fis.command == ATA_CMD_READ_LOG_EXT && | ||
695 | task->ata_task.fis.lbal == ATA_LOG_SATA_NCQ); | ||
696 | |||
697 | } | ||
698 | |||
690 | #endif /* !defined(_ISCI_REQUEST_H_) */ | 699 | #endif /* !defined(_ISCI_REQUEST_H_) */ |
diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 0835a2c2dc71..157e9978183a 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c | |||
@@ -133,6 +133,15 @@ static void isci_task_refuse(struct isci_host *ihost, struct sas_task *task, | |||
133 | for (; num > 0; num--,\ | 133 | for (; num > 0; num--,\ |
134 | task = list_entry(task->list.next, struct sas_task, list)) | 134 | task = list_entry(task->list.next, struct sas_task, list)) |
135 | 135 | ||
136 | |||
137 | static inline int isci_device_io_ready(struct isci_remote_device *idev, | ||
138 | struct sas_task *task) | ||
139 | { | ||
140 | return idev ? test_bit(IDEV_IO_READY, &idev->flags) || | ||
141 | (test_bit(IDEV_IO_NCQERROR, &idev->flags) && | ||
142 | isci_task_is_ncq_recovery(task)) | ||
143 | : 0; | ||
144 | } | ||
136 | /** | 145 | /** |
137 | * isci_task_execute_task() - This function is one of the SAS Domain Template | 146 | * isci_task_execute_task() - This function is one of the SAS Domain Template |
138 | * functions. This function is called by libsas to send a task down to | 147 | * functions. This function is called by libsas to send a task down to |
@@ -165,7 +174,7 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) | |||
165 | for_each_sas_task(num, task) { | 174 | for_each_sas_task(num, task) { |
166 | spin_lock_irqsave(&ihost->scic_lock, flags); | 175 | spin_lock_irqsave(&ihost->scic_lock, flags); |
167 | idev = isci_lookup_device(task->dev); | 176 | idev = isci_lookup_device(task->dev); |
168 | io_ready = idev ? test_bit(IDEV_IO_READY, &idev->flags) : 0; | 177 | io_ready = isci_device_io_ready(idev, task); |
169 | spin_unlock_irqrestore(&ihost->scic_lock, flags); | 178 | spin_unlock_irqrestore(&ihost->scic_lock, flags); |
170 | 179 | ||
171 | dev_dbg(&ihost->pdev->dev, | 180 | dev_dbg(&ihost->pdev->dev, |
@@ -178,6 +187,7 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) | |||
178 | SAS_DEVICE_UNKNOWN); | 187 | SAS_DEVICE_UNKNOWN); |
179 | isci_host_can_dequeue(ihost, 1); | 188 | isci_host_can_dequeue(ihost, 1); |
180 | } else if (!io_ready) { | 189 | } else if (!io_ready) { |
190 | |||
181 | /* Indicate QUEUE_FULL so that the scsi midlayer | 191 | /* Indicate QUEUE_FULL so that the scsi midlayer |
182 | * retries. | 192 | * retries. |
183 | */ | 193 | */ |
@@ -299,7 +309,9 @@ int isci_task_execute_tmf(struct isci_host *ihost, | |||
299 | /* sanity check, return TMF_RESP_FUNC_FAILED | 309 | /* sanity check, return TMF_RESP_FUNC_FAILED |
300 | * if the device is not there and ready. | 310 | * if the device is not there and ready. |
301 | */ | 311 | */ |
302 | if (!isci_device || !test_bit(IDEV_IO_READY, &isci_device->flags)) { | 312 | if (!isci_device || |
313 | (!test_bit(IDEV_IO_READY, &isci_device->flags) && | ||
314 | !test_bit(IDEV_IO_NCQERROR, &isci_device->flags))) { | ||
303 | dev_dbg(&ihost->pdev->dev, | 315 | dev_dbg(&ihost->pdev->dev, |
304 | "%s: isci_device = %p not ready (%#lx)\n", | 316 | "%s: isci_device = %p not ready (%#lx)\n", |
305 | __func__, | 317 | __func__, |