remote_node_context.c 35.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
/*
 * This file is provided under a dual BSD/GPLv2 license.  When using or
 * redistributing this file, you may do so under either license.
 *
 * GPL LICENSE SUMMARY
 *
 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of version 2 of the GNU General Public License as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 * The full GNU General Public License is included in this distribution
 * in the file called LICENSE.GPL.
 *
 * BSD LICENSE
 *
 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *   * Neither the name of Intel Corporation nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "sci_base_state_machine.h"
#include "scic_sds_controller.h"
#include "scic_sds_port.h"
59 60
#include "remote_device.h"
#include "remote_node_context.h"
61 62 63 64 65 66 67 68
#include "sci_environment.h"
#include "sci_util.h"
#include "scu_event_codes.h"
#include "scu_task_context.h"


/**
 *
69
 * @sci_rnc: The RNC for which the is posted request is being made.
70 71 72 73 74 75 76 77 78 79 80
 *
 * This method will return true if the RNC is not in the initial state.  In all
 * other states the RNC is considered active and this will return true. The
 * destroy request of the state machine drives the RNC back to the initial
 * state.  If the state machine changes then this routine will also have to be
 * changed. bool true if the state machine is not in the initial state false if
 * the state machine is in the initial state
 */

/**
 *
81
 * @sci_rnc: The state of the remote node context object to check.
82 83 84 85 86 87
 *
 * This method will return true if the remote node context is in a READY state
 * otherwise it will return false bool true if the remote node context is in
 * the ready state. false if the remote node context is not in the ready state.
 */
bool scic_sds_remote_node_context_is_ready(
88
	struct scic_sds_remote_node_context *sci_rnc)
89
{
90
	u32 current_state = sci_base_state_machine_get_state(&sci_rnc->state_machine);
91 92 93 94 95 96 97 98 99 100

	if (current_state == SCIC_SDS_REMOTE_NODE_CONTEXT_READY_STATE) {
		return true;
	}

	return false;
}

/**
 *
101
 * @sci_dev: The remote device to use to construct the RNC buffer.
102 103 104 105
 * @rnc: The buffer into which the remote device data will be copied.
 *
 * This method will construct the RNC buffer for this remote device object. none
 */
D
Dan Williams 已提交
106
static void scic_sds_remote_node_context_construct_buffer(
107
	struct scic_sds_remote_node_context *sci_rnc)
108
{
109
	struct scic_sds_remote_device *sci_dev = rnc_to_dev(sci_rnc);
110 111
	struct domain_device *dev = sci_dev_to_domain(sci_dev);
	union scu_remote_node_context *rnc;
112
	struct scic_sds_controller *scic;
113

114
	scic = scic_sds_remote_device_get_controller(sci_dev);
115 116

	rnc = scic_sds_controller_get_remote_node_context_buffer(
117
		scic, sci_rnc->remote_node_index);
118

119 120
	memset(rnc, 0, sizeof(union scu_remote_node_context)
		* scic_sds_remote_device_node_count(sci_dev));
121

122
	rnc->ssp.remote_node_index = sci_rnc->remote_node_index;
123
	rnc->ssp.remote_node_port_width = sci_dev->device_port_width;
124
	rnc->ssp.logical_port_index =
125
		scic_sds_remote_device_get_port_index(sci_dev);
126

127 128
	rnc->ssp.remote_sas_address_hi = SCIC_SWAP_DWORD(sci_dev->device_address.high);
	rnc->ssp.remote_sas_address_lo = SCIC_SWAP_DWORD(sci_dev->device_address.low);
129 130 131 132 133 134 135 136 137

	rnc->ssp.nexus_loss_timer_enable = true;
	rnc->ssp.check_bit               = false;
	rnc->ssp.is_valid                = false;
	rnc->ssp.is_remote_node_context  = true;
	rnc->ssp.function_number         = 0;

	rnc->ssp.arbitration_wait_time = 0;

138
	if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) {
139
		rnc->ssp.connection_occupancy_timeout =
140
			scic->user_parameters.sds1.stp_max_occupancy_timeout;
141
		rnc->ssp.connection_inactivity_timeout =
142
			scic->user_parameters.sds1.stp_inactivity_timeout;
143 144
	} else {
		rnc->ssp.connection_occupancy_timeout  =
145
			scic->user_parameters.sds1.ssp_max_occupancy_timeout;
146
		rnc->ssp.connection_inactivity_timeout =
147
			scic->user_parameters.sds1.ssp_inactivity_timeout;
148 149 150 151 152
	}

	rnc->ssp.initial_arbitration_wait_time = 0;

	/* Open Address Frame Parameters */
153
	rnc->ssp.oaf_connection_rate = sci_dev->connection_rate;
154 155 156 157 158 159 160
	rnc->ssp.oaf_features = 0;
	rnc->ssp.oaf_source_zone_group = 0;
	rnc->ssp.oaf_more_compatibility_features = 0;
}

/**
 *
161 162
 * @sci_rnc:
 * @callback:
163 164 165 166 167 168 169
 * @callback_parameter:
 *
 * This method will setup the remote node context object so it will transition
 * to its ready state.  If the remote node context is already setup to
 * transition to its final state then this function does nothing. none
 */
static void scic_sds_remote_node_context_setup_to_resume(
170 171
	struct scic_sds_remote_node_context *sci_rnc,
	scics_sds_remote_node_context_callback callback,
172 173
	void *callback_parameter)
{
174 175 176 177
	if (sci_rnc->destination_state != SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_FINAL) {
		sci_rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_READY;
		sci_rnc->user_callback     = callback;
		sci_rnc->user_cookie       = callback_parameter;
178 179 180 181 182
	}
}

