Commit 726980d56908f2e230624394f03743689db3110c

Authored by Jeff Skirvin
Committed by Dan Williams
1 parent ac78ed0f78

isci: Terminate outstanding TCs on TX/RX RNC suspensions.

TCs must only be terminated when RNCs are suspended.

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>

Showing 7 changed files with 188 additions and 32 deletions Side-by-side Diff

drivers/scsi/isci/host.c
... ... @@ -2696,18 +2696,18 @@
2696 2696 __func__, ihost->sm.current_state_id);
2697 2697 return SCI_FAILURE_INVALID_STATE;
2698 2698 }
2699   -
2700 2699 status = sci_io_request_terminate(ireq);
2701   - if (status != SCI_SUCCESS)
2702   - return status;
2703   -
2704   - /*
2705   - * Utilize the original post context command and or in the POST_TC_ABORT
2706   - * request sub-type.
2707   - */
2708   - sci_controller_post_request(ihost,
2709   - ireq->post_context | SCU_CONTEXT_COMMAND_REQUEST_POST_TC_ABORT);
2710   - return SCI_SUCCESS;
  2700 + if ((status == SCI_SUCCESS) &&
  2701 + !test_bit(IREQ_PENDING_ABORT, &ireq->flags) &&
  2702 + !test_and_set_bit(IREQ_TC_ABORT_POSTED, &ireq->flags)) {
  2703 + /* Utilize the original post context command and or in the
  2704 + * POST_TC_ABORT request sub-type.
  2705 + */
  2706 + sci_controller_post_request(
  2707 + ihost, ireq->post_context |
  2708 + SCU_CONTEXT_COMMAND_REQUEST_POST_TC_ABORT);
  2709 + }
  2710 + return status;
2711 2711 }
2712 2712  
2713 2713 /**
drivers/scsi/isci/remote_device.c
... ... @@ -133,6 +133,50 @@
133 133 wake_up(&ihost->eventq);
134 134 }
135 135  
  136 +static enum sci_status sci_remote_device_suspend(
  137 + struct isci_remote_device *idev)
  138 +{
  139 + return sci_remote_node_context_suspend(
  140 + &idev->rnc,
  141 + SCI_SOFTWARE_SUSPENSION,
  142 + SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT,
  143 + NULL, NULL);
  144 +}
  145 +
  146 +enum sci_status isci_remote_device_suspend(
  147 + struct isci_host *ihost,
  148 + struct isci_remote_device *idev)
  149 +{
  150 + enum sci_status status;
  151 + unsigned long flags;
  152 +
  153 + spin_lock_irqsave(&ihost->scic_lock, flags);
  154 +
  155 + if (isci_lookup_device(idev->domain_dev) == NULL) {
  156 + spin_unlock_irqrestore(&ihost->scic_lock, flags);
  157 + status = SCI_FAILURE;
  158 + } else {
  159 + status = sci_remote_device_suspend(idev);
  160 + spin_unlock_irqrestore(&ihost->scic_lock, flags);
  161 + if (status == SCI_SUCCESS) {
  162 + wait_event(ihost->eventq,
  163 + test_bit(IDEV_TXRX_SUSPENDED, &idev->flags)
  164 + || !test_bit(IDEV_ALLOCATED, &idev->flags));
  165 +
  166 + status = test_bit(IDEV_TXRX_SUSPENDED, &idev->flags)
  167 + ? SCI_SUCCESS : SCI_FAILURE;
  168 + dev_dbg(&ihost->pdev->dev,
  169 + "%s: idev=%p, wait done, device is %s\n",
  170 + __func__, idev,
  171 + test_bit(IDEV_TXRX_SUSPENDED, &idev->flags)
  172 + ? "<suspended>" : "<deallocated!>");
  173 +
  174 + }
  175 + isci_put_device(idev);
  176 + }
  177 + return status;
  178 +}
  179 +
136 180 /* called once the remote node context is ready to be freed.
137 181 * The remote device can now report that its stop operation is complete. none
138 182 */
... ... @@ -144,7 +188,9 @@
144 188 sci_change_state(&idev->sm, SCI_DEV_STOPPED);
145 189 }
146 190  
147   -static enum sci_status sci_remote_device_terminate_requests(struct isci_remote_device *idev)
  191 +static enum sci_status sci_remote_device_terminate_requests_checkabort(
  192 + struct isci_remote_device *idev,
  193 + int check_abort_pending)
