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 This file contains the implementation of the SCIF_SAS_DOMAIN 62 * object. 63 */ 64 65 #include <dev/isci/scil/intel_sas.h> 66 #include <dev/isci/scil/sci_fast_list.h> 67 #include <dev/isci/scil/scic_controller.h> 68 #include <dev/isci/scil/scic_port.h> 69 #include <dev/isci/scil/scic_remote_device.h> 70 #include <dev/isci/scil/scic_io_request.h> 71 #include <dev/isci/scil/scic_user_callback.h> 72 #include <dev/isci/scil/scif_user_callback.h> 73 #include <dev/isci/scil/sci_abstract_list.h> 74 #include <dev/isci/scil/sci_base_iterator.h> 75 76 #include <dev/isci/scil/scif_sas_logger.h> 77 #include <dev/isci/scil/scif_sas_domain.h> 78 #include <dev/isci/scil/scif_sas_controller.h> 79 #include <dev/isci/scil/scif_sas_remote_device.h> 80 #include <dev/isci/scil/scif_sas_smp_remote_device.h> 81 #include <dev/isci/scil/sci_util.h> 82 83 //****************************************************************************** 84 //* P R I V A T E M E T H O D S 85 //****************************************************************************** 86 87 /** 88 * @brief This method will attempt to handle an operation timeout (i.e. 89 * discovery or reset). 90 * 91 * @param[in] cookie This parameter specifies the domain in which the 92 * timeout occurred. 93 * 94 * @return none 95 */ 96 static 97 void scif_sas_domain_operation_timeout_handler( 98 void * cookie 99 ) 100 { 101 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) cookie; 102 U32 state; 103 104 state = sci_base_state_machine_get_state(&fw_domain->parent.state_machine); 105 106 // Based upon the state of the domain, we know whether we were in the 107 // process of performing discovery or a reset. 108 if (state == SCI_BASE_DOMAIN_STATE_DISCOVERING) 109 { 110 SCIF_LOG_WARNING(( 111 sci_base_object_get_logger(fw_domain), 112 SCIF_LOG_OBJECT_DOMAIN, 113 "Domain:0x%x State:0x%x DISCOVER timeout!\n", 114 fw_domain, state 115 )); 116 117 fw_domain->operation.status = SCI_FAILURE_TIMEOUT; 118 119 //search all the smp devices in the domain and cancel their activities 120 //if there is any outstanding activity remained. The smp devices will terminate 121 //all the started internal IOs. 122 scif_sas_domain_cancel_smp_activities(fw_domain); 123 124 scif_sas_domain_continue_discover(fw_domain); 125 } 126 else 127 { 128 SCIF_LOG_ERROR(( 129 sci_base_object_get_logger(fw_domain), 130 SCIF_LOG_OBJECT_DOMAIN, 131 "Domain:0x%x State:0x%x operation timeout in invalid state\n", 132 fw_domain, state 133 )); 134 } 135 } 136 137 //****************************************************************************** 138 //* P U B L I C M E T H O D S 139 //****************************************************************************** 140 141 SCI_PORT_HANDLE_T scif_domain_get_scic_port_handle( 142 SCI_DOMAIN_HANDLE_T domain 143 ) 144 { 145 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) domain; 146 147 if ( (fw_domain == NULL) || (fw_domain->core_object == SCI_INVALID_HANDLE) ) 148 return SCI_INVALID_HANDLE; 149 150 SCIF_LOG_WARNING(( 151 sci_base_object_get_logger(fw_domain), 152 SCIF_LOG_OBJECT_DOMAIN, 153 "Domain:0x%x no associated core port found\n", 154 fw_domain 155 )); 156 157 return fw_domain->core_object; 158 } 159 160 // --------------------------------------------------------------------------- 161 162 SCI_REMOTE_DEVICE_HANDLE_T scif_domain_get_device_by_sas_address( 163 SCI_DOMAIN_HANDLE_T domain, 164 SCI_SAS_ADDRESS_T * sas_address 165 ) 166 { 167 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) domain; 168 SCI_ABSTRACT_ELEMENT_T * element = sci_abstract_list_get_front( 169 &fw_domain->remote_device_list 170 ); 171 SCIF_SAS_REMOTE_DEVICE_T * fw_device; 172 SCI_SAS_ADDRESS_T fw_device_address; 173 174 SCIF_LOG_TRACE(( 175 sci_base_object_get_logger(domain), 176 SCIF_LOG_OBJECT_DOMAIN, 177 "scif_domain_get_device_by_sas_address(0x%x, 0x%x) enter\n", 178 domain, sas_address 179 )); 180 181 // Search the abstract list to see if there is a remote device with the 182 // same SAS address. 183 while (element != NULL) 184 { 185 fw_device = (SCIF_SAS_REMOTE_DEVICE_T*) 186 sci_abstract_list_get_object(element); 187 188 scic_remote_device_get_sas_address( 189 fw_device->core_object, &fw_device_address 190 ); 191 192 // Check to see if this is the device for which we are searching. 193 if ( (fw_device_address.low == sas_address->low) 194 && (fw_device_address.high == sas_address->high) ) 195 { 196 return fw_device; 197 } 198 199 element = sci_abstract_list_get_next(element); 200 } 201 202 return SCI_INVALID_HANDLE; 203 } 204 205 // --------------------------------------------------------------------------- 206 207 #if !defined(DISABLE_SCI_ITERATORS) 208 209 SCI_ITERATOR_HANDLE_T scif_domain_get_remote_device_iterator( 210 SCI_DOMAIN_HANDLE_T domain, 211 void * iterator_buffer 212 ) 213 { 214 SCI_ITERATOR_HANDLE_T iterator = (SCI_ITERATOR_HANDLE_T *)iterator_buffer; 215 216 sci_base_iterator_construct( 217 iterator, &((SCIF_SAS_DOMAIN_T*) domain)->remote_device_list 218 ); 219 220 221 return iterator; 222 } 223 224 #endif // !defined(DISABLE_SCI_ITERATORS) 225 226 // --------------------------------------------------------------------------- 227 228 SCI_STATUS scif_domain_discover( 229 SCI_DOMAIN_HANDLE_T domain, 230 U32 discover_timeout, 231 U32 device_timeout 232 ) 233 { 234 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) domain; 235 SCI_STATUS status = SCI_SUCCESS; 236 SCI_STATUS op_status = SCI_SUCCESS; 237 238 SCIF_LOG_TRACE(( 239 sci_base_object_get_logger(domain), 240 SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 241 "scif_domain_discover(0x%x, 0x%x, 0x%x) enter\n", 242 domain, discover_timeout, device_timeout 243 )); 244 245 // Check to make sure the size of the domain doesn't cause potential issues 246 // with the remote device timer and the domain timer. 247 if ((device_timeout * sci_abstract_list_size(&fw_domain->remote_device_list)) 248 > discover_timeout) 249 status = SCI_WARNING_TIMER_CONFLICT; 250 251 op_status = fw_domain->state_handlers->discover_handler( 252 &fw_domain->parent, discover_timeout, device_timeout 253 ); 254 255 // The status of the discover operation takes priority. 256 if ( (status == SCI_SUCCESS) 257 || (status != SCI_SUCCESS && op_status != SCI_SUCCESS) ) 258 { 259 status = op_status; 260 } 261 262 return status; 263 } 264 265 // --------------------------------------------------------------------------- 266 267 U32 scif_domain_get_suggested_discover_timeout( 268 SCI_DOMAIN_HANDLE_T domain 269 ) 270 { 271 U32 suggested_timeout = SCIF_DOMAIN_DISCOVER_TIMEOUT; //milli-seconds 272 return suggested_timeout; 273 } 274 275 // --------------------------------------------------------------------------- 276 277 void scic_cb_port_stop_complete( 278 SCI_CONTROLLER_HANDLE_T controller, 279 SCI_PORT_HANDLE_T port, 280 SCI_STATUS completion_status 281 ) 282 { 283 SCIF_LOG_TRACE(( 284 sci_base_object_get_logger((SCIF_SAS_DOMAIN_T*)sci_object_get_association(port)), 285 SCIF_LOG_OBJECT_DOMAIN, 286 "scic_cb_port_stop_complete(0x%x, 0x%x, 0x%x) enter\n", 287 controller, port, completion_status 288 )); 289 } 290 291 // --------------------------------------------------------------------------- 292 293 void scic_cb_port_ready( 294 SCI_CONTROLLER_HANDLE_T controller, 295 SCI_PORT_HANDLE_T port 296 ) 297 { 298 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) 299 sci_object_get_association(port); 300 301 SCIF_LOG_TRACE(( 302 sci_base_object_get_logger(fw_domain), 303 SCIF_LOG_OBJECT_DOMAIN, 304 "scic_cb_port_ready(0x%x, 0x%x) enter\n", 305 controller, port 306 )); 307 308 // The controller supplied with the port should match the controller 309 // saved in the domain. 310 ASSERT(sci_object_get_association(controller) == fw_domain->controller); 311 312 fw_domain->is_port_ready = TRUE; 313 314 fw_domain->state_handlers->port_ready_handler(&fw_domain->parent); 315 } 316 317 // --------------------------------------------------------------------------- 318 319 void scic_cb_port_not_ready( 320 SCI_CONTROLLER_HANDLE_T controller, 321 SCI_PORT_HANDLE_T port, 322 U32 reason_code 323 ) 324 { 325 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) 326 sci_object_get_association(port); 327 328 SCIF_LOG_TRACE(( 329 sci_base_object_get_logger(fw_domain), 330 SCIF_LOG_OBJECT_DOMAIN, 331 "scic_cb_port_not_ready(0x%x, 0x%x) enter\n", 332 controller, port 333 )); 334 335 // The controller supplied with the port should match the controller 336 // saved in the domain. 337 ASSERT(sci_object_get_association(controller) == fw_domain->controller); 338 339 // There is no need to take action on the port reconfiguring since it is 340 // just a change of the port width. 341 if (reason_code != SCIC_PORT_NOT_READY_RECONFIGURING) 342 { 343 fw_domain->is_port_ready = FALSE; 344 345 fw_domain->state_handlers->port_not_ready_handler( 346 &fw_domain->parent, reason_code); 347 } 348 } 349 350 // --------------------------------------------------------------------------- 351 352 void scic_cb_port_hard_reset_complete( 353 SCI_CONTROLLER_HANDLE_T controller, 354 SCI_PORT_HANDLE_T port, 355 SCI_STATUS completion_status 356 ) 357 { 358 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) 359 sci_object_get_association(port); 360 SCIF_SAS_REMOTE_DEVICE_T * fw_device; 361 SCI_FAST_LIST_ELEMENT_T * element = fw_domain->request_list.list_head; 362 SCIF_SAS_TASK_REQUEST_T * task_request = NULL; 363 364 SCIF_LOG_TRACE(( 365 sci_base_object_get_logger(fw_domain), 366 SCIF_LOG_OBJECT_DOMAIN, 367 "scic_cb_port_hard_reset_complete(0x%x, 0x%x, 0x%x) enter\n", 368 controller, port, completion_status 369 )); 370 371 while (element != NULL) 372 { 373 task_request = (SCIF_SAS_TASK_REQUEST_T*) sci_fast_list_get_object(element); 374 element = sci_fast_list_get_next(element); 375 376 if (scif_sas_task_request_get_function(task_request) 377 == SCI_SAS_HARD_RESET) 378 { 379 fw_device = task_request->parent.device; 380 381 if (fw_device->domain == fw_domain) 382 { 383 scic_remote_device_reset_complete(fw_device->core_object); 384 385 scif_cb_task_request_complete( 386 sci_object_get_association(controller), 387 fw_device, 388 task_request, 389 (SCI_TASK_STATUS) completion_status 390 ); 391 392 break; 393 } 394 } 395 } 396 } 397 398 // --------------------------------------------------------------------------- 399 400 void scic_cb_port_bc_change_primitive_recieved( 401 SCI_CONTROLLER_HANDLE_T controller, 402 SCI_PORT_HANDLE_T port, 403 SCI_PHY_HANDLE_T phy 404 ) 405 { 406 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) 407 sci_object_get_association(port); 408 409 SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T *) 410 sci_object_get_association(controller); 411 412 SCIF_LOG_TRACE(( 413 sci_base_object_get_logger(fw_domain), 414 SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 415 "scic_cb_port_bc_change_primitive_recieved(0x%x, 0x%x, 0x%x) enter\n", 416 controller, port, phy 417 )); 418 419 if (fw_domain->broadcast_change_count == 0) 420 { // Enable the BCN detection only if the bcn_count is zero. If bcn_count is 421 // not zero at this time, we won't enable BCN detection since all non-zero 422 // BCN_count means same to us. Furthermore, we avoid BCN storm by not 423 // always enabling the BCN_detection. 424 scic_port_enable_broadcast_change_notification(fw_domain->core_object); 425 } 426 427 fw_domain->broadcast_change_count++; 428 429 //if there is smp device on this domain that is in the middle of discover 430 //process or smp target reset, don't notify the driver layer. 431 if( ! scif_sas_domain_is_in_smp_activity(fw_domain) ) 432 // Notify the user that there is, potentially, a change to the domain. 433 scif_cb_domain_change_notification(fw_controller, fw_domain); 434 } 435 436 // --------------------------------------------------------------------------- 437 438 void scic_cb_port_bc_ses_primitive_recieved( 439 SCI_CONTROLLER_HANDLE_T controller, 440 SCI_PORT_HANDLE_T port, 441 SCI_PHY_HANDLE_T phy 442 ) 443 { 444 SCIF_LOG_TRACE(( 445 sci_base_object_get_logger(sci_object_get_association(port)), 446 SCIF_LOG_OBJECT_DOMAIN, 447 "scic_cb_port_bc_ses_primitive_received(0x%x, 0x%x, 0x%x) enter\n", 448 controller, port, phy 449 )); 450 } 451 452 // --------------------------------------------------------------------------- 453 454 void scic_cb_port_bc_expander_primitive_recieved( 455 SCI_CONTROLLER_HANDLE_T controller, 456 SCI_PORT_HANDLE_T port, 457 SCI_PHY_HANDLE_T phy 458 ) 459 { 460 SCIF_LOG_TRACE(( 461 sci_base_object_get_logger(sci_object_get_association(port)), 462 SCIF_LOG_OBJECT_DOMAIN, 463 "scic_cb_port_bc_expander_primitive_received(0x%x, 0x%x, 0x%x) enter\n", 464 controller, port, phy 465 )); 466 } 467 468 // --------------------------------------------------------------------------- 469 470 void scic_cb_port_bc_aen_primitive_recieved( 471 SCI_CONTROLLER_HANDLE_T controller, 472 SCI_PORT_HANDLE_T port, 473 SCI_PHY_HANDLE_T phy 474 ) 475 { 476 SCIF_LOG_TRACE(( 477 sci_base_object_get_logger(sci_object_get_association(port)), 478 SCIF_LOG_OBJECT_DOMAIN, 479 "scic_cb_port_bc_aen_primitive_received(0x%x, 0x%x, 0x%x) enter\n", 480 controller, port, phy 481 )); 482 } 483 484 // --------------------------------------------------------------------------- 485 486 void scic_cb_port_link_up( 487 SCI_CONTROLLER_HANDLE_T controller, 488 SCI_PORT_HANDLE_T port, 489 SCI_PHY_HANDLE_T phy 490 ) 491 { 492 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) 493 sci_object_get_association(port); 494 495 SCIF_LOG_TRACE(( 496 sci_base_object_get_logger(sci_object_get_association(port)), 497 SCIF_LOG_OBJECT_DOMAIN, 498 "scic_cb_port_link_up(0x%x, 0x%x, 0x%x) enter\n", 499 controller, port, phy 500 )); 501 502 scif_sas_domain_update_device_port_width(fw_domain, port); 503 } 504 505 // --------------------------------------------------------------------------- 506 507 void scic_cb_port_link_down( 508 SCI_CONTROLLER_HANDLE_T controller, 509 SCI_PORT_HANDLE_T port, 510 SCI_PHY_HANDLE_T phy 511 ) 512 { 513 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) 514 sci_object_get_association(port); 515 516 SCIF_LOG_TRACE(( 517 sci_base_object_get_logger(sci_object_get_association(port)), 518 SCIF_LOG_OBJECT_DOMAIN, 519 "scic_cb_port_link_down(0x%x, 0x%x, 0x%x) enter\n", 520 controller, port, phy 521 )); 522 523 scif_sas_domain_update_device_port_width(fw_domain, port); 524 } 525 526 //****************************************************************************** 527 //* P R O T E C T E D M E T H O D S 528 //****************************************************************************** 529 530 /** 531 * @brief This method constructs the framework's SAS domain object. During 532 * the construction process a linkage to the corresponding core port 533 * object. 534 * 535 * @param[in] domain This parameter specifies the domain object to be 536 * constructed. 537 * @param[in] domain_id This parameter specifies the ID for the domain 538 * object. 539 * @param[in] fw_controller This parameter specifies the controller managing 540 * the domain being constructed. 541 * 542 * @return none 543 */ 544 void scif_sas_domain_construct( 545 SCIF_SAS_DOMAIN_T * fw_domain, 546 U8 domain_id, 547 SCIF_SAS_CONTROLLER_T * fw_controller 548 ) 549 { 550 SCIF_LOG_TRACE(( 551 sci_base_object_get_logger(fw_controller), 552 SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_INITIALIZATION, 553 "scif_sas_domain_construct(0x%x, 0x%x, 0x%x) enter\n", 554 fw_domain, domain_id, fw_controller 555 )); 556 557 sci_base_domain_construct( 558 &fw_domain->parent, 559 sci_base_object_get_logger(fw_controller), 560 scif_sas_domain_state_table 561 ); 562 563 scif_sas_domain_initialize_state_logging(fw_domain); 564 565 sci_abstract_list_construct( 566 &fw_domain->remote_device_list, &fw_controller->free_remote_device_pool 567 ); 568 569 // Retrieve the core's port object that directly corresponds to this 570 // domain. 571 scic_controller_get_port_handle( 572 fw_controller->core_object, domain_id, &fw_domain->core_object 573 ); 574 575 // Set the association in the core port to this framework domain object. 576 sci_object_set_association( 577 (SCI_OBJECT_HANDLE_T) fw_domain->core_object, fw_domain 578 ); 579 580 sci_fast_list_init(&fw_domain->request_list); 581 582 fw_domain->operation.timer = NULL; 583 584 fw_domain->is_port_ready = FALSE; 585 fw_domain->device_start_count = 0; 586 fw_domain->controller = fw_controller; 587 fw_domain->operation.status = SCI_SUCCESS; 588 fw_domain->is_config_route_table_needed = FALSE; 589 } 590 591 /** 592 * @brief This method will terminate the requests outstanding in the core 593 * based on the supplied criteria. 594 * - if the all three parameters are specified then only the single 595 * SCIF_SAS_REQUEST object is terminated. 596 * - if only the SCIF_SAS_DOMAIN and SCIF_SAS_REMOTE_DEVICE are 597 * specified, then all SCIF_SAS_REQUEST objects outstanding at 598 * the device are terminated. The one exclusion to this rule is 599 * that the fw_requestor is not terminated. 600 * - if only the SCIF_SAS_DOMAIN object is specified, then all 601 * SCIF_SAS_REQUEST objects outstanding in the domain are 602 * terminated. 603 * 604 * @param[in] fw_domain This parameter specifies the domain in which to 605 * terminate requests. 606 * @param[in] fw_device This parameter specifies the remote device in 607 * which to terminate requests. This parameter can be NULL 608 * as long as the fw_request parameter is NULL. It is a 609 * required parameter if the fw_request parameter is not NULL. 610 * @param[in] fw_request This parameter specifies the request object to 611 * be terminated. This parameter can be NULL. 612 * @param[in] fw_requestor This parameter specifies the task management 613 * request that is responsible for the termination of requests. 614 * 615 * @return none 616 */ 617 void scif_sas_domain_terminate_requests( 618 SCIF_SAS_DOMAIN_T * fw_domain, 619 SCIF_SAS_REMOTE_DEVICE_T * fw_device, 620 SCIF_SAS_REQUEST_T * fw_request, 621 SCIF_SAS_TASK_REQUEST_T * fw_requestor 622 ) 623 { 624 SCIF_LOG_TRACE(( 625 sci_base_object_get_logger(fw_domain), 626 SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_TASK_MANAGEMENT, 627 "scif_sas_domain_terminate_requests(0x%x, 0x%x, 0x%x, 0x%x) enter\n", 628 fw_domain, fw_device, fw_request, fw_requestor 629 )); 630 631 if (fw_request != NULL) 632 { 633 fw_request->terminate_requestor = fw_requestor; 634 fw_request->state_handlers->abort_handler(&fw_request->parent); 635 } 636 else 637 { 638 SCI_FAST_LIST_ELEMENT_T * element = fw_domain->request_list.list_head; 639 SCIF_SAS_REQUEST_T * request = NULL; 640 641 // Cycle through the fast list of IO requests. Terminate each 642 // outstanding requests that matches the criteria supplied by the 643 // caller. 644 while (element != NULL) 645 { 646 request = (SCIF_SAS_REQUEST_T*) sci_fast_list_get_object(element); 647 // The current element may be deleted from the list because of 648 // IO completion so advance to the next element early 649 element = sci_fast_list_get_next(element); 650 651 // Ensure we pass the supplied criteria before terminating the 652 // request. 653 if ( 654 (fw_device == NULL) 655 || ( 656 (request->device == fw_device) 657 && (fw_requestor != (SCIF_SAS_TASK_REQUEST_T*) request) 658 ) 659 ) 660 { 661 if ( 662 (request->is_waiting_for_abort_task_set == FALSE) || 663 (request->terminate_requestor == NULL) 664 ) 665 { 666 request->terminate_requestor = fw_requestor; 667 request->state_handlers->abort_handler(&request->parent); 668 } 669 } 670 } 671 } 672 } 673 674 /** 675 * @brief This method searches the domain object to find a 676 * SCIF_SAS_REQUEST object associated with the supplied IO tag. 677 * 678 * @param[in] fw_domain This parameter specifies the domain in which to 679 * to find the request object. 680 * @param[in] io_tag This parameter specifies the IO tag value for which 681 * to locate the corresponding request. 682 * 683 * @return This method returns a pointer to the SCIF_SAS_REQUEST object 684 * associated with the supplied IO tag. 685 * @retval NULL This value is returned if the IO tag does not resolve to 686 * a request. 687 */ 688 SCIF_SAS_REQUEST_T * scif_sas_domain_get_request_by_io_tag( 689 SCIF_SAS_DOMAIN_T * fw_domain, 690 U16 io_tag 691 ) 692 { 693 SCI_FAST_LIST_ELEMENT_T * element = fw_domain->request_list.list_head; 694 SCIF_SAS_IO_REQUEST_T * io_request = NULL; 695 696 SCIF_LOG_TRACE(( 697 sci_base_object_get_logger(fw_domain), 698 SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_TASK_MANAGEMENT, 699 "scif_sas_domain_get_request_by_io_tag(0x%x, 0x%x) enter\n", 700 fw_domain, io_tag 701 )); 702 703 while (element != NULL) 704 { 705 io_request = (SCIF_SAS_IO_REQUEST_T*) sci_fast_list_get_object(element); 706 707 // Check to see if we located the request with an identical IO tag. 708 if (scic_io_request_get_io_tag(io_request->parent.core_object) == io_tag) 709 return &io_request->parent; 710 711 element = sci_fast_list_get_next(element); 712 } 713 714 return NULL; 715 } 716 717 /** 718 * @brief This method performs domain object initialization to be done 719 * when the scif_controller_initialize() method is invoked. 720 * This includes operation timeout creation. 721 * 722 * @param[in] fw_domain This parameter specifies the domain object for 723 * which to perform initialization. 724 * 725 * @return none 726 */ 727 void scif_sas_domain_initialize( 728 SCIF_SAS_DOMAIN_T * fw_domain 729 ) 730 { 731 SCIF_LOG_TRACE(( 732 sci_base_object_get_logger(fw_domain), 733 SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_INITIALIZATION, 734 "scif_sas_domain_initialize(0x%x) enter\n", 735 fw_domain 736 )); 737 738 // Create the timer for each domain. It is too early in the process 739 // to allocate this during construction since the user didn't have 740 // a chance to set it's association. 741 if (fw_domain->operation.timer == 0) 742 { 743 fw_domain->operation.timer = scif_cb_timer_create( 744 fw_domain->controller, 745 scif_sas_domain_operation_timeout_handler, 746 fw_domain 747 ); 748 } 749 } 750 751 /** 752 * @brief This method performs domain object handling for core remote 753 * device start complete notifications. Core remote device starts 754 * and start completes are only done during discovery. This could 755 * ultimately be wrapped into a handler method on the domain (they 756 * actually already exist). This method will decrement the number 757 * of device start operations ongoing and attempt to determine if 758 * discovery is complete. 759 * 760 * @param[in] fw_domain This parameter specifies the domain object for 761 * which to perform initialization. 762 * 763 * @return none 764 */ 765 void scif_sas_domain_remote_device_start_complete( 766 SCIF_SAS_DOMAIN_T * fw_domain, 767 SCIF_SAS_REMOTE_DEVICE_T * fw_device 768 ) 769 { 770 SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols; 771 772 SCIF_LOG_TRACE(( 773 sci_base_object_get_logger(fw_domain), 774 SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 775 "scif_sas_domain_remote_device_start_complete(0x%x, 0x%x) enter\n", 776 fw_domain, fw_device 777 )); 778 779 // If a device is being started/start completed, then we must be 780 // during discovery. 781 ASSERT(fw_domain->parent.state_machine.current_state_id 782 == SCI_BASE_DOMAIN_STATE_DISCOVERING); 783 784 scic_remote_device_get_protocols(fw_device->core_object, &dev_protocols); 785 786 // Decrement the number of devices being started and check to see 787 // if all have finished being started or failed as the case may be. 788 fw_domain->device_start_in_progress_count--; 789 790 if ( dev_protocols.u.bits.attached_smp_target ) 791 { 792 if ( fw_device->containing_device == NULL ) 793 //kick off the smp discover process if this expander is direct attached. 794 scif_sas_smp_remote_device_start_discover(fw_device); 795 else 796 //mark this device, the discover process of this device will start after 797 //its containing smp device finish discover. 798 fw_device->protocol_device.smp_device.scheduled_activity = 799 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER; 800 } 801 else 802 { 803 fw_domain->state_handlers->device_start_complete_handler( 804 &fw_domain->parent, &fw_device->parent 805 ); 806 } 807 } 808 809 810 /** 811 * @brief This methods check each smp device in this domain. If there is at 812 * least one smp device in discover or target reset activity, this 813 * domain is considered in smp activity. Note this routine is not 814 * called on fast IO path. 815 * 816 * @param[in] fw_domain The framework domain object 817 * 818 * @return BOOL value to indicate whether a domain is in SMP activity. 819 */ 820 BOOL scif_sas_domain_is_in_smp_activity( 821 SCIF_SAS_DOMAIN_T * fw_domain 822 ) 823 { 824 SCI_ABSTRACT_ELEMENT_T * current_element = 825 sci_abstract_list_get_front(&fw_domain->remote_device_list); 826 827 SCIF_SAS_REMOTE_DEVICE_T * current_device; 828 829 while ( current_element != NULL ) 830 { 831 SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols; 832 833 current_device = (SCIF_SAS_REMOTE_DEVICE_T *) 834 sci_abstract_list_get_object(current_element); 835 836 scic_remote_device_get_protocols(current_device->core_object, 837 &dev_protocols 838 ); 839 840 if (dev_protocols.u.bits.attached_smp_target && 841 scif_sas_smp_remote_device_is_in_activity(current_device)) 842 return TRUE; 843 844 current_element = 845 sci_abstract_list_get_next(current_element); 846 } 847 848 return FALSE; 849 } 850 851 852 /** 853 * @brief This methods finds a expander attached device by searching the domain's 854 * device list using connected expander device and expander phy id. 855 * 856 * @param[in] fw_domain The framework domain object 857 * @param[in] parent_device The expander device the target device attaches to. 858 * @param[in] expander_phy_id The expander phy id that the target device owns. 859 * 860 * @return found remote device or a NULL value if no device found. 861 */ 862 SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_get_device_by_containing_device( 863 SCIF_SAS_DOMAIN_T * fw_domain, 864 SCIF_SAS_REMOTE_DEVICE_T * containing_device, 865 U8 expander_phy_id 866 ) 867 { 868 SCIF_SAS_REMOTE_DEVICE_T * fw_device; 869 SCI_ABSTRACT_ELEMENT_T * element = sci_abstract_list_get_front( 870 &fw_domain->remote_device_list 871 ); 872 873 //parent device must not be NULL. 874 ASSERT(containing_device != NULL); 875 876 // Search the abstract list to see if there is a remote device meets the 877 // search condition. 878 while (element != NULL) 879 { 880 fw_device = (SCIF_SAS_REMOTE_DEVICE_T*) 881 sci_abstract_list_get_object(element); 882 883 // Check to see if this is the device for which we are searching. 884 if ( 885 (fw_device->containing_device == containing_device) 886 && (fw_device->expander_phy_identifier == expander_phy_id) 887 ) 888 { 889 return fw_device; 890 } 891 892 element = sci_abstract_list_get_next(element); 893 } 894 895 return SCI_INVALID_HANDLE; 896 } 897 898 899 /** 900 * @brief This methods finds the first device that is in STOPPED state and its 901 * connection_rate is still in SPINUP_HOLD(value 3). 902 * 903 * @param[in] fw_domain The framework domain object 904 * 905 * @return SCIF_SAS_REMOTE_DEVICE_T The device that is in SPINUP_HOLD or NULL. 906 */ 907 SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_find_device_in_spinup_hold( 908 SCIF_SAS_DOMAIN_T * fw_domain 909 ) 910 { 911 SCI_ABSTRACT_ELEMENT_T * current_element; 912 SCIF_SAS_REMOTE_DEVICE_T * current_device; 913 914 SCIF_LOG_TRACE(( 915 sci_base_object_get_logger(fw_domain), 916 SCIF_LOG_OBJECT_DOMAIN, 917 "scif_sas_domain_find_device_in_spinup_hold(0x%x) enter\n", 918 fw_domain 919 )); 920 921 //search throught domain's device list to find the first sata device on spinup_hold 922 current_element = sci_abstract_list_get_front(&fw_domain->remote_device_list); 923 while (current_element != NULL ) 924 { 925 current_device = (SCIF_SAS_REMOTE_DEVICE_T *) 926 sci_abstract_list_get_object(current_element); 927 928 //We must get the next element before we remove the current 929 //device. Or else, we will get wrong next_element, since the erased 930 //element has been put into free pool. 931 current_element = sci_abstract_list_get_next(current_element); 932 933 if ( sci_base_state_machine_get_state(¤t_device->parent.state_machine) == 934 SCI_BASE_REMOTE_DEVICE_STATE_STOPPED 935 && scic_remote_device_get_connection_rate(current_device->core_object) == 936 SCI_SATA_SPINUP_HOLD ) 937 { 938 return current_device; 939 } 940 } 941 942 return NULL; 943 } 944 945 946 /** 947 * @brief This methods finds the first device that has specific activity scheduled. 948 * 949 * @param[in] fw_domain The framework domain object 950 * @param[in] smp_activity A specified smp activity. The valid range is [1,5]. 951 * 952 * @return SCIF_SAS_REMOTE_DEVICE_T The device that has specified smp activity scheduled. 953 */ 954 SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_find_device_has_scheduled_activity( 955 SCIF_SAS_DOMAIN_T * fw_domain, 956 U8 smp_activity 957 ) 958 { 959 SCI_ABSTRACT_ELEMENT_T * current_element = 960 sci_abstract_list_get_front(&fw_domain->remote_device_list); 961 962 SCIF_SAS_REMOTE_DEVICE_T * current_device; 963 SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols; 964 965 //config route table activity has higher priority than discover activity. 966 while ( current_element != NULL ) 967 { 968 current_device = (SCIF_SAS_REMOTE_DEVICE_T *) 969 sci_abstract_list_get_object(current_element); 970 971 scic_remote_device_get_protocols(current_device->core_object, 972 &dev_protocols); 973 974 current_element = 975 sci_abstract_list_get_next(current_element); 976 977 if ( dev_protocols.u.bits.attached_smp_target 978 && current_device->protocol_device.smp_device.scheduled_activity == 979 smp_activity) 980 { 981 return current_device; 982 } 983 } 984 985 return NULL; 986 } 987 988 989 /** 990 * @brief This methods finds the smp device that has is_config_route_table_scheduled 991 * flag set to TRUE, and start config route table on it. If there is no 992 * smp device scheduled to config route table, find the smp device has 993 * is_discover_scheduled and start the smp discover process on them. 994 * 995 * @param[in] fw_domain The framework domain that to start smp discover process. 996 * 997 * @return NONE 998 */ 999 void scif_sas_domain_start_smp_activity( 1000 SCIF_SAS_DOMAIN_T * fw_domain 1001 ) 1002 { 1003 SCIF_SAS_REMOTE_DEVICE_T * device_has_scheduled_activity = NULL; 1004 1005 //first, find device that has config route table activity scheduled. 1006 //config route table activity has higher priority than Discover. 1007 device_has_scheduled_activity = 1008 scif_sas_domain_find_device_has_scheduled_activity( 1009 fw_domain, 1010 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE 1011 ); 1012 1013 if (device_has_scheduled_activity != NULL) 1014 { 1015 scif_sas_smp_remote_device_configure_route_table(device_has_scheduled_activity); 1016 device_has_scheduled_activity->protocol_device.smp_device.scheduled_activity = 1017 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE; 1018 return; 1019 } 1020 1021 //if no device has config route table activity scheduled, search again, find 1022 //device has discover activity scheduled. 1023 device_has_scheduled_activity = 1024 scif_sas_domain_find_device_has_scheduled_activity( 1025 fw_domain, 1026 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER 1027 ); 1028 1029 if (device_has_scheduled_activity != NULL) 1030 scif_sas_smp_remote_device_start_discover(device_has_scheduled_activity); 1031 } 1032 1033 1034 /** 1035 * @brief This method starts domain's smp discover process from the top level expander. 1036 * 1037 * @param[in] fw_domain The framework domain that to start smp discover process. 1038 @ @param[in] top_expander The top level expander device to start smp discover process. 1039 * 1040 * @return None 1041 */ 1042 void scif_sas_domain_start_smp_discover( 1043 SCIF_SAS_DOMAIN_T * fw_domain, 1044 SCIF_SAS_REMOTE_DEVICE_T * top_expander 1045 ) 1046 { 1047 SCI_ABSTRACT_ELEMENT_T * current_element = 1048 sci_abstract_list_get_front(&fw_domain->remote_device_list); 1049 1050 SCIF_SAS_REMOTE_DEVICE_T * current_device; 1051 1052 // something changed behind expander 1053 // mark all the device behind expander to be NOT 1054 // is_currently_discovered. 1055 while ( current_element != NULL ) 1056 { 1057 current_device = (SCIF_SAS_REMOTE_DEVICE_T *) 1058 sci_abstract_list_get_object(current_element); 1059 1060 current_device->is_currently_discovered = FALSE; 1061 1062 //reset all the devices' port witdh except the top expander. 1063 if (current_device->containing_device != NULL) 1064 current_device->device_port_width = 1; 1065 1066 current_element = sci_abstract_list_get_next(current_element); 1067 } 1068 1069 //expander device itself should be set to is_currently_discovered. 1070 top_expander->is_currently_discovered = TRUE; 1071 1072 //kick off the smp discover process. 1073 scif_sas_smp_remote_device_start_discover(top_expander); 1074 } 1075 1076 1077 /** 1078 * @brief This method continues domain's smp discover process and 1079 * may transit to READY state if all smp activities are done. 1080 * 1081 * @param[in] fw_domain The framework domain that to start smp discover process. 1082 * 1083 * @return None 1084 */ 1085 void scif_sas_domain_continue_discover( 1086 SCIF_SAS_DOMAIN_T * fw_domain 1087 ) 1088 { 1089 SCIF_LOG_TRACE(( 1090 sci_base_object_get_logger(fw_domain), 1091 SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 1092 "scif_sas_domain_continue_discover(0x%x) enter\n", 1093 fw_domain 1094 )); 1095 1096 if ( fw_domain->device_start_in_progress_count == 0 1097 && !scif_sas_domain_is_in_smp_activity(fw_domain) ) 1098 { 1099 //domain scrub the remote device list to see if there is a need 1100 //to start smp discover on expander device. There may be no 1101 //need to start any smp discover. 1102 scif_sas_domain_start_smp_activity(fw_domain); 1103 1104 //In domain discovery timeout case, we cancel all 1105 //the smp activities, and terminate all the smp requests, then 1106 //this routine is called. But the smp request may not done 1107 //terminated. We want to guard the domain trasitting to READY 1108 //by checking outstanding smp request count. If there is outstanding 1109 //smp request, the domain will not transit to READY. Later when 1110 //the smp request is terminated at smp remote device, this routine 1111 //will be called then the domain will transit to READY state. 1112 if ( ! scif_sas_domain_is_in_smp_activity(fw_domain) 1113 && scif_sas_domain_get_smp_request_count(fw_domain) == 0) 1114 { 1115 //before domain transit to READY state, domain has some clean up 1116 //work to do, such like update domain's remote devcie list. 1117 scif_sas_domain_finish_discover(fw_domain); 1118 } 1119 } 1120 } 1121 1122 1123 /** 1124 * @brief This method finishes domain's smp discover process and 1125 * update domain's remote device list. 1126 * 1127 * @param[in] fw_domain The framework domain that's to finish smp discover process. 1128 * 1129 * @return None 1130 */ 1131 void scif_sas_domain_finish_discover( 1132 SCIF_SAS_DOMAIN_T * fw_domain 1133 ) 1134 { 1135 SCIF_SAS_REMOTE_DEVICE_T * current_device = NULL; 1136 SCI_ABSTRACT_ELEMENT_T * current_element = NULL; 1137 1138 SCIF_LOG_TRACE(( 1139 sci_base_object_get_logger(fw_domain), 1140 SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 1141 "scif_sas_domain_finish_discover(0x%x) enter\n", 1142 fw_domain 1143 )); 1144 1145 //need to scrub all the devices behind the expander. Check each 1146 //device's discover_status. if the is_currently_discovered is FALSE, means 1147 //the device is not been rediscovered. this device needs to be removed. 1148 current_element = sci_abstract_list_get_front(&fw_domain->remote_device_list); 1149 while (current_element != NULL ) 1150 { 1151 current_device = (SCIF_SAS_REMOTE_DEVICE_T *) 1152 sci_abstract_list_get_object(current_element); 1153 1154 //We must get the next element before we remove the current 1155 //device. Or else, we will get wrong next_element, since the erased 1156 //element has been put into free pool. 1157 current_element = sci_abstract_list_get_next(current_element); 1158 1159 if ( current_device->is_currently_discovered == FALSE ) 1160 { 1161 // Notify the framework user of the device removal. 1162 scif_cb_domain_device_removed( 1163 fw_domain->controller, fw_domain, current_device 1164 ); 1165 } 1166 } 1167 1168 sci_base_state_machine_change_state( 1169 &fw_domain->parent.state_machine, SCI_BASE_DOMAIN_STATE_READY 1170 ); 1171 } 1172 1173 1174 1175 /** 1176 * @brief This method remove an expander device and its child devices, in order to 1177 * deal with a detected illeagal phy connection. 1178 * 1179 * @param[in] fw_domain The domain that a expander belongs to. 1180 * @param[in] fw_device The expander device to be removed. 1181 * 1182 * @return none. 1183 */ 1184 void scif_sas_domain_remove_expander_device( 1185 SCIF_SAS_DOMAIN_T * fw_domain, 1186 SCIF_SAS_REMOTE_DEVICE_T * fw_device 1187 ) 1188 { 1189 SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device = 1190 &fw_device->protocol_device.smp_device; 1191 1192 SCI_FAST_LIST_ELEMENT_T * element = smp_remote_device->smp_phy_list.list_head; 1193 SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL; 1194 SCIF_SAS_REMOTE_DEVICE_T * current_device = NULL; 1195 1196 while (element != NULL) 1197 { 1198 curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element); 1199 element = sci_fast_list_get_next(element); 1200 1201 if ( curr_smp_phy->attached_device_type != SMP_NO_DEVICE_ATTACHED 1202 && curr_smp_phy->u.end_device != NULL ) 1203 { 1204 if (curr_smp_phy->attached_device_type == SMP_END_DEVICE_ONLY) 1205 current_device = curr_smp_phy->u.end_device; 1206 else 1207 current_device = curr_smp_phy->u.attached_phy->owning_device; 1208 1209 scif_cb_domain_device_removed(fw_domain->controller, fw_domain, current_device); 1210 } 1211 } 1212 1213 //remove device itself 1214 scif_cb_domain_device_removed(fw_domain->controller, fw_domain, fw_device); 1215 } 1216 1217 1218 /** 1219 * @brief This method searches the whole domain and finds all the smp devices to 1220 * cancel their smp activities if there is any. 1221 * 1222 * @param[in] fw_domain The domain that its smp activities are to be canceled. 1223 * 1224 * @return none. 1225 */ 1226 void scif_sas_domain_cancel_smp_activities( 1227 SCIF_SAS_DOMAIN_T * fw_domain 1228 ) 1229 { 1230 SCI_ABSTRACT_ELEMENT_T * current_element = 1231 sci_abstract_list_get_front(&fw_domain->remote_device_list); 1232 1233 SCIF_SAS_REMOTE_DEVICE_T * current_device; 1234 1235 //purge all the outstanding internal IOs in HPQ. 1236 scif_sas_high_priority_request_queue_purge_domain( 1237 &fw_domain->controller->hprq, fw_domain 1238 ); 1239 1240 while ( current_element != NULL ) 1241 { 1242 SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols; 1243 1244 current_device = (SCIF_SAS_REMOTE_DEVICE_T *) 1245 sci_abstract_list_get_object(current_element); 1246 1247 scic_remote_device_get_protocols(current_device->core_object, 1248 &dev_protocols 1249 ); 1250 1251 if (dev_protocols.u.bits.attached_smp_target) 1252 { 1253 scif_sas_smp_remote_device_cancel_smp_activity(current_device); 1254 } 1255 1256 current_element = 1257 sci_abstract_list_get_next(current_element); 1258 } 1259 } 1260 1261 1262 /** 1263 * @brief This method searches the domain's request list and counts outstanding 1264 * smp IOs. 1265 * 1266 * @param[in] fw_domain The domain that its request list is to be searched. 1267 * 1268 * @return U8 The possible return value of this routine is 0 or 1. 1269 */ 1270 U8 scif_sas_domain_get_smp_request_count( 1271 SCIF_SAS_DOMAIN_T * fw_domain 1272 ) 1273 { 1274 SCI_FAST_LIST_ELEMENT_T * element = fw_domain->request_list.list_head; 1275 SCIF_SAS_REQUEST_T * request = NULL; 1276 U8 count = 0; 1277 SCIC_TRANSPORT_PROTOCOL protocol; 1278 1279 // Cycle through the fast list of IO requests. Terminate each 1280 // outstanding requests that matches the criteria supplied by the 1281 // caller. 1282 while (element != NULL) 1283 { 1284 request = (SCIF_SAS_REQUEST_T*) sci_fast_list_get_object(element); 1285 // The current element may be deleted from the list because of 1286 // IO completion so advance to the next element early 1287 element = sci_fast_list_get_next(element); 1288 1289 protocol = scic_io_request_get_protocol(request->core_object); 1290 1291 if ( protocol == SCIC_SMP_PROTOCOL) 1292 count++; 1293 } 1294 1295 return count; 1296 } 1297 1298 1299 /** 1300 * @brief This method start clear affiliation activities for smp devices in 1301 * this domain. 1302 * 1303 * @param[in] fw_domain The domain that its smp devices are scheduled to clear 1304 * affiliation for all the EA SATA devices. 1305 * 1306 * @return none. 1307 */ 1308 void scif_sas_domain_start_clear_affiliation( 1309 SCIF_SAS_DOMAIN_T * fw_domain 1310 ) 1311 { 1312 scif_sas_domain_schedule_clear_affiliation(fw_domain); 1313 scif_sas_domain_continue_clear_affiliation(fw_domain); 1314 } 1315 1316 1317 /** 1318 * @brief This method schedule clear affiliation activities for smp devices in 1319 * this domain. 1320 * 1321 * @param[in] fw_domain The domain that its smp devices are scheduled to clear 1322 * affiliation for all the EA SATA devices. 1323 * 1324 * @return none. 1325 */ 1326 void scif_sas_domain_schedule_clear_affiliation( 1327 SCIF_SAS_DOMAIN_T * fw_domain 1328 ) 1329 { 1330 SCI_ABSTRACT_ELEMENT_T * current_element = 1331 sci_abstract_list_get_front(&fw_domain->remote_device_list); 1332 1333 SCIF_SAS_REMOTE_DEVICE_T * current_device; 1334 SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols; 1335 1336 //config route table activity has higher priority than discover activity. 1337 while ( current_element != NULL ) 1338 { 1339 current_device = (SCIF_SAS_REMOTE_DEVICE_T *) 1340 sci_abstract_list_get_object(current_element); 1341 1342 scic_remote_device_get_protocols(current_device->core_object, 1343 &dev_protocols); 1344 1345 current_element = 1346 sci_abstract_list_get_next(current_element); 1347 1348 if ( dev_protocols.u.bits.attached_smp_target ) 1349 { 1350 current_device->protocol_device.smp_device.scheduled_activity = 1351 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAR_AFFILIATION; 1352 } 1353 } 1354 } 1355 1356 1357 /** 1358 * @brief This method carries clear affiliation activities for a smp devices in 1359 * this domain during controller stop process. 1360 * 1361 * @param[in] fw_domain The domain that its smp devices are to clear 1362 * affiliation for all the EA SATA devices. 1363 * 1364 * @return none. 1365 */ 1366 void scif_sas_domain_continue_clear_affiliation( 1367 SCIF_SAS_DOMAIN_T * fw_domain 1368 ) 1369 { 1370 SCIF_SAS_REMOTE_DEVICE_T * smp_device = 1371 scif_sas_domain_find_device_has_scheduled_activity( 1372 fw_domain, 1373 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAR_AFFILIATION 1374 ); 1375 1376 if (smp_device != NULL) 1377 scif_sas_smp_remote_device_start_clear_affiliation(smp_device); 1378 else 1379 { 1380 //This domain has done clear affiliation. 1381 SCIF_SAS_CONTROLLER_T * fw_controller = fw_domain->controller; 1382 fw_controller->current_domain_to_clear_affiliation++; 1383 1384 //let controller continue to clear affiliation on other domains. 1385 scif_sas_controller_clear_affiliation(fw_domain->controller); 1386 } 1387 } 1388 1389 1390 /** 1391 * @brief This method releases resource for a framework domain. 1392 * 1393 * @param[in] fw_controller This parameter specifies the framework 1394 * controller, its associated domain's resources are to be released. 1395 * @param[in] fw_domain This parameter specifies the framework 1396 * domain whose resources are to be released. 1397 */ 1398 void scif_sas_domain_release_resource( 1399 SCIF_SAS_CONTROLLER_T * fw_controller, 1400 SCIF_SAS_DOMAIN_T * fw_domain 1401 ) 1402 { 1403 if (fw_domain->operation.timer != NULL) 1404 { 1405 scif_cb_timer_destroy(fw_controller, fw_domain->operation.timer); 1406 fw_domain->operation.timer = NULL; 1407 } 1408 } 1409 1410 1411 /** 1412 * @brief This method finds the a EA device that has target reset scheduled. 1413 * 1414 * @param[in] fw_domain The framework domain object 1415 * 1416 * @return SCIF_SAS_REMOTE_DEVICE_T The EA device that has target reset scheduled. 1417 */ 1418 SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_find_next_ea_target_reset( 1419 SCIF_SAS_DOMAIN_T * fw_domain 1420 ) 1421 { 1422 SCI_ABSTRACT_ELEMENT_T * current_element; 1423 SCIF_SAS_REMOTE_DEVICE_T * current_device; 1424 1425 SCIF_LOG_TRACE(( 1426 sci_base_object_get_logger(fw_domain), 1427 SCIF_LOG_OBJECT_DOMAIN, 1428 "scif_sas_domain_find_next_ea_target_reset(0x%x) enter\n", 1429 fw_domain 1430 )); 1431 1432 //search through domain's device list to find the first sata device on spinup_hold 1433 current_element = sci_abstract_list_get_front(&fw_domain->remote_device_list); 1434 while (current_element != NULL ) 1435 { 1436 current_device = (SCIF_SAS_REMOTE_DEVICE_T *) 1437 sci_abstract_list_get_object(current_element); 1438 1439 current_element = sci_abstract_list_get_next(current_element); 1440 1441 if ( current_device->ea_target_reset_request_scheduled != NULL ) 1442 { 1443 return current_device; 1444 } 1445 } 1446 1447 return NULL; 1448 } 1449 1450 #if !defined(DISABLE_WIDE_PORTED_TARGETS) 1451 /** 1452 * @brief This method update the direct attached device port width. 1453 * 1454 * @param[in] fw_domain The framework domain object 1455 * @param[in] port The associated port object which recently has link up/down 1456 * event happened. 1457 * 1458 * @return none 1459 */ 1460 void scif_sas_domain_update_device_port_width( 1461 SCIF_SAS_DOMAIN_T * fw_domain, 1462 SCI_PORT_HANDLE_T port 1463 ) 1464 { 1465 SCIF_SAS_REMOTE_DEVICE_T * fw_device; 1466 SCIC_PORT_PROPERTIES_T properties; 1467 U8 new_port_width = 0; 1468 1469 SCIF_LOG_TRACE(( 1470 sci_base_object_get_logger(fw_domain), 1471 SCIF_LOG_OBJECT_DOMAIN, 1472 "scif_sas_domain_update_device_port_width(0x%x, 0x%x) enter\n", 1473 fw_domain, port 1474 )); 1475 1476 scic_port_get_properties(port, &properties); 1477 1478 fw_device = (SCIF_SAS_REMOTE_DEVICE_T *) 1479 scif_domain_get_device_by_sas_address( 1480 fw_domain, &properties.remote.sas_address 1481 ); 1482 1483 // If the device already existed in the domain, it is a wide port SSP target, 1484 // we need to update its port width. 1485 if (fw_device != SCI_INVALID_HANDLE) 1486 { 1487 SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols; 1488 scic_remote_device_get_protocols(fw_device->core_object, &dev_protocols); 1489 1490 if (dev_protocols.u.bits.attached_ssp_target) 1491 { 1492 //Get accurate port width from port's phy mask for a DA device. 1493 SCI_GET_BITS_SET_COUNT(properties.phy_mask, new_port_width); 1494 1495 scif_sas_remote_device_update_port_width(fw_device, new_port_width); 1496 } 1497 } 1498 } 1499 #endif //#if !defined(DISABLE_WIDE_PORTED_TARGETS) 1500 1501 1502 #ifdef SCI_LOGGING 1503 /** 1504 * This method will turn on logging of domain state changes. 1505 * 1506 * @param[in] fw_domain The domain for which the state logging is to be turned 1507 * on. 1508 */ 1509 void scif_sas_domain_initialize_state_logging( 1510 SCIF_SAS_DOMAIN_T *fw_domain 1511 ) 1512 { 1513 sci_base_state_machine_logger_initialize( 1514 &fw_domain->parent.state_machine_logger, 1515 &fw_domain->parent.state_machine, 1516 &fw_domain->parent.parent, 1517 scif_cb_logger_log_states, 1518 "SCIF_SAS_DOMAIN_T", "base state machine", 1519 SCIF_LOG_OBJECT_DOMAIN 1520 ); 1521 } 1522 1523 /** 1524 * This method will turn off logging of domain state changes. 1525 * 1526 * @param[in] fw_domain The domain for which the state logging is to be turned 1527 * off. 1528 */ 1529 void scif_sas_domain_deinitialize_state_logging( 1530 SCIF_SAS_DOMAIN_T *fw_domain 1531 ) 1532 { 1533 sci_base_state_machine_logger_deinitialize( 1534 &fw_domain->parent.state_machine_logger, 1535 &fw_domain->parent.state_machine 1536 ); 1537 } 1538 #endif 1539