/**
 *
183 184
 * @sci_rnc:
 * @callback:
185 186 187 188 189 190
 * @callback_parameter:
 *
 * This method will setup the remote node context object so it will transistion
 * to its final state. none
 */
static void scic_sds_remote_node_context_setup_to_destory(
191 192
	struct scic_sds_remote_node_context *sci_rnc,
	scics_sds_remote_node_context_callback callback,
193 194
	void *callback_parameter)
{
195 196 197
	sci_rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_FINAL;
	sci_rnc->user_callback     = callback;
	sci_rnc->user_cookie       = callback_parameter;
198 199 200 201
}

/**
 *
202 203
 * @sci_rnc:
 * @callback:
204 205 206 207 208
 *
 * This method will continue to resume a remote node context.  This is used in
 * the states where a resume is requested while a resume is in progress.
 */
static enum sci_status scic_sds_remote_node_context_continue_to_resume_handler(
209 210
	struct scic_sds_remote_node_context *sci_rnc,
	scics_sds_remote_node_context_callback callback,
211 212
	void *callback_parameter)
{
213 214 215
	if (sci_rnc->destination_state == SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_READY) {
		sci_rnc->user_callback = callback;
		sci_rnc->user_cookie   = callback_parameter;
216 217 218 219 220 221 222 223 224 225

		return SCI_SUCCESS;
	}

	return SCI_FAILURE_INVALID_STATE;
}

/* --------------------------------------------------------------------------- */

static enum sci_status scic_sds_remote_node_context_default_destruct_handler(
226 227
	struct scic_sds_remote_node_context *sci_rnc,
	scics_sds_remote_node_context_callback callback,
228 229
	void *callback_parameter)
{
230
	dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
231 232 233
		 "%s: SCIC Remote Node Context 0x%p requested to stop while "
		 "in unexpected state %d\n",
		 __func__,
234 235
		 sci_rnc,
		 sci_base_state_machine_get_state(&sci_rnc->state_machine));
236 237 238 239 240 241 242 243

	/*
	 * We have decided that the destruct request on the remote node context can not fail
	 * since it is either in the initial/destroyed state or is can be destroyed. */
	return SCI_SUCCESS;
}

static enum sci_status scic_sds_remote_node_context_default_suspend_handler(
244
	struct scic_sds_remote_node_context *sci_rnc,
245
	u32 suspend_type,
246
	scics_sds_remote_node_context_callback callback,
247 248
	void *callback_parameter)
{
249
	dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
250 251 252
		 "%s: SCIC Remote Node Context 0x%p requested to suspend "
		 "while in wrong state %d\n",
		 __func__,
253 254
		 sci_rnc,
		 sci_base_state_machine_get_state(&sci_rnc->state_machine));
255 256 257 258 259

	return SCI_FAILURE_INVALID_STATE;
}

static enum sci_status scic_sds_remote_node_context_default_resume_handler(
260 261
	struct scic_sds_remote_node_context *sci_rnc,
	scics_sds_remote_node_context_callback callback,
262 263
	void *callback_parameter)
{
264
	dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
265 266 267
		 "%s: SCIC Remote Node Context 0x%p requested to resume "
		 "while in wrong state %d\n",
		 __func__,
268 269
		 sci_rnc,
		 sci_base_state_machine_get_state(&sci_rnc->state_machine));
270 271 272 273 274

	return SCI_FAILURE_INVALID_STATE;
}

static enum sci_status scic_sds_remote_node_context_default_start_io_handler(
275 276
	struct scic_sds_remote_node_context *sci_rnc,
	struct scic_sds_request *sci_req)
277
{
278
	dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
279 280 281
		 "%s: SCIC Remote Node Context 0x%p requested to start io "
		 "0x%p while in wrong state %d\n",
		 __func__,
282 283 284
		 sci_rnc,
		 sci_req,
		 sci_base_state_machine_get_state(&sci_rnc->state_machine));
285 286 287 288 289

	return SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED;
}

static enum sci_status scic_sds_remote_node_context_default_start_task_handler(
290 291
	struct scic_sds_remote_node_context *sci_rnc,
	struct scic_sds_request *sci_req)
292
{
293
	dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
294 295 296
		 "%s: SCIC Remote Node Context 0x%p requested to start "
		 "task 0x%p while in wrong state %d\n",
		 __func__,
297 298 299
		 sci_rnc,
		 sci_req,
		 sci_base_state_machine_get_state(&sci_rnc->state_machine));
300 301 302 303 304

	return SCI_FAILURE;
}

static enum sci_status scic_sds_remote_node_context_default_event_handler(
305
	struct scic_sds_remote_node_context *sci_rnc,
306 307
	u32 event_code)
{
308
	dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
309 310 311
		 "%s: SCIC Remote Node Context 0x%p requested to process "
		 "event 0x%x while in wrong state %d\n",
		 __func__,
312
		 sci_rnc,
313
		 event_code,
314
		 sci_base_state_machine_get_state(&sci_rnc->state_machine));
315 316 317 318 319 320

	return SCI_FAILURE_INVALID_STATE;
}

/**
 *
321 322
 * @sci_rnc: The rnc for which the task request is targeted.
 * @sci_req: The request which is going to be started.
323 324 325 326 327 328
 *
 * This method determines if the task request can be started by the SCU
 * hardware. When the RNC is in the ready state any task can be started.
 * enum sci_status SCI_SUCCESS
 */