148 194 {
149 195 struct isci_host *ihost = idev->owning_port->owning_controller;
150 196 enum sci_status status = SCI_SUCCESS;
... ... @@ -155,7 +201,9 @@
155 201 enum sci_status s;
156 202  
157 203 if (!test_bit(IREQ_ACTIVE, &ireq->flags) ||
158   - ireq->target_device != idev)
  204 + (ireq->target_device != idev) ||
  205 + (check_abort_pending && !test_bit(IREQ_PENDING_ABORT,
  206 + &ireq->flags)))
159 207 continue;
160 208  
161 209 s = sci_controller_terminate_request(ihost, idev, ireq);
... ... @@ -166,6 +214,12 @@
166 214 return status;
167 215 }
168 216  
  217 +enum sci_status sci_remote_device_terminate_requests(
  218 + struct isci_remote_device *idev)
  219 +{
  220 + return sci_remote_device_terminate_requests_checkabort(idev, 0);
  221 +}
  222 +
169 223 enum sci_status sci_remote_device_stop(struct isci_remote_device *idev,
170 224 u32 timeout)
171 225 {
... ... @@ -265,14 +319,6 @@
265 319 return SCI_SUCCESS;
266 320 }
267 321  
268   -enum sci_status sci_remote_device_suspend(struct isci_remote_device *idev)
269   -{
270   - return sci_remote_node_context_suspend(&idev->rnc,
271   - SCI_SOFTWARE_SUSPENSION,
272   - SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT,
273   - NULL, NULL);
274   -}
275   -
276 322 enum sci_status sci_remote_device_frame_handler(struct isci_remote_device *idev,
277 323 u32 frame_index)
278 324 {
... ... @@ -1186,7 +1232,7 @@
1186 1232 * the device when there have been no phys added to it.
1187 1233 */
1188 1234 static enum sci_status sci_remote_device_start(struct isci_remote_device *idev,
1189   - u32 timeout)
  1235 + u32 timeout)
1190 1236 {
1191 1237 struct sci_base_state_machine *sm = &idev->sm;
1192 1238 enum sci_remote_device_states state = sm->current_state_id;
... ... @@ -1412,5 +1458,43 @@
1412 1458 wait_for_device_start(isci_host, isci_device);
1413 1459  
1414 1460 return status == SCI_SUCCESS ? 0 : -ENODEV;
  1461 +}
  1462 +
  1463 +enum sci_status isci_remote_device_reset(
  1464 + struct isci_remote_device *idev)
  1465 +{
  1466 + struct isci_host *ihost = dev_to_ihost(idev->domain_dev);
  1467 + unsigned long flags;
  1468 + enum sci_status status;
  1469 +
  1470 + /* Wait for the device suspend. */
  1471 + status = isci_remote_device_suspend(ihost, idev);
  1472 + if (status != SCI_SUCCESS) {
  1473 + dev_dbg(&ihost->pdev->dev,
  1474 + "%s: isci_remote_device_suspend(%p) returned %d!\n",
  1475 + __func__, idev, status);
  1476 + return status;
  1477 + }
  1478 + spin_lock_irqsave(&ihost->scic_lock, flags);
  1479 + status = sci_remote_device_reset(idev);
  1480 + spin_unlock_irqrestore(&ihost->scic_lock, flags);
  1481 + if (status != SCI_SUCCESS) {
  1482 + dev_dbg(&ihost->pdev->dev,
  1483 + "%s: sci_remote_device_reset(%p) returned %d!\n",
  1484 + __func__, idev, status);
  1485 + }
  1486 + return status;
  1487 +}
  1488 +
  1489 +int isci_remote_device_is_safe_to_abort(
  1490 + struct isci_remote_device *idev)
  1491 +{
  1492 + return sci_remote_node_context_is_safe_to_abort(&idev->rnc);
  1493 +}
  1494 +
  1495 +enum sci_status sci_remote_device_abort_requests_pending_abort(
  1496 + struct isci_remote_device *idev)
  1497 +{
  1498 + return sci_remote_device_terminate_requests_checkabort(idev, 1);
1415 1499 }
drivers/scsi/isci/remote_device.h
... ... @@ -85,6 +85,7 @@
85 85 #define IDEV_GONE 3
86 86 #define IDEV_IO_READY 4
87 87 #define IDEV_IO_NCQERROR 5
  88 + #define IDEV_TXRX_SUSPENDED 6
