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