static enum sci_status scic_sds_remote_node_context_success_start_task_handler(
329 330
	struct scic_sds_remote_node_context *sci_rnc,
	struct scic_sds_request *sci_req)
331 332 333 334 335 336
{
	return SCI_SUCCESS;
}

/**
 *
337 338
 * @sci_rnc:
 * @callback:
339 340 341 342 343 344 345 346
 * @callback_parameter:
 *
 * This method handles destruct calls from the various state handlers.  The
 * remote node context can be requested to destroy from any state. If there was
 * a user callback it is always replaced with the request to destroy user
 * callback. enum sci_status
 */
static enum sci_status scic_sds_remote_node_context_general_destruct_handler(
347 348
	struct scic_sds_remote_node_context *sci_rnc,
	scics_sds_remote_node_context_callback callback,
349 350 351
	void *callback_parameter)
{
	scic_sds_remote_node_context_setup_to_destory(
352
		sci_rnc, callback, callback_parameter
353 354 355
		);

	sci_base_state_machine_change_state(
356
		&sci_rnc->state_machine,
357 358 359 360 361 362 363 364 365
		SCIC_SDS_REMOTE_NODE_CONTEXT_INVALIDATING_STATE
		);

	return SCI_SUCCESS;
}

/* --------------------------------------------------------------------------- */

static enum sci_status scic_sds_remote_node_context_initial_state_resume_handler(
366 367
	struct scic_sds_remote_node_context *sci_rnc,
	scics_sds_remote_node_context_callback callback,
368 369
	void *callback_parameter)
{
370
	if (sci_rnc->remote_node_index != SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX) {
371
		scic_sds_remote_node_context_setup_to_resume(
372
			sci_rnc, callback, callback_parameter
373 374
			);

375
		scic_sds_remote_node_context_construct_buffer(sci_rnc);
376 377

		sci_base_state_machine_change_state(
378
			&sci_rnc->state_machine,
379 380 381 382 383 384 385 386 387 388 389 390
			SCIC_SDS_REMOTE_NODE_CONTEXT_POSTING_STATE
			);

		return SCI_SUCCESS;
	}

	return SCI_FAILURE_INVALID_STATE;
}

/* --------------------------------------------------------------------------- */

static enum sci_status scic_sds_remote_node_context_posting_state_event_handler(
391
	struct scic_sds_remote_node_context *sci_rnc,
392 393 394 395 396 397 398 399 400
	u32 event_code)
{
	enum sci_status status;

	switch (scu_get_event_code(event_code)) {
	case SCU_EVENT_POST_RNC_COMPLETE:
		status = SCI_SUCCESS;

		sci_base_state_machine_change_state(
401
			&sci_rnc->state_machine,
402 403 404 405 406 407
			SCIC_SDS_REMOTE_NODE_CONTEXT_READY_STATE
			);
		break;

	default:
		status = SCI_FAILURE;
408
		dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
409 410 411 412
			 "%s: SCIC Remote Node Context 0x%p requested to "
			 "process unexpected event 0x%x while in posting "
			 "state\n",
			 __func__,
413
			 sci_rnc,
414 415 416 417 418 419 420 421 422 423
			 event_code);
		break;
	}

	return status;
}

/* --------------------------------------------------------------------------- */

static enum sci_status scic_sds_remote_node_context_invalidating_state_destruct_handler(
424 425
	struct scic_sds_remote_node_context *sci_rnc,
	scics_sds_remote_node_context_callback callback,
426 427 428
	void *callback_parameter)
{
	scic_sds_remote_node_context_setup_to_destory(
429
		sci_rnc, callback, callback_parameter
430 431 432 433 434 435
		);

	return SCI_SUCCESS;
}

static enum sci_status scic_sds_remote_node_context_invalidating_state_event_handler(
436
	struct scic_sds_remote_node_context *sci_rnc,
437 438 439 440 441 442 443
	u32 event_code)
{
	enum sci_status status;

	if (scu_get_event_code(event_code) == SCU_EVENT_POST_RNC_INVALIDATE_COMPLETE) {
		status = SCI_SUCCESS;

444
		if (sci_rnc->destination_state == SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_FINAL) {
445
			sci_base_state_machine_change_state(
446
				&sci_rnc->state_machine,
447 448 449 450
				SCIC_SDS_REMOTE_NODE_CONTEXT_INITIAL_STATE
				);
		} else {
			sci_base_state_machine_change_state(
451
				&sci_rnc->state_machine,
452 453 454 455 456 457 458 459 460 461
				SCIC_SDS_REMOTE_NODE_CONTEXT_POSTING_STATE
				);
		}
	} else {
		switch (scu_get_event_type(event_code)) {
		case SCU_EVENT_TYPE_RNC_SUSPEND_TX:
		case SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX:
			/*
			 * We really dont care if the hardware is going to suspend
			 * the device since it's being invalidated anyway */
462
			dev_dbg(scirdev_to_dev(rnc_to_dev(sci_rnc)),
463 464 465 466
				"%s: SCIC Remote Node Context 0x%p was "
				"suspeneded by hardware while being "
				"invalidated.\n",
				__func__,
467
				sci_rnc);
468 469 470 471
			status = SCI_SUCCESS;
			break;

		default:
472
			dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
473 474 475 476
				 "%s: SCIC Remote Node Context 0x%p "
				 "requested to process event 0x%x while "
				 "in state %d.\n",
				 __func__,
477
				 sci_rnc,
478 479
				 event_code,
				 sci_base_state_machine_get_state(
480
					 &sci_rnc->state_machine));
481 482 483 484 485 486 487 488 489 490 491 492
			status = SCI_FAILURE;
			break;
		}
	}

	return status;
}

