isci: Intel(R) C600 Series Chipset Storage Control Unit Driver
[linux-2.6-block.git] / drivers / scsi / isci / core / scic_sds_remote_node_context.c
1 /*
2  * This file is provided under a dual BSD/GPLv2 license.  When using or
3  * redistributing this file, you may do so under either license.
4  *
5  * GPL LICENSE SUMMARY
6  *
7  * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of version 2 of the GNU General Public License as
11  * published by the Free Software Foundation.
12  *
13  * This program is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
21  * The full GNU General Public License is included in this distribution
22  * in the file called LICENSE.GPL.
23  *
24  * BSD LICENSE
25  *
26  * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
27  * All rights reserved.
28  *
29  * Redistribution and use in source and binary forms, with or without
30  * modification, are permitted provided that the following conditions
31  * are met:
32  *
33  *   * Redistributions of source code must retain the above copyright
34  *     notice, this list of conditions and the following disclaimer.
35  *   * Redistributions in binary form must reproduce the above copyright
36  *     notice, this list of conditions and the following disclaimer in
37  *     the documentation and/or other materials provided with the
38  *     distribution.
39  *   * Neither the name of Intel Corporation nor the names of its
40  *     contributors may be used to endorse or promote products derived
41  *     from this software without specific prior written permission.
42  *
43  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
44  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
45  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
46  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
47  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
48  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
49  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
50  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
51  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
52  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
53  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
54  */
55
56 #include "sci_base_state_machine.h"
57 #include "scic_remote_device.h"
58 #include "scic_sds_controller.h"
59 #include "scic_sds_port.h"
60 #include "scic_sds_remote_device.h"
61 #include "scic_sds_remote_node_context.h"
62 #include "sci_environment.h"
63 #include "sci_util.h"
64 #include "scu_event_codes.h"
65 #include "scu_task_context.h"
66
67 void scic_sds_remote_node_context_construct(
68         struct scic_sds_remote_device *device,
69         struct scic_sds_remote_node_context *rnc,
70         u16 remote_node_index)
71 {
72         memset(rnc, 0, sizeof(struct scic_sds_remote_node_context));
73
74         rnc->remote_node_index = remote_node_index;
75         rnc->device            = device;
76         rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_UNSPECIFIED;
77
78         sci_base_state_machine_construct(
79                 &rnc->state_machine,
80                 &rnc->parent,
81                 scic_sds_remote_node_context_state_table,
82                 SCIC_SDS_REMOTE_NODE_CONTEXT_INITIAL_STATE
83                 );
84
85         sci_base_state_machine_start(&rnc->state_machine);
86 }
87
88 /**
89  *
90  * @this_rnc: The RNC for which the is posted request is being made.
91  *
92  * This method will return true if the RNC is not in the initial state.  In all
93  * other states the RNC is considered active and this will return true. The
94  * destroy request of the state machine drives the RNC back to the initial
95  * state.  If the state machine changes then this routine will also have to be
96  * changed. bool true if the state machine is not in the initial state false if
97  * the state machine is in the initial state
98  */
99
100 /**
101  *
102  * @this_rnc: The state of the remote node context object to check.
103  *
104  * This method will return true if the remote node context is in a READY state
105  * otherwise it will return false bool true if the remote node context is in
106  * the ready state. false if the remote node context is not in the ready state.
107  */
108 bool scic_sds_remote_node_context_is_ready(
109         struct scic_sds_remote_node_context *this_rnc)
110 {
111         u32 current_state = sci_base_state_machine_get_state(&this_rnc->state_machine);
112
113         if (current_state == SCIC_SDS_REMOTE_NODE_CONTEXT_READY_STATE) {
114                 return true;
115         }
116
117         return false;
118 }
119
120 /**
121  *
122  * @this_device: The remote device to use to construct the RNC buffer.
123  * @rnc: The buffer into which the remote device data will be copied.
124  *
125  * This method will construct the RNC buffer for this remote device object. none
126  */
127 void scic_sds_remote_node_context_construct_buffer(
128         struct scic_sds_remote_node_context *this_rnc)
129 {
130         union scu_remote_node_context *rnc;
131         struct scic_sds_controller *the_controller;
132
133         the_controller = scic_sds_remote_device_get_controller(this_rnc->device);
134
135         rnc = scic_sds_controller_get_remote_node_context_buffer(
136                 the_controller, this_rnc->remote_node_index);
137
138         memset(
139                 rnc,
140                 0x00,
141                 sizeof(union scu_remote_node_context)
142                 * scic_sds_remote_device_node_count(this_rnc->device)
143                 );
144
145         rnc->ssp.remote_node_index = this_rnc->remote_node_index;
146         rnc->ssp.remote_node_port_width = this_rnc->device->device_port_width;
147         rnc->ssp.logical_port_index =
148                 scic_sds_remote_device_get_port_index(this_rnc->device);
149
150         rnc->ssp.remote_sas_address_hi = SCIC_SWAP_DWORD(this_rnc->device->device_address.high);
151         rnc->ssp.remote_sas_address_lo = SCIC_SWAP_DWORD(this_rnc->device->device_address.low);
152
153         rnc->ssp.nexus_loss_timer_enable = true;
154         rnc->ssp.check_bit               = false;
155         rnc->ssp.is_valid                = false;
156         rnc->ssp.is_remote_node_context  = true;
157         rnc->ssp.function_number         = 0;
158
159         rnc->ssp.arbitration_wait_time = 0;
160
161
162         if (
163                 this_rnc->device->target_protocols.u.bits.attached_sata_device
164                 || this_rnc->device->target_protocols.u.bits.attached_stp_target
165                 ) {
166                 rnc->ssp.connection_occupancy_timeout =
167                         the_controller->user_parameters.sds1.stp_max_occupancy_timeout;
168                 rnc->ssp.connection_inactivity_timeout =
169                         the_controller->user_parameters.sds1.stp_inactivity_timeout;
170         } else {
171                 rnc->ssp.connection_occupancy_timeout  =
172                         the_controller->user_parameters.sds1.ssp_max_occupancy_timeout;
173                 rnc->ssp.connection_inactivity_timeout =
174                         the_controller->user_parameters.sds1.ssp_inactivity_timeout;
175         }
176
177         rnc->ssp.initial_arbitration_wait_time = 0;
178
179         /* Open Address Frame Parameters */
180         rnc->ssp.oaf_connection_rate = this_rnc->device->connection_rate;
181         rnc->ssp.oaf_features = 0;
182         rnc->ssp.oaf_source_zone_group = 0;
183         rnc->ssp.oaf_more_compatibility_features = 0;
184 }
185
186 /**
187  *
188  * @this_rnc:
189  * @the_callback:
190  * @callback_parameter:
191  *
192  * This method will setup the remote node context object so it will transition
193  * to its ready state.  If the remote node context is already setup to
194  * transition to its final state then this function does nothing. none
195  */
196 static void scic_sds_remote_node_context_setup_to_resume(
197         struct scic_sds_remote_node_context *this_rnc,
198         SCICS_SDS_REMOTE_NODE_CONTEXT_CALLBACK the_callback,
199         void *callback_parameter)
200 {
201         if (this_rnc->destination_state != SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_FINAL) {
202                 this_rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_READY;
203                 this_rnc->user_callback     = the_callback;
204                 this_rnc->user_cookie       = callback_parameter;
205         }
206 }
207
208 /**
209  *
210  * @this_rnc:
211  * @the_callback:
212  * @callback_parameter:
213  *
214  * This method will setup the remote node context object so it will transistion
215  * to its final state. none
216  */
217 static void scic_sds_remote_node_context_setup_to_destory(
218         struct scic_sds_remote_node_context *this_rnc,
219         SCICS_SDS_REMOTE_NODE_CONTEXT_CALLBACK the_callback,
220         void *callback_parameter)
221 {
222         this_rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_FINAL;
223         this_rnc->user_callback     = the_callback;
224         this_rnc->user_cookie       = callback_parameter;
225 }
226
227 /**
228  *
229  * @this_rnc:
230  * @the_callback:
231  *
232  * This method will continue to resume a remote node context.  This is used in
233  * the states where a resume is requested while a resume is in progress.
234  */
235 static enum sci_status scic_sds_remote_node_context_continue_to_resume_handler(
236         struct scic_sds_remote_node_context *this_rnc,
237         SCICS_SDS_REMOTE_NODE_CONTEXT_CALLBACK the_callback,
238         void *callback_parameter)
239 {
240         if (this_rnc->destination_state == SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_READY) {
241                 this_rnc->user_callback = the_callback;
242                 this_rnc->user_cookie   = callback_parameter;
243
244                 return SCI_SUCCESS;
245         }
246
247         return SCI_FAILURE_INVALID_STATE;
248 }
249
250 /* --------------------------------------------------------------------------- */
251
252 static enum sci_status scic_sds_remote_node_context_default_destruct_handler(
253         struct scic_sds_remote_node_context *this_rnc,
254         SCICS_SDS_REMOTE_NODE_CONTEXT_CALLBACK the_callback,
255         void *callback_parameter)
256 {
257         dev_warn(scirdev_to_dev(this_rnc->device),
258                  "%s: SCIC Remote Node Context 0x%p requested to stop while "
259                  "in unexpected state %d\n",
260                  __func__,
261                  this_rnc,
262                  sci_base_state_machine_get_state(&this_rnc->state_machine));
263
264         /*
265          * We have decided that the destruct request on the remote node context can not fail
266          * since it is either in the initial/destroyed state or is can be destroyed. */
267         return SCI_SUCCESS;
268 }
269
270 static enum sci_status scic_sds_remote_node_context_default_suspend_handler(
271         struct scic_sds_remote_node_context *this_rnc,
272         u32 suspend_type,
273         SCICS_SDS_REMOTE_NODE_CONTEXT_CALLBACK the_callback,
274         void *callback_parameter)
275 {
276         dev_warn(scirdev_to_dev(this_rnc->device),
277                  "%s: SCIC Remote Node Context 0x%p requested to suspend "
278                  "while in wrong state %d\n",
279                  __func__,
280                  this_rnc,
281                  sci_base_state_machine_get_state(&this_rnc->state_machine));
282
283         return SCI_FAILURE_INVALID_STATE;
284 }
285
286 static enum sci_status scic_sds_remote_node_context_default_resume_handler(
287         struct scic_sds_remote_node_context *this_rnc,
288         SCICS_SDS_REMOTE_NODE_CONTEXT_CALLBACK the_callback,
289         void *callback_parameter)
290 {
291         dev_warn(scirdev_to_dev(this_rnc->device),
292                  "%s: SCIC Remote Node Context 0x%p requested to resume "
293                  "while in wrong state %d\n",
294                  __func__,
295                  this_rnc,
296                  sci_base_state_machine_get_state(&this_rnc->state_machine));
297
298         return SCI_FAILURE_INVALID_STATE;
299 }
300
301 static enum sci_status scic_sds_remote_node_context_default_start_io_handler(
302         struct scic_sds_remote_node_context *this_rnc,
303         struct scic_sds_request *the_request)
304 {
305         dev_warn(scirdev_to_dev(this_rnc->device),
306                  "%s: SCIC Remote Node Context 0x%p requested to start io "
307                  "0x%p while in wrong state %d\n",
308                  __func__,
309                  this_rnc,
310                  the_request,
311                  sci_base_state_machine_get_state(&this_rnc->state_machine));
312
313         return SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED;
314 }
315
316 static enum sci_status scic_sds_remote_node_context_default_start_task_handler(
317         struct scic_sds_remote_node_context *this_rnc,
318         struct scic_sds_request *the_request)
319 {
320         dev_warn(scirdev_to_dev(this_rnc->device),
321                  "%s: SCIC Remote Node Context 0x%p requested to start "
322                  "task 0x%p while in wrong state %d\n",
323                  __func__,
324                  this_rnc,
325                  the_request,
326                  sci_base_state_machine_get_state(&this_rnc->state_machine));
327
328         return SCI_FAILURE;
329 }
330
331 static enum sci_status scic_sds_remote_node_context_default_event_handler(
332         struct scic_sds_remote_node_context *this_rnc,
333         u32 event_code)
334 {
335         dev_warn(scirdev_to_dev(this_rnc->device),
336                  "%s: SCIC Remote Node Context 0x%p requested to process "
337                  "event 0x%x while in wrong state %d\n",
338                  __func__,
339                  this_rnc,
340                  event_code,
341                  sci_base_state_machine_get_state(&this_rnc->state_machine));
342
343         return SCI_FAILURE_INVALID_STATE;
344 }
345
346 /**
347  *
348  * @this_rnc: The rnc for which the task request is targeted.
349  * @the_request: The request which is going to be started.
350  *
351  * This method determines if the task request can be started by the SCU
352  * hardware. When the RNC is in the ready state any task can be started.
353  * enum sci_status SCI_SUCCESS
354  */
355 static enum sci_status scic_sds_remote_node_context_success_start_task_handler(
356         struct scic_sds_remote_node_context *this_rnc,
357         struct scic_sds_request *the_request)
358 {
359         return SCI_SUCCESS;
360 }
361
362 /**
363  *
364  * @this_rnc:
365  * @the_callback:
366  * @callback_parameter:
367  *
368  * This method handles destruct calls from the various state handlers.  The
369  * remote node context can be requested to destroy from any state. If there was
370  * a user callback it is always replaced with the request to destroy user
371  * callback. enum sci_status
372  */
373 static enum sci_status scic_sds_remote_node_context_general_destruct_handler(
374         struct scic_sds_remote_node_context *this_rnc,
375         SCICS_SDS_REMOTE_NODE_CONTEXT_CALLBACK the_callback,
376         void *callback_parameter)
377 {
378         scic_sds_remote_node_context_setup_to_destory(
379                 this_rnc, the_callback, callback_parameter
380                 );
381
382         sci_base_state_machine_change_state(
383                 &this_rnc->state_machine,
384                 SCIC_SDS_REMOTE_NODE_CONTEXT_INVALIDATING_STATE
385                 );
386
387         return SCI_SUCCESS;
388 }
389
390 /* --------------------------------------------------------------------------- */
391
392 static enum sci_status scic_sds_remote_node_context_initial_state_resume_handler(
393         struct scic_sds_remote_node_context *this_rnc,
394         SCICS_SDS_REMOTE_NODE_CONTEXT_CALLBACK the_callback,
395         void *callback_parameter)
396 {
397         if (this_rnc->remote_node_index != SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX) {
398                 scic_sds_remote_node_context_setup_to_resume(
399                         this_rnc, the_callback, callback_parameter
400                         );
401
402                 scic_sds_remote_node_context_construct_buffer(this_rnc);
403
404                 sci_base_state_machine_change_state(
405                         &this_rnc->state_machine,
406                         SCIC_SDS_REMOTE_NODE_CONTEXT_POSTING_STATE
407                         );
408
409                 return SCI_SUCCESS;
410         }
411
412         return SCI_FAILURE_INVALID_STATE;
413 }
414
415 /* --------------------------------------------------------------------------- */
416
417 static enum sci_status scic_sds_remote_node_context_posting_state_event_handler(
418         struct scic_sds_remote_node_context *this_rnc,
419         u32 event_code)
420 {
421         enum sci_status status;
422
423         switch (scu_get_event_code(event_code)) {
424         case SCU_EVENT_POST_RNC_COMPLETE:
425                 status = SCI_SUCCESS;
426
427                 sci_base_state_machine_change_state(
428                         &this_rnc->state_machine,
429                         SCIC_SDS_REMOTE_NODE_CONTEXT_READY_STATE
430                         );
431                 break;
432
433         default:
434                 status = SCI_FAILURE;
435                 dev_warn(scirdev_to_dev(this_rnc->device),
436                          "%s: SCIC Remote Node Context 0x%p requested to "
437                          "process unexpected event 0x%x while in posting "
438                          "state\n",
439                          __func__,
440                          this_rnc,
441                          event_code);
442                 break;
443         }
444
445         return status;
446 }
447
448 /* --------------------------------------------------------------------------- */
449
450 static enum sci_status scic_sds_remote_node_context_invalidating_state_destruct_handler(
451         struct scic_sds_remote_node_context *this_rnc,
452         SCICS_SDS_REMOTE_NODE_CONTEXT_CALLBACK the_callback,
453         void *callback_parameter)
454 {
455         scic_sds_remote_node_context_setup_to_destory(
456                 this_rnc, the_callback, callback_parameter
457                 );
458
459         return SCI_SUCCESS;
460 }
461
462 static enum sci_status scic_sds_remote_node_context_invalidating_state_event_handler(
463         struct scic_sds_remote_node_context *this_rnc,
464         u32 event_code)
465 {
466         enum sci_status status;
467
468         if (scu_get_event_code(event_code) == SCU_EVENT_POST_RNC_INVALIDATE_COMPLETE) {
469                 status = SCI_SUCCESS;
470
471                 if (this_rnc->destination_state == SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_FINAL) {
472                         sci_base_state_machine_change_state(
473                                 &this_rnc->state_machine,
474                                 SCIC_SDS_REMOTE_NODE_CONTEXT_INITIAL_STATE
475                                 );
476                 } else {
477                         sci_base_state_machine_change_state(
478                                 &this_rnc->state_machine,
479                                 SCIC_SDS_REMOTE_NODE_CONTEXT_POSTING_STATE
480                                 );
481                 }
482         } else {
483                 switch (scu_get_event_type(event_code)) {
484                 case SCU_EVENT_TYPE_RNC_SUSPEND_TX:
485                 case SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX:
486                         /*
487                          * We really dont care if the hardware is going to suspend
488                          * the device since it's being invalidated anyway */
489                         dev_dbg(scirdev_to_dev(this_rnc->device),
490                                 "%s: SCIC Remote Node Context 0x%p was "
491                                 "suspeneded by hardware while being "
492                                 "invalidated.\n",
493                                 __func__,
494                                 this_rnc);
495                         status = SCI_SUCCESS;
496                         break;
497
498                 default:
499                         dev_warn(scirdev_to_dev(this_rnc->device),
500                                  "%s: SCIC Remote Node Context 0x%p "
501                                  "requested to process event 0x%x while "
502                                  "in state %d.\n",
503                                  __func__,
504                                  this_rnc,
505                                  event_code,
506                                  sci_base_state_machine_get_state(
507                                          &this_rnc->state_machine));
508                         status = SCI_FAILURE;
509                         break;
510                 }
511         }
512
513         return status;
514 }
515
516 /* --------------------------------------------------------------------------- */
517
518
519 static enum sci_status scic_sds_remote_node_context_resuming_state_event_handler(
520         struct scic_sds_remote_node_context *this_rnc,
521         u32 event_code)
522 {
523         enum sci_status status;
524
525         if (scu_get_event_code(event_code) == SCU_EVENT_POST_RCN_RELEASE) {
526                 status = SCI_SUCCESS;
527
528                 sci_base_state_machine_change_state(
529                         &this_rnc->state_machine,
530                         SCIC_SDS_REMOTE_NODE_CONTEXT_READY_STATE
531                         );
532         } else {
533                 switch (scu_get_event_type(event_code)) {
534                 case SCU_EVENT_TYPE_RNC_SUSPEND_TX:
535                 case SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX:
536                         /*
537                          * We really dont care if the hardware is going to suspend
538                          * the device since it's being resumed anyway */
539                         dev_dbg(scirdev_to_dev(this_rnc->device),
540                                 "%s: SCIC Remote Node Context 0x%p was "
541                                 "suspeneded by hardware while being resumed.\n",
542                                 __func__,
543                                 this_rnc);
544                         status = SCI_SUCCESS;
545                         break;
546
547                 default:
548                         dev_warn(scirdev_to_dev(this_rnc->device),
549                                  "%s: SCIC Remote Node Context 0x%p requested "
550                                  "to process event 0x%x while in state %d.\n",
551                                  __func__,
552                                  this_rnc,
553                                  event_code,
554                                  sci_base_state_machine_get_state(
555                                          &this_rnc->state_machine));
556                         status = SCI_FAILURE;
557                         break;
558                 }
559         }
560
561         return status;
562 }
563
564 /* --------------------------------------------------------------------------- */
565
566 /**
567  *
568  * @this_rnc: The remote node context object being suspended.
569  * @the_callback: The callback when the suspension is complete.
570  * @callback_parameter: The parameter that is to be passed into the callback.
571  *
572  * This method will handle the suspend requests from the ready state.
573  * SCI_SUCCESS
574  */
575 static enum sci_status scic_sds_remote_node_context_ready_state_suspend_handler(
576         struct scic_sds_remote_node_context *this_rnc,
577         u32 suspend_type,
578         SCICS_SDS_REMOTE_NODE_CONTEXT_CALLBACK the_callback,
579         void *callback_parameter)
580 {
581         this_rnc->user_callback   = the_callback;
582         this_rnc->user_cookie     = callback_parameter;
583         this_rnc->suspension_code = suspend_type;
584
585         if (suspend_type == SCI_SOFTWARE_SUSPENSION) {
586                 scic_sds_remote_device_post_request(
587                         this_rnc->device,
588                         SCU_CONTEXT_COMMAND_POST_RNC_SUSPEND_TX
589                         );
590         }
591
592         sci_base_state_machine_change_state(
593                 &this_rnc->state_machine,
594                 SCIC_SDS_REMOTE_NODE_CONTEXT_AWAIT_SUSPENSION_STATE
595                 );
596
597         return SCI_SUCCESS;
598 }
599
600 /**
601  *
602  * @this_rnc: The rnc for which the io request is targeted.
603  * @the_request: The request which is going to be started.
604  *
605  * This method determines if the io request can be started by the SCU hardware.
606  * When the RNC is in the ready state any io request can be started. enum sci_status
607  * SCI_SUCCESS
608  */
609 static enum sci_status scic_sds_remote_node_context_ready_state_start_io_handler(
610         struct scic_sds_remote_node_context *this_rnc,
611         struct scic_sds_request *the_request)
612 {
613         return SCI_SUCCESS;
614 }
615
616
617 static enum sci_status scic_sds_remote_node_context_ready_state_event_handler(
618         struct scic_sds_remote_node_context *this_rnc,
619         u32 event_code)
620 {
621         enum sci_status status;
622
623         switch (scu_get_event_type(event_code)) {
624         case SCU_EVENT_TL_RNC_SUSPEND_TX:
625                 sci_base_state_machine_change_state(
626                         &this_rnc->state_machine,
627                         SCIC_SDS_REMOTE_NODE_CONTEXT_TX_SUSPENDED_STATE
628                         );
629
630                 this_rnc->suspension_code = scu_get_event_specifier(event_code);
631                 status = SCI_SUCCESS;
632                 break;
633
634         case SCU_EVENT_TL_RNC_SUSPEND_TX_RX:
635                 sci_base_state_machine_change_state(
636                         &this_rnc->state_machine,
637                         SCIC_SDS_REMOTE_NODE_CONTEXT_TX_RX_SUSPENDED_STATE
638                         );
639
640                 this_rnc->suspension_code = scu_get_event_specifier(event_code);
641                 status = SCI_SUCCESS;
642                 break;
643
644         default:
645                 dev_warn(scirdev_to_dev(this_rnc->device),
646                         "%s: SCIC Remote Node Context 0x%p requested to "
647                         "process event 0x%x while in state %d.\n",
648                         __func__,
649                         this_rnc,
650                         event_code,
651                         sci_base_state_machine_get_state(
652                                 &this_rnc->state_machine));
653
654                 status = SCI_FAILURE;
655                 break;
656         }
657
658         return status;
659 }
660
661 /* --------------------------------------------------------------------------- */
662
663 static enum sci_status scic_sds_remote_node_context_tx_suspended_state_resume_handler(
664         struct scic_sds_remote_node_context *this_rnc,
665         SCICS_SDS_REMOTE_NODE_CONTEXT_CALLBACK the_callback,
666         void *callback_parameter)
667 {
668         enum sci_status status;
669         struct smp_discover_response_protocols protocols;
670
671         scic_sds_remote_node_context_setup_to_resume(
672                 this_rnc, the_callback, callback_parameter
673                 );
674
675         /* TODO: consider adding a resume action of NONE, INVALIDATE, WRITE_TLCR */
676
677         scic_remote_device_get_protocols(this_rnc->device, &protocols);
678
679         if (
680                 (protocols.u.bits.attached_ssp_target == 1)
681                 || (protocols.u.bits.attached_smp_target == 1)
682                 ) {
683                 sci_base_state_machine_change_state(
684                         &this_rnc->state_machine,
685                         SCIC_SDS_REMOTE_NODE_CONTEXT_RESUMING_STATE
686                         );
687
688                 status = SCI_SUCCESS;
689         } else if (protocols.u.bits.attached_stp_target == 1) {
690                 if (this_rnc->device->is_direct_attached) {
691                         /* @todo Fix this since I am being silly in writing to the STPTLDARNI register. */
692                         scic_sds_port_set_direct_attached_device_id(
693                                 this_rnc->device->owning_port,
694                                 this_rnc->remote_node_index
695                                 );
696
697                         sci_base_state_machine_change_state(
698                                 &this_rnc->state_machine,
699                                 SCIC_SDS_REMOTE_NODE_CONTEXT_RESUMING_STATE
700                                 );
701                 } else {
702                         sci_base_state_machine_change_state(
703                                 &this_rnc->state_machine,
704                                 SCIC_SDS_REMOTE_NODE_CONTEXT_INVALIDATING_STATE
705                                 );
706                 }
707
708                 status = SCI_SUCCESS;
709         } else {
710                 status = SCI_FAILURE;
711         }
712
713         return status;
714 }
715
716 /**
717  *
718  * @this_rnc: The remote node context which is to receive the task request.
719  * @the_request: The task request to be transmitted to to the remote target
720  *    device.
721  *
722  * This method will report a success or failure attempt to start a new task
723  * request to the hardware.  Since all task requests are sent on the high
724  * priority queue they can be sent when the RCN is in a TX suspend state.
725  * enum sci_status SCI_SUCCESS
726  */
727 static enum sci_status scic_sds_remote_node_context_suspended_start_task_handler(
728         struct scic_sds_remote_node_context *this_rnc,
729         struct scic_sds_request *the_request)
730 {
731         scic_sds_remote_node_context_resume(this_rnc, NULL, NULL);
732
733         return SCI_SUCCESS;
734 }
735
736 /* --------------------------------------------------------------------------- */
737
738 static enum sci_status scic_sds_remote_node_context_tx_rx_suspended_state_resume_handler(
739         struct scic_sds_remote_node_context *this_rnc,
740         SCICS_SDS_REMOTE_NODE_CONTEXT_CALLBACK the_callback,
741         void *callback_parameter)
742 {
743         scic_sds_remote_node_context_setup_to_resume(
744                 this_rnc, the_callback, callback_parameter
745                 );
746
747         sci_base_state_machine_change_state(
748                 &this_rnc->state_machine,
749                 SCIC_SDS_REMOTE_NODE_CONTEXT_RESUMING_STATE
750                 );
751
752         return SCI_FAILURE_INVALID_STATE;
753 }
754
755 /* --------------------------------------------------------------------------- */
756
757 /**
758  *
759  *
760  *
761  */
762 static enum sci_status scic_sds_remote_node_context_await_suspension_state_resume_handler(
763         struct scic_sds_remote_node_context *this_rnc,
764         SCICS_SDS_REMOTE_NODE_CONTEXT_CALLBACK the_callback,
765         void *callback_parameter)
766 {
767         scic_sds_remote_node_context_setup_to_resume(
768                 this_rnc, the_callback, callback_parameter
769                 );
770
771         return SCI_SUCCESS;
772 }
773
774 /**
775  *
776  * @this_rnc: The remote node context which is to receive the task request.
777  * @the_request: The task request to be transmitted to to the remote target
778  *    device.
779  *
780  * This method will report a success or failure attempt to start a new task
781  * request to the hardware.  Since all task requests are sent on the high
782  * priority queue they can be sent when the RCN is in a TX suspend state.
783  * enum sci_status SCI_SUCCESS
784  */
785 static enum sci_status scic_sds_remote_node_context_await_suspension_state_start_task_handler(
786         struct scic_sds_remote_node_context *this_rnc,
787         struct scic_sds_request *the_request)
788 {
789         return SCI_SUCCESS;
790 }
791
792 static enum sci_status scic_sds_remote_node_context_await_suspension_state_event_handler(
793         struct scic_sds_remote_node_context *this_rnc,
794         u32 event_code)
795 {
796         enum sci_status status;
797
798         switch (scu_get_event_type(event_code)) {
799         case SCU_EVENT_TL_RNC_SUSPEND_TX:
800                 sci_base_state_machine_change_state(
801                         &this_rnc->state_machine,
802                         SCIC_SDS_REMOTE_NODE_CONTEXT_TX_SUSPENDED_STATE
803                         );
804
805                 this_rnc->suspension_code = scu_get_event_specifier(event_code);
806                 status = SCI_SUCCESS;
807                 break;
808
809         case SCU_EVENT_TL_RNC_SUSPEND_TX_RX:
810                 sci_base_state_machine_change_state(
811                         &this_rnc->state_machine,
812                         SCIC_SDS_REMOTE_NODE_CONTEXT_TX_RX_SUSPENDED_STATE
813                         );
814
815                 this_rnc->suspension_code = scu_get_event_specifier(event_code);
816                 status = SCI_SUCCESS;
817                 break;
818
819         default:
820                 dev_warn(scirdev_to_dev(this_rnc->device),
821                          "%s: SCIC Remote Node Context 0x%p requested to "
822                          "process event 0x%x while in state %d.\n",
823                          __func__,
824                          this_rnc,
825                          event_code,
826                          sci_base_state_machine_get_state(
827                                  &this_rnc->state_machine));
828
829                 status = SCI_FAILURE;
830                 break;
831         }
832
833         return status;
834 }
835
836 /* --------------------------------------------------------------------------- */
837
838 struct scic_sds_remote_node_context_handlers
839 scic_sds_remote_node_context_state_handler_table[
840         SCIC_SDS_REMOTE_NODE_CONTEXT_MAX_STATES] =
841 {
842         /* SCIC_SDS_REMOTE_NODE_CONTEXT_INITIAL_STATE */
843         {
844                 scic_sds_remote_node_context_default_destruct_handler,
845                 scic_sds_remote_node_context_default_suspend_handler,
846                 scic_sds_remote_node_context_initial_state_resume_handler,
847                 scic_sds_remote_node_context_default_start_io_handler,
848                 scic_sds_remote_node_context_default_start_task_handler,
849                 scic_sds_remote_node_context_default_event_handler
850         },
851         /* SCIC_SDS_REMOTE_NODE_CONTEXT_POSTING_STATE */
852         {
853                 scic_sds_remote_node_context_general_destruct_handler,
854                 scic_sds_remote_node_context_default_suspend_handler,
855                 scic_sds_remote_node_context_continue_to_resume_handler,
856                 scic_sds_remote_node_context_default_start_io_handler,
857                 scic_sds_remote_node_context_default_start_task_handler,
858                 scic_sds_remote_node_context_posting_state_event_handler
859         },
860         /* SCIC_SDS_REMOTE_NODE_CONTEXT_INVALIDATING_STATE */
861         {
862                 scic_sds_remote_node_context_invalidating_state_destruct_handler,
863                 scic_sds_remote_node_context_default_suspend_handler,
864                 scic_sds_remote_node_context_continue_to_resume_handler,
865                 scic_sds_remote_node_context_default_start_io_handler,
866                 scic_sds_remote_node_context_default_start_task_handler,
867                 scic_sds_remote_node_context_invalidating_state_event_handler
868         },
869         /* SCIC_SDS_REMOTE_NODE_CONTEXT_RESUMING_STATE */
870         {
871                 scic_sds_remote_node_context_general_destruct_handler,
872                 scic_sds_remote_node_context_default_suspend_handler,
873                 scic_sds_remote_node_context_continue_to_resume_handler,
874                 scic_sds_remote_node_context_default_start_io_handler,
875                 scic_sds_remote_node_context_success_start_task_handler,
876                 scic_sds_remote_node_context_resuming_state_event_handler
877         },
878         /* SCIC_SDS_REMOTE_NODE_CONTEXT_READY_STATE */
879         {
880                 scic_sds_remote_node_context_general_destruct_handler,
881                 scic_sds_remote_node_context_ready_state_suspend_handler,
882                 scic_sds_remote_node_context_default_resume_handler,
883                 scic_sds_remote_node_context_ready_state_start_io_handler,
884                 scic_sds_remote_node_context_success_start_task_handler,
885                 scic_sds_remote_node_context_ready_state_event_handler
886         },
887         /* SCIC_SDS_REMOTE_NODE_CONTEXT_TX_SUSPENDED_STATE */
888         {
889                 scic_sds_remote_node_context_general_destruct_handler,
890                 scic_sds_remote_node_context_default_suspend_handler,
891                 scic_sds_remote_node_context_tx_suspended_state_resume_handler,
892                 scic_sds_remote_node_context_default_start_io_handler,
893                 scic_sds_remote_node_context_suspended_start_task_handler,
894                 scic_sds_remote_node_context_default_event_handler
895         },
896         /* SCIC_SDS_REMOTE_NODE_CONTEXT_TX_RX_SUSPENDED_STATE */
897         {
898                 scic_sds_remote_node_context_general_destruct_handler,
899                 scic_sds_remote_node_context_default_suspend_handler,
900                 scic_sds_remote_node_context_tx_rx_suspended_state_resume_handler,
901                 scic_sds_remote_node_context_default_start_io_handler,
902                 scic_sds_remote_node_context_suspended_start_task_handler,
903                 scic_sds_remote_node_context_default_event_handler
904         },
905         /* SCIC_SDS_REMOTE_NODE_CONTEXT_AWAIT_SUSPENSION_STATE */
906         {
907                 scic_sds_remote_node_context_general_destruct_handler,
908                 scic_sds_remote_node_context_default_suspend_handler,
909                 scic_sds_remote_node_context_await_suspension_state_resume_handler,
910                 scic_sds_remote_node_context_default_start_io_handler,
911                 scic_sds_remote_node_context_await_suspension_state_start_task_handler,
912                 scic_sds_remote_node_context_await_suspension_state_event_handler
913         }
914 };
915
916 /*
917  * *****************************************************************************
918  * * REMOTE NODE CONTEXT PRIVATE METHODS
919  * ***************************************************************************** */
920
921 /**
922  *
923  *
924  * This method just calls the user callback function and then resets the
925  * callback.
926  */
927 static void scic_sds_remote_node_context_notify_user(
928         struct scic_sds_remote_node_context *rnc)
929 {
930         if (rnc->user_callback != NULL) {
931                 (*rnc->user_callback)(rnc->user_cookie);
932
933                 rnc->user_callback = NULL;
934                 rnc->user_cookie = NULL;
935         }
936 }
937
938 /**
939  *
940  *
941  * This method will continue the remote node context state machine by
942  * requesting to resume the remote node context state machine from its current
943  * state.
944  */
945 static void scic_sds_remote_node_context_continue_state_transitions(
946         struct scic_sds_remote_node_context *rnc)
947 {
948         if (rnc->destination_state == SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_READY) {
949                 rnc->state_handlers->resume_handler(
950                         rnc, rnc->user_callback, rnc->user_cookie
951                         );
952         }
953 }
954
955 /**
956  *
957  * @this_rnc: The remote node context object that is to be validated.
958  *
959  * This method will mark the rnc buffer as being valid and post the request to
960  * the hardware. none
961  */
962 static void scic_sds_remote_node_context_validate_context_buffer(
963         struct scic_sds_remote_node_context *this_rnc)
964 {
965         union scu_remote_node_context *rnc_buffer;
966
967         rnc_buffer = scic_sds_controller_get_remote_node_context_buffer(
968                 scic_sds_remote_device_get_controller(this_rnc->device),
969                 this_rnc->remote_node_index
970                 );
971
972         rnc_buffer->ssp.is_valid = true;
973
974         if (
975                 !this_rnc->device->is_direct_attached
976                 && this_rnc->device->target_protocols.u.bits.attached_stp_target
977                 ) {
978                 scic_sds_remote_device_post_request(
979                         this_rnc->device,
980                         SCU_CONTEXT_COMMAND_POST_RNC_96
981                         );
982         } else {
983                 scic_sds_remote_device_post_request(
984                         this_rnc->device,
985                         SCU_CONTEXT_COMMAND_POST_RNC_32
986                         );
987
988                 if (this_rnc->device->is_direct_attached) {
989                         scic_sds_port_set_direct_attached_device_id(
990                                 this_rnc->device->owning_port,
991                                 this_rnc->remote_node_index
992                                 );
993                 }
994         }
995 }
996
997 /**
998  *
999  * @this_rnc: The remote node context object that is to be invalidated.
1000  *
1001  * This method will update the RNC buffer and post the invalidate request. none
1002  */
1003 static void scic_sds_remote_node_context_invalidate_context_buffer(
1004         struct scic_sds_remote_node_context *this_rnc)
1005 {
1006         union scu_remote_node_context *rnc_buffer;
1007
1008         rnc_buffer = scic_sds_controller_get_remote_node_context_buffer(
1009                 scic_sds_remote_device_get_controller(this_rnc->device),
1010                 this_rnc->remote_node_index
1011                 );
1012
1013         rnc_buffer->ssp.is_valid = false;
1014
1015         scic_sds_remote_device_post_request(
1016                 this_rnc->device,
1017                 SCU_CONTEXT_COMMAND_POST_RNC_INVALIDATE
1018                 );
1019
1020         if (this_rnc->device->is_direct_attached) {
1021                 scic_sds_port_set_direct_attached_device_id(
1022                         this_rnc->device->owning_port,
1023                         SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX
1024                         );
1025         }
1026 }
1027
1028 /*
1029  * *****************************************************************************
1030  * * REMOTE NODE CONTEXT STATE ENTER AND EXIT METHODS
1031  * ***************************************************************************** */
1032
1033 /**
1034  *
1035  *
1036  *
1037  */
1038 static void scic_sds_remote_node_context_initial_state_enter(
1039         struct sci_base_object *object)
1040 {
1041         struct scic_sds_remote_node_context *rnc;
1042
1043         rnc = (struct scic_sds_remote_node_context *)object;
1044
1045         SET_STATE_HANDLER(
1046                 rnc,
1047                 scic_sds_remote_node_context_state_handler_table,
1048                 SCIC_SDS_REMOTE_NODE_CONTEXT_INITIAL_STATE
1049                 );
1050
1051         /*
1052          * Check to see if we have gotten back to the initial state because someone
1053          * requested to destroy the remote node context object. */
1054         if (
1055                 rnc->state_machine.previous_state_id
1056                 == SCIC_SDS_REMOTE_NODE_CONTEXT_INVALIDATING_STATE
1057                 ) {
1058                 rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_UNSPECIFIED;
1059
1060                 scic_sds_remote_node_context_notify_user(rnc);
1061         }
1062 }
1063
1064 /**
1065  *
1066  *
1067  *
1068  */
1069 static void scic_sds_remote_node_context_posting_state_enter(
1070         struct sci_base_object *object)
1071 {
1072         struct scic_sds_remote_node_context *this_rnc;
1073
1074         this_rnc = (struct scic_sds_remote_node_context *)object;
1075
1076         SET_STATE_HANDLER(
1077                 this_rnc,
1078                 scic_sds_remote_node_context_state_handler_table,
1079                 SCIC_SDS_REMOTE_NODE_CONTEXT_POSTING_STATE
1080                 );
1081
1082         scic_sds_remote_node_context_validate_context_buffer(this_rnc);
1083 }
1084
1085 /**
1086  *
1087  *
1088  *
1089  */
1090 static void scic_sds_remote_node_context_invalidating_state_enter(
1091         struct sci_base_object *object)
1092 {
1093         struct scic_sds_remote_node_context *rnc;
1094
1095         rnc = (struct scic_sds_remote_node_context *)object;
1096
1097         SET_STATE_HANDLER(
1098                 rnc,
1099                 scic_sds_remote_node_context_state_handler_table,
1100                 SCIC_SDS_REMOTE_NODE_CONTEXT_INVALIDATING_STATE
1101                 );
1102
1103         scic_sds_remote_node_context_invalidate_context_buffer(rnc);
1104 }
1105
1106 /**
1107  *
1108  *
1109  *
1110  */
1111 static void scic_sds_remote_node_context_resuming_state_enter(
1112         struct sci_base_object *object)
1113 {
1114         struct scic_sds_remote_node_context *rnc;
1115
1116         rnc = (struct scic_sds_remote_node_context *)object;
1117
1118         SET_STATE_HANDLER(
1119                 rnc,
1120                 scic_sds_remote_node_context_state_handler_table,
1121                 SCIC_SDS_REMOTE_NODE_CONTEXT_RESUMING_STATE
1122                 );
1123
1124         scic_sds_remote_device_post_request(
1125                 rnc->device,
1126                 SCU_CONTEXT_COMMAND_POST_RNC_RESUME
1127                 );
1128 }
1129
1130 /**
1131  *
1132  *
1133  *
1134  */
1135 static void scic_sds_remote_node_context_ready_state_enter(
1136         struct sci_base_object *object)
1137 {
1138         struct scic_sds_remote_node_context *rnc;
1139
1140         rnc = (struct scic_sds_remote_node_context *)object;
1141
1142         SET_STATE_HANDLER(
1143                 rnc,
1144                 scic_sds_remote_node_context_state_handler_table,
1145                 SCIC_SDS_REMOTE_NODE_CONTEXT_READY_STATE
1146                 );
1147
1148         rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_UNSPECIFIED;
1149
1150         if (rnc->user_callback != NULL) {
1151                 scic_sds_remote_node_context_notify_user(rnc);
1152         }
1153 }
1154
1155 /**
1156  *
1157  *
1158  *
1159  */
1160 static void scic_sds_remote_node_context_tx_suspended_state_enter(
1161         struct sci_base_object *object)
1162 {
1163         struct scic_sds_remote_node_context *rnc;
1164
1165         rnc = (struct scic_sds_remote_node_context *)object;
1166
1167         SET_STATE_HANDLER(
1168                 rnc,
1169                 scic_sds_remote_node_context_state_handler_table,
1170                 SCIC_SDS_REMOTE_NODE_CONTEXT_TX_SUSPENDED_STATE
1171                 );
1172
1173         scic_sds_remote_node_context_continue_state_transitions(rnc);
1174 }
1175
1176 /**
1177  *
1178  *
1179  *
1180  */
1181 static void scic_sds_remote_node_context_tx_rx_suspended_state_enter(
1182         struct sci_base_object *object)
1183 {
1184         struct scic_sds_remote_node_context *rnc;
1185
1186         rnc = (struct scic_sds_remote_node_context *)object;
1187
1188         SET_STATE_HANDLER(
1189                 rnc,
1190                 scic_sds_remote_node_context_state_handler_table,
1191                 SCIC_SDS_REMOTE_NODE_CONTEXT_TX_RX_SUSPENDED_STATE
1192                 );
1193
1194         scic_sds_remote_node_context_continue_state_transitions(rnc);
1195 }
1196
1197 /**
1198  *
1199  *
1200  *
1201  */
1202 static void scic_sds_remote_node_context_await_suspension_state_enter(
1203         struct sci_base_object *object)
1204 {
1205         struct scic_sds_remote_node_context *rnc;
1206
1207         rnc = (struct scic_sds_remote_node_context *)object;
1208
1209         SET_STATE_HANDLER(
1210                 rnc,
1211                 scic_sds_remote_node_context_state_handler_table,
1212                 SCIC_SDS_REMOTE_NODE_CONTEXT_AWAIT_SUSPENSION_STATE
1213                 );
1214 }
1215
1216 /* --------------------------------------------------------------------------- */
1217
1218 const struct sci_base_state scic_sds_remote_node_context_state_table[] = {
1219         [SCIC_SDS_REMOTE_NODE_CONTEXT_INITIAL_STATE] = {
1220                 .enter_state = scic_sds_remote_node_context_initial_state_enter,
1221         },
1222         [SCIC_SDS_REMOTE_NODE_CONTEXT_POSTING_STATE] = {
1223                 .enter_state = scic_sds_remote_node_context_posting_state_enter,
1224         },
1225         [SCIC_SDS_REMOTE_NODE_CONTEXT_INVALIDATING_STATE] = {
1226                 .enter_state = scic_sds_remote_node_context_invalidating_state_enter,
1227         },
1228         [SCIC_SDS_REMOTE_NODE_CONTEXT_RESUMING_STATE] = {
1229                 .enter_state = scic_sds_remote_node_context_resuming_state_enter,
1230         },
1231         [SCIC_SDS_REMOTE_NODE_CONTEXT_READY_STATE] = {
1232                 .enter_state = scic_sds_remote_node_context_ready_state_enter,
1233         },
1234         [SCIC_SDS_REMOTE_NODE_CONTEXT_TX_SUSPENDED_STATE] = {
1235                 .enter_state = scic_sds_remote_node_context_tx_suspended_state_enter,
1236         },
1237         [SCIC_SDS_REMOTE_NODE_CONTEXT_TX_RX_SUSPENDED_STATE] = {
1238                 .enter_state = scic_sds_remote_node_context_tx_rx_suspended_state_enter,
1239         },
1240         [SCIC_SDS_REMOTE_NODE_CONTEXT_AWAIT_SUSPENSION_STATE] = {
1241                 .enter_state = scic_sds_remote_node_context_await_suspension_state_enter,
1242         },
1243 };
1244