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