/* --------------------------------------------------------------------------- */


static enum sci_status scic_sds_remote_node_context_resuming_state_event_handler(
493
	struct scic_sds_remote_node_context *sci_rnc,
494 495 496 497 498 499 500 501
	u32 event_code)
{
	enum sci_status status;

	if (scu_get_event_code(event_code) == SCU_EVENT_POST_RCN_RELEASE) {
		status = SCI_SUCCESS;

		sci_base_state_machine_change_state(
502
			&sci_rnc->state_machine,
503 504 505 506 507 508 509 510 511
			SCIC_SDS_REMOTE_NODE_CONTEXT_READY_STATE
			);
	} else {
		switch (scu_get_event_type(event_code)) {
		case SCU_EVENT_TYPE_RNC_SUSPEND_TX:
		case SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX:
			/*
			 * We really dont care if the hardware is going to suspend
			 * the device since it's being resumed anyway */
512
			dev_dbg(scirdev_to_dev(rnc_to_dev(sci_rnc)),
513 514 515
				"%s: SCIC Remote Node Context 0x%p was "
				"suspeneded by hardware while being resumed.\n",
				__func__,
516
				sci_rnc);
517 518 519 520
			status = SCI_SUCCESS;
			break;

		default:
521
			dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
522 523 524
				 "%s: SCIC Remote Node Context 0x%p requested "
				 "to process event 0x%x while in state %d.\n",
				 __func__,
525
				 sci_rnc,
526 527
				 event_code,
				 sci_base_state_machine_get_state(
528
					 &sci_rnc->state_machine));
529 530 531 532 533 534 535 536 537 538 539 540
			status = SCI_FAILURE;
			break;
		}
	}

	return status;
}

/* --------------------------------------------------------------------------- */

/**
 *
541 542
 * @sci_rnc: The remote node context object being suspended.
 * @callback: The callback when the suspension is complete.
543 544 545 546 547 548
 * @callback_parameter: The parameter that is to be passed into the callback.
 *
 * This method will handle the suspend requests from the ready state.
 * SCI_SUCCESS
 */
static enum sci_status scic_sds_remote_node_context_ready_state_suspend_handler(
549
	struct scic_sds_remote_node_context *sci_rnc,
550
	u32 suspend_type,
551
	scics_sds_remote_node_context_callback callback,
552 553
	void *callback_parameter)
{
554 555 556
	sci_rnc->user_callback   = callback;
	sci_rnc->user_cookie     = callback_parameter;
	sci_rnc->suspension_code = suspend_type;
557 558

	if (suspend_type == SCI_SOFTWARE_SUSPENSION) {
559 560
		scic_sds_remote_device_post_request(rnc_to_dev(sci_rnc),
						    SCU_CONTEXT_COMMAND_POST_RNC_SUSPEND_TX);
561 562 563
	}

	sci_base_state_machine_change_state(
564
		&sci_rnc->state_machine,
565 566 567 568 569 570 571 572
		SCIC_SDS_REMOTE_NODE_CONTEXT_AWAIT_SUSPENSION_STATE
		);

	return SCI_SUCCESS;
}

/**
 *
573 574
 * @sci_rnc: The rnc for which the io request is targeted.
 * @sci_req: The request which is going to be started.
575 576 577 578 579 580
 *
 * This method determines if the io request can be started by the SCU hardware.
 * When the RNC is in the ready state any io request can be started. enum sci_status
 * SCI_SUCCESS
 */
static enum sci_status scic_sds_remote_node_context_ready_state_start_io_handler(
581 582
	struct scic_sds_remote_node_context *sci_rnc,
	struct scic_sds_request *sci_req)
583 584 585 586 587 588
{
	return SCI_SUCCESS;
}


static enum sci_status scic_sds_remote_node_context_ready_state_event_handler(
589
	struct scic_sds_remote_node_context *sci_rnc,
590 591 592 593 594 595 596
	u32 event_code)
{
	enum sci_status status;

	switch (scu_get_event_type(event_code)) {
	case SCU_EVENT_TL_RNC_SUSPEND_TX:
		sci_base_state_machine_change_state(
597
			&sci_rnc->state_machine,
598 599 600
			SCIC_SDS_REMOTE_NODE_CONTEXT_TX_SUSPENDED_STATE
			);

601
		sci_rnc->suspension_code = scu_get_event_specifier(event_code);
602 603 604 605 606
		status = SCI_SUCCESS;
		break;

	case SCU_EVENT_TL_RNC_SUSPEND_TX_RX:
		sci_base_state_machine_change_state(
607
			&sci_rnc->state_machine,
608 609 610
			SCIC_SDS_REMOTE_NODE_CONTEXT_TX_RX_SUSPENDED_STATE
			);

611
		sci_rnc->suspension_code = scu_get_event_specifier(event_code);
612 613 614 615
		status = SCI_SUCCESS;
		break;

	default:
616
		dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
617 618 619
			"%s: SCIC Remote Node Context 0x%p requested to "
			"process event 0x%x while in state %d.\n",
			__func__,
620
			sci_rnc,
621 622
			event_code,
			sci_base_state_machine_get_state(
623
				&sci_rnc->state_machine));
624 625 626 627 628 629 630 631 632 633 634

		status = SCI_FAILURE;
		break;
	}

	return status;
}

