#include <sys/cdefs.h>
#include <dev/isci/scil/intel_sas.h>
#include <dev/isci/scil/sci_fast_list.h>
#include <dev/isci/scil/scic_controller.h>
#include <dev/isci/scil/scic_port.h>
#include <dev/isci/scil/scic_remote_device.h>
#include <dev/isci/scil/scic_io_request.h>
#include <dev/isci/scil/scic_user_callback.h>
#include <dev/isci/scil/scif_user_callback.h>
#include <dev/isci/scil/sci_abstract_list.h>
#include <dev/isci/scil/sci_base_iterator.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/scif_sas_remote_device.h>
#include <dev/isci/scil/scif_sas_smp_remote_device.h>
#include <dev/isci/scil/sci_util.h>
static
void scif_sas_domain_operation_timeout_handler(
void * cookie
)
{
SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) cookie;
U32 state;
state = sci_base_state_machine_get_state(&fw_domain->parent.state_machine);
if (state == SCI_BASE_DOMAIN_STATE_DISCOVERING)
{
SCIF_LOG_WARNING((
sci_base_object_get_logger(fw_domain),
SCIF_LOG_OBJECT_DOMAIN,
"Domain:0x%x State:0x%x DISCOVER timeout!\n",
fw_domain, state
));
fw_domain->operation.status = SCI_FAILURE_TIMEOUT;
scif_sas_domain_cancel_smp_activities(fw_domain);
scif_sas_domain_continue_discover(fw_domain);
}
else
{
SCIF_LOG_ERROR((
sci_base_object_get_logger(fw_domain),
SCIF_LOG_OBJECT_DOMAIN,
"Domain:0x%x State:0x%x operation timeout in invalid state\n",
fw_domain, state
));
}
}
SCI_PORT_HANDLE_T scif_domain_get_scic_port_handle(
SCI_DOMAIN_HANDLE_T domain
)
{
SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) domain;
if ( (fw_domain == NULL) || (fw_domain->core_object == SCI_INVALID_HANDLE) )
return SCI_INVALID_HANDLE;
SCIF_LOG_WARNING((
sci_base_object_get_logger(fw_domain),
SCIF_LOG_OBJECT_DOMAIN,
"Domain:0x%x no associated core port found\n",
fw_domain
));
return fw_domain->core_object;
}
SCI_REMOTE_DEVICE_HANDLE_T scif_domain_get_device_by_sas_address(
SCI_DOMAIN_HANDLE_T domain,
SCI_SAS_ADDRESS_T * sas_address
)
{
SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) domain;
SCI_ABSTRACT_ELEMENT_T * element = sci_abstract_list_get_front(
&fw_domain->remote_device_list
);
SCIF_SAS_REMOTE_DEVICE_T * fw_device;
SCI_SAS_ADDRESS_T fw_device_address;
SCIF_LOG_TRACE((
sci_base_object_get_logger(domain),
SCIF_LOG_OBJECT_DOMAIN,
"scif_domain_get_device_by_sas_address(0x%x, 0x%x) enter\n",
domain, sas_address
));
while (element != NULL)
{
fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
sci_abstract_list_get_object(element);
scic_remote_device_get_sas_address(
fw_device->core_object, &fw_device_address
);
if ( (fw_device_address.low == sas_address->low)
&& (fw_device_address.high == sas_address->high) )
{
return fw_device;
}
element = sci_abstract_list_get_next(element);
}
return SCI_INVALID_HANDLE;
}
#if !defined(DISABLE_SCI_ITERATORS)
SCI_ITERATOR_HANDLE_T scif_domain_get_remote_device_iterator(
SCI_DOMAIN_HANDLE_T domain,
void * iterator_buffer
)
{
SCI_ITERATOR_HANDLE_T iterator = (SCI_ITERATOR_HANDLE_T *)iterator_buffer;
sci_base_iterator_construct(
iterator, &((SCIF_SAS_DOMAIN_T*) domain)->remote_device_list
);
return iterator;
}
#endif
SCI_STATUS scif_domain_discover(
SCI_DOMAIN_HANDLE_T domain,
U32 discover_timeout,
U32 device_timeout
)
{
SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) domain;
SCI_STATUS status = SCI_SUCCESS;
SCI_STATUS op_status = SCI_SUCCESS;
SCIF_LOG_TRACE((
sci_base_object_get_logger(domain),
SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"scif_domain_discover(0x%x, 0x%x, 0x%x) enter\n",
domain, discover_timeout, device_timeout
));
if ((device_timeout * sci_abstract_list_size(&fw_domain->remote_device_list))
> discover_timeout)
status = SCI_WARNING_TIMER_CONFLICT;
op_status = fw_domain->state_handlers->discover_handler(
&fw_domain->parent, discover_timeout, device_timeout
);
if ( (status == SCI_SUCCESS)
|| (status != SCI_SUCCESS && op_status != SCI_SUCCESS) )
{
status = op_status;
}
return status;
}
U32 scif_domain_get_suggested_discover_timeout(
SCI_DOMAIN_HANDLE_T domain
)
{
U32 suggested_timeout = SCIF_DOMAIN_DISCOVER_TIMEOUT;
return suggested_timeout;
}
void scic_cb_port_stop_complete(
SCI_CONTROLLER_HANDLE_T controller,
SCI_PORT_HANDLE_T port,
SCI_STATUS completion_status
)
{
SCIF_LOG_TRACE((
sci_base_object_get_logger((SCIF_SAS_DOMAIN_T*)sci_object_get_association(port)),
SCIF_LOG_OBJECT_DOMAIN,
"scic_cb_port_stop_complete(0x%x, 0x%x, 0x%x) enter\n",
controller, port, completion_status
));
}
void scic_cb_port_ready(
SCI_CONTROLLER_HANDLE_T controller,
SCI_PORT_HANDLE_T port
)
{
SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*)
sci_object_get_association(port);
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_domain),
SCIF_LOG_OBJECT_DOMAIN,
"scic_cb_port_ready(0x%x, 0x%x) enter\n",
controller, port
));
ASSERT(sci_object_get_association(controller) == fw_domain->controller);
fw_domain->is_port_ready = TRUE;
fw_domain->state_handlers->port_ready_handler(&fw_domain->parent);
}
void scic_cb_port_not_ready(
SCI_CONTROLLER_HANDLE_T controller,
SCI_PORT_HANDLE_T port,
U32 reason_code
)
{
SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*)
sci_object_get_association(port);
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_domain),
SCIF_LOG_OBJECT_DOMAIN,
"scic_cb_port_not_ready(0x%x, 0x%x) enter\n",
controller, port
));
ASSERT(sci_object_get_association(controller) == fw_domain->controller);
if (reason_code != SCIC_PORT_NOT_READY_RECONFIGURING)
{
fw_domain->is_port_ready = FALSE;
fw_domain->state_handlers->port_not_ready_handler(
&fw_domain->parent, reason_code);
}
}
void scic_cb_port_hard_reset_complete(
SCI_CONTROLLER_HANDLE_T controller,
SCI_PORT_HANDLE_T port,
SCI_STATUS completion_status
)
{
SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*)
sci_object_get_association(port);
SCIF_SAS_REMOTE_DEVICE_T * fw_device;
SCI_FAST_LIST_ELEMENT_T * element = fw_domain->request_list.list_head;
SCIF_SAS_TASK_REQUEST_T * task_request = NULL;
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_domain),
SCIF_LOG_OBJECT_DOMAIN,
"scic_cb_port_hard_reset_complete(0x%x, 0x%x, 0x%x) enter\n",
controller, port, completion_status
));
while (element != NULL)
{
task_request = (SCIF_SAS_TASK_REQUEST_T*) sci_fast_list_get_object(element);
element = sci_fast_list_get_next(element);
if (scif_sas_task_request_get_function(task_request)
== SCI_SAS_HARD_RESET)
{
fw_device = task_request->parent.device;
if (fw_device->domain == fw_domain)
{
scic_remote_device_reset_complete(fw_device->core_object);
scif_cb_task_request_complete(
sci_object_get_association(controller),
fw_device,
task_request,
(SCI_TASK_STATUS) completion_status
);
break;
}
}
}
}
void scic_cb_port_bc_change_primitive_recieved(
SCI_CONTROLLER_HANDLE_T controller,
SCI_PORT_HANDLE_T port,
SCI_PHY_HANDLE_T phy
)
{
SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*)
sci_object_get_association(port);
SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T *)
sci_object_get_association(controller);
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_domain),
SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"scic_cb_port_bc_change_primitive_recieved(0x%x, 0x%x, 0x%x) enter\n",
controller, port, phy
));
if (fw_domain->broadcast_change_count == 0)
{
scic_port_enable_broadcast_change_notification(fw_domain->core_object);
}
fw_domain->broadcast_change_count++;
if( ! scif_sas_domain_is_in_smp_activity(fw_domain) )
scif_cb_domain_change_notification(fw_controller, fw_domain);
}
void scic_cb_port_bc_ses_primitive_recieved(
SCI_CONTROLLER_HANDLE_T controller,
SCI_PORT_HANDLE_T port,
SCI_PHY_HANDLE_T phy
)
{
SCIF_LOG_TRACE((
sci_base_object_get_logger(sci_object_get_association(port)),
SCIF_LOG_OBJECT_DOMAIN,
"scic_cb_port_bc_ses_primitive_received(0x%x, 0x%x, 0x%x) enter\n",
controller, port, phy
));
}
void scic_cb_port_bc_expander_primitive_recieved(
SCI_CONTROLLER_HANDLE_T controller,
SCI_PORT_HANDLE_T port,
SCI_PHY_HANDLE_T phy
)
{
SCIF_LOG_TRACE((
sci_base_object_get_logger(sci_object_get_association(port)),
SCIF_LOG_OBJECT_DOMAIN,
"scic_cb_port_bc_expander_primitive_received(0x%x, 0x%x, 0x%x) enter\n",
controller, port, phy
));
}
void scic_cb_port_bc_aen_primitive_recieved(
SCI_CONTROLLER_HANDLE_T controller,
SCI_PORT_HANDLE_T port,
SCI_PHY_HANDLE_T phy
)
{
SCIF_LOG_TRACE((
sci_base_object_get_logger(sci_object_get_association(port)),
SCIF_LOG_OBJECT_DOMAIN,
"scic_cb_port_bc_aen_primitive_received(0x%x, 0x%x, 0x%x) enter\n",
controller, port, phy
));
}
void scic_cb_port_link_up(
SCI_CONTROLLER_HANDLE_T controller,
SCI_PORT_HANDLE_T port,
SCI_PHY_HANDLE_T phy
)
{
SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*)
sci_object_get_association(port);
SCIF_LOG_TRACE((
sci_base_object_get_logger(sci_object_get_association(port)),
SCIF_LOG_OBJECT_DOMAIN,
"scic_cb_port_link_up(0x%x, 0x%x, 0x%x) enter\n",
controller, port, phy
));
scif_sas_domain_update_device_port_width(fw_domain, port);
}
void scic_cb_port_link_down(
SCI_CONTROLLER_HANDLE_T controller,
SCI_PORT_HANDLE_T port,
SCI_PHY_HANDLE_T phy
)
{
SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*)
sci_object_get_association(port);
SCIF_LOG_TRACE((
sci_base_object_get_logger(sci_object_get_association(port)),
SCIF_LOG_OBJECT_DOMAIN,
"scic_cb_port_link_down(0x%x, 0x%x, 0x%x) enter\n",
controller, port, phy
));
scif_sas_domain_update_device_port_width(fw_domain, port);
}
void scif_sas_domain_construct(
SCIF_SAS_DOMAIN_T * fw_domain,
U8 domain_id,
SCIF_SAS_CONTROLLER_T * fw_controller
)
{
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_controller),
SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_INITIALIZATION,
"scif_sas_domain_construct(0x%x, 0x%x, 0x%x) enter\n",
fw_domain, domain_id, fw_controller
));
sci_base_domain_construct(
&fw_domain->parent,
sci_base_object_get_logger(fw_controller),
scif_sas_domain_state_table
);
scif_sas_domain_initialize_state_logging(fw_domain);
sci_abstract_list_construct(
&fw_domain->remote_device_list, &fw_controller->free_remote_device_pool
);
scic_controller_get_port_handle(
fw_controller->core_object, domain_id, &fw_domain->core_object
);
sci_object_set_association(
(SCI_OBJECT_HANDLE_T) fw_domain->core_object, fw_domain
);
sci_fast_list_init(&fw_domain->request_list);
fw_domain->operation.timer = NULL;
fw_domain->is_port_ready = FALSE;
fw_domain->device_start_count = 0;
fw_domain->controller = fw_controller;
fw_domain->operation.status = SCI_SUCCESS;
fw_domain->is_config_route_table_needed = FALSE;
}
void scif_sas_domain_terminate_requests(
SCIF_SAS_DOMAIN_T * fw_domain,
SCIF_SAS_REMOTE_DEVICE_T * fw_device,
SCIF_SAS_REQUEST_T * fw_request,
SCIF_SAS_TASK_REQUEST_T * fw_requestor
)
{
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_domain),
SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_TASK_MANAGEMENT,
"scif_sas_domain_terminate_requests(0x%x, 0x%x, 0x%x, 0x%x) enter\n",
fw_domain, fw_device, fw_request, fw_requestor
));
if (fw_request != NULL)
{
fw_request->terminate_requestor = fw_requestor;
fw_request->state_handlers->abort_handler(&fw_request->parent);
}
else
{
SCI_FAST_LIST_ELEMENT_T * element = fw_domain->request_list.list_head;
SCIF_SAS_REQUEST_T * request = NULL;
while (element != NULL)
{
request = (SCIF_SAS_REQUEST_T*) sci_fast_list_get_object(element);
element = sci_fast_list_get_next(element);
if (
(fw_device == NULL)
|| (
(request->device == fw_device)
&& (fw_requestor != (SCIF_SAS_TASK_REQUEST_T*) request)
)
)
{
if (
(request->is_waiting_for_abort_task_set == FALSE) ||
(request->terminate_requestor == NULL)
)
{
request->terminate_requestor = fw_requestor;
request->state_handlers->abort_handler(&request->parent);
}
}
}
}
}
SCIF_SAS_REQUEST_T * scif_sas_domain_get_request_by_io_tag(
SCIF_SAS_DOMAIN_T * fw_domain,
U16 io_tag
)
{
SCI_FAST_LIST_ELEMENT_T * element = fw_domain->request_list.list_head;
SCIF_SAS_IO_REQUEST_T * io_request = NULL;
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_domain),
SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_TASK_MANAGEMENT,
"scif_sas_domain_get_request_by_io_tag(0x%x, 0x%x) enter\n",
fw_domain, io_tag
));
while (element != NULL)
{
io_request = (SCIF_SAS_IO_REQUEST_T*) sci_fast_list_get_object(element);
if (scic_io_request_get_io_tag(io_request->parent.core_object) == io_tag)
return &io_request->parent;
element = sci_fast_list_get_next(element);
}
return NULL;
}
void scif_sas_domain_initialize(
SCIF_SAS_DOMAIN_T * fw_domain
)
{
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_domain),
SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_INITIALIZATION,
"scif_sas_domain_initialize(0x%x) enter\n",
fw_domain
));
if (fw_domain->operation.timer == 0)
{
fw_domain->operation.timer = scif_cb_timer_create(
fw_domain->controller,
scif_sas_domain_operation_timeout_handler,
fw_domain
);
}
}
void scif_sas_domain_remote_device_start_complete(
SCIF_SAS_DOMAIN_T * fw_domain,
SCIF_SAS_REMOTE_DEVICE_T * fw_device
)
{
SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols;
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_domain),
SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"scif_sas_domain_remote_device_start_complete(0x%x, 0x%x) enter\n",
fw_domain, fw_device
));
ASSERT(fw_domain->parent.state_machine.current_state_id
== SCI_BASE_DOMAIN_STATE_DISCOVERING);
scic_remote_device_get_protocols(fw_device->core_object, &dev_protocols);
fw_domain->device_start_in_progress_count--;
if ( dev_protocols.u.bits.attached_smp_target )
{
if ( fw_device->containing_device == NULL )
scif_sas_smp_remote_device_start_discover(fw_device);
else
fw_device->protocol_device.smp_device.scheduled_activity =
SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER;
}
else
{
fw_domain->state_handlers->device_start_complete_handler(
&fw_domain->parent, &fw_device->parent
);
}
}
BOOL scif_sas_domain_is_in_smp_activity(
SCIF_SAS_DOMAIN_T * fw_domain
)
{
SCI_ABSTRACT_ELEMENT_T * current_element =
sci_abstract_list_get_front(&fw_domain->remote_device_list);
SCIF_SAS_REMOTE_DEVICE_T * current_device;
while ( current_element != NULL )
{
SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols;
current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
sci_abstract_list_get_object(current_element);
scic_remote_device_get_protocols(current_device->core_object,
&dev_protocols
);
if (dev_protocols.u.bits.attached_smp_target &&
scif_sas_smp_remote_device_is_in_activity(current_device))
return TRUE;
current_element =
sci_abstract_list_get_next(current_element);
}
return FALSE;
}
SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_get_device_by_containing_device(
SCIF_SAS_DOMAIN_T * fw_domain,
SCIF_SAS_REMOTE_DEVICE_T * containing_device,
U8 expander_phy_id
)
{
SCIF_SAS_REMOTE_DEVICE_T * fw_device;
SCI_ABSTRACT_ELEMENT_T * element = sci_abstract_list_get_front(
&fw_domain->remote_device_list
);
ASSERT(containing_device != NULL);
while (element != NULL)
{
fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
sci_abstract_list_get_object(element);
if (
(fw_device->containing_device == containing_device)
&& (fw_device->expander_phy_identifier == expander_phy_id)
)
{
return fw_device;
}
element = sci_abstract_list_get_next(element);
}
return SCI_INVALID_HANDLE;
}
SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_find_device_in_spinup_hold(
SCIF_SAS_DOMAIN_T * fw_domain
)
{
SCI_ABSTRACT_ELEMENT_T * current_element;
SCIF_SAS_REMOTE_DEVICE_T * current_device;
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_domain),
SCIF_LOG_OBJECT_DOMAIN,
"scif_sas_domain_find_device_in_spinup_hold(0x%x) enter\n",
fw_domain
));
current_element = sci_abstract_list_get_front(&fw_domain->remote_device_list);
while (current_element != NULL )
{
current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
sci_abstract_list_get_object(current_element);
current_element = sci_abstract_list_get_next(current_element);
if ( sci_base_state_machine_get_state(¤t_device->parent.state_machine) ==
SCI_BASE_REMOTE_DEVICE_STATE_STOPPED
&& scic_remote_device_get_connection_rate(current_device->core_object) ==
SCI_SATA_SPINUP_HOLD )
{
return current_device;
}
}
return NULL;
}
SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_find_device_has_scheduled_activity(
SCIF_SAS_DOMAIN_T * fw_domain,
U8 smp_activity
)
{
SCI_ABSTRACT_ELEMENT_T * current_element =
sci_abstract_list_get_front(&fw_domain->remote_device_list);
SCIF_SAS_REMOTE_DEVICE_T * current_device;
SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols;
while ( current_element != NULL )
{
current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
sci_abstract_list_get_object(current_element);
scic_remote_device_get_protocols(current_device->core_object,
&dev_protocols);
current_element =
sci_abstract_list_get_next(current_element);
if ( dev_protocols.u.bits.attached_smp_target
&& current_device->protocol_device.smp_device.scheduled_activity ==
smp_activity)
{
return current_device;
}
}
return NULL;
}
void scif_sas_domain_start_smp_activity(
SCIF_SAS_DOMAIN_T * fw_domain
)
{
SCIF_SAS_REMOTE_DEVICE_T * device_has_scheduled_activity = NULL;
device_has_scheduled_activity =
scif_sas_domain_find_device_has_scheduled_activity(
fw_domain,
SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE
);
if (device_has_scheduled_activity != NULL)
{
scif_sas_smp_remote_device_configure_route_table(device_has_scheduled_activity);
device_has_scheduled_activity->protocol_device.smp_device.scheduled_activity =
SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE;
return;
}
device_has_scheduled_activity =
scif_sas_domain_find_device_has_scheduled_activity(
fw_domain,
SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER
);
if (device_has_scheduled_activity != NULL)
scif_sas_smp_remote_device_start_discover(device_has_scheduled_activity);
}
void scif_sas_domain_start_smp_discover(
SCIF_SAS_DOMAIN_T * fw_domain,
SCIF_SAS_REMOTE_DEVICE_T * top_expander
)
{
SCI_ABSTRACT_ELEMENT_T * current_element =
sci_abstract_list_get_front(&fw_domain->remote_device_list);
SCIF_SAS_REMOTE_DEVICE_T * current_device;
while ( current_element != NULL )
{
current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
sci_abstract_list_get_object(current_element);
current_device->is_currently_discovered = FALSE;
if (current_device->containing_device != NULL)
current_device->device_port_width = 1;
current_element = sci_abstract_list_get_next(current_element);
}
top_expander->is_currently_discovered = TRUE;
scif_sas_smp_remote_device_start_discover(top_expander);
}
void scif_sas_domain_continue_discover(
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_continue_discover(0x%x) enter\n",
fw_domain
));
if ( fw_domain->device_start_in_progress_count == 0
&& !scif_sas_domain_is_in_smp_activity(fw_domain) )
{
scif_sas_domain_start_smp_activity(fw_domain);
if ( ! scif_sas_domain_is_in_smp_activity(fw_domain)
&& scif_sas_domain_get_smp_request_count(fw_domain) == 0)
{
scif_sas_domain_finish_discover(fw_domain);
}
}
}
void scif_sas_domain_finish_discover(
SCIF_SAS_DOMAIN_T * fw_domain
)
{
SCIF_SAS_REMOTE_DEVICE_T * current_device = NULL;
SCI_ABSTRACT_ELEMENT_T * current_element = NULL;
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_domain),
SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"scif_sas_domain_finish_discover(0x%x) enter\n",
fw_domain
));
current_element = sci_abstract_list_get_front(&fw_domain->remote_device_list);
while (current_element != NULL )
{
current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
sci_abstract_list_get_object(current_element);
current_element = sci_abstract_list_get_next(current_element);
if ( current_device->is_currently_discovered == FALSE )
{
scif_cb_domain_device_removed(
fw_domain->controller, fw_domain, current_device
);
}
}
sci_base_state_machine_change_state(
&fw_domain->parent.state_machine, SCI_BASE_DOMAIN_STATE_READY
);
}
void scif_sas_domain_remove_expander_device(
SCIF_SAS_DOMAIN_T * fw_domain,
SCIF_SAS_REMOTE_DEVICE_T * fw_device
)
{
SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device =
&fw_device->protocol_device.smp_device;
SCI_FAST_LIST_ELEMENT_T * element = smp_remote_device->smp_phy_list.list_head;
SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL;
SCIF_SAS_REMOTE_DEVICE_T * current_device = NULL;
while (element != NULL)
{
curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element);
element = sci_fast_list_get_next(element);
if ( curr_smp_phy->attached_device_type != SMP_NO_DEVICE_ATTACHED
&& curr_smp_phy->u.end_device != NULL )
{
if (curr_smp_phy->attached_device_type == SMP_END_DEVICE_ONLY)
current_device = curr_smp_phy->u.end_device;
else
current_device = curr_smp_phy->u.attached_phy->owning_device;
scif_cb_domain_device_removed(fw_domain->controller, fw_domain, current_device);
}
}
scif_cb_domain_device_removed(fw_domain->controller, fw_domain, fw_device);
}
void scif_sas_domain_cancel_smp_activities(
SCIF_SAS_DOMAIN_T * fw_domain
)
{
SCI_ABSTRACT_ELEMENT_T * current_element =
sci_abstract_list_get_front(&fw_domain->remote_device_list);
SCIF_SAS_REMOTE_DEVICE_T * current_device;
scif_sas_high_priority_request_queue_purge_domain(
&fw_domain->controller->hprq, fw_domain
);
while ( current_element != NULL )
{
SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols;
current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
sci_abstract_list_get_object(current_element);
scic_remote_device_get_protocols(current_device->core_object,
&dev_protocols
);
if (dev_protocols.u.bits.attached_smp_target)
{
scif_sas_smp_remote_device_cancel_smp_activity(current_device);
}
current_element =
sci_abstract_list_get_next(current_element);
}
}
U8 scif_sas_domain_get_smp_request_count(
SCIF_SAS_DOMAIN_T * fw_domain
)
{
SCI_FAST_LIST_ELEMENT_T * element = fw_domain->request_list.list_head;
SCIF_SAS_REQUEST_T * request = NULL;
U8 count = 0;
SCIC_TRANSPORT_PROTOCOL protocol;
while (element != NULL)
{
request = (SCIF_SAS_REQUEST_T*) sci_fast_list_get_object(element);
element = sci_fast_list_get_next(element);
protocol = scic_io_request_get_protocol(request->core_object);
if ( protocol == SCIC_SMP_PROTOCOL)
count++;
}
return count;
}
void scif_sas_domain_start_clear_affiliation(
SCIF_SAS_DOMAIN_T * fw_domain
)
{
scif_sas_domain_schedule_clear_affiliation(fw_domain);
scif_sas_domain_continue_clear_affiliation(fw_domain);
}
void scif_sas_domain_schedule_clear_affiliation(
SCIF_SAS_DOMAIN_T * fw_domain
)
{
SCI_ABSTRACT_ELEMENT_T * current_element =
sci_abstract_list_get_front(&fw_domain->remote_device_list);
SCIF_SAS_REMOTE_DEVICE_T * current_device;
SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols;
while ( current_element != NULL )
{
current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
sci_abstract_list_get_object(current_element);
scic_remote_device_get_protocols(current_device->core_object,
&dev_protocols);
current_element =
sci_abstract_list_get_next(current_element);
if ( dev_protocols.u.bits.attached_smp_target )
{
current_device->protocol_device.smp_device.scheduled_activity =
SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAR_AFFILIATION;
}
}
}
void scif_sas_domain_continue_clear_affiliation(
SCIF_SAS_DOMAIN_T * fw_domain
)
{
SCIF_SAS_REMOTE_DEVICE_T * smp_device =
scif_sas_domain_find_device_has_scheduled_activity(
fw_domain,
SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAR_AFFILIATION
);
if (smp_device != NULL)
scif_sas_smp_remote_device_start_clear_affiliation(smp_device);
else
{
SCIF_SAS_CONTROLLER_T * fw_controller = fw_domain->controller;
fw_controller->current_domain_to_clear_affiliation++;
scif_sas_controller_clear_affiliation(fw_domain->controller);
}
}
void scif_sas_domain_release_resource(
SCIF_SAS_CONTROLLER_T * fw_controller,
SCIF_SAS_DOMAIN_T * fw_domain
)
{
if (fw_domain->operation.timer != NULL)
{
scif_cb_timer_destroy(fw_controller, fw_domain->operation.timer);
fw_domain->operation.timer = NULL;
}
}
SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_find_next_ea_target_reset(
SCIF_SAS_DOMAIN_T * fw_domain
)
{
SCI_ABSTRACT_ELEMENT_T * current_element;
SCIF_SAS_REMOTE_DEVICE_T * current_device;
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_domain),
SCIF_LOG_OBJECT_DOMAIN,
"scif_sas_domain_find_next_ea_target_reset(0x%x) enter\n",
fw_domain
));
current_element = sci_abstract_list_get_front(&fw_domain->remote_device_list);
while (current_element != NULL )
{
current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
sci_abstract_list_get_object(current_element);
current_element = sci_abstract_list_get_next(current_element);
if ( current_device->ea_target_reset_request_scheduled != NULL )
{
return current_device;
}
}
return NULL;
}
#if !defined(DISABLE_WIDE_PORTED_TARGETS)
void scif_sas_domain_update_device_port_width(
SCIF_SAS_DOMAIN_T * fw_domain,
SCI_PORT_HANDLE_T port
)
{
SCIF_SAS_REMOTE_DEVICE_T * fw_device;
SCIC_PORT_PROPERTIES_T properties;
U8 new_port_width = 0;
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_domain),
SCIF_LOG_OBJECT_DOMAIN,
"scif_sas_domain_update_device_port_width(0x%x, 0x%x) enter\n",
fw_domain, port
));
scic_port_get_properties(port, &properties);
fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)
scif_domain_get_device_by_sas_address(
fw_domain, &properties.remote.sas_address
);
if (fw_device != SCI_INVALID_HANDLE)
{
SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols;
scic_remote_device_get_protocols(fw_device->core_object, &dev_protocols);
if (dev_protocols.u.bits.attached_ssp_target)
{
SCI_GET_BITS_SET_COUNT(properties.phy_mask, new_port_width);
scif_sas_remote_device_update_port_width(fw_device, new_port_width);
}
}
}
#endif
#ifdef SCI_LOGGING
void scif_sas_domain_initialize_state_logging(
SCIF_SAS_DOMAIN_T *fw_domain
)
{
sci_base_state_machine_logger_initialize(
&fw_domain->parent.state_machine_logger,
&fw_domain->parent.state_machine,
&fw_domain->parent.parent,
scif_cb_logger_log_states,
"SCIF_SAS_DOMAIN_T", "base state machine",
SCIF_LOG_OBJECT_DOMAIN
);
}
void scif_sas_domain_deinitialize_state_logging(
SCIF_SAS_DOMAIN_T *fw_domain
)
{
sci_base_state_machine_logger_deinitialize(
&fw_domain->parent.state_machine_logger,
&fw_domain->parent.state_machine
);
}
#endif