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