/* --------------------------------------------------------------------------- */

static enum sci_status scic_sds_remote_node_context_tx_suspended_state_resume_handler(
635 636
	struct scic_sds_remote_node_context *sci_rnc,
	scics_sds_remote_node_context_callback callback,
637 638
	void *callback_parameter)
{
639 640 641
	struct scic_sds_remote_device *sci_dev = rnc_to_dev(sci_rnc);
	struct domain_device *dev = sci_dev_to_domain(sci_dev);
	enum sci_status status = SCI_SUCCESS;
642

643 644
	scic_sds_remote_node_context_setup_to_resume(sci_rnc, callback,
						     callback_parameter);
645 646

	/* TODO: consider adding a resume action of NONE, INVALIDATE, WRITE_TLCR */
647 648 649 650 651
	if (dev->dev_type == SAS_END_DEV || dev_is_expander(dev))
		sci_base_state_machine_change_state(&sci_rnc->state_machine,
						    SCIC_SDS_REMOTE_NODE_CONTEXT_RESUMING_STATE);
	else if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) {
		if (sci_dev->is_direct_attached) {
652 653
			/* @todo Fix this since I am being silly in writing to the STPTLDARNI register. */
			sci_base_state_machine_change_state(
654
				&sci_rnc->state_machine,
655
				SCIC_SDS_REMOTE_NODE_CONTEXT_RESUMING_STATE);
656 657
		} else {
			sci_base_state_machine_change_state(
658
				&sci_rnc->state_machine,
659
				SCIC_SDS_REMOTE_NODE_CONTEXT_INVALIDATING_STATE);
660
		}
661
	} else
662 663 664 665 666 667 668
		status = SCI_FAILURE;

	return status;
}

/**
 *
669 670
 * @sci_rnc: The remote node context which is to receive the task request.
 * @sci_req: The task request to be transmitted to to the remote target
671 672 673 674 675 676 677 678
 *    device.
 *
 * This method will report a success or failure attempt to start a new task
 * request to the hardware.  Since all task requests are sent on the high
 * priority queue they can be sent when the RCN is in a TX suspend state.
 * enum sci_status SCI_SUCCESS
 */
static enum sci_status scic_sds_remote_node_context_suspended_start_task_handler(
679 680
	struct scic_sds_remote_node_context *sci_rnc,
	struct scic_sds_request *sci_req)
681
{
682
	scic_sds_remote_node_context_resume(sci_rnc, NULL, NULL);
683 684 685 686 687 688 689

	return SCI_SUCCESS;
}

/* --------------------------------------------------------------------------- */

static enum sci_status scic_sds_remote_node_context_tx_rx_suspended_state_resume_handler(
690 691
	struct scic_sds_remote_node_context *sci_rnc,
	scics_sds_remote_node_context_callback callback,
692 693 694
	void *callback_parameter)
{
	scic_sds_remote_node_context_setup_to_resume(
695
		sci_rnc, callback, callback_parameter
696 697 698
		);

	sci_base_state_machine_change_state(
699
		&sci_rnc->state_machine,
700 701 702 703 704 705 706 707 708 709 710 711 712 713
		SCIC_SDS_REMOTE_NODE_CONTEXT_RESUMING_STATE
		);

	return SCI_FAILURE_INVALID_STATE;
}

/* --------------------------------------------------------------------------- */

/**
 *
 *
 *
 */
static enum sci_status scic_sds_remote_node_context_await_suspension_state_resume_handler(
714 715
	struct scic_sds_remote_node_context *sci_rnc,
	scics_sds_remote_node_context_callback callback,
716 717 718
	void *callback_parameter)
{
	scic_sds_remote_node_context_setup_to_resume(
719
		sci_rnc, callback, callback_parameter
720 721 722 723 724 725 726
		);

	return SCI_SUCCESS;
}

/**
 *
727 728
 * @sci_rnc: The remote node context which is to receive the task request.
 * @sci_req: The task request to be transmitted to to the remote target
729 730 731 732 733 734 735 736
 *    device.
 *
 * This method will report a success or failure attempt to start a new task
 * request to the hardware.  Since all task requests are sent on the high
 * priority queue they can be sent when the RCN is in a TX suspend state.
 * enum sci_status SCI_SUCCESS
 */
static enum sci_status scic_sds_remote_node_context_await_suspension_state_start_task_handler(
737 738
	struct scic_sds_remote_node_context *sci_rnc,
	struct scic_sds_request *sci_req)
739 740 741 742 743
{
	return SCI_SUCCESS;
}

static enum sci_status scic_sds_remote_node_context_await_suspension_state_event_handler(
744
	struct scic_sds_remote_node_context *sci_rnc,
745 746 747 748 749 750 751
	u32 event_code)
{
	enum sci_status status;

	switch (scu_get_event_type(event_code)) {
	case SCU_EVENT_TL_RNC_SUSPEND_TX:
		sci_base_state_machine_change_state(
752
			&sci_rnc->state_machine,
753 754 755
			SCIC_SDS_REMOTE_NODE_CONTEXT_TX_SUSPENDED_STATE
			);

756
		sci_rnc->suspension_code = scu_get_event_specifier(event_code);
757 758 759 760 761
		status = SCI_SUCCESS;
		break;

	case SCU_EVENT_TL_RNC_SUSPEND_TX_RX:
		sci_base_state_machine_change_state(
762
			&sci_rnc->state_machine,
763 764 765
			SCIC_SDS_REMOTE_NODE_CONTEXT_TX_RX_SUSPENDED_STATE
			);

766
		sci_rnc->suspension_code = scu_get_event_specifier(event_code);
767 768 769 770
		status = SCI_SUCCESS;
		break;

	default:
771
		dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
772 773 774
			 "%s: SCIC Remote Node Context 0x%p requested to "
			 "process event 0x%x while in state %d.\n",
			 __func__,
775
			 sci_rnc,
776 777
			 event_code,
			 sci_base_state_machine_get_state(
778
				 &sci_rnc->state_machine));
779 780 781 782 783 784 785 786 787 788

		status = SCI_FAILURE;
		break;
	}

	return status;
}

