1230557Sjimharris/*-
2230557Sjimharris * This file is provided under a dual BSD/GPLv2 license.  When using or
3230557Sjimharris * redistributing this file, you may do so under either license.
4230557Sjimharris *
5230557Sjimharris * GPL LICENSE SUMMARY
6230557Sjimharris *
7230557Sjimharris * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
8230557Sjimharris *
9230557Sjimharris * This program is free software; you can redistribute it and/or modify
10230557Sjimharris * it under the terms of version 2 of the GNU General Public License as
11230557Sjimharris * published by the Free Software Foundation.
12230557Sjimharris *
13230557Sjimharris * This program is distributed in the hope that it will be useful, but
14230557Sjimharris * WITHOUT ANY WARRANTY; without even the implied warranty of
15230557Sjimharris * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16230557Sjimharris * General Public License for more details.
17230557Sjimharris *
18230557Sjimharris * You should have received a copy of the GNU General Public License
19230557Sjimharris * along with this program; if not, write to the Free Software
20230557Sjimharris * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
21230557Sjimharris * The full GNU General Public License is included in this distribution
22230557Sjimharris * in the file called LICENSE.GPL.
23230557Sjimharris *
24230557Sjimharris * BSD LICENSE
25230557Sjimharris *
26230557Sjimharris * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
27230557Sjimharris * All rights reserved.
28230557Sjimharris *
29230557Sjimharris * Redistribution and use in source and binary forms, with or without
30230557Sjimharris * modification, are permitted provided that the following conditions
31230557Sjimharris * are met:
32230557Sjimharris *
33230557Sjimharris *   * Redistributions of source code must retain the above copyright
34230557Sjimharris *     notice, this list of conditions and the following disclaimer.
35230557Sjimharris *   * Redistributions in binary form must reproduce the above copyright
36230557Sjimharris *     notice, this list of conditions and the following disclaimer in
37230557Sjimharris *     the documentation and/or other materials provided with the
38230557Sjimharris *     distribution.
39230557Sjimharris *
40230557Sjimharris * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
41230557Sjimharris * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
42230557Sjimharris * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
43230557Sjimharris * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
44230557Sjimharris * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45230557Sjimharris * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
46230557Sjimharris * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
47230557Sjimharris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
48230557Sjimharris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
49230557Sjimharris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
50230557Sjimharris * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51230557Sjimharris */
52230557Sjimharris
53230557Sjimharris#include <sys/cdefs.h>
54230557Sjimharris__FBSDID("$FreeBSD$");
55230557Sjimharris
56230557Sjimharris/**
57230557Sjimharris * @file
58230557Sjimharris *
59230557Sjimharris * @brief This file contains the methods for the SCIF_SAS_SMP_REMOTE_DEVICE object.
60230557Sjimharris */
61230557Sjimharris#include <dev/isci/scil/sci_controller.h>
62230557Sjimharris#include <dev/isci/scil/scif_sas_controller.h>
63230557Sjimharris#include <dev/isci/scil/scif_sas_remote_device.h>
64230557Sjimharris#include <dev/isci/scil/scif_sas_logger.h>
65230557Sjimharris
66230557Sjimharris#include <dev/isci/scil/scif_sas_smp_remote_device.h>
67230557Sjimharris#include <dev/isci/scil/scif_sas_smp_io_request.h>
68230557Sjimharris#include <dev/isci/scil/intel_sas.h>
69230557Sjimharris#include <dev/isci/scil/scic_io_request.h>
70230557Sjimharris#include <dev/isci/scil/scic_remote_device.h>
71230557Sjimharris#include <dev/isci/scil/scif_sas_smp_phy.h>
72230557Sjimharris
73230557Sjimharris
74230557Sjimharris/**
75230557Sjimharris * @brief This method resets all fields for a smp remote device. This is a
76230557Sjimharris *        private method.
77230557Sjimharris *
78230557Sjimharris * @param[in] fw_device the framework SMP device that is being
79230557Sjimharris *            constructed.
80230557Sjimharris *
81230557Sjimharris * @return none
82230557Sjimharris */
83230557Sjimharrisvoid scif_sas_smp_remote_device_clear(
84230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device
85230557Sjimharris)
86230557Sjimharris{
87230557Sjimharris   //reset all fields in smp_device, indicate that the smp device is not
88230557Sjimharris   //in discovery process.
89230557Sjimharris   fw_device->protocol_device.smp_device.current_activity =
90230557Sjimharris      SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE;
91230557Sjimharris
92230557Sjimharris   fw_device->protocol_device.smp_device.current_smp_request =
93230557Sjimharris      NOT_IN_SMP_ACTIVITY;
94230557Sjimharris
95230557Sjimharris   fw_device->protocol_device.smp_device.current_activity_phy_index = 0;
96230557Sjimharris
97230557Sjimharris   fw_device->protocol_device.smp_device.curr_config_route_index = 0;
98230557Sjimharris
99230557Sjimharris   fw_device->protocol_device.smp_device.config_route_smp_phy_anchor = NULL;
100230557Sjimharris
101230557Sjimharris   fw_device->protocol_device.smp_device.is_route_table_cleaned = FALSE;
102230557Sjimharris
103230557Sjimharris   fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy = NULL;
104230557Sjimharris
105230557Sjimharris   fw_device->protocol_device.smp_device.scheduled_activity =
106230557Sjimharris      SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE;
107230557Sjimharris
108230557Sjimharris   fw_device->protocol_device.smp_device.io_retry_count = 0;
109230557Sjimharris
110230557Sjimharris   fw_device->protocol_device.smp_device.curr_clear_affiliation_phy = NULL;
111230557Sjimharris
112230557Sjimharris   if (fw_device->protocol_device.smp_device.smp_activity_timer != NULL)
113230557Sjimharris   {
114230557Sjimharris      //stop the timer
115230557Sjimharris      scif_cb_timer_stop(
116230557Sjimharris         fw_device->domain->controller,
117230557Sjimharris         fw_device->protocol_device.smp_device.smp_activity_timer
118230557Sjimharris      );
119230557Sjimharris
120230557Sjimharris      //destroy the timer
121230557Sjimharris      scif_cb_timer_destroy(
122230557Sjimharris         fw_device->domain->controller,
123230557Sjimharris         fw_device->protocol_device.smp_device.smp_activity_timer
124230557Sjimharris      );
125230557Sjimharris
126230557Sjimharris      fw_device->protocol_device.smp_device.smp_activity_timer = NULL;
127230557Sjimharris   }
128230557Sjimharris}
129230557Sjimharris
130230557Sjimharris
131230557Sjimharris/**
132230557Sjimharris * @brief This method intializes a smp remote device.
133230557Sjimharris *
134230557Sjimharris * @param[in] fw_device the framework SMP device that is being
135230557Sjimharris *            constructed.
136230557Sjimharris *
137230557Sjimharris * @return none
138230557Sjimharris */
139230557Sjimharrisvoid scif_sas_smp_remote_device_construct(
140230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device
141230557Sjimharris)
142230557Sjimharris{
143230557Sjimharris   SCIF_LOG_TRACE((
144230557Sjimharris      sci_base_object_get_logger(fw_device),
145230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE,
146230557Sjimharris      "scif_sas_smp_remote_device_construct(0x%x) enter\n",
147230557Sjimharris      fw_device
148230557Sjimharris   ));
149230557Sjimharris
150230557Sjimharris   fw_device->protocol_device.smp_device.number_of_phys = 0;
151230557Sjimharris   fw_device->protocol_device.smp_device.expander_route_indexes = 0;
152230557Sjimharris   fw_device->protocol_device.smp_device.is_table_to_table_supported = FALSE;
153230557Sjimharris   fw_device->protocol_device.smp_device.is_externally_configurable  = FALSE;
154230557Sjimharris   fw_device->protocol_device.smp_device.is_able_to_config_others    = FALSE;
155230557Sjimharris
156230557Sjimharris   sci_fast_list_init(&fw_device->protocol_device.smp_device.smp_phy_list);
157230557Sjimharris
158230557Sjimharris   scif_sas_smp_remote_device_clear(fw_device);
159230557Sjimharris}
160230557Sjimharris
161230557Sjimharris
162230557Sjimharris/**
163230557Sjimharris * @brief This method decodes a smp response to this smp device and then
164230557Sjimharris *        continue the smp discover process.
165230557Sjimharris *
166230557Sjimharris * @param[in] fw_device The framework device that a SMP response targets to.
167230557Sjimharris * @param[in] fw_request The pointer to an smp request whose response
168230557Sjimharris *       is to be decoded.
169230557Sjimharris * @param[in] response_data The response data passed in.
170230557Sjimharris *
171230557Sjimharris * @return none
172230557Sjimharris */
173230557SjimharrisSCI_STATUS scif_sas_smp_remote_device_decode_smp_response(
174230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
175230557Sjimharris   SCIF_SAS_REQUEST_T       * fw_request,
176230557Sjimharris   void                     * response_data,
177230557Sjimharris   SCI_IO_STATUS              completion_status
178230557Sjimharris)
179230557Sjimharris{
180230557Sjimharris   SMP_RESPONSE_T * smp_response = (SMP_RESPONSE_T *)response_data;
181230557Sjimharris   SCI_STATUS       status       = SCI_FAILURE_UNSUPPORTED_INFORMATION_TYPE;
182230557Sjimharris
183230557Sjimharris   if (fw_device->protocol_device.smp_device.smp_activity_timer != NULL)
184230557Sjimharris   {
185230557Sjimharris      //if there is a timer being used, recycle it now. Since we may
186230557Sjimharris      //use the timer for other purpose next.
187230557Sjimharris      scif_cb_timer_destroy(
188230557Sjimharris         fw_device->domain->controller,
189230557Sjimharris         fw_device->protocol_device.smp_device.smp_activity_timer
190230557Sjimharris      );
191230557Sjimharris
192230557Sjimharris      fw_device->protocol_device.smp_device.smp_activity_timer = NULL;
193230557Sjimharris   }
194230557Sjimharris
195230557Sjimharris   //if Core set the status of this io to be RETRY_REQUIRED, we should
196230557Sjimharris   //retry the IO without even decode the response.
197230557Sjimharris   if (completion_status == SCI_FAILURE_RETRY_REQUIRED)
198230557Sjimharris   {
199230557Sjimharris      scif_sas_smp_remote_device_continue_current_activity(
200230557Sjimharris         fw_device, fw_request, SCI_FAILURE_RETRY_REQUIRED
201230557Sjimharris      );
202230557Sjimharris
203230557Sjimharris      return SCI_FAILURE_RETRY_REQUIRED;
204230557Sjimharris   }
205230557Sjimharris
206230557Sjimharris   //check the current smp request, decide what's next smp request to issue.
207230557Sjimharris   switch (fw_device->protocol_device.smp_device.current_smp_request)
208230557Sjimharris   {
209230557Sjimharris      case SMP_FUNCTION_REPORT_GENERAL:
210230557Sjimharris      {
211230557Sjimharris         //interpret REPORT GENERAL response.
212230557Sjimharris         status = scif_sas_smp_remote_device_decode_report_general_response(
213230557Sjimharris            fw_device, smp_response
214230557Sjimharris         );
215230557Sjimharris
216230557Sjimharris         break;
217230557Sjimharris      }
218230557Sjimharris
219230557Sjimharris      case SMP_FUNCTION_REPORT_MANUFACTURER_INFORMATION:
220230557Sjimharris      {
221230557Sjimharris         // No need to perform any parsing.  Just want to see
222230557Sjimharris         // the information in a trace if necessary.
223230557Sjimharris         status = SCI_SUCCESS;
224230557Sjimharris         break;
225230557Sjimharris      }
226230557Sjimharris
227230557Sjimharris      case SMP_FUNCTION_DISCOVER:
228230557Sjimharris      {
229230557Sjimharris         if (fw_device->protocol_device.smp_device.current_activity ==
230230557Sjimharris                SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER)
231230557Sjimharris         {
232230557Sjimharris            //decode discover response
233230557Sjimharris            status = scif_sas_smp_remote_device_decode_initial_discover_response(
234230557Sjimharris                        fw_device, smp_response
235230557Sjimharris                     );
236230557Sjimharris         }
237230557Sjimharris         else if (fw_device->protocol_device.smp_device.current_activity ==
238230557Sjimharris                  SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_TARGET_RESET)
239230557Sjimharris         {
240230557Sjimharris            //decode discover response as a polling result for a remote device
241230557Sjimharris            //target reset.
242230557Sjimharris            status =
243230557Sjimharris               scif_sas_smp_remote_device_decode_target_reset_discover_response(
244230557Sjimharris                  fw_device, smp_response
245230557Sjimharris               );
246230557Sjimharris         }
247230557Sjimharris         else if (fw_device->protocol_device.smp_device.current_activity ==
248230557Sjimharris                SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_SATA_SPINUP_HOLD_RELEASE)
249230557Sjimharris         {
250230557Sjimharris            //decode discover response
251230557Sjimharris            status =
252230557Sjimharris               scif_sas_smp_remote_device_decode_spinup_hold_release_discover_response(
253230557Sjimharris                  fw_device, smp_response
254230557Sjimharris               );
255230557Sjimharris         }
256230557Sjimharris         else
257230557Sjimharris            ASSERT(0);
258230557Sjimharris         break;
259230557Sjimharris      }
260230557Sjimharris
261230557Sjimharris      case SMP_FUNCTION_REPORT_PHY_SATA:
262230557Sjimharris      {
263230557Sjimharris         //decode the report phy sata response.
264230557Sjimharris         status = scif_sas_smp_remote_device_decode_report_phy_sata_response(
265230557Sjimharris            fw_device, smp_response
266230557Sjimharris         );
267230557Sjimharris
268230557Sjimharris         break;
269230557Sjimharris      }
270230557Sjimharris
271230557Sjimharris      case SMP_FUNCTION_PHY_CONTROL:
272230557Sjimharris      {
273230557Sjimharris         if (fw_device->protocol_device.smp_device.current_activity ==
274230557Sjimharris                SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER)
275230557Sjimharris         {
276230557Sjimharris            //decode the phy control response.
277230557Sjimharris            status = scif_sas_smp_remote_device_decode_discover_phy_control_response(
278230557Sjimharris                        fw_device, smp_response
279230557Sjimharris                     );
280230557Sjimharris         }
281230557Sjimharris         else if (fw_device->protocol_device.smp_device.current_activity ==
282230557Sjimharris                     SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_TARGET_RESET)
283230557Sjimharris         {
284230557Sjimharris            //decode discover response as a polling result for a remote device
285230557Sjimharris            //target reset.
286230557Sjimharris            status = scif_sas_smp_remote_device_decode_target_reset_phy_control_response(
287230557Sjimharris                        fw_device, smp_response
288230557Sjimharris                     );
289230557Sjimharris         }
290230557Sjimharris         else if (fw_device->protocol_device.smp_device.current_activity ==
291230557Sjimharris                     SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAR_AFFILIATION)
292230557Sjimharris         {
293230557Sjimharris            //currently don't care about the status.
294230557Sjimharris            status = SCI_SUCCESS;
295230557Sjimharris         }
296230557Sjimharris         else
297230557Sjimharris            ASSERT(0);
298230557Sjimharris         break;
299230557Sjimharris      }
300230557Sjimharris
301230557Sjimharris      case SMP_FUNCTION_CONFIGURE_ROUTE_INFORMATION:
302230557Sjimharris      {
303230557Sjimharris         //Note, currently we don't expect any abnormal status from config route info response,
304230557Sjimharris         //but there is a possibility that we exceed the maximum route index. We will take care
305230557Sjimharris         //of errors later.
306230557Sjimharris         status = scif_sas_smp_remote_device_decode_config_route_info_response(
307230557Sjimharris                     fw_device, smp_response
308230557Sjimharris                  );
309230557Sjimharris         break;
310230557Sjimharris      }
311230557Sjimharris
312230557Sjimharris      default:
313230557Sjimharris         //unsupported case, TBD
314230557Sjimharris         status = SCI_FAILURE_UNSUPPORTED_INFORMATION_TYPE;
315230557Sjimharris         break;
316230557Sjimharris   } //end of switch
317230557Sjimharris
318230557Sjimharris   //Continue current activity based on response's decoding status.
319230557Sjimharris   scif_sas_smp_remote_device_continue_current_activity(
320230557Sjimharris      fw_device, fw_request, status
321230557Sjimharris   );
322230557Sjimharris
323230557Sjimharris   return status;
324230557Sjimharris}
325230557Sjimharris
326230557Sjimharris
327230557Sjimharris/**
328230557Sjimharris * @brief This method decodes a smp Report Genernal response to this smp device
329230557Sjimharris *        and then continue the smp discover process.
330230557Sjimharris *
331230557Sjimharris * @param[in] fw_device The framework device that the REPORT GENERAL command
332230557Sjimharris *       targets to.
333230557Sjimharris * @param[in] report_general_response The pointer to a report general response
334230557Sjimharris *
335230557Sjimharris * @return none
336230557Sjimharris */
337230557SjimharrisSCI_STATUS scif_sas_smp_remote_device_decode_report_general_response(
338230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
339230557Sjimharris   SMP_RESPONSE_T           * smp_response
340230557Sjimharris)
341230557Sjimharris{
342230557Sjimharris   SMP_RESPONSE_REPORT_GENERAL_T * report_general_response =
343230557Sjimharris      &smp_response->response.report_general;
344230557Sjimharris
345230557Sjimharris   SMP_RESPONSE_HEADER_T * response_header = &smp_response->header;
346230557Sjimharris
347230557Sjimharris   SCIF_LOG_TRACE((
348230557Sjimharris      sci_base_object_get_logger(fw_device),
349230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
350230557Sjimharris      "scif_sas_smp_remote_device_decode_report_general_response(0x%x, 0x%x) enter\n",
351230557Sjimharris      fw_device, smp_response
352230557Sjimharris   ));
353230557Sjimharris
354230557Sjimharris   if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
355230557Sjimharris   {
356230557Sjimharris      /// @todo: more decoding work needed when the function_result is not
357230557Sjimharris      /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some
358230557Sjimharris      /// function result.
359230557Sjimharris      SCIF_LOG_ERROR((
360230557Sjimharris         sci_base_object_get_logger(fw_device),
361230557Sjimharris         SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
362230557Sjimharris         "Report General function result(0x%x)\n",
363230557Sjimharris         response_header->function_result
364230557Sjimharris      ));
365230557Sjimharris
366230557Sjimharris      return SCI_FAILURE;
367230557Sjimharris   }
368230557Sjimharris
369230557Sjimharris   //get info from report general response.
370230557Sjimharris   fw_device->protocol_device.smp_device.number_of_phys =
371230557Sjimharris      (U8)report_general_response->number_of_phys;
372230557Sjimharris
373230557Sjimharris   //currently there is byte swap issue in U16 data.
374230557Sjimharris   fw_device->protocol_device.smp_device.expander_route_indexes =
375230557Sjimharris      ((report_general_response->expander_route_indexes & 0xff) << 8) |
376230557Sjimharris      ((report_general_response->expander_route_indexes & 0xff00) >> 8);
377230557Sjimharris
378230557Sjimharris   fw_device->protocol_device.smp_device.is_table_to_table_supported =
379230557Sjimharris      (BOOL)report_general_response->table_to_table_supported;
380230557Sjimharris
381230557Sjimharris   fw_device->protocol_device.smp_device.is_externally_configurable =
382230557Sjimharris      (BOOL)report_general_response->configurable_route_table;
383230557Sjimharris
384230557Sjimharris   fw_device->protocol_device.smp_device.is_able_to_config_others =
385230557Sjimharris      (BOOL)report_general_response->configures_others;
386230557Sjimharris
387230557Sjimharris   //If the top level expander of a domain is able to configure others,
388230557Sjimharris   //no config route table is needed in the domain. Or else,
389230557Sjimharris   //we'll let all the externally configurable expanders in the damain
390230557Sjimharris   //configure route table.
391230557Sjimharris   if (fw_device->containing_device == NULL
392230557Sjimharris       && ! fw_device->protocol_device.smp_device.is_able_to_config_others)
393230557Sjimharris      fw_device->domain->is_config_route_table_needed = TRUE;
394230557Sjimharris
395230557Sjimharris   //knowing number of phys this expander has, we can allocate all the smp phys for
396230557Sjimharris   //this expander now if it is not done already.
397230557Sjimharris   if (fw_device->protocol_device.smp_device.smp_phy_list.element_count == 0)
398230557Sjimharris      scif_sas_smp_remote_device_populate_smp_phy_list(fw_device);
399230557Sjimharris
400230557Sjimharris   if (report_general_response->configuring)
401230557Sjimharris      return SCI_FAILURE_RETRY_REQUIRED;
402230557Sjimharris
403230557Sjimharris   return SCI_SUCCESS;
404230557Sjimharris}
405230557Sjimharris
406230557Sjimharris
407230557Sjimharris/**
408230557Sjimharris * @brief This method decodes a smp Discover response to this smp device
409230557Sjimharris *        and then continue the smp discover process. This is only ever
410230557Sjimharris *        called for the very first discover stage during a given domain
411230557Sjimharris *        discovery process.
412230557Sjimharris *
413230557Sjimharris * @param[in] fw_device The framework device that the DISCOVER command
414230557Sjimharris *       targets to.
415230557Sjimharris * @param[in] discover_response The pointer to a DISCOVER response
416230557Sjimharris *
417230557Sjimharris * @return none
418230557Sjimharris */
419230557SjimharrisSCI_STATUS scif_sas_smp_remote_device_decode_initial_discover_response(
420230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
421230557Sjimharris   SMP_RESPONSE_T           * smp_response
422230557Sjimharris)
423230557Sjimharris{
424230557Sjimharris   SCIF_SAS_DOMAIN_T        * fw_domain = fw_device->domain;
425230557Sjimharris   SCI_SAS_ADDRESS_T          attached_device_address;
426230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * attached_remote_device;
427230557Sjimharris   SMP_RESPONSE_DISCOVER_T  * discover_response =
428230557Sjimharris      &smp_response->response.discover;
429230557Sjimharris   SMP_RESPONSE_HEADER_T    * response_header = &smp_response->header;
430230557Sjimharris
431230557Sjimharris   SCIF_LOG_TRACE((
432230557Sjimharris      sci_base_object_get_logger(fw_device),
433230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
434230557Sjimharris      "scif_sas_smp_remote_device_decode_initial_discover_response(0x%x, 0x%x) enter\n",
435230557Sjimharris      fw_device, smp_response
436230557Sjimharris   ));
437230557Sjimharris
438230557Sjimharris   if (response_header->function_result == SMP_RESULT_PHY_VACANT)
439230557Sjimharris   {
440230557Sjimharris      return SCI_SUCCESS;
441230557Sjimharris   }
442230557Sjimharris   else if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
443230557Sjimharris   {
444230557Sjimharris      /// @todo: more decoding work needed when the function_result is not
445230557Sjimharris      /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some
446230557Sjimharris      /// function result.
447230557Sjimharris      SCIF_LOG_ERROR((
448230557Sjimharris         sci_base_object_get_logger(fw_device),
449230557Sjimharris         SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
450230557Sjimharris         "Discover function result(0x%x)\n",
451230557Sjimharris         response_header->function_result
452230557Sjimharris      ));
453230557Sjimharris
454230557Sjimharris      return SCI_FAILURE;
455230557Sjimharris   }
456230557Sjimharris
457230557Sjimharris   //only if there is target device attached. We don't add device that is
458230557Sjimharris   //initiator only.
459230557Sjimharris   if ( ( discover_response->u2.sas1_1.attached_device_type
460230557Sjimharris             != SMP_NO_DEVICE_ATTACHED )
461230557Sjimharris       && ( discover_response->protocols.u.bits.attached_ssp_target
462230557Sjimharris           || discover_response->protocols.u.bits.attached_stp_target
463230557Sjimharris           || discover_response->protocols.u.bits.attached_smp_target
464230557Sjimharris           || discover_response->protocols.u.bits.attached_sata_device ) )
465230557Sjimharris   {
466230557Sjimharris      attached_device_address = discover_response->attached_sas_address;
467230557Sjimharris
468230557Sjimharris      attached_remote_device = (SCIF_SAS_REMOTE_DEVICE_T *)
469230557Sjimharris         scif_domain_get_device_by_sas_address(
470230557Sjimharris            fw_domain, &attached_device_address
471230557Sjimharris         );
472230557Sjimharris
473230557Sjimharris      //need to check if the device already existed in the domian.
474230557Sjimharris      if (attached_remote_device != SCI_INVALID_HANDLE)
475230557Sjimharris      {
476230557Sjimharris#if !defined(DISABLE_WIDE_PORTED_TARGETS)
477230557Sjimharris         if ( attached_remote_device->is_currently_discovered == TRUE
478230557Sjimharris             && attached_remote_device != fw_device->containing_device )
479230557Sjimharris         {
480230557Sjimharris            //a downstream wide port target is found.
481230557Sjimharris            attached_remote_device->device_port_width++;
482230557Sjimharris         }
483230557Sjimharris         else
484230557Sjimharris#endif //#if !defined(DISABLE_WIDE_PORTED_TARGETS)
485230557Sjimharris         {
486230557Sjimharris            //The device already existed. Mark the device as discovered.
487230557Sjimharris            attached_remote_device->is_currently_discovered = TRUE;
488230557Sjimharris         }
489230557Sjimharris
490230557Sjimharris#if !defined(DISABLE_WIDE_PORTED_TARGETS)
491230557Sjimharris         if (attached_remote_device->device_port_width !=
492230557Sjimharris                scic_remote_device_get_port_width(attached_remote_device->core_object)
493230557Sjimharris             && discover_response->protocols.u.bits.attached_ssp_target
494230557Sjimharris            )
495230557Sjimharris         {
496230557Sjimharris            scif_sas_remote_device_update_port_width(
497230557Sjimharris               attached_remote_device, attached_remote_device->device_port_width);
498230557Sjimharris         }
499230557Sjimharris#endif //#if !defined(DISABLE_WIDE_PORTED_TARGETS)
500230557Sjimharris
501230557Sjimharris         if ( discover_response->protocols.u.bits.attached_smp_target
502230557Sjimharris             && attached_remote_device != fw_device->containing_device)
503230557Sjimharris         {
504230557Sjimharris            //another expander device is discovered. Its own smp discover will starts after
505230557Sjimharris            //this discover finishes.
506230557Sjimharris            attached_remote_device->protocol_device.smp_device.scheduled_activity =
507230557Sjimharris               SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER;
508230557Sjimharris         }
509230557Sjimharris      }
510230557Sjimharris      else
511230557Sjimharris      {
512230557Sjimharris         //report the discovery of a disk for all types of end device.
513230557Sjimharris         scif_cb_domain_ea_device_added(
514230557Sjimharris            fw_domain->controller, fw_domain, fw_device, discover_response
515230557Sjimharris         );
516230557Sjimharris
517230557Sjimharris         //get info from discover response to see what we found. And do
518230557Sjimharris         //extra work according to end device's protocol type.
519230557Sjimharris         if ( discover_response->protocols.u.bits.attached_ssp_target
520230557Sjimharris             || discover_response->protocols.u.bits.attached_smp_target)
521230557Sjimharris         {
522230557Sjimharris            //for SSP or SMP target, no extra work.
523230557Sjimharris            ;
524230557Sjimharris         }
525230557Sjimharris         else if (  (discover_response->protocols.u.bits.attached_stp_target)
526230557Sjimharris                 || (discover_response->protocols.u.bits.attached_sata_device) )
527230557Sjimharris         {
528230557Sjimharris            // We treat a SATA Device bit the same as an attached STP
529230557Sjimharris            // target.
530230557Sjimharris            discover_response->protocols.u.bits.attached_stp_target = 1;
531230557Sjimharris
532230557Sjimharris            //kick off REPORT PHY SATA to the same phy.
533230557Sjimharris            fw_device->protocol_device.smp_device.current_smp_request =
534230557Sjimharris               SMP_FUNCTION_REPORT_PHY_SATA;
535230557Sjimharris         }
536230557Sjimharris      }
537230557Sjimharris   }
538230557Sjimharris   else if( (discover_response->u2.sas1_1.negotiated_physical_link_rate == SCI_SATA_SPINUP_HOLD
539230557Sjimharris             || discover_response->u4.sas2.negotiated_physical_link_rate == SCI_SATA_SPINUP_HOLD)
540230557Sjimharris          &&(discover_response->protocols.u.bits.attached_stp_target
541230557Sjimharris             || discover_response->protocols.u.bits.attached_sata_device)
542230557Sjimharris          )
543230557Sjimharris   {
544230557Sjimharris      attached_remote_device = scif_sas_domain_get_device_by_containing_device(
545230557Sjimharris                                  fw_domain,
546230557Sjimharris                                  fw_device,
547230557Sjimharris                                  discover_response->phy_identifier
548230557Sjimharris                               );
549230557Sjimharris
550230557Sjimharris      if (attached_remote_device != SCI_INVALID_HANDLE)
551230557Sjimharris      {
552230557Sjimharris         //Here, the only reason a device already existed in domain but
553230557Sjimharris         //the initial discover rersponse shows it in SPINUP_HOLD, is that
554230557Sjimharris         //a device has been removed and coming back in SPINUP_HOLD before
555230557Sjimharris         //we detected. The possibility of this situation is very very rare.
556230557Sjimharris         //we need to remove the device then add it back using the new
557230557Sjimharris         //discover response.
558230557Sjimharris         scif_cb_domain_device_removed(
559230557Sjimharris            fw_domain->controller, fw_domain, attached_remote_device
560230557Sjimharris         );
561230557Sjimharris      }
562230557Sjimharris
563230557Sjimharris      discover_response->protocols.u.bits.attached_stp_target = 1;
564230557Sjimharris
565230557Sjimharris      //still report ea_device_added(). But this device will not be
566230557Sjimharris      //started during scif_remote_device_ea_construct().
567230557Sjimharris      scif_cb_domain_ea_device_added(
568230557Sjimharris         fw_domain->controller, fw_domain, fw_device, discover_response
569230557Sjimharris      );
570230557Sjimharris
571230557Sjimharris      //need to send Phy Control (RESET) to release the phy from spinup hold
572230557Sjimharris      //condition.
573230557Sjimharris      fw_device->protocol_device.smp_device.current_smp_request =
574230557Sjimharris         SMP_FUNCTION_PHY_CONTROL;
575230557Sjimharris   }
576230557Sjimharris
577230557Sjimharris   //update the smp phy info based on this DISCOVER response.
578230557Sjimharris   return scif_sas_smp_remote_device_save_smp_phy_info(
579230557Sjimharris             fw_device, discover_response);
580230557Sjimharris}
581230557Sjimharris
582230557Sjimharris
583230557Sjimharris/**
584230557Sjimharris * @brief This method decodes a smp Report Phy Sata response to this
585230557Sjimharris *        smp device and then continue the smp discover process.
586230557Sjimharris *
587230557Sjimharris * @param[in] fw_device The framework device that the REPORT PHY SATA
588230557Sjimharris *       command targets to.
589230557Sjimharris * @param[in] report_phy_sata_response The pointer to a REPORT PHY
590230557Sjimharris *       SATA response
591230557Sjimharris *
592230557Sjimharris * @return none
593230557Sjimharris */
594230557SjimharrisSCI_STATUS scif_sas_smp_remote_device_decode_report_phy_sata_response(
595230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
596230557Sjimharris   SMP_RESPONSE_T           * smp_response
597230557Sjimharris)
598230557Sjimharris{
599230557Sjimharris   SMP_RESPONSE_REPORT_PHY_SATA_T * report_phy_sata_response =
600230557Sjimharris      &smp_response->response.report_phy_sata;
601230557Sjimharris
602230557Sjimharris   SMP_RESPONSE_HEADER_T * response_header = &smp_response->header;
603230557Sjimharris
604230557Sjimharris   SCIF_LOG_TRACE((
605230557Sjimharris      sci_base_object_get_logger(fw_device),
606230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
607230557Sjimharris      "scif_sas_smp_remote_device_decode_report_phy_sata_response(0x%x, 0x%x) enter\n",
608230557Sjimharris      fw_device, smp_response
609230557Sjimharris   ));
610230557Sjimharris
611230557Sjimharris   if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
612230557Sjimharris   {
613230557Sjimharris      /// @todo: more decoding work needed when the function_result is not
614230557Sjimharris      /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some
615230557Sjimharris      /// function result.
616230557Sjimharris      SCIF_LOG_ERROR((
617230557Sjimharris         sci_base_object_get_logger(fw_device),
618230557Sjimharris         SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
619230557Sjimharris         "Report Phy Sata function result(0x%x)\n",
620230557Sjimharris         response_header->function_result
621230557Sjimharris      ));
622230557Sjimharris
623230557Sjimharris      return SCI_FAILURE;
624230557Sjimharris   }
625230557Sjimharris
626230557Sjimharris   scif_sas_remote_device_save_report_phy_sata_information(
627230557Sjimharris      report_phy_sata_response
628230557Sjimharris   );
629230557Sjimharris
630230557Sjimharris   // continue the discover process.
631230557Sjimharris   fw_device->protocol_device.smp_device.current_smp_request =
632230557Sjimharris      SMP_FUNCTION_DISCOVER;
633230557Sjimharris
634230557Sjimharris   return SCI_SUCCESS;
635230557Sjimharris}
636230557Sjimharris
637230557Sjimharris
638230557Sjimharris/**
639230557Sjimharris * @brief This method decodes a smp Phy Control response to this smp device and
640230557Sjimharris *        then continue the smp TARGET RESET process.
641230557Sjimharris *
642230557Sjimharris * @param[in] fw_device The framework device that the Phy Control command
643230557Sjimharris *       targets to.
644230557Sjimharris * @param[in] smp_response The pointer to a Phy Control response
645230557Sjimharris * @param[in] fw_io The scif IO request that associates to this smp response.
646230557Sjimharris *
647230557Sjimharris * @return none
648230557Sjimharris */
649230557SjimharrisSCI_STATUS scif_sas_smp_remote_device_decode_target_reset_phy_control_response(
650230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
651230557Sjimharris   SMP_RESPONSE_T           * smp_response
652230557Sjimharris)
653230557Sjimharris{
654230557Sjimharris   SMP_RESPONSE_HEADER_T * response_header = &smp_response->header;
655230557Sjimharris
656230557Sjimharris   SCI_STATUS status = SCI_SUCCESS;
657230557Sjimharris
658230557Sjimharris   SCIF_LOG_TRACE((
659230557Sjimharris      sci_base_object_get_logger(fw_device),
660230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
661230557Sjimharris      "scif_sas_smp_remote_device_decode_target_reset_phy_control_response(0x%x, 0x%x) enter\n",
662230557Sjimharris      fw_device, smp_response
663230557Sjimharris   ));
664230557Sjimharris
665230557Sjimharris   if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
666230557Sjimharris   {
667230557Sjimharris      /// @todo: more decoding work needed when the function_result is not
668230557Sjimharris      /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some
669230557Sjimharris      /// function result.
670230557Sjimharris      SCIF_LOG_ERROR((
671230557Sjimharris         sci_base_object_get_logger(fw_device),
672230557Sjimharris         SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
673230557Sjimharris         "Phy Control function unaccepted result(0x%x)\n",
674230557Sjimharris         response_header->function_result
675230557Sjimharris      ));
676230557Sjimharris
677230557Sjimharris      status = SCI_FAILURE_RETRY_REQUIRED;
678230557Sjimharris   }
679230557Sjimharris
680230557Sjimharris   // phy Control succeeded.
681230557Sjimharris   return status;
682230557Sjimharris}
683230557Sjimharris
684230557Sjimharris/**
685230557Sjimharris * @brief This method decodes a smp Phy Control response to this smp device and
686230557Sjimharris *        then continue the smp DISCOVER process.
687230557Sjimharris *
688230557Sjimharris * @param[in] fw_device The framework device that the Phy Control command
689230557Sjimharris *       targets to.
690230557Sjimharris * @param[in] smp_response The pointer to a Phy Control response
691230557Sjimharris *
692230557Sjimharris * @return Almost always SCI_SUCCESS
693230557Sjimharris */
694230557SjimharrisSCI_STATUS scif_sas_smp_remote_device_decode_discover_phy_control_response(
695230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
696230557Sjimharris   SMP_RESPONSE_T           * smp_response
697230557Sjimharris)
698230557Sjimharris{
699230557Sjimharris   SMP_RESPONSE_HEADER_T * response_header = &smp_response->header;
700230557Sjimharris
701230557Sjimharris   SCI_STATUS status = SCI_SUCCESS;
702230557Sjimharris
703230557Sjimharris   SCIF_LOG_TRACE((
704230557Sjimharris      sci_base_object_get_logger(fw_device),
705230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
706230557Sjimharris      "scif_sas_smp_remote_device_decode_discover_phy_control_response(0x%x, 0x%x) enter\n",
707230557Sjimharris      fw_device, smp_response
708230557Sjimharris   ));
709230557Sjimharris
710230557Sjimharris   if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
711230557Sjimharris   {
712230557Sjimharris      /// @todo: more decoding work needed when the function_result is not
713230557Sjimharris      /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some
714230557Sjimharris      /// function result.
715230557Sjimharris      SCIF_LOG_ERROR((
716230557Sjimharris         sci_base_object_get_logger(fw_device),
717230557Sjimharris         SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
718230557Sjimharris         "Phy Control function unaccepted result(0x%x)\n",
719230557Sjimharris         response_header->function_result
720230557Sjimharris      ));
721230557Sjimharris
722230557Sjimharris      return SCI_FAILURE_RETRY_REQUIRED;
723230557Sjimharris   }
724230557Sjimharris
725230557Sjimharris   // continue the discover process.
726230557Sjimharris   fw_device->protocol_device.smp_device.current_smp_request =
727230557Sjimharris      SMP_FUNCTION_DISCOVER;
728230557Sjimharris
729230557Sjimharris   // phy Control succeeded.
730230557Sjimharris   return status;
731230557Sjimharris}
732230557Sjimharris
733230557Sjimharris
734230557Sjimharris/**
735230557Sjimharris * @brief This method decodes a smp Discover response to this smp device
736230557Sjimharris *        and then continue the smp discover process.
737230557Sjimharris *
738230557Sjimharris * @param[in] fw_device The framework device that the DISCOVER command
739230557Sjimharris *       targets to.
740230557Sjimharris * @param[in] discover_response The pointer to a DISCOVER response
741230557Sjimharris *
742230557Sjimharris * @return none
743230557Sjimharris */
744230557SjimharrisSCI_STATUS scif_sas_smp_remote_device_decode_target_reset_discover_response(
745230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
746230557Sjimharris   SMP_RESPONSE_T           * smp_response
747230557Sjimharris)
748230557Sjimharris{
749230557Sjimharris   SCIF_SAS_DOMAIN_T  * fw_domain;
750230557Sjimharris   SCI_SAS_ADDRESS_T attached_device_address;
751230557Sjimharris   SMP_RESPONSE_DISCOVER_T * discover_response =
752230557Sjimharris      &smp_response->response.discover;
753230557Sjimharris
754230557Sjimharris   SMP_RESPONSE_HEADER_T * response_header = &smp_response->header;
755230557Sjimharris
756230557Sjimharris   SCIF_LOG_TRACE((
757230557Sjimharris      sci_base_object_get_logger(fw_device),
758230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
759230557Sjimharris      "scif_sas_smp_remote_device_decode_target_reset_discover_response(0x%x, 0x%x) enter\n",
760230557Sjimharris      fw_device, smp_response
761230557Sjimharris   ));
762230557Sjimharris
763230557Sjimharris   if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
764230557Sjimharris   {
765230557Sjimharris      /// @todo: more decoding work needed when the function_result is not
766230557Sjimharris      /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some
767230557Sjimharris      /// function result.
768230557Sjimharris      SCIF_LOG_ERROR((
769230557Sjimharris         sci_base_object_get_logger(fw_device),
770230557Sjimharris         SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
771230557Sjimharris         "Discover function result(0x%x)\n",
772230557Sjimharris         response_header->function_result
773230557Sjimharris      ));
774230557Sjimharris
775230557Sjimharris      return SCI_FAILURE_RETRY_REQUIRED;
776230557Sjimharris   }
777230557Sjimharris
778230557Sjimharris   //only if there is device attached.
779230557Sjimharris   if ( discover_response->u2.sas1_1.attached_device_type != SMP_NO_DEVICE_ATTACHED )
780230557Sjimharris   {
781230557Sjimharris      fw_domain = fw_device->domain;
782230557Sjimharris      attached_device_address = discover_response->attached_sas_address;
783230557Sjimharris
784230557Sjimharris      // the device should have already existed in the domian.
785231137Sjimharris      ASSERT(scif_domain_get_device_by_sas_address(
786231137Sjimharris                fw_domain,
787231137Sjimharris                &attached_device_address
788231137Sjimharris             ) != SCI_INVALID_HANDLE);
789230557Sjimharris      return SCI_SUCCESS;
790230557Sjimharris   }
791230557Sjimharris   else
792230557Sjimharris      return SCI_FAILURE_RETRY_REQUIRED;
793230557Sjimharris}
794230557Sjimharris
795230557Sjimharris/**
796230557Sjimharris * @brief This method decodes a smp Discover response to this smp device
797230557Sjimharris *        for SPINUP_HOLD_RELEASE activity. If a DISCOVER response says
798230557Sjimharris *        SATA DEVICE ATTACHED and has a valid NPL value, we call fw_device's
799230557Sjimharris *        start_handler(). But if a DISCOVER response still shows SPINUP
800230557Sjimharris *        in NPL state, we need to return retry_required status
801230557Sjimharris *
802230557Sjimharris * @param[in] fw_device The framework device that the DISCOVER command
803230557Sjimharris *       targets to.
804230557Sjimharris * @param[in] discover_response The pointer to a DISCOVER response
805230557Sjimharris *
806230557Sjimharris * @return SCI_SUCCESS
807230557Sjimharris *         SCI_FAILURE_RETRY_REQUIRED
808230557Sjimharris */
809230557SjimharrisSCI_STATUS scif_sas_smp_remote_device_decode_spinup_hold_release_discover_response(
810230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
811230557Sjimharris   SMP_RESPONSE_T           * smp_response
812230557Sjimharris)
813230557Sjimharris{
814230557Sjimharris   SMP_RESPONSE_DISCOVER_T * discover_response = &smp_response->response.discover;
815230557Sjimharris
816230557Sjimharris   SMP_RESPONSE_HEADER_T * response_header = &smp_response->header;
817230557Sjimharris
818230557Sjimharris   SCIF_LOG_TRACE((
819230557Sjimharris      sci_base_object_get_logger(fw_device),
820230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
821230557Sjimharris      "scif_sas_smp_remote_device_decode_spinup_hold_release_discover_response(0x%x, 0x%x) enter\n",
822230557Sjimharris      fw_device, smp_response
823230557Sjimharris   ));
824230557Sjimharris
825230557Sjimharris   if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
826230557Sjimharris   {
827230557Sjimharris      /// @todo: more decoding work needed when the function_result is not
828230557Sjimharris      /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some
829230557Sjimharris      /// function result.
830230557Sjimharris      SCIF_LOG_ERROR((
831230557Sjimharris         sci_base_object_get_logger(fw_device),
832230557Sjimharris         SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
833230557Sjimharris         "Discover function result(0x%x)\n",
834230557Sjimharris         response_header->function_result
835230557Sjimharris      ));
836230557Sjimharris
837230557Sjimharris      return SCI_FAILURE;
838230557Sjimharris   }
839230557Sjimharris
840230557Sjimharris   if ( discover_response->u2.sas1_1.attached_device_type != SMP_NO_DEVICE_ATTACHED )
841230557Sjimharris   {
842230557Sjimharris      if (discover_response->u2.sas1_1.negotiated_physical_link_rate != SCI_SATA_SPINUP_HOLD
843230557Sjimharris          && discover_response->u4.sas2.negotiated_physical_link_rate != SCI_SATA_SPINUP_HOLD
844230557Sjimharris          && ( discover_response->protocols.u.bits.attached_stp_target
845230557Sjimharris             ||discover_response->protocols.u.bits.attached_sata_device )
846230557Sjimharris         )
847230557Sjimharris      {
848230557Sjimharris         SCIF_SAS_REMOTE_DEVICE_T * target_device =
849230557Sjimharris            scif_sas_domain_get_device_by_containing_device(
850230557Sjimharris               fw_device->domain,
851230557Sjimharris               fw_device,
852230557Sjimharris               fw_device->protocol_device.smp_device.current_activity_phy_index
853230557Sjimharris            );
854230557Sjimharris
855230557Sjimharris         //Need to update the device's connection rate. Its connection rate was SPINIP_HOLD.
856230557Sjimharris         scic_remote_device_set_max_connection_rate(
857230557Sjimharris            target_device->core_object,
858230557Sjimharris            discover_response->u2.sas1_1.negotiated_physical_link_rate
859230557Sjimharris         );
860230557Sjimharris
861230557Sjimharris         //Need to update the smp phy info too.
862230557Sjimharris         scif_sas_smp_remote_device_save_smp_phy_info(
863230557Sjimharris             fw_device, discover_response);
864230557Sjimharris
865230557Sjimharris         //This device has already constructed, only need to call start_handler
866230557Sjimharris         //of this device here.
867230557Sjimharris         return target_device->state_handlers->parent.start_handler(
868230557Sjimharris                   &target_device->parent );
869230557Sjimharris      }
870230557Sjimharris      else
871230557Sjimharris         return SCI_FAILURE_RETRY_REQUIRED;
872230557Sjimharris   }
873230557Sjimharris   else
874230557Sjimharris      return SCI_FAILURE_RETRY_REQUIRED;
875230557Sjimharris}
876230557Sjimharris
877230557Sjimharris
878230557Sjimharris/**
879230557Sjimharris * @brief This method decodes a smp CONFIG ROUTE INFO response to this smp
880230557Sjimharris *        device and then continue to config route table.
881230557Sjimharris *
882230557Sjimharris * @param[in] fw_device The framework device that the CONFIG ROUTE INFO command
883230557Sjimharris *       targets to.
884230557Sjimharris * @param[in] smp_response The pointer to a CONFIG ROUTE INFO response
885230557Sjimharris *
886230557Sjimharris * @return none
887230557Sjimharris */
888230557SjimharrisSCI_STATUS scif_sas_smp_remote_device_decode_config_route_info_response(
889230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
890230557Sjimharris   SMP_RESPONSE_T           * smp_response
891230557Sjimharris)
892230557Sjimharris{
893230557Sjimharris   SMP_RESPONSE_HEADER_T * response_header = &smp_response->header;
894230557Sjimharris
895230557Sjimharris   SCIF_LOG_TRACE((
896230557Sjimharris      sci_base_object_get_logger(fw_device),
897230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
898230557Sjimharris      "scif_sas_smp_remote_device_decode_config_route_info_response(0x%x, 0x%x) enter\n",
899230557Sjimharris      fw_device, smp_response
900230557Sjimharris   ));
901230557Sjimharris
902230557Sjimharris   if (response_header->function_result == SMP_RESULT_INDEX_DOES_NOT_EXIST)
903230557Sjimharris   {
904230557Sjimharris      //case of exceeding max route index. We need to remove the devices that are not
905230557Sjimharris      //able to be edit to route table. The destination config route smp phy
906230557Sjimharris      //is used to remove devices.
907230557Sjimharris      scif_sas_smp_remote_device_cancel_config_route_table_activity(fw_device);
908230557Sjimharris
909230557Sjimharris      return SCI_FAILURE_EXCEED_MAX_ROUTE_INDEX;
910230557Sjimharris   }
911230557Sjimharris   else if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
912230557Sjimharris   {
913230557Sjimharris      /// @todo: more decoding work needed when the function_result is not
914230557Sjimharris      /// SMP_RESULT_FUNCTION_ACCEPTED. Retry might be the option for some
915230557Sjimharris      /// function result.
916230557Sjimharris      SCIF_LOG_ERROR((
917230557Sjimharris         sci_base_object_get_logger(fw_device),
918230557Sjimharris         SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
919230557Sjimharris         "Discover function result(0x%x)\n",
920230557Sjimharris         response_header->function_result
921230557Sjimharris      ));
922230557Sjimharris
923230557Sjimharris      return SCI_FAILURE;
924230557Sjimharris   }
925230557Sjimharris
926230557Sjimharris   return SCI_SUCCESS;
927230557Sjimharris}
928230557Sjimharris
929230557Sjimharris
930230557Sjimharris/**
931230557Sjimharris * @brief This method starts the smp Discover process for an expander by
932230557Sjimharris *        sending Report General request.
933230557Sjimharris *
934230557Sjimharris * @param[in] fw_device The framework smp device that a  command
935230557Sjimharris *       targets to.
936230557Sjimharris *
937230557Sjimharris * @return none
938230557Sjimharris */
939230557Sjimharrisvoid scif_sas_smp_remote_device_start_discover(
940230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device
941230557Sjimharris)
942230557Sjimharris{
943230557Sjimharris   SCIF_SAS_CONTROLLER_T * fw_controller = fw_device->domain->controller;
944230557Sjimharris
945230557Sjimharris   SCIF_LOG_TRACE((
946230557Sjimharris      sci_base_object_get_logger(fw_device),
947230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
948230557Sjimharris      "scif_sas_smp_remote_device_start_discover(0x%x) enter\n",
949230557Sjimharris      fw_device
950230557Sjimharris   ));
951230557Sjimharris
952230557Sjimharris   //For safety, clear the device again, there may be some config route table
953230557Sjimharris   //related info are not cleared yet.
954230557Sjimharris   scif_sas_smp_remote_device_clear(fw_device);
955230557Sjimharris
956230557Sjimharris   //set current activity
957230557Sjimharris   fw_device->protocol_device.smp_device.current_activity =
958230557Sjimharris      SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER;
959230557Sjimharris
960230557Sjimharris   //Set current_smp_request to REPORT GENERAL.
961230557Sjimharris   fw_device->protocol_device.smp_device.current_smp_request =
962230557Sjimharris      SMP_FUNCTION_REPORT_GENERAL;
963230557Sjimharris
964230557Sjimharris   //reset discover_to_start flag.
965230557Sjimharris   fw_device->protocol_device.smp_device.scheduled_activity =
966230557Sjimharris      SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE;
967230557Sjimharris
968230557Sjimharris   //build the first smp request Report Genernal.
969230557Sjimharris   scif_sas_smp_request_construct_report_general(fw_controller, fw_device);
970230557Sjimharris
971230557Sjimharris   //issue DPC to start this request.
972230557Sjimharris   scif_cb_start_internal_io_task_schedule(
973230557Sjimharris      fw_controller,
974230557Sjimharris      scif_sas_controller_start_high_priority_io,
975230557Sjimharris      fw_controller
976230557Sjimharris   );
977230557Sjimharris}
978230557Sjimharris
979230557Sjimharris
980230557Sjimharris/**
981230557Sjimharris * @brief This method continues the smp Discover process.
982230557Sjimharris *
983230557Sjimharris * @param[in] fw_device The framework smp device that a DISCOVER command
984230557Sjimharris *       targets to.
985230557Sjimharris * @param[in] fw_request The pointer to an smp request whose response
986230557Sjimharris *       has been decoded.
987230557Sjimharris * @param[in] status The decoding status of the smp request's response
988230557Sjimharris *
989230557Sjimharris * @return none
990230557Sjimharris */
991230557Sjimharrisvoid scif_sas_smp_remote_device_continue_current_activity(
992230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
993230557Sjimharris   SCIF_SAS_REQUEST_T       * fw_request,
994230557Sjimharris   SCI_STATUS                 status
995230557Sjimharris)
996230557Sjimharris{
997230557Sjimharris   SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T *)fw_request;
998230557Sjimharris   // save the retry count.
999230557Sjimharris   U8 io_retry_count = fw_io->retry_count;
1000230557Sjimharris
1001230557Sjimharris   if (fw_request->is_internal)
1002230557Sjimharris   {
1003230557Sjimharris      // Complete this internal io request now. We want to free this io before
1004230557Sjimharris      // we create another SMP request, which is going to happen soon.
1005230557Sjimharris      scif_sas_internal_io_request_complete(
1006230557Sjimharris         fw_device->domain->controller,
1007230557Sjimharris         (SCIF_SAS_INTERNAL_IO_REQUEST_T *)fw_request,
1008230557Sjimharris         SCI_SUCCESS
1009230557Sjimharris      );
1010230557Sjimharris   }
1011230557Sjimharris
1012230557Sjimharris   if (fw_device->protocol_device.smp_device.current_activity ==
1013230557Sjimharris      SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER)
1014230557Sjimharris   {
1015230557Sjimharris      if (status == SCI_SUCCESS)
1016230557Sjimharris      {   //continue the discover process.
1017230557Sjimharris         scif_sas_smp_remote_device_continue_discover(fw_device);
1018230557Sjimharris      }
1019230557Sjimharris      else if (status == SCI_FAILURE_RETRY_REQUIRED)
1020230557Sjimharris      {
1021230557Sjimharris         //Retry the smp request. Since we are in the middle of Discover
1022230557Sjimharris         //process, all the smp requests are internal. A new smp request
1023230557Sjimharris         //will be created for retry.
1024230557Sjimharris         U32 retry_wait_duration = (SCIF_DOMAIN_DISCOVER_TIMEOUT / 2) / SCIF_SAS_IO_RETRY_LIMIT;
1025230557Sjimharris
1026230557Sjimharris         if (io_retry_count < SCIF_SAS_IO_RETRY_LIMIT)
1027230557Sjimharris            scif_sas_smp_remote_device_retry_internal_io (
1028230557Sjimharris               fw_device, io_retry_count, retry_wait_duration);
1029230557Sjimharris         else
1030230557Sjimharris            scif_sas_smp_remote_device_fail_discover(fw_device);
1031230557Sjimharris      }
1032230557Sjimharris      else if (status == SCI_FAILURE_ILLEGAL_ROUTING_ATTRIBUTE_CONFIGURATION)
1033230557Sjimharris      {
1034230557Sjimharris         //remove this expander device and its child devices. No need to
1035230557Sjimharris         //continue the discover on this device.
1036230557Sjimharris         scif_sas_domain_remove_expander_device(fw_device->domain, fw_device);
1037230557Sjimharris
1038230557Sjimharris         //continue the domain's smp discover.
1039230557Sjimharris         scif_sas_domain_continue_discover(fw_device->domain);
1040230557Sjimharris      }
1041230557Sjimharris      else
1042230557Sjimharris      {  //terminate the discover process.
1043230557Sjimharris         scif_sas_smp_remote_device_fail_discover(fw_device);
1044230557Sjimharris      }
1045230557Sjimharris   }
1046230557Sjimharris   else if (fw_device->protocol_device.smp_device.current_activity ==
1047230557Sjimharris      SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_TARGET_RESET)
1048230557Sjimharris   {
1049230557Sjimharris      if (status == SCI_SUCCESS)
1050230557Sjimharris      {   //continue the target reset process.
1051230557Sjimharris         scif_sas_smp_remote_device_continue_target_reset(
1052230557Sjimharris            fw_device, fw_request);
1053230557Sjimharris      }
1054230557Sjimharris      else if (status == SCI_FAILURE_RETRY_REQUIRED)
1055230557Sjimharris      {
1056230557Sjimharris         //Retry the same smp request. Since we are in the middle of Target
1057230557Sjimharris         //reset process, all the smp requests are using external resource.
1058230557Sjimharris         //We will use the exactly same memory to retry.
1059230557Sjimharris         if (io_retry_count < SCIF_SAS_IO_RETRY_LIMIT)
1060230557Sjimharris         {
1061230557Sjimharris            if (fw_device->protocol_device.smp_device.smp_activity_timer == NULL)
1062230557Sjimharris            {
1063230557Sjimharris               //create the timer to wait before retry.
1064230557Sjimharris               fw_device->protocol_device.smp_device.smp_activity_timer =
1065230557Sjimharris                  scif_cb_timer_create(
1066230557Sjimharris                  (SCI_CONTROLLER_HANDLE_T *)fw_device->domain->controller,
1067230557Sjimharris                  (SCI_TIMER_CALLBACK_T)scif_sas_smp_external_request_retry,
1068230557Sjimharris                  (void*)fw_request
1069230557Sjimharris               );
1070230557Sjimharris            }
1071230557Sjimharris            else
1072230557Sjimharris            {
1073230557Sjimharris               ASSERT(0);
1074230557Sjimharris            }
1075230557Sjimharris
1076230557Sjimharris            //start the timer to wait
1077230557Sjimharris            scif_cb_timer_start(
1078230557Sjimharris               (SCI_CONTROLLER_HANDLE_T)fw_device->domain->controller,
1079230557Sjimharris               fw_device->protocol_device.smp_device.smp_activity_timer,
1080230557Sjimharris               SMP_REQUEST_RETRY_WAIT_DURATION  //20 miliseconds
1081230557Sjimharris            );
1082230557Sjimharris         }
1083230557Sjimharris         else
1084230557Sjimharris            scif_sas_smp_remote_device_fail_target_reset(fw_device, fw_request);
1085230557Sjimharris      }
1086230557Sjimharris      else
1087230557Sjimharris         //terminate the discover process.
1088230557Sjimharris         scif_sas_smp_remote_device_fail_target_reset(fw_device, fw_request);
1089230557Sjimharris   }
1090230557Sjimharris   else if (fw_device->protocol_device.smp_device.current_activity ==
1091230557Sjimharris      SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_SATA_SPINUP_HOLD_RELEASE)
1092230557Sjimharris   {
1093230557Sjimharris      SCIF_SAS_REMOTE_DEVICE_T * target_device =
1094230557Sjimharris         scif_sas_domain_get_device_by_containing_device(
1095230557Sjimharris            fw_device->domain,
1096230557Sjimharris            fw_device,
1097230557Sjimharris            fw_device->protocol_device.smp_device.current_activity_phy_index
1098230557Sjimharris         );
1099230557Sjimharris
1100230557Sjimharris      if (status == SCI_SUCCESS)
1101230557Sjimharris      {
1102230557Sjimharris         //move on to next round of SPINUP_HOLD_REALSE activity.
1103230557Sjimharris         scif_sas_smp_remote_device_sata_spinup_hold_release(fw_device);
1104230557Sjimharris      }
1105230557Sjimharris      else if (status == SCI_FAILURE_RETRY_REQUIRED)
1106230557Sjimharris      {
1107230557Sjimharris         U32 delay =
1108230557Sjimharris            (scic_remote_device_get_suggested_reset_timeout(target_device->core_object) /
1109230557Sjimharris                SCIF_SAS_IO_RETRY_LIMIT);
1110230557Sjimharris
1111230557Sjimharris         //Retry the smp request. Since we are in the middle of Discover
1112230557Sjimharris         //process, all the smp requests are internal. A new smp request
1113230557Sjimharris         //will be created for retry.
1114230557Sjimharris         if (io_retry_count < SCIF_SAS_IO_RETRY_LIMIT)
1115230557Sjimharris         {
1116230557Sjimharris            scif_sas_smp_remote_device_retry_internal_io(
1117230557Sjimharris               fw_device, io_retry_count, delay);
1118230557Sjimharris         }
1119230557Sjimharris         else //give up on this target device.
1120230557Sjimharris         {
1121230557Sjimharris            scif_sas_smp_remote_device_fail_target_spinup_hold_release(
1122230557Sjimharris               fw_device , target_device);
1123230557Sjimharris         }
1124230557Sjimharris      }
1125230557Sjimharris      else //give up on this target device.
1126230557Sjimharris        scif_sas_smp_remote_device_fail_target_spinup_hold_release(
1127230557Sjimharris           fw_device, target_device);
1128230557Sjimharris   }
1129230557Sjimharris   else if (fw_device->protocol_device.smp_device.current_activity ==
1130230557Sjimharris      SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE)
1131230557Sjimharris   {
1132230557Sjimharris      SCI_FAST_LIST_ELEMENT_T * next_phy_element = sci_fast_list_get_next(
1133230557Sjimharris         &(fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy->list_element) );
1134230557Sjimharris
1135230557Sjimharris      SCI_FAST_LIST_T * destination_smp_phy_list =
1136230557Sjimharris          fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy->list_element.owning_list;
1137230557Sjimharris
1138230557Sjimharris      SCIF_SAS_SMP_PHY_T * next_phy_in_wide_port = NULL;
1139230557Sjimharris
1140230557Sjimharris      if (next_phy_element != NULL
1141230557Sjimharris          && status != SCI_FAILURE_EXCEED_MAX_ROUTE_INDEX)
1142230557Sjimharris      {
1143230557Sjimharris         fw_device->protocol_device.smp_device.curr_config_route_index++;
1144230557Sjimharris
1145230557Sjimharris         fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy =
1146230557Sjimharris            (SCIF_SAS_SMP_PHY_T *)sci_fast_list_get_object(next_phy_element);
1147230557Sjimharris
1148230557Sjimharris         // Update the anchor for config route index.
1149230557Sjimharris         fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->config_route_table_index_anchor =
1150230557Sjimharris            fw_device->protocol_device.smp_device.curr_config_route_index;
1151230557Sjimharris
1152230557Sjimharris         scif_sas_smp_remote_device_configure_route_table(fw_device);
1153230557Sjimharris      }
1154230557Sjimharris      else if ( scif_sas_smp_remote_device_get_config_route_table_method(fw_device)
1155230557Sjimharris                   == SCIF_SAS_CONFIG_ROUTE_TABLE_ALL_PHYS
1156230557Sjimharris                && (next_phy_in_wide_port = scif_sas_smp_phy_find_next_phy_in_wide_port(
1157230557Sjimharris                       fw_device->protocol_device.smp_device.config_route_smp_phy_anchor)
1158230557Sjimharris                   )!= NULL
1159230557Sjimharris              )
1160230557Sjimharris      {
1161230557Sjimharris         //config the other phy in the same wide port
1162230557Sjimharris         fw_device->protocol_device.smp_device.config_route_smp_phy_anchor =
1163230557Sjimharris            next_phy_in_wide_port;
1164230557Sjimharris
1165230557Sjimharris         fw_device->protocol_device.smp_device.current_activity_phy_index =
1166230557Sjimharris            fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->phy_identifier;
1167230557Sjimharris
1168230557Sjimharris         fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy =
1169230557Sjimharris            sci_fast_list_get_head(destination_smp_phy_list);
1170230557Sjimharris
1171230557Sjimharris         if (fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->config_route_table_index_anchor != 0)
1172230557Sjimharris            fw_device->protocol_device.smp_device.curr_config_route_index =
1173230557Sjimharris               fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->config_route_table_index_anchor + 1;
1174230557Sjimharris         else
1175230557Sjimharris            fw_device->protocol_device.smp_device.curr_config_route_index = 0;
1176230557Sjimharris
1177230557Sjimharris         scif_sas_smp_remote_device_configure_route_table(fw_device);
1178230557Sjimharris      }
1179230557Sjimharris      else if ( fw_device->protocol_device.smp_device.is_route_table_cleaned == FALSE)
1180230557Sjimharris      {
1181230557Sjimharris         fw_device->protocol_device.smp_device.current_activity =
1182230557Sjimharris            SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAN_ROUTE_TABLE;
1183230557Sjimharris
1184230557Sjimharris         scif_sas_smp_remote_device_clean_route_table(fw_device);
1185230557Sjimharris      }
1186230557Sjimharris      else
1187230557Sjimharris      {
1188230557Sjimharris         //set this device's activity to NON.
1189230557Sjimharris         fw_device->protocol_device.smp_device.current_activity =
1190230557Sjimharris            SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE;
1191230557Sjimharris
1192230557Sjimharris         //we need to notify domain that this device finished config route table, domain
1193230557Sjimharris         //may pick up other activities (i.e. Discover) for other expanders.
1194230557Sjimharris         scif_sas_domain_continue_discover(fw_device->domain);
1195230557Sjimharris      }
1196230557Sjimharris   }
1197230557Sjimharris   else if (fw_device->protocol_device.smp_device.current_activity ==
1198230557Sjimharris               SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAN_ROUTE_TABLE)
1199230557Sjimharris   {
1200230557Sjimharris      scif_sas_smp_remote_device_clean_route_table(fw_device);
1201230557Sjimharris   }
1202230557Sjimharris   else if (fw_device->protocol_device.smp_device.current_activity ==
1203230557Sjimharris               SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAR_AFFILIATION)
1204230557Sjimharris   {
1205230557Sjimharris      scif_sas_smp_remote_device_continue_clear_affiliation(fw_device);
1206230557Sjimharris   }
1207230557Sjimharris}
1208230557Sjimharris
1209230557Sjimharris
1210230557Sjimharris/**
1211230557Sjimharris * @brief This method continues the smp Discover process.
1212230557Sjimharris *
1213230557Sjimharris * @param[in] fw_device The framework smp device that a DISCOVER command
1214230557Sjimharris *       targets to.
1215230557Sjimharris *
1216230557Sjimharris * @return none
1217230557Sjimharris */
1218230557Sjimharrisvoid scif_sas_smp_remote_device_continue_discover(
1219230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device
1220230557Sjimharris)
1221230557Sjimharris{
1222230557Sjimharris   SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain;
1223230557Sjimharris
1224230557Sjimharris   SCIF_LOG_TRACE((
1225230557Sjimharris      sci_base_object_get_logger(fw_device),
1226230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1227230557Sjimharris      "scif_sas_smp_remote_device_continue_discover(0x%x) enter\n",
1228230557Sjimharris      fw_device
1229230557Sjimharris   ));
1230230557Sjimharris
1231230557Sjimharris   switch (fw_device->protocol_device.smp_device.current_smp_request)
1232230557Sjimharris   {
1233230557Sjimharris      case SMP_FUNCTION_REPORT_GENERAL:
1234230557Sjimharris         // send the REPORT MANUFACTURER_INFO request
1235230557Sjimharris         fw_device->protocol_device.smp_device.current_smp_request =
1236230557Sjimharris            SMP_FUNCTION_REPORT_MANUFACTURER_INFORMATION;
1237230557Sjimharris
1238230557Sjimharris         scif_sas_smp_request_construct_report_manufacturer_info(
1239230557Sjimharris            fw_domain->controller, fw_device
1240230557Sjimharris         );
1241230557Sjimharris
1242230557Sjimharris         break;
1243230557Sjimharris
1244230557Sjimharris      case SMP_FUNCTION_REPORT_MANUFACTURER_INFORMATION:
1245230557Sjimharris         //send the first SMP DISCOVER request.
1246230557Sjimharris         fw_device->protocol_device.smp_device.current_activity_phy_index = 0;
1247230557Sjimharris         fw_device->protocol_device.smp_device.current_smp_request =
1248230557Sjimharris            SMP_FUNCTION_DISCOVER;
1249230557Sjimharris
1250230557Sjimharris         scif_sas_smp_request_construct_discover(
1251230557Sjimharris            fw_domain->controller,
1252230557Sjimharris            fw_device,
1253230557Sjimharris            fw_device->protocol_device.smp_device.current_activity_phy_index,
1254230557Sjimharris            NULL, NULL
1255230557Sjimharris         );
1256230557Sjimharris         break;
1257230557Sjimharris
1258230557Sjimharris
1259230557Sjimharris      case SMP_FUNCTION_DISCOVER:
1260230557Sjimharris         fw_device->protocol_device.smp_device.current_activity_phy_index++;
1261230557Sjimharris
1262230557Sjimharris         if ( (fw_device->protocol_device.smp_device.current_activity_phy_index <
1263230557Sjimharris                  fw_device->protocol_device.smp_device.number_of_phys) )
1264230557Sjimharris         {
1265230557Sjimharris            scif_sas_smp_request_construct_discover(
1266230557Sjimharris               fw_domain->controller,
1267230557Sjimharris               fw_device,
1268230557Sjimharris               fw_device->protocol_device.smp_device.current_activity_phy_index,
1269230557Sjimharris               NULL, NULL
1270230557Sjimharris            );
1271230557Sjimharris         }
1272230557Sjimharris         else
1273230557Sjimharris            scif_sas_smp_remote_device_finish_initial_discover(fw_device);
1274230557Sjimharris         break;
1275230557Sjimharris
1276230557Sjimharris
1277230557Sjimharris      case SMP_FUNCTION_REPORT_PHY_SATA:
1278230557Sjimharris         scif_sas_smp_request_construct_report_phy_sata(
1279230557Sjimharris            fw_device->domain->controller,
1280230557Sjimharris            fw_device,
1281230557Sjimharris            fw_device->protocol_device.smp_device.current_activity_phy_index
1282230557Sjimharris         );
1283230557Sjimharris
1284230557Sjimharris         break;
1285230557Sjimharris
1286230557Sjimharris
1287230557Sjimharris      case SMP_FUNCTION_PHY_CONTROL:
1288230557Sjimharris         scif_sas_smp_request_construct_phy_control(
1289230557Sjimharris            fw_device->domain->controller,
1290230557Sjimharris            fw_device,
1291230557Sjimharris            PHY_OPERATION_HARD_RESET,
1292230557Sjimharris            fw_device->protocol_device.smp_device.current_activity_phy_index,
1293230557Sjimharris            NULL,
1294230557Sjimharris            NULL
1295230557Sjimharris         );
1296230557Sjimharris
1297230557Sjimharris         break;
1298230557Sjimharris
1299230557Sjimharris      default:
1300230557Sjimharris         break;
1301230557Sjimharris   }
1302230557Sjimharris}
1303230557Sjimharris
1304230557Sjimharris/**
1305230557Sjimharris * @brief This method finishes the initial smp DISCOVER process. There
1306230557Sjimharris *        may be a spinup_hold release phase following of initial discover,
1307230557Sjimharris *        depending on whether there are SATA device in the domain
1308230557Sjimharris *        in SATA_SPINUP_HOLD condition.
1309230557Sjimharris *
1310230557Sjimharris * @param[in] fw_device The framework smp device that finishes all the
1311230557Sjimharris *       DISCOVER requests.
1312230557Sjimharris *
1313230557Sjimharris * @return none
1314230557Sjimharris */
1315230557Sjimharrisvoid scif_sas_smp_remote_device_finish_initial_discover(
1316230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device
1317230557Sjimharris)
1318230557Sjimharris{
1319230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * device_in_sata_spinup_hold =
1320230557Sjimharris      scif_sas_domain_find_device_in_spinup_hold(fw_device->domain);
1321230557Sjimharris
1322230557Sjimharris   SCIF_LOG_TRACE((
1323230557Sjimharris      sci_base_object_get_logger(fw_device),
1324230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1325230557Sjimharris      "scif_sas_smp_remote_device_finish_initial_discover(0x%x) enter\n",
1326230557Sjimharris      fw_device
1327230557Sjimharris   ));
1328230557Sjimharris
1329230557Sjimharris   if ( device_in_sata_spinup_hold != NULL )
1330230557Sjimharris   {
1331230557Sjimharris     //call the common private routine to reset all fields of this smp device.
1332230557Sjimharris     scif_sas_smp_remote_device_clear(fw_device);
1333230557Sjimharris
1334230557Sjimharris     //Move on to next activity SPINUP_HOLD_RELEASE
1335230557Sjimharris     fw_device->protocol_device.smp_device.current_activity =
1336230557Sjimharris        SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_SATA_SPINUP_HOLD_RELEASE;
1337230557Sjimharris
1338230557Sjimharris      //create the timer to delay a little bit before going to
1339230557Sjimharris      //sata spinup hold release activity.
1340230557Sjimharris      if (fw_device->protocol_device.smp_device.smp_activity_timer == NULL)
1341230557Sjimharris      {
1342230557Sjimharris      fw_device->protocol_device.smp_device.smp_activity_timer =
1343230557Sjimharris         scif_cb_timer_create(
1344230557Sjimharris            (SCI_CONTROLLER_HANDLE_T *)fw_device->domain->controller,
1345230557Sjimharris            (SCI_TIMER_CALLBACK_T)scif_sas_smp_remote_device_sata_spinup_hold_release,
1346230557Sjimharris            (void*)fw_device
1347230557Sjimharris         );
1348230557Sjimharris      }
1349230557Sjimharris      else
1350230557Sjimharris      {
1351230557Sjimharris         ASSERT (0);
1352230557Sjimharris      }
1353230557Sjimharris
1354230557Sjimharris      scif_cb_timer_start(
1355230557Sjimharris         (SCI_CONTROLLER_HANDLE_T)fw_device->domain->controller,
1356230557Sjimharris         fw_device->protocol_device.smp_device.smp_activity_timer,
1357230557Sjimharris         SMP_SPINUP_HOLD_RELEASE_WAIT_DURATION
1358230557Sjimharris      );
1359230557Sjimharris   }
1360230557Sjimharris   else
1361230557Sjimharris      scif_sas_smp_remote_device_finish_discover(fw_device);
1362230557Sjimharris}
1363230557Sjimharris
1364230557Sjimharris
1365230557Sjimharris/**
1366230557Sjimharris * @brief This method finishes the smp DISCOVER process.
1367230557Sjimharris *
1368230557Sjimharris * @param[in] fw_device The framework smp device that finishes all the
1369230557Sjimharris *       DISCOVER requests.
1370230557Sjimharris *
1371230557Sjimharris * @return none
1372230557Sjimharris */
1373230557Sjimharrisvoid scif_sas_smp_remote_device_finish_discover(
1374230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device
1375230557Sjimharris)
1376230557Sjimharris{
1377230557Sjimharris   SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain;
1378230557Sjimharris
1379230557Sjimharris   SCIF_LOG_TRACE((
1380230557Sjimharris      sci_base_object_get_logger(fw_device),
1381230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1382230557Sjimharris      "scif_sas_smp_remote_device_finish_discover(0x%x) enter\n",
1383230557Sjimharris      fw_device
1384230557Sjimharris   ));
1385230557Sjimharris
1386230557Sjimharris   if ( fw_domain->is_config_route_table_needed
1387230557Sjimharris       && fw_device->protocol_device.smp_device.smp_phy_list.list_head != NULL)
1388230557Sjimharris      scif_sas_smp_remote_device_configure_upstream_expander_route_info(fw_device);
1389230557Sjimharris
1390230557Sjimharris   //call the common private routine to reset all fields of this smp device.
1391230557Sjimharris   scif_sas_smp_remote_device_clear(fw_device);
1392230557Sjimharris
1393230557Sjimharris#ifdef SCI_SMP_PHY_LIST_DEBUG_PRINT
1394230557Sjimharris   scif_sas_smp_remote_device_print_smp_phy_list(fw_device);
1395230557Sjimharris#endif
1396230557Sjimharris
1397230557Sjimharris   //notify domain this smp device's discover finishes, it's up to domain
1398230557Sjimharris   //to continue the discover process in a bigger scope.
1399230557Sjimharris   scif_sas_domain_continue_discover(fw_domain);
1400230557Sjimharris}
1401230557Sjimharris
1402230557Sjimharris
1403230557Sjimharris/**
1404230557Sjimharris * @brief This method continues the smp Target Reset (Phy Control) process.
1405230557Sjimharris *
1406230557Sjimharris * @param[in] fw_device The framework smp device that a smp reset targets to.
1407230557Sjimharris *
1408230557Sjimharris * @return none
1409230557Sjimharris */
1410230557Sjimharrisvoid scif_sas_smp_remote_device_continue_target_reset(
1411230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
1412230557Sjimharris   SCIF_SAS_REQUEST_T       * fw_request
1413230557Sjimharris)
1414230557Sjimharris{
1415230557Sjimharris   SCIF_SAS_CONTROLLER_T * fw_controller = fw_device->domain->controller;
1416230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * target_device =
1417230557Sjimharris      scif_sas_domain_get_device_by_containing_device(
1418230557Sjimharris         fw_device->domain,
1419230557Sjimharris         fw_device,
1420230557Sjimharris         fw_device->protocol_device.smp_device.current_activity_phy_index
1421230557Sjimharris      );
1422230557Sjimharris
1423230557Sjimharris   SCIF_LOG_TRACE((
1424230557Sjimharris      sci_base_object_get_logger(fw_device),
1425230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1426230557Sjimharris      "scif_sas_smp_remote_device_continue_target_reset(0x%x, 0x%x) enter\n",
1427230557Sjimharris      fw_device, fw_request
1428230557Sjimharris   ));
1429230557Sjimharris
1430230557Sjimharris   if (fw_device->protocol_device.smp_device.current_smp_request ==
1431230557Sjimharris          SMP_FUNCTION_PHY_CONTROL)
1432230557Sjimharris   {
1433230557Sjimharris      //query the core remote device to get suggested reset timeout value
1434230557Sjimharris      //then scale down by factor of 8 to get the duration of the pause
1435230557Sjimharris      //before sending out Discover command to poll.
1436230557Sjimharris      U32 delay =
1437230557Sjimharris         (scic_remote_device_get_suggested_reset_timeout(target_device->core_object)/8);
1438230557Sjimharris
1439230557Sjimharris      //create the timer to send Discover command polling target device's
1440230557Sjimharris      //coming back.
1441230557Sjimharris      if (fw_device->protocol_device.smp_device.smp_activity_timer == NULL)
1442230557Sjimharris      {
1443230557Sjimharris         fw_device->protocol_device.smp_device.smp_activity_timer =
1444230557Sjimharris            scif_cb_timer_create(
1445230557Sjimharris               (SCI_CONTROLLER_HANDLE_T *)fw_controller,
1446230557Sjimharris               (SCI_TIMER_CALLBACK_T)scif_sas_smp_remote_device_target_reset_poll,
1447230557Sjimharris               (void*)fw_request
1448230557Sjimharris            );
1449230557Sjimharris      }
1450230557Sjimharris      else
1451230557Sjimharris      {
1452230557Sjimharris         ASSERT(0);
1453230557Sjimharris      }
1454230557Sjimharris
1455230557Sjimharris      //start the timer
1456230557Sjimharris      scif_cb_timer_start(
1457230557Sjimharris         (SCI_CONTROLLER_HANDLE_T)fw_controller,
1458230557Sjimharris         fw_device->protocol_device.smp_device.smp_activity_timer,
1459230557Sjimharris         delay
1460230557Sjimharris      );
1461230557Sjimharris   }
1462230557Sjimharris   else if (fw_device->protocol_device.smp_device.current_smp_request ==
1463230557Sjimharris          SMP_FUNCTION_DISCOVER)
1464230557Sjimharris   {
1465230557Sjimharris      //tell target reset successful
1466230557Sjimharris      scif_sas_remote_device_target_reset_complete(
1467230557Sjimharris         target_device, fw_request, SCI_SUCCESS);
1468230557Sjimharris   }
1469230557Sjimharris}
1470230557Sjimharris
1471230557Sjimharris/**
1472230557Sjimharris * @brief This routine is invoked by timer or when 2 BCN are received
1473230557Sjimharris *        after Phy Control command. This routine will construct a
1474230557Sjimharris *        Discover command to the same expander phy to poll the target
1475230557Sjimharris *        device's coming back. This new request is then put into
1476230557Sjimharris *        high priority queue and will be started by a DPC soon.
1477230557Sjimharris *
1478230557Sjimharris * @param[in] fw_request The scif request for smp activities.
1479230557Sjimharris */
1480230557Sjimharrisvoid scif_sas_smp_remote_device_target_reset_poll(
1481230557Sjimharris   SCIF_SAS_REQUEST_T       * fw_request
1482230557Sjimharris)
1483230557Sjimharris{
1484230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device = fw_request->device;
1485230557Sjimharris   SCIF_SAS_CONTROLLER_T * fw_controller = fw_device->domain->controller;
1486230557Sjimharris   void * new_command_handle;
1487230557Sjimharris
1488230557Sjimharris   SCIF_LOG_TRACE((
1489230557Sjimharris      sci_base_object_get_logger(fw_device),
1490230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1491230557Sjimharris      "scif_sas_smp_remote_device_target_reset_poll(0x%x) enter\n",
1492230557Sjimharris      fw_request
1493230557Sjimharris   ));
1494230557Sjimharris
1495230557Sjimharris   // Before we construct new io using the same memory, we need to
1496230557Sjimharris   // remove the IO from the list of outstanding requests on the domain
1497230557Sjimharris   // so that we don't damage the domain's fast list of request.
1498230557Sjimharris   sci_fast_list_remove_element(&fw_request->list_element);
1499230557Sjimharris
1500230557Sjimharris   fw_device->protocol_device.smp_device.current_smp_request =
1501230557Sjimharris      SMP_FUNCTION_DISCOVER;
1502230557Sjimharris
1503230557Sjimharris   //sent smp discover request to poll on remote device's coming back.
1504230557Sjimharris   //construct Discover command using the same memory as fw_request.
1505230557Sjimharris   new_command_handle = scif_sas_smp_request_construct_discover(
1506230557Sjimharris      fw_device->domain->controller,
1507230557Sjimharris      fw_device,
1508230557Sjimharris      fw_device->protocol_device.smp_device.current_activity_phy_index,
1509230557Sjimharris      (void *)sci_object_get_association(fw_request),
1510230557Sjimharris      (void *)fw_request
1511230557Sjimharris   );
1512230557Sjimharris
1513230557Sjimharris   //put into the high priority queue.
1514230557Sjimharris   sci_pool_put(fw_controller->hprq.pool, (POINTER_UINT) new_command_handle);
1515230557Sjimharris
1516230557Sjimharris   //schedule the DPC to start new Discover command.
1517230557Sjimharris   scif_cb_start_internal_io_task_schedule(
1518230557Sjimharris      fw_controller, scif_sas_controller_start_high_priority_io, fw_controller
1519230557Sjimharris   );
1520230557Sjimharris}
1521230557Sjimharris
1522230557Sjimharris
1523230557Sjimharris/**
1524230557Sjimharris * @brief This method fails discover process.
1525230557Sjimharris *
1526230557Sjimharris * @param[in] fw_device The framework smp device that failed at current
1527230557Sjimharris *       activity.
1528230557Sjimharris *
1529230557Sjimharris * @return none
1530230557Sjimharris */
1531230557Sjimharrisvoid scif_sas_smp_remote_device_fail_discover(
1532230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device
1533230557Sjimharris)
1534230557Sjimharris{
1535230557Sjimharris   SCIF_LOG_TRACE((
1536230557Sjimharris      sci_base_object_get_logger(fw_device),
1537230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1538230557Sjimharris      "scif_sas_smp_remote_device_fail_discover(0x%x) enter\n",
1539230557Sjimharris      fw_device
1540230557Sjimharris   ));
1541230557Sjimharris
1542230557Sjimharris   switch (fw_device->protocol_device.smp_device.current_smp_request)
1543230557Sjimharris   {
1544230557Sjimharris      case SMP_FUNCTION_REPORT_GENERAL:
1545230557Sjimharris      case SMP_FUNCTION_REPORT_MANUFACTURER_INFORMATION:
1546230557Sjimharris         scif_sas_smp_remote_device_finish_discover(fw_device);
1547230557Sjimharris         break;
1548230557Sjimharris
1549230557Sjimharris      case SMP_FUNCTION_DISCOVER:
1550230557Sjimharris      case SMP_FUNCTION_REPORT_PHY_SATA:
1551230557Sjimharris         //Retry limit reached, we will continue to send DISCOVER to next phy.
1552230557Sjimharris         fw_device->protocol_device.smp_device.current_smp_request =
1553230557Sjimharris            SMP_FUNCTION_DISCOVER;
1554230557Sjimharris
1555230557Sjimharris         scif_sas_smp_remote_device_continue_discover(fw_device);
1556230557Sjimharris         break;
1557230557Sjimharris
1558230557Sjimharris      default:
1559230557Sjimharris         break;
1560230557Sjimharris   }
1561230557Sjimharris}
1562230557Sjimharris
1563230557Sjimharris
1564230557Sjimharris/**
1565230557Sjimharris * @brief This method fails Target Reset.
1566230557Sjimharris *
1567230557Sjimharris * @param[in] fw_device The framework smp device that failed at current
1568230557Sjimharris *       activity.
1569230557Sjimharris * @param[in] fw_request The smp request created for target reset
1570230557Sjimharris *       using external resource.
1571230557Sjimharris *
1572230557Sjimharris * @return none
1573230557Sjimharris */
1574230557Sjimharrisvoid scif_sas_smp_remote_device_fail_target_reset(
1575230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
1576230557Sjimharris   SCIF_SAS_REQUEST_T       * fw_request
1577230557Sjimharris)
1578230557Sjimharris{
1579230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * target_device =
1580230557Sjimharris      scif_sas_domain_get_device_by_containing_device(
1581230557Sjimharris         fw_device->domain,
1582230557Sjimharris         fw_device,
1583230557Sjimharris         fw_device->protocol_device.smp_device.current_activity_phy_index
1584230557Sjimharris      );
1585230557Sjimharris
1586230557Sjimharris   SCIF_LOG_TRACE((
1587230557Sjimharris      sci_base_object_get_logger(fw_device),
1588230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1589230557Sjimharris      "scif_sas_smp_remote_device_fail_target_reset(0x%x, 0x%x, 0x%x) enter\n",
1590230557Sjimharris      fw_device, target_device, fw_request
1591230557Sjimharris   ));
1592230557Sjimharris
1593230557Sjimharris   //tell target reset failed
1594230557Sjimharris   scif_sas_remote_device_target_reset_complete(
1595230557Sjimharris      target_device, fw_request, SCI_FAILURE);
1596230557Sjimharris}
1597230557Sjimharris
1598230557Sjimharris/**
1599230557Sjimharris * @brief This method init or continue the SATA SPINUP_HOLD RELEASE activity.
1600230557Sjimharris * This function searches domain's device list, find a device in STOPPED STATE
1601230557Sjimharris * and its connection_rate is SPINIP, then send DISCOVER command to its expander
1602230557Sjimharris * phy id to poll. But if searching the domain's device list for SATA devices on
1603230557Sjimharris * SPINUP_HOLD finds no device, the activity SPINUP_HOLD_RELEASE is finished.
1604230557Sjimharris * We then call fw_domain->device_start_complete_handler() for this smp-device.
1605230557Sjimharris *
1606230557Sjimharris * @param[in] fw_device The framework smp device that is on SATA SPINUP_HOLD_RELEASE
1607230557Sjimharris *       activity.
1608230557Sjimharris *
1609230557Sjimharris * @return none
1610230557Sjimharris */
1611230557Sjimharrisvoid scif_sas_smp_remote_device_sata_spinup_hold_release(
1612230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device
1613230557Sjimharris)
1614230557Sjimharris{
1615230557Sjimharris   SCIF_SAS_DOMAIN_T        * fw_domain = fw_device->domain;
1616230557Sjimharris   SCIF_SAS_CONTROLLER_T    * fw_controller = fw_domain->controller;
1617230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * device_to_poll = NULL;
1618230557Sjimharris
1619230557Sjimharris   SCIF_LOG_TRACE((
1620230557Sjimharris      sci_base_object_get_logger(fw_device),
1621230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1622230557Sjimharris      "scif_sas_smp_remote_device_sata_spinup_hold_release(0x%x) enter\n",
1623230557Sjimharris      fw_device
1624230557Sjimharris   ));
1625230557Sjimharris
1626230557Sjimharris   //search throught domain's device list to find a sata device on spinup_hold
1627230557Sjimharris   //state to poll.
1628230557Sjimharris   device_to_poll = scif_sas_domain_find_device_in_spinup_hold(fw_domain);
1629230557Sjimharris
1630230557Sjimharris   if (device_to_poll != NULL)
1631230557Sjimharris   {
1632230557Sjimharris      //send DISCOVER command to this device's expaner phy.
1633230557Sjimharris      fw_device->protocol_device.smp_device.current_smp_request =
1634230557Sjimharris         SMP_FUNCTION_DISCOVER;
1635230557Sjimharris
1636230557Sjimharris      fw_device->protocol_device.smp_device.current_activity_phy_index =
1637230557Sjimharris        device_to_poll->expander_phy_identifier;
1638230557Sjimharris
1639230557Sjimharris      scif_sas_smp_request_construct_discover(
1640230557Sjimharris         fw_domain->controller,
1641230557Sjimharris         fw_device,
1642230557Sjimharris         fw_device->protocol_device.smp_device.current_activity_phy_index,
1643230557Sjimharris         NULL, NULL
1644230557Sjimharris      );
1645230557Sjimharris
1646230557Sjimharris      //schedule the DPC to start new Discover command.
1647230557Sjimharris      scif_cb_start_internal_io_task_schedule(
1648230557Sjimharris         fw_controller, scif_sas_controller_start_high_priority_io, fw_controller
1649230557Sjimharris      );
1650230557Sjimharris   }
1651230557Sjimharris   else //SATA SPINUP HOLD RELEASE activity is done.
1652230557Sjimharris      scif_sas_smp_remote_device_finish_discover (fw_device);
1653230557Sjimharris}
1654230557Sjimharris
1655230557Sjimharris
1656230557Sjimharris/**
1657230557Sjimharris * @brief This method fail an action of SATA SPINUP_HOLD RELEASE on a single EA
1658230557Sjimharris *        SATA device. It will remove a remote_device object for a sata device
1659230557Sjimharris *        that fails to come out of spinup_hold.
1660230557Sjimharris *
1661230557Sjimharris * @param[in] fw_device The framework smp device that is on SATA SPINUP_HOLD_RELEASE
1662230557Sjimharris *       activity.
1663230557Sjimharris * @param[in] target_device The expander attached device failed being brought out
1664230557Sjimharris *       of SPINUP_HOLD state.
1665230557Sjimharris *
1666230557Sjimharris * @return none
1667230557Sjimharris */
1668230557Sjimharrisvoid scif_sas_smp_remote_device_fail_target_spinup_hold_release(
1669230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
1670230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * target_device
1671230557Sjimharris)
1672230557Sjimharris{
1673230557Sjimharris   SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain;
1674230557Sjimharris
1675230557Sjimharris   SCIF_LOG_TRACE((
1676230557Sjimharris      sci_base_object_get_logger(fw_device),
1677230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1678230557Sjimharris      "scif_sas_smp_remote_device_fail_target_spinup_hold_release(0x%x, 0x%x) enter\n",
1679230557Sjimharris      fw_device, target_device
1680230557Sjimharris   ));
1681230557Sjimharris
1682230557Sjimharris   //need to remove the device, since we have to give up on spinup_hold_release
1683230557Sjimharris   //activity on this device.
1684230557Sjimharris   scif_cb_domain_device_removed(
1685230557Sjimharris      fw_domain->controller, fw_domain, target_device
1686230557Sjimharris   );
1687230557Sjimharris
1688230557Sjimharris   //move on to next round of SPINUP_HOLD_REALSE activity.
1689230557Sjimharris   scif_sas_smp_remote_device_sata_spinup_hold_release(fw_device);
1690230557Sjimharris}
1691230557Sjimharris
1692230557Sjimharris
1693230557Sjimharris/**
1694230557Sjimharris * @brief This method retry only internal IO for the smp device.
1695230557Sjimharris *
1696230557Sjimharris * @param[in] fw_device The framework smp device that has an smp request to retry.
1697230557Sjimharris * @param[in] io_retry_count current count for times the IO being retried.
1698230557Sjimharris * @param[in] delay The time delay before the io gets retried.
1699230557Sjimharris *
1700230557Sjimharris * @return none
1701230557Sjimharris */
1702230557Sjimharrisvoid scif_sas_smp_remote_device_retry_internal_io(
1703230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
1704230557Sjimharris   U8                         io_retry_count,
1705230557Sjimharris   U32                        delay
1706230557Sjimharris)
1707230557Sjimharris{
1708230557Sjimharris   SCIF_LOG_TRACE((
1709230557Sjimharris      sci_base_object_get_logger(fw_device),
1710230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1711230557Sjimharris      "scif_sas_smp_remote_device_retry_internal_io(0x%x, 0x%x, 0x%x) enter\n",
1712230557Sjimharris      fw_device, io_retry_count, delay
1713230557Sjimharris   ));
1714230557Sjimharris
1715230557Sjimharris   fw_device->protocol_device.smp_device.io_retry_count =
1716230557Sjimharris      io_retry_count;
1717230557Sjimharris
1718230557Sjimharris   //create the timer for poll target device's coming back.
1719230557Sjimharris   if (fw_device->protocol_device.smp_device.smp_activity_timer == NULL)
1720230557Sjimharris   {
1721230557Sjimharris      fw_device->protocol_device.smp_device.smp_activity_timer =
1722230557Sjimharris         scif_cb_timer_create(
1723230557Sjimharris            (SCI_CONTROLLER_HANDLE_T *)fw_device->domain->controller,
1724230557Sjimharris            (SCI_TIMER_CALLBACK_T)scif_sas_smp_internal_request_retry,
1725230557Sjimharris            (void*)fw_device
1726230557Sjimharris         );
1727230557Sjimharris   }
1728230557Sjimharris   else
1729230557Sjimharris   {
1730230557Sjimharris      ASSERT(0);
1731230557Sjimharris   }
1732230557Sjimharris   //start the timer for a purpose of waiting.
1733230557Sjimharris   scif_cb_timer_start(
1734230557Sjimharris      (SCI_CONTROLLER_HANDLE_T)fw_device->domain->controller,
1735230557Sjimharris      fw_device->protocol_device.smp_device.smp_activity_timer,
1736230557Sjimharris      delay
1737230557Sjimharris   );
1738230557Sjimharris}
1739230557Sjimharris
1740230557Sjimharris
1741230557Sjimharris/**
1742230557Sjimharris * @brief This method indicates whether an expander device is in Discover
1743230557Sjimharris *        process.
1744230557Sjimharris *
1745230557Sjimharris * @param[in] fw_device The framework smp device.
1746230557Sjimharris *
1747230557Sjimharris * @return Whether an expander device is in the middle of discovery process.
1748230557Sjimharris */
1749230557SjimharrisBOOL scif_sas_smp_remote_device_is_in_activity(
1750230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device
1751230557Sjimharris)
1752230557Sjimharris{
1753230557Sjimharris   return(fw_device->protocol_device.smp_device.current_activity
1754230557Sjimharris          != SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE);
1755230557Sjimharris}
1756230557Sjimharris
1757230557Sjimharris/**
1758230557Sjimharris * @brief This method search through the smp phy list of an expander to
1759230557Sjimharris *        find a smp phy by its phy id of the expander.
1760230557Sjimharris *
1761230557Sjimharris * @param[in] phy_identifier The search criteria.
1762230557Sjimharris * @param[in] smp_remote_device The expander that owns the smp phy list.
1763230557Sjimharris *
1764230557Sjimharris * @return The found smp phy or a NULL pointer to indicate no smp phy is found.
1765230557Sjimharris */
1766230557SjimharrisSCIF_SAS_SMP_PHY_T * scif_sas_smp_remote_device_find_smp_phy_by_id(
1767230557Sjimharris   U8                             phy_identifier,
1768230557Sjimharris   SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device
1769230557Sjimharris)
1770230557Sjimharris{
1771230557Sjimharris   SCI_FAST_LIST_ELEMENT_T  * element = smp_remote_device->smp_phy_list.list_head;
1772230557Sjimharris   SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL;
1773230557Sjimharris
1774231137Sjimharris   ASSERT(phy_identifier < smp_remote_device->smp_phy_list.number_of_phys);
1775231137Sjimharris
1776230557Sjimharris   while (element != NULL)
1777230557Sjimharris   {
1778230557Sjimharris      curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element);
1779230557Sjimharris      element = sci_fast_list_get_next(element);
1780230557Sjimharris
1781230557Sjimharris      if (curr_smp_phy->phy_identifier == phy_identifier)
1782230557Sjimharris         return curr_smp_phy;
1783230557Sjimharris   }
1784230557Sjimharris
1785230557Sjimharris   return NULL;
1786230557Sjimharris}
1787230557Sjimharris
1788230557Sjimharris/**
1789230557Sjimharris * @brief This method takes care of removing smp phy list of a smp devcie, which is
1790230557Sjimharris *           about to be removed.
1791230557Sjimharris *
1792230557Sjimharris * @param[in] fw_device The expander device that is about to be removed.
1793230557Sjimharris *
1794230557Sjimharris * @return none.
1795230557Sjimharris */
1796230557Sjimharrisvoid scif_sas_smp_remote_device_removed(
1797230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * this_device
1798230557Sjimharris)
1799230557Sjimharris{
1800230557Sjimharris   SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device =
1801230557Sjimharris      &this_device->protocol_device.smp_device;
1802230557Sjimharris
1803230557Sjimharris   SCI_FAST_LIST_ELEMENT_T  * element = smp_remote_device->smp_phy_list.list_head;
1804230557Sjimharris   SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL;
1805230557Sjimharris
1806230557Sjimharris   SCIF_LOG_TRACE((
1807230557Sjimharris      sci_base_object_get_logger(this_device),
1808230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1809230557Sjimharris      "scif_sas_smp_remote_device_removed(0x%x) enter\n",
1810230557Sjimharris      this_device
1811230557Sjimharris   ));
1812230557Sjimharris
1813230557Sjimharris   //remove all the smp phys in this device's smp_phy_list, and the conterpart smp phys
1814230557Sjimharris   //in phy connections.
1815230557Sjimharris   while (element != NULL)
1816230557Sjimharris   {
1817230557Sjimharris      curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element);
1818230557Sjimharris      element = sci_fast_list_get_next(element);
1819230557Sjimharris
1820230557Sjimharris      scif_sas_smp_phy_destruct(curr_smp_phy);
1821230557Sjimharris   }
1822230557Sjimharris
1823230557Sjimharris   this_device->protocol_device.smp_device.number_of_phys = 0;
1824230557Sjimharris   this_device->protocol_device.smp_device.expander_route_indexes = 0;
1825230557Sjimharris   this_device->protocol_device.smp_device.is_table_to_table_supported = FALSE;
1826230557Sjimharris   this_device->protocol_device.smp_device.is_externally_configurable  = FALSE;
1827230557Sjimharris   this_device->protocol_device.smp_device.is_able_to_config_others    = FALSE;
1828230557Sjimharris
1829230557Sjimharris   scif_sas_smp_remote_device_clear(this_device);
1830230557Sjimharris}
1831230557Sjimharris
1832230557Sjimharris
1833230557Sjimharris/**
1834230557Sjimharris * @brief This method takes care of terminated smp request to a smp device. The
1835230557Sjimharris *        terminated smp request is most likely timeout and being aborted. A timeout
1836230557Sjimharris *        maybe due to OPEN REJECT (NO DESTINATION).
1837230557Sjimharris *
1838230557Sjimharris * @param[in] fw_device The expander device that a timed out smp request towards to.
1839230557Sjimharris * @param[in] fw_request A failed smp request that is terminated by scic.
1840230557Sjimharris *
1841230557Sjimharris * @return none.
1842230557Sjimharris */
1843230557Sjimharrisvoid scif_sas_smp_remote_device_terminated_request_handler(
1844230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
1845230557Sjimharris   SCIF_SAS_REQUEST_T       * fw_request
1846230557Sjimharris)
1847230557Sjimharris{
1848230557Sjimharris   SCIF_LOG_TRACE((
1849230557Sjimharris      sci_base_object_get_logger(fw_device),
1850230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1851230557Sjimharris      "scif_sas_smp_remote_device_terminated_request_handler(0x%x, 0x%x) enter\n",
1852230557Sjimharris      fw_device, fw_request
1853230557Sjimharris   ));
1854230557Sjimharris
1855230557Sjimharris   scif_sas_smp_remote_device_decode_smp_response(
1856231296Sjimharris      fw_device, fw_request, NULL, SCI_IO_FAILURE_RETRY_REQUIRED
1857230557Sjimharris   );
1858230557Sjimharris}
1859230557Sjimharris
1860230557Sjimharris
1861230557Sjimharris/**
1862230557Sjimharris * @brief This method allocates and populates the smp phy list of a expander device.
1863230557Sjimharris *
1864230557Sjimharris * @param[in] fw_device The expander device, whose smp phy list is to be populated after
1865230557Sjimharris *                      getting REPORT GENERAL response.
1866230557Sjimharris *
1867230557Sjimharris * @return none.
1868230557Sjimharris */
1869230557Sjimharrisvoid scif_sas_smp_remote_device_populate_smp_phy_list(
1870230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device
1871230557Sjimharris)
1872230557Sjimharris{
1873230557Sjimharris   SCIF_SAS_SMP_PHY_T * this_smp_phy = NULL;
1874230557Sjimharris   U8                   expander_phy_id = 0;
1875230557Sjimharris
1876230557Sjimharris   SCIF_LOG_TRACE((
1877230557Sjimharris      sci_base_object_get_logger(fw_device),
1878230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1879230557Sjimharris      "scif_sas_smp_remote_device_populate_smp_phy_list(0x%x) enter\n",
1880230557Sjimharris      fw_device
1881230557Sjimharris   ));
1882230557Sjimharris
1883230557Sjimharris   for ( expander_phy_id = 0;
1884230557Sjimharris         expander_phy_id < fw_device->protocol_device.smp_device.number_of_phys;
1885230557Sjimharris         expander_phy_id++ )
1886230557Sjimharris   {
1887230557Sjimharris      this_smp_phy =
1888230557Sjimharris         scif_sas_controller_allocate_smp_phy(fw_device->domain->controller);
1889230557Sjimharris
1890230557Sjimharris      ASSERT( this_smp_phy != NULL );
1891230557Sjimharris
1892230557Sjimharris      if ( this_smp_phy != NULL )
1893230557Sjimharris         scif_sas_smp_phy_construct(this_smp_phy, fw_device, expander_phy_id);
1894230557Sjimharris   }
1895230557Sjimharris}
1896230557Sjimharris
1897230557Sjimharris
1898230557Sjimharris/**
1899230557Sjimharris * @brief This method updates a smp phy of a expander device based on DISCOVER response.
1900230557Sjimharris *
1901230557Sjimharris * @param[in] fw_device The expander device, one of whose smp phys is to be updated.
1902230557Sjimharris * @param[in] discover_response The smp DISCOVER response.
1903230557Sjimharris *
1904230557Sjimharris * @return SCI_STATUS If a smp phy pair between expanders has invalid routing attribute,
1905230557Sjimharris *                    return SCI_FAILURE_ILLEGAL_ROUTING_ATTRIBUTE_CONFIGURATION, otherwise,
1906230557Sjimharris *                    return SCI_SUCCESS
1907230557Sjimharris */
1908230557SjimharrisSCI_STATUS scif_sas_smp_remote_device_save_smp_phy_info(
1909230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
1910230557Sjimharris   SMP_RESPONSE_DISCOVER_T  * discover_response
1911230557Sjimharris)
1912230557Sjimharris{
1913230557Sjimharris   SCI_STATUS status = SCI_SUCCESS;
1914230557Sjimharris   SCIF_SAS_SMP_PHY_T * smp_phy = NULL;
1915230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * attached_device = NULL;
1916230557Sjimharris
1917230557Sjimharris    SCIF_LOG_TRACE((
1918230557Sjimharris      sci_base_object_get_logger(fw_device),
1919230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1920230557Sjimharris      "scif_sas_smp_remote_device_save_smp_phy_info(0x%x, 0x%x) enter\n",
1921230557Sjimharris      fw_device, discover_response
1922230557Sjimharris   ));
1923230557Sjimharris
1924230557Sjimharris   smp_phy = scif_sas_smp_remote_device_find_smp_phy_by_id(
1925230557Sjimharris                discover_response->phy_identifier,
1926230557Sjimharris                &fw_device->protocol_device.smp_device
1927230557Sjimharris             );
1928230557Sjimharris
1929230557Sjimharris   ASSERT( smp_phy != NULL );
1930230557Sjimharris
1931230557Sjimharris   //Note, attached_device could be NULL, not all the smp phy have to connected to a device.
1932230557Sjimharris   attached_device = (SCIF_SAS_REMOTE_DEVICE_T *)
1933230557Sjimharris      scif_domain_get_device_by_sas_address(
1934230557Sjimharris         fw_device->domain, &discover_response->attached_sas_address);
1935230557Sjimharris
1936231137Sjimharris   scif_sas_smp_phy_save_information(
1937231137Sjimharris      smp_phy, attached_device, discover_response);
1938230557Sjimharris
1939230557Sjimharris   //handle the special case of smp phys between expanders.
1940230557Sjimharris   if ( discover_response->protocols.u.bits.attached_smp_target )
1941230557Sjimharris   {
1942230557Sjimharris       //this fw_device is a child expander, just found its parent expander.
1943230557Sjimharris       //And there is no smp_phy constructed yet, record this phy connection.
1944230557Sjimharris       if ( attached_device != NULL
1945230557Sjimharris           && attached_device == fw_device->containing_device )
1946230557Sjimharris       {
1947230557Sjimharris          //record the smp phy info, for this phy connects to a upstream smp device.
1948230557Sjimharris          //the connection of a pair of smp phys are completed.
1949230557Sjimharris          status = scif_sas_smp_phy_set_attached_phy(
1950230557Sjimharris                      smp_phy,
1951230557Sjimharris                      discover_response->attached_phy_identifier,
1952230557Sjimharris                      attached_device
1953230557Sjimharris                   );
1954230557Sjimharris
1955230557Sjimharris          if (status == SCI_SUCCESS)
1956230557Sjimharris          {
1957230557Sjimharris             //check the routing attribute for this phy and its containing device's
1958230557Sjimharris             //expander_phy_routing_attribute.
1959230557Sjimharris             if ( scif_sas_smp_phy_verify_routing_attribute(
1960230557Sjimharris                     smp_phy, smp_phy->u.attached_phy) != SCI_SUCCESS )
1961230557Sjimharris                return SCI_FAILURE_ILLEGAL_ROUTING_ATTRIBUTE_CONFIGURATION;
1962230557Sjimharris          }
1963230557Sjimharris       }
1964230557Sjimharris    }
1965230557Sjimharris
1966230557Sjimharris    return status;
1967230557Sjimharris}
1968230557Sjimharris
1969230557Sjimharris#ifdef SCI_SMP_PHY_LIST_DEBUG_PRINT
1970230557Sjimharrisvoid scif_sas_smp_remote_device_print_smp_phy_list(
1971230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device
1972230557Sjimharris)
1973230557Sjimharris{
1974230557Sjimharris   SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device = &fw_device->protocol_device.smp_device;
1975230557Sjimharris   SCI_FAST_LIST_ELEMENT_T  * element = smp_remote_device->smp_phy_list.list_head;
1976230557Sjimharris   SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL;
1977230557Sjimharris
1978230557Sjimharris   SCIF_LOG_ERROR((
1979230557Sjimharris      sci_base_object_get_logger(fw_device),
1980230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE,
1981230557Sjimharris      "==========EXPANDER DEVICE (0x%x) smp phy list========== \n",
1982230557Sjimharris      fw_device
1983230557Sjimharris   ));
1984230557Sjimharris
1985230557Sjimharris   while (element != NULL)
1986230557Sjimharris   {
1987230557Sjimharris      curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element);
1988230557Sjimharris      element = sci_fast_list_get_next(element);
1989230557Sjimharris
1990230557Sjimharris      //print every thing about a smp phy
1991230557Sjimharris      SCIF_LOG_ERROR((
1992230557Sjimharris         sci_base_object_get_logger(fw_device),
1993230557Sjimharris         SCIF_LOG_OBJECT_REMOTE_DEVICE,
1994230557Sjimharris         "SMP_PHY_%d (0x%x), attached device(0x%x), attached_sas_address(%x%x) attached_device_type(%d), routing_attribute(%d)\n",
1995230557Sjimharris         curr_smp_phy->phy_identifier, curr_smp_phy,
1996230557Sjimharris         curr_smp_phy->u.end_device,
1997230557Sjimharris         curr_smp_phy->attached_sas_address.high, curr_smp_phy->attached_sas_address.low,
1998230557Sjimharris         curr_smp_phy->attached_device_type,
1999230557Sjimharris         curr_smp_phy->routing_attribute
2000230557Sjimharris      ));
2001230557Sjimharris   }
2002230557Sjimharris}
2003230557Sjimharris#endif
2004230557Sjimharris
2005230557Sjimharris
2006230557Sjimharris/**
2007230557Sjimharris * @brief This method configure upstream expander(s)' (if there is any) route info.
2008230557Sjimharris *
2009230557Sjimharris * @param[in] this_device The expander device that is currently in discover process.
2010230557Sjimharris *
2011230557Sjimharris * @return none.
2012230557Sjimharris */
2013230557Sjimharrisvoid scif_sas_smp_remote_device_configure_upstream_expander_route_info(
2014230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * this_device
2015230557Sjimharris)
2016230557Sjimharris{
2017230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * curr_child_expander = this_device;
2018230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * curr_parent_expander =
2019230557Sjimharris      scif_sas_remote_device_find_upstream_expander(this_device);
2020230557Sjimharris
2021230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * curr_config_route_info_expander = NULL;
2022230557Sjimharris
2023230557Sjimharris   SCIF_LOG_TRACE((
2024230557Sjimharris      sci_base_object_get_logger(this_device),
2025230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
2026230557Sjimharris      "scif_sas_smp_remote_device_configure_upstream_expander_route_info(0x%x) enter\n",
2027230557Sjimharris      this_device
2028230557Sjimharris   ));
2029230557Sjimharris
2030230557Sjimharris   //traverse back to find root device.
2031230557Sjimharris   while(curr_parent_expander != NULL )
2032230557Sjimharris   {
2033230557Sjimharris      //must set destination_smp_phy outside of find_upstream_expander() using the device
2034230557Sjimharris      //that is just about to finish the discovery.
2035230557Sjimharris      curr_parent_expander->protocol_device.smp_device.curr_config_route_destination_smp_phy =
2036230557Sjimharris         (SCIF_SAS_SMP_PHY_T*)sci_fast_list_get_object(
2037230557Sjimharris             this_device->protocol_device.smp_device.smp_phy_list.list_head);
2038230557Sjimharris
2039230557Sjimharris      curr_child_expander = curr_parent_expander;
2040230557Sjimharris      curr_parent_expander = scif_sas_remote_device_find_upstream_expander(curr_child_expander);
2041230557Sjimharris   }
2042230557Sjimharris
2043230557Sjimharris   //found the root device: curr_child_expander. configure it and its downstream expander(s) till
2044230557Sjimharris   //this_device or a self-configuring expander that configures others;
2045230557Sjimharris   curr_config_route_info_expander = curr_child_expander;
2046230557Sjimharris
2047230557Sjimharris   while ( curr_config_route_info_expander != NULL
2048230557Sjimharris          && curr_config_route_info_expander != this_device
2049230557Sjimharris          && curr_config_route_info_expander->protocol_device.smp_device.scheduled_activity
2050230557Sjimharris                == SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE
2051230557Sjimharris         )
2052230557Sjimharris   {
2053230557Sjimharris      if (curr_config_route_info_expander->protocol_device.smp_device.is_externally_configurable)
2054230557Sjimharris      {
2055230557Sjimharris         SCIF_SAS_SMP_PHY_T * phy_being_config =
2056230557Sjimharris            curr_config_route_info_expander->protocol_device.smp_device.config_route_smp_phy_anchor;
2057230557Sjimharris
2058230557Sjimharris         curr_config_route_info_expander->protocol_device.smp_device.curr_config_route_index =
2059230557Sjimharris            phy_being_config->config_route_table_index_anchor;
2060230557Sjimharris
2061230557Sjimharris         if (curr_config_route_info_expander->protocol_device.smp_device.curr_config_route_index != 0)
2062230557Sjimharris            curr_config_route_info_expander->protocol_device.smp_device.curr_config_route_index++;
2063230557Sjimharris
2064230557Sjimharris         curr_config_route_info_expander->protocol_device.smp_device.scheduled_activity =
2065230557Sjimharris            SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE;
2066230557Sjimharris
2067230557Sjimharris         //Find a downstream expander that has curr_config_route_destination_smp_phy.owning device
2068230557Sjimharris         //same as curr_config_route_info_expander.
2069230557Sjimharris         curr_config_route_info_expander = scif_sas_remote_device_find_downstream_expander(
2070230557Sjimharris            curr_config_route_info_expander);
2071230557Sjimharris      }
2072230557Sjimharris      else if (curr_config_route_info_expander->protocol_device.smp_device.is_able_to_config_others)
2073230557Sjimharris      {
2074230557Sjimharris         //no need to config route table to this expander and its children.
2075230557Sjimharris         //find its downstream expander and clear the planned config route table activity.
2076230557Sjimharris         SCIF_SAS_REMOTE_DEVICE_T * curr_downstream_expander =
2077230557Sjimharris            scif_sas_remote_device_find_downstream_expander(
2078230557Sjimharris               curr_config_route_info_expander);
2079230557Sjimharris
2080230557Sjimharris         scif_sas_smp_remote_device_clear(curr_config_route_info_expander);
2081230557Sjimharris
2082230557Sjimharris         while ( curr_downstream_expander != NULL
2083230557Sjimharris                && curr_downstream_expander != this_device )
2084230557Sjimharris         {
2085230557Sjimharris            scif_sas_smp_remote_device_clear(curr_downstream_expander);
2086230557Sjimharris            curr_downstream_expander =
2087230557Sjimharris               scif_sas_remote_device_find_downstream_expander(
2088230557Sjimharris                  curr_config_route_info_expander);
2089230557Sjimharris         }
2090230557Sjimharris
2091230557Sjimharris         break;
2092230557Sjimharris      }
2093230557Sjimharris      else
2094230557Sjimharris      {
2095230557Sjimharris         // current expander is a self-configuring expander, which is not externally
2096230557Sjimharris         // configurable, and doesn't config others. we need to simply skip this expander.
2097230557Sjimharris         curr_config_route_info_expander = scif_sas_remote_device_find_downstream_expander(
2098230557Sjimharris            curr_config_route_info_expander);
2099230557Sjimharris      }
2100230557Sjimharris   }
2101230557Sjimharris}
2102230557Sjimharris
2103230557Sjimharris/**
2104230557Sjimharris * @brief This method finds the immediate upstream expander of a given expander device.
2105230557Sjimharris *
2106230557Sjimharris * @param[in] this_device The given expander device, whose upstream expander is to be found.
2107230557Sjimharris *
2108230557Sjimharris * @return The immediate upstream expander. Or a NULL pointer if this_device is root already.
2109230557Sjimharris */
2110230557SjimharrisSCIF_SAS_REMOTE_DEVICE_T * scif_sas_remote_device_find_upstream_expander(
2111230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * this_device
2112230557Sjimharris)
2113230557Sjimharris{
2114230557Sjimharris   SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device =
2115230557Sjimharris      &this_device->protocol_device.smp_device;
2116230557Sjimharris
2117230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T    * upstream_expander = NULL;
2118230557Sjimharris
2119230557Sjimharris   SCI_FAST_LIST_ELEMENT_T     * element = smp_remote_device->smp_phy_list.list_head;
2120230557Sjimharris   SCIF_SAS_SMP_PHY_T          * curr_smp_phy = NULL;
2121230557Sjimharris
2122230557Sjimharris   SCIF_LOG_TRACE((
2123230557Sjimharris      sci_base_object_get_logger(this_device),
2124230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
2125230557Sjimharris      "scif_sas_smp_remote_device_configure_upstream_expander_route_info(0x%x) enter\n",
2126230557Sjimharris      this_device
2127230557Sjimharris   ));
2128230557Sjimharris
2129230557Sjimharris   while (element != NULL)
2130230557Sjimharris   {
2131230557Sjimharris      curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element);
2132230557Sjimharris      element = sci_fast_list_get_next(element);
2133230557Sjimharris
2134230557Sjimharris      if ( curr_smp_phy->routing_attribute == SUBTRACTIVE_ROUTING_ATTRIBUTE
2135230557Sjimharris          && ( curr_smp_phy->attached_device_type == SMP_EDGE_EXPANDER_DEVICE
2136230557Sjimharris              || curr_smp_phy->attached_device_type == SMP_FANOUT_EXPANDER_DEVICE)
2137230557Sjimharris          && curr_smp_phy->u.attached_phy != NULL
2138230557Sjimharris          && curr_smp_phy->u.attached_phy->routing_attribute == TABLE_ROUTING_ATTRIBUTE )
2139230557Sjimharris      {
2140230557Sjimharris         //set the current_activity and current_config_route_index for that
2141230557Sjimharris         //upstream expander.
2142230557Sjimharris         upstream_expander = curr_smp_phy->u.attached_phy->owning_device;
2143230557Sjimharris
2144230557Sjimharris         upstream_expander->protocol_device.smp_device.current_smp_request =
2145230557Sjimharris            SMP_FUNCTION_CONFIGURE_ROUTE_INFORMATION;
2146230557Sjimharris
2147230557Sjimharris         //if the upstream_expander's config route table method is config phy0 only or
2148230557Sjimharris         //config all phys, the current activity phy is found.
2149230557Sjimharris         upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor =
2150230557Sjimharris            scif_sas_smp_remote_device_find_smp_phy_by_id(
2151230557Sjimharris               curr_smp_phy->u.attached_phy->phy_identifier,
2152230557Sjimharris               &(curr_smp_phy->u.attached_phy->owning_device->protocol_device.smp_device)
2153230557Sjimharris            );
2154230557Sjimharris
2155230557Sjimharris         //if the upstream_expander's config route table method is config middle phy only
2156230557Sjimharris         //config highest phy only, the current activity phy needs a update.
2157230557Sjimharris         if ( scif_sas_smp_remote_device_get_config_route_table_method(upstream_expander)
2158230557Sjimharris                 == SCIF_SAS_CONFIG_ROUTE_TABLE_MIDDLE_PHY_ONLY )
2159230557Sjimharris         {
2160230557Sjimharris            upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor =
2161230557Sjimharris               scif_sas_smp_phy_find_middle_phy_in_wide_port (
2162230557Sjimharris                  upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor
2163230557Sjimharris               );
2164230557Sjimharris         }
2165230557Sjimharris         else if ( scif_sas_smp_remote_device_get_config_route_table_method(upstream_expander)
2166230557Sjimharris                      == SCIF_SAS_CONFIG_ROUTE_TABLE_HIGHEST_PHY_ONLY )
2167230557Sjimharris         {
2168230557Sjimharris            upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor =
2169230557Sjimharris               scif_sas_smp_phy_find_highest_phy_in_wide_port (
2170230557Sjimharris                  upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor
2171230557Sjimharris               );
2172230557Sjimharris         }
2173230557Sjimharris
2174230557Sjimharris         upstream_expander->protocol_device.smp_device.current_activity_phy_index =
2175230557Sjimharris            upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor->phy_identifier;
2176230557Sjimharris
2177230557Sjimharris         return upstream_expander;
2178230557Sjimharris      }
2179230557Sjimharris   }
2180230557Sjimharris
2181230557Sjimharris   return NULL;
2182230557Sjimharris}
2183230557Sjimharris
2184230557Sjimharris
2185230557Sjimharris/**
2186230557Sjimharris * @brief This method finds the immediate downstream expander of a given expander device.
2187230557Sjimharris *
2188230557Sjimharris * @param[in] this_device The given expander device, whose downstream expander is to be found.
2189230557Sjimharris *
2190230557Sjimharris * @return The immediate downstream expander. Or a NULL pointer if there is none.
2191230557Sjimharris */
2192230557SjimharrisSCIF_SAS_REMOTE_DEVICE_T * scif_sas_remote_device_find_downstream_expander(
2193230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * this_device
2194230557Sjimharris)
2195230557Sjimharris{
2196230557Sjimharris   SCIF_SAS_SMP_REMOTE_DEVICE_T * this_smp_remote_device =
2197230557Sjimharris      &this_device->protocol_device.smp_device;
2198230557Sjimharris
2199230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T    * downstream_expander = NULL;
2200230557Sjimharris
2201230557Sjimharris   SCI_FAST_LIST_ELEMENT_T     * element = this_smp_remote_device->smp_phy_list.list_head;
2202230557Sjimharris   SCIF_SAS_SMP_PHY_T          * curr_smp_phy = NULL;
2203230557Sjimharris
2204230557Sjimharris   SCIF_LOG_TRACE((
2205230557Sjimharris      sci_base_object_get_logger(this_device),
2206230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
2207230557Sjimharris      "scif_sas_remote_device_find_downstream_expander(0x%x) enter\n",
2208230557Sjimharris      this_device
2209230557Sjimharris   ));
2210230557Sjimharris
2211230557Sjimharris   while (element != NULL)
2212230557Sjimharris   {
2213230557Sjimharris      curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element);
2214230557Sjimharris      element = sci_fast_list_get_next(element);
2215230557Sjimharris
2216230557Sjimharris      if ( curr_smp_phy->routing_attribute == TABLE_ROUTING_ATTRIBUTE
2217230557Sjimharris          && curr_smp_phy->attached_device_type == SMP_EDGE_EXPANDER_DEVICE
2218230557Sjimharris          && curr_smp_phy->u.attached_phy != NULL)
2219230557Sjimharris      {
2220230557Sjimharris         //set the current_activity and current_config_route_index for that
2221230557Sjimharris         //upstream expander.
2222230557Sjimharris         downstream_expander = curr_smp_phy->u.attached_phy->owning_device;
2223230557Sjimharris
2224230557Sjimharris         if ( downstream_expander->protocol_device.smp_device.curr_config_route_destination_smp_phy != NULL
2225230557Sjimharris             && downstream_expander->protocol_device.smp_device.curr_config_route_destination_smp_phy->owning_device ==
2226230557Sjimharris                this_smp_remote_device->curr_config_route_destination_smp_phy->owning_device )
2227230557Sjimharris            return downstream_expander;
2228230557Sjimharris      }
2229230557Sjimharris   }
2230230557Sjimharris
2231230557Sjimharris   return NULL;
2232230557Sjimharris}
2233230557Sjimharris
2234230557Sjimharris
2235230557Sjimharris/**
2236230557Sjimharris * @brief This method follows route table optimization rule to check if a destination_device
2237230557Sjimharris *        should be recorded in the device_being_config's route table
2238230557Sjimharris *
2239230557Sjimharris * @param[in] device_being_config The upstream expander device, whose route table is being configured.
2240230557Sjimharris * @param[in] destination_smp_phy A smp phy whose attached device is potentially to be
2241230557Sjimharris *               recorded in route table.
2242230557Sjimharris *
2243230557Sjimharris * @return BOOL This method returns TRUE if a destination_device should be recorded in route table.
2244230557Sjimharris *              This method returns FALSE if a destination_device need not to be recorded
2245230557Sjimharris *              in route table.
2246230557Sjimharris */
2247230557SjimharrisBOOL scif_sas_smp_remote_device_do_config_route_info(
2248230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * device_being_config,
2249230557Sjimharris   SCIF_SAS_SMP_PHY_T       * destination_smp_phy
2250230557Sjimharris)
2251230557Sjimharris{
2252230557Sjimharris   SCI_SAS_ADDRESS_T device_being_config_sas_address;
2253230557Sjimharris
2254230557Sjimharris   SCIF_LOG_TRACE((
2255230557Sjimharris      sci_base_object_get_logger(device_being_config),
2256230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
2257230557Sjimharris      "scif_sas_smp_remote_device_do_config_route_info(0x%x, 0x%x) enter\n",
2258230557Sjimharris      device_being_config, destination_smp_phy
2259230557Sjimharris   ));
2260230557Sjimharris
2261230557Sjimharris   scic_remote_device_get_sas_address(
2262230557Sjimharris      device_being_config->core_object, &device_being_config_sas_address
2263230557Sjimharris   );
2264230557Sjimharris
2265230557Sjimharris   //refer to SAS-2 spec 4.8.3, rule (b)
2266230557Sjimharris   if ((destination_smp_phy->attached_sas_address.low == 0
2267230557Sjimharris        && destination_smp_phy->attached_sas_address.high == 0)
2268230557Sjimharris       && (destination_smp_phy->attached_device_type == SMP_NO_DEVICE_ATTACHED))
2269230557Sjimharris   {
2270230557Sjimharris      return FALSE;
2271230557Sjimharris   }
2272230557Sjimharris
2273230557Sjimharris   //refer to SAS-2 spec 4.8.3, rule (c), self-referencing.
2274230557Sjimharris   if (destination_smp_phy->attached_sas_address.high ==
2275230557Sjimharris          device_being_config_sas_address.high
2276230557Sjimharris       && destination_smp_phy->attached_sas_address.low ==
2277230557Sjimharris             device_being_config_sas_address.low)
2278230557Sjimharris   {
2279230557Sjimharris      return FALSE;
2280230557Sjimharris   }
2281230557Sjimharris
2282230557Sjimharris   //There will be no cases that falling into rule (a), (d), (e) to be excluded,
2283230557Sjimharris   //based on our current mechanism of cofig route table.
2284230557Sjimharris
2285230557Sjimharris   return TRUE;
2286230557Sjimharris}
2287230557Sjimharris
2288230557Sjimharris
2289230557Sjimharris/**
2290230557Sjimharris * @brief This method configures device_being_config's route table for all the enclosed devices in
2291230557Sjimharris *           a downstream smp device, destination_device.
2292230557Sjimharris *
2293230557Sjimharris * @param[in] device_being_config The upstream expander device, whose route table is being configured.
2294230557Sjimharris *
2295230557Sjimharris * @return None
2296230557Sjimharris */
2297230557Sjimharrisvoid scif_sas_smp_remote_device_configure_route_table(
2298230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * device_being_config
2299230557Sjimharris)
2300230557Sjimharris{
2301230557Sjimharris   //go through the smp phy list of this_device.
2302230557Sjimharris   SCI_FAST_LIST_ELEMENT_T     * element =
2303230557Sjimharris      &(device_being_config->protocol_device.smp_device.curr_config_route_destination_smp_phy->list_element);
2304230557Sjimharris   SCIF_SAS_SMP_PHY_T          * curr_smp_phy = NULL;
2305230557Sjimharris
2306230557Sjimharris   SCIF_LOG_TRACE((
2307230557Sjimharris      sci_base_object_get_logger(device_being_config),
2308230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
2309230557Sjimharris      "scif_sas_smp_remote_device_configure_route_table(0x%x) enter\n",
2310230557Sjimharris      device_being_config
2311230557Sjimharris   ));
2312230557Sjimharris
2313230557Sjimharris   device_being_config->protocol_device.smp_device.current_activity =
2314230557Sjimharris      SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE;
2315230557Sjimharris
2316230557Sjimharris   while (element != NULL)
2317230557Sjimharris   {
2318230557Sjimharris      curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element);
2319230557Sjimharris      element = sci_fast_list_get_next(element);
2320230557Sjimharris
2321230557Sjimharris      //check if this phy needs to be added to the expander's route table.
2322230557Sjimharris      if (scif_sas_smp_remote_device_do_config_route_info(
2323230557Sjimharris             device_being_config, curr_smp_phy) == TRUE )
2324230557Sjimharris      {
2325230557Sjimharris         SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device =
2326230557Sjimharris            &device_being_config->protocol_device.smp_device;
2327230557Sjimharris
2328230557Sjimharris         smp_remote_device->curr_config_route_destination_smp_phy =
2329230557Sjimharris            curr_smp_phy;
2330230557Sjimharris
2331230557Sjimharris         //Then config this_device's route table entry at the phy and next route_index.
2332230557Sjimharris         //send config_route_info using curr_smp_phy.phy_identifier and sas_address.
2333230557Sjimharris         scif_sas_smp_request_construct_config_route_info(
2334230557Sjimharris            device_being_config->domain->controller,
2335230557Sjimharris            device_being_config,
2336230557Sjimharris            smp_remote_device->current_activity_phy_index,
2337230557Sjimharris            smp_remote_device->curr_config_route_index,
2338230557Sjimharris            curr_smp_phy->attached_sas_address,
2339230557Sjimharris            FALSE
2340230557Sjimharris         );
2341230557Sjimharris
2342230557Sjimharris         //schedule the DPC.
2343230557Sjimharris         scif_cb_start_internal_io_task_schedule(
2344230557Sjimharris            device_being_config->domain->controller,
2345230557Sjimharris            scif_sas_controller_start_high_priority_io,
2346230557Sjimharris            device_being_config->domain->controller
2347230557Sjimharris         );
2348230557Sjimharris
2349230557Sjimharris         //stop here, we need to wait for config route info's response then send
2350230557Sjimharris         //the next one.
2351230557Sjimharris         break;
2352230557Sjimharris      }
2353230557Sjimharris   }
2354230557Sjimharris}
2355230557Sjimharris
2356230557Sjimharris
2357230557Sjimharris/**
2358230557Sjimharris * @brief This method walks through an expander's route table to clean table
2359230557Sjimharris *           attribute phys' route entries. This routine finds one table entry
2360230557Sjimharris *           to clean and will be called repeatly till it finishes cleanning the
2361230557Sjimharris *           whole table.
2362230557Sjimharris *
2363230557Sjimharris * @param[in] fw_device The expander device, whose route table entry is to be cleaned.
2364230557Sjimharris *
2365230557Sjimharris * @return None.
2366230557Sjimharris */
2367230557Sjimharrisvoid scif_sas_smp_remote_device_clean_route_table(
2368230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device
2369230557Sjimharris)
2370230557Sjimharris{
2371231137Sjimharris   SCIF_SAS_SMP_PHY_T * smp_phy_being_config;
2372230557Sjimharris
2373230557Sjimharris   SCIF_LOG_TRACE((
2374230557Sjimharris      sci_base_object_get_logger(fw_device),
2375230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
2376230557Sjimharris      "scif_sas_smp_remote_device_clean_route_table(0x%x) enter\n",
2377230557Sjimharris      fw_device
2378230557Sjimharris   ));
2379230557Sjimharris
2380230557Sjimharris   //from anchors, start to clean all the other route table entries.
2381230557Sjimharris   fw_device->protocol_device.smp_device.curr_config_route_index++;
2382230557Sjimharris
2383230557Sjimharris   if ( fw_device->protocol_device.smp_device.curr_config_route_index >=
2384230557Sjimharris           fw_device->protocol_device.smp_device.expander_route_indexes )
2385230557Sjimharris   {
2386230557Sjimharris      fw_device->protocol_device.smp_device.curr_config_route_index = 0;
2387230557Sjimharris
2388230557Sjimharris      do //find next table attribute PHY.
2389230557Sjimharris      {
2390230557Sjimharris         fw_device->protocol_device.smp_device.current_activity_phy_index++;
2391230557Sjimharris         if (fw_device->protocol_device.smp_device.current_activity_phy_index ==
2392230557Sjimharris                fw_device->protocol_device.smp_device.number_of_phys)
2393230557Sjimharris            fw_device->protocol_device.smp_device.current_activity_phy_index=0;
2394230557Sjimharris
2395230557Sjimharris         //phy_index changed, so update the smp_phy_being_config.
2396230557Sjimharris         smp_phy_being_config =
2397230557Sjimharris            scif_sas_smp_remote_device_find_smp_phy_by_id(
2398230557Sjimharris               fw_device->protocol_device.smp_device.current_activity_phy_index,
2399230557Sjimharris               &(fw_device->protocol_device.smp_device)
2400230557Sjimharris            );
2401230557Sjimharris      } while( smp_phy_being_config->routing_attribute != TABLE_ROUTING_ATTRIBUTE );
2402230557Sjimharris
2403230557Sjimharris      if ( smp_phy_being_config->phy_identifier !=
2404230557Sjimharris              fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->phy_identifier)
2405230557Sjimharris      {
2406230557Sjimharris         if (smp_phy_being_config->config_route_table_index_anchor != 0)
2407230557Sjimharris            fw_device->protocol_device.smp_device.curr_config_route_index =
2408230557Sjimharris               smp_phy_being_config->config_route_table_index_anchor + 1;
2409230557Sjimharris         else
2410230557Sjimharris            fw_device->protocol_device.smp_device.curr_config_route_index = 0;
2411230557Sjimharris      }
2412230557Sjimharris   }
2413230557Sjimharris
2414230557Sjimharris   if ( !(fw_device->protocol_device.smp_device.current_activity_phy_index ==
2415230557Sjimharris             fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->phy_identifier
2416230557Sjimharris          && fw_device->protocol_device.smp_device.curr_config_route_index == 0)
2417230557Sjimharris      )
2418230557Sjimharris   {
2419230557Sjimharris      //clean this route entry.
2420230557Sjimharris      scif_sas_smp_remote_device_clean_route_table_entry(fw_device);
2421230557Sjimharris   }
2422230557Sjimharris   else
2423230557Sjimharris   {
2424230557Sjimharris      fw_device->protocol_device.smp_device.is_route_table_cleaned = TRUE;
2425230557Sjimharris
2426230557Sjimharris      //set this device's activity to NON.
2427230557Sjimharris      fw_device->protocol_device.smp_device.current_activity =
2428230557Sjimharris         SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE;
2429230557Sjimharris
2430230557Sjimharris      //we need to notify domain that this device finished config route table, domain
2431230557Sjimharris      //may pick up other activities (i.e. Discover) for other expanders.
2432230557Sjimharris      scif_sas_domain_continue_discover(fw_device->domain);
2433230557Sjimharris   }
2434230557Sjimharris}
2435230557Sjimharris
2436230557Sjimharris/**
2437230557Sjimharris * @brief This method cleans a device's route table antry.
2438230557Sjimharris *
2439230557Sjimharris * @param[in] fw_device The expander device, whose route table entry is to be cleaned.
2440230557Sjimharris *
2441230557Sjimharris * @return None.
2442230557Sjimharris */
2443230557Sjimharrisvoid scif_sas_smp_remote_device_clean_route_table_entry(
2444230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device
2445230557Sjimharris)
2446230557Sjimharris{
2447230557Sjimharris   SCI_SAS_ADDRESS_T empty_sas_address;
2448230557Sjimharris   SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device =
2449230557Sjimharris      &(fw_device->protocol_device.smp_device);
2450230557Sjimharris
2451230557Sjimharris   SCIF_LOG_TRACE((
2452230557Sjimharris      sci_base_object_get_logger(fw_device),
2453230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
2454230557Sjimharris      "scif_sas_smp_remote_device_clean_route_table(0x%x) enter\n",
2455230557Sjimharris      fw_device
2456230557Sjimharris   ));
2457230557Sjimharris
2458230557Sjimharris   empty_sas_address.high = 0;
2459230557Sjimharris   empty_sas_address.low = 0;
2460230557Sjimharris
2461230557Sjimharris   scif_sas_smp_request_construct_config_route_info(
2462230557Sjimharris      fw_device->domain->controller,
2463230557Sjimharris      fw_device,
2464230557Sjimharris      smp_remote_device->current_activity_phy_index,
2465230557Sjimharris      smp_remote_device->curr_config_route_index,
2466230557Sjimharris      empty_sas_address,
2467230557Sjimharris      TRUE
2468230557Sjimharris   );
2469230557Sjimharris
2470230557Sjimharris   //schedule the DPC.
2471230557Sjimharris   scif_cb_start_internal_io_task_schedule(
2472230557Sjimharris      fw_device->domain->controller,
2473230557Sjimharris      scif_sas_controller_start_high_priority_io,
2474230557Sjimharris      fw_device->domain->controller
2475230557Sjimharris   );
2476230557Sjimharris}
2477230557Sjimharris
2478230557Sjimharris
2479230557Sjimharris/**
2480230557Sjimharris * @brief This method handles the case of exceeding route index when config route table
2481230557Sjimharris *           for a device, by removing the attached device of current config route
2482230557Sjimharris *           destination smp phy and the rest of smp phys in the same smp phy list.
2483230557Sjimharris *
2484230557Sjimharris * @param[in] fw_device The expander device, whose route table to be edited but failed
2485230557Sjimharris *               with a SMP function result of INDEX DOES NOT EXIST.
2486230557Sjimharris *
2487230557Sjimharris * @return None.
2488230557Sjimharris */
2489230557Sjimharrisvoid scif_sas_smp_remote_device_cancel_config_route_table_activity(
2490230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device
2491230557Sjimharris)
2492230557Sjimharris{
2493230557Sjimharris   //go through the rest of the smp phy list of destination device.
2494230557Sjimharris   SCI_FAST_LIST_ELEMENT_T     * element =
2495230557Sjimharris      &(fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy->list_element);
2496230557Sjimharris   SCIF_SAS_SMP_PHY_T          * curr_smp_phy = NULL;
2497230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T    * curr_attached_device = NULL;
2498230557Sjimharris
2499230557Sjimharris   SCIF_LOG_TRACE((
2500230557Sjimharris      sci_base_object_get_logger(fw_device),
2501230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
2502230557Sjimharris      "scif_sas_smp_remote_device_cancel_config_route_table_activity(0x%x) enter\n",
2503230557Sjimharris      fw_device
2504230557Sjimharris   ));
2505230557Sjimharris
2506230557Sjimharris   while (element != NULL)
2507230557Sjimharris   {
2508230557Sjimharris      curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element);
2509230557Sjimharris      element = sci_fast_list_get_next(element);
2510230557Sjimharris
2511230557Sjimharris      //check if this phy needs to be added to the expander's route table but can't due to
2512230557Sjimharris      //exceeding max route index.
2513230557Sjimharris      if (scif_sas_smp_remote_device_do_config_route_info(
2514230557Sjimharris             fw_device, curr_smp_phy) == TRUE )
2515230557Sjimharris      {
2516230557Sjimharris         //set the is_currently_discovered to FALSE for attached device. Then when
2517230557Sjimharris         //domain finish discover, domain will remove this device.
2518230557Sjimharris         curr_attached_device = (SCIF_SAS_REMOTE_DEVICE_T *)
2519230557Sjimharris            scif_domain_get_device_by_sas_address(
2520230557Sjimharris               fw_device->domain, &(curr_smp_phy->attached_sas_address));
2521230557Sjimharris
2522230557Sjimharris         if (curr_attached_device != NULL)
2523230557Sjimharris            curr_attached_device->is_currently_discovered = FALSE;
2524230557Sjimharris      }
2525230557Sjimharris   }
2526230557Sjimharris}
2527230557Sjimharris
2528230557Sjimharris
2529230557Sjimharris/**
2530230557Sjimharris * @brief This method cancel current activity and terminate the outstanding internal IO
2531230557Sjimharris *           if there is one.
2532230557Sjimharris *
2533230557Sjimharris * @param[in] fw_device The expander device, whose smp activity is to be canceled.
2534230557Sjimharris *
2535230557Sjimharris * @return None.
2536230557Sjimharris */
2537230557Sjimharrisvoid scif_sas_smp_remote_device_cancel_smp_activity(
2538230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device
2539230557Sjimharris)
2540230557Sjimharris{
2541230557Sjimharris   SCIF_LOG_TRACE((
2542230557Sjimharris      sci_base_object_get_logger(fw_device),
2543230557Sjimharris      SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
2544230557Sjimharris      "scif_sas_smp_remote_device_cancel_smp_activity(0x%x) enter\n",
2545230557Sjimharris      fw_device
2546230557Sjimharris   ));
2547230557Sjimharris
2548230557Sjimharris   //Terminate all of the requests in the silicon for this device.
2549230557Sjimharris   scif_sas_domain_terminate_requests(
2550230557Sjimharris      fw_device->domain, fw_device, NULL, NULL
2551230557Sjimharris   );
2552230557Sjimharris
2553230557Sjimharris   if (fw_device->protocol_device.smp_device.current_activity ==
2554230557Sjimharris          SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE)
2555230557Sjimharris      scif_sas_smp_remote_device_cancel_config_route_table_activity(fw_device);
2556230557Sjimharris
2557230557Sjimharris   //Clear the device to stop the smp sctivity.
2558230557Sjimharris   scif_sas_smp_remote_device_clear(fw_device);
2559230557Sjimharris}
2560230557Sjimharris
2561230557Sjimharris
2562230557Sjimharris/**
2563230557Sjimharris * @brief This method tells the way to configure route table for a expander. The
2564230557Sjimharris *          possible ways are: configure phy 0's route table, configure middle
2565230557Sjimharris *          phy's route table, configure highest order phy's route table,
2566230557Sjimharris *          configure all phys.
2567230557Sjimharris *
2568230557Sjimharris * @param[in] fw_device The expander device, whose config route table method is
2569230557Sjimharris *               to be chosen.
2570230557Sjimharris *
2571230557Sjimharris * @return one in 4 possible options.
2572230557Sjimharris */
2573230557SjimharrisU8 scif_sas_smp_remote_device_get_config_route_table_method(
2574230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device
2575230557Sjimharris)
2576230557Sjimharris{
2577230557Sjimharris   U8 config_route_table_method;
2578230557Sjimharris
2579230557Sjimharris   //config_route_table_method = SCIF_SAS_CONFIG_ROUTE_TABLE_MIDDLE_PHY_ONLY;
2580230557Sjimharris   config_route_table_method = SCIF_SAS_CONFIG_ROUTE_TABLE_ALL_PHYS;
2581230557Sjimharris
2582230557Sjimharris   return config_route_table_method;
2583230557Sjimharris}
2584230557Sjimharris
2585230557Sjimharris
2586230557Sjimharris/**
2587230557Sjimharris * @brief This method starts the EA target reset process by constructing
2588230557Sjimharris *           and starting a PHY CONTROL (hard reset) smp request.
2589230557Sjimharris *
2590230557Sjimharris * @param[in] expander_device The expander device, to which a PHY Control smp command is
2591230557Sjimharris *               sent.
2592230557Sjimharris * @param[in] target_device The expander attahced target device, to which the target reset
2593230557Sjimharris *               request is sent.
2594230557Sjimharris * @param[in] fw_request The target reset task request.
2595230557Sjimharris *
2596230557Sjimharris * @return none
2597230557Sjimharris */
2598230557Sjimharrisvoid scif_sas_smp_remote_device_start_target_reset(
2599230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * expander_device,
2600230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * target_device,
2601230557Sjimharris   SCIF_SAS_REQUEST_T       * fw_request
2602230557Sjimharris)
2603230557Sjimharris{
2604230557Sjimharris   SCIF_SAS_CONTROLLER_T * fw_controller = expander_device->domain->controller;
2605230557Sjimharris
2606230557Sjimharris   //set current_activity and current_smp_request to expander device.
2607230557Sjimharris   expander_device->protocol_device.smp_device.current_activity =
2608230557Sjimharris      SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_TARGET_RESET;
2609230557Sjimharris   expander_device->protocol_device.smp_device.current_smp_request =
2610230557Sjimharris      SMP_FUNCTION_PHY_CONTROL;
2611230557Sjimharris   expander_device->protocol_device.smp_device.current_activity_phy_index =
2612230557Sjimharris      target_device->expander_phy_identifier;
2613230557Sjimharris
2614230557Sjimharris   //A Phy Control smp request has been constructed towards parent device.
2615230557Sjimharris   //Walk the high priority io path.
2616230557Sjimharris   fw_controller->state_handlers->start_high_priority_io_handler(
2617230557Sjimharris      (SCI_BASE_CONTROLLER_T*) fw_controller,
2618230557Sjimharris      (SCI_BASE_REMOTE_DEVICE_T*) expander_device,
2619230557Sjimharris      (SCI_BASE_REQUEST_T*) fw_request,
2620230557Sjimharris      SCI_CONTROLLER_INVALID_IO_TAG
2621230557Sjimharris   );
2622230557Sjimharris}
2623230557Sjimharris
2624230557Sjimharris
2625