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 all of the entrance and exit methods for each
60230557Sjimharris *        of the domain states defined by the SCI_BASE_DOMAIN state
61230557Sjimharris *        machine.
62230557Sjimharris */
63230557Sjimharris
64230557Sjimharris#include <dev/isci/scil/intel_sas.h>
65230557Sjimharris#include <dev/isci/scil/scic_port.h>
66230557Sjimharris
67230557Sjimharris#include <dev/isci/scil/scif_sas_logger.h>
68230557Sjimharris#include <dev/isci/scil/scif_sas_domain.h>
69230557Sjimharris#include <dev/isci/scil/scif_sas_controller.h>
70230557Sjimharris#include <dev/isci/scil/scic_controller.h>
71230557Sjimharris
72230557Sjimharris//******************************************************************************
73230557Sjimharris//* P R O T E C T E D    M E T H O D S
74230557Sjimharris//******************************************************************************
75230557Sjimharris
76230557Sjimharris/**
77230557Sjimharris * @brief This method will attempt to transition to the stopped state.
78230557Sjimharris *        The transition will only occur if the criteria for transition is
79230557Sjimharris *        met (i.e. all IOs are complete and all devices are stopped).
80230557Sjimharris *
81230557Sjimharris * @param[in]  fw_domain This parameter specifies the domain in which to
82230557Sjimharris *             to attempt to perform the transition.
83230557Sjimharris *
84230557Sjimharris * @return none
85230557Sjimharris */
86230557Sjimharrisvoid scif_sas_domain_transition_to_stopped_state(
87230557Sjimharris   SCIF_SAS_DOMAIN_T * fw_domain
88230557Sjimharris)
89230557Sjimharris{
90230557Sjimharris   SCIF_LOG_TRACE((
91230557Sjimharris      sci_base_object_get_logger(fw_domain),
92230557Sjimharris      SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
93230557Sjimharris      "scif_sas_domain_transition_to_stopped_state(0x%x) enter\n",
94230557Sjimharris      fw_domain
95230557Sjimharris   ));
96230557Sjimharris
97230557Sjimharris   // If IOs are quiesced, and all remote devices are stopped,
98230557Sjimharris   // then transition directly to the STOPPED state.
99230557Sjimharris   if (  (fw_domain->request_list.element_count == 0)
100230557Sjimharris      && (fw_domain->device_start_count == 0) )
101230557Sjimharris   {
102230557Sjimharris      SCIF_LOG_INFO((
103230557Sjimharris         sci_base_object_get_logger(fw_domain),
104230557Sjimharris         SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
105230557Sjimharris         "Domain:0x%x immediate transition to STOPPED\n",
106230557Sjimharris         fw_domain
107230557Sjimharris      ));
108230557Sjimharris
109230557Sjimharris      sci_base_state_machine_change_state(
110230557Sjimharris         &fw_domain->parent.state_machine, SCI_BASE_DOMAIN_STATE_STOPPED
111230557Sjimharris      );
112230557Sjimharris   }
113230557Sjimharris}
114230557Sjimharris
115230557Sjimharris
116230557Sjimharris/**
117230557Sjimharris * @brief This method is called upon entrance to all states where the
118230557Sjimharris *        previous state may have been the DISCOVERING state.
119230557Sjimharris *        We issue the scif_cb_domain_discovery_complete() notification
120230557Sjimharris *        from this method, assuming pre-requisites are met, as opposed
121230557Sjimharris *        to in the exit handler of the DISCOVERING state, so that the
122230557Sjimharris *        appropriate state handlers are in place should the user decide
123230557Sjimharris *        to call scif_domain_discover() again.
124230557Sjimharris *
125230557Sjimharris * @param[in]  fw_domain This parameter specifies the domain for which
126230557Sjimharris *             the state transition has occurred.
127230557Sjimharris *
128230557Sjimharris * @return none
129230557Sjimharris */
130230557Sjimharrisstatic
131230557Sjimharrisvoid scif_sas_domain_transition_from_discovering_state(
132230557Sjimharris   SCIF_SAS_DOMAIN_T * fw_domain
133230557Sjimharris)
134230557Sjimharris{
135230557Sjimharris   SCIF_LOG_TRACE((
136230557Sjimharris      sci_base_object_get_logger(fw_domain),
137230557Sjimharris      SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
138230557Sjimharris      "scif_sas_domain_transition_from_discovering_state(0x%x) enter\n",
139230557Sjimharris      fw_domain
140230557Sjimharris   ));
141230557Sjimharris
142230557Sjimharris   if (fw_domain->parent.state_machine.previous_state_id
143230557Sjimharris       == SCI_BASE_DOMAIN_STATE_DISCOVERING)
144230557Sjimharris   {
145230557Sjimharris      scif_sas_controller_restore_interrupt_coalescence(fw_domain->controller);
146230557Sjimharris
147230557Sjimharris      scif_cb_timer_stop(fw_domain->controller, fw_domain->operation.timer);
148230557Sjimharris
149230557Sjimharris      scif_cb_domain_discovery_complete(
150230557Sjimharris         fw_domain->controller, fw_domain, fw_domain->operation.status
151230557Sjimharris      );
152230557Sjimharris   }
153230557Sjimharris}
154230557Sjimharris
155230557Sjimharris
156230557Sjimharris/**
157230557Sjimharris * @brief This method is called upon entrance to DISCOVERING state. Right before
158230557Sjimharris *           transitioning to DISCOVERING state, we temporarily change interrupt
159230557Sjimharris *           coalescence scheme.
160230557Sjimharris *
161230557Sjimharris * @param[in]  fw_domain This parameter specifies the domain for which
162230557Sjimharris *             the state transition has occurred.
163230557Sjimharris *
164230557Sjimharris * @return none
165230557Sjimharris */
166230557Sjimharrisvoid scif_sas_domain_transition_to_discovering_state(
167230557Sjimharris   SCIF_SAS_DOMAIN_T * fw_domain
168230557Sjimharris)
169230557Sjimharris{
170230557Sjimharris   scif_sas_controller_save_interrupt_coalescence(fw_domain->controller);
171230557Sjimharris
172230557Sjimharris   sci_base_state_machine_change_state(
173230557Sjimharris      &fw_domain->parent.state_machine, SCI_BASE_DOMAIN_STATE_DISCOVERING
174230557Sjimharris   );
175230557Sjimharris}
176230557Sjimharris
177230557Sjimharris
178230557Sjimharris/**
179230557Sjimharris * @brief This method implements the actions taken when entering the
180230557Sjimharris *        INITIAL state.
181230557Sjimharris *
182230557Sjimharris * @param[in]  object This parameter specifies the base object for which
183230557Sjimharris *             the state transition is occurring.  This is cast into a
184230557Sjimharris *             SCIF_SAS_DOMAIN object in the method implementation.
185230557Sjimharris *
186230557Sjimharris * @return none
187230557Sjimharris */
188230557Sjimharrisstatic
189230557Sjimharrisvoid scif_sas_domain_initial_state_enter(
190230557Sjimharris   SCI_BASE_OBJECT_T * object
191230557Sjimharris)
192230557Sjimharris{
193230557Sjimharris   SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T *)object;
194230557Sjimharris
195230557Sjimharris   SET_STATE_HANDLER(
196230557Sjimharris      fw_domain,
197230557Sjimharris      scif_sas_domain_state_handler_table,
198230557Sjimharris      SCI_BASE_DOMAIN_STATE_INITIAL
199230557Sjimharris   );
200230557Sjimharris
201230557Sjimharris   SCIF_LOG_TRACE((
202230557Sjimharris      sci_base_object_get_logger(fw_domain),
203230557Sjimharris      SCIF_LOG_OBJECT_DOMAIN,
204230557Sjimharris      "scif_sas_domain_initial_state_enter(0x%x) enter\n",
205230557Sjimharris      fw_domain
206230557Sjimharris   ));
207230557Sjimharris}
208230557Sjimharris
209230557Sjimharris/**
210230557Sjimharris * @brief This method implements the actions taken when entering the
211230557Sjimharris *        STARTING state.  This includes setting the state handlers and
212230557Sjimharris *        checking to see if the core port has already become READY.
213230557Sjimharris *
214230557Sjimharris * @param[in]  object This parameter specifies the base object for which
215230557Sjimharris *             the state transition is occurring.  This is cast into a
216230557Sjimharris *             SCIF_SAS_DOMAIN object in the method implementation.
217230557Sjimharris *
218230557Sjimharris * @return none
219230557Sjimharris */
220230557Sjimharrisstatic
221230557Sjimharrisvoid scif_sas_domain_starting_state_enter(
222230557Sjimharris   SCI_BASE_OBJECT_T * object
223230557Sjimharris)
224230557Sjimharris{
225230557Sjimharris   SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T *)object;
226230557Sjimharris
227230557Sjimharris   SET_STATE_HANDLER(
228230557Sjimharris      fw_domain,
229230557Sjimharris      scif_sas_domain_state_handler_table,
230230557Sjimharris      SCI_BASE_DOMAIN_STATE_STARTING
231230557Sjimharris   );
232230557Sjimharris
233230557Sjimharris   SCIF_LOG_TRACE((
234230557Sjimharris      sci_base_object_get_logger(fw_domain),
235230557Sjimharris      SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
236230557Sjimharris      "scif_sas_domain_starting_state_enter(0x%x) enter\n",
237230557Sjimharris      fw_domain
238230557Sjimharris   ));
239230557Sjimharris
240230557Sjimharris   scif_sas_domain_transition_from_discovering_state(fw_domain);
241230557Sjimharris
242230557Sjimharris   // If we entered the STARTING state and the core port is actually ready,
243230557Sjimharris   // then directly transition into the READY state.  This can occur
244230557Sjimharris   // if we were in the middle of discovery when the port failed
245230557Sjimharris   // (causing a transition to STOPPING), then before reaching STOPPED
246230557Sjimharris   // the port becomes ready again.
247230557Sjimharris   if (fw_domain->is_port_ready == TRUE)
248230557Sjimharris   {
249230557Sjimharris      sci_base_state_machine_change_state(
250230557Sjimharris         &fw_domain->parent.state_machine, SCI_BASE_DOMAIN_STATE_READY
251230557Sjimharris      );
252230557Sjimharris   }
253230557Sjimharris}
254230557Sjimharris
255230557Sjimharris/**
256230557Sjimharris * @brief This method implements the actions taken when entering the
257230557Sjimharris *        READY state.  If the transition into this state came from:
258230557Sjimharris *        - the STARTING state, then alert the user via a
259230557Sjimharris *          scif_cb_domain_change_notification() that the domain
260230557Sjimharris *          has at least 1 device ready for discovery.
261230557Sjimharris *        - the DISCOVERING state, then alert the user that
262230557Sjimharris *          discovery is complete via the
263230557Sjimharris *          scif_cb_domain_discovery_complete() notification that
264230557Sjimharris *          discovery is finished.
265230557Sjimharris *
266230557Sjimharris * @param[in]  object This parameter specifies the base object for which
267230557Sjimharris *             the state transition is occurring.  This is cast into a
268230557Sjimharris *             SCIF_SAS_DOMAIN object in the method implementation.
269230557Sjimharris *
270230557Sjimharris * @return none
271230557Sjimharris */
272230557Sjimharrisstatic
273230557Sjimharrisvoid scif_sas_domain_ready_state_enter(
274230557Sjimharris   SCI_BASE_OBJECT_T * object
275230557Sjimharris)
276230557Sjimharris{
277230557Sjimharris   SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T *)object;
278230557Sjimharris
279230557Sjimharris   SET_STATE_HANDLER(
280230557Sjimharris      fw_domain,
281230557Sjimharris      scif_sas_domain_state_handler_table,
282230557Sjimharris      SCI_BASE_DOMAIN_STATE_READY
283230557Sjimharris   );
284230557Sjimharris
285230557Sjimharris   SCIF_LOG_TRACE((
286230557Sjimharris      sci_base_object_get_logger(fw_domain),
287230557Sjimharris      SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
288230557Sjimharris      "scif_sas_domain_ready_state_enter(0x%x) enter\n",
289230557Sjimharris      fw_domain
290230557Sjimharris   ));
291230557Sjimharris
292230557Sjimharris   if (fw_domain->parent.state_machine.previous_state_id
293230557Sjimharris       == SCI_BASE_DOMAIN_STATE_STARTING)
294230557Sjimharris   {
295230557Sjimharris      scif_cb_domain_ready(fw_domain->controller, fw_domain);
296230557Sjimharris
297230557Sjimharris      // Only indicate the domain change notification if the previous
298230557Sjimharris      // state was the STARTING state.  We issue the notification here
299230557Sjimharris      // as opposed to exit of the STARTING state so that the appropriate
300230557Sjimharris      // state handlers are in place should the user call
301230557Sjimharris      // scif_domain_discover() from scif_cb_domain_change_notification()
302230557Sjimharris      scif_cb_domain_change_notification(fw_domain->controller, fw_domain);
303230557Sjimharris   }
304230557Sjimharris   else if (fw_domain->parent.state_machine.previous_state_id
305230557Sjimharris            == SCI_BASE_DOMAIN_STATE_DISCOVERING)
306230557Sjimharris   {
307230557Sjimharris      //if domain discovery timed out, we will NOT go back to discover even
308230557Sjimharris      //the broadcast change count is not zero. Instead we finish the discovery
309230557Sjimharris      //back to user. User can check the operation status and decide to
310230557Sjimharris      //retry discover all over again.
311230557Sjimharris      if (fw_domain->operation.status == SCI_FAILURE_TIMEOUT)
312230557Sjimharris         fw_domain->broadcast_change_count = 0;
313230557Sjimharris
314230557Sjimharris      // Check the broadcast change count to determine if discovery
315230557Sjimharris      // is indeed complete.
316230557Sjimharris      if (fw_domain->broadcast_change_count == 0)
317230557Sjimharris      {
318230557Sjimharris         scif_sas_domain_transition_from_discovering_state(fw_domain);
319230557Sjimharris         scif_cb_domain_ready(fw_domain->controller, fw_domain);
320230557Sjimharris      }
321230557Sjimharris      else
322230557Sjimharris      {
323230557Sjimharris         // The broadcast change count indicates something my have
324230557Sjimharris         // changed in the domain, while a discovery was ongoing.
325230557Sjimharris         // Thus, we should start discovery over again.
326230557Sjimharris         sci_base_state_machine_change_state(
327230557Sjimharris            &fw_domain->parent.state_machine, SCI_BASE_DOMAIN_STATE_DISCOVERING
328230557Sjimharris         );
329230557Sjimharris      }
330230557Sjimharris
331230557Sjimharris      // Enable the BCN because underneath hardware may disabled any further
332230557Sjimharris      // BCN.
333230557Sjimharris      scic_port_enable_broadcast_change_notification(fw_domain->core_object);
334230557Sjimharris   }
335230557Sjimharris}
336230557Sjimharris
337230557Sjimharris/**
338230557Sjimharris * @brief This method implements the actions taken when exiting the
339230557Sjimharris *        READY state.
340230557Sjimharris *
341230557Sjimharris * @param[in]  object This parameter specifies the base object for which
342230557Sjimharris *             the state transition is occurring.  This is cast into a
343230557Sjimharris *             SCIF_SAS_DOMAIN object in the method implementation.
344230557Sjimharris *
345230557Sjimharris * @return none
346230557Sjimharris */
347230557Sjimharrisstatic
348230557Sjimharrisvoid scif_sas_domain_ready_state_exit(
349230557Sjimharris   SCI_BASE_OBJECT_T * object
350230557Sjimharris)
351230557Sjimharris{
352230557Sjimharris   SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T *)object;
353230557Sjimharris
354230557Sjimharris   SCIF_LOG_TRACE((
355230557Sjimharris      sci_base_object_get_logger(fw_domain),
356230557Sjimharris      SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
357230557Sjimharris      "scif_sas_domain_ready_state_exit(0x%x) enter\n",
358230557Sjimharris      fw_domain
359230557Sjimharris   ));
360230557Sjimharris
361230557Sjimharris   scif_cb_domain_not_ready(fw_domain->controller, fw_domain);
362230557Sjimharris}
363230557Sjimharris
364230557Sjimharris/**
365230557Sjimharris * @brief This method implements the actions taken when entering the
366230557Sjimharris *        STOPPING state.
367230557Sjimharris *
368230557Sjimharris * @param[in]  object This parameter specifies the base object for which
369230557Sjimharris *             the state transition is occurring.  This is cast into a
370230557Sjimharris *             SCIF_SAS_DOMAIN object in the method implementation.
371230557Sjimharris *
372230557Sjimharris * @return none
373230557Sjimharris */
374230557Sjimharrisstatic
375230557Sjimharrisvoid scif_sas_domain_stopping_state_enter(
376230557Sjimharris   SCI_BASE_OBJECT_T * object
377230557Sjimharris)
378230557Sjimharris{
379230557Sjimharris   SCIF_SAS_REMOTE_DEVICE_T * fw_device;
380230557Sjimharris   SCIF_SAS_DOMAIN_T        * fw_domain = (SCIF_SAS_DOMAIN_T *)object;
381230557Sjimharris   SCI_ABSTRACT_ELEMENT_T   * element   = sci_abstract_list_get_front(
382230557Sjimharris                                             &fw_domain->remote_device_list
383230557Sjimharris                                          );
384230557Sjimharris
385230557Sjimharris   SET_STATE_HANDLER(
386230557Sjimharris      fw_domain,
387230557Sjimharris      scif_sas_domain_state_handler_table,
388230557Sjimharris      SCI_BASE_DOMAIN_STATE_STOPPING
389230557Sjimharris   );
390230557Sjimharris
391230557Sjimharris   // This must be invoked after the state handlers are set to ensure
392230557Sjimharris   // appropriate processing will occur if the user attempts to perform
393230557Sjimharris   // additional actions.
394230557Sjimharris   scif_sas_domain_transition_from_discovering_state(fw_domain);
395230557Sjimharris
396230557Sjimharris   SCIF_LOG_TRACE((
397230557Sjimharris      sci_base_object_get_logger(fw_domain),
398230557Sjimharris      SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
399230557Sjimharris      "scif_sas_domain_stopping_state_enter(0x%x) enter\n",
400230557Sjimharris      fw_domain
401230557Sjimharris   ));
402230557Sjimharris
403230557Sjimharris   scif_sas_high_priority_request_queue_purge_domain(
404230557Sjimharris      &fw_domain->controller->hprq, fw_domain
405230557Sjimharris   );
406230557Sjimharris
407230557Sjimharris   // Search the domain's list of devices and put them all in the STOPPING
408230557Sjimharris   // state.
409230557Sjimharris   while (element != NULL)
410230557Sjimharris   {
411230557Sjimharris      fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
412230557Sjimharris                  sci_abstract_list_get_object(element);
413230557Sjimharris
414230557Sjimharris      // This method will stop the core device.  The core will terminate
415230557Sjimharris      // all IO requests currently outstanding.
416230557Sjimharris      fw_device->state_handlers->parent.stop_handler(&fw_device->parent);
417230557Sjimharris
418230557Sjimharris      element = sci_abstract_list_get_next(element);
419230557Sjimharris   }
420230557Sjimharris
421230557Sjimharris   // Attempt to transition to the stopped state.
422230557Sjimharris   scif_sas_domain_transition_to_stopped_state(fw_domain);
423230557Sjimharris}
424230557Sjimharris
425230557Sjimharris/**
426230557Sjimharris * @brief This method implements the actions taken when entering the
427230557Sjimharris *        STOPPED state.
428230557Sjimharris *
429230557Sjimharris * @param[in]  object This parameter specifies the base object for which
430230557Sjimharris *             the state transition is occurring.  This is cast into a
431230557Sjimharris *             SCIF_SAS_DOMAIN object in the method implementation.
432230557Sjimharris *
433230557Sjimharris * @return none
434230557Sjimharris */
435230557Sjimharrisstatic
436230557Sjimharrisvoid scif_sas_domain_stopped_state_enter(
437230557Sjimharris   SCI_BASE_OBJECT_T * object
438230557Sjimharris)
439230557Sjimharris{
440230557Sjimharris   SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T *)object;
441230557Sjimharris
442230557Sjimharris   SET_STATE_HANDLER(
443230557Sjimharris      fw_domain,
444230557Sjimharris      scif_sas_domain_state_handler_table,
445230557Sjimharris      SCI_BASE_DOMAIN_STATE_STOPPED
446230557Sjimharris   );
447230557Sjimharris
448230557Sjimharris   SCIF_LOG_TRACE((
449230557Sjimharris      sci_base_object_get_logger(fw_domain),
450230557Sjimharris      SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
451230557Sjimharris      "scif_sas_domain_stopped_state_enter(0x%x) enter\n",
452230557Sjimharris      fw_domain
453230557Sjimharris   ));
454230557Sjimharris
455230557Sjimharris   // A hot unplug of the direct attached device has occurred.  Thus,
456230557Sjimharris   // notify the user. Note, if the controller is not in READY state,
457230557Sjimharris   // mostly likely the controller is in STOPPING or STOPPED state,
458230557Sjimharris   // meaning the controller is in the process of stopping, we should
459230557Sjimharris   // not call back to user in the middle of controller stopping.
460230557Sjimharris   if(fw_domain->controller->parent.state_machine.current_state_id
461230557Sjimharris         == SCI_BASE_CONTROLLER_STATE_READY)
462230557Sjimharris      scif_cb_domain_change_notification(fw_domain->controller, fw_domain);
463230557Sjimharris}
464230557Sjimharris
465230557Sjimharris/**
466230557Sjimharris * @brief This method implements the actions taken when entering the
467230557Sjimharris *        DISCOVERING state.  This includes determining from which
468230557Sjimharris *        state we entered.  If we entered from stopping that some sort
469230557Sjimharris *        of hot-remove of the port occurred.  In the hot-remove case
470230557Sjimharris *        all devices should be in the STOPPED state already and, as
471230557Sjimharris *        a result, are removed from the domain with a notification sent
472230557Sjimharris *        to the framework user.
473230557Sjimharris *
474230557Sjimharris * @note This method currently only handles hot-insert/hot-remove of
475230557Sjimharris *       direct attached SSP devices.
476230557Sjimharris *
477230557Sjimharris * @param[in]  object This parameter specifies the base object for which
478230557Sjimharris *             the state transition is occurring.  This is cast into a
479230557Sjimharris *             SCIF_SAS_DOMAIN object in the method implementation.
480230557Sjimharris *
481230557Sjimharris * @return none
482230557Sjimharris */
483230557Sjimharrisstatic
484230557Sjimharrisvoid scif_sas_domain_discovering_state_enter(
485230557Sjimharris   SCI_BASE_OBJECT_T * object
486230557Sjimharris)
487230557Sjimharris{
488230557Sjimharris   SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T *)object;
489230557Sjimharris
490230557Sjimharris   SET_STATE_HANDLER(
491230557Sjimharris      fw_domain,
492230557Sjimharris      scif_sas_domain_state_handler_table,
493230557Sjimharris      SCI_BASE_DOMAIN_STATE_DISCOVERING
494230557Sjimharris   );
495230557Sjimharris
496230557Sjimharris   SCIF_LOG_TRACE((
497230557Sjimharris      sci_base_object_get_logger(fw_domain),
498230557Sjimharris      SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
499230557Sjimharris      "scif_sas_domain_discovering_state_enter(0x%x) enter\n",
500230557Sjimharris      fw_domain
501230557Sjimharris   ));
502230557Sjimharris
503230557Sjimharris   fw_domain->broadcast_change_count = 0;
504230557Sjimharris
505230557Sjimharris   // Did the domain just go through a port not ready action?  If it did,
506230557Sjimharris   // then we will be entering from the STOPPED state.
507230557Sjimharris   if (fw_domain->parent.state_machine.previous_state_id
508230557Sjimharris       != SCI_BASE_DOMAIN_STATE_STOPPED)
509230557Sjimharris   {
510230557Sjimharris      SCIF_SAS_REMOTE_DEVICE_T * remote_device;
511230557Sjimharris      SCIC_PORT_PROPERTIES_T     properties;
512230557Sjimharris
513230557Sjimharris      scic_port_get_properties(fw_domain->core_object, &properties);
514230557Sjimharris
515230557Sjimharris      // If the device has not yet been added to the domain, then
516230557Sjimharris      // inform the user that the device is new.
517230557Sjimharris      remote_device = (SCIF_SAS_REMOTE_DEVICE_T *)
518230557Sjimharris                      scif_domain_get_device_by_sas_address(
519230557Sjimharris                         fw_domain, &properties.remote.sas_address
520230557Sjimharris                      );
521230557Sjimharris      if (remote_device == SCI_INVALID_HANDLE)
522230557Sjimharris      {
523230557Sjimharris         // simply notify the user of the new DA device and be done
524230557Sjimharris         // with discovery.
525230557Sjimharris         scif_cb_domain_da_device_added(
526230557Sjimharris            fw_domain->controller,
527230557Sjimharris            fw_domain,
528230557Sjimharris            &properties.remote.sas_address,
529230557Sjimharris            &properties.remote.protocols
530230557Sjimharris         );
531230557Sjimharris      }
532230557Sjimharris      else
533230557Sjimharris      {
534230557Sjimharris         if(properties.remote.protocols.u.bits.smp_target)
535230557Sjimharris            //kick off the smp discover process.
536230557Sjimharris            scif_sas_domain_start_smp_discover(fw_domain, remote_device);
537230557Sjimharris      }
538230557Sjimharris   }
539230557Sjimharris   else  //entered from STOPPED state.
540230557Sjimharris   {
541230557Sjimharris      SCI_ABSTRACT_ELEMENT_T * current_element =
542230557Sjimharris             sci_abstract_list_get_front(&(fw_domain->remote_device_list) );
543230557Sjimharris
544230557Sjimharris      SCIF_SAS_REMOTE_DEVICE_T * fw_device;
545230557Sjimharris
546230557Sjimharris      while (current_element != NULL)
547230557Sjimharris      {
548230557Sjimharris         fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)
549230557Sjimharris                     sci_abstract_list_get_object(current_element);
550230557Sjimharris
551230557Sjimharris         ASSERT(fw_device->parent.state_machine.current_state_id
552230557Sjimharris                == SCI_BASE_REMOTE_DEVICE_STATE_STOPPED);
553230557Sjimharris
554230557Sjimharris         current_element =
555230557Sjimharris            sci_abstract_list_get_next(current_element);
556230557Sjimharris
557230557Sjimharris         SCIF_LOG_INFO((
558230557Sjimharris            sci_base_object_get_logger(fw_domain),
559230557Sjimharris            SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
560230557Sjimharris            "Controller:0x%x Domain:0x%x Device:0x%x removed\n",
561230557Sjimharris            fw_domain->controller, fw_domain, fw_device
562230557Sjimharris         ));
563230557Sjimharris
564230557Sjimharris         // Notify the framework user of the device removal.
565230557Sjimharris         scif_cb_domain_device_removed(
566230557Sjimharris            fw_domain->controller, fw_domain, fw_device
567230557Sjimharris         );
568230557Sjimharris      }
569230557Sjimharris
570230557Sjimharris      ASSERT(fw_domain->request_list.element_count == 0);
571230557Sjimharris      ASSERT(sci_abstract_list_size(&fw_domain->remote_device_list) == 0);
572230557Sjimharris
573230557Sjimharris      sci_base_state_machine_change_state(
574230557Sjimharris         &fw_domain->parent.state_machine, SCI_BASE_DOMAIN_STATE_STARTING
575230557Sjimharris      );
576230557Sjimharris   }
577230557Sjimharris}
578230557Sjimharris
579230557SjimharrisSCI_BASE_STATE_T scif_sas_domain_state_table[SCI_BASE_DOMAIN_MAX_STATES] =
580230557Sjimharris{
581230557Sjimharris   {
582230557Sjimharris      SCI_BASE_DOMAIN_STATE_INITIAL,
583230557Sjimharris      scif_sas_domain_initial_state_enter,
584230557Sjimharris      NULL,
585230557Sjimharris   },
586230557Sjimharris   {
587230557Sjimharris      SCI_BASE_DOMAIN_STATE_STARTING,
588230557Sjimharris      scif_sas_domain_starting_state_enter,
589230557Sjimharris      NULL,
590230557Sjimharris   },
591230557Sjimharris   {
592230557Sjimharris      SCI_BASE_DOMAIN_STATE_READY,
593230557Sjimharris      scif_sas_domain_ready_state_enter,
594230557Sjimharris      scif_sas_domain_ready_state_exit,
595230557Sjimharris   },
596230557Sjimharris   {
597230557Sjimharris      SCI_BASE_DOMAIN_STATE_STOPPING,
598230557Sjimharris      scif_sas_domain_stopping_state_enter,
599230557Sjimharris      NULL,
600230557Sjimharris   },
601230557Sjimharris   {
602230557Sjimharris      SCI_BASE_DOMAIN_STATE_STOPPED,
603230557Sjimharris      scif_sas_domain_stopped_state_enter,
604230557Sjimharris      NULL,
605230557Sjimharris   },
606230557Sjimharris   {
607230557Sjimharris      SCI_BASE_DOMAIN_STATE_DISCOVERING,
608230557Sjimharris      scif_sas_domain_discovering_state_enter,
609230557Sjimharris      NULL,
610230557Sjimharris   }
611230557Sjimharris};
612230557Sjimharris
613