1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause OR GPL-2.0 3 * 4 * This file is provided under a dual BSD/GPLv2 license. When using or 5 * redistributing this file, you may do so under either license. 6 * 7 * GPL LICENSE SUMMARY 8 * 9 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of version 2 of the GNU General Public License as 13 * published by the Free Software Foundation. 14 * 15 * This program is distributed in the hope that it will be useful, but 16 * WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 * General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 23 * The full GNU General Public License is included in this distribution 24 * in the file called LICENSE.GPL. 25 * 26 * BSD LICENSE 27 * 28 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. 29 * All rights reserved. 30 * 31 * Redistribution and use in source and binary forms, with or without 32 * modification, are permitted provided that the following conditions 33 * are met: 34 * 35 * * Redistributions of source code must retain the above copyright 36 * notice, this list of conditions and the following disclaimer. 37 * * Redistributions in binary form must reproduce the above copyright 38 * notice, this list of conditions and the following disclaimer in 39 * the documentation and/or other materials provided with the 40 * distribution. 41 * 42 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 43 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 44 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 45 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 46 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 47 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 48 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 49 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 50 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 51 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 52 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 53 */ 54 55 #include <sys/cdefs.h> 56 __FBSDID("$FreeBSD$"); 57 58 /** 59 * @file 60 * 61 * @brief 62 */ 63 64 #include <dev/isci/scil/scic_remote_device.h> 65 66 #include <dev/isci/scil/scif_sas_remote_device.h> 67 #include <dev/isci/scil/scif_sas_domain.h> 68 #include <dev/isci/scil/scif_sas_logger.h> 69 70 71 /** 72 * This constant indicates the number of milliseconds to wait for the core 73 * to start/stop it's remote device object. 74 */ 75 //#define SCIF_SAS_REMOTE_DEVICE_CORE_OP_TIMEOUT 1000 76 77 //****************************************************************************** 78 //* P R O T E C T E D M E T H O D S 79 //****************************************************************************** 80 81 /** 82 * @brief This method implements the actions taken when entering the 83 * INITIAL state. This basically, causes an immediate transition 84 * into the STOPPED state. 85 * 86 * @param[in] object This parameter specifies the base object for which 87 * the state transition is occurring. This is cast into a 88 * SCIF_SAS_REMOTE_DEVICE object in the method implementation. 89 * 90 * @return none 91 */ 92 static 93 void scif_sas_remote_device_initial_state_enter( 94 SCI_BASE_OBJECT_T *object 95 ) 96 { 97 SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object; 98 99 SET_STATE_HANDLER( 100 fw_device, 101 scif_sas_remote_device_state_handler_table, 102 SCI_BASE_REMOTE_DEVICE_STATE_INITIAL 103 ); 104 105 // Initial state is a transitional state to the stopped state 106 sci_base_state_machine_change_state( 107 &fw_device->parent.state_machine, 108 SCI_BASE_REMOTE_DEVICE_STATE_STOPPED 109 ); 110 } 111 112 /** 113 * @brief This method implements the actions taken when entering the 114 * STOPPED state. This method updates the domains count of started 115 * devices and will invoke the destruct method if this entrance into 116 * the STOPPED state was due to a scif_remote_device_destruct() 117 * call by the user. 118 * 119 * @param[in] object This parameter specifies the base object for which 120 * the state transition is occurring. This is cast into a 121 * SCIF_SAS_REMOTE_DEVICE object in the method implementation. 122 * 123 * @return none 124 */ 125 static 126 void scif_sas_remote_device_stopped_state_enter( 127 SCI_BASE_OBJECT_T *object 128 ) 129 { 130 SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object; 131 132 SET_STATE_HANDLER( 133 fw_device, 134 scif_sas_remote_device_state_handler_table, 135 SCI_BASE_REMOTE_DEVICE_STATE_STOPPED 136 ); 137 138 // There should be no outstanding requests for this device in the 139 // stopped state. 140 ASSERT(fw_device->request_count == 0); 141 142 // If we are entering the stopped state as a result of a destruct 143 // request, then let's perform the actual destruct operation now. 144 if (fw_device->destruct_when_stopped == TRUE) 145 fw_device->operation_status 146 = fw_device->state_handlers->parent.destruct_handler( 147 &fw_device->parent 148 ); 149 150 /// @todo What should we do if this call fails? 151 fw_device->domain->state_handlers->device_stop_complete_handler( 152 &fw_device->domain->parent, &fw_device->parent 153 ); 154 } 155 156 /** 157 * @brief This method implements the actions taken when entering the 158 * STARTING state. This method will attempt to start the core 159 * remote device and will kick-start the starting sub-state machine 160 * if no errors are encountered. 161 * 162 * @param[in] object This parameter specifies the base object for which 163 * the state transition is occurring. This is cast into a 164 * SCIF_SAS_REMOTE_DEVICE object in the method implementation. 165 * 166 * @return none 167 */ 168 static 169 void scif_sas_remote_device_starting_state_enter( 170 SCI_BASE_OBJECT_T *object 171 ) 172 { 173 SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object; 174 175 SET_STATE_HANDLER( 176 fw_device, 177 scif_sas_remote_device_state_handler_table, 178 SCI_BASE_REMOTE_DEVICE_STATE_STARTING 179 ); 180 181 SCIF_LOG_INFO(( 182 sci_base_object_get_logger(fw_device), 183 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_REMOTE_DEVICE_CONFIG, 184 "RemoteDevice:0x%x starting/configuring\n", 185 fw_device 186 )); 187 188 fw_device->destination_state = 189 SCIF_SAS_REMOTE_DEVICE_DESTINATION_STATE_READY; 190 191 sci_base_state_machine_start(&fw_device->starting_substate_machine); 192 193 fw_device->operation_status = scic_remote_device_start( 194 fw_device->core_object, 195 SCIF_SAS_REMOTE_DEVICE_CORE_OP_TIMEOUT 196 ); 197 198 if (fw_device->operation_status != SCI_SUCCESS) 199 { 200 fw_device->state_handlers->parent.fail_handler(&fw_device->parent); 201 202 // Something is seriously wrong. Starting the core remote device 203 // shouldn't fail in anyway in this state. 204 scif_cb_controller_error(fw_device->domain->controller, 205 SCI_CONTROLLER_REMOTE_DEVICE_ERROR); 206 } 207 } 208 209 /** 210 * @brief This method implements the actions taken when exiting the 211 * STARTING state. Currently this method simply stops the 212 * sub-state machine. 213 * 214 * @param[in] object This parameter specifies the base object for which 215 * the state transition is occurring. This is cast into a 216 * SCIF_SAS_REMOTE_DEVICE object in the method implementation. 217 * 218 * @return none 219 */ 220 static 221 void scif_sas_remote_device_starting_state_exit( 222 SCI_BASE_OBJECT_T *object 223 ) 224 { 225 SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object; 226 227 fw_device->destination_state = 228 SCIF_SAS_REMOTE_DEVICE_DESTINATION_STATE_UNSPECIFIED; 229 230 // Transition immediately into the operational sub-state. 231 sci_base_state_machine_stop(&fw_device->starting_substate_machine); 232 } 233 234 /** 235 * @brief This method implements the actions taken when entering the 236 * READY state. Currently this method simply starts the 237 * sub-state machine. 238 * 239 * @param[in] object This parameter specifies the base object for which 240 * the state transition is occurring. This is cast into a 241 * SCIF_SAS_REMOTE_DEVICE object in the method implementation. 242 * 243 * @return none 244 */ 245 static 246 void scif_sas_remote_device_ready_state_enter( 247 SCI_BASE_OBJECT_T *object 248 ) 249 { 250 SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object; 251 252 // Transition immediately into the operational sub-state. 253 sci_base_state_machine_start(&fw_device->ready_substate_machine); 254 255 #if defined(DISABLE_WIDE_PORTED_TARGETS) 256 scif_sas_domain_remote_device_start_complete(fw_device->domain,fw_device); 257 #endif 258 } 259 260 /** 261 * @brief This method implements the actions taken when exiting the 262 * READY state. Currently this method simply stops the 263 * sub-state machine. 264 * 265 * @param[in] object This parameter specifies the base object for which 266 * the state transition is occurring. This is cast into a 267 * SCIF_SAS_REMOTE_DEVICE object in the method implementation. 268 * 269 * @return none 270 */ 271 static 272 void scif_sas_remote_device_ready_state_exit( 273 SCI_BASE_OBJECT_T *object 274 ) 275 { 276 SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object; 277 278 // Transition immediately into the operational sub-state. 279 sci_base_state_machine_stop(&fw_device->ready_substate_machine); 280 } 281 282 /** 283 * @brief This method implements the actions taken when entering the 284 * STOPPING state. This includes: stopping the core remote device 285 * and handling any errors that may occur. 286 * 287 * @param[in] object This parameter specifies the base object for which 288 * the state transition is occurring. This is cast into a 289 * SCIF_SAS_REMOTE_DEVICE object in the method implementation. 290 * 291 * @return none 292 */ 293 static 294 void scif_sas_remote_device_stopping_state_enter( 295 SCI_BASE_OBJECT_T *object 296 ) 297 { 298 SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object; 299 300 SET_STATE_HANDLER( 301 fw_device, 302 scif_sas_remote_device_state_handler_table, 303 SCI_BASE_REMOTE_DEVICE_STATE_STOPPING 304 ); 305 306 fw_device->operation_status = scic_remote_device_stop( 307 fw_device->core_object, 308 SCIF_SAS_REMOTE_DEVICE_CORE_OP_TIMEOUT 309 ); 310 311 // If there was a failure, then transition directly to the stopped state. 312 if (fw_device->operation_status != SCI_SUCCESS) 313 { 314 /** 315 * @todo We may want to consider adding handling to reset the 316 * structure data for the framework and core devices here 317 * in order to help aid recovery. 318 */ 319 320 fw_device->state_handlers->stop_complete_handler( 321 fw_device, fw_device->operation_status 322 ); 323 } 324 } 325 326 /** 327 * @brief This method implements the actions taken when exiting the 328 * STOPPING state. 329 * 330 * @param[in] object This parameter specifies the base object for which 331 * the state transition is occurring. This is cast into a 332 * SCIF_SAS_REMOTE_DEVICE object in the method implementation. 333 * 334 * @return none 335 */ 336 static 337 void scif_sas_remote_device_stopping_state_exit( 338 SCI_BASE_OBJECT_T *object 339 ) 340 { 341 SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object; 342 343 // Let the domain know that the device has stopped 344 fw_device->domain->device_start_count--; 345 } 346 347 /** 348 * @brief This method implements the actions taken when entering the 349 * FAILED state. This includes setting the state handler methods 350 * and issuing a scif_cb_remote_device_failed() notification to 351 * the user. 352 * 353 * @param[in] object This parameter specifies the base object for which 354 * the state transition is occurring. This is cast into a 355 * SCIF_SAS_REMOTE_DEVICE object in the method implementation. 356 * 357 * @return none 358 */ 359 static 360 void scif_sas_remote_device_failed_state_enter( 361 SCI_BASE_OBJECT_T *object 362 ) 363 { 364 SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object; 365 366 SET_STATE_HANDLER( 367 fw_device, 368 scif_sas_remote_device_state_handler_table, 369 SCI_BASE_REMOTE_DEVICE_STATE_FAILED 370 ); 371 372 SCIF_LOG_INFO(( 373 sci_base_object_get_logger(fw_device), 374 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_REMOTE_DEVICE_CONFIG, 375 "Domain:0x%x Device:0x%x Status:0x%x device failed\n", 376 fw_device->domain, fw_device, fw_device->operation_status 377 )); 378 379 // Notify the user that the device has failed. 380 scif_cb_remote_device_failed( 381 fw_device->domain->controller, 382 fw_device->domain, 383 fw_device, 384 fw_device->operation_status 385 ); 386 387 // Only call start_complete for the remote device if the device failed 388 // from the STARTING state. 389 if (fw_device->parent.state_machine.previous_state_id 390 == SCI_BASE_REMOTE_DEVICE_STATE_STARTING) 391 scif_sas_domain_remote_device_start_complete(fw_device->domain,fw_device); 392 } 393 394 /** 395 * @brief This method implements the actions taken when entering the RESETTING 396 * state. 397 * 398 * @param[in] object This parameter specifies the base object for which 399 * the state transition is occurring. This is cast into a 400 * SCIF_SAS_REMOTE_DEVICE object in the method implementation. 401 * 402 * @return none 403 */ 404 static 405 void scif_sas_remote_device_resetting_state_enter( 406 SCI_BASE_OBJECT_T *object 407 ) 408 { 409 } 410 411 #if !defined(DISABLE_WIDE_PORTED_TARGETS) 412 /** 413 * @brief This method implements the actions taken when entering the UPDATING 414 * PORT WIDTH state. 415 * 416 * @param[in] object This parameter specifies the base object for which 417 * the state transition is occurring. This is cast into a 418 * SCIF_SAS_REMOTE_DEVICE object in the method implementation. 419 * 420 * @return none 421 */ 422 static 423 void scif_sas_remote_device_updating_port_width_state_enter( 424 SCI_BASE_OBJECT_T *object 425 ) 426 { 427 SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object; 428 429 SET_STATE_HANDLER( 430 fw_device, 431 scif_sas_remote_device_state_handler_table, 432 SCI_BASE_REMOTE_DEVICE_STATE_UPDATING_PORT_WIDTH 433 ); 434 435 fw_device->destination_state = SCIF_SAS_REMOTE_DEVICE_DESTINATION_STATE_READY; 436 437 //If the request count is zero, go ahead to update the RNC. 438 //If not, don't do anything for now. The IO complete handler of this state 439 //will update the RNC whenever the request count goes down to zero. 440 if (fw_device->request_count == 0) 441 { 442 //stop the device, upon the stop complete callback, start the device again 443 //with the updated port width. 444 scic_remote_device_stop( 445 fw_device->core_object, SCIF_SAS_REMOTE_DEVICE_CORE_OP_TIMEOUT); 446 } 447 } 448 449 450 /** 451 * @brief This method implements the actions taken when exiting the 452 * STOPPING state. 453 * 454 * @param[in] object This parameter specifies the base object for which 455 * the state transition is occurring. This is cast into a 456 * SCIF_SAS_REMOTE_DEVICE object in the method implementation. 457 * 458 * @return none 459 */ 460 static 461 void scif_sas_remote_device_updating_port_width_state_exit( 462 SCI_BASE_OBJECT_T *object 463 ) 464 { 465 SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object; 466 467 fw_device->destination_state = 468 SCIF_SAS_REMOTE_DEVICE_DESTINATION_STATE_UNSPECIFIED; 469 } 470 471 472 #endif //#if !defined(DISABLE_WIDE_PORTED_TARGETS) 473 474 /** 475 * @brief This method implements the actions taken when entering the 476 * FINAL state. This includes setting the FINAL state handler 477 * methods. 478 * 479 * @param[in] object This parameter specifies the base object for which 480 * the state transition is occurring. This is cast into a 481 * SCIF_SAS_REMOTE_DEVICE object in the method implementation. 482 * 483 * @return none 484 */ 485 static 486 void scif_sas_remote_device_final_state_enter( 487 SCI_BASE_OBJECT_T *object 488 ) 489 { 490 SCIF_SAS_REMOTE_DEVICE_T * fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)object; 491 492 SET_STATE_HANDLER( 493 fw_device, 494 scif_sas_remote_device_state_handler_table, 495 SCI_BASE_REMOTE_DEVICE_STATE_FINAL 496 ); 497 } 498 499 500 SCI_BASE_STATE_T 501 scif_sas_remote_device_state_table[SCI_BASE_REMOTE_DEVICE_MAX_STATES] = 502 { 503 { 504 SCI_BASE_REMOTE_DEVICE_STATE_INITIAL, 505 scif_sas_remote_device_initial_state_enter, 506 NULL 507 }, 508 { 509 SCI_BASE_REMOTE_DEVICE_STATE_STOPPED, 510 scif_sas_remote_device_stopped_state_enter, 511 NULL 512 }, 513 { 514 SCI_BASE_REMOTE_DEVICE_STATE_STARTING, 515 scif_sas_remote_device_starting_state_enter, 516 scif_sas_remote_device_starting_state_exit 517 }, 518 { 519 SCI_BASE_REMOTE_DEVICE_STATE_READY, 520 scif_sas_remote_device_ready_state_enter, 521 scif_sas_remote_device_ready_state_exit 522 }, 523 { 524 SCI_BASE_REMOTE_DEVICE_STATE_STOPPING, 525 scif_sas_remote_device_stopping_state_enter, 526 scif_sas_remote_device_stopping_state_exit 527 }, 528 { 529 SCI_BASE_REMOTE_DEVICE_STATE_FAILED, 530 scif_sas_remote_device_failed_state_enter, 531 NULL 532 }, 533 { 534 SCI_BASE_REMOTE_DEVICE_STATE_RESETTING, 535 scif_sas_remote_device_resetting_state_enter, 536 NULL 537 }, 538 #if !defined(DISABLE_WIDE_PORTED_TARGETS) 539 { 540 SCI_BASE_REMOTE_DEVICE_STATE_UPDATING_PORT_WIDTH, 541 scif_sas_remote_device_updating_port_width_state_enter, 542 scif_sas_remote_device_updating_port_width_state_exit 543 }, 544 #endif //#if !defined(DISABLE_WIDE_PORTED_TARGETS) 545 { 546 SCI_BASE_REMOTE_DEVICE_STATE_FINAL, 547 scif_sas_remote_device_final_state_enter, 548 NULL 549 }, 550 }; 551 552