aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Skirvin <jeffrey.d.skirvin@intel.com>2012-03-09 01:41:54 -0500
committerDan Williams <dan.j.williams@intel.com>2012-05-17 17:33:39 -0400
commit59e35396436c564b5019e1a70073900bc3e19f4f (patch)
tree0bfa36c98fede19f78f136e92c2fd6bb2932051e
parent14aaa9f0a318bd04cbb9d822524b817e95d8b343 (diff)
isci: Add suspension cases for RNC INVALIDATING, POSTING states.
The RNC can be any of the states in the loop from suspended to ready when the API "suspend" or "resume" are called. This change adds destination states parameters that control the suspension / resumption action of the RNC statemachine for those transition states. Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
-rw-r--r--drivers/scsi/isci/port.c11
-rw-r--r--drivers/scsi/isci/remote_device.c2
-rw-r--r--drivers/scsi/isci/remote_node_context.c145
-rw-r--r--drivers/scsi/isci/remote_node_context.h10
4 files changed, 105 insertions, 63 deletions
diff --git a/drivers/scsi/isci/port.c b/drivers/scsi/isci/port.c
index ed206c5a00a6..f1866b0dc195 100644
--- a/drivers/scsi/isci/port.c
+++ b/drivers/scsi/isci/port.c
@@ -1688,17 +1688,6 @@ int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *ipor
1688 __func__, iport, status); 1688 __func__, iport, status);
1689 1689
1690 } 1690 }
1691
1692 /* If the hard reset for the port has failed, consider this
1693 * the same as link failures on all phys in the port.
1694 */
1695 if (ret != TMF_RESP_FUNC_COMPLETE) {
1696
1697 dev_err(&ihost->pdev->dev,
1698 "%s: iport = %p; hard reset failed "
1699 "(0x%x) - driving explicit link fail for all phys\n",
1700 __func__, iport, iport->hard_reset_status);
1701 }
1702 return ret; 1691 return ret;
1703} 1692}
1704 1693
diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c
index c47304cea45d..cf5d554e5056 100644
--- a/drivers/scsi/isci/remote_device.c
+++ b/drivers/scsi/isci/remote_device.c
@@ -192,7 +192,7 @@ static void isci_remote_device_not_ready(struct isci_host *ihost,
192 u32 reason) 192 u32 reason)
193{ 193{
194 dev_dbg(&ihost->pdev->dev, 194 dev_dbg(&ihost->pdev->dev,
195 "%s: isci_device = %p\n", __func__, idev); 195 "%s: isci_device = %p; reason = %d\n", __func__, idev, reason);
196 196
197 switch (reason) { 197 switch (reason) {
198 case SCIC_REMOTE_DEVICE_NOT_READY_STOP_REQUESTED: 198 case SCIC_REMOTE_DEVICE_NOT_READY_STOP_REQUESTED:
diff --git a/drivers/scsi/isci/remote_node_context.c b/drivers/scsi/isci/remote_node_context.c
index feeca17f0f13..75cf043e2adf 100644
--- a/drivers/scsi/isci/remote_node_context.c
+++ b/drivers/scsi/isci/remote_node_context.c
@@ -165,21 +165,24 @@ static void sci_remote_node_context_construct_buffer(struct sci_remote_node_cont
165static void sci_remote_node_context_setup_to_resume( 165static void sci_remote_node_context_setup_to_resume(
166 struct sci_remote_node_context *sci_rnc, 166 struct sci_remote_node_context *sci_rnc,
167 scics_sds_remote_node_context_callback callback, 167 scics_sds_remote_node_context_callback callback,
168 void *callback_parameter) 168 void *callback_parameter,
169 enum sci_remote_node_context_destination_state dest_param)
169{ 170{
170 if (sci_rnc->destination_state != SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_FINAL) { 171 if (sci_rnc->destination_state != RNC_DEST_FINAL) {
171 sci_rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_READY; 172 sci_rnc->destination_state = dest_param;
172 sci_rnc->user_callback = callback; 173 if (callback != NULL) {
173 sci_rnc->user_cookie = callback_parameter; 174 sci_rnc->user_callback = callback;
175 sci_rnc->user_cookie = callback_parameter;
176 }
174 } 177 }
175} 178}
176 179
177static void sci_remote_node_context_setup_to_destory( 180static void sci_remote_node_context_setup_to_destroy(
178 struct sci_remote_node_context *sci_rnc, 181 struct sci_remote_node_context *sci_rnc,
179 scics_sds_remote_node_context_callback callback, 182 scics_sds_remote_node_context_callback callback,
180 void *callback_parameter) 183 void *callback_parameter)
181{ 184{
182 sci_rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_FINAL; 185 sci_rnc->destination_state = RNC_DEST_FINAL;
183 sci_rnc->user_callback = callback; 186 sci_rnc->user_callback = callback;
184 sci_rnc->user_cookie = callback_parameter; 187 sci_rnc->user_cookie = callback_parameter;
185} 188}
@@ -203,9 +206,13 @@ static void sci_remote_node_context_notify_user(
203 206
204static void sci_remote_node_context_continue_state_transitions(struct sci_remote_node_context *rnc) 207static void sci_remote_node_context_continue_state_transitions(struct sci_remote_node_context *rnc)
205{ 208{
206 if (rnc->destination_state == SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_READY) 209 if ((rnc->destination_state == RNC_DEST_READY) ||
210 (rnc->destination_state == RNC_DEST_SUSPENDED_RESUME)) {
211 rnc->destination_state = RNC_DEST_READY;
207 sci_remote_node_context_resume(rnc, rnc->user_callback, 212 sci_remote_node_context_resume(rnc, rnc->user_callback,
208 rnc->user_cookie); 213 rnc->user_cookie);
214 } else
215 rnc->destination_state = RNC_DEST_UNSPECIFIED;
209} 216}
210 217
211static void sci_remote_node_context_validate_context_buffer(struct sci_remote_node_context *sci_rnc) 218static void sci_remote_node_context_validate_context_buffer(struct sci_remote_node_context *sci_rnc)
@@ -252,7 +259,7 @@ static void sci_remote_node_context_initial_state_enter(struct sci_base_state_ma
252 * someone requested to destroy the remote node context object. 259 * someone requested to destroy the remote node context object.
253 */ 260 */
254 if (sm->previous_state_id == SCI_RNC_INVALIDATING) { 261 if (sm->previous_state_id == SCI_RNC_INVALIDATING) {
255 rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_UNSPECIFIED; 262 rnc->destination_state = RNC_DEST_UNSPECIFIED;
256 sci_remote_node_context_notify_user(rnc); 263 sci_remote_node_context_notify_user(rnc);
257 } 264 }
258} 265}
@@ -297,10 +304,26 @@ static void sci_remote_node_context_resuming_state_enter(struct sci_base_state_m
297static void sci_remote_node_context_ready_state_enter(struct sci_base_state_machine *sm) 304static void sci_remote_node_context_ready_state_enter(struct sci_base_state_machine *sm)
298{ 305{
299 struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm); 306 struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm);
300 307 enum sci_remote_node_context_destination_state dest_select;
301 rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_UNSPECIFIED; 308 scics_sds_remote_node_context_callback usr_cb = rnc->user_callback;
302 309 void *usr_param = rnc->user_cookie;
303 if (rnc->user_callback) 310 int tell_user = 1;
311
312 dest_select = rnc->destination_state;
313 rnc->destination_state = RNC_DEST_UNSPECIFIED;
314
315 if ((dest_select == RNC_DEST_SUSPENDED) ||
316 (dest_select == RNC_DEST_SUSPENDED_RESUME)) {
317 sci_remote_node_context_suspend(
318 rnc, SCI_SOFTWARE_SUSPENSION,
319 SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT, NULL, NULL);
320
321 if (dest_select == RNC_DEST_SUSPENDED_RESUME) {
322 sci_remote_node_context_resume(rnc, usr_cb, usr_param);
323 tell_user = 0; /* Wait until ready again. */
324 }
325 }
326 if (tell_user && rnc->user_callback)
304 sci_remote_node_context_notify_user(rnc); 327 sci_remote_node_context_notify_user(rnc);
305} 328}
306 329
@@ -366,7 +389,7 @@ void sci_remote_node_context_construct(struct sci_remote_node_context *rnc,
366 memset(rnc, 0, sizeof(struct sci_remote_node_context)); 389 memset(rnc, 0, sizeof(struct sci_remote_node_context));
367 390
368 rnc->remote_node_index = remote_node_index; 391 rnc->remote_node_index = remote_node_index;
369 rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_UNSPECIFIED; 392 rnc->destination_state = RNC_DEST_UNSPECIFIED;
370 393
371 sci_init_sm(&rnc->sm, sci_remote_node_context_state_table, SCI_RNC_INITIAL); 394 sci_init_sm(&rnc->sm, sci_remote_node_context_state_table, SCI_RNC_INITIAL);
372} 395}
@@ -390,11 +413,11 @@ enum sci_status sci_remote_node_context_event_handler(struct sci_remote_node_con
390 break; 413 break;
391 case SCI_RNC_INVALIDATING: 414 case SCI_RNC_INVALIDATING:
392 if (scu_get_event_code(event_code) == SCU_EVENT_POST_RNC_INVALIDATE_COMPLETE) { 415 if (scu_get_event_code(event_code) == SCU_EVENT_POST_RNC_INVALIDATE_COMPLETE) {
393 if (sci_rnc->destination_state == SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_FINAL) 416 if (sci_rnc->destination_state == RNC_DEST_FINAL)
394 state = SCI_RNC_INITIAL; 417 next_state = SCI_RNC_INITIAL;
395 else 418 else
396 state = SCI_RNC_POSTING; 419 next_state = SCI_RNC_POSTING;
397 sci_change_state(&sci_rnc->sm, state); 420 sci_change_state(&sci_rnc->sm, next_state);
398 } else { 421 } else {
399 switch (scu_get_event_type(event_code)) { 422 switch (scu_get_event_type(event_code)) {
400 case SCU_EVENT_TYPE_RNC_SUSPEND_TX: 423 case SCU_EVENT_TYPE_RNC_SUSPEND_TX:
@@ -483,7 +506,7 @@ enum sci_status sci_remote_node_context_destruct(struct sci_remote_node_context
483 state = sci_rnc->sm.current_state_id; 506 state = sci_rnc->sm.current_state_id;
484 switch (state) { 507 switch (state) {
485 case SCI_RNC_INVALIDATING: 508 case SCI_RNC_INVALIDATING:
486 sci_remote_node_context_setup_to_destory(sci_rnc, cb_fn, cb_p); 509 sci_remote_node_context_setup_to_destroy(sci_rnc, cb_fn, cb_p);
487 return SCI_SUCCESS; 510 return SCI_SUCCESS;
488 case SCI_RNC_POSTING: 511 case SCI_RNC_POSTING:
489 case SCI_RNC_RESUMING: 512 case SCI_RNC_RESUMING:
@@ -491,7 +514,7 @@ enum sci_status sci_remote_node_context_destruct(struct sci_remote_node_context
491 case SCI_RNC_TX_SUSPENDED: 514 case SCI_RNC_TX_SUSPENDED:
492 case SCI_RNC_TX_RX_SUSPENDED: 515 case SCI_RNC_TX_RX_SUSPENDED:
493 case SCI_RNC_AWAIT_SUSPENSION: 516 case SCI_RNC_AWAIT_SUSPENSION:
494 sci_remote_node_context_setup_to_destory(sci_rnc, cb_fn, cb_p); 517 sci_remote_node_context_setup_to_destroy(sci_rnc, cb_fn, cb_p);
495 sci_change_state(&sci_rnc->sm, SCI_RNC_INVALIDATING); 518 sci_change_state(&sci_rnc->sm, SCI_RNC_INVALIDATING);
496 return SCI_SUCCESS; 519 return SCI_SUCCESS;
497 case SCI_RNC_INITIAL: 520 case SCI_RNC_INITIAL:
@@ -522,6 +545,8 @@ enum sci_status sci_remote_node_context_suspend(
522 = sci_rnc->sm.current_state_id; 545 = sci_rnc->sm.current_state_id;
523 struct isci_remote_device *idev = rnc_to_dev(sci_rnc); 546 struct isci_remote_device *idev = rnc_to_dev(sci_rnc);
524 enum sci_status status = SCI_FAILURE_INVALID_STATE; 547 enum sci_status status = SCI_FAILURE_INVALID_STATE;
548 enum sci_remote_node_context_destination_state dest_param =
549 RNC_DEST_UNSPECIFIED;
525 550
526 dev_dbg(scirdev_to_dev(idev), 551 dev_dbg(scirdev_to_dev(idev),
527 "%s: current state %d, current suspend_type %x dest state %d," 552 "%s: current state %d, current suspend_type %x dest state %d,"
@@ -531,12 +556,31 @@ enum sci_status sci_remote_node_context_suspend(
531 suspend_type); 556 suspend_type);
532 557
533 /* Disable automatic state continuations if explicitly suspending. */ 558 /* Disable automatic state continuations if explicitly suspending. */
534 if (suspend_reason == SCI_SOFTWARE_SUSPENSION) 559 if ((suspend_reason != SCI_SOFTWARE_SUSPENSION) ||
535 sci_rnc->destination_state 560 (sci_rnc->destination_state == RNC_DEST_FINAL))
536 = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_UNSPECIFIED; 561 dest_param = sci_rnc->destination_state;
562
537 switch (state) { 563 switch (state) {
564 case SCI_RNC_RESUMING:
565 break; /* The RNC has been posted, so start the suspend. */
538 case SCI_RNC_READY: 566 case SCI_RNC_READY:
539 break; 567 break;
568 case SCI_RNC_INVALIDATING:
569 if (sci_rnc->destination_state == RNC_DEST_FINAL) {
570 dev_warn(scirdev_to_dev(idev),
571 "%s: already destroying %p\n",
572 __func__, sci_rnc);
573 return SCI_FAILURE_INVALID_STATE;
574 }
575 /* Fall through and handle like SCI_RNC_POSTING */
576 case SCI_RNC_POSTING:
577 /* Set the destination state to AWAIT - this signals the
578 * entry into the SCI_RNC_READY state that a suspension
579 * needs to be done immediately.
580 */
581 sci_rnc->destination_state = RNC_DEST_SUSPENDED;
582 return SCI_SUCCESS;
583
540 case SCI_RNC_TX_SUSPENDED: 584 case SCI_RNC_TX_SUSPENDED:
541 if (suspend_type == SCU_EVENT_TL_RNC_SUSPEND_TX) 585 if (suspend_type == SCU_EVENT_TL_RNC_SUSPEND_TX)
542 status = SCI_SUCCESS; 586 status = SCI_SUCCESS;
@@ -556,6 +600,7 @@ enum sci_status sci_remote_node_context_suspend(
556 rnc_state_name(state)); 600 rnc_state_name(state));
557 return SCI_FAILURE_INVALID_STATE; 601 return SCI_FAILURE_INVALID_STATE;
558 } 602 }
603 sci_rnc->destination_state = dest_param;
559 sci_rnc->user_callback = cb_fn; 604 sci_rnc->user_callback = cb_fn;
560 sci_rnc->user_cookie = cb_p; 605 sci_rnc->user_cookie = cb_p;
561 sci_rnc->suspend_type = suspend_type; 606 sci_rnc->suspend_type = suspend_type;
@@ -590,18 +635,31 @@ enum sci_status sci_remote_node_context_resume(struct sci_remote_node_context *s
590 if (sci_rnc->remote_node_index == SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX) 635 if (sci_rnc->remote_node_index == SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX)
591 return SCI_FAILURE_INVALID_STATE; 636 return SCI_FAILURE_INVALID_STATE;
592 637
593 sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p); 638 sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p,
639 RNC_DEST_READY);
594 sci_remote_node_context_construct_buffer(sci_rnc); 640 sci_remote_node_context_construct_buffer(sci_rnc);
595 sci_change_state(&sci_rnc->sm, SCI_RNC_POSTING); 641 sci_change_state(&sci_rnc->sm, SCI_RNC_POSTING);
596 return SCI_SUCCESS; 642 return SCI_SUCCESS;
597 case SCI_RNC_POSTING: 643 case SCI_RNC_POSTING:
598 case SCI_RNC_INVALIDATING: 644 case SCI_RNC_INVALIDATING:
599 case SCI_RNC_RESUMING: 645 case SCI_RNC_RESUMING:
600 if (sci_rnc->destination_state != SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_READY) 646 /* We are still waiting to post when a resume was requested. */
601 return SCI_FAILURE_INVALID_STATE; 647 switch (sci_rnc->destination_state) {
602 648 case RNC_DEST_SUSPENDED:
603 sci_rnc->user_callback = cb_fn; 649 case RNC_DEST_SUSPENDED_RESUME:
604 sci_rnc->user_cookie = cb_p; 650 /* Previously waiting to suspend after posting. Now
651 * continue onto resumption.
652 */
653 sci_remote_node_context_setup_to_resume(
654 sci_rnc, cb_fn, cb_p,
655 RNC_DEST_SUSPENDED_RESUME);
656 break;
657 default:
658 sci_remote_node_context_setup_to_resume(
659 sci_rnc, cb_fn, cb_p,
660 RNC_DEST_READY);
661 break;
662 }
605 return SCI_SUCCESS; 663 return SCI_SUCCESS;
606 case SCI_RNC_TX_SUSPENDED: 664 case SCI_RNC_TX_SUSPENDED:
607 case SCI_RNC_TX_RX_SUSPENDED: { 665 case SCI_RNC_TX_RX_SUSPENDED: {
@@ -613,7 +671,8 @@ enum sci_status sci_remote_node_context_resume(struct sci_remote_node_context *s
613 * to clear the TCi to NCQ tag mapping table for the RNi. 671 * to clear the TCi to NCQ tag mapping table for the RNi.
614 * All other device types we can just resume. 672 * All other device types we can just resume.
615 */ 673 */
616 sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p); 674 sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p,
675 RNC_DEST_READY);
617 676
618 if (dev_is_sata(dev) && dev->parent) 677 if (dev_is_sata(dev) && dev->parent)
619 sci_change_state(&sci_rnc->sm, SCI_RNC_INVALIDATING); 678 sci_change_state(&sci_rnc->sm, SCI_RNC_INVALIDATING);
@@ -622,7 +681,9 @@ enum sci_status sci_remote_node_context_resume(struct sci_remote_node_context *s
622 return SCI_SUCCESS; 681 return SCI_SUCCESS;
623 } 682 }
624 case SCI_RNC_AWAIT_SUSPENSION: 683 case SCI_RNC_AWAIT_SUSPENSION:
625 sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p); 684 sci_remote_node_context_setup_to_resume(
685 sci_rnc, cb_fn, cb_p,
686 RNC_DEST_SUSPENDED_RESUME);
626 return SCI_SUCCESS; 687 return SCI_SUCCESS;
627 default: 688 default:
628 dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), 689 dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
@@ -663,24 +724,12 @@ enum sci_status sci_remote_node_context_start_task(
663 scics_sds_remote_node_context_callback cb_fn, 724 scics_sds_remote_node_context_callback cb_fn,
664 void *cb_p) 725 void *cb_p)
665{ 726{
666 enum scis_sds_remote_node_context_states state; 727 enum sci_status status = sci_remote_node_context_resume(sci_rnc,
667 728 cb_fn, cb_p);
668 state = sci_rnc->sm.current_state_id; 729 if (status != SCI_SUCCESS)
669 switch (state) {
670 case SCI_RNC_RESUMING:
671 case SCI_RNC_READY:
672 case SCI_RNC_AWAIT_SUSPENSION:
673 return SCI_SUCCESS;
674 case SCI_RNC_TX_SUSPENDED:
675 case SCI_RNC_TX_RX_SUSPENDED:
676 sci_remote_node_context_resume(sci_rnc, cb_fn, cb_p);
677 return SCI_SUCCESS;
678 default:
679 dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), 730 dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
680 "%s: invalid state %s\n", __func__, 731 "%s: resume failed: %d\n", __func__, status);
681 rnc_state_name(state)); 732 return status;
682 return SCI_FAILURE_INVALID_STATE;
683 }
684} 733}
685 734
686int sci_remote_node_context_is_safe_to_abort( 735int sci_remote_node_context_is_safe_to_abort(
diff --git a/drivers/scsi/isci/remote_node_context.h b/drivers/scsi/isci/remote_node_context.h
index 2870af14edab..48319066b4d6 100644
--- a/drivers/scsi/isci/remote_node_context.h
+++ b/drivers/scsi/isci/remote_node_context.h
@@ -141,9 +141,13 @@ const char *rnc_state_name(enum scis_sds_remote_node_context_states state);
141 * node context. 141 * node context.
142 */ 142 */
143enum sci_remote_node_context_destination_state { 143enum sci_remote_node_context_destination_state {
144 SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_UNSPECIFIED, 144 RNC_DEST_UNSPECIFIED,
145 SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_READY, 145 RNC_DEST_READY,
146 SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_FINAL 146 RNC_DEST_FINAL,
147 RNC_DEST_SUSPENDED, /* Set when suspend during post/invalidate */
148 RNC_DEST_SUSPENDED_RESUME /* Set when a resume was done during posting
149 * or invalidating and already suspending.
150 */
147}; 151};
148 152
149/** 153/**