/* --------------------------------------------------------------------------- */

D
Dan Williams 已提交
789
static struct scic_sds_remote_node_context_handlers
790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907
scic_sds_remote_node_context_state_handler_table[
	SCIC_SDS_REMOTE_NODE_CONTEXT_MAX_STATES] =
{
	/* SCIC_SDS_REMOTE_NODE_CONTEXT_INITIAL_STATE */
	{
		scic_sds_remote_node_context_default_destruct_handler,
		scic_sds_remote_node_context_default_suspend_handler,
		scic_sds_remote_node_context_initial_state_resume_handler,
		scic_sds_remote_node_context_default_start_io_handler,
		scic_sds_remote_node_context_default_start_task_handler,
		scic_sds_remote_node_context_default_event_handler
	},
	/* SCIC_SDS_REMOTE_NODE_CONTEXT_POSTING_STATE */
	{
		scic_sds_remote_node_context_general_destruct_handler,
		scic_sds_remote_node_context_default_suspend_handler,
		scic_sds_remote_node_context_continue_to_resume_handler,
		scic_sds_remote_node_context_default_start_io_handler,
		scic_sds_remote_node_context_default_start_task_handler,
		scic_sds_remote_node_context_posting_state_event_handler
	},
	/* SCIC_SDS_REMOTE_NODE_CONTEXT_INVALIDATING_STATE */
	{
		scic_sds_remote_node_context_invalidating_state_destruct_handler,
		scic_sds_remote_node_context_default_suspend_handler,
		scic_sds_remote_node_context_continue_to_resume_handler,
		scic_sds_remote_node_context_default_start_io_handler,
		scic_sds_remote_node_context_default_start_task_handler,
		scic_sds_remote_node_context_invalidating_state_event_handler
	},
	/* SCIC_SDS_REMOTE_NODE_CONTEXT_RESUMING_STATE */
	{
		scic_sds_remote_node_context_general_destruct_handler,
		scic_sds_remote_node_context_default_suspend_handler,
		scic_sds_remote_node_context_continue_to_resume_handler,
		scic_sds_remote_node_context_default_start_io_handler,
		scic_sds_remote_node_context_success_start_task_handler,
		scic_sds_remote_node_context_resuming_state_event_handler
	},
	/* SCIC_SDS_REMOTE_NODE_CONTEXT_READY_STATE */
	{
		scic_sds_remote_node_context_general_destruct_handler,
		scic_sds_remote_node_context_ready_state_suspend_handler,
		scic_sds_remote_node_context_default_resume_handler,
		scic_sds_remote_node_context_ready_state_start_io_handler,
		scic_sds_remote_node_context_success_start_task_handler,
		scic_sds_remote_node_context_ready_state_event_handler
	},
	/* SCIC_SDS_REMOTE_NODE_CONTEXT_TX_SUSPENDED_STATE */
	{
		scic_sds_remote_node_context_general_destruct_handler,
		scic_sds_remote_node_context_default_suspend_handler,
		scic_sds_remote_node_context_tx_suspended_state_resume_handler,
		scic_sds_remote_node_context_default_start_io_handler,
		scic_sds_remote_node_context_suspended_start_task_handler,
		scic_sds_remote_node_context_default_event_handler
	},
	/* SCIC_SDS_REMOTE_NODE_CONTEXT_TX_RX_SUSPENDED_STATE */
	{
		scic_sds_remote_node_context_general_destruct_handler,
		scic_sds_remote_node_context_default_suspend_handler,
		scic_sds_remote_node_context_tx_rx_suspended_state_resume_handler,
		scic_sds_remote_node_context_default_start_io_handler,
		scic_sds_remote_node_context_suspended_start_task_handler,
		scic_sds_remote_node_context_default_event_handler
	},
	/* SCIC_SDS_REMOTE_NODE_CONTEXT_AWAIT_SUSPENSION_STATE */
	{
		scic_sds_remote_node_context_general_destruct_handler,
		scic_sds_remote_node_context_default_suspend_handler,
		scic_sds_remote_node_context_await_suspension_state_resume_handler,
		scic_sds_remote_node_context_default_start_io_handler,
		scic_sds_remote_node_context_await_suspension_state_start_task_handler,
		scic_sds_remote_node_context_await_suspension_state_event_handler
	}
};

/*
 * *****************************************************************************
 * * REMOTE NODE CONTEXT PRIVATE METHODS
 * ***************************************************************************** */

/**
 *
 *
 * This method just calls the user callback function and then resets the
 * callback.
 */
static void scic_sds_remote_node_context_notify_user(
	struct scic_sds_remote_node_context *rnc)
{
	if (rnc->user_callback != NULL) {
		(*rnc->user_callback)(rnc->user_cookie);

		rnc->user_callback = NULL;
		rnc->user_cookie = NULL;
	}
}

