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