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 implementation of the SCIF_SAS_DOMAIN
62 * object.
63 */
64
65 #include <dev/isci/scil/intel_sas.h>
66 #include <dev/isci/scil/sci_fast_list.h>
67 #include <dev/isci/scil/scic_controller.h>
68 #include <dev/isci/scil/scic_port.h>
69 #include <dev/isci/scil/scic_remote_device.h>
70 #include <dev/isci/scil/scic_io_request.h>
71 #include <dev/isci/scil/scic_user_callback.h>
72 #include <dev/isci/scil/scif_user_callback.h>
73 #include <dev/isci/scil/sci_abstract_list.h>
74 #include <dev/isci/scil/sci_base_iterator.h>
75
76 #include <dev/isci/scil/scif_sas_logger.h>
77 #include <dev/isci/scil/scif_sas_domain.h>
78 #include <dev/isci/scil/scif_sas_controller.h>
79 #include <dev/isci/scil/scif_sas_remote_device.h>
80 #include <dev/isci/scil/scif_sas_smp_remote_device.h>
81 #include <dev/isci/scil/sci_util.h>
82
83 //******************************************************************************
84 //* P R I V A T E M E T H O D S
85 //******************************************************************************
86
87 /**
88 * @brief This method will attempt to handle an operation timeout (i.e.
89 * discovery or reset).
90 *
91 * @param[in] cookie This parameter specifies the domain in which the
92 * timeout occurred.
93 *
94 * @return none
95 */
96 static
97 void scif_sas_domain_operation_timeout_handler(
98 void * cookie
99 )
100 {
101 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) cookie;
102 U32 state;
103
104 state = sci_base_state_machine_get_state(&fw_domain->parent.state_machine);
105
106 // Based upon the state of the domain, we know whether we were in the
107 // process of performing discovery or a reset.
108 if (state == SCI_BASE_DOMAIN_STATE_DISCOVERING)
109 {
110 SCIF_LOG_WARNING((
111 sci_base_object_get_logger(fw_domain),
112 SCIF_LOG_OBJECT_DOMAIN,
113 "Domain:0x%x State:0x%x DISCOVER timeout!\n",
114 fw_domain, state
115 ));
116
117 fw_domain->operation.status = SCI_FAILURE_TIMEOUT;
118
119 //search all the smp devices in the domain and cancel their activities
120 //if there is any outstanding activity remained. The smp devices will terminate
121 //all the started internal IOs.
122 scif_sas_domain_cancel_smp_activities(fw_domain);
123
124 scif_sas_domain_continue_discover(fw_domain);
125 }
126 else
127 {
128 SCIF_LOG_ERROR((
129 sci_base_object_get_logger(fw_domain),
130 SCIF_LOG_OBJECT_DOMAIN,
131 "Domain:0x%x State:0x%x operation timeout in invalid state\n",
132 fw_domain, state
133 ));
134 }
135 }
136
137 //******************************************************************************
138 //* P U B L I C M E T H O D S
139 //******************************************************************************
140
141 SCI_PORT_HANDLE_T scif_domain_get_scic_port_handle(
142 SCI_DOMAIN_HANDLE_T domain
143 )
144 {
145 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) domain;
146
147 if ( (fw_domain == NULL) || (fw_domain->core_object == SCI_INVALID_HANDLE) )
148 return SCI_INVALID_HANDLE;
149
150 SCIF_LOG_WARNING((
151 sci_base_object_get_logger(fw_domain),
152 SCIF_LOG_OBJECT_DOMAIN,
153 "Domain:0x%x no associated core port found\n",
154 fw_domain
155 ));
156
157 return fw_domain->core_object;
158 }
159
160 // ---------------------------------------------------------------------------
161
162 SCI_REMOTE_DEVICE_HANDLE_T scif_domain_get_device_by_sas_address(
163 SCI_DOMAIN_HANDLE_T domain,
164 SCI_SAS_ADDRESS_T * sas_address
165 )
166 {
167 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) domain;
168 SCI_ABSTRACT_ELEMENT_T * element = sci_abstract_list_get_front(
169 &fw_domain->remote_device_list
170 );
171 SCIF_SAS_REMOTE_DEVICE_T * fw_device;
172 SCI_SAS_ADDRESS_T fw_device_address;
173
174 SCIF_LOG_TRACE((
175 sci_base_object_get_logger(domain),
176 SCIF_LOG_OBJECT_DOMAIN,
177 "scif_domain_get_device_by_sas_address(0x%x, 0x%x) enter\n",
178 domain, sas_address
179 ));
180
181 // Search the abstract list to see if there is a remote device with the
182 // same SAS address.
183 while (element != NULL)
184 {
185 fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
186 sci_abstract_list_get_object(element);
187
188 scic_remote_device_get_sas_address(
189 fw_device->core_object, &fw_device_address
190 );
191
192 // Check to see if this is the device for which we are searching.
193 if ( (fw_device_address.low == sas_address->low)
194 && (fw_device_address.high == sas_address->high) )
195 {
196 return fw_device;
197 }
198
199 element = sci_abstract_list_get_next(element);
200 }
201
202 return SCI_INVALID_HANDLE;
203 }
204
205 // ---------------------------------------------------------------------------
206
207 #if !defined(DISABLE_SCI_ITERATORS)
208
209 SCI_ITERATOR_HANDLE_T scif_domain_get_remote_device_iterator(
210 SCI_DOMAIN_HANDLE_T domain,
211 void * iterator_buffer
212 )
213 {
214 SCI_ITERATOR_HANDLE_T iterator = (SCI_ITERATOR_HANDLE_T *)iterator_buffer;
215
216 sci_base_iterator_construct(
217 iterator, &((SCIF_SAS_DOMAIN_T*) domain)->remote_device_list
218 );
219
220
221 return iterator;
222 }
223
224 #endif // !defined(DISABLE_SCI_ITERATORS)
225
226 // ---------------------------------------------------------------------------
227
228 SCI_STATUS scif_domain_discover(
229 SCI_DOMAIN_HANDLE_T domain,
230 U32 discover_timeout,
231 U32 device_timeout
232 )
233 {
234 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) domain;
235 SCI_STATUS status = SCI_SUCCESS;
236 SCI_STATUS op_status = SCI_SUCCESS;
237
238 SCIF_LOG_TRACE((
239 sci_base_object_get_logger(domain),
240 SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
241 "scif_domain_discover(0x%x, 0x%x, 0x%x) enter\n",
242 domain, discover_timeout, device_timeout
243 ));
244
245 // Check to make sure the size of the domain doesn't cause potential issues
246 // with the remote device timer and the domain timer.
247 if ((device_timeout * sci_abstract_list_size(&fw_domain->remote_device_list))
248 > discover_timeout)
249 status = SCI_WARNING_TIMER_CONFLICT;
250
251 op_status = fw_domain->state_handlers->discover_handler(
252 &fw_domain->parent, discover_timeout, device_timeout
253 );
254
255 // The status of the discover operation takes priority.
256 if ( (status == SCI_SUCCESS)
257 || (status != SCI_SUCCESS && op_status != SCI_SUCCESS) )
258 {
259 status = op_status;
260 }
261
262 return status;
263 }
264
265 // ---------------------------------------------------------------------------
266
267 U32 scif_domain_get_suggested_discover_timeout(
268 SCI_DOMAIN_HANDLE_T domain
269 )
270 {
271 U32 suggested_timeout = SCIF_DOMAIN_DISCOVER_TIMEOUT; //milli-seconds
272 return suggested_timeout;
273 }
274
275 // ---------------------------------------------------------------------------
276
277 void scic_cb_port_stop_complete(
278 SCI_CONTROLLER_HANDLE_T controller,
279 SCI_PORT_HANDLE_T port,
280 SCI_STATUS completion_status
281 )
282 {
283 SCIF_LOG_TRACE((
284 sci_base_object_get_logger((SCIF_SAS_DOMAIN_T*)sci_object_get_association(port)),
285 SCIF_LOG_OBJECT_DOMAIN,
286 "scic_cb_port_stop_complete(0x%x, 0x%x, 0x%x) enter\n",
287 controller, port, completion_status
288 ));
289 }
290
291 // ---------------------------------------------------------------------------
292
293 void scic_cb_port_ready(
294 SCI_CONTROLLER_HANDLE_T controller,
295 SCI_PORT_HANDLE_T port
296 )
297 {
298 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*)
299 sci_object_get_association(port);
300
301 SCIF_LOG_TRACE((
302 sci_base_object_get_logger(fw_domain),
303 SCIF_LOG_OBJECT_DOMAIN,
304 "scic_cb_port_ready(0x%x, 0x%x) enter\n",
305 controller, port
306 ));
307
308 // The controller supplied with the port should match the controller
309 // saved in the domain.
310 ASSERT(sci_object_get_association(controller) == fw_domain->controller);
311
312 fw_domain->is_port_ready = TRUE;
313
314 fw_domain->state_handlers->port_ready_handler(&fw_domain->parent);
315 }
316
317 // ---------------------------------------------------------------------------
318
319 void scic_cb_port_not_ready(
320 SCI_CONTROLLER_HANDLE_T controller,
321 SCI_PORT_HANDLE_T port,
322 U32 reason_code
323 )
324 {
325 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*)
326 sci_object_get_association(port);
327
328 SCIF_LOG_TRACE((
329 sci_base_object_get_logger(fw_domain),
330 SCIF_LOG_OBJECT_DOMAIN,
331 "scic_cb_port_not_ready(0x%x, 0x%x) enter\n",
332 controller, port
333 ));
334
335 // The controller supplied with the port should match the controller
336 // saved in the domain.
337 ASSERT(sci_object_get_association(controller) == fw_domain->controller);
338
339 // There is no need to take action on the port reconfiguring since it is
340 // just a change of the port width.
341 if (reason_code != SCIC_PORT_NOT_READY_RECONFIGURING)
342 {
343 fw_domain->is_port_ready = FALSE;
344
345 fw_domain->state_handlers->port_not_ready_handler(
346 &fw_domain->parent, reason_code);
347 }
348 }
349
350 // ---------------------------------------------------------------------------
351
352 void scic_cb_port_hard_reset_complete(
353 SCI_CONTROLLER_HANDLE_T controller,
354 SCI_PORT_HANDLE_T port,
355 SCI_STATUS completion_status
356 )
357 {
358 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*)
359 sci_object_get_association(port);
360 SCIF_SAS_REMOTE_DEVICE_T * fw_device;
361 SCI_FAST_LIST_ELEMENT_T * element = fw_domain->request_list.list_head;
362 SCIF_SAS_TASK_REQUEST_T * task_request = NULL;
363
364 SCIF_LOG_TRACE((
365 sci_base_object_get_logger(fw_domain),
366 SCIF_LOG_OBJECT_DOMAIN,
367 "scic_cb_port_hard_reset_complete(0x%x, 0x%x, 0x%x) enter\n",
368 controller, port, completion_status
369 ));
370
371 while (element != NULL)
372 {
373 task_request = (SCIF_SAS_TASK_REQUEST_T*) sci_fast_list_get_object(element);
374 element = sci_fast_list_get_next(element);
375
376 if (scif_sas_task_request_get_function(task_request)
377 == SCI_SAS_HARD_RESET)
378 {
379 fw_device = task_request->parent.device;
380
381 if (fw_device->domain == fw_domain)
382 {
383 scic_remote_device_reset_complete(fw_device->core_object);
384
385 scif_cb_task_request_complete(
386 sci_object_get_association(controller),
387 fw_device,
388 task_request,
389 (SCI_TASK_STATUS) completion_status
390 );
391
392 break;
393 }
394 }
395 }
396 }
397
398 // ---------------------------------------------------------------------------
399
400 void scic_cb_port_bc_change_primitive_recieved(
401 SCI_CONTROLLER_HANDLE_T controller,
402 SCI_PORT_HANDLE_T port,
403 SCI_PHY_HANDLE_T phy
404 )
405 {
406 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*)
407 sci_object_get_association(port);
408
409 SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T *)
410 sci_object_get_association(controller);
411
412 SCIF_LOG_TRACE((
413 sci_base_object_get_logger(fw_domain),
414 SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
415 "scic_cb_port_bc_change_primitive_recieved(0x%x, 0x%x, 0x%x) enter\n",
416 controller, port, phy
417 ));
418
419 if (fw_domain->broadcast_change_count == 0)
420 { // Enable the BCN detection only if the bcn_count is zero. If bcn_count is
421 // not zero at this time, we won't enable BCN detection since all non-zero
422 // BCN_count means same to us. Furthermore, we avoid BCN storm by not
423 // always enabling the BCN_detection.
424 scic_port_enable_broadcast_change_notification(fw_domain->core_object);
425 }
426
427 fw_domain->broadcast_change_count++;
428
429 //if there is smp device on this domain that is in the middle of discover
430 //process or smp target reset, don't notify the driver layer.
431 if( ! scif_sas_domain_is_in_smp_activity(fw_domain) )
432 // Notify the user that there is, potentially, a change to the domain.
433 scif_cb_domain_change_notification(fw_controller, fw_domain);
434 }
435
436 // ---------------------------------------------------------------------------
437
438 void scic_cb_port_bc_ses_primitive_recieved(
439 SCI_CONTROLLER_HANDLE_T controller,
440 SCI_PORT_HANDLE_T port,
441 SCI_PHY_HANDLE_T phy
442 )
443 {
444 SCIF_LOG_TRACE((
445 sci_base_object_get_logger(sci_object_get_association(port)),
446 SCIF_LOG_OBJECT_DOMAIN,
447 "scic_cb_port_bc_ses_primitive_received(0x%x, 0x%x, 0x%x) enter\n",
448 controller, port, phy
449 ));
450 }
451
452 // ---------------------------------------------------------------------------
453
454 void scic_cb_port_bc_expander_primitive_recieved(
455 SCI_CONTROLLER_HANDLE_T controller,
456 SCI_PORT_HANDLE_T port,
457 SCI_PHY_HANDLE_T phy
458 )
459 {
460 SCIF_LOG_TRACE((
461 sci_base_object_get_logger(sci_object_get_association(port)),
462 SCIF_LOG_OBJECT_DOMAIN,
463 "scic_cb_port_bc_expander_primitive_received(0x%x, 0x%x, 0x%x) enter\n",
464 controller, port, phy
465 ));
466 }
467
468 // ---------------------------------------------------------------------------
469
470 void scic_cb_port_bc_aen_primitive_recieved(
471 SCI_CONTROLLER_HANDLE_T controller,
472 SCI_PORT_HANDLE_T port,
473 SCI_PHY_HANDLE_T phy
474 )
475 {
476 SCIF_LOG_TRACE((
477 sci_base_object_get_logger(sci_object_get_association(port)),
478 SCIF_LOG_OBJECT_DOMAIN,
479 "scic_cb_port_bc_aen_primitive_received(0x%x, 0x%x, 0x%x) enter\n",
480 controller, port, phy
481 ));
482 }
483
484 // ---------------------------------------------------------------------------
485
486 void scic_cb_port_link_up(
487 SCI_CONTROLLER_HANDLE_T controller,
488 SCI_PORT_HANDLE_T port,
489 SCI_PHY_HANDLE_T phy
490 )
491 {
492 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*)
493 sci_object_get_association(port);
494
495 SCIF_LOG_TRACE((
496 sci_base_object_get_logger(sci_object_get_association(port)),
497 SCIF_LOG_OBJECT_DOMAIN,
498 "scic_cb_port_link_up(0x%x, 0x%x, 0x%x) enter\n",
499 controller, port, phy
500 ));
501
502 scif_sas_domain_update_device_port_width(fw_domain, port);
503 }
504
505 // ---------------------------------------------------------------------------
506
507 void scic_cb_port_link_down(
508 SCI_CONTROLLER_HANDLE_T controller,
509 SCI_PORT_HANDLE_T port,
510 SCI_PHY_HANDLE_T phy
511 )
512 {
513 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*)
514 sci_object_get_association(port);
515
516 SCIF_LOG_TRACE((
517 sci_base_object_get_logger(sci_object_get_association(port)),
518 SCIF_LOG_OBJECT_DOMAIN,
519 "scic_cb_port_link_down(0x%x, 0x%x, 0x%x) enter\n",
520 controller, port, phy
521 ));
522
523 scif_sas_domain_update_device_port_width(fw_domain, port);
524 }
525
526 //******************************************************************************
527 //* P R O T E C T E D M E T H O D S
528 //******************************************************************************
529
530 /**
531 * @brief This method constructs the framework's SAS domain object. During
532 * the construction process a linkage to the corresponding core port
533 * object.
534 *
535 * @param[in] domain This parameter specifies the domain object to be
536 * constructed.
537 * @param[in] domain_id This parameter specifies the ID for the domain
538 * object.
539 * @param[in] fw_controller This parameter specifies the controller managing
540 * the domain being constructed.
541 *
542 * @return none
543 */
544 void scif_sas_domain_construct(
545 SCIF_SAS_DOMAIN_T * fw_domain,
546 U8 domain_id,
547 SCIF_SAS_CONTROLLER_T * fw_controller
548 )
549 {
550 SCIF_LOG_TRACE((
551 sci_base_object_get_logger(fw_controller),
552 SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_INITIALIZATION,
553 "scif_sas_domain_construct(0x%x, 0x%x, 0x%x) enter\n",
554 fw_domain, domain_id, fw_controller
555 ));
556
557 sci_base_domain_construct(
558 &fw_domain->parent,
559 sci_base_object_get_logger(fw_controller),
560 scif_sas_domain_state_table
561 );
562
563 scif_sas_domain_initialize_state_logging(fw_domain);
564
565 sci_abstract_list_construct(
566 &fw_domain->remote_device_list, &fw_controller->free_remote_device_pool
567 );
568
569 // Retrieve the core's port object that directly corresponds to this
570 // domain.
571 scic_controller_get_port_handle(
572 fw_controller->core_object, domain_id, &fw_domain->core_object
573 );
574
575 // Set the association in the core port to this framework domain object.
576 sci_object_set_association(
577 (SCI_OBJECT_HANDLE_T) fw_domain->core_object, fw_domain
578 );
579
580 sci_fast_list_init(&fw_domain->request_list);
581
582 fw_domain->operation.timer = NULL;
583
584 fw_domain->is_port_ready = FALSE;
585 fw_domain->device_start_count = 0;
586 fw_domain->controller = fw_controller;
587 fw_domain->operation.status = SCI_SUCCESS;
588 fw_domain->is_config_route_table_needed = FALSE;
589 }
590
591 /**
592 * @brief This method will terminate the requests outstanding in the core
593 * based on the supplied criteria.
594 * - if the all three parameters are specified then only the single
595 * SCIF_SAS_REQUEST object is terminated.
596 * - if only the SCIF_SAS_DOMAIN and SCIF_SAS_REMOTE_DEVICE are
597 * specified, then all SCIF_SAS_REQUEST objects outstanding at
598 * the device are terminated. The one exclusion to this rule is
599 * that the fw_requestor is not terminated.
600 * - if only the SCIF_SAS_DOMAIN object is specified, then all
601 * SCIF_SAS_REQUEST objects outstanding in the domain are
602 * terminated.
603 *
604 * @param[in] fw_domain This parameter specifies the domain in which to
605 * terminate requests.
606 * @param[in] fw_device This parameter specifies the remote device in
607 * which to terminate requests. This parameter can be NULL
608 * as long as the fw_request parameter is NULL. It is a
609 * required parameter if the fw_request parameter is not NULL.
610 * @param[in] fw_request This parameter specifies the request object to
611 * be terminated. This parameter can be NULL.
612 * @param[in] fw_requestor This parameter specifies the task management
613 * request that is responsible for the termination of requests.
614 *
615 * @return none
616 */
617 void scif_sas_domain_terminate_requests(
618 SCIF_SAS_DOMAIN_T * fw_domain,
619 SCIF_SAS_REMOTE_DEVICE_T * fw_device,
620 SCIF_SAS_REQUEST_T * fw_request,
621 SCIF_SAS_TASK_REQUEST_T * fw_requestor
622 )
623 {
624 SCIF_LOG_TRACE((
625 sci_base_object_get_logger(fw_domain),
626 SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_TASK_MANAGEMENT,
627 "scif_sas_domain_terminate_requests(0x%x, 0x%x, 0x%x, 0x%x) enter\n",
628 fw_domain, fw_device, fw_request, fw_requestor
629 ));
630
631 if (fw_request != NULL)
632 {
633 fw_request->terminate_requestor = fw_requestor;
634 fw_request->state_handlers->abort_handler(&fw_request->parent);
635 }
636 else
637 {
638 SCI_FAST_LIST_ELEMENT_T * element = fw_domain->request_list.list_head;
639 SCIF_SAS_REQUEST_T * request = NULL;
640
641 // Cycle through the fast list of IO requests. Terminate each
642 // outstanding requests that matches the criteria supplied by the
643 // caller.
644 while (element != NULL)
645 {
646 request = (SCIF_SAS_REQUEST_T*) sci_fast_list_get_object(element);
647 // The current element may be deleted from the list because of
648 // IO completion so advance to the next element early
649 element = sci_fast_list_get_next(element);
650
651 // Ensure we pass the supplied criteria before terminating the
652 // request.
653 if (
654 (fw_device == NULL)
655 || (
656 (request->device == fw_device)
657 && (fw_requestor != (SCIF_SAS_TASK_REQUEST_T*) request)
658 )
659 )
660 {
661 if (
662 (request->is_waiting_for_abort_task_set == FALSE) ||
663 (request->terminate_requestor == NULL)
664 )
665 {
666 request->terminate_requestor = fw_requestor;
667 request->state_handlers->abort_handler(&request->parent);
668 }
669 }
670 }
671 }
672 }
673
674 /**
675 * @brief This method searches the domain object to find a
676 * SCIF_SAS_REQUEST object associated with the supplied IO tag.
677 *
678 * @param[in] fw_domain This parameter specifies the domain in which to
679 * to find the request object.
680 * @param[in] io_tag This parameter specifies the IO tag value for which
681 * to locate the corresponding request.
682 *
683 * @return This method returns a pointer to the SCIF_SAS_REQUEST object
684 * associated with the supplied IO tag.
685 * @retval NULL This value is returned if the IO tag does not resolve to
686 * a request.
687 */
688 SCIF_SAS_REQUEST_T * scif_sas_domain_get_request_by_io_tag(
689 SCIF_SAS_DOMAIN_T * fw_domain,
690 U16 io_tag
691 )
692 {
693 SCI_FAST_LIST_ELEMENT_T * element = fw_domain->request_list.list_head;
694 SCIF_SAS_IO_REQUEST_T * io_request = NULL;
695
696 SCIF_LOG_TRACE((
697 sci_base_object_get_logger(fw_domain),
698 SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_TASK_MANAGEMENT,
699 "scif_sas_domain_get_request_by_io_tag(0x%x, 0x%x) enter\n",
700 fw_domain, io_tag
701 ));
702
703 while (element != NULL)
704 {
705 io_request = (SCIF_SAS_IO_REQUEST_T*) sci_fast_list_get_object(element);
706
707 // Check to see if we located the request with an identical IO tag.
708 if (scic_io_request_get_io_tag(io_request->parent.core_object) == io_tag)
709 return &io_request->parent;
710
711 element = sci_fast_list_get_next(element);
712 }
713
714 return NULL;
715 }
716
717 /**
718 * @brief This method performs domain object initialization to be done
719 * when the scif_controller_initialize() method is invoked.
720 * This includes operation timeout creation.
721 *
722 * @param[in] fw_domain This parameter specifies the domain object for
723 * which to perform initialization.
724 *
725 * @return none
726 */
727 void scif_sas_domain_initialize(
728 SCIF_SAS_DOMAIN_T * fw_domain
729 )
730 {
731 SCIF_LOG_TRACE((
732 sci_base_object_get_logger(fw_domain),
733 SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_INITIALIZATION,
734 "scif_sas_domain_initialize(0x%x) enter\n",
735 fw_domain
736 ));
737
738 // Create the timer for each domain. It is too early in the process
739 // to allocate this during construction since the user didn't have
740 // a chance to set it's association.
741 if (fw_domain->operation.timer == 0)
742 {
743 fw_domain->operation.timer = scif_cb_timer_create(
744 fw_domain->controller,
745 scif_sas_domain_operation_timeout_handler,
746 fw_domain
747 );
748 }
749 }
750
751 /**
752 * @brief This method performs domain object handling for core remote
753 * device start complete notifications. Core remote device starts
754 * and start completes are only done during discovery. This could
755 * ultimately be wrapped into a handler method on the domain (they
756 * actually already exist). This method will decrement the number
757 * of device start operations ongoing and attempt to determine if
758 * discovery is complete.
759 *
760 * @param[in] fw_domain This parameter specifies the domain object for
761 * which to perform initialization.
762 *
763 * @return none
764 */
765 void scif_sas_domain_remote_device_start_complete(
766 SCIF_SAS_DOMAIN_T * fw_domain,
767 SCIF_SAS_REMOTE_DEVICE_T * fw_device
768 )
769 {
770 SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols;
771
772 SCIF_LOG_TRACE((
773 sci_base_object_get_logger(fw_domain),
774 SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
775 "scif_sas_domain_remote_device_start_complete(0x%x, 0x%x) enter\n",
776 fw_domain, fw_device
777 ));
778
779 // If a device is being started/start completed, then we must be
780 // during discovery.
781 ASSERT(fw_domain->parent.state_machine.current_state_id
782 == SCI_BASE_DOMAIN_STATE_DISCOVERING);
783
784 scic_remote_device_get_protocols(fw_device->core_object, &dev_protocols);
785
786 // Decrement the number of devices being started and check to see
787 // if all have finished being started or failed as the case may be.
788 fw_domain->device_start_in_progress_count--;
789
790 if ( dev_protocols.u.bits.attached_smp_target )
791 {
792 if ( fw_device->containing_device == NULL )
793 //kick off the smp discover process if this expander is direct attached.
794 scif_sas_smp_remote_device_start_discover(fw_device);
795 else
796 //mark this device, the discover process of this device will start after
797 //its containing smp device finish discover.
798 fw_device->protocol_device.smp_device.scheduled_activity =
799 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER;
800 }
801 else
802 {
803 fw_domain->state_handlers->device_start_complete_handler(
804 &fw_domain->parent, &fw_device->parent
805 );
806 }
807 }
808
809
810 /**
811 * @brief This methods check each smp device in this domain. If there is at
812 * least one smp device in discover or target reset activity, this
813 * domain is considered in smp activity. Note this routine is not
814 * called on fast IO path.
815 *
816 * @param[in] fw_domain The framework domain object
817 *
818 * @return BOOL value to indicate whether a domain is in SMP activity.
819 */
820 BOOL scif_sas_domain_is_in_smp_activity(
821 SCIF_SAS_DOMAIN_T * fw_domain
822 )
823 {
824 SCI_ABSTRACT_ELEMENT_T * current_element =
825 sci_abstract_list_get_front(&fw_domain->remote_device_list);
826
827 SCIF_SAS_REMOTE_DEVICE_T * current_device;
828
829 while ( current_element != NULL )
830 {
831 SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols;
832
833 current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
834 sci_abstract_list_get_object(current_element);
835
836 scic_remote_device_get_protocols(current_device->core_object,
837 &dev_protocols
838 );
839
840 if (dev_protocols.u.bits.attached_smp_target &&
841 scif_sas_smp_remote_device_is_in_activity(current_device))
842 return TRUE;
843
844 current_element =
845 sci_abstract_list_get_next(current_element);
846 }
847
848 return FALSE;
849 }
850
851
852 /**
853 * @brief This methods finds a expander attached device by searching the domain's
854 * device list using connected expander device and expander phy id.
855 *
856 * @param[in] fw_domain The framework domain object
857 * @param[in] parent_device The expander device the target device attaches to.
858 * @param[in] expander_phy_id The expander phy id that the target device owns.
859 *
860 * @return found remote device or a NULL value if no device found.
861 */
862 SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_get_device_by_containing_device(
863 SCIF_SAS_DOMAIN_T * fw_domain,
864 SCIF_SAS_REMOTE_DEVICE_T * containing_device,
865 U8 expander_phy_id
866 )
867 {
868 SCIF_SAS_REMOTE_DEVICE_T * fw_device;
869 SCI_ABSTRACT_ELEMENT_T * element = sci_abstract_list_get_front(
870 &fw_domain->remote_device_list
871 );
872
873 //parent device must not be NULL.
874 ASSERT(containing_device != NULL);
875
876 // Search the abstract list to see if there is a remote device meets the
877 // search condition.
878 while (element != NULL)
879 {
880 fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
881 sci_abstract_list_get_object(element);
882
883 // Check to see if this is the device for which we are searching.
884 if (
885 (fw_device->containing_device == containing_device)
886 && (fw_device->expander_phy_identifier == expander_phy_id)
887 )
888 {
889 return fw_device;
890 }
891
892 element = sci_abstract_list_get_next(element);
893 }
894
895 return SCI_INVALID_HANDLE;
896 }
897
898
899 /**
900 * @brief This methods finds the first device that is in STOPPED state and its
901 * connection_rate is still in SPINUP_HOLD(value 3).
902 *
903 * @param[in] fw_domain The framework domain object
904 *
905 * @return SCIF_SAS_REMOTE_DEVICE_T The device that is in SPINUP_HOLD or NULL.
906 */
907 SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_find_device_in_spinup_hold(
908 SCIF_SAS_DOMAIN_T * fw_domain
909 )
910 {
911 SCI_ABSTRACT_ELEMENT_T * current_element;
912 SCIF_SAS_REMOTE_DEVICE_T * current_device;
913
914 SCIF_LOG_TRACE((
915 sci_base_object_get_logger(fw_domain),
916 SCIF_LOG_OBJECT_DOMAIN,
917 "scif_sas_domain_find_device_in_spinup_hold(0x%x) enter\n",
918 fw_domain
919 ));
920
921 //search throught domain's device list to find the first sata device on spinup_hold
922 current_element = sci_abstract_list_get_front(&fw_domain->remote_device_list);
923 while (current_element != NULL )
924 {
925 current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
926 sci_abstract_list_get_object(current_element);
927
928 //We must get the next element before we remove the current
929 //device. Or else, we will get wrong next_element, since the erased
930 //element has been put into free pool.
931 current_element = sci_abstract_list_get_next(current_element);
932
933 if ( sci_base_state_machine_get_state(¤t_device->parent.state_machine) ==
934 SCI_BASE_REMOTE_DEVICE_STATE_STOPPED
935 && scic_remote_device_get_connection_rate(current_device->core_object) ==
936 SCI_SATA_SPINUP_HOLD )
937 {
938 return current_device;
939 }
940 }
941
942 return NULL;
943 }
944
945
946 /**
947 * @brief This methods finds the first device that has specific activity scheduled.
948 *
949 * @param[in] fw_domain The framework domain object
950 * @param[in] smp_activity A specified smp activity. The valid range is [1,5].
951 *
952 * @return SCIF_SAS_REMOTE_DEVICE_T The device that has specified smp activity scheduled.
953 */
954 SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_find_device_has_scheduled_activity(
955 SCIF_SAS_DOMAIN_T * fw_domain,
956 U8 smp_activity
957 )
958 {
959 SCI_ABSTRACT_ELEMENT_T * current_element =
960 sci_abstract_list_get_front(&fw_domain->remote_device_list);
961
962 SCIF_SAS_REMOTE_DEVICE_T * current_device;
963 SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols;
964
965 //config route table activity has higher priority than discover activity.
966 while ( current_element != NULL )
967 {
968 current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
969 sci_abstract_list_get_object(current_element);
970
971 scic_remote_device_get_protocols(current_device->core_object,
972 &dev_protocols);
973
974 current_element =
975 sci_abstract_list_get_next(current_element);
976
977 if ( dev_protocols.u.bits.attached_smp_target
978 && current_device->protocol_device.smp_device.scheduled_activity ==
979 smp_activity)
980 {
981 return current_device;
982 }
983 }
984
985 return NULL;
986 }
987
988
989 /**
990 * @brief This methods finds the smp device that has is_config_route_table_scheduled
991 * flag set to TRUE, and start config route table on it. If there is no
992 * smp device scheduled to config route table, find the smp device has
993 * is_discover_scheduled and start the smp discover process on them.
994 *
995 * @param[in] fw_domain The framework domain that to start smp discover process.
996 *
997 * @return NONE
998 */
999 void scif_sas_domain_start_smp_activity(
1000 SCIF_SAS_DOMAIN_T * fw_domain
1001 )
1002 {
1003 SCIF_SAS_REMOTE_DEVICE_T * device_has_scheduled_activity = NULL;
1004
1005 //first, find device that has config route table activity scheduled.
1006 //config route table activity has higher priority than Discover.
1007 device_has_scheduled_activity =
1008 scif_sas_domain_find_device_has_scheduled_activity(
1009 fw_domain,
1010 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE
1011 );
1012
1013 if (device_has_scheduled_activity != NULL)
1014 {
1015 scif_sas_smp_remote_device_configure_route_table(device_has_scheduled_activity);
1016 device_has_scheduled_activity->protocol_device.smp_device.scheduled_activity =
1017 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE;
1018 return;
1019 }
1020
1021 //if no device has config route table activity scheduled, search again, find
1022 //device has discover activity scheduled.
1023 device_has_scheduled_activity =
1024 scif_sas_domain_find_device_has_scheduled_activity(
1025 fw_domain,
1026 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER
1027 );
1028
1029 if (device_has_scheduled_activity != NULL)
1030 scif_sas_smp_remote_device_start_discover(device_has_scheduled_activity);
1031 }
1032
1033
1034 /**
1035 * @brief This method starts domain's smp discover process from the top level expander.
1036 *
1037 * @param[in] fw_domain The framework domain that to start smp discover process.
1038 @ @param[in] top_expander The top level expander device to start smp discover process.
1039 *
1040 * @return None
1041 */
1042 void scif_sas_domain_start_smp_discover(
1043 SCIF_SAS_DOMAIN_T * fw_domain,
1044 SCIF_SAS_REMOTE_DEVICE_T * top_expander
1045 )
1046 {
1047 SCI_ABSTRACT_ELEMENT_T * current_element =
1048 sci_abstract_list_get_front(&fw_domain->remote_device_list);
1049
1050 SCIF_SAS_REMOTE_DEVICE_T * current_device;
1051
1052 // something changed behind expander
1053 // mark all the device behind expander to be NOT
1054 // is_currently_discovered.
1055 while ( current_element != NULL )
1056 {
1057 current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
1058 sci_abstract_list_get_object(current_element);
1059
1060 current_device->is_currently_discovered = FALSE;
1061
1062 //reset all the devices' port witdh except the top expander.
1063 if (current_device->containing_device != NULL)
1064 current_device->device_port_width = 1;
1065
1066 current_element = sci_abstract_list_get_next(current_element);
1067 }
1068
1069 //expander device itself should be set to is_currently_discovered.
1070 top_expander->is_currently_discovered = TRUE;
1071
1072 //kick off the smp discover process.
1073 scif_sas_smp_remote_device_start_discover(top_expander);
1074 }
1075
1076
1077 /**
1078 * @brief This method continues domain's smp discover process and
1079 * may transit to READY state if all smp activities are done.
1080 *
1081 * @param[in] fw_domain The framework domain that to start smp discover process.
1082 *
1083 * @return None
1084 */
1085 void scif_sas_domain_continue_discover(
1086 SCIF_SAS_DOMAIN_T * fw_domain
1087 )
1088 {
1089 SCIF_LOG_TRACE((
1090 sci_base_object_get_logger(fw_domain),
1091 SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1092 "scif_sas_domain_continue_discover(0x%x) enter\n",
1093 fw_domain
1094 ));
1095
1096 if ( fw_domain->device_start_in_progress_count == 0
1097 && !scif_sas_domain_is_in_smp_activity(fw_domain) )
1098 {
1099 //domain scrub the remote device list to see if there is a need
1100 //to start smp discover on expander device. There may be no
1101 //need to start any smp discover.
1102 scif_sas_domain_start_smp_activity(fw_domain);
1103
1104 //In domain discovery timeout case, we cancel all
1105 //the smp activities, and terminate all the smp requests, then
1106 //this routine is called. But the smp request may not done
1107 //terminated. We want to guard the domain trasitting to READY
1108 //by checking outstanding smp request count. If there is outstanding
1109 //smp request, the domain will not transit to READY. Later when
1110 //the smp request is terminated at smp remote device, this routine
1111 //will be called then the domain will transit to READY state.
1112 if ( ! scif_sas_domain_is_in_smp_activity(fw_domain)
1113 && scif_sas_domain_get_smp_request_count(fw_domain) == 0)
1114 {
1115 //before domain transit to READY state, domain has some clean up
1116 //work to do, such like update domain's remote devcie list.
1117 scif_sas_domain_finish_discover(fw_domain);
1118 }
1119 }
1120 }
1121
1122
1123 /**
1124 * @brief This method finishes domain's smp discover process and
1125 * update domain's remote device list.
1126 *
1127 * @param[in] fw_domain The framework domain that's to finish smp discover process.
1128 *
1129 * @return None
1130 */
1131 void scif_sas_domain_finish_discover(
1132 SCIF_SAS_DOMAIN_T * fw_domain
1133 )
1134 {
1135 SCIF_SAS_REMOTE_DEVICE_T * current_device = NULL;
1136 SCI_ABSTRACT_ELEMENT_T * current_element = NULL;
1137
1138 SCIF_LOG_TRACE((
1139 sci_base_object_get_logger(fw_domain),
1140 SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1141 "scif_sas_domain_finish_discover(0x%x) enter\n",
1142 fw_domain
1143 ));
1144
1145 //need to scrub all the devices behind the expander. Check each
1146 //device's discover_status. if the is_currently_discovered is FALSE, means
1147 //the device is not been rediscovered. this device needs to be removed.
1148 current_element = sci_abstract_list_get_front(&fw_domain->remote_device_list);
1149 while (current_element != NULL )
1150 {
1151 current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
1152 sci_abstract_list_get_object(current_element);
1153
1154 //We must get the next element before we remove the current
1155 //device. Or else, we will get wrong next_element, since the erased
1156 //element has been put into free pool.
1157 current_element = sci_abstract_list_get_next(current_element);
1158
1159 if ( current_device->is_currently_discovered == FALSE )
1160 {
1161 // Notify the framework user of the device removal.
1162 scif_cb_domain_device_removed(
1163 fw_domain->controller, fw_domain, current_device
1164 );
1165 }
1166 }
1167
1168 sci_base_state_machine_change_state(
1169 &fw_domain->parent.state_machine, SCI_BASE_DOMAIN_STATE_READY
1170 );
1171 }
1172
1173
1174
1175 /**
1176 * @brief This method remove an expander device and its child devices, in order to
1177 * deal with a detected illeagal phy connection.
1178 *
1179 * @param[in] fw_domain The domain that a expander belongs to.
1180 * @param[in] fw_device The expander device to be removed.
1181 *
1182 * @return none.
1183 */
1184 void scif_sas_domain_remove_expander_device(
1185 SCIF_SAS_DOMAIN_T * fw_domain,
1186 SCIF_SAS_REMOTE_DEVICE_T * fw_device
1187 )
1188 {
1189 SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device =
1190 &fw_device->protocol_device.smp_device;
1191
1192 SCI_FAST_LIST_ELEMENT_T * element = smp_remote_device->smp_phy_list.list_head;
1193 SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL;
1194 SCIF_SAS_REMOTE_DEVICE_T * current_device = NULL;
1195
1196 while (element != NULL)
1197 {
1198 curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element);
1199 element = sci_fast_list_get_next(element);
1200
1201 if ( curr_smp_phy->attached_device_type != SMP_NO_DEVICE_ATTACHED
1202 && curr_smp_phy->u.end_device != NULL )
1203 {
1204 if (curr_smp_phy->attached_device_type == SMP_END_DEVICE_ONLY)
1205 current_device = curr_smp_phy->u.end_device;
1206 else
1207 current_device = curr_smp_phy->u.attached_phy->owning_device;
1208
1209 scif_cb_domain_device_removed(fw_domain->controller, fw_domain, current_device);
1210 }
1211 }
1212
1213 //remove device itself
1214 scif_cb_domain_device_removed(fw_domain->controller, fw_domain, fw_device);
1215 }
1216
1217
1218 /**
1219 * @brief This method searches the whole domain and finds all the smp devices to
1220 * cancel their smp activities if there is any.
1221 *
1222 * @param[in] fw_domain The domain that its smp activities are to be canceled.
1223 *
1224 * @return none.
1225 */
1226 void scif_sas_domain_cancel_smp_activities(
1227 SCIF_SAS_DOMAIN_T * fw_domain
1228 )
1229 {
1230 SCI_ABSTRACT_ELEMENT_T * current_element =
1231 sci_abstract_list_get_front(&fw_domain->remote_device_list);
1232
1233 SCIF_SAS_REMOTE_DEVICE_T * current_device;
1234
1235 //purge all the outstanding internal IOs in HPQ.
1236 scif_sas_high_priority_request_queue_purge_domain(
1237 &fw_domain->controller->hprq, fw_domain
1238 );
1239
1240 while ( current_element != NULL )
1241 {
1242 SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols;
1243
1244 current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
1245 sci_abstract_list_get_object(current_element);
1246
1247 scic_remote_device_get_protocols(current_device->core_object,
1248 &dev_protocols
1249 );
1250
1251 if (dev_protocols.u.bits.attached_smp_target)
1252 {
1253 scif_sas_smp_remote_device_cancel_smp_activity(current_device);
1254 }
1255
1256 current_element =
1257 sci_abstract_list_get_next(current_element);
1258 }
1259 }
1260
1261
1262 /**
1263 * @brief This method searches the domain's request list and counts outstanding
1264 * smp IOs.
1265 *
1266 * @param[in] fw_domain The domain that its request list is to be searched.
1267 *
1268 * @return U8 The possible return value of this routine is 0 or 1.
1269 */
1270 U8 scif_sas_domain_get_smp_request_count(
1271 SCIF_SAS_DOMAIN_T * fw_domain
1272 )
1273 {
1274 SCI_FAST_LIST_ELEMENT_T * element = fw_domain->request_list.list_head;
1275 SCIF_SAS_REQUEST_T * request = NULL;
1276 U8 count = 0;
1277 SCIC_TRANSPORT_PROTOCOL protocol;
1278
1279 // Cycle through the fast list of IO requests. Terminate each
1280 // outstanding requests that matches the criteria supplied by the
1281 // caller.
1282 while (element != NULL)
1283 {
1284 request = (SCIF_SAS_REQUEST_T*) sci_fast_list_get_object(element);
1285 // The current element may be deleted from the list because of
1286 // IO completion so advance to the next element early
1287 element = sci_fast_list_get_next(element);
1288
1289 protocol = scic_io_request_get_protocol(request->core_object);
1290
1291 if ( protocol == SCIC_SMP_PROTOCOL)
1292 count++;
1293 }
1294
1295 return count;
1296 }
1297
1298
1299 /**
1300 * @brief This method start clear affiliation activities for smp devices in
1301 * this domain.
1302 *
1303 * @param[in] fw_domain The domain that its smp devices are scheduled to clear
1304 * affiliation for all the EA SATA devices.
1305 *
1306 * @return none.
1307 */
1308 void scif_sas_domain_start_clear_affiliation(
1309 SCIF_SAS_DOMAIN_T * fw_domain
1310 )
1311 {
1312 scif_sas_domain_schedule_clear_affiliation(fw_domain);
1313 scif_sas_domain_continue_clear_affiliation(fw_domain);
1314 }
1315
1316
1317 /**
1318 * @brief This method schedule clear affiliation activities for smp devices in
1319 * this domain.
1320 *
1321 * @param[in] fw_domain The domain that its smp devices are scheduled to clear
1322 * affiliation for all the EA SATA devices.
1323 *
1324 * @return none.
1325 */
1326 void scif_sas_domain_schedule_clear_affiliation(
1327 SCIF_SAS_DOMAIN_T * fw_domain
1328 )
1329 {
1330 SCI_ABSTRACT_ELEMENT_T * current_element =
1331 sci_abstract_list_get_front(&fw_domain->remote_device_list);
1332
1333 SCIF_SAS_REMOTE_DEVICE_T * current_device;
1334 SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols;
1335
1336 //config route table activity has higher priority than discover activity.
1337 while ( current_element != NULL )
1338 {
1339 current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
1340 sci_abstract_list_get_object(current_element);
1341
1342 scic_remote_device_get_protocols(current_device->core_object,
1343 &dev_protocols);
1344
1345 current_element =
1346 sci_abstract_list_get_next(current_element);
1347
1348 if ( dev_protocols.u.bits.attached_smp_target )
1349 {
1350 current_device->protocol_device.smp_device.scheduled_activity =
1351 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAR_AFFILIATION;
1352 }
1353 }
1354 }
1355
1356
1357 /**
1358 * @brief This method carries clear affiliation activities for a smp devices in
1359 * this domain during controller stop process.
1360 *
1361 * @param[in] fw_domain The domain that its smp devices are to clear
1362 * affiliation for all the EA SATA devices.
1363 *
1364 * @return none.
1365 */
1366 void scif_sas_domain_continue_clear_affiliation(
1367 SCIF_SAS_DOMAIN_T * fw_domain
1368 )
1369 {
1370 SCIF_SAS_REMOTE_DEVICE_T * smp_device =
1371 scif_sas_domain_find_device_has_scheduled_activity(
1372 fw_domain,
1373 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAR_AFFILIATION
1374 );
1375
1376 if (smp_device != NULL)
1377 scif_sas_smp_remote_device_start_clear_affiliation(smp_device);
1378 else
1379 {
1380 //This domain has done clear affiliation.
1381 SCIF_SAS_CONTROLLER_T * fw_controller = fw_domain->controller;
1382 fw_controller->current_domain_to_clear_affiliation++;
1383
1384 //let controller continue to clear affiliation on other domains.
1385 scif_sas_controller_clear_affiliation(fw_domain->controller);
1386 }
1387 }
1388
1389
1390 /**
1391 * @brief This method releases resource for a framework domain.
1392 *
1393 * @param[in] fw_controller This parameter specifies the framework
1394 * controller, its associated domain's resources are to be released.
1395 * @param[in] fw_domain This parameter specifies the framework
1396 * domain whose resources are to be released.
1397 */
1398 void scif_sas_domain_release_resource(
1399 SCIF_SAS_CONTROLLER_T * fw_controller,
1400 SCIF_SAS_DOMAIN_T * fw_domain
1401 )
1402 {
1403 if (fw_domain->operation.timer != NULL)
1404 {
1405 scif_cb_timer_destroy(fw_controller, fw_domain->operation.timer);
1406 fw_domain->operation.timer = NULL;
1407 }
1408 }
1409
1410
1411 /**
1412 * @brief This method finds the a EA device that has target reset scheduled.
1413 *
1414 * @param[in] fw_domain The framework domain object
1415 *
1416 * @return SCIF_SAS_REMOTE_DEVICE_T The EA device that has target reset scheduled.
1417 */
1418 SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_find_next_ea_target_reset(
1419 SCIF_SAS_DOMAIN_T * fw_domain
1420 )
1421 {
1422 SCI_ABSTRACT_ELEMENT_T * current_element;
1423 SCIF_SAS_REMOTE_DEVICE_T * current_device;
1424
1425 SCIF_LOG_TRACE((
1426 sci_base_object_get_logger(fw_domain),
1427 SCIF_LOG_OBJECT_DOMAIN,
1428 "scif_sas_domain_find_next_ea_target_reset(0x%x) enter\n",
1429 fw_domain
1430 ));
1431
1432 //search through domain's device list to find the first sata device on spinup_hold
1433 current_element = sci_abstract_list_get_front(&fw_domain->remote_device_list);
1434 while (current_element != NULL )
1435 {
1436 current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
1437 sci_abstract_list_get_object(current_element);
1438
1439 current_element = sci_abstract_list_get_next(current_element);
1440
1441 if ( current_device->ea_target_reset_request_scheduled != NULL )
1442 {
1443 return current_device;
1444 }
1445 }
1446
1447 return NULL;
1448 }
1449
1450 #if !defined(DISABLE_WIDE_PORTED_TARGETS)
1451 /**
1452 * @brief This method update the direct attached device port width.
1453 *
1454 * @param[in] fw_domain The framework domain object
1455 * @param[in] port The associated port object which recently has link up/down
1456 * event happened.
1457 *
1458 * @return none
1459 */
1460 void scif_sas_domain_update_device_port_width(
1461 SCIF_SAS_DOMAIN_T * fw_domain,
1462 SCI_PORT_HANDLE_T port
1463 )
1464 {
1465 SCIF_SAS_REMOTE_DEVICE_T * fw_device;
1466 SCIC_PORT_PROPERTIES_T properties;
1467 U8 new_port_width = 0;
1468
1469 SCIF_LOG_TRACE((
1470 sci_base_object_get_logger(fw_domain),
1471 SCIF_LOG_OBJECT_DOMAIN,
1472 "scif_sas_domain_update_device_port_width(0x%x, 0x%x) enter\n",
1473 fw_domain, port
1474 ));
1475
1476 scic_port_get_properties(port, &properties);
1477
1478 fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)
1479 scif_domain_get_device_by_sas_address(
1480 fw_domain, &properties.remote.sas_address
1481 );
1482
1483 // If the device already existed in the domain, it is a wide port SSP target,
1484 // we need to update its port width.
1485 if (fw_device != SCI_INVALID_HANDLE)
1486 {
1487 SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols;
1488 scic_remote_device_get_protocols(fw_device->core_object, &dev_protocols);
1489
1490 if (dev_protocols.u.bits.attached_ssp_target)
1491 {
1492 //Get accurate port width from port's phy mask for a DA device.
1493 SCI_GET_BITS_SET_COUNT(properties.phy_mask, new_port_width);
1494
1495 scif_sas_remote_device_update_port_width(fw_device, new_port_width);
1496 }
1497 }
1498 }
1499 #endif //#if !defined(DISABLE_WIDE_PORTED_TARGETS)
1500
1501
1502 #ifdef SCI_LOGGING
1503 /**
1504 * This method will turn on logging of domain state changes.
1505 *
1506 * @param[in] fw_domain The domain for which the state logging is to be turned
1507 * on.
1508 */
1509 void scif_sas_domain_initialize_state_logging(
1510 SCIF_SAS_DOMAIN_T *fw_domain
1511 )
1512 {
1513 sci_base_state_machine_logger_initialize(
1514 &fw_domain->parent.state_machine_logger,
1515 &fw_domain->parent.state_machine,
1516 &fw_domain->parent.parent,
1517 scif_cb_logger_log_states,
1518 "SCIF_SAS_DOMAIN_T", "base state machine",
1519 SCIF_LOG_OBJECT_DOMAIN
1520 );
1521 }
1522
1523 /**
1524 * This method will turn off logging of domain state changes.
1525 *
1526 * @param[in] fw_domain The domain for which the state logging is to be turned
1527 * off.
1528 */
1529 void scif_sas_domain_deinitialize_state_logging(
1530 SCIF_SAS_DOMAIN_T *fw_domain
1531 )
1532 {
1533 sci_base_state_machine_logger_deinitialize(
1534 &fw_domain->parent.state_machine_logger,
1535 &fw_domain->parent.state_machine
1536 );
1537 }
1538 #endif
Cache object: 59faa7065dbc92a6a413dd2b49fe3c91
|