2 * This file is provided under a dual BSD/GPLv2 license. When using or
3 * redistributing this file, you may do so under either license.
7 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of version 2 of the GNU General Public License as
11 * published by the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
21 * The full GNU General Public License is included in this distribution
22 * in the file called LICENSE.GPL.
26 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
27 * All rights reserved.
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
33 * * Redistributions of source code must retain the above copyright
34 * notice, this list of conditions and the following disclaimer.
35 * * Redistributions in binary form must reproduce the above copyright
36 * notice, this list of conditions and the following disclaimer in
37 * the documentation and/or other materials provided with the
40 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
41 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
42 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
43 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
44 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
46 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
47 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
48 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
49 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
50 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
53 #include <sys/cdefs.h>
54 __FBSDID("$FreeBSD$");
62 #include <dev/isci/scil/scic_remote_device.h>
64 #include <dev/isci/scil/scif_sas_remote_device.h>
65 #include <dev/isci/scil/scif_sas_domain.h>
66 #include <dev/isci/scil/scif_sas_logger.h>
70 * This constant indicates the number of milliseconds to wait for the core
71 * to start/stop it's remote device object.
73 //#define SCIF_SAS_REMOTE_DEVICE_CORE_OP_TIMEOUT 1000
75 //******************************************************************************
76 //* P R O T E C T E D M E T H O D S
77 //******************************************************************************
80 * @brief This method implements the actions taken when entering the
81 * INITIAL state. This basically, causes an immediate transition
82 * into the STOPPED state.
84 * @param[in] object This parameter specifies the base object for which
85 * the state transition is occurring. This is cast into a
86 * SCIF_SAS_REMOTE_DEVICE object in the method implementation.
91 void scif_sas_remote_device_initial_state_enter(
92 SCI_BASE_OBJECT_T *object
95 SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
99 scif_sas_remote_device_state_handler_table,
100 SCI_BASE_REMOTE_DEVICE_STATE_INITIAL
103 // Initial state is a transitional state to the stopped state
104 sci_base_state_machine_change_state(
105 &fw_device->parent.state_machine,
106 SCI_BASE_REMOTE_DEVICE_STATE_STOPPED
111 * @brief This method implements the actions taken when entering the
112 * STOPPED state. This method updates the domains count of started
113 * devices and will invoke the destruct method if this entrance into
114 * the STOPPED state was due to a scif_remote_device_destruct()
117 * @param[in] object This parameter specifies the base object for which
118 * the state transition is occurring. This is cast into a
119 * SCIF_SAS_REMOTE_DEVICE object in the method implementation.
124 void scif_sas_remote_device_stopped_state_enter(
125 SCI_BASE_OBJECT_T *object
128 SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
132 scif_sas_remote_device_state_handler_table,
133 SCI_BASE_REMOTE_DEVICE_STATE_STOPPED
136 // There should be no outstanding requests for this device in the
138 ASSERT(fw_device->request_count == 0);
140 // If we are entering the stopped state as a result of a destruct
141 // request, then let's perform the actual destruct operation now.
142 if (fw_device->destruct_when_stopped == TRUE)
143 fw_device->operation_status
144 = fw_device->state_handlers->parent.destruct_handler(
148 /// @todo What should we do if this call fails?
149 fw_device->domain->state_handlers->device_stop_complete_handler(
150 &fw_device->domain->parent, &fw_device->parent
155 * @brief This method implements the actions taken when entering the
156 * STARTING state. This method will attempt to start the core
157 * remote device and will kick-start the starting sub-state machine
158 * if no errors are encountered.
160 * @param[in] object This parameter specifies the base object for which
161 * the state transition is occurring. This is cast into a
162 * SCIF_SAS_REMOTE_DEVICE object in the method implementation.
167 void scif_sas_remote_device_starting_state_enter(
168 SCI_BASE_OBJECT_T *object
171 SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
175 scif_sas_remote_device_state_handler_table,
176 SCI_BASE_REMOTE_DEVICE_STATE_STARTING
180 sci_base_object_get_logger(fw_device),
181 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_REMOTE_DEVICE_CONFIG,
182 "RemoteDevice:0x%x starting/configuring\n",
186 fw_device->destination_state =
187 SCIF_SAS_REMOTE_DEVICE_DESTINATION_STATE_READY;
189 sci_base_state_machine_start(&fw_device->starting_substate_machine);
191 fw_device->operation_status = scic_remote_device_start(
192 fw_device->core_object,
193 SCIF_SAS_REMOTE_DEVICE_CORE_OP_TIMEOUT
196 if (fw_device->operation_status != SCI_SUCCESS)
198 fw_device->state_handlers->parent.fail_handler(&fw_device->parent);
200 // Something is seriously wrong. Starting the core remote device
201 // shouldn't fail in anyway in this state.
202 scif_cb_controller_error(fw_device->domain->controller,
203 SCI_CONTROLLER_REMOTE_DEVICE_ERROR);
208 * @brief This method implements the actions taken when exiting the
209 * STARTING state. Currently this method simply stops the
212 * @param[in] object This parameter specifies the base object for which
213 * the state transition is occurring. This is cast into a
214 * SCIF_SAS_REMOTE_DEVICE object in the method implementation.
219 void scif_sas_remote_device_starting_state_exit(
220 SCI_BASE_OBJECT_T *object
223 SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
225 fw_device->destination_state =
226 SCIF_SAS_REMOTE_DEVICE_DESTINATION_STATE_UNSPECIFIED;
228 // Transition immediately into the operational sub-state.
229 sci_base_state_machine_stop(&fw_device->starting_substate_machine);
233 * @brief This method implements the actions taken when entering the
234 * READY state. Currently this method simply starts the
237 * @param[in] object This parameter specifies the base object for which
238 * the state transition is occurring. This is cast into a
239 * SCIF_SAS_REMOTE_DEVICE object in the method implementation.
244 void scif_sas_remote_device_ready_state_enter(
245 SCI_BASE_OBJECT_T *object
248 SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
250 // Transition immediately into the operational sub-state.
251 sci_base_state_machine_start(&fw_device->ready_substate_machine);
253 #if defined(DISABLE_WIDE_PORTED_TARGETS)
254 scif_sas_domain_remote_device_start_complete(fw_device->domain,fw_device);
259 * @brief This method implements the actions taken when exiting the
260 * READY state. Currently this method simply stops the
263 * @param[in] object This parameter specifies the base object for which
264 * the state transition is occurring. This is cast into a
265 * SCIF_SAS_REMOTE_DEVICE object in the method implementation.
270 void scif_sas_remote_device_ready_state_exit(
271 SCI_BASE_OBJECT_T *object
274 SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
276 // Transition immediately into the operational sub-state.
277 sci_base_state_machine_stop(&fw_device->ready_substate_machine);
281 * @brief This method implements the actions taken when entering the
282 * STOPPING state. This includes: stopping the core remote device
283 * and handling any errors that may occur.
285 * @param[in] object This parameter specifies the base object for which
286 * the state transition is occurring. This is cast into a
287 * SCIF_SAS_REMOTE_DEVICE object in the method implementation.
292 void scif_sas_remote_device_stopping_state_enter(
293 SCI_BASE_OBJECT_T *object
296 SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
300 scif_sas_remote_device_state_handler_table,
301 SCI_BASE_REMOTE_DEVICE_STATE_STOPPING
304 fw_device->operation_status = scic_remote_device_stop(
305 fw_device->core_object,
306 SCIF_SAS_REMOTE_DEVICE_CORE_OP_TIMEOUT
309 // If there was a failure, then transition directly to the stopped state.
310 if (fw_device->operation_status != SCI_SUCCESS)
313 * @todo We may want to consider adding handling to reset the
314 * structure data for the framework and core devices here
315 * in order to help aid recovery.
318 fw_device->state_handlers->stop_complete_handler(
319 fw_device, fw_device->operation_status
325 * @brief This method implements the actions taken when exiting the
328 * @param[in] object This parameter specifies the base object for which
329 * the state transition is occurring. This is cast into a
330 * SCIF_SAS_REMOTE_DEVICE object in the method implementation.
335 void scif_sas_remote_device_stopping_state_exit(
336 SCI_BASE_OBJECT_T *object
339 SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
341 // Let the domain know that the device has stopped
342 fw_device->domain->device_start_count--;
346 * @brief This method implements the actions taken when entering the
347 * FAILED state. This includes setting the state handler methods
348 * and issuing a scif_cb_remote_device_failed() notification to
351 * @param[in] object This parameter specifies the base object for which
352 * the state transition is occurring. This is cast into a
353 * SCIF_SAS_REMOTE_DEVICE object in the method implementation.
358 void scif_sas_remote_device_failed_state_enter(
359 SCI_BASE_OBJECT_T *object
362 SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
366 scif_sas_remote_device_state_handler_table,
367 SCI_BASE_REMOTE_DEVICE_STATE_FAILED
371 sci_base_object_get_logger(fw_device),
372 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_REMOTE_DEVICE_CONFIG,
373 "Domain:0x%x Device:0x%x Status:0x%x device failed\n",
374 fw_device->domain, fw_device, fw_device->operation_status
377 // Notify the user that the device has failed.
378 scif_cb_remote_device_failed(
379 fw_device->domain->controller,
382 fw_device->operation_status
385 // Only call start_complete for the remote device if the device failed
386 // from the STARTING state.
387 if (fw_device->parent.state_machine.previous_state_id
388 == SCI_BASE_REMOTE_DEVICE_STATE_STARTING)
389 scif_sas_domain_remote_device_start_complete(fw_device->domain,fw_device);
393 * @brief This method implements the actions taken when entering the RESETTING
396 * @param[in] object This parameter specifies the base object for which
397 * the state transition is occurring. This is cast into a
398 * SCIF_SAS_REMOTE_DEVICE object in the method implementation.
403 void scif_sas_remote_device_resetting_state_enter(
404 SCI_BASE_OBJECT_T *object
409 #if !defined(DISABLE_WIDE_PORTED_TARGETS)
411 * @brief This method implements the actions taken when entering the UPDATING
414 * @param[in] object This parameter specifies the base object for which
415 * the state transition is occurring. This is cast into a
416 * SCIF_SAS_REMOTE_DEVICE object in the method implementation.
421 void scif_sas_remote_device_updating_port_width_state_enter(
422 SCI_BASE_OBJECT_T *object
425 SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
429 scif_sas_remote_device_state_handler_table,
430 SCI_BASE_REMOTE_DEVICE_STATE_UPDATING_PORT_WIDTH
433 fw_device->destination_state = SCIF_SAS_REMOTE_DEVICE_DESTINATION_STATE_READY;
435 //If the request count is zero, go ahead to update the RNC.
436 //If not, don't do anything for now. The IO complete handler of this state
437 //will update the RNC whenever the request count goes down to zero.
438 if (fw_device->request_count == 0)
440 //stop the device, upon the stop complete callback, start the device again
441 //with the updated port width.
442 scic_remote_device_stop(
443 fw_device->core_object, SCIF_SAS_REMOTE_DEVICE_CORE_OP_TIMEOUT);
449 * @brief This method implements the actions taken when exiting the
452 * @param[in] object This parameter specifies the base object for which
453 * the state transition is occurring. This is cast into a
454 * SCIF_SAS_REMOTE_DEVICE object in the method implementation.
459 void scif_sas_remote_device_updating_port_width_state_exit(
460 SCI_BASE_OBJECT_T *object
463 SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
465 fw_device->destination_state =
466 SCIF_SAS_REMOTE_DEVICE_DESTINATION_STATE_UNSPECIFIED;
470 #endif //#if !defined(DISABLE_WIDE_PORTED_TARGETS)
473 * @brief This method implements the actions taken when entering the
474 * FINAL state. This includes setting the FINAL state handler
477 * @param[in] object This parameter specifies the base object for which
478 * the state transition is occurring. This is cast into a
479 * SCIF_SAS_REMOTE_DEVICE object in the method implementation.
484 void scif_sas_remote_device_final_state_enter(
485 SCI_BASE_OBJECT_T *object
488 SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object;
492 scif_sas_remote_device_state_handler_table,
493 SCI_BASE_REMOTE_DEVICE_STATE_FINAL
499 scif_sas_remote_device_state_table[SCI_BASE_REMOTE_DEVICE_MAX_STATES] =
502 SCI_BASE_REMOTE_DEVICE_STATE_INITIAL,
503 scif_sas_remote_device_initial_state_enter,
507 SCI_BASE_REMOTE_DEVICE_STATE_STOPPED,
508 scif_sas_remote_device_stopped_state_enter,
512 SCI_BASE_REMOTE_DEVICE_STATE_STARTING,
513 scif_sas_remote_device_starting_state_enter,
514 scif_sas_remote_device_starting_state_exit
517 SCI_BASE_REMOTE_DEVICE_STATE_READY,
518 scif_sas_remote_device_ready_state_enter,
519 scif_sas_remote_device_ready_state_exit
522 SCI_BASE_REMOTE_DEVICE_STATE_STOPPING,
523 scif_sas_remote_device_stopping_state_enter,
524 scif_sas_remote_device_stopping_state_exit
527 SCI_BASE_REMOTE_DEVICE_STATE_FAILED,
528 scif_sas_remote_device_failed_state_enter,
532 SCI_BASE_REMOTE_DEVICE_STATE_RESETTING,
533 scif_sas_remote_device_resetting_state_enter,
536 #if !defined(DISABLE_WIDE_PORTED_TARGETS)
538 SCI_BASE_REMOTE_DEVICE_STATE_UPDATING_PORT_WIDTH,
539 scif_sas_remote_device_updating_port_width_state_enter,
540 scif_sas_remote_device_updating_port_width_state_exit
542 #endif //#if !defined(DISABLE_WIDE_PORTED_TARGETS)
544 SCI_BASE_REMOTE_DEVICE_STATE_FINAL,
545 scif_sas_remote_device_final_state_enter,