613 lines
20 KiB
C
613 lines
20 KiB
C
|
/*-
|
||
|
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||
|
* redistributing this file, you may do so under either license.
|
||
|
*
|
||
|
* GPL LICENSE SUMMARY
|
||
|
*
|
||
|
* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or modify
|
||
|
* it under the terms of version 2 of the GNU General Public License as
|
||
|
* published by the Free Software Foundation.
|
||
|
*
|
||
|
* This program is distributed in the hope that it will be useful, but
|
||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
* General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with this program; if not, write to the Free Software
|
||
|
* Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||
|
* The full GNU General Public License is included in this distribution
|
||
|
* in the file called LICENSE.GPL.
|
||
|
*
|
||
|
* BSD LICENSE
|
||
|
*
|
||
|
* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
|
||
|
* All rights reserved.
|
||
|
*
|
||
|
* Redistribution and use in source and binary forms, with or without
|
||
|
* modification, are permitted provided that the following conditions
|
||
|
* are met:
|
||
|
*
|
||
|
* * Redistributions of source code must retain the above copyright
|
||
|
* notice, this list of conditions and the following disclaimer.
|
||
|
* * Redistributions in binary form must reproduce the above copyright
|
||
|
* notice, this list of conditions and the following disclaimer in
|
||
|
* the documentation and/or other materials provided with the
|
||
|
* distribution.
|
||
|
*
|
||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||
|
*/
|
||
|
|
||
|
#include <sys/cdefs.h>
|
||
|
__FBSDID("$FreeBSD$");
|
||
|
|
||
|
/**
|
||
|
* @file
|
||
|
*
|
||
|
* @brief This file contains all of the entrance and exit methods for each
|
||
|
* of the domain states defined by the SCI_BASE_DOMAIN state
|
||
|
* machine.
|
||
|
*/
|
||
|
|
||
|
#include <dev/isci/scil/intel_sas.h>
|
||
|
#include <dev/isci/scil/scic_port.h>
|
||
|
|
||
|
#include <dev/isci/scil/scif_sas_logger.h>
|
||
|
#include <dev/isci/scil/scif_sas_domain.h>
|
||
|
#include <dev/isci/scil/scif_sas_controller.h>
|
||
|
#include <dev/isci/scil/scic_controller.h>
|
||
|
|
||
|
//******************************************************************************
|
||
|
//* P R O T E C T E D M E T H O D S
|
||
|
//******************************************************************************
|
||
|
|
||
|
/**
|
||
|
* @brief This method will attempt to transition to the stopped state.
|
||
|
* The transition will only occur if the criteria for transition is
|
||
|
* met (i.e. all IOs are complete and all devices are stopped).
|
||
|
*
|
||
|
* @param[in] fw_domain This parameter specifies the domain in which to
|
||
|
* to attempt to perform the transition.
|
||
|
*
|
||
|
* @return none
|
||
|
*/
|
||
|
void scif_sas_domain_transition_to_stopped_state(
|
||
|
SCIF_SAS_DOMAIN_T * fw_domain
|
||
|
)
|
||
|
{
|
||
|
SCIF_LOG_TRACE((
|
||
|
sci_base_object_get_logger(fw_domain),
|
||
|
SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
|
||
|
"scif_sas_domain_transition_to_stopped_state(0x%x) enter\n",
|
||
|
fw_domain
|
||
|
));
|
||
|
|
||
|
// If IOs are quiesced, and all remote devices are stopped,
|
||
|
// then transition directly to the STOPPED state.
|
||
|
if ( (fw_domain->request_list.element_count == 0)
|
||
|
&& (fw_domain->device_start_count == 0) )
|
||
|
{
|
||
|
SCIF_LOG_INFO((
|
||
|
sci_base_object_get_logger(fw_domain),
|
||
|
SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
|
||
|
"Domain:0x%x immediate transition to STOPPED\n",
|
||
|
fw_domain
|
||
|
));
|
||
|
|
||
|
sci_base_state_machine_change_state(
|
||
|
&fw_domain->parent.state_machine, SCI_BASE_DOMAIN_STATE_STOPPED
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* @brief This method is called upon entrance to all states where the
|
||
|
* previous state may have been the DISCOVERING state.
|
||
|
* We issue the scif_cb_domain_discovery_complete() notification
|
||
|
* from this method, assuming pre-requisites are met, as opposed
|
||
|
* to in the exit handler of the DISCOVERING state, so that the
|
||
|
* appropriate state handlers are in place should the user decide
|
||
|
* to call scif_domain_discover() again.
|
||
|
*
|
||
|
* @param[in] fw_domain This parameter specifies the domain for which
|
||
|
* the state transition has occurred.
|
||
|
*
|
||
|
* @return none
|
||
|
*/
|
||
|
static
|
||
|
void scif_sas_domain_transition_from_discovering_state(
|
||
|
SCIF_SAS_DOMAIN_T * fw_domain
|
||
|
)
|
||
|
{
|
||
|
SCIF_LOG_TRACE((
|
||
|
sci_base_object_get_logger(fw_domain),
|
||
|
SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
|
||
|
"scif_sas_domain_transition_from_discovering_state(0x%x) enter\n",
|
||
|
fw_domain
|
||
|
));
|
||
|
|
||
|
if (fw_domain->parent.state_machine.previous_state_id
|
||
|
== SCI_BASE_DOMAIN_STATE_DISCOVERING)
|
||
|
{
|
||
|
scif_sas_controller_restore_interrupt_coalescence(fw_domain->controller);
|
||
|
|
||
|
scif_cb_timer_stop(fw_domain->controller, fw_domain->operation.timer);
|
||
|
|
||
|
scif_cb_domain_discovery_complete(
|
||
|
fw_domain->controller, fw_domain, fw_domain->operation.status
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* @brief This method is called upon entrance to DISCOVERING state. Right before
|
||
|
* transitioning to DISCOVERING state, we temporarily change interrupt
|
||
|
* coalescence scheme.
|
||
|
*
|
||
|
* @param[in] fw_domain This parameter specifies the domain for which
|
||
|
* the state transition has occurred.
|
||
|
*
|
||
|
* @return none
|
||
|
*/
|
||
|
void scif_sas_domain_transition_to_discovering_state(
|
||
|
SCIF_SAS_DOMAIN_T * fw_domain
|
||
|
)
|
||
|
{
|
||
|
scif_sas_controller_save_interrupt_coalescence(fw_domain->controller);
|
||
|
|
||
|
sci_base_state_machine_change_state(
|
||
|
&fw_domain->parent.state_machine, SCI_BASE_DOMAIN_STATE_DISCOVERING
|
||
|
);
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* @brief This method implements the actions taken when entering the
|
||
|
* INITIAL state.
|
||
|
*
|
||
|
* @param[in] object This parameter specifies the base object for which
|
||
|
* the state transition is occurring. This is cast into a
|
||
|
* SCIF_SAS_DOMAIN object in the method implementation.
|
||
|
*
|
||
|
* @return none
|
||
|
*/
|
||
|
static
|
||
|
void scif_sas_domain_initial_state_enter(
|
||
|
SCI_BASE_OBJECT_T * object
|
||
|
)
|
||
|
{
|
||
|
SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T *)object;
|
||
|
|
||
|
SET_STATE_HANDLER(
|
||
|
fw_domain,
|
||
|
scif_sas_domain_state_handler_table,
|
||
|
SCI_BASE_DOMAIN_STATE_INITIAL
|
||
|
);
|
||
|
|
||
|
SCIF_LOG_TRACE((
|
||
|
sci_base_object_get_logger(fw_domain),
|
||
|
SCIF_LOG_OBJECT_DOMAIN,
|
||
|
"scif_sas_domain_initial_state_enter(0x%x) enter\n",
|
||
|
fw_domain
|
||
|
));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief This method implements the actions taken when entering the
|
||
|
* STARTING state. This includes setting the state handlers and
|
||
|
* checking to see if the core port has already become READY.
|
||
|
*
|
||
|
* @param[in] object This parameter specifies the base object for which
|
||
|
* the state transition is occurring. This is cast into a
|
||
|
* SCIF_SAS_DOMAIN object in the method implementation.
|
||
|
*
|
||
|
* @return none
|
||
|
*/
|
||
|
static
|
||
|
void scif_sas_domain_starting_state_enter(
|
||
|
SCI_BASE_OBJECT_T * object
|
||
|
)
|
||
|
{
|
||
|
SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T *)object;
|
||
|
|
||
|
SET_STATE_HANDLER(
|
||
|
fw_domain,
|
||
|
scif_sas_domain_state_handler_table,
|
||
|
SCI_BASE_DOMAIN_STATE_STARTING
|
||
|
);
|
||
|
|
||
|
SCIF_LOG_TRACE((
|
||
|
sci_base_object_get_logger(fw_domain),
|
||
|
SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
|
||
|
"scif_sas_domain_starting_state_enter(0x%x) enter\n",
|
||
|
fw_domain
|
||
|
));
|
||
|
|
||
|
scif_sas_domain_transition_from_discovering_state(fw_domain);
|
||
|
|
||
|
// If we entered the STARTING state and the core port is actually ready,
|
||
|
// then directly transition into the READY state. This can occur
|
||
|
// if we were in the middle of discovery when the port failed
|
||
|
// (causing a transition to STOPPING), then before reaching STOPPED
|
||
|
// the port becomes ready again.
|
||
|
if (fw_domain->is_port_ready == TRUE)
|
||
|
{
|
||
|
sci_base_state_machine_change_state(
|
||
|
&fw_domain->parent.state_machine, SCI_BASE_DOMAIN_STATE_READY
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief This method implements the actions taken when entering the
|
||
|
* READY state. If the transition into this state came from:
|
||
|
* - the STARTING state, then alert the user via a
|
||
|
* scif_cb_domain_change_notification() that the domain
|
||
|
* has at least 1 device ready for discovery.
|
||
|
* - the DISCOVERING state, then alert the user that
|
||
|
* discovery is complete via the
|
||
|
* scif_cb_domain_discovery_complete() notification that
|
||
|
* discovery is finished.
|
||
|
*
|
||
|
* @param[in] object This parameter specifies the base object for which
|
||
|
* the state transition is occurring. This is cast into a
|
||
|
* SCIF_SAS_DOMAIN object in the method implementation.
|
||
|
*
|
||
|
* @return none
|
||
|
*/
|
||
|
static
|
||
|
void scif_sas_domain_ready_state_enter(
|
||
|
SCI_BASE_OBJECT_T * object
|
||
|
)
|
||
|
{
|
||
|
SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T *)object;
|
||
|
|
||
|
SET_STATE_HANDLER(
|
||
|
fw_domain,
|
||
|
scif_sas_domain_state_handler_table,
|
||
|
SCI_BASE_DOMAIN_STATE_READY
|
||
|
);
|
||
|
|
||
|
SCIF_LOG_TRACE((
|
||
|
sci_base_object_get_logger(fw_domain),
|
||
|
SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
|
||
|
"scif_sas_domain_ready_state_enter(0x%x) enter\n",
|
||
|
fw_domain
|
||
|
));
|
||
|
|
||
|
if (fw_domain->parent.state_machine.previous_state_id
|
||
|
== SCI_BASE_DOMAIN_STATE_STARTING)
|
||
|
{
|
||
|
scif_cb_domain_ready(fw_domain->controller, fw_domain);
|
||
|
|
||
|
// Only indicate the domain change notification if the previous
|
||
|
// state was the STARTING state. We issue the notification here
|
||
|
// as opposed to exit of the STARTING state so that the appropriate
|
||
|
// state handlers are in place should the user call
|
||
|
// scif_domain_discover() from scif_cb_domain_change_notification()
|
||
|
scif_cb_domain_change_notification(fw_domain->controller, fw_domain);
|
||
|
}
|
||
|
else if (fw_domain->parent.state_machine.previous_state_id
|
||
|
== SCI_BASE_DOMAIN_STATE_DISCOVERING)
|
||
|
{
|
||
|
//if domain discovery timed out, we will NOT go back to discover even
|
||
|
//the broadcast change count is not zero. Instead we finish the discovery
|
||
|
//back to user. User can check the operation status and decide to
|
||
|
//retry discover all over again.
|
||
|
if (fw_domain->operation.status == SCI_FAILURE_TIMEOUT)
|
||
|
fw_domain->broadcast_change_count = 0;
|
||
|
|
||
|
// Check the broadcast change count to determine if discovery
|
||
|
// is indeed complete.
|
||
|
if (fw_domain->broadcast_change_count == 0)
|
||
|
{
|
||
|
scif_sas_domain_transition_from_discovering_state(fw_domain);
|
||
|
scif_cb_domain_ready(fw_domain->controller, fw_domain);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// The broadcast change count indicates something my have
|
||
|
// changed in the domain, while a discovery was ongoing.
|
||
|
// Thus, we should start discovery over again.
|
||
|
sci_base_state_machine_change_state(
|
||
|
&fw_domain->parent.state_machine, SCI_BASE_DOMAIN_STATE_DISCOVERING
|
||
|
);
|
||
|
}
|
||
|
|
||
|
// Enable the BCN because underneath hardware may disabled any further
|
||
|
// BCN.
|
||
|
scic_port_enable_broadcast_change_notification(fw_domain->core_object);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief This method implements the actions taken when exiting the
|
||
|
* READY state.
|
||
|
*
|
||
|
* @param[in] object This parameter specifies the base object for which
|
||
|
* the state transition is occurring. This is cast into a
|
||
|
* SCIF_SAS_DOMAIN object in the method implementation.
|
||
|
*
|
||
|
* @return none
|
||
|
*/
|
||
|
static
|
||
|
void scif_sas_domain_ready_state_exit(
|
||
|
SCI_BASE_OBJECT_T * object
|
||
|
)
|
||
|
{
|
||
|
SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T *)object;
|
||
|
|
||
|
SCIF_LOG_TRACE((
|
||
|
sci_base_object_get_logger(fw_domain),
|
||
|
SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
|
||
|
"scif_sas_domain_ready_state_exit(0x%x) enter\n",
|
||
|
fw_domain
|
||
|
));
|
||
|
|
||
|
scif_cb_domain_not_ready(fw_domain->controller, fw_domain);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief This method implements the actions taken when entering the
|
||
|
* STOPPING state.
|
||
|
*
|
||
|
* @param[in] object This parameter specifies the base object for which
|
||
|
* the state transition is occurring. This is cast into a
|
||
|
* SCIF_SAS_DOMAIN object in the method implementation.
|
||
|
*
|
||
|
* @return none
|
||
|
*/
|
||
|
static
|
||
|
void scif_sas_domain_stopping_state_enter(
|
||
|
SCI_BASE_OBJECT_T * object
|
||
|
)
|
||
|
{
|
||
|
SCIF_SAS_REMOTE_DEVICE_T * fw_device;
|
||
|
SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T *)object;
|
||
|
SCI_ABSTRACT_ELEMENT_T * element = sci_abstract_list_get_front(
|
||
|
&fw_domain->remote_device_list
|
||
|
);
|
||
|
|
||
|
SET_STATE_HANDLER(
|
||
|
fw_domain,
|
||
|
scif_sas_domain_state_handler_table,
|
||
|
SCI_BASE_DOMAIN_STATE_STOPPING
|
||
|
);
|
||
|
|
||
|
// This must be invoked after the state handlers are set to ensure
|
||
|
// appropriate processing will occur if the user attempts to perform
|
||
|
// additional actions.
|
||
|
scif_sas_domain_transition_from_discovering_state(fw_domain);
|
||
|
|
||
|
SCIF_LOG_TRACE((
|
||
|
sci_base_object_get_logger(fw_domain),
|
||
|
SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
|
||
|
"scif_sas_domain_stopping_state_enter(0x%x) enter\n",
|
||
|
fw_domain
|
||
|
));
|
||
|
|
||
|
scif_sas_high_priority_request_queue_purge_domain(
|
||
|
&fw_domain->controller->hprq, fw_domain
|
||
|
);
|
||
|
|
||
|
// Search the domain's list of devices and put them all in the STOPPING
|
||
|
// state.
|
||
|
while (element != NULL)
|
||
|
{
|
||
|
fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
|
||
|
sci_abstract_list_get_object(element);
|
||
|
|
||
|
// This method will stop the core device. The core will terminate
|
||
|
// all IO requests currently outstanding.
|
||
|
fw_device->state_handlers->parent.stop_handler(&fw_device->parent);
|
||
|
|
||
|
element = sci_abstract_list_get_next(element);
|
||
|
}
|
||
|
|
||
|
// Attempt to transition to the stopped state.
|
||
|
scif_sas_domain_transition_to_stopped_state(fw_domain);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief This method implements the actions taken when entering the
|
||
|
* STOPPED state.
|
||
|
*
|
||
|
* @param[in] object This parameter specifies the base object for which
|
||
|
* the state transition is occurring. This is cast into a
|
||
|
* SCIF_SAS_DOMAIN object in the method implementation.
|
||
|
*
|
||
|
* @return none
|
||
|
*/
|
||
|
static
|
||
|
void scif_sas_domain_stopped_state_enter(
|
||
|
SCI_BASE_OBJECT_T * object
|
||
|
)
|
||
|
{
|
||
|
SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T *)object;
|
||
|
|
||
|
SET_STATE_HANDLER(
|
||
|
fw_domain,
|
||
|
scif_sas_domain_state_handler_table,
|
||
|
SCI_BASE_DOMAIN_STATE_STOPPED
|
||
|
);
|
||
|
|
||
|
SCIF_LOG_TRACE((
|
||
|
sci_base_object_get_logger(fw_domain),
|
||
|
SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
|
||
|
"scif_sas_domain_stopped_state_enter(0x%x) enter\n",
|
||
|
fw_domain
|
||
|
));
|
||
|
|
||
|
// A hot unplug of the direct attached device has occurred. Thus,
|
||
|
// notify the user. Note, if the controller is not in READY state,
|
||
|
// mostly likely the controller is in STOPPING or STOPPED state,
|
||
|
// meaning the controller is in the process of stopping, we should
|
||
|
// not call back to user in the middle of controller stopping.
|
||
|
if(fw_domain->controller->parent.state_machine.current_state_id
|
||
|
== SCI_BASE_CONTROLLER_STATE_READY)
|
||
|
scif_cb_domain_change_notification(fw_domain->controller, fw_domain);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief This method implements the actions taken when entering the
|
||
|
* DISCOVERING state. This includes determining from which
|
||
|
* state we entered. If we entered from stopping that some sort
|
||
|
* of hot-remove of the port occurred. In the hot-remove case
|
||
|
* all devices should be in the STOPPED state already and, as
|
||
|
* a result, are removed from the domain with a notification sent
|
||
|
* to the framework user.
|
||
|
*
|
||
|
* @note This method currently only handles hot-insert/hot-remove of
|
||
|
* direct attached SSP devices.
|
||
|
*
|
||
|
* @param[in] object This parameter specifies the base object for which
|
||
|
* the state transition is occurring. This is cast into a
|
||
|
* SCIF_SAS_DOMAIN object in the method implementation.
|
||
|
*
|
||
|
* @return none
|
||
|
*/
|
||
|
static
|
||
|
void scif_sas_domain_discovering_state_enter(
|
||
|
SCI_BASE_OBJECT_T * object
|
||
|
)
|
||
|
{
|
||
|
SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T *)object;
|
||
|
|
||
|
SET_STATE_HANDLER(
|
||
|
fw_domain,
|
||
|
scif_sas_domain_state_handler_table,
|
||
|
SCI_BASE_DOMAIN_STATE_DISCOVERING
|
||
|
);
|
||
|
|
||
|
SCIF_LOG_TRACE((
|
||
|
sci_base_object_get_logger(fw_domain),
|
||
|
SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
|
||
|
"scif_sas_domain_discovering_state_enter(0x%x) enter\n",
|
||
|
fw_domain
|
||
|
));
|
||
|
|
||
|
fw_domain->broadcast_change_count = 0;
|
||
|
|
||
|
// Did the domain just go through a port not ready action? If it did,
|
||
|
// then we will be entering from the STOPPED state.
|
||
|
if (fw_domain->parent.state_machine.previous_state_id
|
||
|
!= SCI_BASE_DOMAIN_STATE_STOPPED)
|
||
|
{
|
||
|
SCIF_SAS_REMOTE_DEVICE_T * remote_device;
|
||
|
SCIC_PORT_PROPERTIES_T properties;
|
||
|
|
||
|
scic_port_get_properties(fw_domain->core_object, &properties);
|
||
|
|
||
|
// If the device has not yet been added to the domain, then
|
||
|
// inform the user that the device is new.
|
||
|
remote_device = (SCIF_SAS_REMOTE_DEVICE_T *)
|
||
|
scif_domain_get_device_by_sas_address(
|
||
|
fw_domain, &properties.remote.sas_address
|
||
|
);
|
||
|
if (remote_device == SCI_INVALID_HANDLE)
|
||
|
{
|
||
|
// simply notify the user of the new DA device and be done
|
||
|
// with discovery.
|
||
|
scif_cb_domain_da_device_added(
|
||
|
fw_domain->controller,
|
||
|
fw_domain,
|
||
|
&properties.remote.sas_address,
|
||
|
&properties.remote.protocols
|
||
|
);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(properties.remote.protocols.u.bits.smp_target)
|
||
|
//kick off the smp discover process.
|
||
|
scif_sas_domain_start_smp_discover(fw_domain, remote_device);
|
||
|
}
|
||
|
}
|
||
|
else //entered from STOPPED state.
|
||
|
{
|
||
|
SCI_ABSTRACT_ELEMENT_T * current_element =
|
||
|
sci_abstract_list_get_front(&(fw_domain->remote_device_list) );
|
||
|
|
||
|
SCIF_SAS_REMOTE_DEVICE_T * fw_device;
|
||
|
|
||
|
while (current_element != NULL)
|
||
|
{
|
||
|
fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)
|
||
|
sci_abstract_list_get_object(current_element);
|
||
|
|
||
|
ASSERT(fw_device->parent.state_machine.current_state_id
|
||
|
== SCI_BASE_REMOTE_DEVICE_STATE_STOPPED);
|
||
|
|
||
|
current_element =
|
||
|
sci_abstract_list_get_next(current_element);
|
||
|
|
||
|
SCIF_LOG_INFO((
|
||
|
sci_base_object_get_logger(fw_domain),
|
||
|
SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
|
||
|
"Controller:0x%x Domain:0x%x Device:0x%x removed\n",
|
||
|
fw_domain->controller, fw_domain, fw_device
|
||
|
));
|
||
|
|
||
|
// Notify the framework user of the device removal.
|
||
|
scif_cb_domain_device_removed(
|
||
|
fw_domain->controller, fw_domain, fw_device
|
||
|
);
|
||
|
}
|
||
|
|
||
|
ASSERT(fw_domain->request_list.element_count == 0);
|
||
|
ASSERT(sci_abstract_list_size(&fw_domain->remote_device_list) == 0);
|
||
|
|
||
|
sci_base_state_machine_change_state(
|
||
|
&fw_domain->parent.state_machine, SCI_BASE_DOMAIN_STATE_STARTING
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
SCI_BASE_STATE_T scif_sas_domain_state_table[SCI_BASE_DOMAIN_MAX_STATES] =
|
||
|
{
|
||
|
{
|
||
|
SCI_BASE_DOMAIN_STATE_INITIAL,
|
||
|
scif_sas_domain_initial_state_enter,
|
||
|
NULL,
|
||
|
},
|
||
|
{
|
||
|
SCI_BASE_DOMAIN_STATE_STARTING,
|
||
|
scif_sas_domain_starting_state_enter,
|
||
|
NULL,
|
||
|
},
|
||
|
{
|
||
|
SCI_BASE_DOMAIN_STATE_READY,
|
||
|
scif_sas_domain_ready_state_enter,
|
||
|
scif_sas_domain_ready_state_exit,
|
||
|
},
|
||
|
{
|
||
|
SCI_BASE_DOMAIN_STATE_STOPPING,
|
||
|
scif_sas_domain_stopping_state_enter,
|
||
|
NULL,
|
||
|
},
|
||
|
{
|
||
|
SCI_BASE_DOMAIN_STATE_STOPPED,
|
||
|
scif_sas_domain_stopped_state_enter,
|
||
|
NULL,
|
||
|
},
|
||
|
{
|
||
|
SCI_BASE_DOMAIN_STATE_DISCOVERING,
|
||
|
scif_sas_domain_discovering_state_enter,
|
||
|
NULL,
|
||
|
}
|
||
|
};
|
||
|
|