diff options
Diffstat (limited to 'drivers/scsi/isci/remote_device.c')
-rw-r--r-- | drivers/scsi/isci/remote_device.c | 576 |
1 files changed, 433 insertions, 143 deletions
diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c index 8f501b0a81d6..c3aa6c5457b9 100644 --- a/drivers/scsi/isci/remote_device.c +++ b/drivers/scsi/isci/remote_device.c | |||
@@ -72,46 +72,11 @@ const char *dev_state_name(enum sci_remote_device_states state) | |||
72 | } | 72 | } |
73 | #undef C | 73 | #undef C |
74 | 74 | ||
75 | /** | 75 | enum sci_status sci_remote_device_suspend(struct isci_remote_device *idev, |
76 | * isci_remote_device_not_ready() - This function is called by the ihost when | 76 | enum sci_remote_node_suspension_reasons reason) |
77 | * the remote device is not ready. We mark the isci device as ready (not | ||
78 | * "ready_for_io") and signal the waiting proccess. | ||
79 | * @isci_host: This parameter specifies the isci host object. | ||
80 | * @isci_device: This parameter specifies the remote device | ||
81 | * | ||
82 | * sci_lock is held on entrance to this function. | ||
83 | */ | ||
84 | static void isci_remote_device_not_ready(struct isci_host *ihost, | ||
85 | struct isci_remote_device *idev, u32 reason) | ||
86 | { | 77 | { |
87 | struct isci_request *ireq; | 78 | return sci_remote_node_context_suspend(&idev->rnc, reason, |
88 | 79 | SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT); | |
89 | dev_dbg(&ihost->pdev->dev, | ||
90 | "%s: isci_device = %p\n", __func__, idev); | ||
91 | |||
92 | switch (reason) { | ||
93 | case SCIC_REMOTE_DEVICE_NOT_READY_STOP_REQUESTED: | ||
94 | set_bit(IDEV_GONE, &idev->flags); | ||
95 | break; | ||
96 | case SCIC_REMOTE_DEVICE_NOT_READY_SATA_SDB_ERROR_FIS_RECEIVED: | ||
97 | set_bit(IDEV_IO_NCQERROR, &idev->flags); | ||
98 | |||
99 | /* Kill all outstanding requests for the device. */ | ||
100 | list_for_each_entry(ireq, &idev->reqs_in_process, dev_node) { | ||
101 | |||
102 | dev_dbg(&ihost->pdev->dev, | ||
103 | "%s: isci_device = %p request = %p\n", | ||
104 | __func__, idev, ireq); | ||
105 | |||
106 | sci_controller_terminate_request(ihost, | ||
107 | idev, | ||
108 | ireq); | ||
109 | } | ||
110 | /* Fall through into the default case... */ | ||
111 | default: | ||
112 | clear_bit(IDEV_IO_READY, &idev->flags); | ||
113 | break; | ||
114 | } | ||
115 | } | 80 | } |
116 | 81 | ||
117 | /** | 82 | /** |
@@ -133,18 +98,29 @@ static void isci_remote_device_ready(struct isci_host *ihost, struct isci_remote | |||
133 | wake_up(&ihost->eventq); | 98 | wake_up(&ihost->eventq); |
134 | } | 99 | } |
135 | 100 | ||
136 | /* called once the remote node context is ready to be freed. | 101 | static enum sci_status sci_remote_device_terminate_req( |
137 | * The remote device can now report that its stop operation is complete. none | 102 | struct isci_host *ihost, |
138 | */ | 103 | struct isci_remote_device *idev, |
139 | static void rnc_destruct_done(void *_dev) | 104 | int check_abort, |
105 | struct isci_request *ireq) | ||
140 | { | 106 | { |
141 | struct isci_remote_device *idev = _dev; | 107 | if (!test_bit(IREQ_ACTIVE, &ireq->flags) || |
108 | (ireq->target_device != idev) || | ||
109 | (check_abort && !test_bit(IREQ_PENDING_ABORT, &ireq->flags))) | ||
110 | return SCI_SUCCESS; | ||
142 | 111 | ||
143 | BUG_ON(idev->started_request_count != 0); | 112 | dev_dbg(&ihost->pdev->dev, |
144 | sci_change_state(&idev->sm, SCI_DEV_STOPPED); | 113 | "%s: idev=%p; flags=%lx; req=%p; req target=%p\n", |
114 | __func__, idev, idev->flags, ireq, ireq->target_device); | ||
115 | |||
116 | set_bit(IREQ_ABORT_PATH_ACTIVE, &ireq->flags); | ||
117 | |||
118 | return sci_controller_terminate_request(ihost, idev, ireq); | ||
145 | } | 119 | } |
146 | 120 | ||
147 | static enum sci_status sci_remote_device_terminate_requests(struct isci_remote_device *idev) | 121 | static enum sci_status sci_remote_device_terminate_reqs_checkabort( |
122 | struct isci_remote_device *idev, | ||
123 | int chk) | ||
148 | { | 124 | { |
149 | struct isci_host *ihost = idev->owning_port->owning_controller; | 125 | struct isci_host *ihost = idev->owning_port->owning_controller; |
150 | enum sci_status status = SCI_SUCCESS; | 126 | enum sci_status status = SCI_SUCCESS; |
@@ -154,18 +130,210 @@ static enum sci_status sci_remote_device_terminate_requests(struct isci_remote_d | |||
154 | struct isci_request *ireq = ihost->reqs[i]; | 130 | struct isci_request *ireq = ihost->reqs[i]; |
155 | enum sci_status s; | 131 | enum sci_status s; |
156 | 132 | ||
157 | if (!test_bit(IREQ_ACTIVE, &ireq->flags) || | 133 | s = sci_remote_device_terminate_req(ihost, idev, chk, ireq); |
158 | ireq->target_device != idev) | ||
159 | continue; | ||
160 | |||
161 | s = sci_controller_terminate_request(ihost, idev, ireq); | ||
162 | if (s != SCI_SUCCESS) | 134 | if (s != SCI_SUCCESS) |
163 | status = s; | 135 | status = s; |
164 | } | 136 | } |
137 | return status; | ||
138 | } | ||
139 | |||
140 | static bool isci_compare_suspendcount( | ||
141 | struct isci_remote_device *idev, | ||
142 | u32 localcount) | ||
143 | { | ||
144 | smp_rmb(); | ||
145 | |||
146 | /* Check for a change in the suspend count, or the RNC | ||
147 | * being destroyed. | ||
148 | */ | ||
149 | return (localcount != idev->rnc.suspend_count) | ||
150 | || sci_remote_node_context_is_being_destroyed(&idev->rnc); | ||
151 | } | ||
152 | |||
153 | static bool isci_check_reqterm( | ||
154 | struct isci_host *ihost, | ||
155 | struct isci_remote_device *idev, | ||
156 | struct isci_request *ireq, | ||
157 | u32 localcount) | ||
158 | { | ||
159 | unsigned long flags; | ||
160 | bool res; | ||
165 | 161 | ||
162 | spin_lock_irqsave(&ihost->scic_lock, flags); | ||
163 | res = isci_compare_suspendcount(idev, localcount) | ||
164 | && !test_bit(IREQ_ABORT_PATH_ACTIVE, &ireq->flags); | ||
165 | spin_unlock_irqrestore(&ihost->scic_lock, flags); | ||
166 | |||
167 | return res; | ||
168 | } | ||
169 | |||
170 | static bool isci_check_devempty( | ||
171 | struct isci_host *ihost, | ||
172 | struct isci_remote_device *idev, | ||
173 | u32 localcount) | ||
174 | { | ||
175 | unsigned long flags; | ||
176 | bool res; | ||
177 | |||
178 | spin_lock_irqsave(&ihost->scic_lock, flags); | ||
179 | res = isci_compare_suspendcount(idev, localcount) | ||
180 | && idev->started_request_count == 0; | ||
181 | spin_unlock_irqrestore(&ihost->scic_lock, flags); | ||
182 | |||
183 | return res; | ||
184 | } | ||
185 | |||
186 | enum sci_status isci_remote_device_terminate_requests( | ||
187 | struct isci_host *ihost, | ||
188 | struct isci_remote_device *idev, | ||
189 | struct isci_request *ireq) | ||
190 | { | ||
191 | enum sci_status status = SCI_SUCCESS; | ||
192 | unsigned long flags; | ||
193 | u32 rnc_suspend_count; | ||
194 | |||
195 | spin_lock_irqsave(&ihost->scic_lock, flags); | ||
196 | |||
197 | if (isci_get_device(idev) == NULL) { | ||
198 | dev_dbg(&ihost->pdev->dev, "%s: failed isci_get_device(idev=%p)\n", | ||
199 | __func__, idev); | ||
200 | spin_unlock_irqrestore(&ihost->scic_lock, flags); | ||
201 | status = SCI_FAILURE; | ||
202 | } else { | ||
203 | /* If already suspended, don't wait for another suspension. */ | ||
204 | smp_rmb(); | ||
205 | rnc_suspend_count | ||
206 | = sci_remote_node_context_is_suspended(&idev->rnc) | ||
207 | ? 0 : idev->rnc.suspend_count; | ||
208 | |||
209 | dev_dbg(&ihost->pdev->dev, | ||
210 | "%s: idev=%p, ireq=%p; started_request_count=%d, " | ||
211 | "rnc_suspend_count=%d, rnc.suspend_count=%d" | ||
212 | "about to wait\n", | ||
213 | __func__, idev, ireq, idev->started_request_count, | ||
214 | rnc_suspend_count, idev->rnc.suspend_count); | ||
215 | |||
216 | #define MAX_SUSPEND_MSECS 10000 | ||
217 | if (ireq) { | ||
218 | /* Terminate a specific TC. */ | ||
219 | set_bit(IREQ_NO_AUTO_FREE_TAG, &ireq->flags); | ||
220 | sci_remote_device_terminate_req(ihost, idev, 0, ireq); | ||
221 | spin_unlock_irqrestore(&ihost->scic_lock, flags); | ||
222 | if (!wait_event_timeout(ihost->eventq, | ||
223 | isci_check_reqterm(ihost, idev, ireq, | ||
224 | rnc_suspend_count), | ||
225 | msecs_to_jiffies(MAX_SUSPEND_MSECS))) { | ||
226 | |||
227 | dev_warn(&ihost->pdev->dev, "%s host%d timeout single\n", | ||
228 | __func__, ihost->id); | ||
229 | dev_dbg(&ihost->pdev->dev, | ||
230 | "%s: ******* Timeout waiting for " | ||
231 | "suspend; idev=%p, current state %s; " | ||
232 | "started_request_count=%d, flags=%lx\n\t" | ||
233 | "rnc_suspend_count=%d, rnc.suspend_count=%d " | ||
234 | "RNC: current state %s, current " | ||
235 | "suspend_type %x dest state %d;\n" | ||
236 | "ireq=%p, ireq->flags = %lx\n", | ||
237 | __func__, idev, | ||
238 | dev_state_name(idev->sm.current_state_id), | ||
239 | idev->started_request_count, idev->flags, | ||
240 | rnc_suspend_count, idev->rnc.suspend_count, | ||
241 | rnc_state_name(idev->rnc.sm.current_state_id), | ||
242 | idev->rnc.suspend_type, | ||
243 | idev->rnc.destination_state, | ||
244 | ireq, ireq->flags); | ||
245 | } | ||
246 | spin_lock_irqsave(&ihost->scic_lock, flags); | ||
247 | clear_bit(IREQ_NO_AUTO_FREE_TAG, &ireq->flags); | ||
248 | if (!test_bit(IREQ_ABORT_PATH_ACTIVE, &ireq->flags)) | ||
249 | isci_free_tag(ihost, ireq->io_tag); | ||
250 | spin_unlock_irqrestore(&ihost->scic_lock, flags); | ||
251 | } else { | ||
252 | /* Terminate all TCs. */ | ||
253 | sci_remote_device_terminate_requests(idev); | ||
254 | spin_unlock_irqrestore(&ihost->scic_lock, flags); | ||
255 | if (!wait_event_timeout(ihost->eventq, | ||
256 | isci_check_devempty(ihost, idev, | ||
257 | rnc_suspend_count), | ||
258 | msecs_to_jiffies(MAX_SUSPEND_MSECS))) { | ||
259 | |||
260 | dev_warn(&ihost->pdev->dev, "%s host%d timeout all\n", | ||
261 | __func__, ihost->id); | ||
262 | dev_dbg(&ihost->pdev->dev, | ||
263 | "%s: ******* Timeout waiting for " | ||
264 | "suspend; idev=%p, current state %s; " | ||
265 | "started_request_count=%d, flags=%lx\n\t" | ||
266 | "rnc_suspend_count=%d, " | ||
267 | "RNC: current state %s, " | ||
268 | "rnc.suspend_count=%d, current " | ||
269 | "suspend_type %x dest state %d\n", | ||
270 | __func__, idev, | ||
271 | dev_state_name(idev->sm.current_state_id), | ||
272 | idev->started_request_count, idev->flags, | ||
273 | rnc_suspend_count, | ||
274 | rnc_state_name(idev->rnc.sm.current_state_id), | ||
275 | idev->rnc.suspend_count, | ||
276 | idev->rnc.suspend_type, | ||
277 | idev->rnc.destination_state); | ||
278 | } | ||
279 | } | ||
280 | dev_dbg(&ihost->pdev->dev, "%s: idev=%p, wait done\n", | ||
281 | __func__, idev); | ||
282 | isci_put_device(idev); | ||
283 | } | ||
166 | return status; | 284 | return status; |
167 | } | 285 | } |
168 | 286 | ||
287 | /** | ||
288 | * isci_remote_device_not_ready() - This function is called by the ihost when | ||
289 | * the remote device is not ready. We mark the isci device as ready (not | ||
290 | * "ready_for_io") and signal the waiting proccess. | ||
291 | * @isci_host: This parameter specifies the isci host object. | ||
292 | * @isci_device: This parameter specifies the remote device | ||
293 | * | ||
294 | * sci_lock is held on entrance to this function. | ||
295 | */ | ||
296 | static void isci_remote_device_not_ready(struct isci_host *ihost, | ||
297 | struct isci_remote_device *idev, | ||
298 | u32 reason) | ||
299 | { | ||
300 | dev_dbg(&ihost->pdev->dev, | ||
301 | "%s: isci_device = %p; reason = %d\n", __func__, idev, reason); | ||
302 | |||
303 | switch (reason) { | ||
304 | case SCIC_REMOTE_DEVICE_NOT_READY_SATA_SDB_ERROR_FIS_RECEIVED: | ||
305 | set_bit(IDEV_IO_NCQERROR, &idev->flags); | ||
306 | |||
307 | /* Suspend the remote device so the I/O can be terminated. */ | ||
308 | sci_remote_device_suspend(idev, SCI_SW_SUSPEND_NORMAL); | ||
309 | |||
310 | /* Kill all outstanding requests for the device. */ | ||
311 | sci_remote_device_terminate_requests(idev); | ||
312 | |||
313 | /* Fall through into the default case... */ | ||
314 | default: | ||
315 | clear_bit(IDEV_IO_READY, &idev->flags); | ||
316 | break; | ||
317 | } | ||
318 | } | ||
319 | |||
320 | /* called once the remote node context is ready to be freed. | ||
321 | * The remote device can now report that its stop operation is complete. none | ||
322 | */ | ||
323 | static void rnc_destruct_done(void *_dev) | ||
324 | { | ||
325 | struct isci_remote_device *idev = _dev; | ||
326 | |||
327 | BUG_ON(idev->started_request_count != 0); | ||
328 | sci_change_state(&idev->sm, SCI_DEV_STOPPED); | ||
329 | } | ||
330 | |||
331 | enum sci_status sci_remote_device_terminate_requests( | ||
332 | struct isci_remote_device *idev) | ||
333 | { | ||
334 | return sci_remote_device_terminate_reqs_checkabort(idev, 0); | ||
335 | } | ||
336 | |||
169 | enum sci_status sci_remote_device_stop(struct isci_remote_device *idev, | 337 | enum sci_status sci_remote_device_stop(struct isci_remote_device *idev, |
170 | u32 timeout) | 338 | u32 timeout) |
171 | { | 339 | { |
@@ -201,13 +369,16 @@ enum sci_status sci_remote_device_stop(struct isci_remote_device *idev, | |||
201 | case SCI_SMP_DEV_IDLE: | 369 | case SCI_SMP_DEV_IDLE: |
202 | case SCI_SMP_DEV_CMD: | 370 | case SCI_SMP_DEV_CMD: |
203 | sci_change_state(sm, SCI_DEV_STOPPING); | 371 | sci_change_state(sm, SCI_DEV_STOPPING); |
204 | if (idev->started_request_count == 0) { | 372 | if (idev->started_request_count == 0) |
205 | sci_remote_node_context_destruct(&idev->rnc, | 373 | sci_remote_node_context_destruct(&idev->rnc, |
206 | rnc_destruct_done, idev); | 374 | rnc_destruct_done, |
207 | return SCI_SUCCESS; | 375 | idev); |
208 | } else | 376 | else { |
209 | return sci_remote_device_terminate_requests(idev); | 377 | sci_remote_device_suspend( |
210 | break; | 378 | idev, SCI_SW_SUSPEND_LINKHANG_DETECT); |
379 | sci_remote_device_terminate_requests(idev); | ||
380 | } | ||
381 | return SCI_SUCCESS; | ||
211 | case SCI_DEV_STOPPING: | 382 | case SCI_DEV_STOPPING: |
212 | /* All requests should have been terminated, but if there is an | 383 | /* All requests should have been terminated, but if there is an |
213 | * attempt to stop a device already in the stopping state, then | 384 | * attempt to stop a device already in the stopping state, then |
@@ -265,22 +436,6 @@ enum sci_status sci_remote_device_reset_complete(struct isci_remote_device *idev | |||
265 | return SCI_SUCCESS; | 436 | return SCI_SUCCESS; |
266 | } | 437 | } |
267 | 438 | ||
268 | enum sci_status sci_remote_device_suspend(struct isci_remote_device *idev, | ||
269 | u32 suspend_type) | ||
270 | { | ||
271 | struct sci_base_state_machine *sm = &idev->sm; | ||
272 | enum sci_remote_device_states state = sm->current_state_id; | ||
273 | |||
274 | if (state != SCI_STP_DEV_CMD) { | ||
275 | dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n", | ||
276 | __func__, dev_state_name(state)); | ||
277 | return SCI_FAILURE_INVALID_STATE; | ||
278 | } | ||
279 | |||
280 | return sci_remote_node_context_suspend(&idev->rnc, | ||
281 | suspend_type, NULL, NULL); | ||
282 | } | ||
283 | |||
284 | enum sci_status sci_remote_device_frame_handler(struct isci_remote_device *idev, | 439 | enum sci_status sci_remote_device_frame_handler(struct isci_remote_device *idev, |
285 | u32 frame_index) | 440 | u32 frame_index) |
286 | { | 441 | { |
@@ -412,9 +567,9 @@ static void atapi_remote_device_resume_done(void *_dev) | |||
412 | enum sci_status sci_remote_device_event_handler(struct isci_remote_device *idev, | 567 | enum sci_status sci_remote_device_event_handler(struct isci_remote_device *idev, |
413 | u32 event_code) | 568 | u32 event_code) |
414 | { | 569 | { |
570 | enum sci_status status; | ||
415 | struct sci_base_state_machine *sm = &idev->sm; | 571 | struct sci_base_state_machine *sm = &idev->sm; |
416 | enum sci_remote_device_states state = sm->current_state_id; | 572 | enum sci_remote_device_states state = sm->current_state_id; |
417 | enum sci_status status; | ||
418 | 573 | ||
419 | switch (scu_get_event_type(event_code)) { | 574 | switch (scu_get_event_type(event_code)) { |
420 | case SCU_EVENT_TYPE_RNC_OPS_MISC: | 575 | case SCU_EVENT_TYPE_RNC_OPS_MISC: |
@@ -427,9 +582,7 @@ enum sci_status sci_remote_device_event_handler(struct isci_remote_device *idev, | |||
427 | status = SCI_SUCCESS; | 582 | status = SCI_SUCCESS; |
428 | 583 | ||
429 | /* Suspend the associated RNC */ | 584 | /* Suspend the associated RNC */ |
430 | sci_remote_node_context_suspend(&idev->rnc, | 585 | sci_remote_device_suspend(idev, SCI_SW_SUSPEND_NORMAL); |
431 | SCI_SOFTWARE_SUSPENSION, | ||
432 | NULL, NULL); | ||
433 | 586 | ||
434 | dev_dbg(scirdev_to_dev(idev), | 587 | dev_dbg(scirdev_to_dev(idev), |
435 | "%s: device: %p event code: %x: %s\n", | 588 | "%s: device: %p event code: %x: %s\n", |
@@ -455,6 +608,10 @@ enum sci_status sci_remote_device_event_handler(struct isci_remote_device *idev, | |||
455 | if (status != SCI_SUCCESS) | 608 | if (status != SCI_SUCCESS) |
456 | return status; | 609 | return status; |
457 | 610 | ||
611 | /* Decode device-specific states that may require an RNC resume during | ||
612 | * normal operation. When the abort path is active, these resumes are | ||
613 | * managed when the abort path exits. | ||
614 | */ | ||
458 | if (state == SCI_STP_DEV_ATAPI_ERROR) { | 615 | if (state == SCI_STP_DEV_ATAPI_ERROR) { |
459 | /* For ATAPI error state resume the RNC right away. */ | 616 | /* For ATAPI error state resume the RNC right away. */ |
460 | if (scu_get_event_type(event_code) == SCU_EVENT_TYPE_RNC_SUSPEND_TX || | 617 | if (scu_get_event_type(event_code) == SCU_EVENT_TYPE_RNC_SUSPEND_TX || |
@@ -743,10 +900,6 @@ enum sci_status sci_remote_device_start_task(struct isci_host *ihost, | |||
743 | if (status != SCI_SUCCESS) | 900 | if (status != SCI_SUCCESS) |
744 | return status; | 901 | return status; |
745 | 902 | ||
746 | status = sci_remote_node_context_start_task(&idev->rnc, ireq); | ||
747 | if (status != SCI_SUCCESS) | ||
748 | goto out; | ||
749 | |||
750 | status = sci_request_start(ireq); | 903 | status = sci_request_start(ireq); |
751 | if (status != SCI_SUCCESS) | 904 | if (status != SCI_SUCCESS) |
752 | goto out; | 905 | goto out; |
@@ -765,11 +918,11 @@ enum sci_status sci_remote_device_start_task(struct isci_host *ihost, | |||
765 | * the correct action when the remote node context is suspended | 918 | * the correct action when the remote node context is suspended |
766 | * and later resumed. | 919 | * and later resumed. |
767 | */ | 920 | */ |
768 | sci_remote_node_context_suspend(&idev->rnc, | 921 | sci_remote_device_suspend(idev, |
769 | SCI_SOFTWARE_SUSPENSION, NULL, NULL); | 922 | SCI_SW_SUSPEND_LINKHANG_DETECT); |
770 | sci_remote_node_context_resume(&idev->rnc, | 923 | |
771 | sci_remote_device_continue_request, | 924 | status = sci_remote_node_context_start_task(&idev->rnc, ireq, |
772 | idev); | 925 | sci_remote_device_continue_request, idev); |
773 | 926 | ||
774 | out: | 927 | out: |
775 | sci_remote_device_start_request(idev, ireq, status); | 928 | sci_remote_device_start_request(idev, ireq, status); |
@@ -783,7 +936,9 @@ enum sci_status sci_remote_device_start_task(struct isci_host *ihost, | |||
783 | if (status != SCI_SUCCESS) | 936 | if (status != SCI_SUCCESS) |
784 | return status; | 937 | return status; |
785 | 938 | ||
786 | status = sci_remote_node_context_start_task(&idev->rnc, ireq); | 939 | /* Resume the RNC as needed: */ |
940 | status = sci_remote_node_context_start_task(&idev->rnc, ireq, | ||
941 | NULL, NULL); | ||
787 | if (status != SCI_SUCCESS) | 942 | if (status != SCI_SUCCESS) |
788 | break; | 943 | break; |
789 | 944 | ||
@@ -892,7 +1047,7 @@ static void isci_remote_device_deconstruct(struct isci_host *ihost, struct isci_ | |||
892 | * here should go through isci_remote_device_nuke_requests. | 1047 | * here should go through isci_remote_device_nuke_requests. |
893 | * If we hit this condition, we will need a way to complete | 1048 | * If we hit this condition, we will need a way to complete |
894 | * io requests in process */ | 1049 | * io requests in process */ |
895 | BUG_ON(!list_empty(&idev->reqs_in_process)); | 1050 | BUG_ON(idev->started_request_count > 0); |
896 | 1051 | ||
897 | sci_remote_device_destruct(idev); | 1052 | sci_remote_device_destruct(idev); |
898 | list_del_init(&idev->node); | 1053 | list_del_init(&idev->node); |
@@ -954,14 +1109,21 @@ static void sci_remote_device_ready_state_exit(struct sci_base_state_machine *sm | |||
954 | static void sci_remote_device_resetting_state_enter(struct sci_base_state_machine *sm) | 1109 | static void sci_remote_device_resetting_state_enter(struct sci_base_state_machine *sm) |
955 | { | 1110 | { |
956 | struct isci_remote_device *idev = container_of(sm, typeof(*idev), sm); | 1111 | struct isci_remote_device *idev = container_of(sm, typeof(*idev), sm); |
1112 | struct isci_host *ihost = idev->owning_port->owning_controller; | ||
957 | 1113 | ||
958 | sci_remote_node_context_suspend( | 1114 | dev_dbg(&ihost->pdev->dev, |
959 | &idev->rnc, SCI_SOFTWARE_SUSPENSION, NULL, NULL); | 1115 | "%s: isci_device = %p\n", __func__, idev); |
1116 | |||
1117 | sci_remote_device_suspend(idev, SCI_SW_SUSPEND_LINKHANG_DETECT); | ||
960 | } | 1118 | } |
961 | 1119 | ||
962 | static void sci_remote_device_resetting_state_exit(struct sci_base_state_machine *sm) | 1120 | static void sci_remote_device_resetting_state_exit(struct sci_base_state_machine *sm) |
963 | { | 1121 | { |
964 | struct isci_remote_device *idev = container_of(sm, typeof(*idev), sm); | 1122 | struct isci_remote_device *idev = container_of(sm, typeof(*idev), sm); |
1123 | struct isci_host *ihost = idev->owning_port->owning_controller; | ||
1124 | |||
1125 | dev_dbg(&ihost->pdev->dev, | ||
1126 | "%s: isci_device = %p\n", __func__, idev); | ||
965 | 1127 | ||
966 | sci_remote_node_context_resume(&idev->rnc, NULL, NULL); | 1128 | sci_remote_node_context_resume(&idev->rnc, NULL, NULL); |
967 | } | 1129 | } |
@@ -1113,33 +1275,20 @@ static enum sci_status sci_remote_device_da_construct(struct isci_port *iport, | |||
1113 | { | 1275 | { |
1114 | enum sci_status status; | 1276 | enum sci_status status; |
1115 | struct sci_port_properties properties; | 1277 | struct sci_port_properties properties; |
1116 | struct domain_device *dev = idev->domain_dev; | ||
1117 | 1278 | ||
1118 | sci_remote_device_construct(iport, idev); | 1279 | sci_remote_device_construct(iport, idev); |
1119 | 1280 | ||
1120 | /* | ||
1121 | * This information is request to determine how many remote node context | ||
1122 | * entries will be needed to store the remote node. | ||
1123 | */ | ||
1124 | idev->is_direct_attached = true; | ||
1125 | |||
1126 | sci_port_get_properties(iport, &properties); | 1281 | sci_port_get_properties(iport, &properties); |
1127 | /* Get accurate port width from port's phy mask for a DA device. */ | 1282 | /* Get accurate port width from port's phy mask for a DA device. */ |
1128 | idev->device_port_width = hweight32(properties.phy_mask); | 1283 | idev->device_port_width = hweight32(properties.phy_mask); |
1129 | 1284 | ||
1130 | status = sci_controller_allocate_remote_node_context(iport->owning_controller, | 1285 | status = sci_controller_allocate_remote_node_context(iport->owning_controller, |
1131 | idev, | 1286 | idev, |
1132 | &idev->rnc.remote_node_index); | 1287 | &idev->rnc.remote_node_index); |
1133 | 1288 | ||
1134 | if (status != SCI_SUCCESS) | 1289 | if (status != SCI_SUCCESS) |
1135 | return status; | 1290 | return status; |
1136 | 1291 | ||
1137 | if (dev->dev_type == SAS_END_DEV || dev->dev_type == SATA_DEV || | ||
1138 | (dev->tproto & SAS_PROTOCOL_STP) || dev_is_expander(dev)) | ||
1139 | /* pass */; | ||
1140 | else | ||
1141 | return SCI_FAILURE_UNSUPPORTED_PROTOCOL; | ||
1142 | |||
1143 | idev->connection_rate = sci_port_get_max_allowed_speed(iport); | 1292 | idev->connection_rate = sci_port_get_max_allowed_speed(iport); |
1144 | 1293 | ||
1145 | return SCI_SUCCESS; | 1294 | return SCI_SUCCESS; |
@@ -1171,19 +1320,13 @@ static enum sci_status sci_remote_device_ea_construct(struct isci_port *iport, | |||
1171 | if (status != SCI_SUCCESS) | 1320 | if (status != SCI_SUCCESS) |
1172 | return status; | 1321 | return status; |
1173 | 1322 | ||
1174 | if (dev->dev_type == SAS_END_DEV || dev->dev_type == SATA_DEV || | 1323 | /* For SAS-2 the physical link rate is actually a logical link |
1175 | (dev->tproto & SAS_PROTOCOL_STP) || dev_is_expander(dev)) | ||
1176 | /* pass */; | ||
1177 | else | ||
1178 | return SCI_FAILURE_UNSUPPORTED_PROTOCOL; | ||
1179 | |||
1180 | /* | ||
1181 | * For SAS-2 the physical link rate is actually a logical link | ||
1182 | * rate that incorporates multiplexing. The SCU doesn't | 1324 | * rate that incorporates multiplexing. The SCU doesn't |
1183 | * incorporate multiplexing and for the purposes of the | 1325 | * incorporate multiplexing and for the purposes of the |
1184 | * connection the logical link rate is that same as the | 1326 | * connection the logical link rate is that same as the |
1185 | * physical. Furthermore, the SAS-2 and SAS-1.1 fields overlay | 1327 | * physical. Furthermore, the SAS-2 and SAS-1.1 fields overlay |
1186 | * one another, so this code works for both situations. */ | 1328 | * one another, so this code works for both situations. |
1329 | */ | ||
1187 | idev->connection_rate = min_t(u16, sci_port_get_max_allowed_speed(iport), | 1330 | idev->connection_rate = min_t(u16, sci_port_get_max_allowed_speed(iport), |
1188 | dev->linkrate); | 1331 | dev->linkrate); |
1189 | 1332 | ||
@@ -1193,6 +1336,105 @@ static enum sci_status sci_remote_device_ea_construct(struct isci_port *iport, | |||
1193 | return SCI_SUCCESS; | 1336 | return SCI_SUCCESS; |
1194 | } | 1337 | } |
1195 | 1338 | ||
1339 | enum sci_status sci_remote_device_resume( | ||
1340 | struct isci_remote_device *idev, | ||
1341 | scics_sds_remote_node_context_callback cb_fn, | ||
1342 | void *cb_p) | ||
1343 | { | ||
1344 | enum sci_status status; | ||
1345 | |||
1346 | status = sci_remote_node_context_resume(&idev->rnc, cb_fn, cb_p); | ||
1347 | if (status != SCI_SUCCESS) | ||
1348 | dev_dbg(scirdev_to_dev(idev), "%s: failed to resume: %d\n", | ||
1349 | __func__, status); | ||
1350 | return status; | ||
1351 | } | ||
1352 | |||
1353 | static void isci_remote_device_resume_from_abort_complete(void *cbparam) | ||
1354 | { | ||
1355 | struct isci_remote_device *idev = cbparam; | ||
1356 | struct isci_host *ihost = idev->owning_port->owning_controller; | ||
1357 | scics_sds_remote_node_context_callback abort_resume_cb = | ||
1358 | idev->abort_resume_cb; | ||
1359 | |||
1360 | dev_dbg(scirdev_to_dev(idev), "%s: passing-along resume: %p\n", | ||
1361 | __func__, abort_resume_cb); | ||
1362 | |||
1363 | if (abort_resume_cb != NULL) { | ||
1364 | idev->abort_resume_cb = NULL; | ||
1365 | abort_resume_cb(idev->abort_resume_cbparam); | ||
1366 | } | ||
1367 | clear_bit(IDEV_ABORT_PATH_RESUME_PENDING, &idev->flags); | ||
1368 | wake_up(&ihost->eventq); | ||
1369 | } | ||
1370 | |||
1371 | static bool isci_remote_device_test_resume_done( | ||
1372 | struct isci_host *ihost, | ||
1373 | struct isci_remote_device *idev) | ||
1374 | { | ||
1375 | unsigned long flags; | ||
1376 | bool done; | ||
1377 | |||
1378 | spin_lock_irqsave(&ihost->scic_lock, flags); | ||
1379 | done = !test_bit(IDEV_ABORT_PATH_RESUME_PENDING, &idev->flags) | ||
1380 | || test_bit(IDEV_STOP_PENDING, &idev->flags) | ||
1381 | || sci_remote_node_context_is_being_destroyed(&idev->rnc); | ||
1382 | spin_unlock_irqrestore(&ihost->scic_lock, flags); | ||
1383 | |||
1384 | return done; | ||
1385 | } | ||
1386 | |||
1387 | void isci_remote_device_wait_for_resume_from_abort( | ||
1388 | struct isci_host *ihost, | ||
1389 | struct isci_remote_device *idev) | ||
1390 | { | ||
1391 | dev_dbg(&ihost->pdev->dev, "%s: starting resume wait: %p\n", | ||
1392 | __func__, idev); | ||
1393 | |||
1394 | #define MAX_RESUME_MSECS 10000 | ||
1395 | if (!wait_event_timeout(ihost->eventq, | ||
1396 | isci_remote_device_test_resume_done(ihost, idev), | ||
1397 | msecs_to_jiffies(MAX_RESUME_MSECS))) { | ||
1398 | |||
1399 | dev_warn(&ihost->pdev->dev, "%s: #### Timeout waiting for " | ||
1400 | "resume: %p\n", __func__, idev); | ||
1401 | } | ||
1402 | clear_bit(IDEV_ABORT_PATH_RESUME_PENDING, &idev->flags); | ||
1403 | |||
1404 | dev_dbg(&ihost->pdev->dev, "%s: resume wait done: %p\n", | ||
1405 | __func__, idev); | ||
1406 | } | ||
1407 | |||
1408 | enum sci_status isci_remote_device_resume_from_abort( | ||
1409 | struct isci_host *ihost, | ||
1410 | struct isci_remote_device *idev) | ||
1411 | { | ||
1412 | unsigned long flags; | ||
1413 | enum sci_status status = SCI_SUCCESS; | ||
1414 | int destroyed; | ||
1415 | |||
1416 | spin_lock_irqsave(&ihost->scic_lock, flags); | ||
1417 | /* Preserve any current resume callbacks, for instance from other | ||
1418 | * resumptions. | ||
1419 | */ | ||
1420 | idev->abort_resume_cb = idev->rnc.user_callback; | ||
1421 | idev->abort_resume_cbparam = idev->rnc.user_cookie; | ||
1422 | set_bit(IDEV_ABORT_PATH_RESUME_PENDING, &idev->flags); | ||
1423 | clear_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags); | ||
1424 | destroyed = sci_remote_node_context_is_being_destroyed(&idev->rnc); | ||
1425 | if (!destroyed) | ||
1426 | status = sci_remote_device_resume( | ||
1427 | idev, isci_remote_device_resume_from_abort_complete, | ||
1428 | idev); | ||
1429 | spin_unlock_irqrestore(&ihost->scic_lock, flags); | ||
1430 | if (!destroyed && (status == SCI_SUCCESS)) | ||
1431 | isci_remote_device_wait_for_resume_from_abort(ihost, idev); | ||
1432 | else | ||
1433 | clear_bit(IDEV_ABORT_PATH_RESUME_PENDING, &idev->flags); | ||
1434 | |||
1435 | return status; | ||
1436 | } | ||
1437 | |||
1196 | /** | 1438 | /** |
1197 | * sci_remote_device_start() - This method will start the supplied remote | 1439 | * sci_remote_device_start() - This method will start the supplied remote |
1198 | * device. This method enables normal IO requests to flow through to the | 1440 | * device. This method enables normal IO requests to flow through to the |
@@ -1207,7 +1449,7 @@ static enum sci_status sci_remote_device_ea_construct(struct isci_port *iport, | |||
1207 | * the device when there have been no phys added to it. | 1449 | * the device when there have been no phys added to it. |
1208 | */ | 1450 | */ |
1209 | static enum sci_status sci_remote_device_start(struct isci_remote_device *idev, | 1451 | static enum sci_status sci_remote_device_start(struct isci_remote_device *idev, |
1210 | u32 timeout) | 1452 | u32 timeout) |
1211 | { | 1453 | { |
1212 | struct sci_base_state_machine *sm = &idev->sm; | 1454 | struct sci_base_state_machine *sm = &idev->sm; |
1213 | enum sci_remote_device_states state = sm->current_state_id; | 1455 | enum sci_remote_device_states state = sm->current_state_id; |
@@ -1219,9 +1461,8 @@ static enum sci_status sci_remote_device_start(struct isci_remote_device *idev, | |||
1219 | return SCI_FAILURE_INVALID_STATE; | 1461 | return SCI_FAILURE_INVALID_STATE; |
1220 | } | 1462 | } |
1221 | 1463 | ||
1222 | status = sci_remote_node_context_resume(&idev->rnc, | 1464 | status = sci_remote_device_resume(idev, remote_device_resume_done, |
1223 | remote_device_resume_done, | 1465 | idev); |
1224 | idev); | ||
1225 | if (status != SCI_SUCCESS) | 1466 | if (status != SCI_SUCCESS) |
1226 | return status; | 1467 | return status; |
1227 | 1468 | ||
@@ -1259,20 +1500,6 @@ static enum sci_status isci_remote_device_construct(struct isci_port *iport, | |||
1259 | return status; | 1500 | return status; |
1260 | } | 1501 | } |
1261 | 1502 | ||
1262 | void isci_remote_device_nuke_requests(struct isci_host *ihost, struct isci_remote_device *idev) | ||
1263 | { | ||
1264 | DECLARE_COMPLETION_ONSTACK(aborted_task_completion); | ||
1265 | |||
1266 | dev_dbg(&ihost->pdev->dev, | ||
1267 | "%s: idev = %p\n", __func__, idev); | ||
1268 | |||
1269 | /* Cleanup all requests pending for this device. */ | ||
1270 | isci_terminate_pending_requests(ihost, idev); | ||
1271 | |||
1272 | dev_dbg(&ihost->pdev->dev, | ||
1273 | "%s: idev = %p, done\n", __func__, idev); | ||
1274 | } | ||
1275 | |||
1276 | /** | 1503 | /** |
1277 | * This function builds the isci_remote_device when a libsas dev_found message | 1504 | * This function builds the isci_remote_device when a libsas dev_found message |
1278 | * is received. | 1505 | * is received. |
@@ -1297,10 +1524,6 @@ isci_remote_device_alloc(struct isci_host *ihost, struct isci_port *iport) | |||
1297 | dev_warn(&ihost->pdev->dev, "%s: failed\n", __func__); | 1524 | dev_warn(&ihost->pdev->dev, "%s: failed\n", __func__); |
1298 | return NULL; | 1525 | return NULL; |
1299 | } | 1526 | } |
1300 | |||
1301 | if (WARN_ONCE(!list_empty(&idev->reqs_in_process), "found requests in process\n")) | ||
1302 | return NULL; | ||
1303 | |||
1304 | if (WARN_ONCE(!list_empty(&idev->node), "found non-idle remote device\n")) | 1527 | if (WARN_ONCE(!list_empty(&idev->node), "found non-idle remote device\n")) |
1305 | return NULL; | 1528 | return NULL; |
1306 | 1529 | ||
@@ -1342,14 +1565,8 @@ enum sci_status isci_remote_device_stop(struct isci_host *ihost, struct isci_rem | |||
1342 | spin_lock_irqsave(&ihost->scic_lock, flags); | 1565 | spin_lock_irqsave(&ihost->scic_lock, flags); |
1343 | idev->domain_dev->lldd_dev = NULL; /* disable new lookups */ | 1566 | idev->domain_dev->lldd_dev = NULL; /* disable new lookups */ |
1344 | set_bit(IDEV_GONE, &idev->flags); | 1567 | set_bit(IDEV_GONE, &idev->flags); |
1345 | spin_unlock_irqrestore(&ihost->scic_lock, flags); | ||
1346 | |||
1347 | /* Kill all outstanding requests. */ | ||
1348 | isci_remote_device_nuke_requests(ihost, idev); | ||
1349 | 1568 | ||
1350 | set_bit(IDEV_STOP_PENDING, &idev->flags); | 1569 | set_bit(IDEV_STOP_PENDING, &idev->flags); |
1351 | |||
1352 | spin_lock_irqsave(&ihost->scic_lock, flags); | ||
1353 | status = sci_remote_device_stop(idev, 50); | 1570 | status = sci_remote_device_stop(idev, 50); |
1354 | spin_unlock_irqrestore(&ihost->scic_lock, flags); | 1571 | spin_unlock_irqrestore(&ihost->scic_lock, flags); |
1355 | 1572 | ||
@@ -1359,6 +1576,9 @@ enum sci_status isci_remote_device_stop(struct isci_host *ihost, struct isci_rem | |||
1359 | else | 1576 | else |
1360 | wait_for_device_stop(ihost, idev); | 1577 | wait_for_device_stop(ihost, idev); |
1361 | 1578 | ||
1579 | dev_dbg(&ihost->pdev->dev, | ||
1580 | "%s: isci_device = %p, waiting done.\n", __func__, idev); | ||
1581 | |||
1362 | return status; | 1582 | return status; |
1363 | } | 1583 | } |
1364 | 1584 | ||
@@ -1434,3 +1654,73 @@ int isci_remote_device_found(struct domain_device *dev) | |||
1434 | 1654 | ||
1435 | return status == SCI_SUCCESS ? 0 : -ENODEV; | 1655 | return status == SCI_SUCCESS ? 0 : -ENODEV; |
1436 | } | 1656 | } |
1657 | |||
1658 | enum sci_status isci_remote_device_suspend_terminate( | ||
1659 | struct isci_host *ihost, | ||
1660 | struct isci_remote_device *idev, | ||
1661 | struct isci_request *ireq) | ||
1662 | { | ||
1663 | unsigned long flags; | ||
1664 | enum sci_status status; | ||
1665 | |||
1666 | /* Put the device into suspension. */ | ||
1667 | spin_lock_irqsave(&ihost->scic_lock, flags); | ||
1668 | set_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags); | ||
1669 | sci_remote_device_suspend(idev, SCI_SW_SUSPEND_LINKHANG_DETECT); | ||
1670 | spin_unlock_irqrestore(&ihost->scic_lock, flags); | ||
1671 | |||
1672 | /* Terminate and wait for the completions. */ | ||
1673 | status = isci_remote_device_terminate_requests(ihost, idev, ireq); | ||
1674 | if (status != SCI_SUCCESS) | ||
1675 | dev_dbg(&ihost->pdev->dev, | ||
1676 | "%s: isci_remote_device_terminate_requests(%p) " | ||
1677 | "returned %d!\n", | ||
1678 | __func__, idev, status); | ||
1679 | |||
1680 | /* NOTE: RNC resumption is left to the caller! */ | ||
1681 | return status; | ||
1682 | } | ||
1683 | |||
1684 | int isci_remote_device_is_safe_to_abort( | ||
1685 | struct isci_remote_device *idev) | ||
1686 | { | ||
1687 | return sci_remote_node_context_is_safe_to_abort(&idev->rnc); | ||
1688 | } | ||
1689 | |||
1690 | enum sci_status sci_remote_device_abort_requests_pending_abort( | ||
1691 | struct isci_remote_device *idev) | ||
1692 | { | ||
1693 | return sci_remote_device_terminate_reqs_checkabort(idev, 1); | ||
1694 | } | ||
1695 | |||
1696 | enum sci_status isci_remote_device_reset_complete( | ||
1697 | struct isci_host *ihost, | ||
1698 | struct isci_remote_device *idev) | ||
1699 | { | ||
1700 | unsigned long flags; | ||
1701 | enum sci_status status; | ||
1702 | |||
1703 | spin_lock_irqsave(&ihost->scic_lock, flags); | ||
1704 | status = sci_remote_device_reset_complete(idev); | ||
1705 | spin_unlock_irqrestore(&ihost->scic_lock, flags); | ||
1706 | |||
1707 | return status; | ||
1708 | } | ||
1709 | |||
1710 | void isci_dev_set_hang_detection_timeout( | ||
1711 | struct isci_remote_device *idev, | ||
1712 | u32 timeout) | ||
1713 | { | ||
1714 | if (dev_is_sata(idev->domain_dev)) { | ||
1715 | if (timeout) { | ||
1716 | if (test_and_set_bit(IDEV_RNC_LLHANG_ENABLED, | ||
1717 | &idev->flags)) | ||
1718 | return; /* Already enabled. */ | ||
1719 | } else if (!test_and_clear_bit(IDEV_RNC_LLHANG_ENABLED, | ||
1720 | &idev->flags)) | ||
1721 | return; /* Not enabled. */ | ||
1722 | |||
1723 | sci_port_set_hang_detection_timeout(idev->owning_port, | ||
1724 | timeout); | ||
1725 | } | ||
1726 | } | ||