/**
 *
 *
 * This method will continue the remote node context state machine by
 * requesting to resume the remote node context state machine from its current
 * state.
 */
static void scic_sds_remote_node_context_continue_state_transitions(
	struct scic_sds_remote_node_context *rnc)
{
	if (rnc->destination_state == SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_READY) {
		rnc->state_handlers->resume_handler(
			rnc, rnc->user_callback, rnc->user_cookie
			);
	}
}

/**
 *
908
 * @sci_rnc: The remote node context object that is to be validated.
909 910 911 912 913
 *
 * This method will mark the rnc buffer as being valid and post the request to
 * the hardware. none
 */
static void scic_sds_remote_node_context_validate_context_buffer(
914
	struct scic_sds_remote_node_context *sci_rnc)
915
{
916
	struct scic_sds_remote_device *sci_dev = rnc_to_dev(sci_rnc);
917
	struct domain_device *dev = sci_dev_to_domain(sci_dev);
918 919 920
	union scu_remote_node_context *rnc_buffer;

	rnc_buffer = scic_sds_controller_get_remote_node_context_buffer(
921
		scic_sds_remote_device_get_controller(sci_dev),
922
		sci_rnc->remote_node_index
923 924 925 926
		);

	rnc_buffer->ssp.is_valid = true;

927
	if (!sci_dev->is_direct_attached &&
928
	    (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP))) {
929 930
		scic_sds_remote_device_post_request(sci_dev,
						    SCU_CONTEXT_COMMAND_POST_RNC_96);
931
	} else {
932
		scic_sds_remote_device_post_request(sci_dev, SCU_CONTEXT_COMMAND_POST_RNC_32);
933

934 935 936
		if (sci_dev->is_direct_attached) {
			scic_sds_port_setup_transports(sci_dev->owning_port,
						       sci_rnc->remote_node_index);
937 938 939 940 941 942
		}
	}
}

/**
 *
943
 * @sci_rnc: The remote node context object that is to be invalidated.
944 945 946 947
 *
 * This method will update the RNC buffer and post the invalidate request. none
 */
static void scic_sds_remote_node_context_invalidate_context_buffer(
948
	struct scic_sds_remote_node_context *sci_rnc)
949 950 951 952
{
	union scu_remote_node_context *rnc_buffer;

	rnc_buffer = scic_sds_controller_get_remote_node_context_buffer(
953 954
		scic_sds_remote_device_get_controller(rnc_to_dev(sci_rnc)),
		sci_rnc->remote_node_index);
955 956 957

	rnc_buffer->ssp.is_valid = false;

958 959
	scic_sds_remote_device_post_request(rnc_to_dev(sci_rnc),
					    SCU_CONTEXT_COMMAND_POST_RNC_INVALIDATE);
960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005
}

/*
 * *****************************************************************************
 * * REMOTE NODE CONTEXT STATE ENTER AND EXIT METHODS
 * ***************************************************************************** */

/**
 *
 *
 *
 */
static void scic_sds_remote_node_context_initial_state_enter(
	struct sci_base_object *object)
{
	struct scic_sds_remote_node_context *rnc;

	rnc = (struct scic_sds_remote_node_context *)object;

	SET_STATE_HANDLER(
		rnc,
		scic_sds_remote_node_context_state_handler_table,
		SCIC_SDS_REMOTE_NODE_CONTEXT_INITIAL_STATE
		);

	/*
	 * Check to see if we have gotten back to the initial state because someone
	 * requested to destroy the remote node context object. */
	if (
		rnc->state_machine.previous_state_id
		== SCIC_SDS_REMOTE_NODE_CONTEXT_INVALIDATING_STATE
		) {
		rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_UNSPECIFIED;

		scic_sds_remote_node_context_notify_user(rnc);
	}
}

/**
 *
 *
 *
 */
static void scic_sds_remote_node_context_posting_state_enter(
	struct sci_base_object *object)
{
1006
	struct scic_sds_remote_node_context *sci_rnc;
1007

1008
	sci_rnc = (struct scic_sds_remote_node_context *)object;
1009 1010

	SET_STATE_HANDLER(
1011
		sci_rnc,
1012 1013 1014 1015
		scic_sds_remote_node_context_state_handler_table,
		SCIC_SDS_REMOTE_NODE_CONTEXT_POSTING_STATE
		);

1016
	scic_sds_remote_node_context_validate_context_buffer(sci_rnc);
1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048
}

/**
 *
 *
 *
 */
static void scic_sds_remote_node_context_invalidating_state_enter(
	struct sci_base_object *object)
{
	struct scic_sds_remote_node_context *rnc;

	rnc = (struct scic_sds_remote_node_context *)object;

	SET_STATE_HANDLER(
		rnc,
		scic_sds_remote_node_context_state_handler_table,
		SCIC_SDS_REMOTE_NODE_CONTEXT_INVALIDATING_STATE
		);

	scic_sds_remote_node_context_invalidate_context_buffer(rnc);
}

/**
 *
 *
 *
 */
static void scic_sds_remote_node_context_resuming_state_enter(
	struct sci_base_object *object)
{
	struct scic_sds_remote_node_context *rnc;
1049
	struct scic_sds_remote_device *sci_dev;
1050
	struct domain_device *dev;
1051 1052

	rnc = (struct scic_sds_remote_node_context *)object;
1053
	sci_dev = rnc_to_dev(rnc);
1054
	dev = sci_dev_to_domain(sci_dev);
1055 1056 1057 1058 1059 1060 1061

