806 lines · c
1/*2 * This file is provided under a dual BSD/GPLv2 license. When using or3 * redistributing this file, you may do so under either license.4 *5 * GPL LICENSE SUMMARY6 *7 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.8 *9 * This program is free software; you can redistribute it and/or modify10 * it under the terms of version 2 of the GNU General Public License as11 * published by the Free Software Foundation.12 *13 * This program is distributed in the hope that it will be useful, but14 * WITHOUT ANY WARRANTY; without even the implied warranty of15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU16 * General Public License for more details.17 *18 * You should have received a copy of the GNU General Public License19 * along with this program; if not, write to the Free Software20 * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.21 * The full GNU General Public License is included in this distribution22 * in the file called LICENSE.GPL.23 *24 * BSD LICENSE25 *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 without30 * modification, are permitted provided that the following conditions31 * are met:32 *33 * * Redistributions of source code must retain the above copyright34 * notice, this list of conditions and the following disclaimer.35 * * Redistributions in binary form must reproduce the above copyright36 * notice, this list of conditions and the following disclaimer in37 * the documentation and/or other materials provided with the38 * distribution.39 * * Neither the name of Intel Corporation nor the names of its40 * contributors may be used to endorse or promote products derived41 * from this software without specific prior written permission.42 *43 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS44 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT45 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR46 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT47 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,48 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT49 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,50 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY51 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT52 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE53 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.54 */55#include <scsi/sas_ata.h>56#include "host.h"57#include "isci.h"58#include "remote_device.h"59#include "remote_node_context.h"60#include "scu_event_codes.h"61#include "scu_task_context.h"62 63#undef C64#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;68 69 if (state >= ARRAY_SIZE(strings))70 return "UNKNOWN";71 72 return strings[state];73}74#undef C75 76/**77 * sci_remote_node_context_is_ready()78 * @sci_rnc: The state of the remote node context object to check.79 *80 * This method will return true if the remote node context is in a READY state81 * otherwise it will return false bool true if the remote node context is in82 * the ready state. false if the remote node context is not in the ready state.83 */84bool sci_remote_node_context_is_ready(85 struct sci_remote_node_context *sci_rnc)86{87 u32 current_state = sci_rnc->sm.current_state_id;88 89 if (current_state == SCI_RNC_READY) {90 return true;91 }92 93 return false;94}95 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 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)115{116 struct isci_remote_device *idev = rnc_to_dev(sci_rnc);117 struct domain_device *dev = idev->domain_dev;118 int rni = sci_rnc->remote_node_index;119 union scu_remote_node_context *rnc;120 struct isci_host *ihost;121 __le64 sas_addr;122 123 ihost = idev->owning_port->owning_controller;124 rnc = sci_rnc_by_id(ihost, rni);125 126 memset(rnc, 0, sizeof(union scu_remote_node_context)127 * sci_remote_device_node_count(idev));128 129 rnc->ssp.remote_node_index = rni;130 rnc->ssp.remote_node_port_width = idev->device_port_width;131 rnc->ssp.logical_port_index = idev->owning_port->physical_port_index;132 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);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 146 if (dev_is_sata(dev)) {147 rnc->ssp.connection_occupancy_timeout =148 ihost->user_parameters.stp_max_occupancy_timeout;149 rnc->ssp.connection_inactivity_timeout =150 ihost->user_parameters.stp_inactivity_timeout;151 } else {152 rnc->ssp.connection_occupancy_timeout =153 ihost->user_parameters.ssp_max_occupancy_timeout;154 rnc->ssp.connection_inactivity_timeout =155 ihost->user_parameters.ssp_inactivity_timeout;156 }157 158 rnc->ssp.initial_arbitration_wait_time = 0;159 160 /* Open Address Frame Parameters */161 rnc->ssp.oaf_connection_rate = idev->connection_rate;162 rnc->ssp.oaf_features = 0;163 rnc->ssp.oaf_source_zone_group = 0;164 rnc->ssp.oaf_more_compatibility_features = 0;165}166/*167 * This method will setup the remote node context object so it will transition168 * to its ready state. If the remote node context is already setup to169 * transition to its final state then this function does nothing. none170 */171static void sci_remote_node_context_setup_to_resume(172 struct sci_remote_node_context *sci_rnc,173 scics_sds_remote_node_context_callback callback,174 void *callback_parameter,175 enum sci_remote_node_context_destination_state dest_param)176{177 if (sci_rnc->destination_state != RNC_DEST_FINAL) {178 sci_rnc->destination_state = dest_param;179 if (callback != NULL) {180 sci_rnc->user_callback = callback;181 sci_rnc->user_cookie = callback_parameter;182 }183 }184}185 186static void sci_remote_node_context_setup_to_destroy(187 struct sci_remote_node_context *sci_rnc,188 scics_sds_remote_node_context_callback callback,189 void *callback_parameter)190{191 struct isci_host *ihost = idev_to_ihost(rnc_to_dev(sci_rnc));192 193 sci_rnc->destination_state = RNC_DEST_FINAL;194 sci_rnc->user_callback = callback;195 sci_rnc->user_cookie = callback_parameter;196 197 wake_up(&ihost->eventq);198}199 200/*201 * This method just calls the user callback function and then resets the202 * callback.203 */204static void sci_remote_node_context_notify_user(205 struct sci_remote_node_context *rnc)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 215static void sci_remote_node_context_continue_state_transitions(struct sci_remote_node_context *rnc)216{217 switch (rnc->destination_state) {218 case RNC_DEST_READY:219 case RNC_DEST_SUSPENDED_RESUME:220 rnc->destination_state = RNC_DEST_READY;221 fallthrough;222 case RNC_DEST_FINAL:223 sci_remote_node_context_resume(rnc, rnc->user_callback,224 rnc->user_cookie);225 break;226 default:227 rnc->destination_state = RNC_DEST_UNSPECIFIED;228 break;229 }230}231 232static void sci_remote_node_context_validate_context_buffer(struct sci_remote_node_context *sci_rnc)233{234 union scu_remote_node_context *rnc_buffer;235 struct isci_remote_device *idev = rnc_to_dev(sci_rnc);236 struct domain_device *dev = idev->domain_dev;237 struct isci_host *ihost = idev->owning_port->owning_controller;238 239 rnc_buffer = sci_rnc_by_id(ihost, sci_rnc->remote_node_index);240 241 rnc_buffer->ssp.is_valid = true;242 243 if (dev_is_sata(dev) && dev->parent) {244 sci_remote_device_post_request(idev, SCU_CONTEXT_COMMAND_POST_RNC_96);245 } else {246 sci_remote_device_post_request(idev, SCU_CONTEXT_COMMAND_POST_RNC_32);247 248 if (!dev->parent)249 sci_port_setup_transports(idev->owning_port,250 sci_rnc->remote_node_index);251 }252}253 254static void sci_remote_node_context_invalidate_context_buffer(struct sci_remote_node_context *sci_rnc)255{256 union scu_remote_node_context *rnc_buffer;257 struct isci_remote_device *idev = rnc_to_dev(sci_rnc);258 struct isci_host *ihost = idev->owning_port->owning_controller;259 260 rnc_buffer = sci_rnc_by_id(ihost, sci_rnc->remote_node_index);261 262 rnc_buffer->ssp.is_valid = false;263 264 sci_remote_device_post_request(rnc_to_dev(sci_rnc),265 SCU_CONTEXT_COMMAND_POST_RNC_INVALIDATE);266}267 268static void sci_remote_node_context_initial_state_enter(struct sci_base_state_machine *sm)269{270 struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm);271 struct isci_remote_device *idev = rnc_to_dev(rnc);272 struct isci_host *ihost = idev->owning_port->owning_controller;273 274 /* Check to see if we have gotten back to the initial state because275 * someone requested to destroy the remote node context object.276 */277 if (sm->previous_state_id == SCI_RNC_INVALIDATING) {278 rnc->destination_state = RNC_DEST_UNSPECIFIED;279 sci_remote_node_context_notify_user(rnc);280 281 smp_wmb();282 wake_up(&ihost->eventq);283 }284}285 286static void sci_remote_node_context_posting_state_enter(struct sci_base_state_machine *sm)287{288 struct sci_remote_node_context *sci_rnc = container_of(sm, typeof(*sci_rnc), sm);289 290 sci_remote_node_context_validate_context_buffer(sci_rnc);291}292 293static void sci_remote_node_context_invalidating_state_enter(struct sci_base_state_machine *sm)294{295 struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm);296 297 /* Terminate all outstanding requests. */298 sci_remote_device_terminate_requests(rnc_to_dev(rnc));299 sci_remote_node_context_invalidate_context_buffer(rnc);300}301 302static void sci_remote_node_context_resuming_state_enter(struct sci_base_state_machine *sm)303{304 struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm);305 struct isci_remote_device *idev;306 struct domain_device *dev;307 308 idev = rnc_to_dev(rnc);309 dev = idev->domain_dev;310 311 /*312 * For direct attached SATA devices we need to clear the TLCR313 * NCQ to TCi tag mapping on the phy and in cases where we314 * resume because of a target reset we also need to update315 * the STPTLDARNI register with the RNi of the device316 */317 if (dev_is_sata(dev) && !dev->parent)318 sci_port_setup_transports(idev->owning_port, rnc->remote_node_index);319 320 sci_remote_device_post_request(idev, SCU_CONTEXT_COMMAND_POST_RNC_RESUME);321}322 323static void sci_remote_node_context_ready_state_enter(struct sci_base_state_machine *sm)324{325 struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm);326 enum sci_remote_node_context_destination_state dest_select;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(335 rnc, rnc->suspend_reason,336 SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT);337 338 if (dest_select == RNC_DEST_SUSPENDED_RESUME)339 tell_user = 0; /* Wait until ready again. */340 }341 if (tell_user)342 sci_remote_node_context_notify_user(rnc);343}344 345static void sci_remote_node_context_tx_suspended_state_enter(struct sci_base_state_machine *sm)346{347 struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm);348 349 sci_remote_node_context_continue_state_transitions(rnc);350}351 352static void sci_remote_node_context_tx_rx_suspended_state_enter(struct sci_base_state_machine *sm)353{354 struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm);355 struct isci_remote_device *idev = rnc_to_dev(rnc);356 struct isci_host *ihost = idev->owning_port->owning_controller;357 u32 new_count = rnc->suspend_count + 1;358 359 if (new_count == 0)360 rnc->suspend_count = 1;361 else362 rnc->suspend_count = new_count;363 smp_wmb();364 365 /* Terminate outstanding requests pending abort. */366 sci_remote_device_abort_requests_pending_abort(idev);367 368 wake_up(&ihost->eventq);369 sci_remote_node_context_continue_state_transitions(rnc);370}371 372static void sci_remote_node_context_await_suspend_state_exit(373 struct sci_base_state_machine *sm)374{375 struct sci_remote_node_context *rnc376 = container_of(sm, typeof(*rnc), sm);377 struct isci_remote_device *idev = rnc_to_dev(rnc);378 379 if (dev_is_sata(idev->domain_dev))380 isci_dev_set_hang_detection_timeout(idev, 0);381}382 383static const struct sci_base_state sci_remote_node_context_state_table[] = {384 [SCI_RNC_INITIAL] = {385 .enter_state = sci_remote_node_context_initial_state_enter,386 },387 [SCI_RNC_POSTING] = {388 .enter_state = sci_remote_node_context_posting_state_enter,389 },390 [SCI_RNC_INVALIDATING] = {391 .enter_state = sci_remote_node_context_invalidating_state_enter,392 },393 [SCI_RNC_RESUMING] = {394 .enter_state = sci_remote_node_context_resuming_state_enter,395 },396 [SCI_RNC_READY] = {397 .enter_state = sci_remote_node_context_ready_state_enter,398 },399 [SCI_RNC_TX_SUSPENDED] = {400 .enter_state = sci_remote_node_context_tx_suspended_state_enter,401 },402 [SCI_RNC_TX_RX_SUSPENDED] = {403 .enter_state = sci_remote_node_context_tx_rx_suspended_state_enter,404 },405 [SCI_RNC_AWAIT_SUSPENSION] = {406 .exit_state = sci_remote_node_context_await_suspend_state_exit,407 },408};409 410void sci_remote_node_context_construct(struct sci_remote_node_context *rnc,411 u16 remote_node_index)412{413 memset(rnc, 0, sizeof(struct sci_remote_node_context));414 415 rnc->remote_node_index = remote_node_index;416 rnc->destination_state = RNC_DEST_UNSPECIFIED;417 418 sci_init_sm(&rnc->sm, sci_remote_node_context_state_table, SCI_RNC_INITIAL);419}420 421enum sci_status sci_remote_node_context_event_handler(struct sci_remote_node_context *sci_rnc,422 u32 event_code)423{424 enum scis_sds_remote_node_context_states state;425 u32 next_state;426 427 state = sci_rnc->sm.current_state_id;428 switch (state) {429 case SCI_RNC_POSTING:430 switch (scu_get_event_code(event_code)) {431 case SCU_EVENT_POST_RNC_COMPLETE:432 sci_change_state(&sci_rnc->sm, SCI_RNC_READY);433 break;434 default:435 goto out;436 }437 break;438 case SCI_RNC_INVALIDATING:439 if (scu_get_event_code(event_code) == SCU_EVENT_POST_RNC_INVALIDATE_COMPLETE) {440 if (sci_rnc->destination_state == RNC_DEST_FINAL)441 next_state = SCI_RNC_INITIAL;442 else443 next_state = SCI_RNC_POSTING;444 sci_change_state(&sci_rnc->sm, next_state);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 suspend450 * the device since it's being invalidated anyway */451 dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),452 "%s: SCIC Remote Node Context 0x%p was "453 "suspended by hardware while being "454 "invalidated.\n", __func__, sci_rnc);455 break;456 default:457 goto out;458 }459 }460 break;461 case SCI_RNC_RESUMING:462 if (scu_get_event_code(event_code) == SCU_EVENT_POST_RCN_RELEASE) {463 sci_change_state(&sci_rnc->sm, SCI_RNC_READY);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 suspend469 * the device since it's being resumed anyway */470 dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),471 "%s: SCIC Remote Node Context 0x%p was "472 "suspended by hardware while being resumed.\n",473 __func__, sci_rnc);474 break;475 default:476 goto out;477 }478 }479 break;480 case SCI_RNC_READY:481 switch (scu_get_event_type(event_code)) {482 case SCU_EVENT_TL_RNC_SUSPEND_TX:483 sci_change_state(&sci_rnc->sm, SCI_RNC_TX_SUSPENDED);484 sci_rnc->suspend_type = scu_get_event_type(event_code);485 break;486 case SCU_EVENT_TL_RNC_SUSPEND_TX_RX:487 sci_change_state(&sci_rnc->sm, SCI_RNC_TX_RX_SUSPENDED);488 sci_rnc->suspend_type = scu_get_event_type(event_code);489 break;490 default:491 goto out;492 }493 break;494 case SCI_RNC_AWAIT_SUSPENSION:495 switch (scu_get_event_type(event_code)) {496 case SCU_EVENT_TL_RNC_SUSPEND_TX:497 next_state = SCI_RNC_TX_SUSPENDED;498 break;499 case SCU_EVENT_TL_RNC_SUSPEND_TX_RX:500 next_state = SCI_RNC_TX_RX_SUSPENDED;501 break;502 default:503 goto out;504 }505 if (sci_rnc->suspend_type == scu_get_event_type(event_code))506 sci_change_state(&sci_rnc->sm, next_state);507 break;508 default:509 dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),510 "%s: invalid state: %s\n", __func__,511 rnc_state_name(state));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)),518 "%s: code: %#x state: %s\n", __func__, event_code,519 rnc_state_name(state));520 return SCI_FAILURE;521 522}523 524enum sci_status sci_remote_node_context_destruct(struct sci_remote_node_context *sci_rnc,525 scics_sds_remote_node_context_callback cb_fn,526 void *cb_p)527{528 enum scis_sds_remote_node_context_states state;529 530 state = sci_rnc->sm.current_state_id;531 switch (state) {532 case SCI_RNC_INVALIDATING:533 sci_remote_node_context_setup_to_destroy(sci_rnc, cb_fn, cb_p);534 return SCI_SUCCESS;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:540 sci_remote_node_context_setup_to_destroy(sci_rnc, cb_fn, cb_p);541 sci_change_state(&sci_rnc->sm, SCI_RNC_INVALIDATING);542 return SCI_SUCCESS;543 case SCI_RNC_AWAIT_SUSPENSION:544 sci_remote_node_context_setup_to_destroy(sci_rnc, cb_fn, cb_p);545 return SCI_SUCCESS;546 case SCI_RNC_INITIAL:547 dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),548 "%s: invalid state: %s\n", __func__,549 rnc_state_name(state));550 /* We have decided that the destruct request on the remote node context551 * can not fail since it is either in the initial/destroyed state or is552 * can be destroyed.553 */554 return SCI_SUCCESS;555 default:556 dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),557 "%s: invalid state %s\n", __func__,558 rnc_state_name(state));559 return SCI_FAILURE_INVALID_STATE;560 }561}562 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,566 u32 suspend_type)567{568 enum scis_sds_remote_node_context_states state569 = 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;572 enum sci_remote_node_context_destination_state dest_param =573 RNC_DEST_UNSPECIFIED;574 575 dev_dbg(scirdev_to_dev(idev),576 "%s: current state %s, current suspend_type %x dest state %d,"577 " arg suspend_reason %d, arg suspend_type %x",578 __func__, rnc_state_name(state), sci_rnc->suspend_type,579 sci_rnc->destination_state, suspend_reason,580 suspend_type);581 582 /* Disable automatic state continuations if explicitly suspending. */583 if ((suspend_reason == SCI_HW_SUSPEND) ||584 (sci_rnc->destination_state == RNC_DEST_FINAL))585 dest_param = sci_rnc->destination_state;586 587 switch (state) {588 case SCI_RNC_READY:589 break;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 }597 fallthrough; /* and handle like SCI_RNC_POSTING */598 case SCI_RNC_RESUMING:599 fallthrough; /* and handle like SCI_RNC_POSTING */600 case SCI_RNC_POSTING:601 /* Set the destination state to AWAIT - this signals the602 * entry into the SCI_RNC_READY state that a suspension603 * needs to be done immediately.604 */605 if (sci_rnc->destination_state != RNC_DEST_FINAL)606 sci_rnc->destination_state = RNC_DEST_SUSPENDED;607 sci_rnc->suspend_type = suspend_type;608 sci_rnc->suspend_reason = suspend_reason;609 return SCI_SUCCESS;610 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:625 dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),626 "%s: invalid state %s\n", __func__,627 rnc_state_name(state));628 return SCI_FAILURE_INVALID_STATE;629 }630 sci_rnc->destination_state = dest_param;631 sci_rnc->suspend_type = suspend_type;632 sci_rnc->suspend_reason = suspend_reason;633 634 if (status == SCI_SUCCESS) { /* Already in the destination state? */635 struct isci_host *ihost = idev->owning_port->owning_controller;636 637 wake_up_all(&ihost->eventq); /* Let observers look. */638 return SCI_SUCCESS;639 }640 if ((suspend_reason == SCI_SW_SUSPEND_NORMAL) ||641 (suspend_reason == SCI_SW_SUSPEND_LINKHANG_DETECT)) {642 643 if (suspend_reason == SCI_SW_SUSPEND_LINKHANG_DETECT)644 isci_dev_set_hang_detection_timeout(idev, 0x00000001);645 646 sci_remote_device_post_request(647 idev, SCI_SOFTWARE_SUSPEND_CMD);648 }649 if (state != SCI_RNC_AWAIT_SUSPENSION)650 sci_change_state(&sci_rnc->sm, SCI_RNC_AWAIT_SUSPENSION);651 652 return SCI_SUCCESS;653}654 655enum sci_status sci_remote_node_context_resume(struct sci_remote_node_context *sci_rnc,656 scics_sds_remote_node_context_callback cb_fn,657 void *cb_p)658{659 enum scis_sds_remote_node_context_states state;660 struct isci_remote_device *idev = rnc_to_dev(sci_rnc);661 662 state = sci_rnc->sm.current_state_id;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>");670 671 switch (state) {672 case SCI_RNC_INITIAL:673 if (sci_rnc->remote_node_index == SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX)674 return SCI_FAILURE_INVALID_STATE;675 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)) {679 sci_remote_node_context_construct_buffer(sci_rnc);680 sci_change_state(&sci_rnc->sm, SCI_RNC_POSTING);681 }682 return SCI_SUCCESS;683 684 case SCI_RNC_POSTING:685 case SCI_RNC_INVALIDATING:686 case SCI_RNC_RESUMING:687 /* We are still waiting to post when a resume was688 * 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.695 */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;705 }706 return SCI_SUCCESS;707 708 case SCI_RNC_TX_SUSPENDED:709 case SCI_RNC_TX_RX_SUSPENDED:710 {711 struct domain_device *dev = idev->domain_dev;712 /* If this is an expander attached SATA device we must713 * invalidate and repost the RNC since this is the only714 * way to clear the TCi to NCQ tag mapping table for715 * 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);719 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 else726 sci_change_state(&sci_rnc->sm,727 SCI_RNC_RESUMING);728 }729 }730 return SCI_SUCCESS;731 732 case SCI_RNC_AWAIT_SUSPENSION:733 sci_remote_node_context_setup_to_resume(734 sci_rnc, cb_fn, cb_p, RNC_DEST_SUSPENDED_RESUME);735 return SCI_SUCCESS;736 default:737 dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),738 "%s: invalid state %s\n", __func__,739 rnc_state_name(state));740 return SCI_FAILURE_INVALID_STATE;741 }742}743 744enum sci_status sci_remote_node_context_start_io(struct sci_remote_node_context *sci_rnc,745 struct isci_request *ireq)746{747 enum scis_sds_remote_node_context_states state;748 749 state = sci_rnc->sm.current_state_id;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:757 dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),758 "%s: invalid state %s\n", __func__,759 rnc_state_name(state));760 return SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED;761 default: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;766 }767}768 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)774{775 enum sci_status status = sci_remote_node_context_resume(sci_rnc,776 cb_fn, cb_p);777 if (status != SCI_SUCCESS)778 dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),779 "%s: resume failed: %d\n", __func__, status);780 return status;781}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}806