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