brintos

brintos / linux-shallow public Read only

0
0
Text · 25.1 KiB · 77ba029 Raw
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