	SET_STATE_HANDLER(
		rnc,
		scic_sds_remote_node_context_state_handler_table,
		SCIC_SDS_REMOTE_NODE_CONTEXT_RESUMING_STATE
		);

1062 1063 1064 1065 1066 1067
	/*
	 * For direct attached SATA devices we need to clear the TLCR
	 * NCQ to TCi tag mapping on the phy and in cases where we
	 * resume because of a target reset we also need to update
	 * the STPTLDARNI register with the RNi of the device
	 */
1068 1069
	if ((dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) &&
	    sci_dev->is_direct_attached)
1070 1071
		scic_sds_port_setup_transports(sci_dev->owning_port,
					       rnc->remote_node_index);
1072

1073
	scic_sds_remote_device_post_request(sci_dev, SCU_CONTEXT_COMMAND_POST_RNC_RESUME);
1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163
}

/**
 *
 *
 *
 */
static void scic_sds_remote_node_context_ready_state_enter(
	struct sci_base_object *object)
{
	struct scic_sds_remote_node_context *rnc;

	rnc = (struct scic_sds_remote_node_context *)object;

	SET_STATE_HANDLER(
		rnc,
		scic_sds_remote_node_context_state_handler_table,
		SCIC_SDS_REMOTE_NODE_CONTEXT_READY_STATE
		);

	rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_UNSPECIFIED;

	if (rnc->user_callback != NULL) {
		scic_sds_remote_node_context_notify_user(rnc);
	}
}

/**
 *
 *
 *
 */
static void scic_sds_remote_node_context_tx_suspended_state_enter(
	struct sci_base_object *object)
{
	struct scic_sds_remote_node_context *rnc;

	rnc = (struct scic_sds_remote_node_context *)object;

	SET_STATE_HANDLER(
		rnc,
		scic_sds_remote_node_context_state_handler_table,
		SCIC_SDS_REMOTE_NODE_CONTEXT_TX_SUSPENDED_STATE
		);

	scic_sds_remote_node_context_continue_state_transitions(rnc);
}

/**
 *
 *
 *
 */
static void scic_sds_remote_node_context_tx_rx_suspended_state_enter(
	struct sci_base_object *object)
{
	struct scic_sds_remote_node_context *rnc;

	rnc = (struct scic_sds_remote_node_context *)object;

	SET_STATE_HANDLER(
		rnc,
		scic_sds_remote_node_context_state_handler_table,
		SCIC_SDS_REMOTE_NODE_CONTEXT_TX_RX_SUSPENDED_STATE
		);

	scic_sds_remote_node_context_continue_state_transitions(rnc);
}

/**
 *
 *
 *
 */
static void scic_sds_remote_node_context_await_suspension_state_enter(
	struct sci_base_object *object)
{
	struct scic_sds_remote_node_context *rnc;

	rnc = (struct scic_sds_remote_node_context *)object;

	SET_STATE_HANDLER(
		rnc,
		scic_sds_remote_node_context_state_handler_table,
		SCIC_SDS_REMOTE_NODE_CONTEXT_AWAIT_SUSPENSION_STATE
		);
}

/* --------------------------------------------------------------------------- */

D
Dan Williams 已提交
1164
static const struct sci_base_state scic_sds_remote_node_context_state_table[] = {
1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190
	[SCIC_SDS_REMOTE_NODE_CONTEXT_INITIAL_STATE] = {
		.enter_state = scic_sds_remote_node_context_initial_state_enter,
	},
	[SCIC_SDS_REMOTE_NODE_CONTEXT_POSTING_STATE] = {
		.enter_state = scic_sds_remote_node_context_posting_state_enter,
	},
	[SCIC_SDS_REMOTE_NODE_CONTEXT_INVALIDATING_STATE] = {
		.enter_state = scic_sds_remote_node_context_invalidating_state_enter,
	},
	[SCIC_SDS_REMOTE_NODE_CONTEXT_RESUMING_STATE] = {
		.enter_state = scic_sds_remote_node_context_resuming_state_enter,
	},
	[SCIC_SDS_REMOTE_NODE_CONTEXT_READY_STATE] = {
		.enter_state = scic_sds_remote_node_context_ready_state_enter,
	},
	[SCIC_SDS_REMOTE_NODE_CONTEXT_TX_SUSPENDED_STATE] = {
		.enter_state = scic_sds_remote_node_context_tx_suspended_state_enter,
	},
	[SCIC_SDS_REMOTE_NODE_CONTEXT_TX_RX_SUSPENDED_STATE] = {
		.enter_state = scic_sds_remote_node_context_tx_rx_suspended_state_enter,
	},
	[SCIC_SDS_REMOTE_NODE_CONTEXT_AWAIT_SUSPENSION_STATE] = {
		.enter_state = scic_sds_remote_node_context_await_suspension_state_enter,
	},
};

1191 1192
void scic_sds_remote_node_context_construct(struct scic_sds_remote_node_context *rnc,
					    u16 remote_node_index)
D
Dan Williams 已提交
1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207
{
	memset(rnc, 0, sizeof(struct scic_sds_remote_node_context));

	rnc->remote_node_index = remote_node_index;
	rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_UNSPECIFIED;

	sci_base_state_machine_construct(
		&rnc->state_machine,
		&rnc->parent,
		scic_sds_remote_node_context_state_table,
		SCIC_SDS_REMOTE_NODE_CONTEXT_INITIAL_STATE
		);

	sci_base_state_machine_start(&rnc->state_machine);
}