1230557Sjimharris/*-
2230557Sjimharris * This file is provided under a dual BSD/GPLv2 license.  When using or
3230557Sjimharris * redistributing this file, you may do so under either license.
4230557Sjimharris *
5230557Sjimharris * GPL LICENSE SUMMARY
6230557Sjimharris *
7230557Sjimharris * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
8230557Sjimharris *
9230557Sjimharris * This program is free software; you can redistribute it and/or modify
10230557Sjimharris * it under the terms of version 2 of the GNU General Public License as
11230557Sjimharris * published by the Free Software Foundation.
12230557Sjimharris *
13230557Sjimharris * This program is distributed in the hope that it will be useful, but
14230557Sjimharris * WITHOUT ANY WARRANTY; without even the implied warranty of
15230557Sjimharris * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16230557Sjimharris * General Public License for more details.
17230557Sjimharris *
18230557Sjimharris * You should have received a copy of the GNU General Public License
19230557Sjimharris * along with this program; if not, write to the Free Software
20230557Sjimharris * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
21230557Sjimharris * The full GNU General Public License is included in this distribution
22230557Sjimharris * in the file called LICENSE.GPL.
23230557Sjimharris *
24230557Sjimharris * BSD LICENSE
25230557Sjimharris *
26230557Sjimharris * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
27230557Sjimharris * All rights reserved.
28230557Sjimharris *
29230557Sjimharris * Redistribution and use in source and binary forms, with or without
30230557Sjimharris * modification, are permitted provided that the following conditions
31230557Sjimharris * are met:
32230557Sjimharris *
33230557Sjimharris *   * Redistributions of source code must retain the above copyright
34230557Sjimharris *     notice, this list of conditions and the following disclaimer.
35230557Sjimharris *   * Redistributions in binary form must reproduce the above copyright
36230557Sjimharris *     notice, this list of conditions and the following disclaimer in
37230557Sjimharris *     the documentation and/or other materials provided with the
38230557Sjimharris *     distribution.
39230557Sjimharris *
40230557Sjimharris * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
41230557Sjimharris * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
42230557Sjimharris * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
43230557Sjimharris * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
44230557Sjimharris * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45230557Sjimharris * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
46230557Sjimharris * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
47230557Sjimharris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
48230557Sjimharris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
49230557Sjimharris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
50230557Sjimharris * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51230557Sjimharris */
52230557Sjimharris
53230557Sjimharris#include <sys/cdefs.h>
54230557Sjimharris__FBSDID("$FreeBSD$");
55230557Sjimharris
56230557Sjimharris/**
57230557Sjimharris * @file
58230557Sjimharris *
59230557Sjimharris * @brief This file contains the implementation of the SCIF_SAS_DOMAIN
60230557Sjimharris *        object.
61230557Sjimharris */
62230557Sjimharris
63230557Sjimharris#include <dev/isci/scil/intel_sas.h>
64230557Sjimharris#include <dev/isci/scil/sci_fast_list.h>
65230557Sjimharris#include <dev/isci/scil/scic_controller.h>
66230557Sjimharris#include <dev/isci/scil/scic_port.h>
67230557Sjimharris#include <dev/isci/scil/scic_remote_device.h>
68230557Sjimharris#include <dev/isci/scil/scic_io_request.h>
69230557Sjimharris#include <dev/isci/scil/scic_user_callback.h>
70230557Sjimharris#include <dev/isci/scil/scif_user_callback.h>
71230557Sjimharris#include <dev/isci/scil/sci_abstract_list.h>
72230557Sjimharris#include <dev/isci/scil/sci_base_iterator.h>
73230557Sjimharris
74230557Sjimharris#include <dev/isci/scil/scif_sas_logger.h>
75230557Sjimharris#include <dev/isci/scil/scif_sas_domain.h>
76230557Sjimharris#include <dev/isci/scil/scif_sas_controller.h>
77230557Sjimharris#include <dev/isci/scil/scif_sas_remote_device.h>
78230557Sjimharris#include <dev/isci/scil/scif_sas_smp_remote_device.h>
79230557Sjimharris#include <dev/isci/scil/sci_util.h>
80230557Sjimharris
81230557Sjimharris//******************************************************************************
82230557Sjimharris//* P R I V A T E   M E T H O D S
83230557Sjimharris//******************************************************************************
84230557Sjimharris
85230557Sjimharris/**
86230557Sjimharris * @brief This method will attempt to handle an operation timeout (i.e.
87230557Sjimharris *        discovery or reset).
88230557Sjimharris *
89230557Sjimharris * @param[in]  cookie This parameter specifies the domain in which the
90230557Sjimharris *             timeout occurred.
91230557Sjimharris *
92230557Sjimharris * @return none
93230557Sjimharris */
94230557Sjimharrisstatic
95230557Sjimharrisvoid scif_sas_domain_operation_timeout_handler(
96230557Sjimharris   void * cookie
97230557Sjimharris)
98230557Sjimharris{
99230557Sjimharris   SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) cookie;
100230557Sjimharris   U32                 state;
101230557Sjimharris
102230557Sjimharris   state = sci_base_state_machine_get_state(&fw_domain->parent.state_machine);
103230557Sjimharris
104230557Sjimharris   // Based upon the state of the domain, we know whether we were in the
105230557Sjimharris   // process of performing discovery or a reset.
106230557Sjimharris   if (state == SCI_BASE_DOMAIN_STATE_DISCOVERING)
107230557Sjimharris   {
108230557Sjimharris      SCIF_LOG_WARNING((
109230557Sjimharris         sci_base_object_get_logger(fw_domain),
110230557Sjimharris         SCIF_LOG_OBJECT_DOMAIN,
111230557Sjimharris         "Domain:0x%x State:0x%x DISCOVER timeout!\n",
112230557Sjimharris         fw_domain, state
113230557Sjimharris      ));
114230557Sjimharris
115230557Sjimharris      fw_domain->operation.status = SCI_FAILURE_TIMEOUT;
116230557Sjimharris
117230557Sjimharris      //search all the smp devices in the domain and cancel their activities
118230557Sjimharris      //if there is any outstanding activity remained. The smp devices will terminate
119230557Sjimharris      //all the started internal IOs.
120230557Sjimharris      scif_sas_domain_cancel_smp_activities(fw_domain);
121230557Sjimharris
122230557Sjimharris      scif_sas_domain_continue_discover(fw_domain);
123230557Sjimharris   }
124230557Sjimharris   else
125230557Sjimharris   {
126230557Sjimharris      SCIF_LOG_ERROR((
127230557Sjimharris         sci_base_object_get_logger(fw_domain),
128230557Sjimharris         SCIF_LOG_OBJECT_DOMAIN,
129230557Sjimharris         "Domain:0x%x State:0x%x operation timeout in invalid state\n",
130230557Sjimharris         fw_domain, state
131230557Sjimharris      ));
132230557Sjimharris   }
133230557Sjimharris}
134230557Sjimharris
135230557Sjimharris//******************************************************************************
136230557Sjimharris//* P U B L I C   M E T H O D S
137230557Sjimharris//******************************************************************************
138230557Sjimharris
139230557SjimharrisSCI_PORT_HANDLE_T scif_domain_get_scic_port_handle(
140230557Sjimharris   SCI_DOMAIN_HANDLE_T  domain
141230557Sjimharris)
142230557Sjimharris{
143230557Sjimharris   SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) domain;
144230557Sjimharris
145231137Sjimharris   if ( (fw_domain == NULL) || (fw_domain->core_object == SCI_INVALID_HANDLE) )
146231137Sjimharris      return SCI_INVALID_HANDLE;
147230557Sjimharris
148230557Sjimharris   SCIF_LOG_WARNING((
149230557Sjimharris      sci_base_object_get_logger(fw_domain),
150230557Sjimharris      SCIF_LOG_OBJECT_DOMAIN,
151230557Sjimharris      "Domain:0x%x no associated core port found\n",
152230557Sjimharris      fw_domain
153230557Sjimharris   ));
154230557Sjimharris
155231137Sjimharris   return fw_domain->core_object;
156230557Sjimharris}
157230557Sjimharris
158230557Sjimharris// ---------------------------------------------------------------------------
159230557Sjimharris
160230557SjimharrisSCI_REMOTE_DEVICE_HANDLE_T scif_domain_get_device_by_sas_address(
161230557Sjimharris   SCI_DOMAIN_HANDLE_T   domain,
162230557Sjimharris   SCI_SAS_ADDRESS_T   * sas_address
163230557Sjimharris)
164230557Sjimharris{
165230557Sjimharris   SCIF_SAS_DOMAIN_T        * fw_domain = (SCIF_SAS_DOMAIN_T*) domain;
166230557Sjimharris   SCI_ABSTRACT_ELEMENT_T   * element   = sci_abstract_list_get_front(
167230557Sjimharris                                             &fw_domain->remote_device_list
168230557Sjimharris                                          );
169230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device;
170230557Sjimharris   SCI_SAS_ADDRESS_T          fw_device_address;
171230557Sjimharris
172230557Sjimharris   SCIF_LOG_TRACE((
173230557Sjimharris      sci_base_object_get_logger(domain),
174230557Sjimharris      SCIF_LOG_OBJECT_DOMAIN,
175230557Sjimharris      "scif_domain_get_device_by_sas_address(0x%x, 0x%x) enter\n",
176230557Sjimharris      domain, sas_address
177230557Sjimharris   ));
178230557Sjimharris
179230557Sjimharris   // Search the abstract list to see if there is a remote device with the
180230557Sjimharris   // same SAS address.
181230557Sjimharris   while (element != NULL)
182230557Sjimharris   {
183230557Sjimharris      fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
184230557Sjimharris                  sci_abstract_list_get_object(element);
185230557Sjimharris
186230557Sjimharris      scic_remote_device_get_sas_address(
187230557Sjimharris         fw_device->core_object, &fw_device_address
188230557Sjimharris      );
189230557Sjimharris
190230557Sjimharris      // Check to see if this is the device for which we are searching.
191230557Sjimharris      if (  (fw_device_address.low == sas_address->low)
192230557Sjimharris         && (fw_device_address.high == sas_address->high) )
193230557Sjimharris      {
194230557Sjimharris         return fw_device;
195230557Sjimharris      }
196230557Sjimharris
197230557Sjimharris      element = sci_abstract_list_get_next(element);
198230557Sjimharris   }
199230557Sjimharris
200230557Sjimharris   return SCI_INVALID_HANDLE;
201230557Sjimharris}
202230557Sjimharris
203230557Sjimharris// ---------------------------------------------------------------------------
204230557Sjimharris
205230557Sjimharris#if !defined(DISABLE_SCI_ITERATORS)
206230557Sjimharris
207230557SjimharrisSCI_ITERATOR_HANDLE_T scif_domain_get_remote_device_iterator(
208230557Sjimharris   SCI_DOMAIN_HANDLE_T   domain,
209230557Sjimharris   void                * iterator_buffer
210230557Sjimharris)
211230557Sjimharris{
212230557Sjimharris   SCI_ITERATOR_HANDLE_T iterator = (SCI_ITERATOR_HANDLE_T *)iterator_buffer;
213230557Sjimharris
214230557Sjimharris   sci_base_iterator_construct(
215230557Sjimharris      iterator, &((SCIF_SAS_DOMAIN_T*) domain)->remote_device_list
216230557Sjimharris   );
217230557Sjimharris
218230557Sjimharris
219230557Sjimharris   return iterator;
220230557Sjimharris}
221230557Sjimharris
222230557Sjimharris#endif // !defined(DISABLE_SCI_ITERATORS)
223230557Sjimharris
224230557Sjimharris// ---------------------------------------------------------------------------
225230557Sjimharris
226230557SjimharrisSCI_STATUS scif_domain_discover(
227230557Sjimharris   SCI_DOMAIN_HANDLE_T   domain,
228230557Sjimharris   U32                   discover_timeout,
229230557Sjimharris   U32                   device_timeout
230230557Sjimharris)
231230557Sjimharris{
232230557Sjimharris   SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) domain;
233230557Sjimharris   SCI_STATUS          status    = SCI_SUCCESS;
234230557Sjimharris   SCI_STATUS          op_status = SCI_SUCCESS;
235230557Sjimharris
236230557Sjimharris   SCIF_LOG_TRACE((
237230557Sjimharris      sci_base_object_get_logger(domain),
238230557Sjimharris      SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
239230557Sjimharris      "scif_domain_discover(0x%x, 0x%x, 0x%x) enter\n",
240230557Sjimharris      domain, discover_timeout, device_timeout
241230557Sjimharris   ));
242230557Sjimharris
243230557Sjimharris   // Check to make sure the size of the domain doesn't cause potential issues
244230557Sjimharris   // with the remote device timer and the domain timer.
245230557Sjimharris   if ((device_timeout * sci_abstract_list_size(&fw_domain->remote_device_list))
246230557Sjimharris        > discover_timeout)
247230557Sjimharris      status = SCI_WARNING_TIMER_CONFLICT;
248230557Sjimharris
249230557Sjimharris   op_status = fw_domain->state_handlers->discover_handler(
250230557Sjimharris                  &fw_domain->parent, discover_timeout, device_timeout
251230557Sjimharris               );
252230557Sjimharris
253230557Sjimharris   // The status of the discover operation takes priority.
254230557Sjimharris   if (  (status == SCI_SUCCESS)
255230557Sjimharris      || (status != SCI_SUCCESS && op_status != SCI_SUCCESS) )
256230557Sjimharris   {
257230557Sjimharris      status = op_status;
258230557Sjimharris   }
259230557Sjimharris
260230557Sjimharris   return status;
261230557Sjimharris}
262230557Sjimharris
263230557Sjimharris// ---------------------------------------------------------------------------
264230557Sjimharris
265230557SjimharrisU32 scif_domain_get_suggested_discover_timeout(
266230557Sjimharris   SCI_DOMAIN_HANDLE_T   domain
267230557Sjimharris)
268230557Sjimharris{
269230557Sjimharris   U32 suggested_timeout = SCIF_DOMAIN_DISCOVER_TIMEOUT; //milli-seconds
270230557Sjimharris   return suggested_timeout;
271230557Sjimharris}
272230557Sjimharris
273230557Sjimharris// ---------------------------------------------------------------------------
274230557Sjimharris
275230557Sjimharrisvoid scic_cb_port_stop_complete(
276230557Sjimharris   SCI_CONTROLLER_HANDLE_T  controller,
277230557Sjimharris   SCI_PORT_HANDLE_T        port,
278230557Sjimharris   SCI_STATUS               completion_status
279230557Sjimharris)
280230557Sjimharris{
281230557Sjimharris   SCIF_LOG_TRACE((
282230557Sjimharris      sci_base_object_get_logger((SCIF_SAS_DOMAIN_T*)sci_object_get_association(port)),
283230557Sjimharris      SCIF_LOG_OBJECT_DOMAIN,
284230557Sjimharris      "scic_cb_port_stop_complete(0x%x, 0x%x, 0x%x) enter\n",
285230557Sjimharris      controller, port, completion_status
286230557Sjimharris   ));
287230557Sjimharris}
288230557Sjimharris
289230557Sjimharris// ---------------------------------------------------------------------------
290230557Sjimharris
291230557Sjimharrisvoid scic_cb_port_ready(
292230557Sjimharris   SCI_CONTROLLER_HANDLE_T  controller,
293230557Sjimharris   SCI_PORT_HANDLE_T        port
294230557Sjimharris)
295230557Sjimharris{
296230557Sjimharris   SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*)
297230557Sjimharris                                   sci_object_get_association(port);
298230557Sjimharris
299230557Sjimharris   SCIF_LOG_TRACE((
300230557Sjimharris      sci_base_object_get_logger(fw_domain),
301230557Sjimharris      SCIF_LOG_OBJECT_DOMAIN,
302230557Sjimharris      "scic_cb_port_ready(0x%x, 0x%x) enter\n",
303230557Sjimharris      controller, port
304230557Sjimharris   ));
305230557Sjimharris
306230557Sjimharris   // The controller supplied with the port should match the controller
307230557Sjimharris   // saved in the domain.
308230557Sjimharris   ASSERT(sci_object_get_association(controller) == fw_domain->controller);
309230557Sjimharris
310230557Sjimharris   fw_domain->is_port_ready = TRUE;
311230557Sjimharris
312230557Sjimharris   fw_domain->state_handlers->port_ready_handler(&fw_domain->parent);
313230557Sjimharris}
314230557Sjimharris
315230557Sjimharris// ---------------------------------------------------------------------------
316230557Sjimharris
317230557Sjimharrisvoid scic_cb_port_not_ready(
318230557Sjimharris   SCI_CONTROLLER_HANDLE_T  controller,
319230557Sjimharris   SCI_PORT_HANDLE_T        port,
320230557Sjimharris   U32                      reason_code
321230557Sjimharris)
322230557Sjimharris{
323230557Sjimharris   SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*)
324230557Sjimharris                                   sci_object_get_association(port);
325230557Sjimharris
326230557Sjimharris   SCIF_LOG_TRACE((
327230557Sjimharris      sci_base_object_get_logger(fw_domain),
328230557Sjimharris      SCIF_LOG_OBJECT_DOMAIN,
329230557Sjimharris      "scic_cb_port_not_ready(0x%x, 0x%x) enter\n",
330230557Sjimharris      controller, port
331230557Sjimharris   ));
332230557Sjimharris
333230557Sjimharris   // The controller supplied with the port should match the controller
334230557Sjimharris   // saved in the domain.
335230557Sjimharris   ASSERT(sci_object_get_association(controller) == fw_domain->controller);
336230557Sjimharris
337230557Sjimharris   // There is no need to take action on the port reconfiguring since it is
338230557Sjimharris   // just a change of the port width.
339230557Sjimharris   if (reason_code != SCIC_PORT_NOT_READY_RECONFIGURING)
340230557Sjimharris   {
341230557Sjimharris      fw_domain->is_port_ready = FALSE;
342230557Sjimharris
343230557Sjimharris      fw_domain->state_handlers->port_not_ready_handler(
344230557Sjimharris                                    &fw_domain->parent, reason_code);
345230557Sjimharris   }
346230557Sjimharris}
347230557Sjimharris
348230557Sjimharris// ---------------------------------------------------------------------------
349230557Sjimharris
350230557Sjimharrisvoid scic_cb_port_hard_reset_complete(
351230557Sjimharris   SCI_CONTROLLER_HANDLE_T  controller,
352230557Sjimharris   SCI_PORT_HANDLE_T        port,
353230557Sjimharris   SCI_STATUS               completion_status
354230557Sjimharris)
355230557Sjimharris{
356230557Sjimharris   SCIF_SAS_DOMAIN_T        * fw_domain = (SCIF_SAS_DOMAIN_T*)
357230557Sjimharris                                   sci_object_get_association(port);
358230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device;
359230557Sjimharris   SCI_FAST_LIST_ELEMENT_T  * element = fw_domain->request_list.list_head;
360230557Sjimharris   SCIF_SAS_TASK_REQUEST_T  * task_request = NULL;
361230557Sjimharris
362230557Sjimharris   SCIF_LOG_TRACE((
363230557Sjimharris      sci_base_object_get_logger(fw_domain),
364230557Sjimharris      SCIF_LOG_OBJECT_DOMAIN,
365230557Sjimharris      "scic_cb_port_hard_reset_complete(0x%x, 0x%x, 0x%x) enter\n",
366230557Sjimharris      controller, port, completion_status
367230557Sjimharris   ));
368230557Sjimharris
369230557Sjimharris   while (element != NULL)
370230557Sjimharris   {
371230557Sjimharris      task_request = (SCIF_SAS_TASK_REQUEST_T*) sci_fast_list_get_object(element);
372230557Sjimharris      element = sci_fast_list_get_next(element);
373230557Sjimharris
374230557Sjimharris      if (scif_sas_task_request_get_function(task_request)
375230557Sjimharris             == SCI_SAS_HARD_RESET)
376230557Sjimharris      {
377230557Sjimharris         fw_device = task_request->parent.device;
378230557Sjimharris
379230557Sjimharris         if (fw_device->domain == fw_domain)
380230557Sjimharris         {
381230557Sjimharris            scic_remote_device_reset_complete(fw_device->core_object);
382230557Sjimharris
383230557Sjimharris            scif_cb_task_request_complete(
384230557Sjimharris               sci_object_get_association(controller),
385230557Sjimharris               fw_device,
386230557Sjimharris               task_request,
387230557Sjimharris               (SCI_TASK_STATUS) completion_status
388230557Sjimharris            );
389230557Sjimharris
390230557Sjimharris            break;
391230557Sjimharris         }
392230557Sjimharris      }
393230557Sjimharris   }
394230557Sjimharris}
395230557Sjimharris
396230557Sjimharris// ---------------------------------------------------------------------------
397230557Sjimharris
398230557Sjimharrisvoid scic_cb_port_bc_change_primitive_recieved(
399230557Sjimharris   SCI_CONTROLLER_HANDLE_T  controller,
400230557Sjimharris   SCI_PORT_HANDLE_T        port,
401230557Sjimharris   SCI_PHY_HANDLE_T         phy
402230557Sjimharris)
403230557Sjimharris{
404230557Sjimharris   SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*)
405230557Sjimharris                                   sci_object_get_association(port);
406230557Sjimharris
407230557Sjimharris   SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T *)
408230557Sjimharris                                           sci_object_get_association(controller);
409230557Sjimharris
410230557Sjimharris   SCIF_LOG_TRACE((
411230557Sjimharris      sci_base_object_get_logger(fw_domain),
412230557Sjimharris      SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
413230557Sjimharris      "scic_cb_port_bc_change_primitive_recieved(0x%x, 0x%x, 0x%x) enter\n",
414230557Sjimharris      controller, port, phy
415230557Sjimharris   ));
416230557Sjimharris
417230557Sjimharris   if (fw_domain->broadcast_change_count == 0)
418230557Sjimharris   {  // Enable the BCN detection only if the bcn_count is zero. If bcn_count is
419230557Sjimharris      // not zero at this time, we won't enable BCN detection since all non-zero
420230557Sjimharris      // BCN_count means same to us. Furthermore, we avoid BCN storm by not
421230557Sjimharris      // always enabling the BCN_detection.
422230557Sjimharris      scic_port_enable_broadcast_change_notification(fw_domain->core_object);
423230557Sjimharris   }
424230557Sjimharris
425230557Sjimharris   fw_domain->broadcast_change_count++;
426230557Sjimharris
427230557Sjimharris   //if there is smp device on this domain that is in the middle of discover
428230557Sjimharris   //process or smp target reset, don't notify the driver layer.
429230557Sjimharris   if( ! scif_sas_domain_is_in_smp_activity(fw_domain) )
430230557Sjimharris      // Notify the user that there is, potentially, a change to the domain.
431230557Sjimharris      scif_cb_domain_change_notification(fw_controller, fw_domain);
432230557Sjimharris}
433230557Sjimharris
434230557Sjimharris// ---------------------------------------------------------------------------
435230557Sjimharris
436230557Sjimharrisvoid scic_cb_port_bc_ses_primitive_recieved(
437230557Sjimharris   SCI_CONTROLLER_HANDLE_T  controller,
438230557Sjimharris   SCI_PORT_HANDLE_T        port,
439230557Sjimharris   SCI_PHY_HANDLE_T         phy
440230557Sjimharris)
441230557Sjimharris{
442230557Sjimharris   SCIF_LOG_TRACE((
443230557Sjimharris      sci_base_object_get_logger(sci_object_get_association(port)),
444230557Sjimharris      SCIF_LOG_OBJECT_DOMAIN,
445230557Sjimharris      "scic_cb_port_bc_ses_primitive_received(0x%x, 0x%x, 0x%x) enter\n",
446230557Sjimharris      controller, port, phy
447230557Sjimharris   ));
448230557Sjimharris}
449230557Sjimharris
450230557Sjimharris// ---------------------------------------------------------------------------
451230557Sjimharris
452230557Sjimharrisvoid scic_cb_port_bc_expander_primitive_recieved(
453230557Sjimharris   SCI_CONTROLLER_HANDLE_T  controller,
454230557Sjimharris   SCI_PORT_HANDLE_T        port,
455230557Sjimharris   SCI_PHY_HANDLE_T         phy
456230557Sjimharris)
457230557Sjimharris{
458230557Sjimharris   SCIF_LOG_TRACE((
459230557Sjimharris      sci_base_object_get_logger(sci_object_get_association(port)),
460230557Sjimharris      SCIF_LOG_OBJECT_DOMAIN,
461230557Sjimharris      "scic_cb_port_bc_expander_primitive_received(0x%x, 0x%x, 0x%x) enter\n",
462230557Sjimharris      controller, port, phy
463230557Sjimharris   ));
464230557Sjimharris}
465230557Sjimharris
466230557Sjimharris// ---------------------------------------------------------------------------
467230557Sjimharris
468230557Sjimharrisvoid scic_cb_port_bc_aen_primitive_recieved(
469230557Sjimharris   SCI_CONTROLLER_HANDLE_T  controller,
470230557Sjimharris   SCI_PORT_HANDLE_T        port,
471230557Sjimharris   SCI_PHY_HANDLE_T         phy
472230557Sjimharris)
473230557Sjimharris{
474230557Sjimharris   SCIF_LOG_TRACE((
475230557Sjimharris      sci_base_object_get_logger(sci_object_get_association(port)),
476230557Sjimharris      SCIF_LOG_OBJECT_DOMAIN,
477230557Sjimharris      "scic_cb_port_bc_aen_primitive_received(0x%x, 0x%x, 0x%x) enter\n",
478230557Sjimharris      controller, port, phy
479230557Sjimharris   ));
480230557Sjimharris}
481230557Sjimharris
482230557Sjimharris// ---------------------------------------------------------------------------
483230557Sjimharris
484230557Sjimharrisvoid scic_cb_port_link_up(
485230557Sjimharris   SCI_CONTROLLER_HANDLE_T  controller,
486230557Sjimharris   SCI_PORT_HANDLE_T        port,
487230557Sjimharris   SCI_PHY_HANDLE_T         phy
488230557Sjimharris)
489230557Sjimharris{
490230557Sjimharris   SCIF_SAS_DOMAIN_T        * fw_domain = (SCIF_SAS_DOMAIN_T*)
491230557Sjimharris                                 sci_object_get_association(port);
492230557Sjimharris
493230557Sjimharris   SCIF_LOG_TRACE((
494230557Sjimharris      sci_base_object_get_logger(sci_object_get_association(port)),
495230557Sjimharris      SCIF_LOG_OBJECT_DOMAIN,
496230557Sjimharris      "scic_cb_port_link_up(0x%x, 0x%x, 0x%x) enter\n",
497230557Sjimharris      controller, port, phy
498230557Sjimharris   ));
499230557Sjimharris
500230557Sjimharris   scif_sas_domain_update_device_port_width(fw_domain, port);
501230557Sjimharris}
502230557Sjimharris
503230557Sjimharris// ---------------------------------------------------------------------------
504230557Sjimharris
505230557Sjimharrisvoid scic_cb_port_link_down(
506230557Sjimharris   SCI_CONTROLLER_HANDLE_T  controller,
507230557Sjimharris   SCI_PORT_HANDLE_T        port,
508230557Sjimharris   SCI_PHY_HANDLE_T         phy
509230557Sjimharris)
510230557Sjimharris{
511230557Sjimharris   SCIF_SAS_DOMAIN_T        * fw_domain = (SCIF_SAS_DOMAIN_T*)
512230557Sjimharris                                 sci_object_get_association(port);
513230557Sjimharris
514230557Sjimharris   SCIF_LOG_TRACE((
515230557Sjimharris      sci_base_object_get_logger(sci_object_get_association(port)),
516230557Sjimharris      SCIF_LOG_OBJECT_DOMAIN,
517230557Sjimharris      "scic_cb_port_link_down(0x%x, 0x%x, 0x%x) enter\n",
518230557Sjimharris      controller, port, phy
519230557Sjimharris   ));
520230557Sjimharris
521230557Sjimharris   scif_sas_domain_update_device_port_width(fw_domain, port);
522230557Sjimharris}
523230557Sjimharris
524230557Sjimharris//******************************************************************************
525230557Sjimharris//* P R O T E C T E D   M E T H O D S
526230557Sjimharris//******************************************************************************
527230557Sjimharris
528230557Sjimharris/**
529230557Sjimharris * @brief This method constructs the framework's SAS domain object.  During
530230557Sjimharris *        the construction process a linkage to the corresponding core port
531230557Sjimharris *        object.
532230557Sjimharris *
533230557Sjimharris * @param[in]  domain This parameter specifies the domain object to be
534230557Sjimharris *             constructed.
535230557Sjimharris * @param[in]  domain_id This parameter specifies the ID for the domain
536230557Sjimharris *             object.
537230557Sjimharris * @param[in]  fw_controller This parameter specifies the controller managing
538230557Sjimharris *             the domain being constructed.
539230557Sjimharris *
540230557Sjimharris * @return none
541230557Sjimharris */
542230557Sjimharrisvoid scif_sas_domain_construct(
543230557Sjimharris   SCIF_SAS_DOMAIN_T     * fw_domain,
544230557Sjimharris   U8                      domain_id,
545230557Sjimharris   SCIF_SAS_CONTROLLER_T * fw_controller
546230557Sjimharris)
547230557Sjimharris{
548230557Sjimharris   SCIF_LOG_TRACE((
549230557Sjimharris      sci_base_object_get_logger(fw_controller),
550230557Sjimharris      SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_INITIALIZATION,
551230557Sjimharris      "scif_sas_domain_construct(0x%x, 0x%x, 0x%x) enter\n",
552230557Sjimharris      fw_domain, domain_id, fw_controller
553230557Sjimharris   ));
554230557Sjimharris
555230557Sjimharris   sci_base_domain_construct(
556230557Sjimharris      &fw_domain->parent,
557230557Sjimharris      sci_base_object_get_logger(fw_controller),
558230557Sjimharris      scif_sas_domain_state_table
559230557Sjimharris   );
560230557Sjimharris
561230557Sjimharris   scif_sas_domain_initialize_state_logging(fw_domain);
562230557Sjimharris
563230557Sjimharris   sci_abstract_list_construct(
564230557Sjimharris      &fw_domain->remote_device_list, &fw_controller->free_remote_device_pool
565230557Sjimharris   );
566230557Sjimharris
567230557Sjimharris   // Retrieve the core's port object that directly corresponds to this
568230557Sjimharris   // domain.
569230557Sjimharris   scic_controller_get_port_handle(
570230557Sjimharris      fw_controller->core_object, domain_id, &fw_domain->core_object
571230557Sjimharris   );
572230557Sjimharris
573230557Sjimharris   // Set the association in the core port to this framework domain object.
574230557Sjimharris   sci_object_set_association(
575230557Sjimharris      (SCI_OBJECT_HANDLE_T) fw_domain->core_object, fw_domain
576230557Sjimharris   );
577230557Sjimharris
578230557Sjimharris   sci_fast_list_init(&fw_domain->request_list);
579230557Sjimharris
580230557Sjimharris   fw_domain->operation.timer = NULL;
581230557Sjimharris
582230557Sjimharris   fw_domain->is_port_ready      = FALSE;
583230557Sjimharris   fw_domain->device_start_count = 0;
584230557Sjimharris   fw_domain->controller         = fw_controller;
585230557Sjimharris   fw_domain->operation.status   = SCI_SUCCESS;
586230557Sjimharris   fw_domain->is_config_route_table_needed = FALSE;
587230557Sjimharris}
588230557Sjimharris
589230557Sjimharris/**
590230557Sjimharris * @brief This method will terminate the requests outstanding in the core
591230557Sjimharris *        based on the supplied criteria.
592230557Sjimharris *        - if the all three parameters are specified then only the single
593230557Sjimharris *          SCIF_SAS_REQUEST object is terminated.
594230557Sjimharris *        - if only the SCIF_SAS_DOMAIN and SCIF_SAS_REMOTE_DEVICE are
595230557Sjimharris *          specified, then all SCIF_SAS_REQUEST objects outstanding at
596230557Sjimharris *          the device are terminated.  The one exclusion to this rule is
597230557Sjimharris *          that the fw_requestor is not terminated.
598230557Sjimharris *        - if only the SCIF_SAS_DOMAIN object is specified, then all
599230557Sjimharris *          SCIF_SAS_REQUEST objects outstanding in the domain are
600230557Sjimharris *          terminated.
601230557Sjimharris *
602230557Sjimharris * @param[in]  fw_domain This parameter specifies the domain in which to
603230557Sjimharris *             terminate requests.
604230557Sjimharris * @param[in]  fw_device This parameter specifies the remote device in
605230557Sjimharris *             which to terminate requests.  This parameter can be NULL
606230557Sjimharris *             as long as the fw_request parameter is NULL.  It is a
607230557Sjimharris *             required parameter if the fw_request parameter is not NULL.
608230557Sjimharris * @param[in]  fw_request This parameter specifies the request object to
609230557Sjimharris *             be terminated.  This parameter can be NULL.
610230557Sjimharris * @param[in]  fw_requestor This parameter specifies the task management
611230557Sjimharris *             request that is responsible for the termination of requests.
612230557Sjimharris *
613230557Sjimharris * @return none
614230557Sjimharris */
615230557Sjimharrisvoid scif_sas_domain_terminate_requests(
616230557Sjimharris   SCIF_SAS_DOMAIN_T        * fw_domain,
617230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device,
618230557Sjimharris   SCIF_SAS_REQUEST_T       * fw_request,
619230557Sjimharris   SCIF_SAS_TASK_REQUEST_T  * fw_requestor
620230557Sjimharris)
621230557Sjimharris{
622230557Sjimharris   SCIF_LOG_TRACE((
623230557Sjimharris      sci_base_object_get_logger(fw_domain),
624230557Sjimharris      SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_TASK_MANAGEMENT,
625230557Sjimharris      "scif_sas_domain_terminate_requests(0x%x, 0x%x, 0x%x, 0x%x) enter\n",
626230557Sjimharris      fw_domain, fw_device, fw_request, fw_requestor
627230557Sjimharris   ));
628230557Sjimharris
629230557Sjimharris   if (fw_request != NULL)
630230557Sjimharris   {
631230557Sjimharris      fw_request->terminate_requestor = fw_requestor;
632230557Sjimharris      fw_request->state_handlers->abort_handler(&fw_request->parent);
633230557Sjimharris   }
634230557Sjimharris   else
635230557Sjimharris   {
636230557Sjimharris      SCI_FAST_LIST_ELEMENT_T * element = fw_domain->request_list.list_head;
637230557Sjimharris      SCIF_SAS_REQUEST_T      * request = NULL;
638230557Sjimharris
639230557Sjimharris      // Cycle through the fast list of IO requests.  Terminate each
640250460Seadler      // outstanding requests that matches the criteria supplied by the
641230557Sjimharris      // caller.
642230557Sjimharris      while (element != NULL)
643230557Sjimharris      {
644230557Sjimharris         request = (SCIF_SAS_REQUEST_T*) sci_fast_list_get_object(element);
645230557Sjimharris         // The current element may be deleted from the list becasue of
646230557Sjimharris         // IO completion so advance to the next element early
647230557Sjimharris         element = sci_fast_list_get_next(element);
648230557Sjimharris
649230557Sjimharris         // Ensure we pass the supplied criteria before terminating the
650230557Sjimharris         // request.
651230557Sjimharris         if (
652230557Sjimharris               (fw_device == NULL)
653230557Sjimharris            || (
654230557Sjimharris                  (request->device == fw_device)
655230557Sjimharris               && (fw_requestor != (SCIF_SAS_TASK_REQUEST_T*) request)
656230557Sjimharris               )
657230557Sjimharris            )
658230557Sjimharris         {
659230557Sjimharris            if (
660230557Sjimharris                  (request->is_waiting_for_abort_task_set == FALSE) ||
661230557Sjimharris                  (request->terminate_requestor == NULL)
662230557Sjimharris               )
663230557Sjimharris            {
664230557Sjimharris               request->terminate_requestor = fw_requestor;
665230557Sjimharris               request->state_handlers->abort_handler(&request->parent);
666230557Sjimharris            }
667230557Sjimharris         }
668230557Sjimharris      }
669230557Sjimharris   }
670230557Sjimharris}
671230557Sjimharris
672230557Sjimharris/**
673230557Sjimharris * @brief This method searches the domain object to find a
674230557Sjimharris *        SCIF_SAS_REQUEST object associated with the supplied IO tag.
675230557Sjimharris *
676230557Sjimharris * @param[in]  fw_domain This parameter specifies the domain in which to
677230557Sjimharris *             to find the request object.
678230557Sjimharris * @param[in]  io_tag This parameter specifies the IO tag value for which
679230557Sjimharris *             to locate the corresponding request.
680230557Sjimharris *
681230557Sjimharris * @return This method returns a pointer to the SCIF_SAS_REQUEST object
682230557Sjimharris *         associated with the supplied IO tag.
683230557Sjimharris * @retval NULL This value is returned if the IO tag does not resolve to
684230557Sjimharris *         a request.
685230557Sjimharris */
686230557SjimharrisSCIF_SAS_REQUEST_T * scif_sas_domain_get_request_by_io_tag(
687230557Sjimharris   SCIF_SAS_DOMAIN_T * fw_domain,
688230557Sjimharris   U16                 io_tag
689230557Sjimharris)
690230557Sjimharris{
691230557Sjimharris   SCI_FAST_LIST_ELEMENT_T * element    = fw_domain->request_list.list_head;
692230557Sjimharris   SCIF_SAS_IO_REQUEST_T   * io_request = NULL;
693230557Sjimharris
694230557Sjimharris   SCIF_LOG_TRACE((
695230557Sjimharris      sci_base_object_get_logger(fw_domain),
696230557Sjimharris      SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_TASK_MANAGEMENT,
697230557Sjimharris      "scif_sas_domain_get_request_by_io_tag(0x%x, 0x%x) enter\n",
698230557Sjimharris      fw_domain, io_tag
699230557Sjimharris   ));
700230557Sjimharris
701230557Sjimharris   while (element != NULL)
702230557Sjimharris   {
703230557Sjimharris      io_request = (SCIF_SAS_IO_REQUEST_T*) sci_fast_list_get_object(element);
704230557Sjimharris
705230557Sjimharris      // Check to see if we located the request with an identical IO tag.
706230557Sjimharris      if (scic_io_request_get_io_tag(io_request->parent.core_object) == io_tag)
707230557Sjimharris         return &io_request->parent;
708230557Sjimharris
709230557Sjimharris      element = sci_fast_list_get_next(element);
710230557Sjimharris   }
711230557Sjimharris
712230557Sjimharris   return NULL;
713230557Sjimharris}
714230557Sjimharris
715230557Sjimharris/**
716230557Sjimharris * @brief This method performs domain object initialization to be done
717230557Sjimharris *        when the scif_controller_initialize() method is invoked.
718230557Sjimharris *        This includes operation timeout creation.
719230557Sjimharris *
720230557Sjimharris * @param[in]  fw_domain This parameter specifies the domain object for
721230557Sjimharris *             which to perform initialization.
722230557Sjimharris *
723230557Sjimharris * @return none
724230557Sjimharris */
725230557Sjimharrisvoid scif_sas_domain_initialize(
726230557Sjimharris   SCIF_SAS_DOMAIN_T * fw_domain
727230557Sjimharris)
728230557Sjimharris{
729230557Sjimharris   SCIF_LOG_TRACE((
730230557Sjimharris      sci_base_object_get_logger(fw_domain),
731230557Sjimharris      SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_INITIALIZATION,
732230557Sjimharris      "scif_sas_domain_initialize(0x%x) enter\n",
733230557Sjimharris      fw_domain
734230557Sjimharris   ));
735230557Sjimharris
736230557Sjimharris   // Create the timer for each domain.  It is too early in the process
737230557Sjimharris   // to allocate this during construction since the user didn't have
738230557Sjimharris   // a chance to set it's association.
739230557Sjimharris   if (fw_domain->operation.timer == 0)
740230557Sjimharris   {
741230557Sjimharris      fw_domain->operation.timer = scif_cb_timer_create(
742230557Sjimharris                                      fw_domain->controller,
743230557Sjimharris                                      scif_sas_domain_operation_timeout_handler,
744230557Sjimharris                                      fw_domain
745230557Sjimharris                                   );
746230557Sjimharris   }
747230557Sjimharris}
748230557Sjimharris
749230557Sjimharris/**
750230557Sjimharris * @brief This method performs domain object handling for core remote
751230557Sjimharris *        device start complete notifications.  Core remote device starts
752230557Sjimharris *        and start completes are only done during discovery.  This could
753230557Sjimharris *        ultimately be wrapped into a handler method on the domain (they
754230557Sjimharris *        actually already exist).  This method will decrement the number
755230557Sjimharris *        of device start operations ongoing and attempt to determine if
756230557Sjimharris *        discovery is complete.
757230557Sjimharris *
758230557Sjimharris * @param[in]  fw_domain This parameter specifies the domain object for
759230557Sjimharris *             which to perform initialization.
760230557Sjimharris *
761230557Sjimharris * @return none
762230557Sjimharris */
763230557Sjimharrisvoid scif_sas_domain_remote_device_start_complete(
764230557Sjimharris   SCIF_SAS_DOMAIN_T        * fw_domain,
765230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device
766230557Sjimharris)
767230557Sjimharris{
768230557Sjimharris   SMP_DISCOVER_RESPONSE_PROTOCOLS_T  dev_protocols;
769230557Sjimharris
770230557Sjimharris   SCIF_LOG_TRACE((
771230557Sjimharris      sci_base_object_get_logger(fw_domain),
772230557Sjimharris      SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
773230557Sjimharris      "scif_sas_domain_remote_device_start_complete(0x%x, 0x%x) enter\n",
774230557Sjimharris      fw_domain, fw_device
775230557Sjimharris   ));
776230557Sjimharris
777230557Sjimharris   // If a device is being started/start completed, then we must be
778230557Sjimharris   // during discovery.
779230557Sjimharris   ASSERT(fw_domain->parent.state_machine.current_state_id
780230557Sjimharris          == SCI_BASE_DOMAIN_STATE_DISCOVERING);
781230557Sjimharris
782230557Sjimharris   scic_remote_device_get_protocols(fw_device->core_object, &dev_protocols);
783230557Sjimharris
784230557Sjimharris   // Decrement the number of devices being started and check to see
785230557Sjimharris   // if all have finished being started or failed as the case may be.
786230557Sjimharris   fw_domain->device_start_in_progress_count--;
787230557Sjimharris
788230557Sjimharris   if ( dev_protocols.u.bits.attached_smp_target )
789230557Sjimharris   {
790230557Sjimharris      if ( fw_device->containing_device == NULL )
791230557Sjimharris         //kick off the smp discover process if this expander is direct attached.
792230557Sjimharris         scif_sas_smp_remote_device_start_discover(fw_device);
793230557Sjimharris      else
794230557Sjimharris         //mark this device, the discover process of this device will start after
795230557Sjimharris         //its containing smp device finish discover.
796230557Sjimharris         fw_device->protocol_device.smp_device.scheduled_activity =
797230557Sjimharris            SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER;
798230557Sjimharris   }
799230557Sjimharris   else
800230557Sjimharris   {
801230557Sjimharris      fw_domain->state_handlers->device_start_complete_handler(
802230557Sjimharris         &fw_domain->parent, &fw_device->parent
803230557Sjimharris      );
804230557Sjimharris   }
805230557Sjimharris}
806230557Sjimharris
807230557Sjimharris
808230557Sjimharris/**
809230557Sjimharris * @brief This methods check each smp device in this domain. If there is at
810230557Sjimharris *        least one smp device in discover or target reset activity, this
811230557Sjimharris *        domain is considered in smp activity. Note this routine is not
812230557Sjimharris *        called on fast IO path.
813230557Sjimharris *
814230557Sjimharris * @param[in] fw_domain The framework domain object
815230557Sjimharris *
816230557Sjimharris * @return BOOL value to indicate whether a domain is in SMP activity.
817230557Sjimharris */
818230557SjimharrisBOOL scif_sas_domain_is_in_smp_activity(
819230557Sjimharris   SCIF_SAS_DOMAIN_T        * fw_domain
820230557Sjimharris)
821230557Sjimharris{
822230557Sjimharris   SCI_ABSTRACT_ELEMENT_T * current_element =
823230557Sjimharris      sci_abstract_list_get_front(&fw_domain->remote_device_list);
824230557Sjimharris
825230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * current_device;
826230557Sjimharris
827230557Sjimharris   while ( current_element != NULL )
828230557Sjimharris   {
829230557Sjimharris      SMP_DISCOVER_RESPONSE_PROTOCOLS_T  dev_protocols;
830230557Sjimharris
831230557Sjimharris      current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
832230557Sjimharris                       sci_abstract_list_get_object(current_element);
833230557Sjimharris
834230557Sjimharris      scic_remote_device_get_protocols(current_device->core_object,
835230557Sjimharris                                       &dev_protocols
836230557Sjimharris      );
837230557Sjimharris
838230557Sjimharris      if (dev_protocols.u.bits.attached_smp_target &&
839230557Sjimharris          scif_sas_smp_remote_device_is_in_activity(current_device))
840230557Sjimharris         return TRUE;
841230557Sjimharris
842230557Sjimharris      current_element =
843230557Sjimharris         sci_abstract_list_get_next(current_element);
844230557Sjimharris   }
845230557Sjimharris
846230557Sjimharris   return FALSE;
847230557Sjimharris}
848230557Sjimharris
849230557Sjimharris
850230557Sjimharris/**
851230557Sjimharris * @brief This methods finds a expander attached device by searching the domain's
852230557Sjimharris *        device list using connected expander device and expander phy id.
853230557Sjimharris *
854230557Sjimharris * @param[in] fw_domain The framework domain object
855230557Sjimharris * @param[in] parent_device The expander device the target device attaches to.
856230557Sjimharris * @param[in] expander_phy_id The expander phy id that the target device owns.
857230557Sjimharris *
858230557Sjimharris * @return found remote device or a NULL value if no device found.
859230557Sjimharris */
860230557SjimharrisSCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_get_device_by_containing_device(
861230557Sjimharris   SCIF_SAS_DOMAIN_T        * fw_domain,
862230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * containing_device,
863230557Sjimharris   U8                         expander_phy_id
864230557Sjimharris)
865230557Sjimharris{
866230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device;
867230557Sjimharris   SCI_ABSTRACT_ELEMENT_T * element = sci_abstract_list_get_front(
868230557Sjimharris                                         &fw_domain->remote_device_list
869230557Sjimharris                                      );
870230557Sjimharris
871230557Sjimharris   //parent device must not be NULL.
872230557Sjimharris   ASSERT(containing_device != NULL);
873230557Sjimharris
874230557Sjimharris   // Search the abstract list to see if there is a remote device meets the
875230557Sjimharris   // search condition.
876230557Sjimharris   while (element != NULL)
877230557Sjimharris   {
878230557Sjimharris      fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
879230557Sjimharris                  sci_abstract_list_get_object(element);
880230557Sjimharris
881230557Sjimharris      // Check to see if this is the device for which we are searching.
882230557Sjimharris      if (
883230557Sjimharris            (fw_device->containing_device == containing_device)
884230557Sjimharris         && (fw_device->expander_phy_identifier == expander_phy_id)
885230557Sjimharris         )
886230557Sjimharris      {
887230557Sjimharris         return fw_device;
888230557Sjimharris      }
889230557Sjimharris
890230557Sjimharris      element = sci_abstract_list_get_next(element);
891230557Sjimharris   }
892230557Sjimharris
893230557Sjimharris   return SCI_INVALID_HANDLE;
894230557Sjimharris}
895230557Sjimharris
896230557Sjimharris
897230557Sjimharris/**
898230557Sjimharris * @brief This methods finds the first device that is in STOPPED state and its
899230557Sjimharris *        connection_rate is still in SPINUP_HOLD(value 3).
900230557Sjimharris *
901230557Sjimharris * @param[in] fw_domain The framework domain object
902230557Sjimharris *
903230557Sjimharris * @return SCIF_SAS_REMOTE_DEVICE_T The device that is in SPINUP_HOLD or NULL.
904230557Sjimharris */
905230557SjimharrisSCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_find_device_in_spinup_hold(
906230557Sjimharris   SCIF_SAS_DOMAIN_T        * fw_domain
907230557Sjimharris)
908230557Sjimharris{
909230557Sjimharris   SCI_ABSTRACT_ELEMENT_T   * current_element;
910230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * current_device;
911230557Sjimharris
912230557Sjimharris   SCIF_LOG_TRACE((
913230557Sjimharris      sci_base_object_get_logger(fw_domain),
914230557Sjimharris      SCIF_LOG_OBJECT_DOMAIN,
915230557Sjimharris      "scif_sas_domain_find_device_in_spinup_hold(0x%x) enter\n",
916230557Sjimharris      fw_domain
917230557Sjimharris   ));
918230557Sjimharris
919230557Sjimharris   //search throught domain's device list to find the first sata device on spinup_hold
920230557Sjimharris   current_element = sci_abstract_list_get_front(&fw_domain->remote_device_list);
921230557Sjimharris   while (current_element != NULL )
922230557Sjimharris   {
923230557Sjimharris      current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
924230557Sjimharris                       sci_abstract_list_get_object(current_element);
925230557Sjimharris
926230557Sjimharris      //We must get the next element before we remove the current
927230557Sjimharris      //device. Or else, we will get wrong next_element, since the erased
928230557Sjimharris      //element has been put into free pool.
929230557Sjimharris      current_element = sci_abstract_list_get_next(current_element);
930230557Sjimharris
931230557Sjimharris      if ( sci_base_state_machine_get_state(&current_device->parent.state_machine) ==
932230557Sjimharris              SCI_BASE_REMOTE_DEVICE_STATE_STOPPED
933230557Sjimharris          && scic_remote_device_get_connection_rate(current_device->core_object) ==
934230557Sjimharris                SCI_SATA_SPINUP_HOLD )
935230557Sjimharris      {
936230557Sjimharris         return current_device;
937230557Sjimharris      }
938230557Sjimharris   }
939230557Sjimharris
940230557Sjimharris   return NULL;
941230557Sjimharris}
942230557Sjimharris
943230557Sjimharris
944230557Sjimharris/**
945230557Sjimharris * @brief This methods finds the first device that has specific activity scheduled.
946230557Sjimharris *
947230557Sjimharris * @param[in] fw_domain The framework domain object
948230557Sjimharris * @param[in] smp_activity A specified smp activity. The valid range is [1,5].
949230557Sjimharris *
950230557Sjimharris * @return SCIF_SAS_REMOTE_DEVICE_T The device that has specified smp activity scheduled.
951230557Sjimharris */
952230557SjimharrisSCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_find_device_has_scheduled_activity(
953230557Sjimharris   SCIF_SAS_DOMAIN_T        * fw_domain,
954230557Sjimharris   U8                         smp_activity
955230557Sjimharris)
956230557Sjimharris{
957230557Sjimharris   SCI_ABSTRACT_ELEMENT_T * current_element =
958230557Sjimharris      sci_abstract_list_get_front(&fw_domain->remote_device_list);
959230557Sjimharris
960230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * current_device;
961230557Sjimharris   SMP_DISCOVER_RESPONSE_PROTOCOLS_T  dev_protocols;
962230557Sjimharris
963230557Sjimharris   //config route table activity has higher priority than discover activity.
964230557Sjimharris   while ( current_element != NULL )
965230557Sjimharris   {
966230557Sjimharris      current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
967230557Sjimharris                       sci_abstract_list_get_object(current_element);
968230557Sjimharris
969230557Sjimharris      scic_remote_device_get_protocols(current_device->core_object,
970230557Sjimharris                                       &dev_protocols);
971230557Sjimharris
972230557Sjimharris      current_element =
973230557Sjimharris         sci_abstract_list_get_next(current_element);
974230557Sjimharris
975230557Sjimharris      if ( dev_protocols.u.bits.attached_smp_target
976230557Sjimharris          && current_device->protocol_device.smp_device.scheduled_activity ==
977230557Sjimharris                smp_activity)
978230557Sjimharris      {
979230557Sjimharris         return current_device;
980230557Sjimharris      }
981230557Sjimharris   }
982230557Sjimharris
983230557Sjimharris   return NULL;
984230557Sjimharris}
985230557Sjimharris
986230557Sjimharris
987230557Sjimharris/**
988230557Sjimharris * @brief This methods finds the smp device that has is_config_route_table_scheduled
989230557Sjimharris *        flag set to TRUE, and start config route table on it. If there is no
990230557Sjimharris *        smp device scheduled to config route table, find the smp device has
991230557Sjimharris *        is_discover_scheduled and start the smp discover process on them.
992230557Sjimharris *
993230557Sjimharris * @param[in] fw_domain The framework domain that to start smp discover process.
994230557Sjimharris *
995230557Sjimharris * @return NONE
996230557Sjimharris */
997230557Sjimharrisvoid scif_sas_domain_start_smp_activity(
998230557Sjimharris  SCIF_SAS_DOMAIN_T        * fw_domain
999230557Sjimharris)
1000230557Sjimharris{
1001230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * device_has_scheduled_activity = NULL;
1002230557Sjimharris
1003230557Sjimharris   //first, find device that has config route table activity scheduled.
1004230557Sjimharris   //config route table activity has higher priority than Discover.
1005230557Sjimharris   device_has_scheduled_activity =
1006230557Sjimharris      scif_sas_domain_find_device_has_scheduled_activity(
1007230557Sjimharris         fw_domain,
1008230557Sjimharris         SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE
1009230557Sjimharris      );
1010230557Sjimharris
1011230557Sjimharris   if (device_has_scheduled_activity != NULL)
1012230557Sjimharris   {
1013230557Sjimharris      scif_sas_smp_remote_device_configure_route_table(device_has_scheduled_activity);
1014230557Sjimharris      device_has_scheduled_activity->protocol_device.smp_device.scheduled_activity =
1015230557Sjimharris         SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE;
1016230557Sjimharris      return;
1017230557Sjimharris   }
1018230557Sjimharris
1019230557Sjimharris   //if no device has config route table activity scheduled, search again, find
1020230557Sjimharris   //device has discover activity scheduled.
1021230557Sjimharris   device_has_scheduled_activity =
1022230557Sjimharris      scif_sas_domain_find_device_has_scheduled_activity(
1023230557Sjimharris         fw_domain,
1024230557Sjimharris         SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER
1025230557Sjimharris      );
1026230557Sjimharris
1027230557Sjimharris   if (device_has_scheduled_activity != NULL)
1028230557Sjimharris      scif_sas_smp_remote_device_start_discover(device_has_scheduled_activity);
1029230557Sjimharris}
1030230557Sjimharris
1031230557Sjimharris
1032230557Sjimharris/**
1033230557Sjimharris * @brief This method starts domain's smp discover process from the top level expander.
1034230557Sjimharris *
1035230557Sjimharris * @param[in] fw_domain The framework domain that to start smp discover process.
1036230557Sjimharris @ @param[in] top_expander The top level expander device to start smp discover process.
1037230557Sjimharris *
1038230557Sjimharris * @return None
1039230557Sjimharris */
1040230557Sjimharrisvoid scif_sas_domain_start_smp_discover(
1041230557Sjimharris   SCIF_SAS_DOMAIN_T        * fw_domain,
1042230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * top_expander
1043230557Sjimharris)
1044230557Sjimharris{
1045230557Sjimharris   SCI_ABSTRACT_ELEMENT_T * current_element =
1046230557Sjimharris       sci_abstract_list_get_front(&fw_domain->remote_device_list);
1047230557Sjimharris
1048230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * current_device;
1049230557Sjimharris
1050230557Sjimharris   // something changed behind expander
1051230557Sjimharris   // mark all the device behind expander to be NOT
1052230557Sjimharris   // is_currently_discovered.
1053230557Sjimharris   while ( current_element != NULL )
1054230557Sjimharris   {
1055230557Sjimharris      current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
1056230557Sjimharris                           sci_abstract_list_get_object(current_element);
1057230557Sjimharris
1058230557Sjimharris      current_device->is_currently_discovered = FALSE;
1059230557Sjimharris
1060230557Sjimharris      //reset all the devices' port witdh except the top expander.
1061230557Sjimharris      if (current_device->containing_device != NULL)
1062230557Sjimharris         current_device->device_port_width = 1;
1063230557Sjimharris
1064230557Sjimharris      current_element = sci_abstract_list_get_next(current_element);
1065230557Sjimharris   }
1066230557Sjimharris
1067230557Sjimharris   //expander device itself should be set to is_currently_discovered.
1068230557Sjimharris   top_expander->is_currently_discovered = TRUE;
1069230557Sjimharris
1070230557Sjimharris   //kick off the smp discover process.
1071230557Sjimharris   scif_sas_smp_remote_device_start_discover(top_expander);
1072230557Sjimharris}
1073230557Sjimharris
1074230557Sjimharris
1075230557Sjimharris/**
1076230557Sjimharris * @brief This method continues domain's smp discover process and
1077230557Sjimharris *        may transit to READY state if all smp activities are done.
1078230557Sjimharris *
1079230557Sjimharris * @param[in] fw_domain The framework domain that to start smp discover process.
1080230557Sjimharris *
1081230557Sjimharris * @return None
1082230557Sjimharris */
1083230557Sjimharrisvoid scif_sas_domain_continue_discover(
1084230557Sjimharris   SCIF_SAS_DOMAIN_T * fw_domain
1085230557Sjimharris)
1086230557Sjimharris{
1087230557Sjimharris   SCIF_LOG_TRACE((
1088230557Sjimharris      sci_base_object_get_logger(fw_domain),
1089230557Sjimharris      SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1090230557Sjimharris      "scif_sas_domain_continue_discover(0x%x) enter\n",
1091230557Sjimharris      fw_domain
1092230557Sjimharris   ));
1093230557Sjimharris
1094230557Sjimharris   if ( fw_domain->device_start_in_progress_count == 0
1095230557Sjimharris       && !scif_sas_domain_is_in_smp_activity(fw_domain) )
1096230557Sjimharris   {
1097230557Sjimharris      //domain scrub the remote device list to see if there is a need
1098230557Sjimharris      //to start smp discover on expander device. There may be no
1099230557Sjimharris      //need to start any smp discover.
1100230557Sjimharris      scif_sas_domain_start_smp_activity(fw_domain);
1101230557Sjimharris
1102230557Sjimharris      //In domain discovery timeout case, we cancel all
1103230557Sjimharris      //the smp activities, and terminate all the smp requests, then
1104230557Sjimharris      //this routine is called. But the smp request may not done
1105230557Sjimharris      //terminated. We want to guard the domain trasitting to READY
1106230557Sjimharris      //by checking outstanding smp request count. If there is outstanding
1107230557Sjimharris      //smp request, the domain will not transit to READY. Later when
1108230557Sjimharris      //the smp request is terminated at smp remote device, this routine
1109230557Sjimharris      //will be called then the domain will transit to READY state.
1110230557Sjimharris      if ( ! scif_sas_domain_is_in_smp_activity(fw_domain)
1111230557Sjimharris          && scif_sas_domain_get_smp_request_count(fw_domain) == 0)
1112230557Sjimharris      {
1113230557Sjimharris         //before domain transit to READY state, domain has some clean up
1114230557Sjimharris         //work to do, such like update domain's remote devcie list.
1115230557Sjimharris         scif_sas_domain_finish_discover(fw_domain);
1116230557Sjimharris      }
1117230557Sjimharris   }
1118230557Sjimharris}
1119230557Sjimharris
1120230557Sjimharris
1121230557Sjimharris/**
1122230557Sjimharris * @brief This method finishes domain's smp discover process and
1123230557Sjimharris *        update domain's remote device list.
1124230557Sjimharris *
1125230557Sjimharris * @param[in] fw_domain The framework domain that's to finish smp discover process.
1126230557Sjimharris *
1127230557Sjimharris * @return None
1128230557Sjimharris */
1129230557Sjimharrisvoid scif_sas_domain_finish_discover(
1130230557Sjimharris   SCIF_SAS_DOMAIN_T * fw_domain
1131230557Sjimharris)
1132230557Sjimharris{
1133230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * current_device = NULL;
1134230557Sjimharris   SCI_ABSTRACT_ELEMENT_T   * current_element = NULL;
1135230557Sjimharris
1136230557Sjimharris   SCIF_LOG_TRACE((
1137230557Sjimharris      sci_base_object_get_logger(fw_domain),
1138230557Sjimharris      SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1139230557Sjimharris      "scif_sas_domain_finish_discover(0x%x) enter\n",
1140230557Sjimharris      fw_domain
1141230557Sjimharris   ));
1142230557Sjimharris
1143230557Sjimharris   //need to scrub all the devices behind the expander. Check each
1144230557Sjimharris   //device's discover_status. if the is_currently_discovered is FALSE, means
1145230557Sjimharris   //the device is not been rediscovered. this device needs to be removed.
1146230557Sjimharris   current_element = sci_abstract_list_get_front(&fw_domain->remote_device_list);
1147230557Sjimharris   while (current_element != NULL )
1148230557Sjimharris   {
1149230557Sjimharris      current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
1150230557Sjimharris                          sci_abstract_list_get_object(current_element);
1151230557Sjimharris
1152230557Sjimharris      //We must get the next element before we remove the current
1153230557Sjimharris      //device. Or else, we will get wrong next_element, since the erased
1154230557Sjimharris      //element has been put into free pool.
1155230557Sjimharris      current_element = sci_abstract_list_get_next(current_element);
1156230557Sjimharris
1157230557Sjimharris      if ( current_device->is_currently_discovered == FALSE )
1158230557Sjimharris      {
1159230557Sjimharris         // Notify the framework user of the device removal.
1160230557Sjimharris         scif_cb_domain_device_removed(
1161230557Sjimharris            fw_domain->controller, fw_domain, current_device
1162230557Sjimharris         );
1163230557Sjimharris      }
1164230557Sjimharris   }
1165230557Sjimharris
1166230557Sjimharris   sci_base_state_machine_change_state(
1167230557Sjimharris      &fw_domain->parent.state_machine, SCI_BASE_DOMAIN_STATE_READY
1168230557Sjimharris   );
1169230557Sjimharris}
1170230557Sjimharris
1171230557Sjimharris
1172230557Sjimharris
1173230557Sjimharris/**
1174230557Sjimharris * @brief This method remove an expander device and its child devices, in order to
1175230557Sjimharris *        deal with a detected illeagal phy connection.
1176230557Sjimharris *
1177230557Sjimharris * @param[in] fw_domain The domain that a expander belongs to.
1178230557Sjimharris * @param[in] fw_device The expander device to be removed.
1179230557Sjimharris *
1180230557Sjimharris * @return none.
1181230557Sjimharris */
1182230557Sjimharrisvoid scif_sas_domain_remove_expander_device(
1183230557Sjimharris   SCIF_SAS_DOMAIN_T        * fw_domain,
1184230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device
1185230557Sjimharris)
1186230557Sjimharris{
1187230557Sjimharris   SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device =
1188230557Sjimharris      &fw_device->protocol_device.smp_device;
1189230557Sjimharris
1190230557Sjimharris   SCI_FAST_LIST_ELEMENT_T     * element = smp_remote_device->smp_phy_list.list_head;
1191230557Sjimharris   SCIF_SAS_SMP_PHY_T          * curr_smp_phy = NULL;
1192230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T    * current_device = NULL;
1193230557Sjimharris
1194230557Sjimharris   while (element != NULL)
1195230557Sjimharris   {
1196230557Sjimharris      curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element);
1197230557Sjimharris      element = sci_fast_list_get_next(element);
1198230557Sjimharris
1199230557Sjimharris      if ( curr_smp_phy->attached_device_type != SMP_NO_DEVICE_ATTACHED
1200230557Sjimharris          && curr_smp_phy->u.end_device != NULL )
1201230557Sjimharris      {
1202230557Sjimharris         if (curr_smp_phy->attached_device_type == SMP_END_DEVICE_ONLY)
1203230557Sjimharris            current_device = curr_smp_phy->u.end_device;
1204230557Sjimharris         else
1205230557Sjimharris            current_device = curr_smp_phy->u.attached_phy->owning_device;
1206230557Sjimharris
1207230557Sjimharris         scif_cb_domain_device_removed(fw_domain->controller, fw_domain, current_device);
1208230557Sjimharris      }
1209230557Sjimharris   }
1210230557Sjimharris
1211230557Sjimharris   //remove device itself
1212230557Sjimharris   scif_cb_domain_device_removed(fw_domain->controller, fw_domain, fw_device);
1213230557Sjimharris}
1214230557Sjimharris
1215230557Sjimharris
1216230557Sjimharris/**
1217230557Sjimharris * @brief This method searches the whole domain and finds all the smp devices to
1218230557Sjimharris *        cancel their smp activities if there is any.
1219230557Sjimharris *
1220230557Sjimharris * @param[in] fw_domain The domain that its smp activities are to be canceled.
1221230557Sjimharris *
1222230557Sjimharris * @return none.
1223230557Sjimharris */
1224230557Sjimharrisvoid scif_sas_domain_cancel_smp_activities(
1225230557Sjimharris   SCIF_SAS_DOMAIN_T * fw_domain
1226230557Sjimharris)
1227230557Sjimharris{
1228230557Sjimharris   SCI_ABSTRACT_ELEMENT_T * current_element =
1229230557Sjimharris      sci_abstract_list_get_front(&fw_domain->remote_device_list);
1230230557Sjimharris
1231230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * current_device;
1232230557Sjimharris
1233230557Sjimharris   //purge all the outstanding internal IOs in HPQ.
1234230557Sjimharris   scif_sas_high_priority_request_queue_purge_domain(
1235230557Sjimharris      &fw_domain->controller->hprq, fw_domain
1236230557Sjimharris   );
1237230557Sjimharris
1238230557Sjimharris   while ( current_element != NULL )
1239230557Sjimharris   {
1240230557Sjimharris      SMP_DISCOVER_RESPONSE_PROTOCOLS_T  dev_protocols;
1241230557Sjimharris
1242230557Sjimharris      current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
1243230557Sjimharris                       sci_abstract_list_get_object(current_element);
1244230557Sjimharris
1245230557Sjimharris      scic_remote_device_get_protocols(current_device->core_object,
1246230557Sjimharris                                       &dev_protocols
1247230557Sjimharris      );
1248230557Sjimharris
1249230557Sjimharris      if (dev_protocols.u.bits.attached_smp_target)
1250230557Sjimharris      {
1251230557Sjimharris         scif_sas_smp_remote_device_cancel_smp_activity(current_device);
1252230557Sjimharris      }
1253230557Sjimharris
1254230557Sjimharris      current_element =
1255230557Sjimharris         sci_abstract_list_get_next(current_element);
1256230557Sjimharris   }
1257230557Sjimharris}
1258230557Sjimharris
1259230557Sjimharris
1260230557Sjimharris/**
1261230557Sjimharris * @brief This method searches the domain's request list and counts outstanding
1262230557Sjimharris *           smp IOs.
1263230557Sjimharris *
1264230557Sjimharris * @param[in] fw_domain The domain that its request list is to be searched.
1265230557Sjimharris *
1266230557Sjimharris * @return U8 The possible return value of this routine is 0 or 1.
1267230557Sjimharris */
1268230557SjimharrisU8 scif_sas_domain_get_smp_request_count(
1269230557Sjimharris   SCIF_SAS_DOMAIN_T * fw_domain
1270230557Sjimharris)
1271230557Sjimharris{
1272230557Sjimharris   SCI_FAST_LIST_ELEMENT_T * element = fw_domain->request_list.list_head;
1273230557Sjimharris   SCIF_SAS_REQUEST_T      * request = NULL;
1274230557Sjimharris   U8                        count = 0;
1275230557Sjimharris   SCIC_TRANSPORT_PROTOCOL   protocol;
1276230557Sjimharris
1277230557Sjimharris   // Cycle through the fast list of IO requests.  Terminate each
1278250460Seadler   // outstanding requests that matches the criteria supplied by the
1279230557Sjimharris   // caller.
1280230557Sjimharris   while (element != NULL)
1281230557Sjimharris   {
1282230557Sjimharris      request = (SCIF_SAS_REQUEST_T*) sci_fast_list_get_object(element);
1283230557Sjimharris      // The current element may be deleted from the list becasue of
1284230557Sjimharris      // IO completion so advance to the next element early
1285230557Sjimharris      element = sci_fast_list_get_next(element);
1286230557Sjimharris
1287230557Sjimharris      protocol = scic_io_request_get_protocol(request->core_object);
1288230557Sjimharris
1289230557Sjimharris      if ( protocol == SCIC_SMP_PROTOCOL)
1290230557Sjimharris         count++;
1291230557Sjimharris   }
1292230557Sjimharris
1293230557Sjimharris   return count;
1294230557Sjimharris}
1295230557Sjimharris
1296230557Sjimharris
1297230557Sjimharris/**
1298230557Sjimharris * @brief This method start clear affiliation activities for smp devices in
1299230557Sjimharris *           this domain.
1300230557Sjimharris *
1301230557Sjimharris * @param[in] fw_domain The domain that its smp devices are scheduled to clear
1302230557Sjimharris *                affiliation for all the EA SATA devices.
1303230557Sjimharris *
1304230557Sjimharris * @return none.
1305230557Sjimharris */
1306230557Sjimharrisvoid scif_sas_domain_start_clear_affiliation(
1307230557Sjimharris   SCIF_SAS_DOMAIN_T * fw_domain
1308230557Sjimharris)
1309230557Sjimharris{
1310230557Sjimharris   scif_sas_domain_schedule_clear_affiliation(fw_domain);
1311230557Sjimharris   scif_sas_domain_continue_clear_affiliation(fw_domain);
1312230557Sjimharris}
1313230557Sjimharris
1314230557Sjimharris
1315230557Sjimharris/**
1316230557Sjimharris * @brief This method schedule clear affiliation activities for smp devices in
1317230557Sjimharris *           this domain.
1318230557Sjimharris *
1319230557Sjimharris * @param[in] fw_domain The domain that its smp devices are scheduled to clear
1320230557Sjimharris *                affiliation for all the EA SATA devices.
1321230557Sjimharris *
1322230557Sjimharris * @return none.
1323230557Sjimharris */
1324230557Sjimharrisvoid scif_sas_domain_schedule_clear_affiliation(
1325230557Sjimharris   SCIF_SAS_DOMAIN_T * fw_domain
1326230557Sjimharris)
1327230557Sjimharris{
1328230557Sjimharris   SCI_ABSTRACT_ELEMENT_T * current_element =
1329230557Sjimharris      sci_abstract_list_get_front(&fw_domain->remote_device_list);
1330230557Sjimharris
1331230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * current_device;
1332230557Sjimharris   SMP_DISCOVER_RESPONSE_PROTOCOLS_T  dev_protocols;
1333230557Sjimharris
1334230557Sjimharris   //config route table activity has higher priority than discover activity.
1335230557Sjimharris   while ( current_element != NULL )
1336230557Sjimharris   {
1337230557Sjimharris      current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
1338230557Sjimharris                       sci_abstract_list_get_object(current_element);
1339230557Sjimharris
1340230557Sjimharris      scic_remote_device_get_protocols(current_device->core_object,
1341230557Sjimharris                                       &dev_protocols);
1342230557Sjimharris
1343230557Sjimharris      current_element =
1344230557Sjimharris         sci_abstract_list_get_next(current_element);
1345230557Sjimharris
1346230557Sjimharris      if ( dev_protocols.u.bits.attached_smp_target )
1347230557Sjimharris      {
1348230557Sjimharris         current_device->protocol_device.smp_device.scheduled_activity =
1349230557Sjimharris            SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAR_AFFILIATION;
1350230557Sjimharris      }
1351230557Sjimharris   }
1352230557Sjimharris}
1353230557Sjimharris
1354230557Sjimharris
1355230557Sjimharris/**
1356230557Sjimharris * @brief This method carries clear affiliation activities for a smp devices in
1357230557Sjimharris *           this domain during controller stop process.
1358230557Sjimharris *
1359230557Sjimharris * @param[in] fw_domain The domain that its smp devices are to clear
1360230557Sjimharris *                affiliation for all the EA SATA devices.
1361230557Sjimharris *
1362230557Sjimharris * @return none.
1363230557Sjimharris */
1364230557Sjimharrisvoid scif_sas_domain_continue_clear_affiliation(
1365230557Sjimharris   SCIF_SAS_DOMAIN_T * fw_domain
1366230557Sjimharris)
1367230557Sjimharris{
1368230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * smp_device =
1369230557Sjimharris      scif_sas_domain_find_device_has_scheduled_activity(
1370230557Sjimharris         fw_domain,
1371230557Sjimharris         SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAR_AFFILIATION
1372230557Sjimharris      );
1373230557Sjimharris
1374230557Sjimharris   if (smp_device != NULL)
1375230557Sjimharris      scif_sas_smp_remote_device_start_clear_affiliation(smp_device);
1376230557Sjimharris   else
1377230557Sjimharris   {
1378230557Sjimharris      //This domain has done clear affiliation.
1379230557Sjimharris      SCIF_SAS_CONTROLLER_T * fw_controller = fw_domain->controller;
1380230557Sjimharris      fw_controller->current_domain_to_clear_affiliation++;
1381230557Sjimharris
1382230557Sjimharris      //let controller continue to clear affiliation on other domains.
1383230557Sjimharris      scif_sas_controller_clear_affiliation(fw_domain->controller);
1384230557Sjimharris   }
1385230557Sjimharris}
1386230557Sjimharris
1387230557Sjimharris
1388230557Sjimharris/**
1389230557Sjimharris * @brief This method releases resource for a framework domain.
1390230557Sjimharris *
1391230557Sjimharris * @param[in] fw_controller This parameter specifies the framework
1392230557Sjimharris *            controller, its associated domain's resources are to be released.
1393230557Sjimharris * @param[in] fw_domain This parameter specifies the framework
1394230557Sjimharris *            domain whose resources are to be released.
1395230557Sjimharris */
1396230557Sjimharrisvoid scif_sas_domain_release_resource(
1397230557Sjimharris   SCIF_SAS_CONTROLLER_T * fw_controller,
1398230557Sjimharris   SCIF_SAS_DOMAIN_T     * fw_domain
1399230557Sjimharris)
1400230557Sjimharris{
1401230557Sjimharris   if (fw_domain->operation.timer != NULL)
1402230557Sjimharris   {
1403230557Sjimharris      scif_cb_timer_destroy(fw_controller, fw_domain->operation.timer);
1404230557Sjimharris      fw_domain->operation.timer = NULL;
1405230557Sjimharris   }
1406230557Sjimharris}
1407230557Sjimharris
1408230557Sjimharris
1409230557Sjimharris/**
1410230557Sjimharris * @brief This method finds the a EA device that has target reset scheduled.
1411230557Sjimharris *
1412230557Sjimharris * @param[in] fw_domain The framework domain object
1413230557Sjimharris *
1414230557Sjimharris * @return SCIF_SAS_REMOTE_DEVICE_T The EA device that has target reset scheduled.
1415230557Sjimharris */
1416230557SjimharrisSCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_find_next_ea_target_reset(
1417230557Sjimharris   SCIF_SAS_DOMAIN_T     * fw_domain
1418230557Sjimharris)
1419230557Sjimharris{
1420230557Sjimharris   SCI_ABSTRACT_ELEMENT_T   * current_element;
1421230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * current_device;
1422230557Sjimharris
1423230557Sjimharris   SCIF_LOG_TRACE((
1424230557Sjimharris      sci_base_object_get_logger(fw_domain),
1425230557Sjimharris      SCIF_LOG_OBJECT_DOMAIN,
1426230557Sjimharris      "scif_sas_domain_find_next_ea_target_reset(0x%x) enter\n",
1427230557Sjimharris      fw_domain
1428230557Sjimharris   ));
1429230557Sjimharris
1430230557Sjimharris   //search throught domain's device list to find the first sata device on spinup_hold
1431230557Sjimharris   current_element = sci_abstract_list_get_front(&fw_domain->remote_device_list);
1432230557Sjimharris   while (current_element != NULL )
1433230557Sjimharris   {
1434230557Sjimharris      current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
1435230557Sjimharris                       sci_abstract_list_get_object(current_element);
1436230557Sjimharris
1437230557Sjimharris      current_element = sci_abstract_list_get_next(current_element);
1438230557Sjimharris
1439230557Sjimharris      if ( current_device->ea_target_reset_request_scheduled != NULL )
1440230557Sjimharris      {
1441230557Sjimharris         return current_device;
1442230557Sjimharris      }
1443230557Sjimharris   }
1444230557Sjimharris
1445230557Sjimharris   return NULL;
1446230557Sjimharris}
1447230557Sjimharris
1448230557Sjimharris#if !defined(DISABLE_WIDE_PORTED_TARGETS)
1449230557Sjimharris/**
1450230557Sjimharris * @brief This method update the direct attached device port width.
1451230557Sjimharris *
1452230557Sjimharris * @param[in] fw_domain The framework domain object
1453230557Sjimharris * @param[in] port The associated port object which recently has link up/down
1454230557Sjimharris *                 event happened.
1455230557Sjimharris *
1456230557Sjimharris * @return none
1457230557Sjimharris */
1458230557Sjimharrisvoid scif_sas_domain_update_device_port_width(
1459230557Sjimharris   SCIF_SAS_DOMAIN_T * fw_domain,
1460230557Sjimharris   SCI_PORT_HANDLE_T   port
1461230557Sjimharris)
1462230557Sjimharris{
1463230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device;
1464230557Sjimharris   SCIC_PORT_PROPERTIES_T     properties;
1465230557Sjimharris   U8                         new_port_width = 0;
1466230557Sjimharris
1467230557Sjimharris   SCIF_LOG_TRACE((
1468230557Sjimharris      sci_base_object_get_logger(fw_domain),
1469230557Sjimharris      SCIF_LOG_OBJECT_DOMAIN,
1470230557Sjimharris      "scif_sas_domain_update_device_port_width(0x%x, 0x%x) enter\n",
1471230557Sjimharris      fw_domain, port
1472230557Sjimharris   ));
1473230557Sjimharris
1474230557Sjimharris   scic_port_get_properties(port, &properties);
1475230557Sjimharris
1476230557Sjimharris   fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)
1477230557Sjimharris                  scif_domain_get_device_by_sas_address(
1478230557Sjimharris                  fw_domain, &properties.remote.sas_address
1479230557Sjimharris               );
1480230557Sjimharris
1481230557Sjimharris   // If the device already existed in the domain, it is a wide port SSP target,
1482230557Sjimharris   // we need to update its port width.
1483230557Sjimharris   if (fw_device != SCI_INVALID_HANDLE)
1484230557Sjimharris   {
1485230557Sjimharris      SMP_DISCOVER_RESPONSE_PROTOCOLS_T  dev_protocols;
1486230557Sjimharris      scic_remote_device_get_protocols(fw_device->core_object, &dev_protocols);
1487230557Sjimharris
1488230557Sjimharris      if (dev_protocols.u.bits.attached_ssp_target)
1489230557Sjimharris      {
1490230557Sjimharris         //Get accurate port width from port's phy mask for a DA device.
1491230557Sjimharris         SCI_GET_BITS_SET_COUNT(properties.phy_mask, new_port_width);
1492230557Sjimharris
1493230557Sjimharris         scif_sas_remote_device_update_port_width(fw_device, new_port_width);
1494230557Sjimharris      }
1495230557Sjimharris   }
1496230557Sjimharris}
1497230557Sjimharris#endif //#if !defined(DISABLE_WIDE_PORTED_TARGETS)
1498230557Sjimharris
1499230557Sjimharris
1500230557Sjimharris#ifdef SCI_LOGGING
1501230557Sjimharris/**
1502230557Sjimharris * This method will turn on logging of domain state changes.
1503230557Sjimharris *
1504230557Sjimharris * @param[in] fw_domain The domain for which the state logging is to be turned
1505230557Sjimharris *       on.
1506230557Sjimharris */
1507230557Sjimharrisvoid scif_sas_domain_initialize_state_logging(
1508230557Sjimharris   SCIF_SAS_DOMAIN_T *fw_domain
1509230557Sjimharris)
1510230557Sjimharris{
1511230557Sjimharris   sci_base_state_machine_logger_initialize(
1512230557Sjimharris      &fw_domain->parent.state_machine_logger,
1513230557Sjimharris      &fw_domain->parent.state_machine,
1514230557Sjimharris      &fw_domain->parent.parent,
1515230557Sjimharris      scif_cb_logger_log_states,
1516230557Sjimharris      "SCIF_SAS_DOMAIN_T", "base state machine",
1517230557Sjimharris      SCIF_LOG_OBJECT_DOMAIN
1518230557Sjimharris   );
1519230557Sjimharris}
1520230557Sjimharris
1521230557Sjimharris/**
1522230557Sjimharris * This method will turn off logging of domain state changes.
1523230557Sjimharris *
1524230557Sjimharris * @param[in] fw_domain The domain for which the state logging is to be turned
1525230557Sjimharris *       off.
1526230557Sjimharris */
1527230557Sjimharrisvoid scif_sas_domain_deinitialize_state_logging(
1528230557Sjimharris   SCIF_SAS_DOMAIN_T *fw_domain
1529230557Sjimharris)
1530230557Sjimharris{
1531230557Sjimharris   sci_base_state_machine_logger_deinitialize(
1532230557Sjimharris      &fw_domain->parent.state_machine_logger,
1533230557Sjimharris      &fw_domain->parent.state_machine
1534230557Sjimharris   );
1535230557Sjimharris}
1536230557Sjimharris#endif
1537