2 * This file is provided under a dual BSD/GPLv2 license. When using or
3 * redistributing this file, you may do so under either license.
7 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of version 2 of the GNU General Public License as
11 * published by the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
21 * The full GNU General Public License is included in this distribution
22 * in the file called LICENSE.GPL.
26 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
27 * All rights reserved.
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
33 * * Redistributions of source code must retain the above copyright
34 * notice, this list of conditions and the following disclaimer.
35 * * Redistributions in binary form must reproduce the above copyright
36 * notice, this list of conditions and the following disclaimer in
37 * the documentation and/or other materials provided with the
40 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
41 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
42 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
43 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
44 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
46 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
47 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
48 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
49 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
50 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
53 #include <sys/cdefs.h>
54 __FBSDID("$FreeBSD$");
59 * @brief This file contains the methods for the SCIF_SAS_SMP_REMOTE_DEVICE object.
61 #include <dev/isci/scil/sci_controller.h>
62 #include <dev/isci/scil/scif_sas_controller.h>
63 #include <dev/isci/scil/scif_sas_remote_device.h>
64 #include <dev/isci/scil/scif_sas_logger.h>
66 #include <dev/isci/scil/scif_sas_smp_remote_device.h>
67 #include <dev/isci/scil/scif_sas_smp_io_request.h>
68 #include <dev/isci/scil/intel_sas.h>
69 #include <dev/isci/scil/scic_io_request.h>
70 #include <dev/isci/scil/scic_remote_device.h>
71 #include <dev/isci/scil/scif_sas_smp_phy.h>
75 * @brief This method resets all fields for a smp remote device. This is a
78 * @param[in] fw_device the framework SMP device that is being
83 void scif_sas_smp_remote_device_clear(
84 SCIF_SAS_REMOTE_DEVICE_T * fw_device
87 //reset all fields in smp_device, indicate that the smp device is not
88 //in discovery process.
89 fw_device->protocol_device.smp_device.current_activity =
90 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE;
92 fw_device->protocol_device.smp_device.current_smp_request =
95 fw_device->protocol_device.smp_device.current_activity_phy_index = 0;
97 fw_device->protocol_device.smp_device.curr_config_route_index = 0;
99 fw_device->protocol_device.smp_device.config_route_smp_phy_anchor = NULL;
101 fw_device->protocol_device.smp_device.is_route_table_cleaned = FALSE;
103 fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy = NULL;
105 fw_device->protocol_device.smp_device.scheduled_activity =
106 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE;
108 fw_device->protocol_device.smp_device.io_retry_count = 0;
110 fw_device->protocol_device.smp_device.curr_clear_affiliation_phy = NULL;
112 if (fw_device->protocol_device.smp_device.smp_activity_timer != NULL)
116 fw_device->domain->controller,
117 fw_device->protocol_device.smp_device.smp_activity_timer
121 scif_cb_timer_destroy(
122 fw_device->domain->controller,
123 fw_device->protocol_device.smp_device.smp_activity_timer
126 fw_device->protocol_device.smp_device.smp_activity_timer = NULL;
132 * @brief This method intializes a smp remote device.
134 * @param[in] fw_device the framework SMP device that is being
139 void scif_sas_smp_remote_device_construct(
140 SCIF_SAS_REMOTE_DEVICE_T * fw_device
144 sci_base_object_get_logger(fw_device),
145 SCIF_LOG_OBJECT_REMOTE_DEVICE,
146 "scif_sas_smp_remote_device_construct(0x%x) enter\n",
150 fw_device->protocol_device.smp_device.number_of_phys = 0;
151 fw_device->protocol_device.smp_device.expander_route_indexes = 0;
152 fw_device->protocol_device.smp_device.is_table_to_table_supported = FALSE;
153 fw_device->protocol_device.smp_device.is_externally_configurable = FALSE;
154 fw_device->protocol_device.smp_device.is_able_to_config_others = FALSE;
156 sci_fast_list_init(&fw_device->protocol_device.smp_device.smp_phy_list);
158 scif_sas_smp_remote_device_clear(fw_device);
163 * @brief This method decodes a smp response to this smp device and then
164 * continue the smp discover process.
166 * @param[in] fw_device The framework device that a SMP response targets to.
167 * @param[in] fw_request The pointer to an smp request whose response
169 * @param[in] response_data The response data passed in.
173 SCI_STATUS scif_sas_smp_remote_device_decode_smp_response(
174 SCIF_SAS_REMOTE_DEVICE_T * fw_device,
175 SCIF_SAS_REQUEST_T * fw_request,
176 void * response_data,
177 SCI_IO_STATUS completion_status
180 SMP_RESPONSE_T * smp_response = (SMP_RESPONSE_T *)response_data;
181 SCI_STATUS status = SCI_FAILURE_UNSUPPORTED_INFORMATION_TYPE;
183 if (fw_device->protocol_device.smp_device.smp_activity_timer != NULL)
185 //if there is a timer being used, recycle it now. Since we may
186 //use the timer for other purpose next.
187 scif_cb_timer_destroy(
188 fw_device->domain->controller,
189 fw_device->protocol_device.smp_device.smp_activity_timer
192 fw_device->protocol_device.smp_device.smp_activity_timer = NULL;
195 //if Core set the status of this io to be RETRY_REQUIRED, we should
196 //retry the IO without even decode the response.
197 if (completion_status == SCI_FAILURE_RETRY_REQUIRED)
199 scif_sas_smp_remote_device_continue_current_activity(
200 fw_device, fw_request, SCI_FAILURE_RETRY_REQUIRED
203 return SCI_FAILURE_RETRY_REQUIRED;
206 //check the current smp request, decide what's next smp request to issue.
207 switch (fw_device->protocol_device.smp_device.current_smp_request)
209 case SMP_FUNCTION_REPORT_GENERAL:
211 //interpret REPORT GENERAL response.
212 status = scif_sas_smp_remote_device_decode_report_general_response(
213 fw_device, smp_response
219 case SMP_FUNCTION_REPORT_MANUFACTURER_INFORMATION:
221 // No need to perform any parsing. Just want to see
222 // the information in a trace if necessary.
223 status = SCI_SUCCESS;
227 case SMP_FUNCTION_DISCOVER:
229 if (fw_device->protocol_device.smp_device.current_activity ==
230 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER)
232 //decode discover response
233 status = scif_sas_smp_remote_device_decode_initial_discover_response(
234 fw_device, smp_response
237 else if (fw_device->protocol_device.smp_device.current_activity ==
238 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_TARGET_RESET)
240 //decode discover response as a polling result for a remote device
243 scif_sas_smp_remote_device_decode_target_reset_discover_response(
244 fw_device, smp_response
247 else if (fw_device->protocol_device.smp_device.current_activity ==
248 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_SATA_SPINUP_HOLD_RELEASE)
250 //decode discover response
252 scif_sas_smp_remote_device_decode_spinup_hold_release_discover_response(
253 fw_device, smp_response
261 case SMP_FUNCTION_REPORT_PHY_SATA:
263 //decode the report phy sata response.
264 status = scif_sas_smp_remote_device_decode_report_phy_sata_response(
265 fw_device, smp_response
271 case SMP_FUNCTION_PHY_CONTROL:
273 if (fw_device->protocol_device.smp_device.current_activity ==
274 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER)
276 //decode the phy control response.
277 status = scif_sas_smp_remote_device_decode_discover_phy_control_response(
278 fw_device, smp_response
281 else if (fw_device->protocol_device.smp_device.current_activity ==
282 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_TARGET_RESET)
284 //decode discover response as a polling result for a remote device
286 status = scif_sas_smp_remote_device_decode_target_reset_phy_control_response(
287 fw_device, smp_response
290 else if (fw_device->protocol_device.smp_device.current_activity ==
291 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAR_AFFILIATION)
293 //currently don't care about the status.
294 status = SCI_SUCCESS;
301 case SMP_FUNCTION_CONFIGURE_ROUTE_INFORMATION:
303 //Note, currently we don't expect any abnormal status from config route info response,
304 //but there is a possibility that we exceed the maximum route index. We will take care
306 status = scif_sas_smp_remote_device_decode_config_route_info_response(
307 fw_device, smp_response
313 //unsupported case, TBD
314 status = SCI_FAILURE_UNSUPPORTED_INFORMATION_TYPE;
318 //Continue current activity based on response's decoding status.
319 scif_sas_smp_remote_device_continue_current_activity(
320 fw_device, fw_request, status
328 * @brief This method decodes a smp Report Genernal response to this smp device
329 * and then continue the smp discover process.
331 * @param[in] fw_device The framework device that the REPORT GENERAL command
333 * @param[in] report_general_response The pointer to a report general response
337 SCI_STATUS scif_sas_smp_remote_device_decode_report_general_response(
338 SCIF_SAS_REMOTE_DEVICE_T * fw_device,
339 SMP_RESPONSE_T * smp_response
342 SMP_RESPONSE_REPORT_GENERAL_T * report_general_response =
343 &smp_response->response.report_general;
345 SMP_RESPONSE_HEADER_T * response_header = &smp_response->header;
348 sci_base_object_get_logger(fw_device),
349 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
350 "scif_sas_smp_remote_device_decode_report_general_response(0x%x, 0x%x) enter\n",
351 fw_device, smp_response
354 if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
356 /// @todo: more decoding work needed when the function_result is not
357 /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some
360 sci_base_object_get_logger(fw_device),
361 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
362 "Report General function result(0x%x)\n",
363 response_header->function_result
369 //get info from report general response.
370 fw_device->protocol_device.smp_device.number_of_phys =
371 (U8)report_general_response->number_of_phys;
373 //currently there is byte swap issue in U16 data.
374 fw_device->protocol_device.smp_device.expander_route_indexes =
375 ((report_general_response->expander_route_indexes & 0xff) << 8) |
376 ((report_general_response->expander_route_indexes & 0xff00) >> 8);
378 fw_device->protocol_device.smp_device.is_table_to_table_supported =
379 (BOOL)report_general_response->table_to_table_supported;
381 fw_device->protocol_device.smp_device.is_externally_configurable =
382 (BOOL)report_general_response->configurable_route_table;
384 fw_device->protocol_device.smp_device.is_able_to_config_others =
385 (BOOL)report_general_response->configures_others;
387 //If the top level expander of a domain is able to configure others,
388 //no config route table is needed in the domain. Or else,
389 //we'll let all the externally configurable expanders in the damain
390 //configure route table.
391 if (fw_device->containing_device == NULL
392 && ! fw_device->protocol_device.smp_device.is_able_to_config_others)
393 fw_device->domain->is_config_route_table_needed = TRUE;
395 //knowing number of phys this expander has, we can allocate all the smp phys for
396 //this expander now if it is not done already.
397 if (fw_device->protocol_device.smp_device.smp_phy_list.element_count == 0)
398 scif_sas_smp_remote_device_populate_smp_phy_list(fw_device);
400 if (report_general_response->configuring)
401 return SCI_FAILURE_RETRY_REQUIRED;
408 * @brief This method decodes a smp Discover response to this smp device
409 * and then continue the smp discover process. This is only ever
410 * called for the very first discover stage during a given domain
413 * @param[in] fw_device The framework device that the DISCOVER command
415 * @param[in] discover_response The pointer to a DISCOVER response
419 SCI_STATUS scif_sas_smp_remote_device_decode_initial_discover_response(
420 SCIF_SAS_REMOTE_DEVICE_T * fw_device,
421 SMP_RESPONSE_T * smp_response
424 SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain;
425 SCI_SAS_ADDRESS_T attached_device_address;
426 SCIF_SAS_REMOTE_DEVICE_T * attached_remote_device;
427 SMP_RESPONSE_DISCOVER_T * discover_response =
428 &smp_response->response.discover;
429 SMP_RESPONSE_HEADER_T * response_header = &smp_response->header;
432 sci_base_object_get_logger(fw_device),
433 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
434 "scif_sas_smp_remote_device_decode_initial_discover_response(0x%x, 0x%x) enter\n",
435 fw_device, smp_response
438 if (response_header->function_result == SMP_RESULT_PHY_VACANT)
442 else if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
444 /// @todo: more decoding work needed when the function_result is not
445 /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some
448 sci_base_object_get_logger(fw_device),
449 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
450 "Discover function result(0x%x)\n",
451 response_header->function_result
457 //only if there is target device attached. We don't add device that is
459 if ( ( discover_response->u2.sas1_1.attached_device_type
460 != SMP_NO_DEVICE_ATTACHED )
461 && ( discover_response->protocols.u.bits.attached_ssp_target
462 || discover_response->protocols.u.bits.attached_stp_target
463 || discover_response->protocols.u.bits.attached_smp_target
464 || discover_response->protocols.u.bits.attached_sata_device ) )
466 attached_device_address = discover_response->attached_sas_address;
468 attached_remote_device = (SCIF_SAS_REMOTE_DEVICE_T *)
469 scif_domain_get_device_by_sas_address(
470 fw_domain, &attached_device_address
473 //need to check if the device already existed in the domian.
474 if (attached_remote_device != SCI_INVALID_HANDLE)
476 #if !defined(DISABLE_WIDE_PORTED_TARGETS)
477 if ( attached_remote_device->is_currently_discovered == TRUE
478 && attached_remote_device != fw_device->containing_device )
480 //a downstream wide port target is found.
481 attached_remote_device->device_port_width++;
484 #endif //#if !defined(DISABLE_WIDE_PORTED_TARGETS)
486 //The device already existed. Mark the device as discovered.
487 attached_remote_device->is_currently_discovered = TRUE;
490 #if !defined(DISABLE_WIDE_PORTED_TARGETS)
491 if (attached_remote_device->device_port_width !=
492 scic_remote_device_get_port_width(attached_remote_device->core_object)
493 && discover_response->protocols.u.bits.attached_ssp_target
496 scif_sas_remote_device_update_port_width(
497 attached_remote_device, attached_remote_device->device_port_width);
499 #endif //#if !defined(DISABLE_WIDE_PORTED_TARGETS)
501 if ( discover_response->protocols.u.bits.attached_smp_target
502 && attached_remote_device != fw_device->containing_device)
504 //another expander device is discovered. Its own smp discover will starts after
505 //this discover finishes.
506 attached_remote_device->protocol_device.smp_device.scheduled_activity =
507 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER;
512 //report the discovery of a disk for all types of end device.
513 scif_cb_domain_ea_device_added(
514 fw_domain->controller, fw_domain, fw_device, discover_response
517 //get info from discover response to see what we found. And do
518 //extra work according to end device's protocol type.
519 if ( discover_response->protocols.u.bits.attached_ssp_target
520 || discover_response->protocols.u.bits.attached_smp_target)
522 //for SSP or SMP target, no extra work.
525 else if ( (discover_response->protocols.u.bits.attached_stp_target)
526 || (discover_response->protocols.u.bits.attached_sata_device) )
528 // We treat a SATA Device bit the same as an attached STP
530 discover_response->protocols.u.bits.attached_stp_target = 1;
532 //kick off REPORT PHY SATA to the same phy.
533 fw_device->protocol_device.smp_device.current_smp_request =
534 SMP_FUNCTION_REPORT_PHY_SATA;
538 else if( (discover_response->u2.sas1_1.negotiated_physical_link_rate == SCI_SATA_SPINUP_HOLD
539 || discover_response->u4.sas2.negotiated_physical_link_rate == SCI_SATA_SPINUP_HOLD)
540 &&(discover_response->protocols.u.bits.attached_stp_target
541 || discover_response->protocols.u.bits.attached_sata_device)
544 attached_remote_device = scif_sas_domain_get_device_by_containing_device(
547 discover_response->phy_identifier
550 if (attached_remote_device != SCI_INVALID_HANDLE)
552 //Here, the only reason a device already existed in domain but
553 //the initial discover rersponse shows it in SPINUP_HOLD, is that
554 //a device has been removed and coming back in SPINUP_HOLD before
555 //we detected. The possibility of this situation is very very rare.
556 //we need to remove the device then add it back using the new
558 scif_cb_domain_device_removed(
559 fw_domain->controller, fw_domain, attached_remote_device
563 discover_response->protocols.u.bits.attached_stp_target = 1;
565 //still report ea_device_added(). But this device will not be
566 //started during scif_remote_device_ea_construct().
567 scif_cb_domain_ea_device_added(
568 fw_domain->controller, fw_domain, fw_device, discover_response
571 //need to send Phy Control (RESET) to release the phy from spinup hold
573 fw_device->protocol_device.smp_device.current_smp_request =
574 SMP_FUNCTION_PHY_CONTROL;
577 //update the smp phy info based on this DISCOVER response.
578 return scif_sas_smp_remote_device_save_smp_phy_info(
579 fw_device, discover_response);
584 * @brief This method decodes a smp Report Phy Sata response to this
585 * smp device and then continue the smp discover process.
587 * @param[in] fw_device The framework device that the REPORT PHY SATA
588 * command targets to.
589 * @param[in] report_phy_sata_response The pointer to a REPORT PHY
594 SCI_STATUS scif_sas_smp_remote_device_decode_report_phy_sata_response(
595 SCIF_SAS_REMOTE_DEVICE_T * fw_device,
596 SMP_RESPONSE_T * smp_response
599 SMP_RESPONSE_REPORT_PHY_SATA_T * report_phy_sata_response =
600 &smp_response->response.report_phy_sata;
602 SMP_RESPONSE_HEADER_T * response_header = &smp_response->header;
605 sci_base_object_get_logger(fw_device),
606 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
607 "scif_sas_smp_remote_device_decode_report_phy_sata_response(0x%x, 0x%x) enter\n",
608 fw_device, smp_response
611 if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
613 /// @todo: more decoding work needed when the function_result is not
614 /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some
617 sci_base_object_get_logger(fw_device),
618 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
619 "Report Phy Sata function result(0x%x)\n",
620 response_header->function_result
626 scif_sas_remote_device_save_report_phy_sata_information(
627 report_phy_sata_response
630 // continue the discover process.
631 fw_device->protocol_device.smp_device.current_smp_request =
632 SMP_FUNCTION_DISCOVER;
639 * @brief This method decodes a smp Phy Control response to this smp device and
640 * then continue the smp TARGET RESET process.
642 * @param[in] fw_device The framework device that the Phy Control command
644 * @param[in] smp_response The pointer to a Phy Control response
645 * @param[in] fw_io The scif IO request that associates to this smp response.
649 SCI_STATUS scif_sas_smp_remote_device_decode_target_reset_phy_control_response(
650 SCIF_SAS_REMOTE_DEVICE_T * fw_device,
651 SMP_RESPONSE_T * smp_response
654 SMP_RESPONSE_HEADER_T * response_header = &smp_response->header;
656 SCI_STATUS status = SCI_SUCCESS;
659 sci_base_object_get_logger(fw_device),
660 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
661 "scif_sas_smp_remote_device_decode_target_reset_phy_control_response(0x%x, 0x%x) enter\n",
662 fw_device, smp_response
665 if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
667 /// @todo: more decoding work needed when the function_result is not
668 /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some
671 sci_base_object_get_logger(fw_device),
672 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
673 "Phy Control function unaccepted result(0x%x)\n",
674 response_header->function_result
677 status = SCI_FAILURE_RETRY_REQUIRED;
680 // phy Control succeeded.
685 * @brief This method decodes a smp Phy Control response to this smp device and
686 * then continue the smp DISCOVER process.
688 * @param[in] fw_device The framework device that the Phy Control command
690 * @param[in] smp_response The pointer to a Phy Control response
692 * @return Almost always SCI_SUCCESS
694 SCI_STATUS scif_sas_smp_remote_device_decode_discover_phy_control_response(
695 SCIF_SAS_REMOTE_DEVICE_T * fw_device,
696 SMP_RESPONSE_T * smp_response
699 SMP_RESPONSE_HEADER_T * response_header = &smp_response->header;
701 SCI_STATUS status = SCI_SUCCESS;
704 sci_base_object_get_logger(fw_device),
705 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
706 "scif_sas_smp_remote_device_decode_discover_phy_control_response(0x%x, 0x%x) enter\n",
707 fw_device, smp_response
710 if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
712 /// @todo: more decoding work needed when the function_result is not
713 /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some
716 sci_base_object_get_logger(fw_device),
717 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
718 "Phy Control function unaccepted result(0x%x)\n",
719 response_header->function_result
722 return SCI_FAILURE_RETRY_REQUIRED;
725 // continue the discover process.
726 fw_device->protocol_device.smp_device.current_smp_request =
727 SMP_FUNCTION_DISCOVER;
729 // phy Control succeeded.
735 * @brief This method decodes a smp Discover response to this smp device
736 * and then continue the smp discover process.
738 * @param[in] fw_device The framework device that the DISCOVER command
740 * @param[in] discover_response The pointer to a DISCOVER response
744 SCI_STATUS scif_sas_smp_remote_device_decode_target_reset_discover_response(
745 SCIF_SAS_REMOTE_DEVICE_T * fw_device,
746 SMP_RESPONSE_T * smp_response
749 SCIF_SAS_DOMAIN_T * fw_domain;
750 SCI_SAS_ADDRESS_T attached_device_address;
751 SMP_RESPONSE_DISCOVER_T * discover_response =
752 &smp_response->response.discover;
754 SMP_RESPONSE_HEADER_T * response_header = &smp_response->header;
757 sci_base_object_get_logger(fw_device),
758 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
759 "scif_sas_smp_remote_device_decode_target_reset_discover_response(0x%x, 0x%x) enter\n",
760 fw_device, smp_response
763 if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
765 /// @todo: more decoding work needed when the function_result is not
766 /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some
769 sci_base_object_get_logger(fw_device),
770 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
771 "Discover function result(0x%x)\n",
772 response_header->function_result
775 return SCI_FAILURE_RETRY_REQUIRED;
778 //only if there is device attached.
779 if ( discover_response->u2.sas1_1.attached_device_type != SMP_NO_DEVICE_ATTACHED )
781 fw_domain = fw_device->domain;
782 attached_device_address = discover_response->attached_sas_address;
784 // the device should have already existed in the domian.
785 ASSERT(scif_domain_get_device_by_sas_address(
787 &attached_device_address
788 ) != SCI_INVALID_HANDLE);
792 return SCI_FAILURE_RETRY_REQUIRED;
796 * @brief This method decodes a smp Discover response to this smp device
797 * for SPINUP_HOLD_RELEASE activity. If a DISCOVER response says
798 * SATA DEVICE ATTACHED and has a valid NPL value, we call fw_device's
799 * start_handler(). But if a DISCOVER response still shows SPINUP
800 * in NPL state, we need to return retry_required status
802 * @param[in] fw_device The framework device that the DISCOVER command
804 * @param[in] discover_response The pointer to a DISCOVER response
806 * @return SCI_SUCCESS
807 * SCI_FAILURE_RETRY_REQUIRED
809 SCI_STATUS scif_sas_smp_remote_device_decode_spinup_hold_release_discover_response(
810 SCIF_SAS_REMOTE_DEVICE_T * fw_device,
811 SMP_RESPONSE_T * smp_response
814 SMP_RESPONSE_DISCOVER_T * discover_response = &smp_response->response.discover;
816 SMP_RESPONSE_HEADER_T * response_header = &smp_response->header;
819 sci_base_object_get_logger(fw_device),
820 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
821 "scif_sas_smp_remote_device_decode_spinup_hold_release_discover_response(0x%x, 0x%x) enter\n",
822 fw_device, smp_response
825 if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
827 /// @todo: more decoding work needed when the function_result is not
828 /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some
831 sci_base_object_get_logger(fw_device),
832 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
833 "Discover function result(0x%x)\n",
834 response_header->function_result
840 if ( discover_response->u2.sas1_1.attached_device_type != SMP_NO_DEVICE_ATTACHED )
842 if (discover_response->u2.sas1_1.negotiated_physical_link_rate != SCI_SATA_SPINUP_HOLD
843 && discover_response->u4.sas2.negotiated_physical_link_rate != SCI_SATA_SPINUP_HOLD
844 && ( discover_response->protocols.u.bits.attached_stp_target
845 ||discover_response->protocols.u.bits.attached_sata_device )
848 SCIF_SAS_REMOTE_DEVICE_T * target_device =
849 scif_sas_domain_get_device_by_containing_device(
852 fw_device->protocol_device.smp_device.current_activity_phy_index
855 //Need to update the device's connection rate. Its connection rate was SPINIP_HOLD.
856 scic_remote_device_set_max_connection_rate(
857 target_device->core_object,
858 discover_response->u2.sas1_1.negotiated_physical_link_rate
861 //Need to update the smp phy info too.
862 scif_sas_smp_remote_device_save_smp_phy_info(
863 fw_device, discover_response);
865 //This device has already constructed, only need to call start_handler
866 //of this device here.
867 return target_device->state_handlers->parent.start_handler(
868 &target_device->parent );
871 return SCI_FAILURE_RETRY_REQUIRED;
874 return SCI_FAILURE_RETRY_REQUIRED;
879 * @brief This method decodes a smp CONFIG ROUTE INFO response to this smp
880 * device and then continue to config route table.
882 * @param[in] fw_device The framework device that the CONFIG ROUTE INFO command
884 * @param[in] smp_response The pointer to a CONFIG ROUTE INFO response
888 SCI_STATUS scif_sas_smp_remote_device_decode_config_route_info_response(
889 SCIF_SAS_REMOTE_DEVICE_T * fw_device,
890 SMP_RESPONSE_T * smp_response
893 SMP_RESPONSE_HEADER_T * response_header = &smp_response->header;
896 sci_base_object_get_logger(fw_device),
897 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
898 "scif_sas_smp_remote_device_decode_config_route_info_response(0x%x, 0x%x) enter\n",
899 fw_device, smp_response
902 if (response_header->function_result == SMP_RESULT_INDEX_DOES_NOT_EXIST)
904 //case of exceeding max route index. We need to remove the devices that are not
905 //able to be edit to route table. The destination config route smp phy
906 //is used to remove devices.
907 scif_sas_smp_remote_device_cancel_config_route_table_activity(fw_device);
909 return SCI_FAILURE_EXCEED_MAX_ROUTE_INDEX;
911 else if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
913 /// @todo: more decoding work needed when the function_result is not
914 /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some
917 sci_base_object_get_logger(fw_device),
918 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
919 "Discover function result(0x%x)\n",
920 response_header->function_result
931 * @brief This method starts the smp Discover process for an expander by
932 * sending Report General request.
934 * @param[in] fw_device The framework smp device that a command
939 void scif_sas_smp_remote_device_start_discover(
940 SCIF_SAS_REMOTE_DEVICE_T * fw_device
943 SCIF_SAS_CONTROLLER_T * fw_controller = fw_device->domain->controller;
946 sci_base_object_get_logger(fw_device),
947 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
948 "scif_sas_smp_remote_device_start_discover(0x%x) enter\n",
952 //For safety, clear the device again, there may be some config route table
953 //related info are not cleared yet.
954 scif_sas_smp_remote_device_clear(fw_device);
956 //set current activity
957 fw_device->protocol_device.smp_device.current_activity =
958 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER;
960 //Set current_smp_request to REPORT GENERAL.
961 fw_device->protocol_device.smp_device.current_smp_request =
962 SMP_FUNCTION_REPORT_GENERAL;
964 //reset discover_to_start flag.
965 fw_device->protocol_device.smp_device.scheduled_activity =
966 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE;
968 //build the first smp request Report Genernal.
969 scif_sas_smp_request_construct_report_general(fw_controller, fw_device);
971 //issue DPC to start this request.
972 scif_cb_start_internal_io_task_schedule(
974 scif_sas_controller_start_high_priority_io,
981 * @brief This method continues the smp Discover process.
983 * @param[in] fw_device The framework smp device that a DISCOVER command
985 * @param[in] fw_request The pointer to an smp request whose response
987 * @param[in] status The decoding status of the smp request's response
991 void scif_sas_smp_remote_device_continue_current_activity(
992 SCIF_SAS_REMOTE_DEVICE_T * fw_device,
993 SCIF_SAS_REQUEST_T * fw_request,
997 SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T *)fw_request;
998 // save the retry count.
999 U8 io_retry_count = fw_io->retry_count;
1001 if (fw_request->is_internal)
1003 // Complete this internal io request now. We want to free this io before
1004 // we create another SMP request, which is going to happen soon.
1005 scif_sas_internal_io_request_complete(
1006 fw_device->domain->controller,
1007 (SCIF_SAS_INTERNAL_IO_REQUEST_T *)fw_request,
1012 if (fw_device->protocol_device.smp_device.current_activity ==
1013 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER)
1015 if (status == SCI_SUCCESS)
1016 { //continue the discover process.
1017 scif_sas_smp_remote_device_continue_discover(fw_device);
1019 else if (status == SCI_FAILURE_RETRY_REQUIRED)
1021 //Retry the smp request. Since we are in the middle of Discover
1022 //process, all the smp requests are internal. A new smp request
1023 //will be created for retry.
1024 U32 retry_wait_duration = (SCIF_DOMAIN_DISCOVER_TIMEOUT / 2) / SCIF_SAS_IO_RETRY_LIMIT;
1026 if (io_retry_count < SCIF_SAS_IO_RETRY_LIMIT)
1027 scif_sas_smp_remote_device_retry_internal_io (
1028 fw_device, io_retry_count, retry_wait_duration);
1030 scif_sas_smp_remote_device_fail_discover(fw_device);
1032 else if (status == SCI_FAILURE_ILLEGAL_ROUTING_ATTRIBUTE_CONFIGURATION)
1034 //remove this expander device and its child devices. No need to
1035 //continue the discover on this device.
1036 scif_sas_domain_remove_expander_device(fw_device->domain, fw_device);
1038 //continue the domain's smp discover.
1039 scif_sas_domain_continue_discover(fw_device->domain);
1042 { //terminate the discover process.
1043 scif_sas_smp_remote_device_fail_discover(fw_device);
1046 else if (fw_device->protocol_device.smp_device.current_activity ==
1047 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_TARGET_RESET)
1049 if (status == SCI_SUCCESS)
1050 { //continue the target reset process.
1051 scif_sas_smp_remote_device_continue_target_reset(
1052 fw_device, fw_request);
1054 else if (status == SCI_FAILURE_RETRY_REQUIRED)
1056 //Retry the same smp request. Since we are in the middle of Target
1057 //reset process, all the smp requests are using external resource.
1058 //We will use the exactly same memory to retry.
1059 if (io_retry_count < SCIF_SAS_IO_RETRY_LIMIT)
1061 if (fw_device->protocol_device.smp_device.smp_activity_timer == NULL)
1063 //create the timer to wait before retry.
1064 fw_device->protocol_device.smp_device.smp_activity_timer =
1065 scif_cb_timer_create(
1066 (SCI_CONTROLLER_HANDLE_T *)fw_device->domain->controller,
1067 (SCI_TIMER_CALLBACK_T)scif_sas_smp_external_request_retry,
1076 //start the timer to wait
1077 scif_cb_timer_start(
1078 (SCI_CONTROLLER_HANDLE_T)fw_device->domain->controller,
1079 fw_device->protocol_device.smp_device.smp_activity_timer,
1080 SMP_REQUEST_RETRY_WAIT_DURATION //20 miliseconds
1084 scif_sas_smp_remote_device_fail_target_reset(fw_device, fw_request);
1087 //terminate the discover process.
1088 scif_sas_smp_remote_device_fail_target_reset(fw_device, fw_request);
1090 else if (fw_device->protocol_device.smp_device.current_activity ==
1091 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_SATA_SPINUP_HOLD_RELEASE)
1093 SCIF_SAS_REMOTE_DEVICE_T * target_device =
1094 scif_sas_domain_get_device_by_containing_device(
1097 fw_device->protocol_device.smp_device.current_activity_phy_index
1100 if (status == SCI_SUCCESS)
1102 //move on to next round of SPINUP_HOLD_REALSE activity.
1103 scif_sas_smp_remote_device_sata_spinup_hold_release(fw_device);
1105 else if (status == SCI_FAILURE_RETRY_REQUIRED)
1108 (scic_remote_device_get_suggested_reset_timeout(target_device->core_object) /
1109 SCIF_SAS_IO_RETRY_LIMIT);
1111 //Retry the smp request. Since we are in the middle of Discover
1112 //process, all the smp requests are internal. A new smp request
1113 //will be created for retry.
1114 if (io_retry_count < SCIF_SAS_IO_RETRY_LIMIT)
1116 scif_sas_smp_remote_device_retry_internal_io(
1117 fw_device, io_retry_count, delay);
1119 else //give up on this target device.
1121 scif_sas_smp_remote_device_fail_target_spinup_hold_release(
1122 fw_device , target_device);
1125 else //give up on this target device.
1126 scif_sas_smp_remote_device_fail_target_spinup_hold_release(
1127 fw_device, target_device);
1129 else if (fw_device->protocol_device.smp_device.current_activity ==
1130 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE)
1132 SCI_FAST_LIST_ELEMENT_T * next_phy_element = sci_fast_list_get_next(
1133 &(fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy->list_element) );
1135 SCI_FAST_LIST_T * destination_smp_phy_list =
1136 fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy->list_element.owning_list;
1138 SCIF_SAS_SMP_PHY_T * next_phy_in_wide_port = NULL;
1140 if (next_phy_element != NULL
1141 && status != SCI_FAILURE_EXCEED_MAX_ROUTE_INDEX)
1143 fw_device->protocol_device.smp_device.curr_config_route_index++;
1145 fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy =
1146 (SCIF_SAS_SMP_PHY_T *)sci_fast_list_get_object(next_phy_element);
1148 // Update the anchor for config route index.
1149 fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->config_route_table_index_anchor =
1150 fw_device->protocol_device.smp_device.curr_config_route_index;
1152 scif_sas_smp_remote_device_configure_route_table(fw_device);
1154 else if ( scif_sas_smp_remote_device_get_config_route_table_method(fw_device)
1155 == SCIF_SAS_CONFIG_ROUTE_TABLE_ALL_PHYS
1156 && (next_phy_in_wide_port = scif_sas_smp_phy_find_next_phy_in_wide_port(
1157 fw_device->protocol_device.smp_device.config_route_smp_phy_anchor)
1161 //config the other phy in the same wide port
1162 fw_device->protocol_device.smp_device.config_route_smp_phy_anchor =
1163 next_phy_in_wide_port;
1165 fw_device->protocol_device.smp_device.current_activity_phy_index =
1166 fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->phy_identifier;
1168 fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy =
1169 sci_fast_list_get_head(destination_smp_phy_list);
1171 if (fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->config_route_table_index_anchor != 0)
1172 fw_device->protocol_device.smp_device.curr_config_route_index =
1173 fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->config_route_table_index_anchor + 1;
1175 fw_device->protocol_device.smp_device.curr_config_route_index = 0;
1177 scif_sas_smp_remote_device_configure_route_table(fw_device);
1179 else if ( fw_device->protocol_device.smp_device.is_route_table_cleaned == FALSE)
1181 fw_device->protocol_device.smp_device.current_activity =
1182 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAN_ROUTE_TABLE;
1184 scif_sas_smp_remote_device_clean_route_table(fw_device);
1188 //set this device's activity to NON.
1189 fw_device->protocol_device.smp_device.current_activity =
1190 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE;
1192 //we need to notify domain that this device finished config route table, domain
1193 //may pick up other activities (i.e. Discover) for other expanders.
1194 scif_sas_domain_continue_discover(fw_device->domain);
1197 else if (fw_device->protocol_device.smp_device.current_activity ==
1198 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAN_ROUTE_TABLE)
1200 scif_sas_smp_remote_device_clean_route_table(fw_device);
1202 else if (fw_device->protocol_device.smp_device.current_activity ==
1203 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAR_AFFILIATION)
1205 scif_sas_smp_remote_device_continue_clear_affiliation(fw_device);
1211 * @brief This method continues the smp Discover process.
1213 * @param[in] fw_device The framework smp device that a DISCOVER command
1218 void scif_sas_smp_remote_device_continue_discover(
1219 SCIF_SAS_REMOTE_DEVICE_T * fw_device
1222 SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain;
1225 sci_base_object_get_logger(fw_device),
1226 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1227 "scif_sas_smp_remote_device_continue_discover(0x%x) enter\n",
1231 switch (fw_device->protocol_device.smp_device.current_smp_request)
1233 case SMP_FUNCTION_REPORT_GENERAL:
1234 // send the REPORT MANUFACTURER_INFO request
1235 fw_device->protocol_device.smp_device.current_smp_request =
1236 SMP_FUNCTION_REPORT_MANUFACTURER_INFORMATION;
1238 scif_sas_smp_request_construct_report_manufacturer_info(
1239 fw_domain->controller, fw_device
1244 case SMP_FUNCTION_REPORT_MANUFACTURER_INFORMATION:
1245 //send the first SMP DISCOVER request.
1246 fw_device->protocol_device.smp_device.current_activity_phy_index = 0;
1247 fw_device->protocol_device.smp_device.current_smp_request =
1248 SMP_FUNCTION_DISCOVER;
1250 scif_sas_smp_request_construct_discover(
1251 fw_domain->controller,
1253 fw_device->protocol_device.smp_device.current_activity_phy_index,
1259 case SMP_FUNCTION_DISCOVER:
1260 fw_device->protocol_device.smp_device.current_activity_phy_index++;
1262 if ( (fw_device->protocol_device.smp_device.current_activity_phy_index <
1263 fw_device->protocol_device.smp_device.number_of_phys) )
1265 scif_sas_smp_request_construct_discover(
1266 fw_domain->controller,
1268 fw_device->protocol_device.smp_device.current_activity_phy_index,
1273 scif_sas_smp_remote_device_finish_initial_discover(fw_device);
1277 case SMP_FUNCTION_REPORT_PHY_SATA:
1278 scif_sas_smp_request_construct_report_phy_sata(
1279 fw_device->domain->controller,
1281 fw_device->protocol_device.smp_device.current_activity_phy_index
1287 case SMP_FUNCTION_PHY_CONTROL:
1288 scif_sas_smp_request_construct_phy_control(
1289 fw_device->domain->controller,
1291 PHY_OPERATION_HARD_RESET,
1292 fw_device->protocol_device.smp_device.current_activity_phy_index,
1305 * @brief This method finishes the initial smp DISCOVER process. There
1306 * may be a spinup_hold release phase following of initial discover,
1307 * depending on whether there are SATA device in the domain
1308 * in SATA_SPINUP_HOLD condition.
1310 * @param[in] fw_device The framework smp device that finishes all the
1311 * DISCOVER requests.
1315 void scif_sas_smp_remote_device_finish_initial_discover(
1316 SCIF_SAS_REMOTE_DEVICE_T * fw_device
1319 SCIF_SAS_REMOTE_DEVICE_T * device_in_sata_spinup_hold =
1320 scif_sas_domain_find_device_in_spinup_hold(fw_device->domain);
1323 sci_base_object_get_logger(fw_device),
1324 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1325 "scif_sas_smp_remote_device_finish_initial_discover(0x%x) enter\n",
1329 if ( device_in_sata_spinup_hold != NULL )
1331 //call the common private routine to reset all fields of this smp device.
1332 scif_sas_smp_remote_device_clear(fw_device);
1334 //Move on to next activity SPINUP_HOLD_RELEASE
1335 fw_device->protocol_device.smp_device.current_activity =
1336 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_SATA_SPINUP_HOLD_RELEASE;
1338 //create the timer to delay a little bit before going to
1339 //sata spinup hold release activity.
1340 if (fw_device->protocol_device.smp_device.smp_activity_timer == NULL)
1342 fw_device->protocol_device.smp_device.smp_activity_timer =
1343 scif_cb_timer_create(
1344 (SCI_CONTROLLER_HANDLE_T *)fw_device->domain->controller,
1345 (SCI_TIMER_CALLBACK_T)scif_sas_smp_remote_device_sata_spinup_hold_release,
1354 scif_cb_timer_start(
1355 (SCI_CONTROLLER_HANDLE_T)fw_device->domain->controller,
1356 fw_device->protocol_device.smp_device.smp_activity_timer,
1357 SMP_SPINUP_HOLD_RELEASE_WAIT_DURATION
1361 scif_sas_smp_remote_device_finish_discover(fw_device);
1366 * @brief This method finishes the smp DISCOVER process.
1368 * @param[in] fw_device The framework smp device that finishes all the
1369 * DISCOVER requests.
1373 void scif_sas_smp_remote_device_finish_discover(
1374 SCIF_SAS_REMOTE_DEVICE_T * fw_device
1377 SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain;
1380 sci_base_object_get_logger(fw_device),
1381 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1382 "scif_sas_smp_remote_device_finish_discover(0x%x) enter\n",
1386 if ( fw_domain->is_config_route_table_needed
1387 && fw_device->protocol_device.smp_device.smp_phy_list.list_head != NULL)
1388 scif_sas_smp_remote_device_configure_upstream_expander_route_info(fw_device);
1390 //call the common private routine to reset all fields of this smp device.
1391 scif_sas_smp_remote_device_clear(fw_device);
1393 #ifdef SCI_SMP_PHY_LIST_DEBUG_PRINT
1394 scif_sas_smp_remote_device_print_smp_phy_list(fw_device);
1397 //notify domain this smp device's discover finishes, it's up to domain
1398 //to continue the discover process in a bigger scope.
1399 scif_sas_domain_continue_discover(fw_domain);
1404 * @brief This method continues the smp Target Reset (Phy Control) process.
1406 * @param[in] fw_device The framework smp device that a smp reset targets to.
1410 void scif_sas_smp_remote_device_continue_target_reset(
1411 SCIF_SAS_REMOTE_DEVICE_T * fw_device,
1412 SCIF_SAS_REQUEST_T * fw_request
1415 SCIF_SAS_CONTROLLER_T * fw_controller = fw_device->domain->controller;
1416 SCIF_SAS_REMOTE_DEVICE_T * target_device =
1417 scif_sas_domain_get_device_by_containing_device(
1420 fw_device->protocol_device.smp_device.current_activity_phy_index
1424 sci_base_object_get_logger(fw_device),
1425 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1426 "scif_sas_smp_remote_device_continue_target_reset(0x%x, 0x%x) enter\n",
1427 fw_device, fw_request
1430 if (fw_device->protocol_device.smp_device.current_smp_request ==
1431 SMP_FUNCTION_PHY_CONTROL)
1433 //query the core remote device to get suggested reset timeout value
1434 //then scale down by factor of 8 to get the duration of the pause
1435 //before sending out Discover command to poll.
1437 (scic_remote_device_get_suggested_reset_timeout(target_device->core_object)/8);
1439 //create the timer to send Discover command polling target device's
1441 if (fw_device->protocol_device.smp_device.smp_activity_timer == NULL)
1443 fw_device->protocol_device.smp_device.smp_activity_timer =
1444 scif_cb_timer_create(
1445 (SCI_CONTROLLER_HANDLE_T *)fw_controller,
1446 (SCI_TIMER_CALLBACK_T)scif_sas_smp_remote_device_target_reset_poll,
1456 scif_cb_timer_start(
1457 (SCI_CONTROLLER_HANDLE_T)fw_controller,
1458 fw_device->protocol_device.smp_device.smp_activity_timer,
1462 else if (fw_device->protocol_device.smp_device.current_smp_request ==
1463 SMP_FUNCTION_DISCOVER)
1465 //tell target reset successful
1466 scif_sas_remote_device_target_reset_complete(
1467 target_device, fw_request, SCI_SUCCESS);
1472 * @brief This routine is invoked by timer or when 2 BCN are received
1473 * after Phy Control command. This routine will construct a
1474 * Discover command to the same expander phy to poll the target
1475 * device's coming back. This new request is then put into
1476 * high priority queue and will be started by a DPC soon.
1478 * @param[in] fw_request The scif request for smp activities.
1480 void scif_sas_smp_remote_device_target_reset_poll(
1481 SCIF_SAS_REQUEST_T * fw_request
1484 SCIF_SAS_REMOTE_DEVICE_T * fw_device = fw_request->device;
1485 SCIF_SAS_CONTROLLER_T * fw_controller = fw_device->domain->controller;
1486 void * new_command_handle;
1489 sci_base_object_get_logger(fw_device),
1490 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1491 "scif_sas_smp_remote_device_target_reset_poll(0x%x) enter\n",
1495 // Before we construct new io using the same memory, we need to
1496 // remove the IO from the list of outstanding requests on the domain
1497 // so that we don't damage the domain's fast list of request.
1498 sci_fast_list_remove_element(&fw_request->list_element);
1500 fw_device->protocol_device.smp_device.current_smp_request =
1501 SMP_FUNCTION_DISCOVER;
1503 //sent smp discover request to poll on remote device's coming back.
1504 //construct Discover command using the same memory as fw_request.
1505 new_command_handle = scif_sas_smp_request_construct_discover(
1506 fw_device->domain->controller,
1508 fw_device->protocol_device.smp_device.current_activity_phy_index,
1509 (void *)sci_object_get_association(fw_request),
1513 //put into the high priority queue.
1514 sci_pool_put(fw_controller->hprq.pool, (POINTER_UINT) new_command_handle);
1516 //schedule the DPC to start new Discover command.
1517 scif_cb_start_internal_io_task_schedule(
1518 fw_controller, scif_sas_controller_start_high_priority_io, fw_controller
1524 * @brief This method fails discover process.
1526 * @param[in] fw_device The framework smp device that failed at current
1531 void scif_sas_smp_remote_device_fail_discover(
1532 SCIF_SAS_REMOTE_DEVICE_T * fw_device
1536 sci_base_object_get_logger(fw_device),
1537 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1538 "scif_sas_smp_remote_device_fail_discover(0x%x) enter\n",
1542 switch (fw_device->protocol_device.smp_device.current_smp_request)
1544 case SMP_FUNCTION_REPORT_GENERAL:
1545 case SMP_FUNCTION_REPORT_MANUFACTURER_INFORMATION:
1546 scif_sas_smp_remote_device_finish_discover(fw_device);
1549 case SMP_FUNCTION_DISCOVER:
1550 case SMP_FUNCTION_REPORT_PHY_SATA:
1551 //Retry limit reached, we will continue to send DISCOVER to next phy.
1552 fw_device->protocol_device.smp_device.current_smp_request =
1553 SMP_FUNCTION_DISCOVER;
1555 scif_sas_smp_remote_device_continue_discover(fw_device);
1565 * @brief This method fails Target Reset.
1567 * @param[in] fw_device The framework smp device that failed at current
1569 * @param[in] fw_request The smp request created for target reset
1570 * using external resource.
1574 void scif_sas_smp_remote_device_fail_target_reset(
1575 SCIF_SAS_REMOTE_DEVICE_T * fw_device,
1576 SCIF_SAS_REQUEST_T * fw_request
1579 SCIF_SAS_REMOTE_DEVICE_T * target_device =
1580 scif_sas_domain_get_device_by_containing_device(
1583 fw_device->protocol_device.smp_device.current_activity_phy_index
1587 sci_base_object_get_logger(fw_device),
1588 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1589 "scif_sas_smp_remote_device_fail_target_reset(0x%x, 0x%x, 0x%x) enter\n",
1590 fw_device, target_device, fw_request
1593 //tell target reset failed
1594 scif_sas_remote_device_target_reset_complete(
1595 target_device, fw_request, SCI_FAILURE);
1599 * @brief This method init or continue the SATA SPINUP_HOLD RELEASE activity.
1600 * This function searches domain's device list, find a device in STOPPED STATE
1601 * and its connection_rate is SPINIP, then send DISCOVER command to its expander
1602 * phy id to poll. But if searching the domain's device list for SATA devices on
1603 * SPINUP_HOLD finds no device, the activity SPINUP_HOLD_RELEASE is finished.
1604 * We then call fw_domain->device_start_complete_handler() for this smp-device.
1606 * @param[in] fw_device The framework smp device that is on SATA SPINUP_HOLD_RELEASE
1611 void scif_sas_smp_remote_device_sata_spinup_hold_release(
1612 SCIF_SAS_REMOTE_DEVICE_T * fw_device
1615 SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain;
1616 SCIF_SAS_CONTROLLER_T * fw_controller = fw_domain->controller;
1617 SCIF_SAS_REMOTE_DEVICE_T * device_to_poll = NULL;
1620 sci_base_object_get_logger(fw_device),
1621 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1622 "scif_sas_smp_remote_device_sata_spinup_hold_release(0x%x) enter\n",
1626 //search throught domain's device list to find a sata device on spinup_hold
1628 device_to_poll = scif_sas_domain_find_device_in_spinup_hold(fw_domain);
1630 if (device_to_poll != NULL)
1632 //send DISCOVER command to this device's expaner phy.
1633 fw_device->protocol_device.smp_device.current_smp_request =
1634 SMP_FUNCTION_DISCOVER;
1636 fw_device->protocol_device.smp_device.current_activity_phy_index =
1637 device_to_poll->expander_phy_identifier;
1639 scif_sas_smp_request_construct_discover(
1640 fw_domain->controller,
1642 fw_device->protocol_device.smp_device.current_activity_phy_index,
1646 //schedule the DPC to start new Discover command.
1647 scif_cb_start_internal_io_task_schedule(
1648 fw_controller, scif_sas_controller_start_high_priority_io, fw_controller
1651 else //SATA SPINUP HOLD RELEASE activity is done.
1652 scif_sas_smp_remote_device_finish_discover (fw_device);
1657 * @brief This method fail an action of SATA SPINUP_HOLD RELEASE on a single EA
1658 * SATA device. It will remove a remote_device object for a sata device
1659 * that fails to come out of spinup_hold.
1661 * @param[in] fw_device The framework smp device that is on SATA SPINUP_HOLD_RELEASE
1663 * @param[in] target_device The expander attached device failed being brought out
1664 * of SPINUP_HOLD state.
1668 void scif_sas_smp_remote_device_fail_target_spinup_hold_release(
1669 SCIF_SAS_REMOTE_DEVICE_T * fw_device,
1670 SCIF_SAS_REMOTE_DEVICE_T * target_device
1673 SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain;
1676 sci_base_object_get_logger(fw_device),
1677 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1678 "scif_sas_smp_remote_device_fail_target_spinup_hold_release(0x%x, 0x%x) enter\n",
1679 fw_device, target_device
1682 //need to remove the device, since we have to give up on spinup_hold_release
1683 //activity on this device.
1684 scif_cb_domain_device_removed(
1685 fw_domain->controller, fw_domain, target_device
1688 //move on to next round of SPINUP_HOLD_REALSE activity.
1689 scif_sas_smp_remote_device_sata_spinup_hold_release(fw_device);
1694 * @brief This method retry only internal IO for the smp device.
1696 * @param[in] fw_device The framework smp device that has an smp request to retry.
1697 * @param[in] io_retry_count current count for times the IO being retried.
1698 * @param[in] delay The time delay before the io gets retried.
1702 void scif_sas_smp_remote_device_retry_internal_io(
1703 SCIF_SAS_REMOTE_DEVICE_T * fw_device,
1709 sci_base_object_get_logger(fw_device),
1710 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1711 "scif_sas_smp_remote_device_retry_internal_io(0x%x, 0x%x, 0x%x) enter\n",
1712 fw_device, io_retry_count, delay
1715 fw_device->protocol_device.smp_device.io_retry_count =
1718 //create the timer for poll target device's coming back.
1719 if (fw_device->protocol_device.smp_device.smp_activity_timer == NULL)
1721 fw_device->protocol_device.smp_device.smp_activity_timer =
1722 scif_cb_timer_create(
1723 (SCI_CONTROLLER_HANDLE_T *)fw_device->domain->controller,
1724 (SCI_TIMER_CALLBACK_T)scif_sas_smp_internal_request_retry,
1732 //start the timer for a purpose of waiting.
1733 scif_cb_timer_start(
1734 (SCI_CONTROLLER_HANDLE_T)fw_device->domain->controller,
1735 fw_device->protocol_device.smp_device.smp_activity_timer,
1742 * @brief This method indicates whether an expander device is in Discover
1745 * @param[in] fw_device The framework smp device.
1747 * @return Whether an expander device is in the middle of discovery process.
1749 BOOL scif_sas_smp_remote_device_is_in_activity(
1750 SCIF_SAS_REMOTE_DEVICE_T * fw_device
1753 return(fw_device->protocol_device.smp_device.current_activity
1754 != SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE);
1758 * @brief This method search through the smp phy list of an expander to
1759 * find a smp phy by its phy id of the expander.
1761 * @param[in] phy_identifier The search criteria.
1762 * @param[in] smp_remote_device The expander that owns the smp phy list.
1764 * @return The found smp phy or a NULL pointer to indicate no smp phy is found.
1766 SCIF_SAS_SMP_PHY_T * scif_sas_smp_remote_device_find_smp_phy_by_id(
1768 SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device
1771 SCI_FAST_LIST_ELEMENT_T * element = smp_remote_device->smp_phy_list.list_head;
1772 SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL;
1774 ASSERT(phy_identifier < smp_remote_device->smp_phy_list.number_of_phys);
1776 while (element != NULL)
1778 curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element);
1779 element = sci_fast_list_get_next(element);
1781 if (curr_smp_phy->phy_identifier == phy_identifier)
1782 return curr_smp_phy;
1789 * @brief This method takes care of removing smp phy list of a smp devcie, which is
1790 * about to be removed.
1792 * @param[in] fw_device The expander device that is about to be removed.
1796 void scif_sas_smp_remote_device_removed(
1797 SCIF_SAS_REMOTE_DEVICE_T * this_device
1800 SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device =
1801 &this_device->protocol_device.smp_device;
1803 SCI_FAST_LIST_ELEMENT_T * element = smp_remote_device->smp_phy_list.list_head;
1804 SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL;
1807 sci_base_object_get_logger(this_device),
1808 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1809 "scif_sas_smp_remote_device_removed(0x%x) enter\n",
1813 //remove all the smp phys in this device's smp_phy_list, and the conterpart smp phys
1814 //in phy connections.
1815 while (element != NULL)
1817 curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element);
1818 element = sci_fast_list_get_next(element);
1820 scif_sas_smp_phy_destruct(curr_smp_phy);
1823 this_device->protocol_device.smp_device.number_of_phys = 0;
1824 this_device->protocol_device.smp_device.expander_route_indexes = 0;
1825 this_device->protocol_device.smp_device.is_table_to_table_supported = FALSE;
1826 this_device->protocol_device.smp_device.is_externally_configurable = FALSE;
1827 this_device->protocol_device.smp_device.is_able_to_config_others = FALSE;
1829 scif_sas_smp_remote_device_clear(this_device);
1834 * @brief This method takes care of terminated smp request to a smp device. The
1835 * terminated smp request is most likely timeout and being aborted. A timeout
1836 * maybe due to OPEN REJECT (NO DESTINATION).
1838 * @param[in] fw_device The expander device that a timed out smp request towards to.
1839 * @param[in] fw_request A failed smp request that is terminated by scic.
1843 void scif_sas_smp_remote_device_terminated_request_handler(
1844 SCIF_SAS_REMOTE_DEVICE_T * fw_device,
1845 SCIF_SAS_REQUEST_T * fw_request
1849 sci_base_object_get_logger(fw_device),
1850 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1851 "scif_sas_smp_remote_device_terminated_request_handler(0x%x, 0x%x) enter\n",
1852 fw_device, fw_request
1855 scif_sas_smp_remote_device_decode_smp_response(
1856 fw_device, fw_request, NULL, SCI_IO_FAILURE_RETRY_REQUIRED
1862 * @brief This method allocates and populates the smp phy list of a expander device.
1864 * @param[in] fw_device The expander device, whose smp phy list is to be populated after
1865 * getting REPORT GENERAL response.
1869 void scif_sas_smp_remote_device_populate_smp_phy_list(
1870 SCIF_SAS_REMOTE_DEVICE_T * fw_device
1873 SCIF_SAS_SMP_PHY_T * this_smp_phy = NULL;
1874 U8 expander_phy_id = 0;
1877 sci_base_object_get_logger(fw_device),
1878 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1879 "scif_sas_smp_remote_device_populate_smp_phy_list(0x%x) enter\n",
1883 for ( expander_phy_id = 0;
1884 expander_phy_id < fw_device->protocol_device.smp_device.number_of_phys;
1888 scif_sas_controller_allocate_smp_phy(fw_device->domain->controller);
1890 ASSERT( this_smp_phy != NULL );
1892 if ( this_smp_phy != NULL )
1893 scif_sas_smp_phy_construct(this_smp_phy, fw_device, expander_phy_id);
1899 * @brief This method updates a smp phy of a expander device based on DISCOVER response.
1901 * @param[in] fw_device The expander device, one of whose smp phys is to be updated.
1902 * @param[in] discover_response The smp DISCOVER response.
1904 * @return SCI_STATUS If a smp phy pair between expanders has invalid routing attribute,
1905 * return SCI_FAILURE_ILLEGAL_ROUTING_ATTRIBUTE_CONFIGURATION, otherwise,
1906 * return SCI_SUCCESS
1908 SCI_STATUS scif_sas_smp_remote_device_save_smp_phy_info(
1909 SCIF_SAS_REMOTE_DEVICE_T * fw_device,
1910 SMP_RESPONSE_DISCOVER_T * discover_response
1913 SCI_STATUS status = SCI_SUCCESS;
1914 SCIF_SAS_SMP_PHY_T * smp_phy = NULL;
1915 SCIF_SAS_REMOTE_DEVICE_T * attached_device = NULL;
1918 sci_base_object_get_logger(fw_device),
1919 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1920 "scif_sas_smp_remote_device_save_smp_phy_info(0x%x, 0x%x) enter\n",
1921 fw_device, discover_response
1924 smp_phy = scif_sas_smp_remote_device_find_smp_phy_by_id(
1925 discover_response->phy_identifier,
1926 &fw_device->protocol_device.smp_device
1929 ASSERT( smp_phy != NULL );
1931 //Note, attached_device could be NULL, not all the smp phy have to connected to a device.
1932 attached_device = (SCIF_SAS_REMOTE_DEVICE_T *)
1933 scif_domain_get_device_by_sas_address(
1934 fw_device->domain, &discover_response->attached_sas_address);
1936 scif_sas_smp_phy_save_information(
1937 smp_phy, attached_device, discover_response);
1939 //handle the special case of smp phys between expanders.
1940 if ( discover_response->protocols.u.bits.attached_smp_target )
1942 //this fw_device is a child expander, just found its parent expander.
1943 //And there is no smp_phy constructed yet, record this phy connection.
1944 if ( attached_device != NULL
1945 && attached_device == fw_device->containing_device )
1947 //record the smp phy info, for this phy connects to a upstream smp device.
1948 //the connection of a pair of smp phys are completed.
1949 status = scif_sas_smp_phy_set_attached_phy(
1951 discover_response->attached_phy_identifier,
1955 if (status == SCI_SUCCESS)
1957 //check the routing attribute for this phy and its containing device's
1958 //expander_phy_routing_attribute.
1959 if ( scif_sas_smp_phy_verify_routing_attribute(
1960 smp_phy, smp_phy->u.attached_phy) != SCI_SUCCESS )
1961 return SCI_FAILURE_ILLEGAL_ROUTING_ATTRIBUTE_CONFIGURATION;
1969 #ifdef SCI_SMP_PHY_LIST_DEBUG_PRINT
1970 void scif_sas_smp_remote_device_print_smp_phy_list(
1971 SCIF_SAS_REMOTE_DEVICE_T * fw_device
1974 SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device = &fw_device->protocol_device.smp_device;
1975 SCI_FAST_LIST_ELEMENT_T * element = smp_remote_device->smp_phy_list.list_head;
1976 SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL;
1979 sci_base_object_get_logger(fw_device),
1980 SCIF_LOG_OBJECT_REMOTE_DEVICE,
1981 "==========EXPANDER DEVICE (0x%x) smp phy list========== \n",
1985 while (element != NULL)
1987 curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element);
1988 element = sci_fast_list_get_next(element);
1990 //print every thing about a smp phy
1992 sci_base_object_get_logger(fw_device),
1993 SCIF_LOG_OBJECT_REMOTE_DEVICE,
1994 "SMP_PHY_%d (0x%x), attached device(0x%x), attached_sas_address(%x%x) attached_device_type(%d), routing_attribute(%d)\n",
1995 curr_smp_phy->phy_identifier, curr_smp_phy,
1996 curr_smp_phy->u.end_device,
1997 curr_smp_phy->attached_sas_address.high, curr_smp_phy->attached_sas_address.low,
1998 curr_smp_phy->attached_device_type,
1999 curr_smp_phy->routing_attribute
2007 * @brief This method configure upstream expander(s)' (if there is any) route info.
2009 * @param[in] this_device The expander device that is currently in discover process.
2013 void scif_sas_smp_remote_device_configure_upstream_expander_route_info(
2014 SCIF_SAS_REMOTE_DEVICE_T * this_device
2017 SCIF_SAS_REMOTE_DEVICE_T * curr_child_expander = this_device;
2018 SCIF_SAS_REMOTE_DEVICE_T * curr_parent_expander =
2019 scif_sas_remote_device_find_upstream_expander(this_device);
2021 SCIF_SAS_REMOTE_DEVICE_T * curr_config_route_info_expander = NULL;
2024 sci_base_object_get_logger(this_device),
2025 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
2026 "scif_sas_smp_remote_device_configure_upstream_expander_route_info(0x%x) enter\n",
2030 //traverse back to find root device.
2031 while(curr_parent_expander != NULL )
2033 //must set destination_smp_phy outside of find_upstream_expander() using the device
2034 //that is just about to finish the discovery.
2035 curr_parent_expander->protocol_device.smp_device.curr_config_route_destination_smp_phy =
2036 (SCIF_SAS_SMP_PHY_T*)sci_fast_list_get_object(
2037 this_device->protocol_device.smp_device.smp_phy_list.list_head);
2039 curr_child_expander = curr_parent_expander;
2040 curr_parent_expander = scif_sas_remote_device_find_upstream_expander(curr_child_expander);
2043 //found the root device: curr_child_expander. configure it and its downstream expander(s) till
2044 //this_device or a self-configuring expander that configures others;
2045 curr_config_route_info_expander = curr_child_expander;
2047 while ( curr_config_route_info_expander != NULL
2048 && curr_config_route_info_expander != this_device
2049 && curr_config_route_info_expander->protocol_device.smp_device.scheduled_activity
2050 == SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE
2053 if (curr_config_route_info_expander->protocol_device.smp_device.is_externally_configurable)
2055 SCIF_SAS_SMP_PHY_T * phy_being_config =
2056 curr_config_route_info_expander->protocol_device.smp_device.config_route_smp_phy_anchor;
2058 curr_config_route_info_expander->protocol_device.smp_device.curr_config_route_index =
2059 phy_being_config->config_route_table_index_anchor;
2061 if (curr_config_route_info_expander->protocol_device.smp_device.curr_config_route_index != 0)
2062 curr_config_route_info_expander->protocol_device.smp_device.curr_config_route_index++;
2064 curr_config_route_info_expander->protocol_device.smp_device.scheduled_activity =
2065 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE;
2067 //Find a downstream expander that has curr_config_route_destination_smp_phy.owning device
2068 //same as curr_config_route_info_expander.
2069 curr_config_route_info_expander = scif_sas_remote_device_find_downstream_expander(
2070 curr_config_route_info_expander);
2072 else if (curr_config_route_info_expander->protocol_device.smp_device.is_able_to_config_others)
2074 //no need to config route table to this expander and its children.
2075 //find its downstream expander and clear the planned config route table activity.
2076 SCIF_SAS_REMOTE_DEVICE_T * curr_downstream_expander =
2077 scif_sas_remote_device_find_downstream_expander(
2078 curr_config_route_info_expander);
2080 scif_sas_smp_remote_device_clear(curr_config_route_info_expander);
2082 while ( curr_downstream_expander != NULL
2083 && curr_downstream_expander != this_device )
2085 scif_sas_smp_remote_device_clear(curr_downstream_expander);
2086 curr_downstream_expander =
2087 scif_sas_remote_device_find_downstream_expander(
2088 curr_config_route_info_expander);
2095 // current expander is a self-configuring expander, which is not externally
2096 // configurable, and doesn't config others. we need to simply skip this expander.
2097 curr_config_route_info_expander = scif_sas_remote_device_find_downstream_expander(
2098 curr_config_route_info_expander);
2104 * @brief This method finds the immediate upstream expander of a given expander device.
2106 * @param[in] this_device The given expander device, whose upstream expander is to be found.
2108 * @return The immediate upstream expander. Or a NULL pointer if this_device is root already.
2110 SCIF_SAS_REMOTE_DEVICE_T * scif_sas_remote_device_find_upstream_expander(
2111 SCIF_SAS_REMOTE_DEVICE_T * this_device
2114 SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device =
2115 &this_device->protocol_device.smp_device;
2117 SCIF_SAS_REMOTE_DEVICE_T * upstream_expander = NULL;
2119 SCI_FAST_LIST_ELEMENT_T * element = smp_remote_device->smp_phy_list.list_head;
2120 SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL;
2123 sci_base_object_get_logger(this_device),
2124 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
2125 "scif_sas_smp_remote_device_configure_upstream_expander_route_info(0x%x) enter\n",
2129 while (element != NULL)
2131 curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element);
2132 element = sci_fast_list_get_next(element);
2134 if ( curr_smp_phy->routing_attribute == SUBTRACTIVE_ROUTING_ATTRIBUTE
2135 && ( curr_smp_phy->attached_device_type == SMP_EDGE_EXPANDER_DEVICE
2136 || curr_smp_phy->attached_device_type == SMP_FANOUT_EXPANDER_DEVICE)
2137 && curr_smp_phy->u.attached_phy != NULL
2138 && curr_smp_phy->u.attached_phy->routing_attribute == TABLE_ROUTING_ATTRIBUTE )
2140 //set the current_activity and current_config_route_index for that
2141 //upstream expander.
2142 upstream_expander = curr_smp_phy->u.attached_phy->owning_device;
2144 upstream_expander->protocol_device.smp_device.current_smp_request =
2145 SMP_FUNCTION_CONFIGURE_ROUTE_INFORMATION;
2147 //if the upstream_expander's config route table method is config phy0 only or
2148 //config all phys, the current activity phy is found.
2149 upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor =
2150 scif_sas_smp_remote_device_find_smp_phy_by_id(
2151 curr_smp_phy->u.attached_phy->phy_identifier,
2152 &(curr_smp_phy->u.attached_phy->owning_device->protocol_device.smp_device)
2155 //if the upstream_expander's config route table method is config middle phy only
2156 //config highest phy only, the current activity phy needs a update.
2157 if ( scif_sas_smp_remote_device_get_config_route_table_method(upstream_expander)
2158 == SCIF_SAS_CONFIG_ROUTE_TABLE_MIDDLE_PHY_ONLY )
2160 upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor =
2161 scif_sas_smp_phy_find_middle_phy_in_wide_port (
2162 upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor
2165 else if ( scif_sas_smp_remote_device_get_config_route_table_method(upstream_expander)
2166 == SCIF_SAS_CONFIG_ROUTE_TABLE_HIGHEST_PHY_ONLY )
2168 upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor =
2169 scif_sas_smp_phy_find_highest_phy_in_wide_port (
2170 upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor
2174 upstream_expander->protocol_device.smp_device.current_activity_phy_index =
2175 upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor->phy_identifier;
2177 return upstream_expander;
2186 * @brief This method finds the immediate downstream expander of a given expander device.
2188 * @param[in] this_device The given expander device, whose downstream expander is to be found.
2190 * @return The immediate downstream expander. Or a NULL pointer if there is none.
2192 SCIF_SAS_REMOTE_DEVICE_T * scif_sas_remote_device_find_downstream_expander(
2193 SCIF_SAS_REMOTE_DEVICE_T * this_device
2196 SCIF_SAS_SMP_REMOTE_DEVICE_T * this_smp_remote_device =
2197 &this_device->protocol_device.smp_device;
2199 SCIF_SAS_REMOTE_DEVICE_T * downstream_expander = NULL;
2201 SCI_FAST_LIST_ELEMENT_T * element = this_smp_remote_device->smp_phy_list.list_head;
2202 SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL;
2205 sci_base_object_get_logger(this_device),
2206 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
2207 "scif_sas_remote_device_find_downstream_expander(0x%x) enter\n",
2211 while (element != NULL)
2213 curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element);
2214 element = sci_fast_list_get_next(element);
2216 if ( curr_smp_phy->routing_attribute == TABLE_ROUTING_ATTRIBUTE
2217 && curr_smp_phy->attached_device_type == SMP_EDGE_EXPANDER_DEVICE
2218 && curr_smp_phy->u.attached_phy != NULL)
2220 //set the current_activity and current_config_route_index for that
2221 //upstream expander.
2222 downstream_expander = curr_smp_phy->u.attached_phy->owning_device;
2224 if ( downstream_expander->protocol_device.smp_device.curr_config_route_destination_smp_phy != NULL
2225 && downstream_expander->protocol_device.smp_device.curr_config_route_destination_smp_phy->owning_device ==
2226 this_smp_remote_device->curr_config_route_destination_smp_phy->owning_device )
2227 return downstream_expander;
2236 * @brief This method follows route table optimization rule to check if a destination_device
2237 * should be recorded in the device_being_config's route table
2239 * @param[in] device_being_config The upstream expander device, whose route table is being configured.
2240 * @param[in] destination_smp_phy A smp phy whose attached device is potentially to be
2241 * recorded in route table.
2243 * @return BOOL This method returns TRUE if a destination_device should be recorded in route table.
2244 * This method returns FALSE if a destination_device need not to be recorded
2247 BOOL scif_sas_smp_remote_device_do_config_route_info(
2248 SCIF_SAS_REMOTE_DEVICE_T * device_being_config,
2249 SCIF_SAS_SMP_PHY_T * destination_smp_phy
2252 SCI_SAS_ADDRESS_T device_being_config_sas_address;
2255 sci_base_object_get_logger(device_being_config),
2256 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
2257 "scif_sas_smp_remote_device_do_config_route_info(0x%x, 0x%x) enter\n",
2258 device_being_config, destination_smp_phy
2261 scic_remote_device_get_sas_address(
2262 device_being_config->core_object, &device_being_config_sas_address
2265 //refer to SAS-2 spec 4.8.3, rule (b)
2266 if ((destination_smp_phy->attached_sas_address.low == 0
2267 && destination_smp_phy->attached_sas_address.high == 0)
2268 && (destination_smp_phy->attached_device_type == SMP_NO_DEVICE_ATTACHED))
2273 //refer to SAS-2 spec 4.8.3, rule (c), self-referencing.
2274 if (destination_smp_phy->attached_sas_address.high ==
2275 device_being_config_sas_address.high
2276 && destination_smp_phy->attached_sas_address.low ==
2277 device_being_config_sas_address.low)
2282 //There will be no cases that falling into rule (a), (d), (e) to be excluded,
2283 //based on our current mechanism of cofig route table.
2290 * @brief This method configures device_being_config's route table for all the enclosed devices in
2291 * a downstream smp device, destination_device.
2293 * @param[in] device_being_config The upstream expander device, whose route table is being configured.
2297 void scif_sas_smp_remote_device_configure_route_table(
2298 SCIF_SAS_REMOTE_DEVICE_T * device_being_config
2301 //go through the smp phy list of this_device.
2302 SCI_FAST_LIST_ELEMENT_T * element =
2303 &(device_being_config->protocol_device.smp_device.curr_config_route_destination_smp_phy->list_element);
2304 SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL;
2307 sci_base_object_get_logger(device_being_config),
2308 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
2309 "scif_sas_smp_remote_device_configure_route_table(0x%x) enter\n",
2313 device_being_config->protocol_device.smp_device.current_activity =
2314 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE;
2316 while (element != NULL)
2318 curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element);
2319 element = sci_fast_list_get_next(element);
2321 //check if this phy needs to be added to the expander's route table.
2322 if (scif_sas_smp_remote_device_do_config_route_info(
2323 device_being_config, curr_smp_phy) == TRUE )
2325 SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device =
2326 &device_being_config->protocol_device.smp_device;
2328 smp_remote_device->curr_config_route_destination_smp_phy =
2331 //Then config this_device's route table entry at the phy and next route_index.
2332 //send config_route_info using curr_smp_phy.phy_identifier and sas_address.
2333 scif_sas_smp_request_construct_config_route_info(
2334 device_being_config->domain->controller,
2335 device_being_config,
2336 smp_remote_device->current_activity_phy_index,
2337 smp_remote_device->curr_config_route_index,
2338 curr_smp_phy->attached_sas_address,
2343 scif_cb_start_internal_io_task_schedule(
2344 device_being_config->domain->controller,
2345 scif_sas_controller_start_high_priority_io,
2346 device_being_config->domain->controller
2349 //stop here, we need to wait for config route info's response then send
2358 * @brief This method walks through an expander's route table to clean table
2359 * attribute phys' route entries. This routine finds one table entry
2360 * to clean and will be called repeatly till it finishes cleanning the
2363 * @param[in] fw_device The expander device, whose route table entry is to be cleaned.
2367 void scif_sas_smp_remote_device_clean_route_table(
2368 SCIF_SAS_REMOTE_DEVICE_T * fw_device
2371 SCIF_SAS_SMP_PHY_T * smp_phy_being_config;
2374 sci_base_object_get_logger(fw_device),
2375 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
2376 "scif_sas_smp_remote_device_clean_route_table(0x%x) enter\n",
2380 //from anchors, start to clean all the other route table entries.
2381 fw_device->protocol_device.smp_device.curr_config_route_index++;
2383 if ( fw_device->protocol_device.smp_device.curr_config_route_index >=
2384 fw_device->protocol_device.smp_device.expander_route_indexes )
2386 fw_device->protocol_device.smp_device.curr_config_route_index = 0;
2388 do //find next table attribute PHY.
2390 fw_device->protocol_device.smp_device.current_activity_phy_index++;
2391 if (fw_device->protocol_device.smp_device.current_activity_phy_index ==
2392 fw_device->protocol_device.smp_device.number_of_phys)
2393 fw_device->protocol_device.smp_device.current_activity_phy_index=0;
2395 //phy_index changed, so update the smp_phy_being_config.
2396 smp_phy_being_config =
2397 scif_sas_smp_remote_device_find_smp_phy_by_id(
2398 fw_device->protocol_device.smp_device.current_activity_phy_index,
2399 &(fw_device->protocol_device.smp_device)
2401 } while( smp_phy_being_config->routing_attribute != TABLE_ROUTING_ATTRIBUTE );
2403 if ( smp_phy_being_config->phy_identifier !=
2404 fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->phy_identifier)
2406 if (smp_phy_being_config->config_route_table_index_anchor != 0)
2407 fw_device->protocol_device.smp_device.curr_config_route_index =
2408 smp_phy_being_config->config_route_table_index_anchor + 1;
2410 fw_device->protocol_device.smp_device.curr_config_route_index = 0;
2414 if ( !(fw_device->protocol_device.smp_device.current_activity_phy_index ==
2415 fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->phy_identifier
2416 && fw_device->protocol_device.smp_device.curr_config_route_index == 0)
2419 //clean this route entry.
2420 scif_sas_smp_remote_device_clean_route_table_entry(fw_device);
2424 fw_device->protocol_device.smp_device.is_route_table_cleaned = TRUE;
2426 //set this device's activity to NON.
2427 fw_device->protocol_device.smp_device.current_activity =
2428 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE;
2430 //we need to notify domain that this device finished config route table, domain
2431 //may pick up other activities (i.e. Discover) for other expanders.
2432 scif_sas_domain_continue_discover(fw_device->domain);
2437 * @brief This method cleans a device's route table antry.
2439 * @param[in] fw_device The expander device, whose route table entry is to be cleaned.
2443 void scif_sas_smp_remote_device_clean_route_table_entry(
2444 SCIF_SAS_REMOTE_DEVICE_T * fw_device
2447 SCI_SAS_ADDRESS_T empty_sas_address;
2448 SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device =
2449 &(fw_device->protocol_device.smp_device);
2452 sci_base_object_get_logger(fw_device),
2453 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
2454 "scif_sas_smp_remote_device_clean_route_table(0x%x) enter\n",
2458 empty_sas_address.high = 0;
2459 empty_sas_address.low = 0;
2461 scif_sas_smp_request_construct_config_route_info(
2462 fw_device->domain->controller,
2464 smp_remote_device->current_activity_phy_index,
2465 smp_remote_device->curr_config_route_index,
2471 scif_cb_start_internal_io_task_schedule(
2472 fw_device->domain->controller,
2473 scif_sas_controller_start_high_priority_io,
2474 fw_device->domain->controller
2480 * @brief This method handles the case of exceeding route index when config route table
2481 * for a device, by removing the attached device of current config route
2482 * destination smp phy and the rest of smp phys in the same smp phy list.
2484 * @param[in] fw_device The expander device, whose route table to be edited but failed
2485 * with a SMP function result of INDEX DOES NOT EXIST.
2489 void scif_sas_smp_remote_device_cancel_config_route_table_activity(
2490 SCIF_SAS_REMOTE_DEVICE_T * fw_device
2493 //go through the rest of the smp phy list of destination device.
2494 SCI_FAST_LIST_ELEMENT_T * element =
2495 &(fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy->list_element);
2496 SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL;
2497 SCIF_SAS_REMOTE_DEVICE_T * curr_attached_device = NULL;
2500 sci_base_object_get_logger(fw_device),
2501 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
2502 "scif_sas_smp_remote_device_cancel_config_route_table_activity(0x%x) enter\n",
2506 while (element != NULL)
2508 curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element);
2509 element = sci_fast_list_get_next(element);
2511 //check if this phy needs to be added to the expander's route table but can't due to
2512 //exceeding max route index.
2513 if (scif_sas_smp_remote_device_do_config_route_info(
2514 fw_device, curr_smp_phy) == TRUE )
2516 //set the is_currently_discovered to FALSE for attached device. Then when
2517 //domain finish discover, domain will remove this device.
2518 curr_attached_device = (SCIF_SAS_REMOTE_DEVICE_T *)
2519 scif_domain_get_device_by_sas_address(
2520 fw_device->domain, &(curr_smp_phy->attached_sas_address));
2522 if (curr_attached_device != NULL)
2523 curr_attached_device->is_currently_discovered = FALSE;
2530 * @brief This method cancel current activity and terminate the outstanding internal IO
2533 * @param[in] fw_device The expander device, whose smp activity is to be canceled.
2537 void scif_sas_smp_remote_device_cancel_smp_activity(
2538 SCIF_SAS_REMOTE_DEVICE_T * fw_device
2542 sci_base_object_get_logger(fw_device),
2543 SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
2544 "scif_sas_smp_remote_device_cancel_smp_activity(0x%x) enter\n",
2548 //Terminate all of the requests in the silicon for this device.
2549 scif_sas_domain_terminate_requests(
2550 fw_device->domain, fw_device, NULL, NULL
2553 if (fw_device->protocol_device.smp_device.current_activity ==
2554 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE)
2555 scif_sas_smp_remote_device_cancel_config_route_table_activity(fw_device);
2557 //Clear the device to stop the smp sctivity.
2558 scif_sas_smp_remote_device_clear(fw_device);
2563 * @brief This method tells the way to configure route table for a expander. The
2564 * possible ways are: configure phy 0's route table, configure middle
2565 * phy's route table, configure highest order phy's route table,
2566 * configure all phys.
2568 * @param[in] fw_device The expander device, whose config route table method is
2571 * @return one in 4 possible options.
2573 U8 scif_sas_smp_remote_device_get_config_route_table_method(
2574 SCIF_SAS_REMOTE_DEVICE_T * fw_device
2577 U8 config_route_table_method;
2579 //config_route_table_method = SCIF_SAS_CONFIG_ROUTE_TABLE_MIDDLE_PHY_ONLY;
2580 config_route_table_method = SCIF_SAS_CONFIG_ROUTE_TABLE_ALL_PHYS;
2582 return config_route_table_method;
2587 * @brief This method starts the EA target reset process by constructing
2588 * and starting a PHY CONTROL (hard reset) smp request.
2590 * @param[in] expander_device The expander device, to which a PHY Control smp command is
2592 * @param[in] target_device The expander attahced target device, to which the target reset
2594 * @param[in] fw_request The target reset task request.
2598 void scif_sas_smp_remote_device_start_target_reset(
2599 SCIF_SAS_REMOTE_DEVICE_T * expander_device,
2600 SCIF_SAS_REMOTE_DEVICE_T * target_device,
2601 SCIF_SAS_REQUEST_T * fw_request
2604 SCIF_SAS_CONTROLLER_T * fw_controller = expander_device->domain->controller;
2606 //set current_activity and current_smp_request to expander device.
2607 expander_device->protocol_device.smp_device.current_activity =
2608 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_TARGET_RESET;
2609 expander_device->protocol_device.smp_device.current_smp_request =
2610 SMP_FUNCTION_PHY_CONTROL;
2611 expander_device->protocol_device.smp_device.current_activity_phy_index =
2612 target_device->expander_phy_identifier;
2614 //A Phy Control smp request has been constructed towards parent device.
2615 //Walk the high priority io path.
2616 fw_controller->state_handlers->start_high_priority_io_handler(
2617 (SCI_BASE_CONTROLLER_T*) fw_controller,
2618 (SCI_BASE_REMOTE_DEVICE_T*) expander_device,
2619 (SCI_BASE_REQUEST_T*) fw_request,
2620 SCI_CONTROLLER_INVALID_IO_TAG