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 methods for the SCIF_SAS_SMP_REMOTE_DEVICE object. 60 */ 61 #include <dev/isci/scil/sci_controller.h> 62 #include <dev/isci/scil/scif_sas_controller.h> 63 #include <dev/isci/scil/scif_sas_remote_device.h> 64 #include <dev/isci/scil/scif_sas_logger.h> 65 66 #include <dev/isci/scil/scif_sas_smp_remote_device.h> 67 #include <dev/isci/scil/scif_sas_smp_io_request.h> 68 #include <dev/isci/scil/intel_sas.h> 69 #include <dev/isci/scil/scic_io_request.h> 70 #include <dev/isci/scil/scic_remote_device.h> 71 #include <dev/isci/scil/scif_sas_smp_phy.h> 72 73 74 /** 75 * @brief This method resets all fields for a smp remote device. This is a 76 * private method. 77 * 78 * @param[in] fw_device the framework SMP device that is being 79 * constructed. 80 * 81 * @return none 82 */ 83 void scif_sas_smp_remote_device_clear( 84 SCIF_SAS_REMOTE_DEVICE_T * fw_device 85 ) 86 { 87 //reset all fields in smp_device, indicate that the smp device is not 88 //in discovery process. 89 fw_device->protocol_device.smp_device.current_activity = 90 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE; 91 92 fw_device->protocol_device.smp_device.current_smp_request = 93 NOT_IN_SMP_ACTIVITY; 94 95 fw_device->protocol_device.smp_device.current_activity_phy_index = 0; 96 97 fw_device->protocol_device.smp_device.curr_config_route_index = 0; 98 99 fw_device->protocol_device.smp_device.config_route_smp_phy_anchor = NULL; 100 101 fw_device->protocol_device.smp_device.is_route_table_cleaned = FALSE; 102 103 fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy = NULL; 104 105 fw_device->protocol_device.smp_device.scheduled_activity = 106 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE; 107 108 fw_device->protocol_device.smp_device.io_retry_count = 0; 109 110 fw_device->protocol_device.smp_device.curr_clear_affiliation_phy = NULL; 111 112 if (fw_device->protocol_device.smp_device.smp_activity_timer != NULL) 113 { 114 //stop the timer 115 scif_cb_timer_stop( 116 fw_device->domain->controller, 117 fw_device->protocol_device.smp_device.smp_activity_timer 118 ); 119 120 //destroy the timer 121 scif_cb_timer_destroy( 122 fw_device->domain->controller, 123 fw_device->protocol_device.smp_device.smp_activity_timer 124 ); 125 126 fw_device->protocol_device.smp_device.smp_activity_timer = NULL; 127 } 128 } 129 130 131 /** 132 * @brief This method intializes a smp remote device. 133 * 134 * @param[in] fw_device the framework SMP device that is being 135 * constructed. 136 * 137 * @return none 138 */ 139 void scif_sas_smp_remote_device_construct( 140 SCIF_SAS_REMOTE_DEVICE_T * fw_device 141 ) 142 { 143 SCIF_LOG_TRACE(( 144 sci_base_object_get_logger(fw_device), 145 SCIF_LOG_OBJECT_REMOTE_DEVICE, 146 "scif_sas_smp_remote_device_construct(0x%x) enter\n", 147 fw_device 148 )); 149 150 fw_device->protocol_device.smp_device.number_of_phys = 0; 151 fw_device->protocol_device.smp_device.expander_route_indexes = 0; 152 fw_device->protocol_device.smp_device.is_table_to_table_supported = FALSE; 153 fw_device->protocol_device.smp_device.is_externally_configurable = FALSE; 154 fw_device->protocol_device.smp_device.is_able_to_config_others = FALSE; 155 156 sci_fast_list_init(&fw_device->protocol_device.smp_device.smp_phy_list); 157 158 scif_sas_smp_remote_device_clear(fw_device); 159 } 160 161 162 /** 163 * @brief This method decodes a smp response to this smp device and then 164 * continue the smp discover process. 165 * 166 * @param[in] fw_device The framework device that a SMP response targets to. 167 * @param[in] fw_request The pointer to an smp request whose response 168 * is to be decoded. 169 * @param[in] response_data The response data passed in. 170 * 171 * @return none 172 */ 173 SCI_STATUS scif_sas_smp_remote_device_decode_smp_response( 174 SCIF_SAS_REMOTE_DEVICE_T * fw_device, 175 SCIF_SAS_REQUEST_T * fw_request, 176 void * response_data, 177 SCI_IO_STATUS completion_status 178 ) 179 { 180 SMP_RESPONSE_T * smp_response = (SMP_RESPONSE_T *)response_data; 181 SCI_STATUS status = SCI_FAILURE_UNSUPPORTED_INFORMATION_TYPE; 182 183 if (fw_device->protocol_device.smp_device.smp_activity_timer != NULL) 184 { 185 //if there is a timer being used, recycle it now. Since we may 186 //use the timer for other purpose next. 187 scif_cb_timer_destroy( 188 fw_device->domain->controller, 189 fw_device->protocol_device.smp_device.smp_activity_timer 190 ); 191 192 fw_device->protocol_device.smp_device.smp_activity_timer = NULL; 193 } 194 195 //if Core set the status of this io to be RETRY_REQUIRED, we should 196 //retry the IO without even decode the response. 197 if (completion_status == SCI_FAILURE_RETRY_REQUIRED) 198 { 199 scif_sas_smp_remote_device_continue_current_activity( 200 fw_device, fw_request, SCI_FAILURE_RETRY_REQUIRED 201 ); 202 203 return SCI_FAILURE_RETRY_REQUIRED; 204 } 205 206 //check the current smp request, decide what's next smp request to issue. 207 switch (fw_device->protocol_device.smp_device.current_smp_request) 208 { 209 case SMP_FUNCTION_REPORT_GENERAL: 210 { 211 //interpret REPORT GENERAL response. 212 status = scif_sas_smp_remote_device_decode_report_general_response( 213 fw_device, smp_response 214 ); 215 216 break; 217 } 218 219 case SMP_FUNCTION_REPORT_MANUFACTURER_INFORMATION: 220 { 221 // No need to perform any parsing. Just want to see 222 // the information in a trace if necessary. 223 status = SCI_SUCCESS; 224 break; 225 } 226 227 case SMP_FUNCTION_DISCOVER: 228 { 229 if (fw_device->protocol_device.smp_device.current_activity == 230 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER) 231 { 232 //decode discover response 233 status = scif_sas_smp_remote_device_decode_initial_discover_response( 234 fw_device, smp_response 235 ); 236 } 237 else if (fw_device->protocol_device.smp_device.current_activity == 238 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_TARGET_RESET) 239 { 240 //decode discover response as a polling result for a remote device 241 //target reset. 242 status = 243 scif_sas_smp_remote_device_decode_target_reset_discover_response( 244 fw_device, smp_response 245 ); 246 } 247 else if (fw_device->protocol_device.smp_device.current_activity == 248 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_SATA_SPINUP_HOLD_RELEASE) 249 { 250 //decode discover response 251 status = 252 scif_sas_smp_remote_device_decode_spinup_hold_release_discover_response( 253 fw_device, smp_response 254 ); 255 } 256 else 257 ASSERT(0); 258 break; 259 } 260 261 case SMP_FUNCTION_REPORT_PHY_SATA: 262 { 263 //decode the report phy sata response. 264 status = scif_sas_smp_remote_device_decode_report_phy_sata_response( 265 fw_device, smp_response 266 ); 267 268 break; 269 } 270 271 case SMP_FUNCTION_PHY_CONTROL: 272 { 273 if (fw_device->protocol_device.smp_device.current_activity == 274 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER) 275 { 276 //decode the phy control response. 277 status = scif_sas_smp_remote_device_decode_discover_phy_control_response( 278 fw_device, smp_response 279 ); 280 } 281 else if (fw_device->protocol_device.smp_device.current_activity == 282 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_TARGET_RESET) 283 { 284 //decode discover response as a polling result for a remote device 285 //target reset. 286 status = scif_sas_smp_remote_device_decode_target_reset_phy_control_response( 287 fw_device, smp_response 288 ); 289 } 290 else if (fw_device->protocol_device.smp_device.current_activity == 291 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAR_AFFILIATION) 292 { 293 //currently don't care about the status. 294 status = SCI_SUCCESS; 295 } 296 else 297 ASSERT(0); 298 break; 299 } 300 301 case SMP_FUNCTION_CONFIGURE_ROUTE_INFORMATION: 302 { 303 //Note, currently we don't expect any abnormal status from config route info response, 304 //but there is a possibility that we exceed the maximum route index. We will take care 305 //of errors later. 306 status = scif_sas_smp_remote_device_decode_config_route_info_response( 307 fw_device, smp_response 308 ); 309 break; 310 } 311 312 default: 313 //unsupported case, TBD 314 status = SCI_FAILURE_UNSUPPORTED_INFORMATION_TYPE; 315 break; 316 } //end of switch 317 318 //Continue current activity based on response's decoding status. 319 scif_sas_smp_remote_device_continue_current_activity( 320 fw_device, fw_request, status 321 ); 322 323 return status; 324 } 325 326 327 /** 328 * @brief This method decodes a smp Report Genernal response to this smp device 329 * and then continue the smp discover process. 330 * 331 * @param[in] fw_device The framework device that the REPORT GENERAL command 332 * targets to. 333 * @param[in] report_general_response The pointer to a report general response 334 * 335 * @return none 336 */ 337 SCI_STATUS scif_sas_smp_remote_device_decode_report_general_response( 338 SCIF_SAS_REMOTE_DEVICE_T * fw_device, 339 SMP_RESPONSE_T * smp_response 340 ) 341 { 342 SMP_RESPONSE_REPORT_GENERAL_T * report_general_response = 343 &smp_response->response.report_general; 344 345 SMP_RESPONSE_HEADER_T * response_header = &smp_response->header; 346 347 SCIF_LOG_TRACE(( 348 sci_base_object_get_logger(fw_device), 349 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 350 "scif_sas_smp_remote_device_decode_report_general_response(0x%x, 0x%x) enter\n", 351 fw_device, smp_response 352 )); 353 354 if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED) 355 { 356 /// @todo: more decoding work needed when the function_result is not 357 /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some 358 /// function result. 359 SCIF_LOG_ERROR(( 360 sci_base_object_get_logger(fw_device), 361 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 362 "Report General function result(0x%x)\n", 363 response_header->function_result 364 )); 365 366 return SCI_FAILURE; 367 } 368 369 //get info from report general response. 370 fw_device->protocol_device.smp_device.number_of_phys = 371 (U8)report_general_response->number_of_phys; 372 373 //currently there is byte swap issue in U16 data. 374 fw_device->protocol_device.smp_device.expander_route_indexes = 375 ((report_general_response->expander_route_indexes & 0xff) << 8) | 376 ((report_general_response->expander_route_indexes & 0xff00) >> 8); 377 378 fw_device->protocol_device.smp_device.is_table_to_table_supported = 379 (BOOL)report_general_response->table_to_table_supported; 380 381 fw_device->protocol_device.smp_device.is_externally_configurable = 382 (BOOL)report_general_response->configurable_route_table; 383 384 fw_device->protocol_device.smp_device.is_able_to_config_others = 385 (BOOL)report_general_response->configures_others; 386 387 //If the top level expander of a domain is able to configure others, 388 //no config route table is needed in the domain. Or else, 389 //we'll let all the externally configurable expanders in the damain 390 //configure route table. 391 if (fw_device->containing_device == NULL 392 && ! fw_device->protocol_device.smp_device.is_able_to_config_others) 393 fw_device->domain->is_config_route_table_needed = TRUE; 394 395 //knowing number of phys this expander has, we can allocate all the smp phys for 396 //this expander now if it is not done already. 397 if (fw_device->protocol_device.smp_device.smp_phy_list.element_count == 0) 398 scif_sas_smp_remote_device_populate_smp_phy_list(fw_device); 399 400 if (report_general_response->configuring) 401 return SCI_FAILURE_RETRY_REQUIRED; 402 403 return SCI_SUCCESS; 404 } 405 406 407 /** 408 * @brief This method decodes a smp Discover response to this smp device 409 * and then continue the smp discover process. This is only ever 410 * called for the very first discover stage during a given domain 411 * discovery process. 412 * 413 * @param[in] fw_device The framework device that the DISCOVER command 414 * targets to. 415 * @param[in] discover_response The pointer to a DISCOVER response 416 * 417 * @return none 418 */ 419 SCI_STATUS scif_sas_smp_remote_device_decode_initial_discover_response( 420 SCIF_SAS_REMOTE_DEVICE_T * fw_device, 421 SMP_RESPONSE_T * smp_response 422 ) 423 { 424 SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain; 425 SCI_SAS_ADDRESS_T attached_device_address; 426 SCIF_SAS_REMOTE_DEVICE_T * attached_remote_device; 427 SMP_RESPONSE_DISCOVER_T * discover_response = 428 &smp_response->response.discover; 429 SMP_RESPONSE_HEADER_T * response_header = &smp_response->header; 430 431 SCIF_LOG_TRACE(( 432 sci_base_object_get_logger(fw_device), 433 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 434 "scif_sas_smp_remote_device_decode_initial_discover_response(0x%x, 0x%x) enter\n", 435 fw_device, smp_response 436 )); 437 438 if (response_header->function_result == SMP_RESULT_PHY_VACANT) 439 { 440 return SCI_SUCCESS; 441 } 442 else if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED) 443 { 444 /// @todo: more decoding work needed when the function_result is not 445 /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some 446 /// function result. 447 SCIF_LOG_ERROR(( 448 sci_base_object_get_logger(fw_device), 449 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 450 "Discover function result(0x%x)\n", 451 response_header->function_result 452 )); 453 454 return SCI_FAILURE; 455 } 456 457 //only if there is target device attached. We don't add device that is 458 //initiator only. 459 if ( ( discover_response->u2.sas1_1.attached_device_type 460 != SMP_NO_DEVICE_ATTACHED ) 461 && ( discover_response->protocols.u.bits.attached_ssp_target 462 || discover_response->protocols.u.bits.attached_stp_target 463 || discover_response->protocols.u.bits.attached_smp_target 464 || discover_response->protocols.u.bits.attached_sata_device ) ) 465 { 466 attached_device_address = discover_response->attached_sas_address; 467 468 attached_remote_device = (SCIF_SAS_REMOTE_DEVICE_T *) 469 scif_domain_get_device_by_sas_address( 470 fw_domain, &attached_device_address 471 ); 472 473 //need to check if the device already existed in the domian. 474 if (attached_remote_device != SCI_INVALID_HANDLE) 475 { 476 #if !defined(DISABLE_WIDE_PORTED_TARGETS) 477 if ( attached_remote_device->is_currently_discovered == TRUE 478 && attached_remote_device != fw_device->containing_device ) 479 { 480 //a downstream wide port target is found. 481 attached_remote_device->device_port_width++; 482 } 483 else 484 #endif //#if !defined(DISABLE_WIDE_PORTED_TARGETS) 485 { 486 //The device already existed. Mark the device as discovered. 487 attached_remote_device->is_currently_discovered = TRUE; 488 } 489 490 #if !defined(DISABLE_WIDE_PORTED_TARGETS) 491 if (attached_remote_device->device_port_width != 492 scic_remote_device_get_port_width(attached_remote_device->core_object) 493 && discover_response->protocols.u.bits.attached_ssp_target 494 ) 495 { 496 scif_sas_remote_device_update_port_width( 497 attached_remote_device, attached_remote_device->device_port_width); 498 } 499 #endif //#if !defined(DISABLE_WIDE_PORTED_TARGETS) 500 501 if ( discover_response->protocols.u.bits.attached_smp_target 502 && attached_remote_device != fw_device->containing_device) 503 { 504 //another expander device is discovered. Its own smp discover will starts after 505 //this discover finishes. 506 attached_remote_device->protocol_device.smp_device.scheduled_activity = 507 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER; 508 } 509 } 510 else 511 { 512 //report the discovery of a disk for all types of end device. 513 scif_cb_domain_ea_device_added( 514 fw_domain->controller, fw_domain, fw_device, discover_response 515 ); 516 517 //get info from discover response to see what we found. And do 518 //extra work according to end device's protocol type. 519 if ( discover_response->protocols.u.bits.attached_ssp_target 520 || discover_response->protocols.u.bits.attached_smp_target) 521 { 522 //for SSP or SMP target, no extra work. 523 ; 524 } 525 else if ( (discover_response->protocols.u.bits.attached_stp_target) 526 || (discover_response->protocols.u.bits.attached_sata_device) ) 527 { 528 // We treat a SATA Device bit the same as an attached STP 529 // target. 530 discover_response->protocols.u.bits.attached_stp_target = 1; 531 532 //kick off REPORT PHY SATA to the same phy. 533 fw_device->protocol_device.smp_device.current_smp_request = 534 SMP_FUNCTION_REPORT_PHY_SATA; 535 } 536 } 537 } 538 else if( (discover_response->u2.sas1_1.negotiated_physical_link_rate == SCI_SATA_SPINUP_HOLD 539 || discover_response->u4.sas2.negotiated_physical_link_rate == SCI_SATA_SPINUP_HOLD) 540 &&(discover_response->protocols.u.bits.attached_stp_target 541 || discover_response->protocols.u.bits.attached_sata_device) 542 ) 543 { 544 attached_remote_device = scif_sas_domain_get_device_by_containing_device( 545 fw_domain, 546 fw_device, 547 discover_response->phy_identifier 548 ); 549 550 if (attached_remote_device != SCI_INVALID_HANDLE) 551 { 552 //Here, the only reason a device already existed in domain but 553 //the initial discover rersponse shows it in SPINUP_HOLD, is that 554 //a device has been removed and coming back in SPINUP_HOLD before 555 //we detected. The possibility of this situation is very very rare. 556 //we need to remove the device then add it back using the new 557 //discover response. 558 scif_cb_domain_device_removed( 559 fw_domain->controller, fw_domain, attached_remote_device 560 ); 561 } 562 563 discover_response->protocols.u.bits.attached_stp_target = 1; 564 565 //still report ea_device_added(). But this device will not be 566 //started during scif_remote_device_ea_construct(). 567 scif_cb_domain_ea_device_added( 568 fw_domain->controller, fw_domain, fw_device, discover_response 569 ); 570 571 //need to send Phy Control (RESET) to release the phy from spinup hold 572 //condition. 573 fw_device->protocol_device.smp_device.current_smp_request = 574 SMP_FUNCTION_PHY_CONTROL; 575 } 576 577 //update the smp phy info based on this DISCOVER response. 578 return scif_sas_smp_remote_device_save_smp_phy_info( 579 fw_device, discover_response); 580 } 581 582 583 /** 584 * @brief This method decodes a smp Report Phy Sata response to this 585 * smp device and then continue the smp discover process. 586 * 587 * @param[in] fw_device The framework device that the REPORT PHY SATA 588 * command targets to. 589 * @param[in] report_phy_sata_response The pointer to a REPORT PHY 590 * SATA response 591 * 592 * @return none 593 */ 594 SCI_STATUS scif_sas_smp_remote_device_decode_report_phy_sata_response( 595 SCIF_SAS_REMOTE_DEVICE_T * fw_device, 596 SMP_RESPONSE_T * smp_response 597 ) 598 { 599 SMP_RESPONSE_REPORT_PHY_SATA_T * report_phy_sata_response = 600 &smp_response->response.report_phy_sata; 601 602 SMP_RESPONSE_HEADER_T * response_header = &smp_response->header; 603 604 SCIF_LOG_TRACE(( 605 sci_base_object_get_logger(fw_device), 606 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 607 "scif_sas_smp_remote_device_decode_report_phy_sata_response(0x%x, 0x%x) enter\n", 608 fw_device, smp_response 609 )); 610 611 if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED) 612 { 613 /// @todo: more decoding work needed when the function_result is not 614 /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some 615 /// function result. 616 SCIF_LOG_ERROR(( 617 sci_base_object_get_logger(fw_device), 618 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 619 "Report Phy Sata function result(0x%x)\n", 620 response_header->function_result 621 )); 622 623 return SCI_FAILURE; 624 } 625 626 scif_sas_remote_device_save_report_phy_sata_information( 627 report_phy_sata_response 628 ); 629 630 // continue the discover process. 631 fw_device->protocol_device.smp_device.current_smp_request = 632 SMP_FUNCTION_DISCOVER; 633 634 return SCI_SUCCESS; 635 } 636 637 638 /** 639 * @brief This method decodes a smp Phy Control response to this smp device and 640 * then continue the smp TARGET RESET process. 641 * 642 * @param[in] fw_device The framework device that the Phy Control command 643 * targets to. 644 * @param[in] smp_response The pointer to a Phy Control response 645 * @param[in] fw_io The scif IO request that associates to this smp response. 646 * 647 * @return none 648 */ 649 SCI_STATUS scif_sas_smp_remote_device_decode_target_reset_phy_control_response( 650 SCIF_SAS_REMOTE_DEVICE_T * fw_device, 651 SMP_RESPONSE_T * smp_response 652 ) 653 { 654 SMP_RESPONSE_HEADER_T * response_header = &smp_response->header; 655 656 SCI_STATUS status = SCI_SUCCESS; 657 658 SCIF_LOG_TRACE(( 659 sci_base_object_get_logger(fw_device), 660 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 661 "scif_sas_smp_remote_device_decode_target_reset_phy_control_response(0x%x, 0x%x) enter\n", 662 fw_device, smp_response 663 )); 664 665 if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED) 666 { 667 /// @todo: more decoding work needed when the function_result is not 668 /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some 669 /// function result. 670 SCIF_LOG_ERROR(( 671 sci_base_object_get_logger(fw_device), 672 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 673 "Phy Control function unaccepted result(0x%x)\n", 674 response_header->function_result 675 )); 676 677 status = SCI_FAILURE_RETRY_REQUIRED; 678 } 679 680 // phy Control succeeded. 681 return status; 682 } 683 684 /** 685 * @brief This method decodes a smp Phy Control response to this smp device and 686 * then continue the smp DISCOVER process. 687 * 688 * @param[in] fw_device The framework device that the Phy Control command 689 * targets to. 690 * @param[in] smp_response The pointer to a Phy Control response 691 * 692 * @return Almost always SCI_SUCCESS 693 */ 694 SCI_STATUS scif_sas_smp_remote_device_decode_discover_phy_control_response( 695 SCIF_SAS_REMOTE_DEVICE_T * fw_device, 696 SMP_RESPONSE_T * smp_response 697 ) 698 { 699 SMP_RESPONSE_HEADER_T * response_header = &smp_response->header; 700 701 SCI_STATUS status = SCI_SUCCESS; 702 703 SCIF_LOG_TRACE(( 704 sci_base_object_get_logger(fw_device), 705 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 706 "scif_sas_smp_remote_device_decode_discover_phy_control_response(0x%x, 0x%x) enter\n", 707 fw_device, smp_response 708 )); 709 710 if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED) 711 { 712 /// @todo: more decoding work needed when the function_result is not 713 /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some 714 /// function result. 715 SCIF_LOG_ERROR(( 716 sci_base_object_get_logger(fw_device), 717 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 718 "Phy Control function unaccepted result(0x%x)\n", 719 response_header->function_result 720 )); 721 722 return SCI_FAILURE_RETRY_REQUIRED; 723 } 724 725 // continue the discover process. 726 fw_device->protocol_device.smp_device.current_smp_request = 727 SMP_FUNCTION_DISCOVER; 728 729 // phy Control succeeded. 730 return status; 731 } 732 733 734 /** 735 * @brief This method decodes a smp Discover response to this smp device 736 * and then continue the smp discover process. 737 * 738 * @param[in] fw_device The framework device that the DISCOVER command 739 * targets to. 740 * @param[in] discover_response The pointer to a DISCOVER response 741 * 742 * @return none 743 */ 744 SCI_STATUS scif_sas_smp_remote_device_decode_target_reset_discover_response( 745 SCIF_SAS_REMOTE_DEVICE_T * fw_device, 746 SMP_RESPONSE_T * smp_response 747 ) 748 { 749 SCIF_SAS_DOMAIN_T * fw_domain; 750 SCI_SAS_ADDRESS_T attached_device_address; 751 SCIF_SAS_REMOTE_DEVICE_T * attached_remote_device; 752 SMP_RESPONSE_DISCOVER_T * discover_response = 753 &smp_response->response.discover; 754 755 SMP_RESPONSE_HEADER_T * response_header = &smp_response->header; 756 757 SCIF_LOG_TRACE(( 758 sci_base_object_get_logger(fw_device), 759 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 760 "scif_sas_smp_remote_device_decode_target_reset_discover_response(0x%x, 0x%x) enter\n", 761 fw_device, smp_response 762 )); 763 764 if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED) 765 { 766 /// @todo: more decoding work needed when the function_result is not 767 /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some 768 /// function result. 769 SCIF_LOG_ERROR(( 770 sci_base_object_get_logger(fw_device), 771 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 772 "Discover function result(0x%x)\n", 773 response_header->function_result 774 )); 775 776 return SCI_FAILURE_RETRY_REQUIRED; 777 } 778 779 //only if there is device attached. 780 if ( discover_response->u2.sas1_1.attached_device_type != SMP_NO_DEVICE_ATTACHED ) 781 { 782 fw_domain = fw_device->domain; 783 attached_device_address = discover_response->attached_sas_address; 784 785 attached_remote_device = (SCIF_SAS_REMOTE_DEVICE_T *) 786 scif_domain_get_device_by_sas_address( 787 fw_domain, &attached_device_address 788 ); 789 790 // the device should have already existed in the domian. 791 ASSERT (attached_remote_device != SCI_INVALID_HANDLE); 792 return SCI_SUCCESS; 793 } 794 else 795 return SCI_FAILURE_RETRY_REQUIRED; 796 } 797 798 /** 799 * @brief This method decodes a smp Discover response to this smp device 800 * for SPINUP_HOLD_RELEASE activity. If a DISCOVER response says 801 * SATA DEVICE ATTACHED and has a valid NPL value, we call fw_device's 802 * start_handler(). But if a DISCOVER response still shows SPINUP 803 * in NPL state, we need to return retry_required status 804 * 805 * @param[in] fw_device The framework device that the DISCOVER command 806 * targets to. 807 * @param[in] discover_response The pointer to a DISCOVER response 808 * 809 * @return SCI_SUCCESS 810 * SCI_FAILURE_RETRY_REQUIRED 811 */ 812 SCI_STATUS scif_sas_smp_remote_device_decode_spinup_hold_release_discover_response( 813 SCIF_SAS_REMOTE_DEVICE_T * fw_device, 814 SMP_RESPONSE_T * smp_response 815 ) 816 { 817 SMP_RESPONSE_DISCOVER_T * discover_response = &smp_response->response.discover; 818 819 SMP_RESPONSE_HEADER_T * response_header = &smp_response->header; 820 821 SCIF_LOG_TRACE(( 822 sci_base_object_get_logger(fw_device), 823 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 824 "scif_sas_smp_remote_device_decode_spinup_hold_release_discover_response(0x%x, 0x%x) enter\n", 825 fw_device, smp_response 826 )); 827 828 if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED) 829 { 830 /// @todo: more decoding work needed when the function_result is not 831 /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some 832 /// function result. 833 SCIF_LOG_ERROR(( 834 sci_base_object_get_logger(fw_device), 835 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 836 "Discover function result(0x%x)\n", 837 response_header->function_result 838 )); 839 840 return SCI_FAILURE; 841 } 842 843 if ( discover_response->u2.sas1_1.attached_device_type != SMP_NO_DEVICE_ATTACHED ) 844 { 845 if (discover_response->u2.sas1_1.negotiated_physical_link_rate != SCI_SATA_SPINUP_HOLD 846 && discover_response->u4.sas2.negotiated_physical_link_rate != SCI_SATA_SPINUP_HOLD 847 && ( discover_response->protocols.u.bits.attached_stp_target 848 ||discover_response->protocols.u.bits.attached_sata_device ) 849 ) 850 { 851 SCIF_SAS_REMOTE_DEVICE_T * target_device = 852 scif_sas_domain_get_device_by_containing_device( 853 fw_device->domain, 854 fw_device, 855 fw_device->protocol_device.smp_device.current_activity_phy_index 856 ); 857 858 //Need to update the device's connection rate. Its connection rate was SPINIP_HOLD. 859 scic_remote_device_set_max_connection_rate( 860 target_device->core_object, 861 discover_response->u2.sas1_1.negotiated_physical_link_rate 862 ); 863 864 //Need to update the smp phy info too. 865 scif_sas_smp_remote_device_save_smp_phy_info( 866 fw_device, discover_response); 867 868 //This device has already constructed, only need to call start_handler 869 //of this device here. 870 return target_device->state_handlers->parent.start_handler( 871 &target_device->parent ); 872 } 873 else 874 return SCI_FAILURE_RETRY_REQUIRED; 875 } 876 else 877 return SCI_FAILURE_RETRY_REQUIRED; 878 } 879 880 881 /** 882 * @brief This method decodes a smp CONFIG ROUTE INFO response to this smp 883 * device and then continue to config route table. 884 * 885 * @param[in] fw_device The framework device that the CONFIG ROUTE INFO command 886 * targets to. 887 * @param[in] smp_response The pointer to a CONFIG ROUTE INFO response 888 * 889 * @return none 890 */ 891 SCI_STATUS scif_sas_smp_remote_device_decode_config_route_info_response( 892 SCIF_SAS_REMOTE_DEVICE_T * fw_device, 893 SMP_RESPONSE_T * smp_response 894 ) 895 { 896 SMP_RESPONSE_HEADER_T * response_header = &smp_response->header; 897 898 SCIF_LOG_TRACE(( 899 sci_base_object_get_logger(fw_device), 900 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 901 "scif_sas_smp_remote_device_decode_config_route_info_response(0x%x, 0x%x) enter\n", 902 fw_device, smp_response 903 )); 904 905 if (response_header->function_result == SMP_RESULT_INDEX_DOES_NOT_EXIST) 906 { 907 //case of exceeding max route index. We need to remove the devices that are not 908 //able to be edit to route table. The destination config route smp phy 909 //is used to remove devices. 910 scif_sas_smp_remote_device_cancel_config_route_table_activity(fw_device); 911 912 return SCI_FAILURE_EXCEED_MAX_ROUTE_INDEX; 913 } 914 else if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED) 915 { 916 /// @todo: more decoding work needed when the function_result is not 917 /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some 918 /// function result. 919 SCIF_LOG_ERROR(( 920 sci_base_object_get_logger(fw_device), 921 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 922 "Discover function result(0x%x)\n", 923 response_header->function_result 924 )); 925 926 return SCI_FAILURE; 927 } 928 929 return SCI_SUCCESS; 930 } 931 932 933 /** 934 * @brief This method starts the smp Discover process for an expander by 935 * sending Report General request. 936 * 937 * @param[in] fw_device The framework smp device that a command 938 * targets to. 939 * 940 * @return none 941 */ 942 void scif_sas_smp_remote_device_start_discover( 943 SCIF_SAS_REMOTE_DEVICE_T * fw_device 944 ) 945 { 946 SCIF_SAS_CONTROLLER_T * fw_controller = fw_device->domain->controller; 947 948 SCIF_LOG_TRACE(( 949 sci_base_object_get_logger(fw_device), 950 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 951 "scif_sas_smp_remote_device_start_discover(0x%x) enter\n", 952 fw_device 953 )); 954 955 //For safety, clear the device again, there may be some config route table 956 //related info are not cleared yet. 957 scif_sas_smp_remote_device_clear(fw_device); 958 959 //set current activity 960 fw_device->protocol_device.smp_device.current_activity = 961 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER; 962 963 //Set current_smp_request to REPORT GENERAL. 964 fw_device->protocol_device.smp_device.current_smp_request = 965 SMP_FUNCTION_REPORT_GENERAL; 966 967 //reset discover_to_start flag. 968 fw_device->protocol_device.smp_device.scheduled_activity = 969 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE; 970 971 //build the first smp request Report Genernal. 972 scif_sas_smp_request_construct_report_general(fw_controller, fw_device); 973 974 //issue DPC to start this request. 975 scif_cb_start_internal_io_task_schedule( 976 fw_controller, 977 scif_sas_controller_start_high_priority_io, 978 fw_controller 979 ); 980 } 981 982 983 /** 984 * @brief This method continues the smp Discover process. 985 * 986 * @param[in] fw_device The framework smp device that a DISCOVER command 987 * targets to. 988 * @param[in] fw_request The pointer to an smp request whose response 989 * has been decoded. 990 * @param[in] status The decoding status of the smp request's response 991 * 992 * @return none 993 */ 994 void scif_sas_smp_remote_device_continue_current_activity( 995 SCIF_SAS_REMOTE_DEVICE_T * fw_device, 996 SCIF_SAS_REQUEST_T * fw_request, 997 SCI_STATUS status 998 ) 999 { 1000 SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T *)fw_request; 1001 // save the retry count. 1002 U8 io_retry_count = fw_io->retry_count; 1003 1004 if (fw_request->is_internal) 1005 { 1006 // Complete this internal io request now. We want to free this io before 1007 // we create another SMP request, which is going to happen soon. 1008 scif_sas_internal_io_request_complete( 1009 fw_device->domain->controller, 1010 (SCIF_SAS_INTERNAL_IO_REQUEST_T *)fw_request, 1011 SCI_SUCCESS 1012 ); 1013 } 1014 1015 if (fw_device->protocol_device.smp_device.current_activity == 1016 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER) 1017 { 1018 if (status == SCI_SUCCESS) 1019 { //continue the discover process. 1020 scif_sas_smp_remote_device_continue_discover(fw_device); 1021 } 1022 else if (status == SCI_FAILURE_RETRY_REQUIRED) 1023 { 1024 //Retry the smp request. Since we are in the middle of Discover 1025 //process, all the smp requests are internal. A new smp request 1026 //will be created for retry. 1027 U32 retry_wait_duration = (SCIF_DOMAIN_DISCOVER_TIMEOUT / 2) / SCIF_SAS_IO_RETRY_LIMIT; 1028 1029 if (io_retry_count < SCIF_SAS_IO_RETRY_LIMIT) 1030 scif_sas_smp_remote_device_retry_internal_io ( 1031 fw_device, io_retry_count, retry_wait_duration); 1032 else 1033 scif_sas_smp_remote_device_fail_discover(fw_device); 1034 } 1035 else if (status == SCI_FAILURE_ILLEGAL_ROUTING_ATTRIBUTE_CONFIGURATION) 1036 { 1037 //remove this expander device and its child devices. No need to 1038 //continue the discover on this device. 1039 scif_sas_domain_remove_expander_device(fw_device->domain, fw_device); 1040 1041 //continue the domain's smp discover. 1042 scif_sas_domain_continue_discover(fw_device->domain); 1043 } 1044 else 1045 { //terminate the discover process. 1046 scif_sas_smp_remote_device_fail_discover(fw_device); 1047 } 1048 } 1049 else if (fw_device->protocol_device.smp_device.current_activity == 1050 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_TARGET_RESET) 1051 { 1052 if (status == SCI_SUCCESS) 1053 { //continue the target reset process. 1054 scif_sas_smp_remote_device_continue_target_reset( 1055 fw_device, fw_request); 1056 } 1057 else if (status == SCI_FAILURE_RETRY_REQUIRED) 1058 { 1059 //Retry the same smp request. Since we are in the middle of Target 1060 //reset process, all the smp requests are using external resource. 1061 //We will use the exactly same memory to retry. 1062 if (io_retry_count < SCIF_SAS_IO_RETRY_LIMIT) 1063 { 1064 if (fw_device->protocol_device.smp_device.smp_activity_timer == NULL) 1065 { 1066 //create the timer to wait before retry. 1067 fw_device->protocol_device.smp_device.smp_activity_timer = 1068 scif_cb_timer_create( 1069 (SCI_CONTROLLER_HANDLE_T *)fw_device->domain->controller, 1070 (SCI_TIMER_CALLBACK_T)scif_sas_smp_external_request_retry, 1071 (void*)fw_request 1072 ); 1073 } 1074 else 1075 { 1076 ASSERT(0); 1077 } 1078 1079 //start the timer to wait 1080 scif_cb_timer_start( 1081 (SCI_CONTROLLER_HANDLE_T)fw_device->domain->controller, 1082 fw_device->protocol_device.smp_device.smp_activity_timer, 1083 SMP_REQUEST_RETRY_WAIT_DURATION //20 miliseconds 1084 ); 1085 } 1086 else 1087 scif_sas_smp_remote_device_fail_target_reset(fw_device, fw_request); 1088 } 1089 else 1090 //terminate the discover process. 1091 scif_sas_smp_remote_device_fail_target_reset(fw_device, fw_request); 1092 } 1093 else if (fw_device->protocol_device.smp_device.current_activity == 1094 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_SATA_SPINUP_HOLD_RELEASE) 1095 { 1096 SCIF_SAS_REMOTE_DEVICE_T * target_device = 1097 scif_sas_domain_get_device_by_containing_device( 1098 fw_device->domain, 1099 fw_device, 1100 fw_device->protocol_device.smp_device.current_activity_phy_index 1101 ); 1102 1103 if (status == SCI_SUCCESS) 1104 { 1105 //move on to next round of SPINUP_HOLD_REALSE activity. 1106 scif_sas_smp_remote_device_sata_spinup_hold_release(fw_device); 1107 } 1108 else if (status == SCI_FAILURE_RETRY_REQUIRED) 1109 { 1110 U32 delay = 1111 (scic_remote_device_get_suggested_reset_timeout(target_device->core_object) / 1112 SCIF_SAS_IO_RETRY_LIMIT); 1113 1114 //Retry the smp request. Since we are in the middle of Discover 1115 //process, all the smp requests are internal. A new smp request 1116 //will be created for retry. 1117 if (io_retry_count < SCIF_SAS_IO_RETRY_LIMIT) 1118 { 1119 scif_sas_smp_remote_device_retry_internal_io( 1120 fw_device, io_retry_count, delay); 1121 } 1122 else //give up on this target device. 1123 { 1124 scif_sas_smp_remote_device_fail_target_spinup_hold_release( 1125 fw_device , target_device); 1126 } 1127 } 1128 else //give up on this target device. 1129 scif_sas_smp_remote_device_fail_target_spinup_hold_release( 1130 fw_device, target_device); 1131 } 1132 else if (fw_device->protocol_device.smp_device.current_activity == 1133 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE) 1134 { 1135 SCI_FAST_LIST_ELEMENT_T * next_phy_element = sci_fast_list_get_next( 1136 &(fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy->list_element) ); 1137 1138 SCI_FAST_LIST_T * destination_smp_phy_list = 1139 fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy->list_element.owning_list; 1140 1141 SCIF_SAS_SMP_PHY_T * next_phy_in_wide_port = NULL; 1142 1143 if (next_phy_element != NULL 1144 && status != SCI_FAILURE_EXCEED_MAX_ROUTE_INDEX) 1145 { 1146 fw_device->protocol_device.smp_device.curr_config_route_index++; 1147 1148 fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy = 1149 (SCIF_SAS_SMP_PHY_T *)sci_fast_list_get_object(next_phy_element); 1150 1151 // Update the anchor for config route index. 1152 fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->config_route_table_index_anchor = 1153 fw_device->protocol_device.smp_device.curr_config_route_index; 1154 1155 scif_sas_smp_remote_device_configure_route_table(fw_device); 1156 } 1157 else if ( scif_sas_smp_remote_device_get_config_route_table_method(fw_device) 1158 == SCIF_SAS_CONFIG_ROUTE_TABLE_ALL_PHYS 1159 && (next_phy_in_wide_port = scif_sas_smp_phy_find_next_phy_in_wide_port( 1160 fw_device->protocol_device.smp_device.config_route_smp_phy_anchor) 1161 )!= NULL 1162 ) 1163 { 1164 //config the other phy in the same wide port 1165 fw_device->protocol_device.smp_device.config_route_smp_phy_anchor = 1166 next_phy_in_wide_port; 1167 1168 fw_device->protocol_device.smp_device.current_activity_phy_index = 1169 fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->phy_identifier; 1170 1171 fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy = 1172 sci_fast_list_get_head(destination_smp_phy_list); 1173 1174 if (fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->config_route_table_index_anchor != 0) 1175 fw_device->protocol_device.smp_device.curr_config_route_index = 1176 fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->config_route_table_index_anchor + 1; 1177 else 1178 fw_device->protocol_device.smp_device.curr_config_route_index = 0; 1179 1180 scif_sas_smp_remote_device_configure_route_table(fw_device); 1181 } 1182 else if ( fw_device->protocol_device.smp_device.is_route_table_cleaned == FALSE) 1183 { 1184 fw_device->protocol_device.smp_device.current_activity = 1185 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAN_ROUTE_TABLE; 1186 1187 scif_sas_smp_remote_device_clean_route_table(fw_device); 1188 } 1189 else 1190 { 1191 //set this device's activity to NON. 1192 fw_device->protocol_device.smp_device.current_activity = 1193 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE; 1194 1195 //we need to notify domain that this device finished config route table, domain 1196 //may pick up other activities (i.e. Discover) for other expanders. 1197 scif_sas_domain_continue_discover(fw_device->domain); 1198 } 1199 } 1200 else if (fw_device->protocol_device.smp_device.current_activity == 1201 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAN_ROUTE_TABLE) 1202 { 1203 scif_sas_smp_remote_device_clean_route_table(fw_device); 1204 } 1205 else if (fw_device->protocol_device.smp_device.current_activity == 1206 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAR_AFFILIATION) 1207 { 1208 scif_sas_smp_remote_device_continue_clear_affiliation(fw_device); 1209 } 1210 } 1211 1212 1213 /** 1214 * @brief This method continues the smp Discover process. 1215 * 1216 * @param[in] fw_device The framework smp device that a DISCOVER command 1217 * targets to. 1218 * 1219 * @return none 1220 */ 1221 void scif_sas_smp_remote_device_continue_discover( 1222 SCIF_SAS_REMOTE_DEVICE_T * fw_device 1223 ) 1224 { 1225 SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain; 1226 1227 SCIF_LOG_TRACE(( 1228 sci_base_object_get_logger(fw_device), 1229 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 1230 "scif_sas_smp_remote_device_continue_discover(0x%x) enter\n", 1231 fw_device 1232 )); 1233 1234 switch (fw_device->protocol_device.smp_device.current_smp_request) 1235 { 1236 case SMP_FUNCTION_REPORT_GENERAL: 1237 // send the REPORT MANUFACTURER_INFO request 1238 fw_device->protocol_device.smp_device.current_smp_request = 1239 SMP_FUNCTION_REPORT_MANUFACTURER_INFORMATION; 1240 1241 scif_sas_smp_request_construct_report_manufacturer_info( 1242 fw_domain->controller, fw_device 1243 ); 1244 1245 break; 1246 1247 case SMP_FUNCTION_REPORT_MANUFACTURER_INFORMATION: 1248 //send the first SMP DISCOVER request. 1249 fw_device->protocol_device.smp_device.current_activity_phy_index = 0; 1250 fw_device->protocol_device.smp_device.current_smp_request = 1251 SMP_FUNCTION_DISCOVER; 1252 1253 scif_sas_smp_request_construct_discover( 1254 fw_domain->controller, 1255 fw_device, 1256 fw_device->protocol_device.smp_device.current_activity_phy_index, 1257 NULL, NULL 1258 ); 1259 break; 1260 1261 1262 case SMP_FUNCTION_DISCOVER: 1263 fw_device->protocol_device.smp_device.current_activity_phy_index++; 1264 1265 if ( (fw_device->protocol_device.smp_device.current_activity_phy_index < 1266 fw_device->protocol_device.smp_device.number_of_phys) ) 1267 { 1268 scif_sas_smp_request_construct_discover( 1269 fw_domain->controller, 1270 fw_device, 1271 fw_device->protocol_device.smp_device.current_activity_phy_index, 1272 NULL, NULL 1273 ); 1274 } 1275 else 1276 scif_sas_smp_remote_device_finish_initial_discover(fw_device); 1277 break; 1278 1279 1280 case SMP_FUNCTION_REPORT_PHY_SATA: 1281 scif_sas_smp_request_construct_report_phy_sata( 1282 fw_device->domain->controller, 1283 fw_device, 1284 fw_device->protocol_device.smp_device.current_activity_phy_index 1285 ); 1286 1287 break; 1288 1289 1290 case SMP_FUNCTION_PHY_CONTROL: 1291 scif_sas_smp_request_construct_phy_control( 1292 fw_device->domain->controller, 1293 fw_device, 1294 PHY_OPERATION_HARD_RESET, 1295 fw_device->protocol_device.smp_device.current_activity_phy_index, 1296 NULL, 1297 NULL 1298 ); 1299 1300 break; 1301 1302 default: 1303 break; 1304 } 1305 } 1306 1307 /** 1308 * @brief This method finishes the initial smp DISCOVER process. There 1309 * may be a spinup_hold release phase following of initial discover, 1310 * depending on whether there are SATA device in the domain 1311 * in SATA_SPINUP_HOLD condition. 1312 * 1313 * @param[in] fw_device The framework smp device that finishes all the 1314 * DISCOVER requests. 1315 * 1316 * @return none 1317 */ 1318 void scif_sas_smp_remote_device_finish_initial_discover( 1319 SCIF_SAS_REMOTE_DEVICE_T * fw_device 1320 ) 1321 { 1322 SCIF_SAS_REMOTE_DEVICE_T * device_in_sata_spinup_hold = 1323 scif_sas_domain_find_device_in_spinup_hold(fw_device->domain); 1324 1325 SCIF_LOG_TRACE(( 1326 sci_base_object_get_logger(fw_device), 1327 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 1328 "scif_sas_smp_remote_device_finish_initial_discover(0x%x) enter\n", 1329 fw_device 1330 )); 1331 1332 if ( device_in_sata_spinup_hold != NULL ) 1333 { 1334 //call the common private routine to reset all fields of this smp device. 1335 scif_sas_smp_remote_device_clear(fw_device); 1336 1337 //Move on to next activity SPINUP_HOLD_RELEASE 1338 fw_device->protocol_device.smp_device.current_activity = 1339 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_SATA_SPINUP_HOLD_RELEASE; 1340 1341 //create the timer to delay a little bit before going to 1342 //sata spinup hold release activity. 1343 if (fw_device->protocol_device.smp_device.smp_activity_timer == NULL) 1344 { 1345 fw_device->protocol_device.smp_device.smp_activity_timer = 1346 scif_cb_timer_create( 1347 (SCI_CONTROLLER_HANDLE_T *)fw_device->domain->controller, 1348 (SCI_TIMER_CALLBACK_T)scif_sas_smp_remote_device_sata_spinup_hold_release, 1349 (void*)fw_device 1350 ); 1351 } 1352 else 1353 { 1354 ASSERT (0); 1355 } 1356 1357 scif_cb_timer_start( 1358 (SCI_CONTROLLER_HANDLE_T)fw_device->domain->controller, 1359 fw_device->protocol_device.smp_device.smp_activity_timer, 1360 SMP_SPINUP_HOLD_RELEASE_WAIT_DURATION 1361 ); 1362 } 1363 else 1364 scif_sas_smp_remote_device_finish_discover(fw_device); 1365 } 1366 1367 1368 /** 1369 * @brief This method finishes the smp DISCOVER process. 1370 * 1371 * @param[in] fw_device The framework smp device that finishes all the 1372 * DISCOVER requests. 1373 * 1374 * @return none 1375 */ 1376 void scif_sas_smp_remote_device_finish_discover( 1377 SCIF_SAS_REMOTE_DEVICE_T * fw_device 1378 ) 1379 { 1380 SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain; 1381 1382 SCIF_LOG_TRACE(( 1383 sci_base_object_get_logger(fw_device), 1384 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 1385 "scif_sas_smp_remote_device_finish_discover(0x%x) enter\n", 1386 fw_device 1387 )); 1388 1389 if ( fw_domain->is_config_route_table_needed 1390 && fw_device->protocol_device.smp_device.smp_phy_list.list_head != NULL) 1391 scif_sas_smp_remote_device_configure_upstream_expander_route_info(fw_device); 1392 1393 //call the common private routine to reset all fields of this smp device. 1394 scif_sas_smp_remote_device_clear(fw_device); 1395 1396 #ifdef SCI_SMP_PHY_LIST_DEBUG_PRINT 1397 scif_sas_smp_remote_device_print_smp_phy_list(fw_device); 1398 #endif 1399 1400 //notify domain this smp device's discover finishes, it's up to domain 1401 //to continue the discover process in a bigger scope. 1402 scif_sas_domain_continue_discover(fw_domain); 1403 } 1404 1405 1406 /** 1407 * @brief This method continues the smp Target Reset (Phy Control) process. 1408 * 1409 * @param[in] fw_device The framework smp device that a smp reset targets to. 1410 * 1411 * @return none 1412 */ 1413 void scif_sas_smp_remote_device_continue_target_reset( 1414 SCIF_SAS_REMOTE_DEVICE_T * fw_device, 1415 SCIF_SAS_REQUEST_T * fw_request 1416 ) 1417 { 1418 SCIF_SAS_CONTROLLER_T * fw_controller = fw_device->domain->controller; 1419 SCIF_SAS_REMOTE_DEVICE_T * target_device = 1420 scif_sas_domain_get_device_by_containing_device( 1421 fw_device->domain, 1422 fw_device, 1423 fw_device->protocol_device.smp_device.current_activity_phy_index 1424 ); 1425 1426 SCIF_LOG_TRACE(( 1427 sci_base_object_get_logger(fw_device), 1428 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 1429 "scif_sas_smp_remote_device_continue_target_reset(0x%x, 0x%x) enter\n", 1430 fw_device, fw_request 1431 )); 1432 1433 if (fw_device->protocol_device.smp_device.current_smp_request == 1434 SMP_FUNCTION_PHY_CONTROL) 1435 { 1436 //query the core remote device to get suggested reset timeout value 1437 //then scale down by factor of 8 to get the duration of the pause 1438 //before sending out Discover command to poll. 1439 U32 delay = 1440 (scic_remote_device_get_suggested_reset_timeout(target_device->core_object)/8); 1441 1442 //create the timer to send Discover command polling target device's 1443 //coming back. 1444 if (fw_device->protocol_device.smp_device.smp_activity_timer == NULL) 1445 { 1446 fw_device->protocol_device.smp_device.smp_activity_timer = 1447 scif_cb_timer_create( 1448 (SCI_CONTROLLER_HANDLE_T *)fw_controller, 1449 (SCI_TIMER_CALLBACK_T)scif_sas_smp_remote_device_target_reset_poll, 1450 (void*)fw_request 1451 ); 1452 } 1453 else 1454 { 1455 ASSERT(0); 1456 } 1457 1458 //start the timer 1459 scif_cb_timer_start( 1460 (SCI_CONTROLLER_HANDLE_T)fw_controller, 1461 fw_device->protocol_device.smp_device.smp_activity_timer, 1462 delay 1463 ); 1464 } 1465 else if (fw_device->protocol_device.smp_device.current_smp_request == 1466 SMP_FUNCTION_DISCOVER) 1467 { 1468 //tell target reset successful 1469 scif_sas_remote_device_target_reset_complete( 1470 target_device, fw_request, SCI_SUCCESS); 1471 } 1472 } 1473 1474 /** 1475 * @brief This routine is invoked by timer or when 2 BCN are received 1476 * after Phy Control command. This routine will construct a 1477 * Discover command to the same expander phy to poll the target 1478 * device's coming back. This new request is then put into 1479 * high priority queue and will be started by a DPC soon. 1480 * 1481 * @param[in] fw_request The scif request for smp activities. 1482 */ 1483 void scif_sas_smp_remote_device_target_reset_poll( 1484 SCIF_SAS_REQUEST_T * fw_request 1485 ) 1486 { 1487 SCIF_SAS_REMOTE_DEVICE_T * fw_device = fw_request->device; 1488 SCIF_SAS_CONTROLLER_T * fw_controller = fw_device->domain->controller; 1489 void * new_command_handle; 1490 1491 SCIF_LOG_TRACE(( 1492 sci_base_object_get_logger(fw_device), 1493 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 1494 "scif_sas_smp_remote_device_target_reset_poll(0x%x) enter\n", 1495 fw_request 1496 )); 1497 1498 // Before we construct new io using the same memory, we need to 1499 // remove the IO from the list of outstanding requests on the domain 1500 // so that we don't damage the domain's fast list of request. 1501 sci_fast_list_remove_element(&fw_request->list_element); 1502 1503 fw_device->protocol_device.smp_device.current_smp_request = 1504 SMP_FUNCTION_DISCOVER; 1505 1506 //sent smp discover request to poll on remote device's coming back. 1507 //construct Discover command using the same memory as fw_request. 1508 new_command_handle = scif_sas_smp_request_construct_discover( 1509 fw_device->domain->controller, 1510 fw_device, 1511 fw_device->protocol_device.smp_device.current_activity_phy_index, 1512 (void *)sci_object_get_association(fw_request), 1513 (void *)fw_request 1514 ); 1515 1516 //put into the high priority queue. 1517 sci_pool_put(fw_controller->hprq.pool, (POINTER_UINT) new_command_handle); 1518 1519 //schedule the DPC to start new Discover command. 1520 scif_cb_start_internal_io_task_schedule( 1521 fw_controller, scif_sas_controller_start_high_priority_io, fw_controller 1522 ); 1523 } 1524 1525 1526 /** 1527 * @brief This method fails discover process. 1528 * 1529 * @param[in] fw_device The framework smp device that failed at current 1530 * activity. 1531 * 1532 * @return none 1533 */ 1534 void scif_sas_smp_remote_device_fail_discover( 1535 SCIF_SAS_REMOTE_DEVICE_T * fw_device 1536 ) 1537 { 1538 SCIF_LOG_TRACE(( 1539 sci_base_object_get_logger(fw_device), 1540 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 1541 "scif_sas_smp_remote_device_fail_discover(0x%x) enter\n", 1542 fw_device 1543 )); 1544 1545 switch (fw_device->protocol_device.smp_device.current_smp_request) 1546 { 1547 case SMP_FUNCTION_REPORT_GENERAL: 1548 case SMP_FUNCTION_REPORT_MANUFACTURER_INFORMATION: 1549 scif_sas_smp_remote_device_finish_discover(fw_device); 1550 break; 1551 1552 case SMP_FUNCTION_DISCOVER: 1553 case SMP_FUNCTION_REPORT_PHY_SATA: 1554 //Retry limit reached, we will continue to send DISCOVER to next phy. 1555 fw_device->protocol_device.smp_device.current_smp_request = 1556 SMP_FUNCTION_DISCOVER; 1557 1558 scif_sas_smp_remote_device_continue_discover(fw_device); 1559 break; 1560 1561 default: 1562 break; 1563 } 1564 } 1565 1566 1567 /** 1568 * @brief This method fails Target Reset. 1569 * 1570 * @param[in] fw_device The framework smp device that failed at current 1571 * activity. 1572 * @param[in] fw_request The smp request created for target reset 1573 * using external resource. 1574 * 1575 * @return none 1576 */ 1577 void scif_sas_smp_remote_device_fail_target_reset( 1578 SCIF_SAS_REMOTE_DEVICE_T * fw_device, 1579 SCIF_SAS_REQUEST_T * fw_request 1580 ) 1581 { 1582 SCIF_SAS_REMOTE_DEVICE_T * target_device = 1583 scif_sas_domain_get_device_by_containing_device( 1584 fw_device->domain, 1585 fw_device, 1586 fw_device->protocol_device.smp_device.current_activity_phy_index 1587 ); 1588 1589 SCIF_LOG_TRACE(( 1590 sci_base_object_get_logger(fw_device), 1591 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 1592 "scif_sas_smp_remote_device_fail_target_reset(0x%x, 0x%x, 0x%x) enter\n", 1593 fw_device, target_device, fw_request 1594 )); 1595 1596 //tell target reset failed 1597 scif_sas_remote_device_target_reset_complete( 1598 target_device, fw_request, SCI_FAILURE); 1599 } 1600 1601 /** 1602 * @brief This method init or continue the SATA SPINUP_HOLD RELEASE activity. 1603 * This function searches domain's device list, find a device in STOPPED STATE 1604 * and its connection_rate is SPINIP, then send DISCOVER command to its expander 1605 * phy id to poll. But if searching the domain's device list for SATA devices on 1606 * SPINUP_HOLD finds no device, the activity SPINUP_HOLD_RELEASE is finished. 1607 * We then call fw_domain->device_start_complete_handler() for this smp-device. 1608 * 1609 * @param[in] fw_device The framework smp device that is on SATA SPINUP_HOLD_RELEASE 1610 * activity. 1611 * 1612 * @return none 1613 */ 1614 void scif_sas_smp_remote_device_sata_spinup_hold_release( 1615 SCIF_SAS_REMOTE_DEVICE_T * fw_device 1616 ) 1617 { 1618 SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain; 1619 SCIF_SAS_CONTROLLER_T * fw_controller = fw_domain->controller; 1620 SCIF_SAS_REMOTE_DEVICE_T * device_to_poll = NULL; 1621 1622 SCIF_LOG_TRACE(( 1623 sci_base_object_get_logger(fw_device), 1624 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 1625 "scif_sas_smp_remote_device_sata_spinup_hold_release(0x%x) enter\n", 1626 fw_device 1627 )); 1628 1629 //search throught domain's device list to find a sata device on spinup_hold 1630 //state to poll. 1631 device_to_poll = scif_sas_domain_find_device_in_spinup_hold(fw_domain); 1632 1633 if (device_to_poll != NULL) 1634 { 1635 //send DISCOVER command to this device's expaner phy. 1636 fw_device->protocol_device.smp_device.current_smp_request = 1637 SMP_FUNCTION_DISCOVER; 1638 1639 fw_device->protocol_device.smp_device.current_activity_phy_index = 1640 device_to_poll->expander_phy_identifier; 1641 1642 scif_sas_smp_request_construct_discover( 1643 fw_domain->controller, 1644 fw_device, 1645 fw_device->protocol_device.smp_device.current_activity_phy_index, 1646 NULL, NULL 1647 ); 1648 1649 //schedule the DPC to start new Discover command. 1650 scif_cb_start_internal_io_task_schedule( 1651 fw_controller, scif_sas_controller_start_high_priority_io, fw_controller 1652 ); 1653 } 1654 else //SATA SPINUP HOLD RELEASE activity is done. 1655 scif_sas_smp_remote_device_finish_discover (fw_device); 1656 } 1657 1658 1659 /** 1660 * @brief This method fail an action of SATA SPINUP_HOLD RELEASE on a single EA 1661 * SATA device. It will remove a remote_device object for a sata device 1662 * that fails to come out of spinup_hold. 1663 * 1664 * @param[in] fw_device The framework smp device that is on SATA SPINUP_HOLD_RELEASE 1665 * activity. 1666 * @param[in] target_device The expander attached device failed being brought out 1667 * of SPINUP_HOLD state. 1668 * 1669 * @return none 1670 */ 1671 void scif_sas_smp_remote_device_fail_target_spinup_hold_release( 1672 SCIF_SAS_REMOTE_DEVICE_T * fw_device, 1673 SCIF_SAS_REMOTE_DEVICE_T * target_device 1674 ) 1675 { 1676 SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain; 1677 1678 SCIF_LOG_TRACE(( 1679 sci_base_object_get_logger(fw_device), 1680 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 1681 "scif_sas_smp_remote_device_fail_target_spinup_hold_release(0x%x, 0x%x) enter\n", 1682 fw_device, target_device 1683 )); 1684 1685 //need to remove the device, since we have to give up on spinup_hold_release 1686 //activity on this device. 1687 scif_cb_domain_device_removed( 1688 fw_domain->controller, fw_domain, target_device 1689 ); 1690 1691 //move on to next round of SPINUP_HOLD_REALSE activity. 1692 scif_sas_smp_remote_device_sata_spinup_hold_release(fw_device); 1693 } 1694 1695 1696 /** 1697 * @brief This method retry only internal IO for the smp device. 1698 * 1699 * @param[in] fw_device The framework smp device that has an smp request to retry. 1700 * @param[in] io_retry_count current count for times the IO being retried. 1701 * @param[in] delay The time delay before the io gets retried. 1702 * 1703 * @return none 1704 */ 1705 void scif_sas_smp_remote_device_retry_internal_io( 1706 SCIF_SAS_REMOTE_DEVICE_T * fw_device, 1707 U8 io_retry_count, 1708 U32 delay 1709 ) 1710 { 1711 SCIF_LOG_TRACE(( 1712 sci_base_object_get_logger(fw_device), 1713 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 1714 "scif_sas_smp_remote_device_retry_internal_io(0x%x, 0x%x, 0x%x) enter\n", 1715 fw_device, io_retry_count, delay 1716 )); 1717 1718 fw_device->protocol_device.smp_device.io_retry_count = 1719 io_retry_count; 1720 1721 //create the timer for poll target device's coming back. 1722 if (fw_device->protocol_device.smp_device.smp_activity_timer == NULL) 1723 { 1724 fw_device->protocol_device.smp_device.smp_activity_timer = 1725 scif_cb_timer_create( 1726 (SCI_CONTROLLER_HANDLE_T *)fw_device->domain->controller, 1727 (SCI_TIMER_CALLBACK_T)scif_sas_smp_internal_request_retry, 1728 (void*)fw_device 1729 ); 1730 } 1731 else 1732 { 1733 ASSERT(0); 1734 } 1735 //start the timer for a purpose of waiting. 1736 scif_cb_timer_start( 1737 (SCI_CONTROLLER_HANDLE_T)fw_device->domain->controller, 1738 fw_device->protocol_device.smp_device.smp_activity_timer, 1739 delay 1740 ); 1741 } 1742 1743 1744 /** 1745 * @brief This method indicates whether an expander device is in Discover 1746 * process. 1747 * 1748 * @param[in] fw_device The framework smp device. 1749 * 1750 * @return Whether an expander device is in the middle of discovery process. 1751 */ 1752 BOOL scif_sas_smp_remote_device_is_in_activity( 1753 SCIF_SAS_REMOTE_DEVICE_T * fw_device 1754 ) 1755 { 1756 return(fw_device->protocol_device.smp_device.current_activity 1757 != SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE); 1758 } 1759 1760 /** 1761 * @brief This method search through the smp phy list of an expander to 1762 * find a smp phy by its phy id of the expander. 1763 * 1764 * @param[in] phy_identifier The search criteria. 1765 * @param[in] smp_remote_device The expander that owns the smp phy list. 1766 * 1767 * @return The found smp phy or a NULL pointer to indicate no smp phy is found. 1768 */ 1769 SCIF_SAS_SMP_PHY_T * scif_sas_smp_remote_device_find_smp_phy_by_id( 1770 U8 phy_identifier, 1771 SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device 1772 ) 1773 { 1774 SCI_FAST_LIST_ELEMENT_T * element = smp_remote_device->smp_phy_list.list_head; 1775 SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL; 1776 1777 while (element != NULL) 1778 { 1779 curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element); 1780 element = sci_fast_list_get_next(element); 1781 1782 if (curr_smp_phy->phy_identifier == phy_identifier) 1783 return curr_smp_phy; 1784 } 1785 1786 return NULL; 1787 } 1788 1789 /** 1790 * @brief This method takes care of removing smp phy list of a smp devcie, which is 1791 * about to be removed. 1792 * 1793 * @param[in] fw_device The expander device that is about to be removed. 1794 * 1795 * @return none. 1796 */ 1797 void scif_sas_smp_remote_device_removed( 1798 SCIF_SAS_REMOTE_DEVICE_T * this_device 1799 ) 1800 { 1801 SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device = 1802 &this_device->protocol_device.smp_device; 1803 1804 SCI_FAST_LIST_ELEMENT_T * element = smp_remote_device->smp_phy_list.list_head; 1805 SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL; 1806 1807 SCIF_LOG_TRACE(( 1808 sci_base_object_get_logger(this_device), 1809 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 1810 "scif_sas_smp_remote_device_removed(0x%x) enter\n", 1811 this_device 1812 )); 1813 1814 //remove all the smp phys in this device's smp_phy_list, and the conterpart smp phys 1815 //in phy connections. 1816 while (element != NULL) 1817 { 1818 curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element); 1819 element = sci_fast_list_get_next(element); 1820 1821 scif_sas_smp_phy_destruct(curr_smp_phy); 1822 } 1823 1824 this_device->protocol_device.smp_device.number_of_phys = 0; 1825 this_device->protocol_device.smp_device.expander_route_indexes = 0; 1826 this_device->protocol_device.smp_device.is_table_to_table_supported = FALSE; 1827 this_device->protocol_device.smp_device.is_externally_configurable = FALSE; 1828 this_device->protocol_device.smp_device.is_able_to_config_others = FALSE; 1829 1830 scif_sas_smp_remote_device_clear(this_device); 1831 } 1832 1833 1834 /** 1835 * @brief This method takes care of terminated smp request to a smp device. The 1836 * terminated smp request is most likely timeout and being aborted. A timeout 1837 * maybe due to OPEN REJECT (NO DESTINATION). 1838 * 1839 * @param[in] fw_device The expander device that a timed out smp request towards to. 1840 * @param[in] fw_request A failed smp request that is terminated by scic. 1841 * 1842 * @return none. 1843 */ 1844 void scif_sas_smp_remote_device_terminated_request_handler( 1845 SCIF_SAS_REMOTE_DEVICE_T * fw_device, 1846 SCIF_SAS_REQUEST_T * fw_request 1847 ) 1848 { 1849 SCIF_LOG_TRACE(( 1850 sci_base_object_get_logger(fw_device), 1851 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 1852 "scif_sas_smp_remote_device_terminated_request_handler(0x%x, 0x%x) enter\n", 1853 fw_device, fw_request 1854 )); 1855 1856 scif_sas_smp_remote_device_decode_smp_response( 1857 fw_device, fw_request, NULL, SCI_FAILURE_RETRY_REQUIRED 1858 ); 1859 } 1860 1861 1862 /** 1863 * @brief This method allocates and populates the smp phy list of a expander device. 1864 * 1865 * @param[in] fw_device The expander device, whose smp phy list is to be populated after 1866 * getting REPORT GENERAL response. 1867 * 1868 * @return none. 1869 */ 1870 void scif_sas_smp_remote_device_populate_smp_phy_list( 1871 SCIF_SAS_REMOTE_DEVICE_T * fw_device 1872 ) 1873 { 1874 SCIF_SAS_SMP_PHY_T * this_smp_phy = NULL; 1875 U8 expander_phy_id = 0; 1876 1877 SCIF_LOG_TRACE(( 1878 sci_base_object_get_logger(fw_device), 1879 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 1880 "scif_sas_smp_remote_device_populate_smp_phy_list(0x%x) enter\n", 1881 fw_device 1882 )); 1883 1884 for ( expander_phy_id = 0; 1885 expander_phy_id < fw_device->protocol_device.smp_device.number_of_phys; 1886 expander_phy_id++ ) 1887 { 1888 this_smp_phy = 1889 scif_sas_controller_allocate_smp_phy(fw_device->domain->controller); 1890 1891 ASSERT( this_smp_phy != NULL ); 1892 1893 if ( this_smp_phy != NULL ) 1894 scif_sas_smp_phy_construct(this_smp_phy, fw_device, expander_phy_id); 1895 } 1896 } 1897 1898 1899 /** 1900 * @brief This method updates a smp phy of a expander device based on DISCOVER response. 1901 * 1902 * @param[in] fw_device The expander device, one of whose smp phys is to be updated. 1903 * @param[in] discover_response The smp DISCOVER response. 1904 * 1905 * @return SCI_STATUS If a smp phy pair between expanders has invalid routing attribute, 1906 * return SCI_FAILURE_ILLEGAL_ROUTING_ATTRIBUTE_CONFIGURATION, otherwise, 1907 * return SCI_SUCCESS 1908 */ 1909 SCI_STATUS scif_sas_smp_remote_device_save_smp_phy_info( 1910 SCIF_SAS_REMOTE_DEVICE_T * fw_device, 1911 SMP_RESPONSE_DISCOVER_T * discover_response 1912 ) 1913 { 1914 SCI_STATUS status = SCI_SUCCESS; 1915 SCIF_SAS_SMP_PHY_T * smp_phy = NULL; 1916 SCIF_SAS_REMOTE_DEVICE_T * attached_device = NULL; 1917 1918 SCIF_LOG_TRACE(( 1919 sci_base_object_get_logger(fw_device), 1920 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 1921 "scif_sas_smp_remote_device_save_smp_phy_info(0x%x, 0x%x) enter\n", 1922 fw_device, discover_response 1923 )); 1924 1925 smp_phy = scif_sas_smp_remote_device_find_smp_phy_by_id( 1926 discover_response->phy_identifier, 1927 &fw_device->protocol_device.smp_device 1928 ); 1929 1930 ASSERT( smp_phy != NULL ); 1931 1932 //Note, attached_device could be NULL, not all the smp phy have to connected to a device. 1933 attached_device = (SCIF_SAS_REMOTE_DEVICE_T *) 1934 scif_domain_get_device_by_sas_address( 1935 fw_device->domain, &discover_response->attached_sas_address); 1936 1937 if (smp_phy != NULL) 1938 { 1939 scif_sas_smp_phy_save_information( 1940 smp_phy, attached_device, discover_response); 1941 } 1942 1943 //handle the special case of smp phys between expanders. 1944 if ( discover_response->protocols.u.bits.attached_smp_target ) 1945 { 1946 //this fw_device is a child expander, just found its parent expander. 1947 //And there is no smp_phy constructed yet, record this phy connection. 1948 if ( attached_device != NULL 1949 && attached_device == fw_device->containing_device ) 1950 { 1951 //record the smp phy info, for this phy connects to a upstream smp device. 1952 //the connection of a pair of smp phys are completed. 1953 status = scif_sas_smp_phy_set_attached_phy( 1954 smp_phy, 1955 discover_response->attached_phy_identifier, 1956 attached_device 1957 ); 1958 1959 if (status == SCI_SUCCESS) 1960 { 1961 //check the routing attribute for this phy and its containing device's 1962 //expander_phy_routing_attribute. 1963 if ( scif_sas_smp_phy_verify_routing_attribute( 1964 smp_phy, smp_phy->u.attached_phy) != SCI_SUCCESS ) 1965 return SCI_FAILURE_ILLEGAL_ROUTING_ATTRIBUTE_CONFIGURATION; 1966 } 1967 } 1968 } 1969 1970 return status; 1971 } 1972 1973 #ifdef SCI_SMP_PHY_LIST_DEBUG_PRINT 1974 void scif_sas_smp_remote_device_print_smp_phy_list( 1975 SCIF_SAS_REMOTE_DEVICE_T * fw_device 1976 ) 1977 { 1978 SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device = &fw_device->protocol_device.smp_device; 1979 SCI_FAST_LIST_ELEMENT_T * element = smp_remote_device->smp_phy_list.list_head; 1980 SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL; 1981 1982 SCIF_LOG_ERROR(( 1983 sci_base_object_get_logger(fw_device), 1984 SCIF_LOG_OBJECT_REMOTE_DEVICE, 1985 "==========EXPANDER DEVICE (0x%x) smp phy list========== \n", 1986 fw_device 1987 )); 1988 1989 while (element != NULL) 1990 { 1991 curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element); 1992 element = sci_fast_list_get_next(element); 1993 1994 //print every thing about a smp phy 1995 SCIF_LOG_ERROR(( 1996 sci_base_object_get_logger(fw_device), 1997 SCIF_LOG_OBJECT_REMOTE_DEVICE, 1998 "SMP_PHY_%d (0x%x), attached device(0x%x), attached_sas_address(%x%x) attached_device_type(%d), routing_attribute(%d)\n", 1999 curr_smp_phy->phy_identifier, curr_smp_phy, 2000 curr_smp_phy->u.end_device, 2001 curr_smp_phy->attached_sas_address.high, curr_smp_phy->attached_sas_address.low, 2002 curr_smp_phy->attached_device_type, 2003 curr_smp_phy->routing_attribute 2004 )); 2005 } 2006 } 2007 #endif 2008 2009 2010 /** 2011 * @brief This method configure upstream expander(s)' (if there is any) route info. 2012 * 2013 * @param[in] this_device The expander device that is currently in discover process. 2014 * 2015 * @return none. 2016 */ 2017 void scif_sas_smp_remote_device_configure_upstream_expander_route_info( 2018 SCIF_SAS_REMOTE_DEVICE_T * this_device 2019 ) 2020 { 2021 SCIF_SAS_REMOTE_DEVICE_T * curr_child_expander = this_device; 2022 SCIF_SAS_REMOTE_DEVICE_T * curr_parent_expander = 2023 scif_sas_remote_device_find_upstream_expander(this_device); 2024 2025 SCIF_SAS_REMOTE_DEVICE_T * curr_config_route_info_expander = NULL; 2026 2027 SCIF_LOG_TRACE(( 2028 sci_base_object_get_logger(this_device), 2029 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 2030 "scif_sas_smp_remote_device_configure_upstream_expander_route_info(0x%x) enter\n", 2031 this_device 2032 )); 2033 2034 //traverse back to find root device. 2035 while(curr_parent_expander != NULL ) 2036 { 2037 //must set destination_smp_phy outside of find_upstream_expander() using the device 2038 //that is just about to finish the discovery. 2039 curr_parent_expander->protocol_device.smp_device.curr_config_route_destination_smp_phy = 2040 (SCIF_SAS_SMP_PHY_T*)sci_fast_list_get_object( 2041 this_device->protocol_device.smp_device.smp_phy_list.list_head); 2042 2043 curr_child_expander = curr_parent_expander; 2044 curr_parent_expander = scif_sas_remote_device_find_upstream_expander(curr_child_expander); 2045 } 2046 2047 //found the root device: curr_child_expander. configure it and its downstream expander(s) till 2048 //this_device or a self-configuring expander that configures others; 2049 curr_config_route_info_expander = curr_child_expander; 2050 2051 while ( curr_config_route_info_expander != NULL 2052 && curr_config_route_info_expander != this_device 2053 && curr_config_route_info_expander->protocol_device.smp_device.scheduled_activity 2054 == SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE 2055 ) 2056 { 2057 if (curr_config_route_info_expander->protocol_device.smp_device.is_externally_configurable) 2058 { 2059 SCIF_SAS_SMP_PHY_T * phy_being_config = 2060 curr_config_route_info_expander->protocol_device.smp_device.config_route_smp_phy_anchor; 2061 2062 curr_config_route_info_expander->protocol_device.smp_device.curr_config_route_index = 2063 phy_being_config->config_route_table_index_anchor; 2064 2065 if (curr_config_route_info_expander->protocol_device.smp_device.curr_config_route_index != 0) 2066 curr_config_route_info_expander->protocol_device.smp_device.curr_config_route_index++; 2067 2068 curr_config_route_info_expander->protocol_device.smp_device.scheduled_activity = 2069 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE; 2070 2071 //Find a downstream expander that has curr_config_route_destination_smp_phy.owning device 2072 //same as curr_config_route_info_expander. 2073 curr_config_route_info_expander = scif_sas_remote_device_find_downstream_expander( 2074 curr_config_route_info_expander); 2075 } 2076 else if (curr_config_route_info_expander->protocol_device.smp_device.is_able_to_config_others) 2077 { 2078 //no need to config route table to this expander and its children. 2079 //find its downstream expander and clear the planned config route table activity. 2080 SCIF_SAS_REMOTE_DEVICE_T * curr_downstream_expander = 2081 scif_sas_remote_device_find_downstream_expander( 2082 curr_config_route_info_expander); 2083 2084 scif_sas_smp_remote_device_clear(curr_config_route_info_expander); 2085 2086 while ( curr_downstream_expander != NULL 2087 && curr_downstream_expander != this_device ) 2088 { 2089 scif_sas_smp_remote_device_clear(curr_downstream_expander); 2090 curr_downstream_expander = 2091 scif_sas_remote_device_find_downstream_expander( 2092 curr_config_route_info_expander); 2093 } 2094 2095 break; 2096 } 2097 else 2098 { 2099 // current expander is a self-configuring expander, which is not externally 2100 // configurable, and doesn't config others. we need to simply skip this expander. 2101 curr_config_route_info_expander = scif_sas_remote_device_find_downstream_expander( 2102 curr_config_route_info_expander); 2103 } 2104 } 2105 } 2106 2107 /** 2108 * @brief This method finds the immediate upstream expander of a given expander device. 2109 * 2110 * @param[in] this_device The given expander device, whose upstream expander is to be found. 2111 * 2112 * @return The immediate upstream expander. Or a NULL pointer if this_device is root already. 2113 */ 2114 SCIF_SAS_REMOTE_DEVICE_T * scif_sas_remote_device_find_upstream_expander( 2115 SCIF_SAS_REMOTE_DEVICE_T * this_device 2116 ) 2117 { 2118 SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device = 2119 &this_device->protocol_device.smp_device; 2120 2121 SCIF_SAS_REMOTE_DEVICE_T * upstream_expander = NULL; 2122 2123 SCI_FAST_LIST_ELEMENT_T * element = smp_remote_device->smp_phy_list.list_head; 2124 SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL; 2125 2126 SCIF_LOG_TRACE(( 2127 sci_base_object_get_logger(this_device), 2128 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 2129 "scif_sas_smp_remote_device_configure_upstream_expander_route_info(0x%x) enter\n", 2130 this_device 2131 )); 2132 2133 while (element != NULL) 2134 { 2135 curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element); 2136 element = sci_fast_list_get_next(element); 2137 2138 if ( curr_smp_phy->routing_attribute == SUBTRACTIVE_ROUTING_ATTRIBUTE 2139 && ( curr_smp_phy->attached_device_type == SMP_EDGE_EXPANDER_DEVICE 2140 || curr_smp_phy->attached_device_type == SMP_FANOUT_EXPANDER_DEVICE) 2141 && curr_smp_phy->u.attached_phy != NULL 2142 && curr_smp_phy->u.attached_phy->routing_attribute == TABLE_ROUTING_ATTRIBUTE ) 2143 { 2144 //set the current_activity and current_config_route_index for that 2145 //upstream expander. 2146 upstream_expander = curr_smp_phy->u.attached_phy->owning_device; 2147 2148 upstream_expander->protocol_device.smp_device.current_smp_request = 2149 SMP_FUNCTION_CONFIGURE_ROUTE_INFORMATION; 2150 2151 //if the upstream_expander's config route table method is config phy0 only or 2152 //config all phys, the current activity phy is found. 2153 upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor = 2154 scif_sas_smp_remote_device_find_smp_phy_by_id( 2155 curr_smp_phy->u.attached_phy->phy_identifier, 2156 &(curr_smp_phy->u.attached_phy->owning_device->protocol_device.smp_device) 2157 ); 2158 2159 //if the upstream_expander's config route table method is config middle phy only 2160 //config highest phy only, the current activity phy needs a update. 2161 if ( scif_sas_smp_remote_device_get_config_route_table_method(upstream_expander) 2162 == SCIF_SAS_CONFIG_ROUTE_TABLE_MIDDLE_PHY_ONLY ) 2163 { 2164 upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor = 2165 scif_sas_smp_phy_find_middle_phy_in_wide_port ( 2166 upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor 2167 ); 2168 } 2169 else if ( scif_sas_smp_remote_device_get_config_route_table_method(upstream_expander) 2170 == SCIF_SAS_CONFIG_ROUTE_TABLE_HIGHEST_PHY_ONLY ) 2171 { 2172 upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor = 2173 scif_sas_smp_phy_find_highest_phy_in_wide_port ( 2174 upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor 2175 ); 2176 } 2177 2178 upstream_expander->protocol_device.smp_device.current_activity_phy_index = 2179 upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor->phy_identifier; 2180 2181 return upstream_expander; 2182 } 2183 } 2184 2185 return NULL; 2186 } 2187 2188 2189 /** 2190 * @brief This method finds the immediate downstream expander of a given expander device. 2191 * 2192 * @param[in] this_device The given expander device, whose downstream expander is to be found. 2193 * 2194 * @return The immediate downstream expander. Or a NULL pointer if there is none. 2195 */ 2196 SCIF_SAS_REMOTE_DEVICE_T * scif_sas_remote_device_find_downstream_expander( 2197 SCIF_SAS_REMOTE_DEVICE_T * this_device 2198 ) 2199 { 2200 SCIF_SAS_SMP_REMOTE_DEVICE_T * this_smp_remote_device = 2201 &this_device->protocol_device.smp_device; 2202 2203 SCIF_SAS_REMOTE_DEVICE_T * downstream_expander = NULL; 2204 2205 SCI_FAST_LIST_ELEMENT_T * element = this_smp_remote_device->smp_phy_list.list_head; 2206 SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL; 2207 2208 SCIF_LOG_TRACE(( 2209 sci_base_object_get_logger(this_device), 2210 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 2211 "scif_sas_remote_device_find_downstream_expander(0x%x) enter\n", 2212 this_device 2213 )); 2214 2215 while (element != NULL) 2216 { 2217 curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element); 2218 element = sci_fast_list_get_next(element); 2219 2220 if ( curr_smp_phy->routing_attribute == TABLE_ROUTING_ATTRIBUTE 2221 && curr_smp_phy->attached_device_type == SMP_EDGE_EXPANDER_DEVICE 2222 && curr_smp_phy->u.attached_phy != NULL) 2223 { 2224 //set the current_activity and current_config_route_index for that 2225 //upstream expander. 2226 downstream_expander = curr_smp_phy->u.attached_phy->owning_device; 2227 2228 if ( downstream_expander->protocol_device.smp_device.curr_config_route_destination_smp_phy != NULL 2229 && downstream_expander->protocol_device.smp_device.curr_config_route_destination_smp_phy->owning_device == 2230 this_smp_remote_device->curr_config_route_destination_smp_phy->owning_device ) 2231 return downstream_expander; 2232 } 2233 } 2234 2235 return NULL; 2236 } 2237 2238 2239 /** 2240 * @brief This method follows route table optimization rule to check if a destination_device 2241 * should be recorded in the device_being_config's route table 2242 * 2243 * @param[in] device_being_config The upstream expander device, whose route table is being configured. 2244 * @param[in] destination_smp_phy A smp phy whose attached device is potentially to be 2245 * recorded in route table. 2246 * 2247 * @return BOOL This method returns TRUE if a destination_device should be recorded in route table. 2248 * This method returns FALSE if a destination_device need not to be recorded 2249 * in route table. 2250 */ 2251 BOOL scif_sas_smp_remote_device_do_config_route_info( 2252 SCIF_SAS_REMOTE_DEVICE_T * device_being_config, 2253 SCIF_SAS_SMP_PHY_T * destination_smp_phy 2254 ) 2255 { 2256 SCI_SAS_ADDRESS_T device_being_config_sas_address; 2257 2258 SCIF_LOG_TRACE(( 2259 sci_base_object_get_logger(device_being_config), 2260 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 2261 "scif_sas_smp_remote_device_do_config_route_info(0x%x, 0x%x) enter\n", 2262 device_being_config, destination_smp_phy 2263 )); 2264 2265 scic_remote_device_get_sas_address( 2266 device_being_config->core_object, &device_being_config_sas_address 2267 ); 2268 2269 //refer to SAS-2 spec 4.8.3, rule (b) 2270 if ((destination_smp_phy->attached_sas_address.low == 0 2271 && destination_smp_phy->attached_sas_address.high == 0) 2272 && (destination_smp_phy->attached_device_type == SMP_NO_DEVICE_ATTACHED)) 2273 { 2274 return FALSE; 2275 } 2276 2277 //refer to SAS-2 spec 4.8.3, rule (c), self-referencing. 2278 if (destination_smp_phy->attached_sas_address.high == 2279 device_being_config_sas_address.high 2280 && destination_smp_phy->attached_sas_address.low == 2281 device_being_config_sas_address.low) 2282 { 2283 return FALSE; 2284 } 2285 2286 //There will be no cases that falling into rule (a), (d), (e) to be excluded, 2287 //based on our current mechanism of cofig route table. 2288 2289 return TRUE; 2290 } 2291 2292 2293 /** 2294 * @brief This method configures device_being_config's route table for all the enclosed devices in 2295 * a downstream smp device, destination_device. 2296 * 2297 * @param[in] device_being_config The upstream expander device, whose route table is being configured. 2298 * 2299 * @return None 2300 */ 2301 void scif_sas_smp_remote_device_configure_route_table( 2302 SCIF_SAS_REMOTE_DEVICE_T * device_being_config 2303 ) 2304 { 2305 //go through the smp phy list of this_device. 2306 SCI_FAST_LIST_ELEMENT_T * element = 2307 &(device_being_config->protocol_device.smp_device.curr_config_route_destination_smp_phy->list_element); 2308 SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL; 2309 2310 SCIF_LOG_TRACE(( 2311 sci_base_object_get_logger(device_being_config), 2312 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 2313 "scif_sas_smp_remote_device_configure_route_table(0x%x) enter\n", 2314 device_being_config 2315 )); 2316 2317 device_being_config->protocol_device.smp_device.current_activity = 2318 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE; 2319 2320 while (element != NULL) 2321 { 2322 curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element); 2323 element = sci_fast_list_get_next(element); 2324 2325 //check if this phy needs to be added to the expander's route table. 2326 if (scif_sas_smp_remote_device_do_config_route_info( 2327 device_being_config, curr_smp_phy) == TRUE ) 2328 { 2329 SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device = 2330 &device_being_config->protocol_device.smp_device; 2331 2332 smp_remote_device->curr_config_route_destination_smp_phy = 2333 curr_smp_phy; 2334 2335 //Then config this_device's route table entry at the phy and next route_index. 2336 //send config_route_info using curr_smp_phy.phy_identifier and sas_address. 2337 scif_sas_smp_request_construct_config_route_info( 2338 device_being_config->domain->controller, 2339 device_being_config, 2340 smp_remote_device->current_activity_phy_index, 2341 smp_remote_device->curr_config_route_index, 2342 curr_smp_phy->attached_sas_address, 2343 FALSE 2344 ); 2345 2346 //schedule the DPC. 2347 scif_cb_start_internal_io_task_schedule( 2348 device_being_config->domain->controller, 2349 scif_sas_controller_start_high_priority_io, 2350 device_being_config->domain->controller 2351 ); 2352 2353 //stop here, we need to wait for config route info's response then send 2354 //the next one. 2355 break; 2356 } 2357 } 2358 } 2359 2360 2361 /** 2362 * @brief This method walks through an expander's route table to clean table 2363 * attribute phys' route entries. This routine finds one table entry 2364 * to clean and will be called repeatly till it finishes cleanning the 2365 * whole table. 2366 * 2367 * @param[in] fw_device The expander device, whose route table entry is to be cleaned. 2368 * 2369 * @return None. 2370 */ 2371 void scif_sas_smp_remote_device_clean_route_table( 2372 SCIF_SAS_REMOTE_DEVICE_T * fw_device 2373 ) 2374 { 2375 SCIF_SAS_SMP_PHY_T * smp_phy_being_config = 2376 scif_sas_smp_remote_device_find_smp_phy_by_id( 2377 fw_device->protocol_device.smp_device.current_activity_phy_index, 2378 &(fw_device->protocol_device.smp_device) 2379 ); 2380 2381 SCIF_LOG_TRACE(( 2382 sci_base_object_get_logger(fw_device), 2383 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 2384 "scif_sas_smp_remote_device_clean_route_table(0x%x) enter\n", 2385 fw_device 2386 )); 2387 2388 //from anchors, start to clean all the other route table entries. 2389 fw_device->protocol_device.smp_device.curr_config_route_index++; 2390 2391 if ( fw_device->protocol_device.smp_device.curr_config_route_index >= 2392 fw_device->protocol_device.smp_device.expander_route_indexes ) 2393 { 2394 fw_device->protocol_device.smp_device.curr_config_route_index = 0; 2395 2396 do //find next table attribute PHY. 2397 { 2398 fw_device->protocol_device.smp_device.current_activity_phy_index++; 2399 if (fw_device->protocol_device.smp_device.current_activity_phy_index == 2400 fw_device->protocol_device.smp_device.number_of_phys) 2401 fw_device->protocol_device.smp_device.current_activity_phy_index=0; 2402 2403 //phy_index changed, so update the smp_phy_being_config. 2404 smp_phy_being_config = 2405 scif_sas_smp_remote_device_find_smp_phy_by_id( 2406 fw_device->protocol_device.smp_device.current_activity_phy_index, 2407 &(fw_device->protocol_device.smp_device) 2408 ); 2409 } while( smp_phy_being_config->routing_attribute != TABLE_ROUTING_ATTRIBUTE ); 2410 2411 if ( smp_phy_being_config->phy_identifier != 2412 fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->phy_identifier) 2413 { 2414 if (smp_phy_being_config->config_route_table_index_anchor != 0) 2415 fw_device->protocol_device.smp_device.curr_config_route_index = 2416 smp_phy_being_config->config_route_table_index_anchor + 1; 2417 else 2418 fw_device->protocol_device.smp_device.curr_config_route_index = 0; 2419 } 2420 } 2421 2422 if ( !(fw_device->protocol_device.smp_device.current_activity_phy_index == 2423 fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->phy_identifier 2424 && fw_device->protocol_device.smp_device.curr_config_route_index == 0) 2425 ) 2426 { 2427 //clean this route entry. 2428 scif_sas_smp_remote_device_clean_route_table_entry(fw_device); 2429 } 2430 else 2431 { 2432 fw_device->protocol_device.smp_device.is_route_table_cleaned = TRUE; 2433 2434 //set this device's activity to NON. 2435 fw_device->protocol_device.smp_device.current_activity = 2436 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE; 2437 2438 //we need to notify domain that this device finished config route table, domain 2439 //may pick up other activities (i.e. Discover) for other expanders. 2440 scif_sas_domain_continue_discover(fw_device->domain); 2441 } 2442 } 2443 2444 /** 2445 * @brief This method cleans a device's route table antry. 2446 * 2447 * @param[in] fw_device The expander device, whose route table entry is to be cleaned. 2448 * 2449 * @return None. 2450 */ 2451 void scif_sas_smp_remote_device_clean_route_table_entry( 2452 SCIF_SAS_REMOTE_DEVICE_T * fw_device 2453 ) 2454 { 2455 SCI_SAS_ADDRESS_T empty_sas_address; 2456 SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device = 2457 &(fw_device->protocol_device.smp_device); 2458 2459 SCIF_LOG_TRACE(( 2460 sci_base_object_get_logger(fw_device), 2461 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 2462 "scif_sas_smp_remote_device_clean_route_table(0x%x) enter\n", 2463 fw_device 2464 )); 2465 2466 empty_sas_address.high = 0; 2467 empty_sas_address.low = 0; 2468 2469 scif_sas_smp_request_construct_config_route_info( 2470 fw_device->domain->controller, 2471 fw_device, 2472 smp_remote_device->current_activity_phy_index, 2473 smp_remote_device->curr_config_route_index, 2474 empty_sas_address, 2475 TRUE 2476 ); 2477 2478 //schedule the DPC. 2479 scif_cb_start_internal_io_task_schedule( 2480 fw_device->domain->controller, 2481 scif_sas_controller_start_high_priority_io, 2482 fw_device->domain->controller 2483 ); 2484 } 2485 2486 2487 /** 2488 * @brief This method handles the case of exceeding route index when config route table 2489 * for a device, by removing the attached device of current config route 2490 * destination smp phy and the rest of smp phys in the same smp phy list. 2491 * 2492 * @param[in] fw_device The expander device, whose route table to be edited but failed 2493 * with a SMP function result of INDEX DOES NOT EXIST. 2494 * 2495 * @return None. 2496 */ 2497 void scif_sas_smp_remote_device_cancel_config_route_table_activity( 2498 SCIF_SAS_REMOTE_DEVICE_T * fw_device 2499 ) 2500 { 2501 //go through the rest of the smp phy list of destination device. 2502 SCI_FAST_LIST_ELEMENT_T * element = 2503 &(fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy->list_element); 2504 SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL; 2505 SCIF_SAS_REMOTE_DEVICE_T * curr_attached_device = NULL; 2506 2507 SCIF_LOG_TRACE(( 2508 sci_base_object_get_logger(fw_device), 2509 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 2510 "scif_sas_smp_remote_device_cancel_config_route_table_activity(0x%x) enter\n", 2511 fw_device 2512 )); 2513 2514 while (element != NULL) 2515 { 2516 curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element); 2517 element = sci_fast_list_get_next(element); 2518 2519 //check if this phy needs to be added to the expander's route table but can't due to 2520 //exceeding max route index. 2521 if (scif_sas_smp_remote_device_do_config_route_info( 2522 fw_device, curr_smp_phy) == TRUE ) 2523 { 2524 //set the is_currently_discovered to FALSE for attached device. Then when 2525 //domain finish discover, domain will remove this device. 2526 curr_attached_device = (SCIF_SAS_REMOTE_DEVICE_T *) 2527 scif_domain_get_device_by_sas_address( 2528 fw_device->domain, &(curr_smp_phy->attached_sas_address)); 2529 2530 if (curr_attached_device != NULL) 2531 curr_attached_device->is_currently_discovered = FALSE; 2532 } 2533 } 2534 } 2535 2536 2537 /** 2538 * @brief This method cancel current activity and terminate the outstanding internal IO 2539 * if there is one. 2540 * 2541 * @param[in] fw_device The expander device, whose smp activity is to be canceled. 2542 * 2543 * @return None. 2544 */ 2545 void scif_sas_smp_remote_device_cancel_smp_activity( 2546 SCIF_SAS_REMOTE_DEVICE_T * fw_device 2547 ) 2548 { 2549 SCIF_LOG_TRACE(( 2550 sci_base_object_get_logger(fw_device), 2551 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 2552 "scif_sas_smp_remote_device_cancel_smp_activity(0x%x) enter\n", 2553 fw_device 2554 )); 2555 2556 //Terminate all of the requests in the silicon for this device. 2557 scif_sas_domain_terminate_requests( 2558 fw_device->domain, fw_device, NULL, NULL 2559 ); 2560 2561 if (fw_device->protocol_device.smp_device.current_activity == 2562 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE) 2563 scif_sas_smp_remote_device_cancel_config_route_table_activity(fw_device); 2564 2565 //Clear the device to stop the smp sctivity. 2566 scif_sas_smp_remote_device_clear(fw_device); 2567 } 2568 2569 2570 /** 2571 * @brief This method tells the way to configure route table for a expander. The 2572 * possible ways are: configure phy 0's route table, configure middle 2573 * phy's route table, configure highest order phy's route table, 2574 * configure all phys. 2575 * 2576 * @param[in] fw_device The expander device, whose config route table method is 2577 * to be chosen. 2578 * 2579 * @return one in 4 possible options. 2580 */ 2581 U8 scif_sas_smp_remote_device_get_config_route_table_method( 2582 SCIF_SAS_REMOTE_DEVICE_T * fw_device 2583 ) 2584 { 2585 U8 config_route_table_method; 2586 2587 //config_route_table_method = SCIF_SAS_CONFIG_ROUTE_TABLE_MIDDLE_PHY_ONLY; 2588 config_route_table_method = SCIF_SAS_CONFIG_ROUTE_TABLE_ALL_PHYS; 2589 2590 return config_route_table_method; 2591 } 2592 2593 2594 /** 2595 * @brief This method starts the EA target reset process by constructing 2596 * and starting a PHY CONTROL (hard reset) smp request. 2597 * 2598 * @param[in] expander_device The expander device, to which a PHY Control smp command is 2599 * sent. 2600 * @param[in] target_device The expander attahced target device, to which the target reset 2601 * request is sent. 2602 * @param[in] fw_request The target reset task request. 2603 * 2604 * @return none 2605 */ 2606 void scif_sas_smp_remote_device_start_target_reset( 2607 SCIF_SAS_REMOTE_DEVICE_T * expander_device, 2608 SCIF_SAS_REMOTE_DEVICE_T * target_device, 2609 SCIF_SAS_REQUEST_T * fw_request 2610 ) 2611 { 2612 SCIF_SAS_CONTROLLER_T * fw_controller = expander_device->domain->controller; 2613 2614 //set current_activity and current_smp_request to expander device. 2615 expander_device->protocol_device.smp_device.current_activity = 2616 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_TARGET_RESET; 2617 expander_device->protocol_device.smp_device.current_smp_request = 2618 SMP_FUNCTION_PHY_CONTROL; 2619 expander_device->protocol_device.smp_device.current_activity_phy_index = 2620 target_device->expander_phy_identifier; 2621 2622 //A Phy Control smp request has been constructed towards parent device. 2623 //Walk the high priority io path. 2624 fw_controller->state_handlers->start_high_priority_io_handler( 2625 (SCI_BASE_CONTROLLER_T*) fw_controller, 2626 (SCI_BASE_REMOTE_DEVICE_T*) expander_device, 2627 (SCI_BASE_REQUEST_T*) fw_request, 2628 SCI_CONTROLLER_INVALID_IO_TAG 2629 ); 2630 } 2631 2632 2633