88 89 unsigned long flags;
89 90 struct kref kref;
90 91 struct isci_port *isci_port;
... ... @@ -335,5 +336,14 @@
335 336 struct isci_remote_device *idev,
336 337 u32 request);
337 338  
  339 +enum sci_status sci_remote_device_terminate_requests(
  340 + struct isci_remote_device *idev);
  341 +
  342 +int isci_remote_device_is_safe_to_abort(
  343 + struct isci_remote_device *idev);
  344 +
  345 +enum sci_status
  346 +sci_remote_device_abort_requests_pending_abort(
  347 + struct isci_remote_device *idev);
338 348 #endif /* !defined(_ISCI_REMOTE_DEVICE_H_) */
drivers/scsi/isci/remote_node_context.c
... ... @@ -268,6 +268,8 @@
268 268 {
269 269 struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm);
270 270  
  271 + /* Terminate outstanding requests pending abort. */
  272 + sci_remote_device_abort_requests_pending_abort(rnc_to_dev(rnc));
271 273 sci_remote_node_context_invalidate_context_buffer(rnc);
272 274 }
273 275  
274 276  
275 277  
... ... @@ -312,10 +314,28 @@
312 314 static void sci_remote_node_context_tx_rx_suspended_state_enter(struct sci_base_state_machine *sm)
313 315 {
314 316 struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm);
  317 + struct isci_remote_device *idev = rnc_to_dev(rnc);
  318 + struct isci_host *ihost = idev->owning_port->owning_controller;
315 319  
  320 + set_bit(IDEV_TXRX_SUSPENDED, &idev->flags);
  321 +
  322 + /* Terminate outstanding requests pending abort. */
  323 + sci_remote_device_abort_requests_pending_abort(idev);
  324 +
  325 + wake_up(&ihost->eventq);
316 326 sci_remote_node_context_continue_state_transitions(rnc);
317 327 }
318 328  
  329 +static void sci_remote_node_context_tx_rx_suspended_state_exit(
  330 + struct sci_base_state_machine *sm)
  331 +{
  332 + struct sci_remote_node_context *rnc
  333 + = container_of(sm, typeof(*rnc), sm);
  334 + struct isci_remote_device *idev = rnc_to_dev(rnc);
  335 +
  336 + clear_bit(IDEV_TXRX_SUSPENDED, &idev->flags);
  337 +}
  338 +
319 339 static void sci_remote_node_context_await_suspend_state_exit(
320 340 struct sci_base_state_machine *sm)
321 341 {
... ... @@ -346,6 +366,8 @@
346 366 },
347 367 [SCI_RNC_TX_RX_SUSPENDED] = {
348 368 .enter_state = sci_remote_node_context_tx_rx_suspended_state_enter,
  369 + .exit_state
  370 + = sci_remote_node_context_tx_rx_suspended_state_exit,
349 371 },
350 372 [SCI_RNC_AWAIT_SUSPENSION] = {
351 373 .exit_state = sci_remote_node_context_await_suspend_state_exit,
... ... @@ -515,6 +537,13 @@
515 537 struct isci_remote_device *idev = rnc_to_dev(sci_rnc);
516 538 enum sci_status status = SCI_FAILURE_INVALID_STATE;
517 539  
  540 + dev_dbg(scirdev_to_dev(idev),
  541 + "%s: current state %d, current suspend_type %x dest state %d,"
  542 + " arg suspend_reason %d, arg suspend_type %x",
  543 + __func__, state, sci_rnc->suspend_type,
  544 + sci_rnc->destination_state, suspend_reason,
  545 + suspend_type);
  546 +
518 547 /* Disable automatic state continuations if explicitly suspending. */
519 548 if (suspend_reason == SCI_SOFTWARE_SUSPENSION)
520 549 sci_rnc->destination_state
521 550  
... ... @@ -546,7 +575,10 @@
546 575 sci_rnc->suspend_type = suspend_type;
547 576  
548 577 if (status == SCI_SUCCESS) { /* Already in the destination state? */
  578 + struct isci_host *ihost = idev->owning_port->owning_controller;
  579 +
549 580 sci_remote_node_context_notify_user(sci_rnc);
  581 + wake_up_all(&ihost->eventq); /* Let observers look. */
550 582 return SCI_SUCCESS;
551 583 }
552 584 if (suspend_reason == SCI_SOFTWARE_SUSPENSION) {
... ... @@ -659,6 +691,30 @@
659 691 "%s: invalid state %s\n", __func__,
660 692 rnc_state_name(state));
661 693 return SCI_FAILURE_INVALID_STATE;
  694 + }
  695 +}
  696 +
  697 +int sci_remote_node_context_is_safe_to_abort(
  698 + struct sci_remote_node_context *sci_rnc)
  699 +{
  700 + enum scis_sds_remote_node_context_states state;
  701 +
  702 + state = sci_rnc->sm.current_state_id;
  703 + switch (state) {
  704 + case SCI_RNC_INVALIDATING:
  705 + case SCI_RNC_TX_RX_SUSPENDED:
  706 + return 1;
  707 + case SCI_RNC_POSTING:
  708 + case SCI_RNC_RESUMING:
  709 + case SCI_RNC_READY:
  710 + case SCI_RNC_TX_SUSPENDED:
  711 + case SCI_RNC_AWAIT_SUSPENSION:
  712 + case SCI_RNC_INITIAL:
  713 + return 0;
  714 + default:
  715 + dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
  716 + "%s: invalid state %d\n", __func__, state);
  717 + return 0;
662 718 }
663 719 }
drivers/scsi/isci/remote_node_context.h
... ... @@ -214,6 +214,8 @@
214 214 struct isci_request *ireq);
215 215 enum sci_status sci_remote_node_context_start_io(struct sci_remote_node_context *sci_rnc,
216 216 struct isci_request *ireq);
  217 +int sci_remote_node_context_is_safe_to_abort(
  218 + struct sci_remote_node_context *sci_rnc);
