1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause OR GPL-2.0 3 * 4 * This file is provided under a dual BSD/GPLv2 license. When using or 5 * redistributing this file, you may do so under either license. 6 * 7 * GPL LICENSE SUMMARY 8 * 9 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of version 2 of the GNU General Public License as 13 * published by the Free Software Foundation. 14 * 15 * This program is distributed in the hope that it will be useful, but 16 * WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 * General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 23 * The full GNU General Public License is included in this distribution 24 * in the file called LICENSE.GPL. 25 * 26 * BSD LICENSE 27 * 28 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. 29 * All rights reserved. 30 * 31 * Redistribution and use in source and binary forms, with or without 32 * modification, are permitted provided that the following conditions 33 * are met: 34 * 35 * * Redistributions of source code must retain the above copyright 36 * notice, this list of conditions and the following disclaimer. 37 * * Redistributions in binary form must reproduce the above copyright 38 * notice, this list of conditions and the following disclaimer in 39 * the documentation and/or other materials provided with the 40 * distribution. 41 * 42 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 43 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 44 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 45 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 46 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 47 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 48 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 49 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 50 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 51 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 52 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 53 */ 54 55 #include <sys/cdefs.h> 56 /** 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 SMP_RESPONSE_DISCOVER_T * discover_response = 752 &smp_response->response.discover; 753 754 SMP_RESPONSE_HEADER_T * response_header = &smp_response->header; 755 756 SCIF_LOG_TRACE(( 757 sci_base_object_get_logger(fw_device), 758 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 759 "scif_sas_smp_remote_device_decode_target_reset_discover_response(0x%x, 0x%x) enter\n", 760 fw_device, smp_response 761 )); 762 763 if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED) 764 { 765 /// @todo: more decoding work needed when the function_result is not 766 /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some 767 /// function result. 768 SCIF_LOG_ERROR(( 769 sci_base_object_get_logger(fw_device), 770 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 771 "Discover function result(0x%x)\n", 772 response_header->function_result 773 )); 774 775 return SCI_FAILURE_RETRY_REQUIRED; 776 } 777 778 //only if there is device attached. 779 if ( discover_response->u2.sas1_1.attached_device_type != SMP_NO_DEVICE_ATTACHED ) 780 { 781 fw_domain = fw_device->domain; 782 attached_device_address = discover_response->attached_sas_address; 783 784 // the device should have already existed in the domian. 785 ASSERT(scif_domain_get_device_by_sas_address( 786 fw_domain, 787 &attached_device_address 788 ) != SCI_INVALID_HANDLE); 789 return SCI_SUCCESS; 790 } 791 else 792 return SCI_FAILURE_RETRY_REQUIRED; 793 } 794 795 /** 796 * @brief This method decodes a smp Discover response to this smp device 797 * for SPINUP_HOLD_RELEASE activity. If a DISCOVER response says 798 * SATA DEVICE ATTACHED and has a valid NPL value, we call fw_device's 799 * start_handler(). But if a DISCOVER response still shows SPINUP 800 * in NPL state, we need to return retry_required status 801 * 802 * @param[in] fw_device The framework device that the DISCOVER command 803 * targets to. 804 * @param[in] discover_response The pointer to a DISCOVER response 805 * 806 * @return SCI_SUCCESS 807 * SCI_FAILURE_RETRY_REQUIRED 808 */ 809 SCI_STATUS scif_sas_smp_remote_device_decode_spinup_hold_release_discover_response( 810 SCIF_SAS_REMOTE_DEVICE_T * fw_device, 811 SMP_RESPONSE_T * smp_response 812 ) 813 { 814 SMP_RESPONSE_DISCOVER_T * discover_response = &smp_response->response.discover; 815 816 SMP_RESPONSE_HEADER_T * response_header = &smp_response->header; 817 818 SCIF_LOG_TRACE(( 819 sci_base_object_get_logger(fw_device), 820 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 821 "scif_sas_smp_remote_device_decode_spinup_hold_release_discover_response(0x%x, 0x%x) enter\n", 822 fw_device, smp_response 823 )); 824 825 if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED) 826 { 827 /// @todo: more decoding work needed when the function_result is not 828 /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some 829 /// function result. 830 SCIF_LOG_ERROR(( 831 sci_base_object_get_logger(fw_device), 832 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 833 "Discover function result(0x%x)\n", 834 response_header->function_result 835 )); 836 837 return SCI_FAILURE; 838 } 839 840 if ( discover_response->u2.sas1_1.attached_device_type != SMP_NO_DEVICE_ATTACHED ) 841 { 842 if (discover_response->u2.sas1_1.negotiated_physical_link_rate != SCI_SATA_SPINUP_HOLD 843 && discover_response->u4.sas2.negotiated_physical_link_rate != SCI_SATA_SPINUP_HOLD 844 && ( discover_response->protocols.u.bits.attached_stp_target 845 ||discover_response->protocols.u.bits.attached_sata_device ) 846 ) 847 { 848 SCIF_SAS_REMOTE_DEVICE_T * target_device = 849 scif_sas_domain_get_device_by_containing_device( 850 fw_device->domain, 851 fw_device, 852 fw_device->protocol_device.smp_device.current_activity_phy_index 853 ); 854 855 //Need to update the device's connection rate. Its connection rate was SPINIP_HOLD. 856 scic_remote_device_set_max_connection_rate( 857 target_device->core_object, 858 discover_response->u2.sas1_1.negotiated_physical_link_rate 859 ); 860 861 //Need to update the smp phy info too. 862 scif_sas_smp_remote_device_save_smp_phy_info( 863 fw_device, discover_response); 864 865 //This device has already constructed, only need to call start_handler 866 //of this device here. 867 return target_device->state_handlers->parent.start_handler( 868 &target_device->parent ); 869 } 870 else 871 return SCI_FAILURE_RETRY_REQUIRED; 872 } 873 else 874 return SCI_FAILURE_RETRY_REQUIRED; 875 } 876 877 878 /** 879 * @brief This method decodes a smp CONFIG ROUTE INFO response to this smp 880 * device and then continue to config route table. 881 * 882 * @param[in] fw_device The framework device that the CONFIG ROUTE INFO command 883 * targets to. 884 * @param[in] smp_response The pointer to a CONFIG ROUTE INFO response 885 * 886 * @return none 887 */ 888 SCI_STATUS scif_sas_smp_remote_device_decode_config_route_info_response( 889 SCIF_SAS_REMOTE_DEVICE_T * fw_device, 890 SMP_RESPONSE_T * smp_response 891 ) 892 { 893 SMP_RESPONSE_HEADER_T * response_header = &smp_response->header; 894 895 SCIF_LOG_TRACE(( 896 sci_base_object_get_logger(fw_device), 897 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 898 "scif_sas_smp_remote_device_decode_config_route_info_response(0x%x, 0x%x) enter\n", 899 fw_device, smp_response 900 )); 901 902 if (response_header->function_result == SMP_RESULT_INDEX_DOES_NOT_EXIST) 903 { 904 //case of exceeding max route index. We need to remove the devices that are not 905 //able to be edit to route table. The destination config route smp phy 906 //is used to remove devices. 907 scif_sas_smp_remote_device_cancel_config_route_table_activity(fw_device); 908 909 return SCI_FAILURE_EXCEED_MAX_ROUTE_INDEX; 910 } 911 else if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED) 912 { 913 /// @todo: more decoding work needed when the function_result is not 914 /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some 915 /// function result. 916 SCIF_LOG_ERROR(( 917 sci_base_object_get_logger(fw_device), 918 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 919 "Discover function result(0x%x)\n", 920 response_header->function_result 921 )); 922 923 return SCI_FAILURE; 924 } 925 926 return SCI_SUCCESS; 927 } 928 929 930 /** 931 * @brief This method starts the smp Discover process for an expander by 932 * sending Report General request. 933 * 934 * @param[in] fw_device The framework smp device that a command 935 * targets to. 936 * 937 * @return none 938 */ 939 void scif_sas_smp_remote_device_start_discover( 940 SCIF_SAS_REMOTE_DEVICE_T * fw_device 941 ) 942 { 943 SCIF_SAS_CONTROLLER_T * fw_controller = fw_device->domain->controller; 944 945 SCIF_LOG_TRACE(( 946 sci_base_object_get_logger(fw_device), 947 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 948 "scif_sas_smp_remote_device_start_discover(0x%x) enter\n", 949 fw_device 950 )); 951 952 //For safety, clear the device again, there may be some config route table 953 //related info are not cleared yet. 954 scif_sas_smp_remote_device_clear(fw_device); 955 956 //set current activity 957 fw_device->protocol_device.smp_device.current_activity = 958 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER; 959 960 //Set current_smp_request to REPORT GENERAL. 961 fw_device->protocol_device.smp_device.current_smp_request = 962 SMP_FUNCTION_REPORT_GENERAL; 963 964 //reset discover_to_start flag. 965 fw_device->protocol_device.smp_device.scheduled_activity = 966 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE; 967 968 //build the first smp request Report Genernal. 969 scif_sas_smp_request_construct_report_general(fw_controller, fw_device); 970 971 //issue DPC to start this request. 972 scif_cb_start_internal_io_task_schedule( 973 fw_controller, 974 scif_sas_controller_start_high_priority_io, 975 fw_controller 976 ); 977 } 978 979 980 /** 981 * @brief This method continues the smp Discover process. 982 * 983 * @param[in] fw_device The framework smp device that a DISCOVER command 984 * targets to. 985 * @param[in] fw_request The pointer to an smp request whose response 986 * has been decoded. 987 * @param[in] status The decoding status of the smp request's response 988 * 989 * @return none 990 */ 991 void scif_sas_smp_remote_device_continue_current_activity( 992 SCIF_SAS_REMOTE_DEVICE_T * fw_device, 993 SCIF_SAS_REQUEST_T * fw_request, 994 SCI_STATUS status 995 ) 996 { 997 SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T *)fw_request; 998 // save the retry count. 999 U8 io_retry_count = fw_io->retry_count; 1000 1001 if (fw_request->is_internal) 1002 { 1003 // Complete this internal io request now. We want to free this io before 1004 // we create another SMP request, which is going to happen soon. 1005 scif_sas_internal_io_request_complete( 1006 fw_device->domain->controller, 1007 (SCIF_SAS_INTERNAL_IO_REQUEST_T *)fw_request, 1008 SCI_SUCCESS 1009 ); 1010 } 1011 1012 if (fw_device->protocol_device.smp_device.current_activity == 1013 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER) 1014 { 1015 if (status == SCI_SUCCESS) 1016 { //continue the discover process. 1017 scif_sas_smp_remote_device_continue_discover(fw_device); 1018 } 1019 else if (status == SCI_FAILURE_RETRY_REQUIRED) 1020 { 1021 //Retry the smp request. Since we are in the middle of Discover 1022 //process, all the smp requests are internal. A new smp request 1023 //will be created for retry. 1024 U32 retry_wait_duration = (SCIF_DOMAIN_DISCOVER_TIMEOUT / 2) / SCIF_SAS_IO_RETRY_LIMIT; 1025 1026 if (io_retry_count < SCIF_SAS_IO_RETRY_LIMIT) 1027 scif_sas_smp_remote_device_retry_internal_io ( 1028 fw_device, io_retry_count, retry_wait_duration); 1029 else 1030 scif_sas_smp_remote_device_fail_discover(fw_device); 1031 } 1032 else if (status == SCI_FAILURE_ILLEGAL_ROUTING_ATTRIBUTE_CONFIGURATION) 1033 { 1034 //remove this expander device and its child devices. No need to 1035 //continue the discover on this device. 1036 scif_sas_domain_remove_expander_device(fw_device->domain, fw_device); 1037 1038 //continue the domain's smp discover. 1039 scif_sas_domain_continue_discover(fw_device->domain); 1040 } 1041 else 1042 { //terminate the discover process. 1043 scif_sas_smp_remote_device_fail_discover(fw_device); 1044 } 1045 } 1046 else if (fw_device->protocol_device.smp_device.current_activity == 1047 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_TARGET_RESET) 1048 { 1049 if (status == SCI_SUCCESS) 1050 { //continue the target reset process. 1051 scif_sas_smp_remote_device_continue_target_reset( 1052 fw_device, fw_request); 1053 } 1054 else if (status == SCI_FAILURE_RETRY_REQUIRED) 1055 { 1056 //Retry the same smp request. Since we are in the middle of Target 1057 //reset process, all the smp requests are using external resource. 1058 //We will use the exactly same memory to retry. 1059 if (io_retry_count < SCIF_SAS_IO_RETRY_LIMIT) 1060 { 1061 if (fw_device->protocol_device.smp_device.smp_activity_timer == NULL) 1062 { 1063 //create the timer to wait before retry. 1064 fw_device->protocol_device.smp_device.smp_activity_timer = 1065 scif_cb_timer_create( 1066 (SCI_CONTROLLER_HANDLE_T *)fw_device->domain->controller, 1067 (SCI_TIMER_CALLBACK_T)scif_sas_smp_external_request_retry, 1068 (void*)fw_request 1069 ); 1070 } 1071 else 1072 { 1073 ASSERT(0); 1074 } 1075 1076 //start the timer to wait 1077 scif_cb_timer_start( 1078 (SCI_CONTROLLER_HANDLE_T)fw_device->domain->controller, 1079 fw_device->protocol_device.smp_device.smp_activity_timer, 1080 SMP_REQUEST_RETRY_WAIT_DURATION //20 miliseconds 1081 ); 1082 } 1083 else 1084 scif_sas_smp_remote_device_fail_target_reset(fw_device, fw_request); 1085 } 1086 else 1087 //terminate the discover process. 1088 scif_sas_smp_remote_device_fail_target_reset(fw_device, fw_request); 1089 } 1090 else if (fw_device->protocol_device.smp_device.current_activity == 1091 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_SATA_SPINUP_HOLD_RELEASE) 1092 { 1093 SCIF_SAS_REMOTE_DEVICE_T * target_device = 1094 scif_sas_domain_get_device_by_containing_device( 1095 fw_device->domain, 1096 fw_device, 1097 fw_device->protocol_device.smp_device.current_activity_phy_index 1098 ); 1099 1100 if (status == SCI_SUCCESS) 1101 { 1102 //move on to next round of SPINUP_HOLD_REALSE activity. 1103 scif_sas_smp_remote_device_sata_spinup_hold_release(fw_device); 1104 } 1105 else if (status == SCI_FAILURE_RETRY_REQUIRED) 1106 { 1107 U32 delay = 1108 (scic_remote_device_get_suggested_reset_timeout(target_device->core_object) / 1109 SCIF_SAS_IO_RETRY_LIMIT); 1110 1111 //Retry the smp request. Since we are in the middle of Discover 1112 //process, all the smp requests are internal. A new smp request 1113 //will be created for retry. 1114 if (io_retry_count < SCIF_SAS_IO_RETRY_LIMIT) 1115 { 1116 scif_sas_smp_remote_device_retry_internal_io( 1117 fw_device, io_retry_count, delay); 1118 } 1119 else //give up on this target device. 1120 { 1121 scif_sas_smp_remote_device_fail_target_spinup_hold_release( 1122 fw_device , target_device); 1123 } 1124 } 1125 else //give up on this target device. 1126 scif_sas_smp_remote_device_fail_target_spinup_hold_release( 1127 fw_device, target_device); 1128 } 1129 else if (fw_device->protocol_device.smp_device.current_activity == 1130 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE) 1131 { 1132 SCI_FAST_LIST_ELEMENT_T * next_phy_element = sci_fast_list_get_next( 1133 &(fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy->list_element) ); 1134 1135 SCI_FAST_LIST_T * destination_smp_phy_list = 1136 fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy->list_element.owning_list; 1137 1138 SCIF_SAS_SMP_PHY_T * next_phy_in_wide_port = NULL; 1139 1140 if (next_phy_element != NULL 1141 && status != SCI_FAILURE_EXCEED_MAX_ROUTE_INDEX) 1142 { 1143 fw_device->protocol_device.smp_device.curr_config_route_index++; 1144 1145 fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy = 1146 (SCIF_SAS_SMP_PHY_T *)sci_fast_list_get_object(next_phy_element); 1147 1148 // Update the anchor for config route index. 1149 fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->config_route_table_index_anchor = 1150 fw_device->protocol_device.smp_device.curr_config_route_index; 1151 1152 scif_sas_smp_remote_device_configure_route_table(fw_device); 1153 } 1154 else if ( scif_sas_smp_remote_device_get_config_route_table_method(fw_device) 1155 == SCIF_SAS_CONFIG_ROUTE_TABLE_ALL_PHYS 1156 && (next_phy_in_wide_port = scif_sas_smp_phy_find_next_phy_in_wide_port( 1157 fw_device->protocol_device.smp_device.config_route_smp_phy_anchor) 1158 )!= NULL 1159 ) 1160 { 1161 //config the other phy in the same wide port 1162 fw_device->protocol_device.smp_device.config_route_smp_phy_anchor = 1163 next_phy_in_wide_port; 1164 1165 fw_device->protocol_device.smp_device.current_activity_phy_index = 1166 fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->phy_identifier; 1167 1168 fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy = 1169 sci_fast_list_get_head(destination_smp_phy_list); 1170 1171 if (fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->config_route_table_index_anchor != 0) 1172 fw_device->protocol_device.smp_device.curr_config_route_index = 1173 fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->config_route_table_index_anchor + 1; 1174 else 1175 fw_device->protocol_device.smp_device.curr_config_route_index = 0; 1176 1177 scif_sas_smp_remote_device_configure_route_table(fw_device); 1178 } 1179 else if ( fw_device->protocol_device.smp_device.is_route_table_cleaned == FALSE) 1180 { 1181 fw_device->protocol_device.smp_device.current_activity = 1182 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAN_ROUTE_TABLE; 1183 1184 scif_sas_smp_remote_device_clean_route_table(fw_device); 1185 } 1186 else 1187 { 1188 //set this device's activity to NON. 1189 fw_device->protocol_device.smp_device.current_activity = 1190 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE; 1191 1192 //we need to notify domain that this device finished config route table, domain 1193 //may pick up other activities (i.e. Discover) for other expanders. 1194 scif_sas_domain_continue_discover(fw_device->domain); 1195 } 1196 } 1197 else if (fw_device->protocol_device.smp_device.current_activity == 1198 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAN_ROUTE_TABLE) 1199 { 1200 scif_sas_smp_remote_device_clean_route_table(fw_device); 1201 } 1202 else if (fw_device->protocol_device.smp_device.current_activity == 1203 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAR_AFFILIATION) 1204 { 1205 scif_sas_smp_remote_device_continue_clear_affiliation(fw_device); 1206 } 1207 } 1208 1209 1210 /** 1211 * @brief This method continues the smp Discover process. 1212 * 1213 * @param[in] fw_device The framework smp device that a DISCOVER command 1214 * targets to. 1215 * 1216 * @return none 1217 */ 1218 void scif_sas_smp_remote_device_continue_discover( 1219 SCIF_SAS_REMOTE_DEVICE_T * fw_device 1220 ) 1221 { 1222 SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain; 1223 1224 SCIF_LOG_TRACE(( 1225 sci_base_object_get_logger(fw_device), 1226 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 1227 "scif_sas_smp_remote_device_continue_discover(0x%x) enter\n", 1228 fw_device 1229 )); 1230 1231 switch (fw_device->protocol_device.smp_device.current_smp_request) 1232 { 1233 case SMP_FUNCTION_REPORT_GENERAL: 1234 // send the REPORT MANUFACTURER_INFO request 1235 fw_device->protocol_device.smp_device.current_smp_request = 1236 SMP_FUNCTION_REPORT_MANUFACTURER_INFORMATION; 1237 1238 scif_sas_smp_request_construct_report_manufacturer_info( 1239 fw_domain->controller, fw_device 1240 ); 1241 1242 break; 1243 1244 case SMP_FUNCTION_REPORT_MANUFACTURER_INFORMATION: 1245 //send the first SMP DISCOVER request. 1246 fw_device->protocol_device.smp_device.current_activity_phy_index = 0; 1247 fw_device->protocol_device.smp_device.current_smp_request = 1248 SMP_FUNCTION_DISCOVER; 1249 1250 scif_sas_smp_request_construct_discover( 1251 fw_domain->controller, 1252 fw_device, 1253 fw_device->protocol_device.smp_device.current_activity_phy_index, 1254 NULL, NULL 1255 ); 1256 break; 1257 1258 1259 case SMP_FUNCTION_DISCOVER: 1260 fw_device->protocol_device.smp_device.current_activity_phy_index++; 1261 1262 if ( (fw_device->protocol_device.smp_device.current_activity_phy_index < 1263 fw_device->protocol_device.smp_device.number_of_phys) ) 1264 { 1265 scif_sas_smp_request_construct_discover( 1266 fw_domain->controller, 1267 fw_device, 1268 fw_device->protocol_device.smp_device.current_activity_phy_index, 1269 NULL, NULL 1270 ); 1271 } 1272 else 1273 scif_sas_smp_remote_device_finish_initial_discover(fw_device); 1274 break; 1275 1276 1277 case SMP_FUNCTION_REPORT_PHY_SATA: 1278 scif_sas_smp_request_construct_report_phy_sata( 1279 fw_device->domain->controller, 1280 fw_device, 1281 fw_device->protocol_device.smp_device.current_activity_phy_index 1282 ); 1283 1284 break; 1285 1286 1287 case SMP_FUNCTION_PHY_CONTROL: 1288 scif_sas_smp_request_construct_phy_control( 1289 fw_device->domain->controller, 1290 fw_device, 1291 PHY_OPERATION_HARD_RESET, 1292 fw_device->protocol_device.smp_device.current_activity_phy_index, 1293 NULL, 1294 NULL 1295 ); 1296 1297 break; 1298 1299 default: 1300 break; 1301 } 1302 } 1303 1304 /** 1305 * @brief This method finishes the initial smp DISCOVER process. There 1306 * may be a spinup_hold release phase following of initial discover, 1307 * depending on whether there are SATA device in the domain 1308 * in SATA_SPINUP_HOLD condition. 1309 * 1310 * @param[in] fw_device The framework smp device that finishes all the 1311 * DISCOVER requests. 1312 * 1313 * @return none 1314 */ 1315 void scif_sas_smp_remote_device_finish_initial_discover( 1316 SCIF_SAS_REMOTE_DEVICE_T * fw_device 1317 ) 1318 { 1319 SCIF_SAS_REMOTE_DEVICE_T * device_in_sata_spinup_hold = 1320 scif_sas_domain_find_device_in_spinup_hold(fw_device->domain); 1321 1322 SCIF_LOG_TRACE(( 1323 sci_base_object_get_logger(fw_device), 1324 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 1325 "scif_sas_smp_remote_device_finish_initial_discover(0x%x) enter\n", 1326 fw_device 1327 )); 1328 1329 if ( device_in_sata_spinup_hold != NULL ) 1330 { 1331 //call the common private routine to reset all fields of this smp device. 1332 scif_sas_smp_remote_device_clear(fw_device); 1333 1334 //Move on to next activity SPINUP_HOLD_RELEASE 1335 fw_device->protocol_device.smp_device.current_activity = 1336 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_SATA_SPINUP_HOLD_RELEASE; 1337 1338 //create the timer to delay a little bit before going to 1339 //sata spinup hold release activity. 1340 if (fw_device->protocol_device.smp_device.smp_activity_timer == NULL) 1341 { 1342 fw_device->protocol_device.smp_device.smp_activity_timer = 1343 scif_cb_timer_create( 1344 (SCI_CONTROLLER_HANDLE_T *)fw_device->domain->controller, 1345 (SCI_TIMER_CALLBACK_T)scif_sas_smp_remote_device_sata_spinup_hold_release, 1346 (void*)fw_device 1347 ); 1348 } 1349 else 1350 { 1351 ASSERT (0); 1352 } 1353 1354 scif_cb_timer_start( 1355 (SCI_CONTROLLER_HANDLE_T)fw_device->domain->controller, 1356 fw_device->protocol_device.smp_device.smp_activity_timer, 1357 SMP_SPINUP_HOLD_RELEASE_WAIT_DURATION 1358 ); 1359 } 1360 else 1361 scif_sas_smp_remote_device_finish_discover(fw_device); 1362 } 1363 1364 1365 /** 1366 * @brief This method finishes the smp DISCOVER process. 1367 * 1368 * @param[in] fw_device The framework smp device that finishes all the 1369 * DISCOVER requests. 1370 * 1371 * @return none 1372 */ 1373 void scif_sas_smp_remote_device_finish_discover( 1374 SCIF_SAS_REMOTE_DEVICE_T * fw_device 1375 ) 1376 { 1377 SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain; 1378 1379 SCIF_LOG_TRACE(( 1380 sci_base_object_get_logger(fw_device), 1381 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 1382 "scif_sas_smp_remote_device_finish_discover(0x%x) enter\n", 1383 fw_device 1384 )); 1385 1386 if ( fw_domain->is_config_route_table_needed 1387 && fw_device->protocol_device.smp_device.smp_phy_list.list_head != NULL) 1388 scif_sas_smp_remote_device_configure_upstream_expander_route_info(fw_device); 1389 1390 //call the common private routine to reset all fields of this smp device. 1391 scif_sas_smp_remote_device_clear(fw_device); 1392 1393 #ifdef SCI_SMP_PHY_LIST_DEBUG_PRINT 1394 scif_sas_smp_remote_device_print_smp_phy_list(fw_device); 1395 #endif 1396 1397 //notify domain this smp device's discover finishes, it's up to domain 1398 //to continue the discover process in a bigger scope. 1399 scif_sas_domain_continue_discover(fw_domain); 1400 } 1401 1402 1403 /** 1404 * @brief This method continues the smp Target Reset (Phy Control) process. 1405 * 1406 * @param[in] fw_device The framework smp device that a smp reset targets to. 1407 * 1408 * @return none 1409 */ 1410 void scif_sas_smp_remote_device_continue_target_reset( 1411 SCIF_SAS_REMOTE_DEVICE_T * fw_device, 1412 SCIF_SAS_REQUEST_T * fw_request 1413 ) 1414 { 1415 SCIF_SAS_CONTROLLER_T * fw_controller = fw_device->domain->controller; 1416 SCIF_SAS_REMOTE_DEVICE_T * target_device = 1417 scif_sas_domain_get_device_by_containing_device( 1418 fw_device->domain, 1419 fw_device, 1420 fw_device->protocol_device.smp_device.current_activity_phy_index 1421 ); 1422 1423 SCIF_LOG_TRACE(( 1424 sci_base_object_get_logger(fw_device), 1425 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 1426 "scif_sas_smp_remote_device_continue_target_reset(0x%x, 0x%x) enter\n", 1427 fw_device, fw_request 1428 )); 1429 1430 if (fw_device->protocol_device.smp_device.current_smp_request == 1431 SMP_FUNCTION_PHY_CONTROL) 1432 { 1433 //query the core remote device to get suggested reset timeout value 1434 //then scale down by factor of 8 to get the duration of the pause 1435 //before sending out Discover command to poll. 1436 U32 delay = 1437 (scic_remote_device_get_suggested_reset_timeout(target_device->core_object)/8); 1438 1439 //create the timer to send Discover command polling target device's 1440 //coming back. 1441 if (fw_device->protocol_device.smp_device.smp_activity_timer == NULL) 1442 { 1443 fw_device->protocol_device.smp_device.smp_activity_timer = 1444 scif_cb_timer_create( 1445 (SCI_CONTROLLER_HANDLE_T *)fw_controller, 1446 (SCI_TIMER_CALLBACK_T)scif_sas_smp_remote_device_target_reset_poll, 1447 (void*)fw_request 1448 ); 1449 } 1450 else 1451 { 1452 ASSERT(0); 1453 } 1454 1455 //start the timer 1456 scif_cb_timer_start( 1457 (SCI_CONTROLLER_HANDLE_T)fw_controller, 1458 fw_device->protocol_device.smp_device.smp_activity_timer, 1459 delay 1460 ); 1461 } 1462 else if (fw_device->protocol_device.smp_device.current_smp_request == 1463 SMP_FUNCTION_DISCOVER) 1464 { 1465 //tell target reset successful 1466 scif_sas_remote_device_target_reset_complete( 1467 target_device, fw_request, SCI_SUCCESS); 1468 } 1469 } 1470 1471 /** 1472 * @brief This routine is invoked by timer or when 2 BCN are received 1473 * after Phy Control command. This routine will construct a 1474 * Discover command to the same expander phy to poll the target 1475 * device's coming back. This new request is then put into 1476 * high priority queue and will be started by a DPC soon. 1477 * 1478 * @param[in] fw_request The scif request for smp activities. 1479 */ 1480 void scif_sas_smp_remote_device_target_reset_poll( 1481 SCIF_SAS_REQUEST_T * fw_request 1482 ) 1483 { 1484 SCIF_SAS_REMOTE_DEVICE_T * fw_device = fw_request->device; 1485 SCIF_SAS_CONTROLLER_T * fw_controller = fw_device->domain->controller; 1486 void * new_command_handle; 1487 1488 SCIF_LOG_TRACE(( 1489 sci_base_object_get_logger(fw_device), 1490 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 1491 "scif_sas_smp_remote_device_target_reset_poll(0x%x) enter\n", 1492 fw_request 1493 )); 1494 1495 // Before we construct new io using the same memory, we need to 1496 // remove the IO from the list of outstanding requests on the domain 1497 // so that we don't damage the domain's fast list of request. 1498 sci_fast_list_remove_element(&fw_request->list_element); 1499 1500 fw_device->protocol_device.smp_device.current_smp_request = 1501 SMP_FUNCTION_DISCOVER; 1502 1503 //sent smp discover request to poll on remote device's coming back. 1504 //construct Discover command using the same memory as fw_request. 1505 new_command_handle = scif_sas_smp_request_construct_discover( 1506 fw_device->domain->controller, 1507 fw_device, 1508 fw_device->protocol_device.smp_device.current_activity_phy_index, 1509 (void *)sci_object_get_association(fw_request), 1510 (void *)fw_request 1511 ); 1512 1513 //put into the high priority queue. 1514 sci_pool_put(fw_controller->hprq.pool, (POINTER_UINT) new_command_handle); 1515 1516 //schedule the DPC to start new Discover command. 1517 scif_cb_start_internal_io_task_schedule( 1518 fw_controller, scif_sas_controller_start_high_priority_io, fw_controller 1519 ); 1520 } 1521 1522 1523 /** 1524 * @brief This method fails discover process. 1525 * 1526 * @param[in] fw_device The framework smp device that failed at current 1527 * activity. 1528 * 1529 * @return none 1530 */ 1531 void scif_sas_smp_remote_device_fail_discover( 1532 SCIF_SAS_REMOTE_DEVICE_T * fw_device 1533 ) 1534 { 1535 SCIF_LOG_TRACE(( 1536 sci_base_object_get_logger(fw_device), 1537 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 1538 "scif_sas_smp_remote_device_fail_discover(0x%x) enter\n", 1539 fw_device 1540 )); 1541 1542 switch (fw_device->protocol_device.smp_device.current_smp_request) 1543 { 1544 case SMP_FUNCTION_REPORT_GENERAL: 1545 case SMP_FUNCTION_REPORT_MANUFACTURER_INFORMATION: 1546 scif_sas_smp_remote_device_finish_discover(fw_device); 1547 break; 1548 1549 case SMP_FUNCTION_DISCOVER: 1550 case SMP_FUNCTION_REPORT_PHY_SATA: 1551 //Retry limit reached, we will continue to send DISCOVER to next phy. 1552 fw_device->protocol_device.smp_device.current_smp_request = 1553 SMP_FUNCTION_DISCOVER; 1554 1555 scif_sas_smp_remote_device_continue_discover(fw_device); 1556 break; 1557 1558 default: 1559 break; 1560 } 1561 } 1562 1563 1564 /** 1565 * @brief This method fails Target Reset. 1566 * 1567 * @param[in] fw_device The framework smp device that failed at current 1568 * activity. 1569 * @param[in] fw_request The smp request created for target reset 1570 * using external resource. 1571 * 1572 * @return none 1573 */ 1574 void scif_sas_smp_remote_device_fail_target_reset( 1575 SCIF_SAS_REMOTE_DEVICE_T * fw_device, 1576 SCIF_SAS_REQUEST_T * fw_request 1577 ) 1578 { 1579 SCIF_SAS_REMOTE_DEVICE_T * target_device = 1580 scif_sas_domain_get_device_by_containing_device( 1581 fw_device->domain, 1582 fw_device, 1583 fw_device->protocol_device.smp_device.current_activity_phy_index 1584 ); 1585 1586 SCIF_LOG_TRACE(( 1587 sci_base_object_get_logger(fw_device), 1588 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 1589 "scif_sas_smp_remote_device_fail_target_reset(0x%x, 0x%x, 0x%x) enter\n", 1590 fw_device, target_device, fw_request 1591 )); 1592 1593 //tell target reset failed 1594 scif_sas_remote_device_target_reset_complete( 1595 target_device, fw_request, SCI_FAILURE); 1596 } 1597 1598 /** 1599 * @brief This method init or continue the SATA SPINUP_HOLD RELEASE activity. 1600 * This function searches domain's device list, find a device in STOPPED STATE 1601 * and its connection_rate is SPINIP, then send DISCOVER command to its expander 1602 * phy id to poll. But if searching the domain's device list for SATA devices on 1603 * SPINUP_HOLD finds no device, the activity SPINUP_HOLD_RELEASE is finished. 1604 * We then call fw_domain->device_start_complete_handler() for this smp-device. 1605 * 1606 * @param[in] fw_device The framework smp device that is on SATA SPINUP_HOLD_RELEASE 1607 * activity. 1608 * 1609 * @return none 1610 */ 1611 void scif_sas_smp_remote_device_sata_spinup_hold_release( 1612 SCIF_SAS_REMOTE_DEVICE_T * fw_device 1613 ) 1614 { 1615 SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain; 1616 SCIF_SAS_CONTROLLER_T * fw_controller = fw_domain->controller; 1617 SCIF_SAS_REMOTE_DEVICE_T * device_to_poll = NULL; 1618 1619 SCIF_LOG_TRACE(( 1620 sci_base_object_get_logger(fw_device), 1621 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 1622 "scif_sas_smp_remote_device_sata_spinup_hold_release(0x%x) enter\n", 1623 fw_device 1624 )); 1625 1626 //search throught domain's device list to find a sata device on spinup_hold 1627 //state to poll. 1628 device_to_poll = scif_sas_domain_find_device_in_spinup_hold(fw_domain); 1629 1630 if (device_to_poll != NULL) 1631 { 1632 //send DISCOVER command to this device's expaner phy. 1633 fw_device->protocol_device.smp_device.current_smp_request = 1634 SMP_FUNCTION_DISCOVER; 1635 1636 fw_device->protocol_device.smp_device.current_activity_phy_index = 1637 device_to_poll->expander_phy_identifier; 1638 1639 scif_sas_smp_request_construct_discover( 1640 fw_domain->controller, 1641 fw_device, 1642 fw_device->protocol_device.smp_device.current_activity_phy_index, 1643 NULL, NULL 1644 ); 1645 1646 //schedule the DPC to start new Discover command. 1647 scif_cb_start_internal_io_task_schedule( 1648 fw_controller, scif_sas_controller_start_high_priority_io, fw_controller 1649 ); 1650 } 1651 else //SATA SPINUP HOLD RELEASE activity is done. 1652 scif_sas_smp_remote_device_finish_discover (fw_device); 1653 } 1654 1655 1656 /** 1657 * @brief This method fail an action of SATA SPINUP_HOLD RELEASE on a single EA 1658 * SATA device. It will remove a remote_device object for a sata device 1659 * that fails to come out of spinup_hold. 1660 * 1661 * @param[in] fw_device The framework smp device that is on SATA SPINUP_HOLD_RELEASE 1662 * activity. 1663 * @param[in] target_device The expander attached device failed being brought out 1664 * of SPINUP_HOLD state. 1665 * 1666 * @return none 1667 */ 1668 void scif_sas_smp_remote_device_fail_target_spinup_hold_release( 1669 SCIF_SAS_REMOTE_DEVICE_T * fw_device, 1670 SCIF_SAS_REMOTE_DEVICE_T * target_device 1671 ) 1672 { 1673 SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain; 1674 1675 SCIF_LOG_TRACE(( 1676 sci_base_object_get_logger(fw_device), 1677 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 1678 "scif_sas_smp_remote_device_fail_target_spinup_hold_release(0x%x, 0x%x) enter\n", 1679 fw_device, target_device 1680 )); 1681 1682 //need to remove the device, since we have to give up on spinup_hold_release 1683 //activity on this device. 1684 scif_cb_domain_device_removed( 1685 fw_domain->controller, fw_domain, target_device 1686 ); 1687 1688 //move on to next round of SPINUP_HOLD_REALSE activity. 1689 scif_sas_smp_remote_device_sata_spinup_hold_release(fw_device); 1690 } 1691 1692 1693 /** 1694 * @brief This method retry only internal IO for the smp device. 1695 * 1696 * @param[in] fw_device The framework smp device that has an smp request to retry. 1697 * @param[in] io_retry_count current count for times the IO being retried. 1698 * @param[in] delay The time delay before the io gets retried. 1699 * 1700 * @return none 1701 */ 1702 void scif_sas_smp_remote_device_retry_internal_io( 1703 SCIF_SAS_REMOTE_DEVICE_T * fw_device, 1704 U8 io_retry_count, 1705 U32 delay 1706 ) 1707 { 1708 SCIF_LOG_TRACE(( 1709 sci_base_object_get_logger(fw_device), 1710 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 1711 "scif_sas_smp_remote_device_retry_internal_io(0x%x, 0x%x, 0x%x) enter\n", 1712 fw_device, io_retry_count, delay 1713 )); 1714 1715 fw_device->protocol_device.smp_device.io_retry_count = 1716 io_retry_count; 1717 1718 //create the timer for poll target device's coming back. 1719 if (fw_device->protocol_device.smp_device.smp_activity_timer == NULL) 1720 { 1721 fw_device->protocol_device.smp_device.smp_activity_timer = 1722 scif_cb_timer_create( 1723 (SCI_CONTROLLER_HANDLE_T *)fw_device->domain->controller, 1724 (SCI_TIMER_CALLBACK_T)scif_sas_smp_internal_request_retry, 1725 (void*)fw_device 1726 ); 1727 } 1728 else 1729 { 1730 ASSERT(0); 1731 } 1732 //start the timer for a purpose of waiting. 1733 scif_cb_timer_start( 1734 (SCI_CONTROLLER_HANDLE_T)fw_device->domain->controller, 1735 fw_device->protocol_device.smp_device.smp_activity_timer, 1736 delay 1737 ); 1738 } 1739 1740 1741 /** 1742 * @brief This method indicates whether an expander device is in Discover 1743 * process. 1744 * 1745 * @param[in] fw_device The framework smp device. 1746 * 1747 * @return Whether an expander device is in the middle of discovery process. 1748 */ 1749 BOOL scif_sas_smp_remote_device_is_in_activity( 1750 SCIF_SAS_REMOTE_DEVICE_T * fw_device 1751 ) 1752 { 1753 return(fw_device->protocol_device.smp_device.current_activity 1754 != SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE); 1755 } 1756 1757 /** 1758 * @brief This method search through the smp phy list of an expander to 1759 * find a smp phy by its phy id of the expander. 1760 * 1761 * @param[in] phy_identifier The search criteria. 1762 * @param[in] smp_remote_device The expander that owns the smp phy list. 1763 * 1764 * @return The found smp phy or a NULL pointer to indicate no smp phy is found. 1765 */ 1766 SCIF_SAS_SMP_PHY_T * scif_sas_smp_remote_device_find_smp_phy_by_id( 1767 U8 phy_identifier, 1768 SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device 1769 ) 1770 { 1771 SCI_FAST_LIST_ELEMENT_T * element = smp_remote_device->smp_phy_list.list_head; 1772 SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL; 1773 1774 ASSERT(phy_identifier < smp_remote_device->smp_phy_list.number_of_phys); 1775 1776 while (element != NULL) 1777 { 1778 curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element); 1779 element = sci_fast_list_get_next(element); 1780 1781 if (curr_smp_phy->phy_identifier == phy_identifier) 1782 return curr_smp_phy; 1783 } 1784 1785 return NULL; 1786 } 1787 1788 /** 1789 * @brief This method takes care of removing smp phy list of a smp devcie, which is 1790 * about to be removed. 1791 * 1792 * @param[in] fw_device The expander device that is about to be removed. 1793 * 1794 * @return none. 1795 */ 1796 void scif_sas_smp_remote_device_removed( 1797 SCIF_SAS_REMOTE_DEVICE_T * this_device 1798 ) 1799 { 1800 SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device = 1801 &this_device->protocol_device.smp_device; 1802 1803 SCI_FAST_LIST_ELEMENT_T * element = smp_remote_device->smp_phy_list.list_head; 1804 SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL; 1805 1806 SCIF_LOG_TRACE(( 1807 sci_base_object_get_logger(this_device), 1808 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 1809 "scif_sas_smp_remote_device_removed(0x%x) enter\n", 1810 this_device 1811 )); 1812 1813 //remove all the smp phys in this device's smp_phy_list, and the conterpart smp phys 1814 //in phy connections. 1815 while (element != NULL) 1816 { 1817 curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element); 1818 element = sci_fast_list_get_next(element); 1819 1820 scif_sas_smp_phy_destruct(curr_smp_phy); 1821 } 1822 1823 this_device->protocol_device.smp_device.number_of_phys = 0; 1824 this_device->protocol_device.smp_device.expander_route_indexes = 0; 1825 this_device->protocol_device.smp_device.is_table_to_table_supported = FALSE; 1826 this_device->protocol_device.smp_device.is_externally_configurable = FALSE; 1827 this_device->protocol_device.smp_device.is_able_to_config_others = FALSE; 1828 1829 scif_sas_smp_remote_device_clear(this_device); 1830 } 1831 1832 1833 /** 1834 * @brief This method takes care of terminated smp request to a smp device. The 1835 * terminated smp request is most likely timeout and being aborted. A timeout 1836 * maybe due to OPEN REJECT (NO DESTINATION). 1837 * 1838 * @param[in] fw_device The expander device that a timed out smp request towards to. 1839 * @param[in] fw_request A failed smp request that is terminated by scic. 1840 * 1841 * @return none. 1842 */ 1843 void scif_sas_smp_remote_device_terminated_request_handler( 1844 SCIF_SAS_REMOTE_DEVICE_T * fw_device, 1845 SCIF_SAS_REQUEST_T * fw_request 1846 ) 1847 { 1848 SCIF_LOG_TRACE(( 1849 sci_base_object_get_logger(fw_device), 1850 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 1851 "scif_sas_smp_remote_device_terminated_request_handler(0x%x, 0x%x) enter\n", 1852 fw_device, fw_request 1853 )); 1854 1855 scif_sas_smp_remote_device_decode_smp_response( 1856 fw_device, fw_request, NULL, SCI_IO_FAILURE_RETRY_REQUIRED 1857 ); 1858 } 1859 1860 1861 /** 1862 * @brief This method allocates and populates the smp phy list of a expander device. 1863 * 1864 * @param[in] fw_device The expander device, whose smp phy list is to be populated after 1865 * getting REPORT GENERAL response. 1866 * 1867 * @return none. 1868 */ 1869 void scif_sas_smp_remote_device_populate_smp_phy_list( 1870 SCIF_SAS_REMOTE_DEVICE_T * fw_device 1871 ) 1872 { 1873 SCIF_SAS_SMP_PHY_T * this_smp_phy = NULL; 1874 U8 expander_phy_id = 0; 1875 1876 SCIF_LOG_TRACE(( 1877 sci_base_object_get_logger(fw_device), 1878 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 1879 "scif_sas_smp_remote_device_populate_smp_phy_list(0x%x) enter\n", 1880 fw_device 1881 )); 1882 1883 for ( expander_phy_id = 0; 1884 expander_phy_id < fw_device->protocol_device.smp_device.number_of_phys; 1885 expander_phy_id++ ) 1886 { 1887 this_smp_phy = 1888 scif_sas_controller_allocate_smp_phy(fw_device->domain->controller); 1889 1890 ASSERT( this_smp_phy != NULL ); 1891 1892 if ( this_smp_phy != NULL ) 1893 scif_sas_smp_phy_construct(this_smp_phy, fw_device, expander_phy_id); 1894 } 1895 } 1896 1897 1898 /** 1899 * @brief This method updates a smp phy of a expander device based on DISCOVER response. 1900 * 1901 * @param[in] fw_device The expander device, one of whose smp phys is to be updated. 1902 * @param[in] discover_response The smp DISCOVER response. 1903 * 1904 * @return SCI_STATUS If a smp phy pair between expanders has invalid routing attribute, 1905 * return SCI_FAILURE_ILLEGAL_ROUTING_ATTRIBUTE_CONFIGURATION, otherwise, 1906 * return SCI_SUCCESS 1907 */ 1908 SCI_STATUS scif_sas_smp_remote_device_save_smp_phy_info( 1909 SCIF_SAS_REMOTE_DEVICE_T * fw_device, 1910 SMP_RESPONSE_DISCOVER_T * discover_response 1911 ) 1912 { 1913 SCI_STATUS status = SCI_SUCCESS; 1914 SCIF_SAS_SMP_PHY_T * smp_phy = NULL; 1915 SCIF_SAS_REMOTE_DEVICE_T * attached_device = NULL; 1916 1917 SCIF_LOG_TRACE(( 1918 sci_base_object_get_logger(fw_device), 1919 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 1920 "scif_sas_smp_remote_device_save_smp_phy_info(0x%x, 0x%x) enter\n", 1921 fw_device, discover_response 1922 )); 1923 1924 smp_phy = scif_sas_smp_remote_device_find_smp_phy_by_id( 1925 discover_response->phy_identifier, 1926 &fw_device->protocol_device.smp_device 1927 ); 1928 1929 ASSERT( smp_phy != NULL ); 1930 1931 //Note, attached_device could be NULL, not all the smp phy have to connected to a device. 1932 attached_device = (SCIF_SAS_REMOTE_DEVICE_T *) 1933 scif_domain_get_device_by_sas_address( 1934 fw_device->domain, &discover_response->attached_sas_address); 1935 1936 scif_sas_smp_phy_save_information( 1937 smp_phy, attached_device, discover_response); 1938 1939 //handle the special case of smp phys between expanders. 1940 if ( discover_response->protocols.u.bits.attached_smp_target ) 1941 { 1942 //this fw_device is a child expander, just found its parent expander. 1943 //And there is no smp_phy constructed yet, record this phy connection. 1944 if ( attached_device != NULL 1945 && attached_device == fw_device->containing_device ) 1946 { 1947 //record the smp phy info, for this phy connects to a upstream smp device. 1948 //the connection of a pair of smp phys are completed. 1949 status = scif_sas_smp_phy_set_attached_phy( 1950 smp_phy, 1951 discover_response->attached_phy_identifier, 1952 attached_device 1953 ); 1954 1955 if (status == SCI_SUCCESS) 1956 { 1957 //check the routing attribute for this phy and its containing device's 1958 //expander_phy_routing_attribute. 1959 if ( scif_sas_smp_phy_verify_routing_attribute( 1960 smp_phy, smp_phy->u.attached_phy) != SCI_SUCCESS ) 1961 return SCI_FAILURE_ILLEGAL_ROUTING_ATTRIBUTE_CONFIGURATION; 1962 } 1963 } 1964 } 1965 1966 return status; 1967 } 1968 1969 #ifdef SCI_SMP_PHY_LIST_DEBUG_PRINT 1970 void scif_sas_smp_remote_device_print_smp_phy_list( 1971 SCIF_SAS_REMOTE_DEVICE_T * fw_device 1972 ) 1973 { 1974 SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device = &fw_device->protocol_device.smp_device; 1975 SCI_FAST_LIST_ELEMENT_T * element = smp_remote_device->smp_phy_list.list_head; 1976 SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL; 1977 1978 SCIF_LOG_ERROR(( 1979 sci_base_object_get_logger(fw_device), 1980 SCIF_LOG_OBJECT_REMOTE_DEVICE, 1981 "==========EXPANDER DEVICE (0x%x) smp phy list========== \n", 1982 fw_device 1983 )); 1984 1985 while (element != NULL) 1986 { 1987 curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element); 1988 element = sci_fast_list_get_next(element); 1989 1990 //print every thing about a smp phy 1991 SCIF_LOG_ERROR(( 1992 sci_base_object_get_logger(fw_device), 1993 SCIF_LOG_OBJECT_REMOTE_DEVICE, 1994 "SMP_PHY_%d (0x%x), attached device(0x%x), attached_sas_address(%x%x) attached_device_type(%d), routing_attribute(%d)\n", 1995 curr_smp_phy->phy_identifier, curr_smp_phy, 1996 curr_smp_phy->u.end_device, 1997 curr_smp_phy->attached_sas_address.high, curr_smp_phy->attached_sas_address.low, 1998 curr_smp_phy->attached_device_type, 1999 curr_smp_phy->routing_attribute 2000 )); 2001 } 2002 } 2003 #endif 2004 2005 2006 /** 2007 * @brief This method configure upstream expander(s)' (if there is any) route info. 2008 * 2009 * @param[in] this_device The expander device that is currently in discover process. 2010 * 2011 * @return none. 2012 */ 2013 void scif_sas_smp_remote_device_configure_upstream_expander_route_info( 2014 SCIF_SAS_REMOTE_DEVICE_T * this_device 2015 ) 2016 { 2017 SCIF_SAS_REMOTE_DEVICE_T * curr_child_expander = this_device; 2018 SCIF_SAS_REMOTE_DEVICE_T * curr_parent_expander = 2019 scif_sas_remote_device_find_upstream_expander(this_device); 2020 2021 SCIF_SAS_REMOTE_DEVICE_T * curr_config_route_info_expander = NULL; 2022 2023 SCIF_LOG_TRACE(( 2024 sci_base_object_get_logger(this_device), 2025 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 2026 "scif_sas_smp_remote_device_configure_upstream_expander_route_info(0x%x) enter\n", 2027 this_device 2028 )); 2029 2030 //traverse back to find root device. 2031 while(curr_parent_expander != NULL ) 2032 { 2033 //must set destination_smp_phy outside of find_upstream_expander() using the device 2034 //that is just about to finish the discovery. 2035 curr_parent_expander->protocol_device.smp_device.curr_config_route_destination_smp_phy = 2036 (SCIF_SAS_SMP_PHY_T*)sci_fast_list_get_object( 2037 this_device->protocol_device.smp_device.smp_phy_list.list_head); 2038 2039 curr_child_expander = curr_parent_expander; 2040 curr_parent_expander = scif_sas_remote_device_find_upstream_expander(curr_child_expander); 2041 } 2042 2043 //found the root device: curr_child_expander. configure it and its downstream expander(s) till 2044 //this_device or a self-configuring expander that configures others; 2045 curr_config_route_info_expander = curr_child_expander; 2046 2047 while ( curr_config_route_info_expander != NULL 2048 && curr_config_route_info_expander != this_device 2049 && curr_config_route_info_expander->protocol_device.smp_device.scheduled_activity 2050 == SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE 2051 ) 2052 { 2053 if (curr_config_route_info_expander->protocol_device.smp_device.is_externally_configurable) 2054 { 2055 SCIF_SAS_SMP_PHY_T * phy_being_config = 2056 curr_config_route_info_expander->protocol_device.smp_device.config_route_smp_phy_anchor; 2057 2058 curr_config_route_info_expander->protocol_device.smp_device.curr_config_route_index = 2059 phy_being_config->config_route_table_index_anchor; 2060 2061 if (curr_config_route_info_expander->protocol_device.smp_device.curr_config_route_index != 0) 2062 curr_config_route_info_expander->protocol_device.smp_device.curr_config_route_index++; 2063 2064 curr_config_route_info_expander->protocol_device.smp_device.scheduled_activity = 2065 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE; 2066 2067 //Find a downstream expander that has curr_config_route_destination_smp_phy.owning device 2068 //same as curr_config_route_info_expander. 2069 curr_config_route_info_expander = scif_sas_remote_device_find_downstream_expander( 2070 curr_config_route_info_expander); 2071 } 2072 else if (curr_config_route_info_expander->protocol_device.smp_device.is_able_to_config_others) 2073 { 2074 //no need to config route table to this expander and its children. 2075 //find its downstream expander and clear the planned config route table activity. 2076 SCIF_SAS_REMOTE_DEVICE_T * curr_downstream_expander = 2077 scif_sas_remote_device_find_downstream_expander( 2078 curr_config_route_info_expander); 2079 2080 scif_sas_smp_remote_device_clear(curr_config_route_info_expander); 2081 2082 while ( curr_downstream_expander != NULL 2083 && curr_downstream_expander != this_device ) 2084 { 2085 scif_sas_smp_remote_device_clear(curr_downstream_expander); 2086 curr_downstream_expander = 2087 scif_sas_remote_device_find_downstream_expander( 2088 curr_config_route_info_expander); 2089 } 2090 2091 break; 2092 } 2093 else 2094 { 2095 // current expander is a self-configuring expander, which is not externally 2096 // configurable, and doesn't config others. we need to simply skip this expander. 2097 curr_config_route_info_expander = scif_sas_remote_device_find_downstream_expander( 2098 curr_config_route_info_expander); 2099 } 2100 } 2101 } 2102 2103 /** 2104 * @brief This method finds the immediate upstream expander of a given expander device. 2105 * 2106 * @param[in] this_device The given expander device, whose upstream expander is to be found. 2107 * 2108 * @return The immediate upstream expander. Or a NULL pointer if this_device is root already. 2109 */ 2110 SCIF_SAS_REMOTE_DEVICE_T * scif_sas_remote_device_find_upstream_expander( 2111 SCIF_SAS_REMOTE_DEVICE_T * this_device 2112 ) 2113 { 2114 SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device = 2115 &this_device->protocol_device.smp_device; 2116 2117 SCIF_SAS_REMOTE_DEVICE_T * upstream_expander = NULL; 2118 2119 SCI_FAST_LIST_ELEMENT_T * element = smp_remote_device->smp_phy_list.list_head; 2120 SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL; 2121 2122 SCIF_LOG_TRACE(( 2123 sci_base_object_get_logger(this_device), 2124 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 2125 "scif_sas_smp_remote_device_configure_upstream_expander_route_info(0x%x) enter\n", 2126 this_device 2127 )); 2128 2129 while (element != NULL) 2130 { 2131 curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element); 2132 element = sci_fast_list_get_next(element); 2133 2134 if ( curr_smp_phy->routing_attribute == SUBTRACTIVE_ROUTING_ATTRIBUTE 2135 && ( curr_smp_phy->attached_device_type == SMP_EDGE_EXPANDER_DEVICE 2136 || curr_smp_phy->attached_device_type == SMP_FANOUT_EXPANDER_DEVICE) 2137 && curr_smp_phy->u.attached_phy != NULL 2138 && curr_smp_phy->u.attached_phy->routing_attribute == TABLE_ROUTING_ATTRIBUTE ) 2139 { 2140 //set the current_activity and current_config_route_index for that 2141 //upstream expander. 2142 upstream_expander = curr_smp_phy->u.attached_phy->owning_device; 2143 2144 upstream_expander->protocol_device.smp_device.current_smp_request = 2145 SMP_FUNCTION_CONFIGURE_ROUTE_INFORMATION; 2146 2147 //if the upstream_expander's config route table method is config phy0 only or 2148 //config all phys, the current activity phy is found. 2149 upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor = 2150 scif_sas_smp_remote_device_find_smp_phy_by_id( 2151 curr_smp_phy->u.attached_phy->phy_identifier, 2152 &(curr_smp_phy->u.attached_phy->owning_device->protocol_device.smp_device) 2153 ); 2154 2155 //if the upstream_expander's config route table method is config middle phy only 2156 //config highest phy only, the current activity phy needs a update. 2157 if ( scif_sas_smp_remote_device_get_config_route_table_method(upstream_expander) 2158 == SCIF_SAS_CONFIG_ROUTE_TABLE_MIDDLE_PHY_ONLY ) 2159 { 2160 upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor = 2161 scif_sas_smp_phy_find_middle_phy_in_wide_port ( 2162 upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor 2163 ); 2164 } 2165 else if ( scif_sas_smp_remote_device_get_config_route_table_method(upstream_expander) 2166 == SCIF_SAS_CONFIG_ROUTE_TABLE_HIGHEST_PHY_ONLY ) 2167 { 2168 upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor = 2169 scif_sas_smp_phy_find_highest_phy_in_wide_port ( 2170 upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor 2171 ); 2172 } 2173 2174 upstream_expander->protocol_device.smp_device.current_activity_phy_index = 2175 upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor->phy_identifier; 2176 2177 return upstream_expander; 2178 } 2179 } 2180 2181 return NULL; 2182 } 2183 2184 2185 /** 2186 * @brief This method finds the immediate downstream expander of a given expander device. 2187 * 2188 * @param[in] this_device The given expander device, whose downstream expander is to be found. 2189 * 2190 * @return The immediate downstream expander. Or a NULL pointer if there is none. 2191 */ 2192 SCIF_SAS_REMOTE_DEVICE_T * scif_sas_remote_device_find_downstream_expander( 2193 SCIF_SAS_REMOTE_DEVICE_T * this_device 2194 ) 2195 { 2196 SCIF_SAS_SMP_REMOTE_DEVICE_T * this_smp_remote_device = 2197 &this_device->protocol_device.smp_device; 2198 2199 SCIF_SAS_REMOTE_DEVICE_T * downstream_expander = NULL; 2200 2201 SCI_FAST_LIST_ELEMENT_T * element = this_smp_remote_device->smp_phy_list.list_head; 2202 SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL; 2203 2204 SCIF_LOG_TRACE(( 2205 sci_base_object_get_logger(this_device), 2206 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 2207 "scif_sas_remote_device_find_downstream_expander(0x%x) enter\n", 2208 this_device 2209 )); 2210 2211 while (element != NULL) 2212 { 2213 curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element); 2214 element = sci_fast_list_get_next(element); 2215 2216 if ( curr_smp_phy->routing_attribute == TABLE_ROUTING_ATTRIBUTE 2217 && curr_smp_phy->attached_device_type == SMP_EDGE_EXPANDER_DEVICE 2218 && curr_smp_phy->u.attached_phy != NULL) 2219 { 2220 //set the current_activity and current_config_route_index for that 2221 //upstream expander. 2222 downstream_expander = curr_smp_phy->u.attached_phy->owning_device; 2223 2224 if ( downstream_expander->protocol_device.smp_device.curr_config_route_destination_smp_phy != NULL 2225 && downstream_expander->protocol_device.smp_device.curr_config_route_destination_smp_phy->owning_device == 2226 this_smp_remote_device->curr_config_route_destination_smp_phy->owning_device ) 2227 return downstream_expander; 2228 } 2229 } 2230 2231 return NULL; 2232 } 2233 2234 2235 /** 2236 * @brief This method follows route table optimization rule to check if a destination_device 2237 * should be recorded in the device_being_config's route table 2238 * 2239 * @param[in] device_being_config The upstream expander device, whose route table is being configured. 2240 * @param[in] destination_smp_phy A smp phy whose attached device is potentially to be 2241 * recorded in route table. 2242 * 2243 * @return BOOL This method returns TRUE if a destination_device should be recorded in route table. 2244 * This method returns FALSE if a destination_device need not to be recorded 2245 * in route table. 2246 */ 2247 BOOL scif_sas_smp_remote_device_do_config_route_info( 2248 SCIF_SAS_REMOTE_DEVICE_T * device_being_config, 2249 SCIF_SAS_SMP_PHY_T * destination_smp_phy 2250 ) 2251 { 2252 SCI_SAS_ADDRESS_T device_being_config_sas_address; 2253 2254 SCIF_LOG_TRACE(( 2255 sci_base_object_get_logger(device_being_config), 2256 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 2257 "scif_sas_smp_remote_device_do_config_route_info(0x%x, 0x%x) enter\n", 2258 device_being_config, destination_smp_phy 2259 )); 2260 2261 scic_remote_device_get_sas_address( 2262 device_being_config->core_object, &device_being_config_sas_address 2263 ); 2264 2265 //refer to SAS-2 spec 4.8.3, rule (b) 2266 if ((destination_smp_phy->attached_sas_address.low == 0 2267 && destination_smp_phy->attached_sas_address.high == 0) 2268 && (destination_smp_phy->attached_device_type == SMP_NO_DEVICE_ATTACHED)) 2269 { 2270 return FALSE; 2271 } 2272 2273 //refer to SAS-2 spec 4.8.3, rule (c), self-referencing. 2274 if (destination_smp_phy->attached_sas_address.high == 2275 device_being_config_sas_address.high 2276 && destination_smp_phy->attached_sas_address.low == 2277 device_being_config_sas_address.low) 2278 { 2279 return FALSE; 2280 } 2281 2282 //There will be no cases that falling into rule (a), (d), (e) to be excluded, 2283 //based on our current mechanism of cofig route table. 2284 2285 return TRUE; 2286 } 2287 2288 2289 /** 2290 * @brief This method configures device_being_config's route table for all the enclosed devices in 2291 * a downstream smp device, destination_device. 2292 * 2293 * @param[in] device_being_config The upstream expander device, whose route table is being configured. 2294 * 2295 * @return None 2296 */ 2297 void scif_sas_smp_remote_device_configure_route_table( 2298 SCIF_SAS_REMOTE_DEVICE_T * device_being_config 2299 ) 2300 { 2301 //go through the smp phy list of this_device. 2302 SCI_FAST_LIST_ELEMENT_T * element = 2303 &(device_being_config->protocol_device.smp_device.curr_config_route_destination_smp_phy->list_element); 2304 SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL; 2305 2306 SCIF_LOG_TRACE(( 2307 sci_base_object_get_logger(device_being_config), 2308 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 2309 "scif_sas_smp_remote_device_configure_route_table(0x%x) enter\n", 2310 device_being_config 2311 )); 2312 2313 device_being_config->protocol_device.smp_device.current_activity = 2314 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE; 2315 2316 while (element != NULL) 2317 { 2318 curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element); 2319 element = sci_fast_list_get_next(element); 2320 2321 //check if this phy needs to be added to the expander's route table. 2322 if (scif_sas_smp_remote_device_do_config_route_info( 2323 device_being_config, curr_smp_phy) == TRUE ) 2324 { 2325 SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device = 2326 &device_being_config->protocol_device.smp_device; 2327 2328 smp_remote_device->curr_config_route_destination_smp_phy = 2329 curr_smp_phy; 2330 2331 //Then config this_device's route table entry at the phy and next route_index. 2332 //send config_route_info using curr_smp_phy.phy_identifier and sas_address. 2333 scif_sas_smp_request_construct_config_route_info( 2334 device_being_config->domain->controller, 2335 device_being_config, 2336 smp_remote_device->current_activity_phy_index, 2337 smp_remote_device->curr_config_route_index, 2338 curr_smp_phy->attached_sas_address, 2339 FALSE 2340 ); 2341 2342 //schedule the DPC. 2343 scif_cb_start_internal_io_task_schedule( 2344 device_being_config->domain->controller, 2345 scif_sas_controller_start_high_priority_io, 2346 device_being_config->domain->controller 2347 ); 2348 2349 //stop here, we need to wait for config route info's response then send 2350 //the next one. 2351 break; 2352 } 2353 } 2354 } 2355 2356 2357 /** 2358 * @brief This method walks through an expander's route table to clean table 2359 * attribute phys' route entries. This routine finds one table entry 2360 * to clean and will be called repeatly till it finishes cleanning the 2361 * whole table. 2362 * 2363 * @param[in] fw_device The expander device, whose route table entry is to be cleaned. 2364 * 2365 * @return None. 2366 */ 2367 void scif_sas_smp_remote_device_clean_route_table( 2368 SCIF_SAS_REMOTE_DEVICE_T * fw_device 2369 ) 2370 { 2371 SCIF_SAS_SMP_PHY_T * smp_phy_being_config; 2372 2373 SCIF_LOG_TRACE(( 2374 sci_base_object_get_logger(fw_device), 2375 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 2376 "scif_sas_smp_remote_device_clean_route_table(0x%x) enter\n", 2377 fw_device 2378 )); 2379 2380 //from anchors, start to clean all the other route table entries. 2381 fw_device->protocol_device.smp_device.curr_config_route_index++; 2382 2383 if ( fw_device->protocol_device.smp_device.curr_config_route_index >= 2384 fw_device->protocol_device.smp_device.expander_route_indexes ) 2385 { 2386 fw_device->protocol_device.smp_device.curr_config_route_index = 0; 2387 2388 do //find next table attribute PHY. 2389 { 2390 fw_device->protocol_device.smp_device.current_activity_phy_index++; 2391 if (fw_device->protocol_device.smp_device.current_activity_phy_index == 2392 fw_device->protocol_device.smp_device.number_of_phys) 2393 fw_device->protocol_device.smp_device.current_activity_phy_index=0; 2394 2395 //phy_index changed, so update the smp_phy_being_config. 2396 smp_phy_being_config = 2397 scif_sas_smp_remote_device_find_smp_phy_by_id( 2398 fw_device->protocol_device.smp_device.current_activity_phy_index, 2399 &(fw_device->protocol_device.smp_device) 2400 ); 2401 } while( smp_phy_being_config->routing_attribute != TABLE_ROUTING_ATTRIBUTE ); 2402 2403 if ( smp_phy_being_config->phy_identifier != 2404 fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->phy_identifier) 2405 { 2406 if (smp_phy_being_config->config_route_table_index_anchor != 0) 2407 fw_device->protocol_device.smp_device.curr_config_route_index = 2408 smp_phy_being_config->config_route_table_index_anchor + 1; 2409 else 2410 fw_device->protocol_device.smp_device.curr_config_route_index = 0; 2411 } 2412 } 2413 2414 if ( !(fw_device->protocol_device.smp_device.current_activity_phy_index == 2415 fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->phy_identifier 2416 && fw_device->protocol_device.smp_device.curr_config_route_index == 0) 2417 ) 2418 { 2419 //clean this route entry. 2420 scif_sas_smp_remote_device_clean_route_table_entry(fw_device); 2421 } 2422 else 2423 { 2424 fw_device->protocol_device.smp_device.is_route_table_cleaned = TRUE; 2425 2426 //set this device's activity to NON. 2427 fw_device->protocol_device.smp_device.current_activity = 2428 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE; 2429 2430 //we need to notify domain that this device finished config route table, domain 2431 //may pick up other activities (i.e. Discover) for other expanders. 2432 scif_sas_domain_continue_discover(fw_device->domain); 2433 } 2434 } 2435 2436 /** 2437 * @brief This method cleans a device's route table antry. 2438 * 2439 * @param[in] fw_device The expander device, whose route table entry is to be cleaned. 2440 * 2441 * @return None. 2442 */ 2443 void scif_sas_smp_remote_device_clean_route_table_entry( 2444 SCIF_SAS_REMOTE_DEVICE_T * fw_device 2445 ) 2446 { 2447 SCI_SAS_ADDRESS_T empty_sas_address; 2448 SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device = 2449 &(fw_device->protocol_device.smp_device); 2450 2451 SCIF_LOG_TRACE(( 2452 sci_base_object_get_logger(fw_device), 2453 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 2454 "scif_sas_smp_remote_device_clean_route_table(0x%x) enter\n", 2455 fw_device 2456 )); 2457 2458 empty_sas_address.high = 0; 2459 empty_sas_address.low = 0; 2460 2461 scif_sas_smp_request_construct_config_route_info( 2462 fw_device->domain->controller, 2463 fw_device, 2464 smp_remote_device->current_activity_phy_index, 2465 smp_remote_device->curr_config_route_index, 2466 empty_sas_address, 2467 TRUE 2468 ); 2469 2470 //schedule the DPC. 2471 scif_cb_start_internal_io_task_schedule( 2472 fw_device->domain->controller, 2473 scif_sas_controller_start_high_priority_io, 2474 fw_device->domain->controller 2475 ); 2476 } 2477 2478 2479 /** 2480 * @brief This method handles the case of exceeding route index when config route table 2481 * for a device, by removing the attached device of current config route 2482 * destination smp phy and the rest of smp phys in the same smp phy list. 2483 * 2484 * @param[in] fw_device The expander device, whose route table to be edited but failed 2485 * with a SMP function result of INDEX DOES NOT EXIST. 2486 * 2487 * @return None. 2488 */ 2489 void scif_sas_smp_remote_device_cancel_config_route_table_activity( 2490 SCIF_SAS_REMOTE_DEVICE_T * fw_device 2491 ) 2492 { 2493 //go through the rest of the smp phy list of destination device. 2494 SCI_FAST_LIST_ELEMENT_T * element = 2495 &(fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy->list_element); 2496 SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL; 2497 SCIF_SAS_REMOTE_DEVICE_T * curr_attached_device = NULL; 2498 2499 SCIF_LOG_TRACE(( 2500 sci_base_object_get_logger(fw_device), 2501 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 2502 "scif_sas_smp_remote_device_cancel_config_route_table_activity(0x%x) enter\n", 2503 fw_device 2504 )); 2505 2506 while (element != NULL) 2507 { 2508 curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element); 2509 element = sci_fast_list_get_next(element); 2510 2511 //check if this phy needs to be added to the expander's route table but can't due to 2512 //exceeding max route index. 2513 if (scif_sas_smp_remote_device_do_config_route_info( 2514 fw_device, curr_smp_phy) == TRUE ) 2515 { 2516 //set the is_currently_discovered to FALSE for attached device. Then when 2517 //domain finish discover, domain will remove this device. 2518 curr_attached_device = (SCIF_SAS_REMOTE_DEVICE_T *) 2519 scif_domain_get_device_by_sas_address( 2520 fw_device->domain, &(curr_smp_phy->attached_sas_address)); 2521 2522 if (curr_attached_device != NULL) 2523 curr_attached_device->is_currently_discovered = FALSE; 2524 } 2525 } 2526 } 2527 2528 2529 /** 2530 * @brief This method cancel current activity and terminate the outstanding internal IO 2531 * if there is one. 2532 * 2533 * @param[in] fw_device The expander device, whose smp activity is to be canceled. 2534 * 2535 * @return None. 2536 */ 2537 void scif_sas_smp_remote_device_cancel_smp_activity( 2538 SCIF_SAS_REMOTE_DEVICE_T * fw_device 2539 ) 2540 { 2541 SCIF_LOG_TRACE(( 2542 sci_base_object_get_logger(fw_device), 2543 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 2544 "scif_sas_smp_remote_device_cancel_smp_activity(0x%x) enter\n", 2545 fw_device 2546 )); 2547 2548 //Terminate all of the requests in the silicon for this device. 2549 scif_sas_domain_terminate_requests( 2550 fw_device->domain, fw_device, NULL, NULL 2551 ); 2552 2553 if (fw_device->protocol_device.smp_device.current_activity == 2554 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE) 2555 scif_sas_smp_remote_device_cancel_config_route_table_activity(fw_device); 2556 2557 //Clear the device to stop the smp sctivity. 2558 scif_sas_smp_remote_device_clear(fw_device); 2559 } 2560 2561 2562 /** 2563 * @brief This method tells the way to configure route table for a expander. The 2564 * possible ways are: configure phy 0's route table, configure middle 2565 * phy's route table, configure highest order phy's route table, 2566 * configure all phys. 2567 * 2568 * @param[in] fw_device The expander device, whose config route table method is 2569 * to be chosen. 2570 * 2571 * @return one in 4 possible options. 2572 */ 2573 U8 scif_sas_smp_remote_device_get_config_route_table_method( 2574 SCIF_SAS_REMOTE_DEVICE_T * fw_device 2575 ) 2576 { 2577 U8 config_route_table_method; 2578 2579 //config_route_table_method = SCIF_SAS_CONFIG_ROUTE_TABLE_MIDDLE_PHY_ONLY; 2580 config_route_table_method = SCIF_SAS_CONFIG_ROUTE_TABLE_ALL_PHYS; 2581 2582 return config_route_table_method; 2583 } 2584 2585 2586 /** 2587 * @brief This method starts the EA target reset process by constructing 2588 * and starting a PHY CONTROL (hard reset) smp request. 2589 * 2590 * @param[in] expander_device The expander device, to which a PHY Control smp command is 2591 * sent. 2592 * @param[in] target_device The expander attahced target device, to which the target reset 2593 * request is sent. 2594 * @param[in] fw_request The target reset task request. 2595 * 2596 * @return none 2597 */ 2598 void scif_sas_smp_remote_device_start_target_reset( 2599 SCIF_SAS_REMOTE_DEVICE_T * expander_device, 2600 SCIF_SAS_REMOTE_DEVICE_T * target_device, 2601 SCIF_SAS_REQUEST_T * fw_request 2602 ) 2603 { 2604 SCIF_SAS_CONTROLLER_T * fw_controller = expander_device->domain->controller; 2605 2606 //set current_activity and current_smp_request to expander device. 2607 expander_device->protocol_device.smp_device.current_activity = 2608 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_TARGET_RESET; 2609 expander_device->protocol_device.smp_device.current_smp_request = 2610 SMP_FUNCTION_PHY_CONTROL; 2611 expander_device->protocol_device.smp_device.current_activity_phy_index = 2612 target_device->expander_phy_identifier; 2613 2614 //A Phy Control smp request has been constructed towards parent device. 2615 //Walk the high priority io path. 2616 fw_controller->state_handlers->start_high_priority_io_handler( 2617 (SCI_BASE_CONTROLLER_T*) fw_controller, 2618 (SCI_BASE_REMOTE_DEVICE_T*) expander_device, 2619 (SCI_BASE_REQUEST_T*) fw_request, 2620 SCI_CONTROLLER_INVALID_IO_TAG 2621 ); 2622 } 2623 2624 2625