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