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 */
96static
97void 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
141SCI_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
162SCI_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
209SCI_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
228SCI_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
267U32 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
277void 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
293void 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
319void 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
352void 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
400void 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
438void 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
454void 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
470void 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
486void 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
507void 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 */
544void 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 */
617void 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 */
688SCIF_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 */
727void 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 */
765void 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 */
820BOOL 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 */
862SCIF_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 */
907SCIF_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(&current_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 */
954SCIF_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 */
999void 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 */
1042void 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 */
1085void 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 */
1131void 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 */
1184void 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 */
1226void 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 */
1270U8 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 */
1308void 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 */
1326void 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 */
1366void 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 */
1398void 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 */
1418SCIF_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 */
1460void 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 */
1509void 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 */
1529void 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
1539