217 219  
218 220 #endif /* _SCIC_SDS_REMOTE_NODE_CONTEXT_H_ */
drivers/scsi/isci/request.c
... ... @@ -863,6 +863,8 @@
863 863  
864 864 switch (state) {
865 865 case SCI_REQ_CONSTRUCTED:
  866 + /* Set to make sure no HW terminate posting is done: */
  867 + set_bit(IREQ_TC_ABORT_POSTED, &ireq->flags);
866 868 ireq->scu_status = SCU_TASK_DONE_TASK_ABORT;
867 869 ireq->sci_status = SCI_FAILURE_IO_TERMINATED;
868 870 sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
... ... @@ -883,8 +885,7 @@
883 885 case SCI_REQ_ATAPI_WAIT_PIO_SETUP:
884 886 case SCI_REQ_ATAPI_WAIT_D2H:
885 887 case SCI_REQ_ATAPI_WAIT_TC_COMP:
886   - sci_change_state(&ireq->sm, SCI_REQ_ABORTING);
887   - return SCI_SUCCESS;
  888 + /* Fall through and change state to ABORTING... */
888 889 case SCI_REQ_TASK_WAIT_TC_RESP:
889 890 /* The task frame was already confirmed to have been
890 891 * sent by the SCU HW. Since the state machine is
891 892  
892 893  
893 894  
... ... @@ -893,20 +894,21 @@
893 894 * and don't wait for the task response.
894 895 */
895 896 sci_change_state(&ireq->sm, SCI_REQ_ABORTING);
896   - sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
897   - return SCI_SUCCESS;
  897 + /* Fall through and handle like ABORTING... */
898 898 case SCI_REQ_ABORTING:
899   - /* If a request has a termination requested twice, return
900   - * a failure indication, since HW confirmation of the first
901   - * abort is still outstanding.
  899 + if (!isci_remote_device_is_safe_to_abort(ireq->target_device))
  900 + set_bit(IREQ_PENDING_ABORT, &ireq->flags);
  901 + else
  902 + clear_bit(IREQ_PENDING_ABORT, &ireq->flags);
  903 + /* If the request is only waiting on the remote device
  904 + * suspension, return SUCCESS so the caller will wait too.
902 905 */
  906 + return SCI_SUCCESS;
903 907 case SCI_REQ_COMPLETED:
904 908 default:
905 909 dev_warn(&ireq->owning_controller->pdev->dev,
906 910 "%s: SCIC IO Request requested to abort while in wrong "
907   - "state %d\n",
908   - __func__,
909   - ireq->sm.current_state_id);
  911 + "state %d\n", __func__, ireq->sm.current_state_id);
910 912 break;
911 913 }
912 914  
drivers/scsi/isci/request.h
... ... @@ -102,6 +102,8 @@
102 102 #define IREQ_TERMINATED 1
103 103 #define IREQ_TMF 2
104 104 #define IREQ_ACTIVE 3
  105 + #define IREQ_PENDING_ABORT 4 /* Set == device was not suspended yet */
  106 + #define IREQ_TC_ABORT_POSTED 5
105 107 unsigned long flags;
106 108 /* XXX kill ttype and ttype_ptr, allocate full sas_task */
107 109 union ttype_ptr_union {