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