aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorJeff Skirvin <jeffrey.d.skirvin@intel.com>2012-03-09 01:41:50 -0500
committerDan Williams <dan.j.williams@intel.com>2012-05-17 17:33:37 -0400
commit726980d56908f2e230624394f03743689db3110c (patch)
tree6aca898ea8f57c276088feb2eed5770fba6dfd86 /drivers/scsi
parentac78ed0f78eae5c3c918e132b5e2029cdc4fdedc (diff)
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>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/isci/host.c22
-rw-r--r--drivers/scsi/isci/remote_device.c106
-rw-r--r--drivers/scsi/isci/remote_device.h10
-rw-r--r--drivers/scsi/isci/remote_node_context.c56
-rw-r--r--drivers/scsi/isci/remote_node_context.h2
-rw-r--r--drivers/scsi/isci/request.c22
-rw-r--r--drivers/scsi/isci/request.h2
7 files changed, 188 insertions, 32 deletions
diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c
index 5832b13e7b07..d241b5722eb3 100644
--- a/drivers/scsi/isci/host.c
+++ b/drivers/scsi/isci/host.c
@@ -2696,18 +2696,18 @@ enum sci_status sci_controller_terminate_request(struct isci_host *ihost,
2696 __func__, ihost->sm.current_state_id); 2696 __func__, ihost->sm.current_state_id);
2697 return SCI_FAILURE_INVALID_STATE; 2697 return SCI_FAILURE_INVALID_STATE;
2698 } 2698 }
2699
2700 status = sci_io_request_terminate(ireq); 2699 status = sci_io_request_terminate(ireq);
2701 if (status != SCI_SUCCESS) 2700 if ((status == SCI_SUCCESS) &&
2702 return status; 2701 !test_bit(IREQ_PENDING_ABORT, &ireq->flags) &&
2703 2702 !test_and_set_bit(IREQ_TC_ABORT_POSTED, &ireq->flags)) {
2704 /* 2703 /* Utilize the original post context command and or in the
2705 * Utilize the original post context command and or in the POST_TC_ABORT 2704 * POST_TC_ABORT request sub-type.
2706 * request sub-type. 2705 */
2707 */ 2706 sci_controller_post_request(
2708 sci_controller_post_request(ihost, 2707 ihost, ireq->post_context |
2709 ireq->post_context | SCU_CONTEXT_COMMAND_REQUEST_POST_TC_ABORT); 2708 SCU_CONTEXT_COMMAND_REQUEST_POST_TC_ABORT);
2710 return SCI_SUCCESS; 2709 }
2710 return status;
2711} 2711}
2712 2712
2713/** 2713/**
diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c
index b1a8000a5ef8..9f03877534d2 100644
--- a/drivers/scsi/isci/remote_device.c
+++ b/drivers/scsi/isci/remote_device.c
@@ -133,6 +133,50 @@ static void isci_remote_device_ready(struct isci_host *ihost, struct isci_remote
133 wake_up(&ihost->eventq); 133 wake_up(&ihost->eventq);
134} 134}
135 135
136static 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
146enum 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/* called once the remote node context is ready to be freed. 180/* called once the remote node context is ready to be freed.
137 * The remote device can now report that its stop operation is complete. none 181 * The remote device can now report that its stop operation is complete. none
138 */ 182 */
@@ -144,7 +188,9 @@ static void rnc_destruct_done(void *_dev)
144 sci_change_state(&idev->sm, SCI_DEV_STOPPED); 188 sci_change_state(&idev->sm, SCI_DEV_STOPPED);
145} 189}
146 190
147static enum sci_status sci_remote_device_terminate_requests(struct isci_remote_device *idev) 191static enum sci_status sci_remote_device_terminate_requests_checkabort(
192 struct isci_remote_device *idev,
193 int check_abort_pending)
148{ 194{
149 struct isci_host *ihost = idev->owning_port->owning_controller; 195 struct isci_host *ihost = idev->owning_port->owning_controller;
150 enum sci_status status = SCI_SUCCESS; 196 enum sci_status status = SCI_SUCCESS;
@@ -155,7 +201,9 @@ static enum sci_status sci_remote_device_terminate_requests(struct isci_remote_d
155 enum sci_status s; 201 enum sci_status s;
156 202
157 if (!test_bit(IREQ_ACTIVE, &ireq->flags) || 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 continue; 207 continue;
160 208
161 s = sci_controller_terminate_request(ihost, idev, ireq); 209 s = sci_controller_terminate_request(ihost, idev, ireq);
@@ -166,6 +214,12 @@ static enum sci_status sci_remote_device_terminate_requests(struct isci_remote_d
166 return status; 214 return status;
167} 215}
168 216
217enum 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
169enum sci_status sci_remote_device_stop(struct isci_remote_device *idev, 223enum sci_status sci_remote_device_stop(struct isci_remote_device *idev,
170 u32 timeout) 224 u32 timeout)
171{ 225{
@@ -265,14 +319,6 @@ enum sci_status sci_remote_device_reset_complete(struct isci_remote_device *idev
265 return SCI_SUCCESS; 319 return SCI_SUCCESS;
266} 320}
267 321
268enum 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
276enum sci_status sci_remote_device_frame_handler(struct isci_remote_device *idev, 322enum sci_status sci_remote_device_frame_handler(struct isci_remote_device *idev,
277 u32 frame_index) 323 u32 frame_index)
278{ 324{
@@ -1186,7 +1232,7 @@ static enum sci_status sci_remote_device_ea_construct(struct isci_port *iport,
1186 * the device when there have been no phys added to it. 1232 * the device when there have been no phys added to it.
1187 */ 1233 */
1188static enum sci_status sci_remote_device_start(struct isci_remote_device *idev, 1234static enum sci_status sci_remote_device_start(struct isci_remote_device *idev,
1189 u32 timeout) 1235 u32 timeout)
1190{ 1236{
1191 struct sci_base_state_machine *sm = &idev->sm; 1237 struct sci_base_state_machine *sm = &idev->sm;
1192 enum sci_remote_device_states state = sm->current_state_id; 1238 enum sci_remote_device_states state = sm->current_state_id;
@@ -1413,3 +1459,41 @@ int isci_remote_device_found(struct domain_device *dev)
1413 1459
1414 return status == SCI_SUCCESS ? 0 : -ENODEV; 1460 return status == SCI_SUCCESS ? 0 : -ENODEV;
1415} 1461}
1462
1463enum 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
1489int 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
1495enum 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);
1499}
diff --git a/drivers/scsi/isci/remote_device.h b/drivers/scsi/isci/remote_device.h
index 39159053b7ff..ae508ee33664 100644
--- a/drivers/scsi/isci/remote_device.h
+++ b/drivers/scsi/isci/remote_device.h
@@ -85,6 +85,7 @@ struct isci_remote_device {
85 #define IDEV_GONE 3 85 #define IDEV_GONE 3
86 #define IDEV_IO_READY 4 86 #define IDEV_IO_READY 4
87 #define IDEV_IO_NCQERROR 5 87 #define IDEV_IO_NCQERROR 5
88 #define IDEV_TXRX_SUSPENDED 6
88 unsigned long flags; 89 unsigned long flags;
89 struct kref kref; 90 struct kref kref;
90 struct isci_port *isci_port; 91 struct isci_port *isci_port;
@@ -335,4 +336,13 @@ void sci_remote_device_post_request(
335 struct isci_remote_device *idev, 336 struct isci_remote_device *idev,
336 u32 request); 337 u32 request);
337 338
339enum sci_status sci_remote_device_terminate_requests(
340 struct isci_remote_device *idev);
341
342int isci_remote_device_is_safe_to_abort(
343 struct isci_remote_device *idev);
344
345enum sci_status
346sci_remote_device_abort_requests_pending_abort(
347 struct isci_remote_device *idev);
338#endif /* !defined(_ISCI_REMOTE_DEVICE_H_) */ 348#endif /* !defined(_ISCI_REMOTE_DEVICE_H_) */
diff --git a/drivers/scsi/isci/remote_node_context.c b/drivers/scsi/isci/remote_node_context.c
index f180c726c5bb..7a8347e51767 100644
--- a/drivers/scsi/isci/remote_node_context.c
+++ b/drivers/scsi/isci/remote_node_context.c
@@ -268,6 +268,8 @@ static void sci_remote_node_context_invalidating_state_enter(struct sci_base_sta
268{ 268{
269 struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm); 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 sci_remote_node_context_invalidate_context_buffer(rnc); 273 sci_remote_node_context_invalidate_context_buffer(rnc);
272} 274}
273 275
@@ -312,10 +314,28 @@ static void sci_remote_node_context_tx_suspended_state_enter(struct sci_base_sta
312static void sci_remote_node_context_tx_rx_suspended_state_enter(struct sci_base_state_machine *sm) 314static void sci_remote_node_context_tx_rx_suspended_state_enter(struct sci_base_state_machine *sm)
313{ 315{
314 struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm); 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;
319
320 set_bit(IDEV_TXRX_SUSPENDED, &idev->flags);
315 321
322 /* Terminate outstanding requests pending abort. */
323 sci_remote_device_abort_requests_pending_abort(idev);
324
325 wake_up(&ihost->eventq);
316 sci_remote_node_context_continue_state_transitions(rnc); 326 sci_remote_node_context_continue_state_transitions(rnc);
317} 327}
318 328
329static 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
319static void sci_remote_node_context_await_suspend_state_exit( 339static void sci_remote_node_context_await_suspend_state_exit(
320 struct sci_base_state_machine *sm) 340 struct sci_base_state_machine *sm)
321{ 341{
@@ -346,6 +366,8 @@ static const struct sci_base_state sci_remote_node_context_state_table[] = {
346 }, 366 },
347 [SCI_RNC_TX_RX_SUSPENDED] = { 367 [SCI_RNC_TX_RX_SUSPENDED] = {
348 .enter_state = sci_remote_node_context_tx_rx_suspended_state_enter, 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 [SCI_RNC_AWAIT_SUSPENSION] = { 372 [SCI_RNC_AWAIT_SUSPENSION] = {
351 .exit_state = sci_remote_node_context_await_suspend_state_exit, 373 .exit_state = sci_remote_node_context_await_suspend_state_exit,
@@ -515,6 +537,13 @@ enum sci_status sci_remote_node_context_suspend(
515 struct isci_remote_device *idev = rnc_to_dev(sci_rnc); 537 struct isci_remote_device *idev = rnc_to_dev(sci_rnc);
516 enum sci_status status = SCI_FAILURE_INVALID_STATE; 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 /* Disable automatic state continuations if explicitly suspending. */ 547 /* Disable automatic state continuations if explicitly suspending. */
519 if (suspend_reason == SCI_SOFTWARE_SUSPENSION) 548 if (suspend_reason == SCI_SOFTWARE_SUSPENSION)
520 sci_rnc->destination_state 549 sci_rnc->destination_state
@@ -546,7 +575,10 @@ enum sci_status sci_remote_node_context_suspend(
546 sci_rnc->suspend_type = suspend_type; 575 sci_rnc->suspend_type = suspend_type;
547 576
548 if (status == SCI_SUCCESS) { /* Already in the destination state? */ 577 if (status == SCI_SUCCESS) { /* Already in the destination state? */
578 struct isci_host *ihost = idev->owning_port->owning_controller;
579
549 sci_remote_node_context_notify_user(sci_rnc); 580 sci_remote_node_context_notify_user(sci_rnc);
581 wake_up_all(&ihost->eventq); /* Let observers look. */
550 return SCI_SUCCESS; 582 return SCI_SUCCESS;
551 } 583 }
552 if (suspend_reason == SCI_SOFTWARE_SUSPENSION) { 584 if (suspend_reason == SCI_SOFTWARE_SUSPENSION) {
@@ -661,3 +693,27 @@ enum sci_status sci_remote_node_context_start_task(struct sci_remote_node_contex
661 return SCI_FAILURE_INVALID_STATE; 693 return SCI_FAILURE_INVALID_STATE;
662 } 694 }
663} 695}
696
697int 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;
718 }
719}
diff --git a/drivers/scsi/isci/remote_node_context.h b/drivers/scsi/isci/remote_node_context.h
index 276fc491e8f9..5ddf88b53133 100644
--- a/drivers/scsi/isci/remote_node_context.h
+++ b/drivers/scsi/isci/remote_node_context.h
@@ -214,5 +214,7 @@ enum sci_status sci_remote_node_context_start_task(struct sci_remote_node_contex
214 struct isci_request *ireq); 214 struct isci_request *ireq);
215enum sci_status sci_remote_node_context_start_io(struct sci_remote_node_context *sci_rnc, 215enum sci_status sci_remote_node_context_start_io(struct sci_remote_node_context *sci_rnc,
216 struct isci_request *ireq); 216 struct isci_request *ireq);
217int sci_remote_node_context_is_safe_to_abort(
218 struct sci_remote_node_context *sci_rnc);
217 219
218#endif /* _SCIC_SDS_REMOTE_NODE_CONTEXT_H_ */ 220#endif /* _SCIC_SDS_REMOTE_NODE_CONTEXT_H_ */
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
index 605dc68cbf79..1f314d0d71d5 100644
--- a/drivers/scsi/isci/request.c
+++ b/drivers/scsi/isci/request.c
@@ -863,6 +863,8 @@ sci_io_request_terminate(struct isci_request *ireq)
863 863
864 switch (state) { 864 switch (state) {
865 case SCI_REQ_CONSTRUCTED: 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 ireq->scu_status = SCU_TASK_DONE_TASK_ABORT; 868 ireq->scu_status = SCU_TASK_DONE_TASK_ABORT;
867 ireq->sci_status = SCI_FAILURE_IO_TERMINATED; 869 ireq->sci_status = SCI_FAILURE_IO_TERMINATED;
868 sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); 870 sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
@@ -883,8 +885,7 @@ sci_io_request_terminate(struct isci_request *ireq)
883 case SCI_REQ_ATAPI_WAIT_PIO_SETUP: 885 case SCI_REQ_ATAPI_WAIT_PIO_SETUP:
884 case SCI_REQ_ATAPI_WAIT_D2H: 886 case SCI_REQ_ATAPI_WAIT_D2H:
885 case SCI_REQ_ATAPI_WAIT_TC_COMP: 887 case SCI_REQ_ATAPI_WAIT_TC_COMP:
886 sci_change_state(&ireq->sm, SCI_REQ_ABORTING); 888 /* Fall through and change state to ABORTING... */
887 return SCI_SUCCESS;
888 case SCI_REQ_TASK_WAIT_TC_RESP: 889 case SCI_REQ_TASK_WAIT_TC_RESP:
889 /* The task frame was already confirmed to have been 890 /* The task frame was already confirmed to have been
890 * sent by the SCU HW. Since the state machine is 891 * sent by the SCU HW. Since the state machine is
@@ -893,20 +894,21 @@ sci_io_request_terminate(struct isci_request *ireq)
893 * and don't wait for the task response. 894 * and don't wait for the task response.
894 */ 895 */
895 sci_change_state(&ireq->sm, SCI_REQ_ABORTING); 896 sci_change_state(&ireq->sm, SCI_REQ_ABORTING);
896 sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); 897 /* Fall through and handle like ABORTING... */
897 return SCI_SUCCESS;
898 case SCI_REQ_ABORTING: 898 case SCI_REQ_ABORTING:
899 /* If a request has a termination requested twice, return 899 if (!isci_remote_device_is_safe_to_abort(ireq->target_device))
900 * a failure indication, since HW confirmation of the first 900 set_bit(IREQ_PENDING_ABORT, &ireq->flags);
901 * abort is still outstanding. 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 case SCI_REQ_COMPLETED: 907 case SCI_REQ_COMPLETED:
904 default: 908 default:
905 dev_warn(&ireq->owning_controller->pdev->dev, 909 dev_warn(&ireq->owning_controller->pdev->dev,
906 "%s: SCIC IO Request requested to abort while in wrong " 910 "%s: SCIC IO Request requested to abort while in wrong "
907 "state %d\n", 911 "state %d\n", __func__, ireq->sm.current_state_id);
908 __func__,
909 ireq->sm.current_state_id);
910 break; 912 break;
911 } 913 }
912 914
diff --git a/drivers/scsi/isci/request.h b/drivers/scsi/isci/request.h
index e845a31ecebb..8d55f78010aa 100644
--- a/drivers/scsi/isci/request.h
+++ b/drivers/scsi/isci/request.h
@@ -102,6 +102,8 @@ struct isci_request {
102 #define IREQ_TERMINATED 1 102 #define IREQ_TERMINATED 1
103 #define IREQ_TMF 2 103 #define IREQ_TMF 2
104 #define IREQ_ACTIVE 3 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 unsigned long flags; 107 unsigned long flags;
106 /* XXX kill ttype and ttype_ptr, allocate full sas_task */ 108 /* XXX kill ttype and ttype_ptr, allocate full sas_task */
107 union ttype_ptr_union { 109 union ttype_ptr_union {