drm/ast: Rename AST_IO_DAC_INDEX_WRITE to AST_IO_VGADWR
[linux-block.git] / drivers / scsi / isci / remote_node_context.c
CommitLineData
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 */
c94fc1ad 55#include <scsi/sas_ata.h>
cc9203bf 56#include "host.h"
12ef6544 57#include "isci.h"
88f3b62a
DW
58#include "remote_device.h"
59#include "remote_node_context.h"
6f231dda
DW
60#include "scu_event_codes.h"
61#include "scu_task_context.h"
62
d7a0ccdd
DW
63#undef C
64#define C(a) (#a)
65const char *rnc_state_name(enum scis_sds_remote_node_context_states state)
66{
67 static const char * const strings[] = RNC_STATES;
6f231dda 68
5cfa2a3c
AB
69 if (state >= ARRAY_SIZE(strings))
70 return "UNKNOWN";
71
d7a0ccdd
DW
72 return strings[state];
73}
74#undef C
6f231dda
DW
75
76/**
ad276048 77 * sci_remote_node_context_is_ready()
e2023b87 78 * @sci_rnc: The state of the remote node context object to check.
6f231dda
DW
79 *
80 * This method will return true if the remote node context is in a READY state
81 * otherwise it will return false bool true if the remote node context is in
82 * the ready state. false if the remote node context is not in the ready state.
83 */
89a7301f
DW
84bool sci_remote_node_context_is_ready(
85 struct sci_remote_node_context *sci_rnc)
6f231dda 86{
e301370a 87 u32 current_state = sci_rnc->sm.current_state_id;
6f231dda 88
e301370a 89 if (current_state == SCI_RNC_READY) {
6f231dda
DW
90 return true;
91 }
92
93 return false;
94}
95
31a38ef0
JS
96bool sci_remote_node_context_is_suspended(struct sci_remote_node_context *sci_rnc)
97{
98 u32 current_state = sci_rnc->sm.current_state_id;
99
100 if (current_state == SCI_RNC_TX_RX_SUSPENDED)
101 return true;
102 return false;
103}
104
89a7301f
DW
105static union scu_remote_node_context *sci_rnc_by_id(struct isci_host *ihost, u16 id)
106{
107 if (id < ihost->remote_node_entries &&
108 ihost->device_table[id])
109 return &ihost->remote_node_context_table[id];
110
111 return NULL;
112}
113
114static void sci_remote_node_context_construct_buffer(struct sci_remote_node_context *sci_rnc)
6f231dda 115{
78a6f06e
DW
116 struct isci_remote_device *idev = rnc_to_dev(sci_rnc);
117 struct domain_device *dev = idev->domain_dev;
1f4fa1f9 118 int rni = sci_rnc->remote_node_index;
a1a113b0 119 union scu_remote_node_context *rnc;
d9dcb4ba 120 struct isci_host *ihost;
a3d568f0 121 __le64 sas_addr;
6f231dda 122
34a99158 123 ihost = idev->owning_port->owning_controller;
89a7301f 124 rnc = sci_rnc_by_id(ihost, rni);
6f231dda 125
9614395e 126 memset(rnc, 0, sizeof(union scu_remote_node_context)
89a7301f 127 * sci_remote_device_node_count(idev));
6f231dda 128
1f4fa1f9 129 rnc->ssp.remote_node_index = rni;
78a6f06e
DW
130 rnc->ssp.remote_node_port_width = idev->device_port_width;
131 rnc->ssp.logical_port_index = idev->owning_port->physical_port_index;
6f231dda 132
a3d568f0
DW
133 /* sas address is __be64, context ram format is __le64 */
134 sas_addr = cpu_to_le64(SAS_ADDR(dev->sas_addr));
135 rnc->ssp.remote_sas_address_hi = upper_32_bits(sas_addr);
136 rnc->ssp.remote_sas_address_lo = lower_32_bits(sas_addr);
6f231dda
DW
137
138 rnc->ssp.nexus_loss_timer_enable = true;
139 rnc->ssp.check_bit = false;
140 rnc->ssp.is_valid = false;
141 rnc->ssp.is_remote_node_context = true;
142 rnc->ssp.function_number = 0;
143
144 rnc->ssp.arbitration_wait_time = 0;
145
11cc5183 146 if (dev_is_sata(dev)) {
6f231dda 147 rnc->ssp.connection_occupancy_timeout =
89a7301f 148 ihost->user_parameters.stp_max_occupancy_timeout;
6f231dda 149 rnc->ssp.connection_inactivity_timeout =
89a7301f 150 ihost->user_parameters.stp_inactivity_timeout;
6f231dda
DW
151 } else {
152 rnc->ssp.connection_occupancy_timeout =
89a7301f 153 ihost->user_parameters.ssp_max_occupancy_timeout;
6f231dda 154 rnc->ssp.connection_inactivity_timeout =
89a7301f 155 ihost->user_parameters.ssp_inactivity_timeout;
6f231dda
DW
156 }
157
158 rnc->ssp.initial_arbitration_wait_time = 0;
159
160 /* Open Address Frame Parameters */
78a6f06e 161 rnc->ssp.oaf_connection_rate = idev->connection_rate;
6f231dda
DW
162 rnc->ssp.oaf_features = 0;
163 rnc->ssp.oaf_source_zone_group = 0;
164 rnc->ssp.oaf_more_compatibility_features = 0;
165}
ad276048 166/*
6f231dda
DW
167 * This method will setup the remote node context object so it will transition
168 * to its ready state. If the remote node context is already setup to
169 * transition to its final state then this function does nothing. none
170 */
89a7301f
DW
171static void sci_remote_node_context_setup_to_resume(
172 struct sci_remote_node_context *sci_rnc,
e2023b87 173 scics_sds_remote_node_context_callback callback,
59e35396
JS
174 void *callback_parameter,
175 enum sci_remote_node_context_destination_state dest_param)
6f231dda 176{
59e35396
JS
177 if (sci_rnc->destination_state != RNC_DEST_FINAL) {
178 sci_rnc->destination_state = dest_param;
6c6aacbb
JS
179 if (callback != NULL) {
180 sci_rnc->user_callback = callback;
181 sci_rnc->user_cookie = callback_parameter;
182 }
6f231dda
DW
183 }
184}
185
59e35396 186static void sci_remote_node_context_setup_to_destroy(
89a7301f 187 struct sci_remote_node_context *sci_rnc,
e2023b87 188 scics_sds_remote_node_context_callback callback,
6f231dda
DW
189 void *callback_parameter)
190{
de2eb4d5
JS
191 struct isci_host *ihost = idev_to_ihost(rnc_to_dev(sci_rnc));
192
59e35396 193 sci_rnc->destination_state = RNC_DEST_FINAL;
e2023b87
DJ
194 sci_rnc->user_callback = callback;
195 sci_rnc->user_cookie = callback_parameter;
de2eb4d5
JS
196
197 wake_up(&ihost->eventq);
6f231dda
DW
198}
199
d2d480f1 200/*
6f231dda
DW
201 * This method just calls the user callback function and then resets the
202 * callback.
203 */
89a7301f
DW
204static void sci_remote_node_context_notify_user(
205 struct sci_remote_node_context *rnc)
6f231dda
DW
206{
207 if (rnc->user_callback != NULL) {
208 (*rnc->user_callback)(rnc->user_cookie);
209
210 rnc->user_callback = NULL;
211 rnc->user_cookie = NULL;
212 }
213}
214
89a7301f 215static void sci_remote_node_context_continue_state_transitions(struct sci_remote_node_context *rnc)
6f231dda 216{
79cbab89
JS
217 switch (rnc->destination_state) {
218 case RNC_DEST_READY:
219 case RNC_DEST_SUSPENDED_RESUME:
59e35396 220 rnc->destination_state = RNC_DEST_READY;
df561f66 221 fallthrough;
79cbab89 222 case RNC_DEST_FINAL:
89a7301f 223 sci_remote_node_context_resume(rnc, rnc->user_callback,
79cbab89
JS
224 rnc->user_cookie);
225 break;
226 default:
59e35396 227 rnc->destination_state = RNC_DEST_UNSPECIFIED;
79cbab89
JS
228 break;
229 }
6f231dda
DW
230}
231
89a7301f 232static void sci_remote_node_context_validate_context_buffer(struct sci_remote_node_context *sci_rnc)
6f231dda 233{
89a7301f 234 union scu_remote_node_context *rnc_buffer;
78a6f06e
DW
235 struct isci_remote_device *idev = rnc_to_dev(sci_rnc);
236 struct domain_device *dev = idev->domain_dev;
89a7301f 237 struct isci_host *ihost = idev->owning_port->owning_controller;
6f231dda 238
89a7301f 239 rnc_buffer = sci_rnc_by_id(ihost, sci_rnc->remote_node_index);
6f231dda
DW
240
241 rnc_buffer->ssp.is_valid = true;
242
11cc5183 243 if (dev_is_sata(dev) && dev->parent) {
89a7301f 244 sci_remote_device_post_request(idev, SCU_CONTEXT_COMMAND_POST_RNC_96);
6f231dda 245 } else {
89a7301f 246 sci_remote_device_post_request(idev, SCU_CONTEXT_COMMAND_POST_RNC_32);
6f231dda 247
11cc5183 248 if (!dev->parent)
89a7301f
DW
249 sci_port_setup_transports(idev->owning_port,
250 sci_rnc->remote_node_index);
6f231dda
DW
251 }
252}
253
89a7301f 254static void sci_remote_node_context_invalidate_context_buffer(struct sci_remote_node_context *sci_rnc)
6f231dda
DW
255{
256 union scu_remote_node_context *rnc_buffer;
89a7301f
DW
257 struct isci_remote_device *idev = rnc_to_dev(sci_rnc);
258 struct isci_host *ihost = idev->owning_port->owning_controller;
6f231dda 259
89a7301f 260 rnc_buffer = sci_rnc_by_id(ihost, sci_rnc->remote_node_index);
6f231dda
DW
261
262 rnc_buffer->ssp.is_valid = false;
263
89a7301f
DW
264 sci_remote_device_post_request(rnc_to_dev(sci_rnc),
265 SCU_CONTEXT_COMMAND_POST_RNC_INVALIDATE);
6f231dda
DW
266}
267
89a7301f 268static void sci_remote_node_context_initial_state_enter(struct sci_base_state_machine *sm)
6f231dda 269{
89a7301f 270 struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm);
1f053889
JS
271 struct isci_remote_device *idev = rnc_to_dev(rnc);
272 struct isci_host *ihost = idev->owning_port->owning_controller;
6f231dda 273
f34d9e5d
DW
274 /* Check to see if we have gotten back to the initial state because
275 * someone requested to destroy the remote node context object.
276 */
e301370a 277 if (sm->previous_state_id == SCI_RNC_INVALIDATING) {
59e35396 278 rnc->destination_state = RNC_DEST_UNSPECIFIED;
89a7301f 279 sci_remote_node_context_notify_user(rnc);
1f053889
JS
280
281 smp_wmb();
282 wake_up(&ihost->eventq);
6f231dda
DW
283 }
284}
285
89a7301f 286static void sci_remote_node_context_posting_state_enter(struct sci_base_state_machine *sm)
6f231dda 287{
89a7301f 288 struct sci_remote_node_context *sci_rnc = container_of(sm, typeof(*sci_rnc), sm);
6f231dda 289
89a7301f 290 sci_remote_node_context_validate_context_buffer(sci_rnc);
6f231dda
DW
291}
292
89a7301f 293static void sci_remote_node_context_invalidating_state_enter(struct sci_base_state_machine *sm)
6f231dda 294{
89a7301f 295 struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm);
6f231dda 296
aa20d934
JS
297 /* Terminate all outstanding requests. */
298 sci_remote_device_terminate_requests(rnc_to_dev(rnc));
89a7301f 299 sci_remote_node_context_invalidate_context_buffer(rnc);
6f231dda
DW
300}
301
89a7301f 302static void sci_remote_node_context_resuming_state_enter(struct sci_base_state_machine *sm)
6f231dda 303{
89a7301f 304 struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm);
78a6f06e 305 struct isci_remote_device *idev;
a1a113b0 306 struct domain_device *dev;
6f231dda 307
78a6f06e
DW
308 idev = rnc_to_dev(rnc);
309 dev = idev->domain_dev;
6f231dda 310
24621466
HD
311 /*
312 * For direct attached SATA devices we need to clear the TLCR
313 * NCQ to TCi tag mapping on the phy and in cases where we
314 * resume because of a target reset we also need to update
315 * the STPTLDARNI register with the RNi of the device
316 */
11cc5183
DW
317 if (dev_is_sata(dev) && !dev->parent)
318 sci_port_setup_transports(idev->owning_port, rnc->remote_node_index);
24621466 319
89a7301f 320 sci_remote_device_post_request(idev, SCU_CONTEXT_COMMAND_POST_RNC_RESUME);
6f231dda
DW
321}
322
89a7301f 323static void sci_remote_node_context_ready_state_enter(struct sci_base_state_machine *sm)
6f231dda 324{
89a7301f 325 struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm);
59e35396 326 enum sci_remote_node_context_destination_state dest_select;
59e35396
JS
327 int tell_user = 1;
328
329 dest_select = rnc->destination_state;
330 rnc->destination_state = RNC_DEST_UNSPECIFIED;
331
332 if ((dest_select == RNC_DEST_SUSPENDED) ||
333 (dest_select == RNC_DEST_SUSPENDED_RESUME)) {
334 sci_remote_node_context_suspend(
447bfbce
JS
335 rnc, rnc->suspend_reason,
336 SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT);
59e35396 337
d76689e4 338 if (dest_select == RNC_DEST_SUSPENDED_RESUME)
59e35396 339 tell_user = 0; /* Wait until ready again. */
59e35396 340 }
d76689e4 341 if (tell_user)
89a7301f 342 sci_remote_node_context_notify_user(rnc);
6f231dda
DW
343}
344
89a7301f 345static void sci_remote_node_context_tx_suspended_state_enter(struct sci_base_state_machine *sm)
6f231dda 346{
89a7301f 347 struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm);
6f231dda 348
89a7301f 349 sci_remote_node_context_continue_state_transitions(rnc);
6f231dda
DW
350}
351
89a7301f 352static void sci_remote_node_context_tx_rx_suspended_state_enter(struct sci_base_state_machine *sm)
6f231dda 353{
89a7301f 354 struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm);
726980d5
JS
355 struct isci_remote_device *idev = rnc_to_dev(rnc);
356 struct isci_host *ihost = idev->owning_port->owning_controller;
31a38ef0
JS
357 u32 new_count = rnc->suspend_count + 1;
358
359 if (new_count == 0)
360 rnc->suspend_count = 1;
361 else
362 rnc->suspend_count = new_count;
363 smp_wmb();
726980d5 364
726980d5
JS
365 /* Terminate outstanding requests pending abort. */
366 sci_remote_device_abort_requests_pending_abort(idev);
367
368 wake_up(&ihost->eventq);
89a7301f 369 sci_remote_node_context_continue_state_transitions(rnc);
6f231dda
DW
370}
371
6f48844e
JS
372static void sci_remote_node_context_await_suspend_state_exit(
373 struct sci_base_state_machine *sm)
374{
375 struct sci_remote_node_context *rnc
376 = container_of(sm, typeof(*rnc), sm);
c94fc1ad 377 struct isci_remote_device *idev = rnc_to_dev(rnc);
6f48844e 378
c94fc1ad
JS
379 if (dev_is_sata(idev->domain_dev))
380 isci_dev_set_hang_detection_timeout(idev, 0);
6f48844e
JS
381}
382
89a7301f 383static const struct sci_base_state sci_remote_node_context_state_table[] = {
e301370a 384 [SCI_RNC_INITIAL] = {
89a7301f 385 .enter_state = sci_remote_node_context_initial_state_enter,
6f231dda 386 },
e301370a 387 [SCI_RNC_POSTING] = {
89a7301f 388 .enter_state = sci_remote_node_context_posting_state_enter,
6f231dda 389 },
e301370a 390 [SCI_RNC_INVALIDATING] = {
89a7301f 391 .enter_state = sci_remote_node_context_invalidating_state_enter,
6f231dda 392 },
e301370a 393 [SCI_RNC_RESUMING] = {
89a7301f 394 .enter_state = sci_remote_node_context_resuming_state_enter,
6f231dda 395 },
e301370a 396 [SCI_RNC_READY] = {
89a7301f 397 .enter_state = sci_remote_node_context_ready_state_enter,
6f231dda 398 },
e301370a 399 [SCI_RNC_TX_SUSPENDED] = {
89a7301f 400 .enter_state = sci_remote_node_context_tx_suspended_state_enter,
6f231dda 401 },
e301370a 402 [SCI_RNC_TX_RX_SUSPENDED] = {
89a7301f 403 .enter_state = sci_remote_node_context_tx_rx_suspended_state_enter,
6f231dda 404 },
6f48844e
JS
405 [SCI_RNC_AWAIT_SUSPENSION] = {
406 .exit_state = sci_remote_node_context_await_suspend_state_exit,
407 },
6f231dda
DW
408};
409
89a7301f 410void sci_remote_node_context_construct(struct sci_remote_node_context *rnc,
9614395e 411 u16 remote_node_index)
35173d57 412{
89a7301f 413 memset(rnc, 0, sizeof(struct sci_remote_node_context));
35173d57
DW
414
415 rnc->remote_node_index = remote_node_index;
59e35396 416 rnc->destination_state = RNC_DEST_UNSPECIFIED;
35173d57 417
89a7301f 418 sci_init_sm(&rnc->sm, sci_remote_node_context_state_table, SCI_RNC_INITIAL);
35173d57 419}
338e386d 420
89a7301f 421enum sci_status sci_remote_node_context_event_handler(struct sci_remote_node_context *sci_rnc,
338e386d
DW
422 u32 event_code)
423{
424 enum scis_sds_remote_node_context_states state;
ac78ed0f 425 u32 next_state;
338e386d 426
e301370a 427 state = sci_rnc->sm.current_state_id;
338e386d 428 switch (state) {
e301370a 429 case SCI_RNC_POSTING:
338e386d
DW
430 switch (scu_get_event_code(event_code)) {
431 case SCU_EVENT_POST_RNC_COMPLETE:
e301370a 432 sci_change_state(&sci_rnc->sm, SCI_RNC_READY);
338e386d
DW
433 break;
434 default:
435 goto out;
436 }
437 break;
e301370a 438 case SCI_RNC_INVALIDATING:
338e386d 439 if (scu_get_event_code(event_code) == SCU_EVENT_POST_RNC_INVALIDATE_COMPLETE) {
59e35396
JS
440 if (sci_rnc->destination_state == RNC_DEST_FINAL)
441 next_state = SCI_RNC_INITIAL;
338e386d 442 else
59e35396
JS
443 next_state = SCI_RNC_POSTING;
444 sci_change_state(&sci_rnc->sm, next_state);
338e386d
DW
445 } else {
446 switch (scu_get_event_type(event_code)) {
447 case SCU_EVENT_TYPE_RNC_SUSPEND_TX:
448 case SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX:
449 /* We really dont care if the hardware is going to suspend
450 * the device since it's being invalidated anyway */
8c731888 451 dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
338e386d 452 "%s: SCIC Remote Node Context 0x%p was "
99c7b6ae 453 "suspended by hardware while being "
338e386d
DW
454 "invalidated.\n", __func__, sci_rnc);
455 break;
456 default:
457 goto out;
458 }
459 }
460 break;
e301370a 461 case SCI_RNC_RESUMING:
338e386d 462 if (scu_get_event_code(event_code) == SCU_EVENT_POST_RCN_RELEASE) {
e301370a 463 sci_change_state(&sci_rnc->sm, SCI_RNC_READY);
338e386d
DW
464 } else {
465 switch (scu_get_event_type(event_code)) {
466 case SCU_EVENT_TYPE_RNC_SUSPEND_TX:
467 case SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX:
468 /* We really dont care if the hardware is going to suspend
469 * the device since it's being resumed anyway */
8c731888 470 dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
338e386d 471 "%s: SCIC Remote Node Context 0x%p was "
99c7b6ae 472 "suspended by hardware while being resumed.\n",
338e386d
DW
473 __func__, sci_rnc);
474 break;
475 default:
476 goto out;
477 }
478 }
479 break;
e301370a 480 case SCI_RNC_READY:
338e386d
DW
481 switch (scu_get_event_type(event_code)) {
482 case SCU_EVENT_TL_RNC_SUSPEND_TX:
e301370a 483 sci_change_state(&sci_rnc->sm, SCI_RNC_TX_SUSPENDED);
ac78ed0f 484 sci_rnc->suspend_type = scu_get_event_type(event_code);
338e386d
DW
485 break;
486 case SCU_EVENT_TL_RNC_SUSPEND_TX_RX:
e301370a 487 sci_change_state(&sci_rnc->sm, SCI_RNC_TX_RX_SUSPENDED);
ac78ed0f 488 sci_rnc->suspend_type = scu_get_event_type(event_code);
338e386d
DW
489 break;
490 default:
491 goto out;
492 }
493 break;
e301370a 494 case SCI_RNC_AWAIT_SUSPENSION:
338e386d
DW
495 switch (scu_get_event_type(event_code)) {
496 case SCU_EVENT_TL_RNC_SUSPEND_TX:
ac78ed0f 497 next_state = SCI_RNC_TX_SUSPENDED;
338e386d
DW
498 break;
499 case SCU_EVENT_TL_RNC_SUSPEND_TX_RX:
ac78ed0f 500 next_state = SCI_RNC_TX_RX_SUSPENDED;
338e386d
DW
501 break;
502 default:
503 goto out;
504 }
ac78ed0f
JS
505 if (sci_rnc->suspend_type == scu_get_event_type(event_code))
506 sci_change_state(&sci_rnc->sm, next_state);
338e386d
DW
507 break;
508 default:
509 dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
14e99b4a
DW
510 "%s: invalid state: %s\n", __func__,
511 rnc_state_name(state));
338e386d
DW
512 return SCI_FAILURE_INVALID_STATE;
513 }
514 return SCI_SUCCESS;
515
516 out:
517 dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
14e99b4a
DW
518 "%s: code: %#x state: %s\n", __func__, event_code,
519 rnc_state_name(state));
338e386d
DW
520 return SCI_FAILURE;
521
522}
c845ae96 523
89a7301f 524enum sci_status sci_remote_node_context_destruct(struct sci_remote_node_context *sci_rnc,
c845ae96
DW
525 scics_sds_remote_node_context_callback cb_fn,
526 void *cb_p)
527{
528 enum scis_sds_remote_node_context_states state;
529
e301370a 530 state = sci_rnc->sm.current_state_id;
c845ae96 531 switch (state) {
e301370a 532 case SCI_RNC_INVALIDATING:
59e35396 533 sci_remote_node_context_setup_to_destroy(sci_rnc, cb_fn, cb_p);
c845ae96 534 return SCI_SUCCESS;
e301370a
EN
535 case SCI_RNC_POSTING:
536 case SCI_RNC_RESUMING:
537 case SCI_RNC_READY:
538 case SCI_RNC_TX_SUSPENDED:
539 case SCI_RNC_TX_RX_SUSPENDED:
59e35396 540 sci_remote_node_context_setup_to_destroy(sci_rnc, cb_fn, cb_p);
e301370a 541 sci_change_state(&sci_rnc->sm, SCI_RNC_INVALIDATING);
c845ae96 542 return SCI_SUCCESS;
79cbab89
JS
543 case SCI_RNC_AWAIT_SUSPENSION:
544 sci_remote_node_context_setup_to_destroy(sci_rnc, cb_fn, cb_p);
545 return SCI_SUCCESS;
e301370a 546 case SCI_RNC_INITIAL:
c845ae96 547 dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
14e99b4a
DW
548 "%s: invalid state: %s\n", __func__,
549 rnc_state_name(state));
c845ae96
DW
550 /* We have decided that the destruct request on the remote node context
551 * can not fail since it is either in the initial/destroyed state or is
552 * can be destroyed.
553 */
554 return SCI_SUCCESS;
555 default:
556 dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
14e99b4a
DW
557 "%s: invalid state %s\n", __func__,
558 rnc_state_name(state));
c845ae96
DW
559 return SCI_FAILURE_INVALID_STATE;
560 }
561}
ed3efb77 562
ac78ed0f
JS
563enum sci_status sci_remote_node_context_suspend(
564 struct sci_remote_node_context *sci_rnc,
565 enum sci_remote_node_suspension_reasons suspend_reason,
447bfbce 566 u32 suspend_type)
ed3efb77 567{
ac78ed0f
JS
568 enum scis_sds_remote_node_context_states state
569 = sci_rnc->sm.current_state_id;
570 struct isci_remote_device *idev = rnc_to_dev(sci_rnc);
571 enum sci_status status = SCI_FAILURE_INVALID_STATE;
59e35396
JS
572 enum sci_remote_node_context_destination_state dest_param =
573 RNC_DEST_UNSPECIFIED;
ed3efb77 574
726980d5 575 dev_dbg(scirdev_to_dev(idev),
8c731888 576 "%s: current state %s, current suspend_type %x dest state %d,"
726980d5 577 " arg suspend_reason %d, arg suspend_type %x",
8c731888 578 __func__, rnc_state_name(state), sci_rnc->suspend_type,
726980d5
JS
579 sci_rnc->destination_state, suspend_reason,
580 suspend_type);
581
ac78ed0f 582 /* Disable automatic state continuations if explicitly suspending. */
c94fc1ad 583 if ((suspend_reason == SCI_HW_SUSPEND) ||
59e35396
JS
584 (sci_rnc->destination_state == RNC_DEST_FINAL))
585 dest_param = sci_rnc->destination_state;
586
ac78ed0f
JS
587 switch (state) {
588 case SCI_RNC_READY:
589 break;
59e35396
JS
590 case SCI_RNC_INVALIDATING:
591 if (sci_rnc->destination_state == RNC_DEST_FINAL) {
592 dev_warn(scirdev_to_dev(idev),
593 "%s: already destroying %p\n",
594 __func__, sci_rnc);
595 return SCI_FAILURE_INVALID_STATE;
596 }
df561f66 597 fallthrough; /* and handle like SCI_RNC_POSTING */
d76689e4 598 case SCI_RNC_RESUMING:
df561f66 599 fallthrough; /* and handle like SCI_RNC_POSTING */
59e35396
JS
600 case SCI_RNC_POSTING:
601 /* Set the destination state to AWAIT - this signals the
602 * entry into the SCI_RNC_READY state that a suspension
603 * needs to be done immediately.
604 */
6c6aacbb
JS
605 if (sci_rnc->destination_state != RNC_DEST_FINAL)
606 sci_rnc->destination_state = RNC_DEST_SUSPENDED;
447bfbce
JS
607 sci_rnc->suspend_type = suspend_type;
608 sci_rnc->suspend_reason = suspend_reason;
59e35396
JS
609 return SCI_SUCCESS;
610
ac78ed0f
JS
611 case SCI_RNC_TX_SUSPENDED:
612 if (suspend_type == SCU_EVENT_TL_RNC_SUSPEND_TX)
613 status = SCI_SUCCESS;
614 break;
615 case SCI_RNC_TX_RX_SUSPENDED:
616 if (suspend_type == SCU_EVENT_TL_RNC_SUSPEND_TX_RX)
617 status = SCI_SUCCESS;
618 break;
619 case SCI_RNC_AWAIT_SUSPENSION:
620 if ((sci_rnc->suspend_type == SCU_EVENT_TL_RNC_SUSPEND_TX_RX)
621 || (suspend_type == sci_rnc->suspend_type))
622 return SCI_SUCCESS;
623 break;
624 default:
ed3efb77 625 dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
14e99b4a
DW
626 "%s: invalid state %s\n", __func__,
627 rnc_state_name(state));
ed3efb77
DW
628 return SCI_FAILURE_INVALID_STATE;
629 }
59e35396 630 sci_rnc->destination_state = dest_param;
447bfbce
JS
631 sci_rnc->suspend_type = suspend_type;
632 sci_rnc->suspend_reason = suspend_reason;
ed3efb77 633
ac78ed0f 634 if (status == SCI_SUCCESS) { /* Already in the destination state? */
726980d5
JS
635 struct isci_host *ihost = idev->owning_port->owning_controller;
636
726980d5 637 wake_up_all(&ihost->eventq); /* Let observers look. */
ac78ed0f
JS
638 return SCI_SUCCESS;
639 }
c94fc1ad
JS
640 if ((suspend_reason == SCI_SW_SUSPEND_NORMAL) ||
641 (suspend_reason == SCI_SW_SUSPEND_LINKHANG_DETECT)) {
642
9608b640 643 if (suspend_reason == SCI_SW_SUSPEND_LINKHANG_DETECT)
c94fc1ad
JS
644 isci_dev_set_hang_detection_timeout(idev, 0x00000001);
645
ac78ed0f
JS
646 sci_remote_device_post_request(
647 idev, SCI_SOFTWARE_SUSPEND_CMD);
ed3efb77 648 }
ac78ed0f
JS
649 if (state != SCI_RNC_AWAIT_SUSPENSION)
650 sci_change_state(&sci_rnc->sm, SCI_RNC_AWAIT_SUSPENSION);
ed3efb77 651
ed3efb77
DW
652 return SCI_SUCCESS;
653}
654
89a7301f 655enum sci_status sci_remote_node_context_resume(struct sci_remote_node_context *sci_rnc,
ed3efb77
DW
656 scics_sds_remote_node_context_callback cb_fn,
657 void *cb_p)
658{
659 enum scis_sds_remote_node_context_states state;
0c3ce38f 660 struct isci_remote_device *idev = rnc_to_dev(sci_rnc);
ed3efb77 661
e301370a 662 state = sci_rnc->sm.current_state_id;
0c3ce38f
JS
663 dev_dbg(scirdev_to_dev(idev),
664 "%s: state %s, cb_fn = %p, cb_p = %p; dest_state = %d; "
665 "dev resume path %s\n",
666 __func__, rnc_state_name(state), cb_fn, cb_p,
667 sci_rnc->destination_state,
668 test_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags)
669 ? "<abort active>" : "<normal>");
31a38ef0 670
ed3efb77 671 switch (state) {
e301370a 672 case SCI_RNC_INITIAL:
ed3efb77
DW
673 if (sci_rnc->remote_node_index == SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX)
674 return SCI_FAILURE_INVALID_STATE;
675
6c6aacbb
JS
676 sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p,
677 RNC_DEST_READY);
678 if (!test_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags)) {
0c3ce38f
JS
679 sci_remote_node_context_construct_buffer(sci_rnc);
680 sci_change_state(&sci_rnc->sm, SCI_RNC_POSTING);
681 }
ed3efb77 682 return SCI_SUCCESS;
0c3ce38f 683
e301370a
EN
684 case SCI_RNC_POSTING:
685 case SCI_RNC_INVALIDATING:
686 case SCI_RNC_RESUMING:
6c6aacbb
JS
687 /* We are still waiting to post when a resume was
688 * requested.
689 */
690 switch (sci_rnc->destination_state) {
691 case RNC_DEST_SUSPENDED:
692 case RNC_DEST_SUSPENDED_RESUME:
693 /* Previously waiting to suspend after posting.
694 * Now continue onto resumption.
59e35396 695 */
6c6aacbb
JS
696 sci_remote_node_context_setup_to_resume(
697 sci_rnc, cb_fn, cb_p,
698 RNC_DEST_SUSPENDED_RESUME);
699 break;
700 default:
701 sci_remote_node_context_setup_to_resume(
702 sci_rnc, cb_fn, cb_p,
703 RNC_DEST_READY);
704 break;
59e35396 705 }
ed3efb77 706 return SCI_SUCCESS;
0c3ce38f 707
56d7c013 708 case SCI_RNC_TX_SUSPENDED:
0c3ce38f 709 case SCI_RNC_TX_RX_SUSPENDED:
6c6aacbb 710 {
0c3ce38f
JS
711 struct domain_device *dev = idev->domain_dev;
712 /* If this is an expander attached SATA device we must
713 * invalidate and repost the RNC since this is the only
714 * way to clear the TCi to NCQ tag mapping table for
715 * the RNi. All other device types we can just resume.
716 */
717 sci_remote_node_context_setup_to_resume(
718 sci_rnc, cb_fn, cb_p, RNC_DEST_READY);
ed3efb77 719
6c6aacbb
JS
720 if (!test_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags)) {
721 if ((dev_is_sata(dev) && dev->parent) ||
722 (sci_rnc->destination_state == RNC_DEST_FINAL))
723 sci_change_state(&sci_rnc->sm,
724 SCI_RNC_INVALIDATING);
725 else
726 sci_change_state(&sci_rnc->sm,
727 SCI_RNC_RESUMING);
728 }
0c3ce38f 729 }
ed3efb77 730 return SCI_SUCCESS;
0c3ce38f 731
e301370a 732 case SCI_RNC_AWAIT_SUSPENSION:
6c6aacbb
JS
733 sci_remote_node_context_setup_to_resume(
734 sci_rnc, cb_fn, cb_p, RNC_DEST_SUSPENDED_RESUME);
ed3efb77
DW
735 return SCI_SUCCESS;
736 default:
737 dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
14e99b4a
DW
738 "%s: invalid state %s\n", __func__,
739 rnc_state_name(state));
ed3efb77
DW
740 return SCI_FAILURE_INVALID_STATE;
741 }
742}
f34d9e5d 743
89a7301f 744enum sci_status sci_remote_node_context_start_io(struct sci_remote_node_context *sci_rnc,
5076a1a9 745 struct isci_request *ireq)
f34d9e5d
DW
746{
747 enum scis_sds_remote_node_context_states state;
748
e301370a 749 state = sci_rnc->sm.current_state_id;
fd536601
JS
750
751 switch (state) {
752 case SCI_RNC_READY:
753 return SCI_SUCCESS;
754 case SCI_RNC_TX_SUSPENDED:
755 case SCI_RNC_TX_RX_SUSPENDED:
756 case SCI_RNC_AWAIT_SUSPENSION:
f34d9e5d 757 dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
14e99b4a
DW
758 "%s: invalid state %s\n", __func__,
759 rnc_state_name(state));
f34d9e5d 760 return SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED;
fd536601 761 default:
14e99b4a
DW
762 dev_dbg(scirdev_to_dev(rnc_to_dev(sci_rnc)),
763 "%s: invalid state %s\n", __func__,
764 rnc_state_name(state));
765 return SCI_FAILURE_INVALID_STATE;
f34d9e5d 766 }
f34d9e5d
DW
767}
768
14aaa9f0
JS
769enum sci_status sci_remote_node_context_start_task(
770 struct sci_remote_node_context *sci_rnc,
771 struct isci_request *ireq,
772 scics_sds_remote_node_context_callback cb_fn,
773 void *cb_p)
f34d9e5d 774{
59e35396
JS
775 enum sci_status status = sci_remote_node_context_resume(sci_rnc,
776 cb_fn, cb_p);
777 if (status != SCI_SUCCESS)
f34d9e5d 778 dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
59e35396
JS
779 "%s: resume failed: %d\n", __func__, status);
780 return status;
f34d9e5d 781}
726980d5
JS
782
783int sci_remote_node_context_is_safe_to_abort(
784 struct sci_remote_node_context *sci_rnc)
785{
786 enum scis_sds_remote_node_context_states state;
787
788 state = sci_rnc->sm.current_state_id;
789 switch (state) {
790 case SCI_RNC_INVALIDATING:
791 case SCI_RNC_TX_RX_SUSPENDED:
792 return 1;
793 case SCI_RNC_POSTING:
794 case SCI_RNC_RESUMING:
795 case SCI_RNC_READY:
796 case SCI_RNC_TX_SUSPENDED:
797 case SCI_RNC_AWAIT_SUSPENSION:
798 case SCI_RNC_INITIAL:
799 return 0;
800 default:
801 dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
802 "%s: invalid state %d\n", __func__, state);
803 return 0;
804 }
805}