#include <sys/cdefs.h>
#include <dev/isci/scil/sci_controller.h>
#include <dev/isci/scil/scif_sas_controller.h>
#include <dev/isci/scil/scif_sas_remote_device.h>
#include <dev/isci/scil/scif_sas_logger.h>
#include <dev/isci/scil/scif_sas_smp_remote_device.h>
#include <dev/isci/scil/scif_sas_smp_io_request.h>
#include <dev/isci/scil/intel_sas.h>
#include <dev/isci/scil/scic_io_request.h>
#include <dev/isci/scil/scic_remote_device.h>
#include <dev/isci/scil/scif_sas_smp_phy.h>
void scif_sas_smp_remote_device_clear(
SCIF_SAS_REMOTE_DEVICE_T * fw_device
)
{
fw_device->protocol_device.smp_device.current_activity =
SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE;
fw_device->protocol_device.smp_device.current_smp_request =
NOT_IN_SMP_ACTIVITY;
fw_device->protocol_device.smp_device.current_activity_phy_index = 0;
fw_device->protocol_device.smp_device.curr_config_route_index = 0;
fw_device->protocol_device.smp_device.config_route_smp_phy_anchor = NULL;
fw_device->protocol_device.smp_device.is_route_table_cleaned = FALSE;
fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy = NULL;
fw_device->protocol_device.smp_device.scheduled_activity =
SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE;
fw_device->protocol_device.smp_device.io_retry_count = 0;
fw_device->protocol_device.smp_device.curr_clear_affiliation_phy = NULL;
if (fw_device->protocol_device.smp_device.smp_activity_timer != NULL)
{
scif_cb_timer_stop(
fw_device->domain->controller,
fw_device->protocol_device.smp_device.smp_activity_timer
);
scif_cb_timer_destroy(
fw_device->domain->controller,
fw_device->protocol_device.smp_device.smp_activity_timer
);
fw_device->protocol_device.smp_device.smp_activity_timer = NULL;
}
}
void scif_sas_smp_remote_device_construct(
SCIF_SAS_REMOTE_DEVICE_T * fw_device
)
{
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE,
"scif_sas_smp_remote_device_construct(0x%x) enter\n",
fw_device
));
fw_device->protocol_device.smp_device.number_of_phys = 0;
fw_device->protocol_device.smp_device.expander_route_indexes = 0;
fw_device->protocol_device.smp_device.is_table_to_table_supported = FALSE;
fw_device->protocol_device.smp_device.is_externally_configurable = FALSE;
fw_device->protocol_device.smp_device.is_able_to_config_others = FALSE;
sci_fast_list_init(&fw_device->protocol_device.smp_device.smp_phy_list);
scif_sas_smp_remote_device_clear(fw_device);
}
SCI_STATUS scif_sas_smp_remote_device_decode_smp_response(
SCIF_SAS_REMOTE_DEVICE_T * fw_device,
SCIF_SAS_REQUEST_T * fw_request,
void * response_data,
SCI_IO_STATUS completion_status
)
{
SMP_RESPONSE_T * smp_response = (SMP_RESPONSE_T *)response_data;
SCI_STATUS status = SCI_FAILURE_UNSUPPORTED_INFORMATION_TYPE;
if (fw_device->protocol_device.smp_device.smp_activity_timer != NULL)
{
scif_cb_timer_destroy(
fw_device->domain->controller,
fw_device->protocol_device.smp_device.smp_activity_timer
);
fw_device->protocol_device.smp_device.smp_activity_timer = NULL;
}
if (completion_status == SCI_IO_FAILURE_RETRY_REQUIRED)
{
scif_sas_smp_remote_device_continue_current_activity(
fw_device, fw_request, SCI_FAILURE_RETRY_REQUIRED
);
return SCI_FAILURE_RETRY_REQUIRED;
}
switch (fw_device->protocol_device.smp_device.current_smp_request)
{
case SMP_FUNCTION_REPORT_GENERAL:
{
status = scif_sas_smp_remote_device_decode_report_general_response(
fw_device, smp_response
);
break;
}
case SMP_FUNCTION_REPORT_MANUFACTURER_INFORMATION:
{
status = SCI_SUCCESS;
break;
}
case SMP_FUNCTION_DISCOVER:
{
if (fw_device->protocol_device.smp_device.current_activity ==
SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER)
{
status = scif_sas_smp_remote_device_decode_initial_discover_response(
fw_device, smp_response
);
}
else if (fw_device->protocol_device.smp_device.current_activity ==
SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_TARGET_RESET)
{
status =
scif_sas_smp_remote_device_decode_target_reset_discover_response(
fw_device, smp_response
);
}
else if (fw_device->protocol_device.smp_device.current_activity ==
SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_SATA_SPINUP_HOLD_RELEASE)
{
status =
scif_sas_smp_remote_device_decode_spinup_hold_release_discover_response(
fw_device, smp_response
);
}
else
ASSERT(0);
break;
}
case SMP_FUNCTION_REPORT_PHY_SATA:
{
status = scif_sas_smp_remote_device_decode_report_phy_sata_response(
fw_device, smp_response
);
break;
}
case SMP_FUNCTION_PHY_CONTROL:
{
if (fw_device->protocol_device.smp_device.current_activity ==
SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER)
{
status = scif_sas_smp_remote_device_decode_discover_phy_control_response(
fw_device, smp_response
);
}
else if (fw_device->protocol_device.smp_device.current_activity ==
SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_TARGET_RESET)
{
status = scif_sas_smp_remote_device_decode_target_reset_phy_control_response(
fw_device, smp_response
);
}
else if (fw_device->protocol_device.smp_device.current_activity ==
SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAR_AFFILIATION)
{
status = SCI_SUCCESS;
}
else
ASSERT(0);
break;
}
case SMP_FUNCTION_CONFIGURE_ROUTE_INFORMATION:
{
status = scif_sas_smp_remote_device_decode_config_route_info_response(
fw_device, smp_response
);
break;
}
default:
status = SCI_FAILURE_UNSUPPORTED_INFORMATION_TYPE;
break;
}
scif_sas_smp_remote_device_continue_current_activity(
fw_device, fw_request, status
);
return status;
}
SCI_STATUS scif_sas_smp_remote_device_decode_report_general_response(
SCIF_SAS_REMOTE_DEVICE_T * fw_device,
SMP_RESPONSE_T * smp_response
)
{
SMP_RESPONSE_REPORT_GENERAL_T * report_general_response =
&smp_response->response.report_general;
SMP_RESPONSE_HEADER_T * response_header = &smp_response->header;
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"scif_sas_smp_remote_device_decode_report_general_response(0x%x, 0x%x) enter\n",
fw_device, smp_response
));
if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
{
SCIF_LOG_ERROR((
sci_base_object_get_logger(fw_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"Report General function result(0x%x)\n",
response_header->function_result
));
return SCI_FAILURE;
}
fw_device->protocol_device.smp_device.number_of_phys =
(U8)report_general_response->number_of_phys;
fw_device->protocol_device.smp_device.expander_route_indexes =
((report_general_response->expander_route_indexes & 0xff) << 8) |
((report_general_response->expander_route_indexes & 0xff00) >> 8);
fw_device->protocol_device.smp_device.is_table_to_table_supported =
(BOOL)report_general_response->table_to_table_supported;
fw_device->protocol_device.smp_device.is_externally_configurable =
(BOOL)report_general_response->configurable_route_table;
fw_device->protocol_device.smp_device.is_able_to_config_others =
(BOOL)report_general_response->configures_others;
if (fw_device->containing_device == NULL
&& ! fw_device->protocol_device.smp_device.is_able_to_config_others)
fw_device->domain->is_config_route_table_needed = TRUE;
if (fw_device->protocol_device.smp_device.smp_phy_list.element_count == 0)
scif_sas_smp_remote_device_populate_smp_phy_list(fw_device);
if (report_general_response->configuring)
return SCI_FAILURE_RETRY_REQUIRED;
return SCI_SUCCESS;
}
SCI_STATUS scif_sas_smp_remote_device_decode_initial_discover_response(
SCIF_SAS_REMOTE_DEVICE_T * fw_device,
SMP_RESPONSE_T * smp_response
)
{
SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain;
SCI_SAS_ADDRESS_T attached_device_address;
SCIF_SAS_REMOTE_DEVICE_T * attached_remote_device;
SMP_RESPONSE_DISCOVER_T * discover_response =
&smp_response->response.discover;
SMP_RESPONSE_HEADER_T * response_header = &smp_response->header;
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"scif_sas_smp_remote_device_decode_initial_discover_response(0x%x, 0x%x) enter\n",
fw_device, smp_response
));
if (response_header->function_result == SMP_RESULT_PHY_VACANT)
{
return SCI_SUCCESS;
}
else if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
{
SCIF_LOG_ERROR((
sci_base_object_get_logger(fw_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"Discover function result(0x%x)\n",
response_header->function_result
));
return SCI_FAILURE;
}
if ( ( discover_response->u2.sas1_1.attached_device_type
!= SMP_NO_DEVICE_ATTACHED )
&& ( discover_response->protocols.u.bits.attached_ssp_target
|| discover_response->protocols.u.bits.attached_stp_target
|| discover_response->protocols.u.bits.attached_smp_target
|| discover_response->protocols.u.bits.attached_sata_device ) )
{
attached_device_address = discover_response->attached_sas_address;
attached_remote_device = (SCIF_SAS_REMOTE_DEVICE_T *)
scif_domain_get_device_by_sas_address(
fw_domain, &attached_device_address
);
if (attached_remote_device != SCI_INVALID_HANDLE)
{
#if !defined(DISABLE_WIDE_PORTED_TARGETS)
if ( attached_remote_device->is_currently_discovered == TRUE
&& attached_remote_device != fw_device->containing_device )
{
attached_remote_device->device_port_width++;
}
else
#endif
{
attached_remote_device->is_currently_discovered = TRUE;
}
#if !defined(DISABLE_WIDE_PORTED_TARGETS)
if (attached_remote_device->device_port_width !=
scic_remote_device_get_port_width(attached_remote_device->core_object)
&& discover_response->protocols.u.bits.attached_ssp_target
)
{
scif_sas_remote_device_update_port_width(
attached_remote_device, attached_remote_device->device_port_width);
}
#endif
if ( discover_response->protocols.u.bits.attached_smp_target
&& attached_remote_device != fw_device->containing_device)
{
attached_remote_device->protocol_device.smp_device.scheduled_activity =
SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER;
}
}
else
{
scif_cb_domain_ea_device_added(
fw_domain->controller, fw_domain, fw_device, discover_response
);
if ( discover_response->protocols.u.bits.attached_ssp_target
|| discover_response->protocols.u.bits.attached_smp_target)
{
;
}
else if ( (discover_response->protocols.u.bits.attached_stp_target)
|| (discover_response->protocols.u.bits.attached_sata_device) )
{
discover_response->protocols.u.bits.attached_stp_target = 1;
fw_device->protocol_device.smp_device.current_smp_request =
SMP_FUNCTION_REPORT_PHY_SATA;
}
}
}
else if( (discover_response->u2.sas1_1.negotiated_physical_link_rate == SCI_SATA_SPINUP_HOLD
|| discover_response->u4.sas2.negotiated_physical_link_rate == SCI_SATA_SPINUP_HOLD)
&&(discover_response->protocols.u.bits.attached_stp_target
|| discover_response->protocols.u.bits.attached_sata_device)
)
{
attached_remote_device = scif_sas_domain_get_device_by_containing_device(
fw_domain,
fw_device,
discover_response->phy_identifier
);
if (attached_remote_device != SCI_INVALID_HANDLE)
{
scif_cb_domain_device_removed(
fw_domain->controller, fw_domain, attached_remote_device
);
}
discover_response->protocols.u.bits.attached_stp_target = 1;
scif_cb_domain_ea_device_added(
fw_domain->controller, fw_domain, fw_device, discover_response
);
fw_device->protocol_device.smp_device.current_smp_request =
SMP_FUNCTION_PHY_CONTROL;
}
return scif_sas_smp_remote_device_save_smp_phy_info(
fw_device, discover_response);
}
SCI_STATUS scif_sas_smp_remote_device_decode_report_phy_sata_response(
SCIF_SAS_REMOTE_DEVICE_T * fw_device,
SMP_RESPONSE_T * smp_response
)
{
SMP_RESPONSE_REPORT_PHY_SATA_T * report_phy_sata_response =
&smp_response->response.report_phy_sata;
SMP_RESPONSE_HEADER_T * response_header = &smp_response->header;
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"scif_sas_smp_remote_device_decode_report_phy_sata_response(0x%x, 0x%x) enter\n",
fw_device, smp_response
));
if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
{
SCIF_LOG_ERROR((
sci_base_object_get_logger(fw_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"Report Phy Sata function result(0x%x)\n",
response_header->function_result
));
return SCI_FAILURE;
}
scif_sas_remote_device_save_report_phy_sata_information(
report_phy_sata_response
);
fw_device->protocol_device.smp_device.current_smp_request =
SMP_FUNCTION_DISCOVER;
return SCI_SUCCESS;
}
SCI_STATUS scif_sas_smp_remote_device_decode_target_reset_phy_control_response(
SCIF_SAS_REMOTE_DEVICE_T * fw_device,
SMP_RESPONSE_T * smp_response
)
{
SMP_RESPONSE_HEADER_T * response_header = &smp_response->header;
SCI_STATUS status = SCI_SUCCESS;
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"scif_sas_smp_remote_device_decode_target_reset_phy_control_response(0x%x, 0x%x) enter\n",
fw_device, smp_response
));
if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
{
SCIF_LOG_ERROR((
sci_base_object_get_logger(fw_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"Phy Control function unaccepted result(0x%x)\n",
response_header->function_result
));
status = SCI_FAILURE_RETRY_REQUIRED;
}
return status;
}
SCI_STATUS scif_sas_smp_remote_device_decode_discover_phy_control_response(
SCIF_SAS_REMOTE_DEVICE_T * fw_device,
SMP_RESPONSE_T * smp_response
)
{
SMP_RESPONSE_HEADER_T * response_header = &smp_response->header;
SCI_STATUS status = SCI_SUCCESS;
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"scif_sas_smp_remote_device_decode_discover_phy_control_response(0x%x, 0x%x) enter\n",
fw_device, smp_response
));
if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
{
SCIF_LOG_ERROR((
sci_base_object_get_logger(fw_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"Phy Control function unaccepted result(0x%x)\n",
response_header->function_result
));
return SCI_FAILURE_RETRY_REQUIRED;
}
fw_device->protocol_device.smp_device.current_smp_request =
SMP_FUNCTION_DISCOVER;
return status;
}
SCI_STATUS scif_sas_smp_remote_device_decode_target_reset_discover_response(
SCIF_SAS_REMOTE_DEVICE_T * fw_device,
SMP_RESPONSE_T * smp_response
)
{
SCIF_SAS_DOMAIN_T * fw_domain;
SCI_SAS_ADDRESS_T attached_device_address;
SMP_RESPONSE_DISCOVER_T * discover_response =
&smp_response->response.discover;
SMP_RESPONSE_HEADER_T * response_header = &smp_response->header;
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"scif_sas_smp_remote_device_decode_target_reset_discover_response(0x%x, 0x%x) enter\n",
fw_device, smp_response
));
if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
{
SCIF_LOG_ERROR((
sci_base_object_get_logger(fw_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"Discover function result(0x%x)\n",
response_header->function_result
));
return SCI_FAILURE_RETRY_REQUIRED;
}
if ( discover_response->u2.sas1_1.attached_device_type != SMP_NO_DEVICE_ATTACHED )
{
fw_domain = fw_device->domain;
attached_device_address = discover_response->attached_sas_address;
ASSERT(scif_domain_get_device_by_sas_address(
fw_domain,
&attached_device_address
) != SCI_INVALID_HANDLE);
return SCI_SUCCESS;
}
else
return SCI_FAILURE_RETRY_REQUIRED;
}
SCI_STATUS scif_sas_smp_remote_device_decode_spinup_hold_release_discover_response(
SCIF_SAS_REMOTE_DEVICE_T * fw_device,
SMP_RESPONSE_T * smp_response
)
{
SMP_RESPONSE_DISCOVER_T * discover_response = &smp_response->response.discover;
SMP_RESPONSE_HEADER_T * response_header = &smp_response->header;
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"scif_sas_smp_remote_device_decode_spinup_hold_release_discover_response(0x%x, 0x%x) enter\n",
fw_device, smp_response
));
if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
{
SCIF_LOG_ERROR((
sci_base_object_get_logger(fw_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"Discover function result(0x%x)\n",
response_header->function_result
));
return SCI_FAILURE;
}
if ( discover_response->u2.sas1_1.attached_device_type != SMP_NO_DEVICE_ATTACHED )
{
if (discover_response->u2.sas1_1.negotiated_physical_link_rate != SCI_SATA_SPINUP_HOLD
&& discover_response->u4.sas2.negotiated_physical_link_rate != SCI_SATA_SPINUP_HOLD
&& ( discover_response->protocols.u.bits.attached_stp_target
||discover_response->protocols.u.bits.attached_sata_device )
)
{
SCIF_SAS_REMOTE_DEVICE_T * target_device =
scif_sas_domain_get_device_by_containing_device(
fw_device->domain,
fw_device,
fw_device->protocol_device.smp_device.current_activity_phy_index
);
scic_remote_device_set_max_connection_rate(
target_device->core_object,
discover_response->u2.sas1_1.negotiated_physical_link_rate
);
scif_sas_smp_remote_device_save_smp_phy_info(
fw_device, discover_response);
return target_device->state_handlers->parent.start_handler(
&target_device->parent );
}
else
return SCI_FAILURE_RETRY_REQUIRED;
}
else
return SCI_FAILURE_RETRY_REQUIRED;
}
SCI_STATUS scif_sas_smp_remote_device_decode_config_route_info_response(
SCIF_SAS_REMOTE_DEVICE_T * fw_device,
SMP_RESPONSE_T * smp_response
)
{
SMP_RESPONSE_HEADER_T * response_header = &smp_response->header;
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"scif_sas_smp_remote_device_decode_config_route_info_response(0x%x, 0x%x) enter\n",
fw_device, smp_response
));
if (response_header->function_result == SMP_RESULT_INDEX_DOES_NOT_EXIST)
{
scif_sas_smp_remote_device_cancel_config_route_table_activity(fw_device);
return SCI_FAILURE_EXCEED_MAX_ROUTE_INDEX;
}
else if (response_header->function_result != SMP_RESULT_FUNCTION_ACCEPTED)
{
SCIF_LOG_ERROR((
sci_base_object_get_logger(fw_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"Discover function result(0x%x)\n",
response_header->function_result
));
return SCI_FAILURE;
}
return SCI_SUCCESS;
}
void scif_sas_smp_remote_device_start_discover(
SCIF_SAS_REMOTE_DEVICE_T * fw_device
)
{
SCIF_SAS_CONTROLLER_T * fw_controller = fw_device->domain->controller;
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"scif_sas_smp_remote_device_start_discover(0x%x) enter\n",
fw_device
));
scif_sas_smp_remote_device_clear(fw_device);
fw_device->protocol_device.smp_device.current_activity =
SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER;
fw_device->protocol_device.smp_device.current_smp_request =
SMP_FUNCTION_REPORT_GENERAL;
fw_device->protocol_device.smp_device.scheduled_activity =
SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE;
scif_sas_smp_request_construct_report_general(fw_controller, fw_device);
scif_cb_start_internal_io_task_schedule(
fw_controller,
scif_sas_controller_start_high_priority_io,
fw_controller
);
}
void scif_sas_smp_remote_device_continue_current_activity(
SCIF_SAS_REMOTE_DEVICE_T * fw_device,
SCIF_SAS_REQUEST_T * fw_request,
SCI_STATUS status
)
{
SCIF_SAS_IO_REQUEST_T * fw_io = (SCIF_SAS_IO_REQUEST_T *)fw_request;
U8 io_retry_count = fw_io->retry_count;
if (fw_request->is_internal)
{
scif_sas_internal_io_request_complete(
fw_device->domain->controller,
(SCIF_SAS_INTERNAL_IO_REQUEST_T *)fw_request,
SCI_SUCCESS
);
}
if (fw_device->protocol_device.smp_device.current_activity ==
SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER)
{
if (status == SCI_SUCCESS)
{
scif_sas_smp_remote_device_continue_discover(fw_device);
}
else if (status == SCI_FAILURE_RETRY_REQUIRED)
{
U32 retry_wait_duration = (SCIF_DOMAIN_DISCOVER_TIMEOUT / 2) / SCIF_SAS_IO_RETRY_LIMIT;
if (io_retry_count < SCIF_SAS_IO_RETRY_LIMIT)
scif_sas_smp_remote_device_retry_internal_io (
fw_device, io_retry_count, retry_wait_duration);
else
scif_sas_smp_remote_device_fail_discover(fw_device);
}
else if (status == SCI_FAILURE_ILLEGAL_ROUTING_ATTRIBUTE_CONFIGURATION)
{
scif_sas_domain_remove_expander_device(fw_device->domain, fw_device);
scif_sas_domain_continue_discover(fw_device->domain);
}
else
{
scif_sas_smp_remote_device_fail_discover(fw_device);
}
}
else if (fw_device->protocol_device.smp_device.current_activity ==
SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_TARGET_RESET)
{
if (status == SCI_SUCCESS)
{
scif_sas_smp_remote_device_continue_target_reset(
fw_device, fw_request);
}
else if (status == SCI_FAILURE_RETRY_REQUIRED)
{
if (io_retry_count < SCIF_SAS_IO_RETRY_LIMIT)
{
if (fw_device->protocol_device.smp_device.smp_activity_timer == NULL)
{
fw_device->protocol_device.smp_device.smp_activity_timer =
scif_cb_timer_create(
(SCI_CONTROLLER_HANDLE_T *)fw_device->domain->controller,
(SCI_TIMER_CALLBACK_T)scif_sas_smp_external_request_retry,
(void*)fw_request
);
}
else
{
ASSERT(0);
}
scif_cb_timer_start(
(SCI_CONTROLLER_HANDLE_T)fw_device->domain->controller,
fw_device->protocol_device.smp_device.smp_activity_timer,
SMP_REQUEST_RETRY_WAIT_DURATION
);
}
else
scif_sas_smp_remote_device_fail_target_reset(fw_device, fw_request);
}
else
scif_sas_smp_remote_device_fail_target_reset(fw_device, fw_request);
}
else if (fw_device->protocol_device.smp_device.current_activity ==
SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_SATA_SPINUP_HOLD_RELEASE)
{
SCIF_SAS_REMOTE_DEVICE_T * target_device =
scif_sas_domain_get_device_by_containing_device(
fw_device->domain,
fw_device,
fw_device->protocol_device.smp_device.current_activity_phy_index
);
if (status == SCI_SUCCESS)
{
scif_sas_smp_remote_device_sata_spinup_hold_release(fw_device);
}
else if (status == SCI_FAILURE_RETRY_REQUIRED)
{
U32 delay =
(scic_remote_device_get_suggested_reset_timeout(target_device->core_object) /
SCIF_SAS_IO_RETRY_LIMIT);
if (io_retry_count < SCIF_SAS_IO_RETRY_LIMIT)
{
scif_sas_smp_remote_device_retry_internal_io(
fw_device, io_retry_count, delay);
}
else
{
scif_sas_smp_remote_device_fail_target_spinup_hold_release(
fw_device , target_device);
}
}
else
scif_sas_smp_remote_device_fail_target_spinup_hold_release(
fw_device, target_device);
}
else if (fw_device->protocol_device.smp_device.current_activity ==
SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE)
{
SCI_FAST_LIST_ELEMENT_T * next_phy_element = sci_fast_list_get_next(
&(fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy->list_element) );
SCI_FAST_LIST_T * destination_smp_phy_list =
fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy->list_element.owning_list;
SCIF_SAS_SMP_PHY_T * next_phy_in_wide_port = NULL;
if (next_phy_element != NULL
&& status != SCI_FAILURE_EXCEED_MAX_ROUTE_INDEX)
{
fw_device->protocol_device.smp_device.curr_config_route_index++;
fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy =
(SCIF_SAS_SMP_PHY_T *)sci_fast_list_get_object(next_phy_element);
fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->config_route_table_index_anchor =
fw_device->protocol_device.smp_device.curr_config_route_index;
scif_sas_smp_remote_device_configure_route_table(fw_device);
}
else if ( scif_sas_smp_remote_device_get_config_route_table_method(fw_device)
== SCIF_SAS_CONFIG_ROUTE_TABLE_ALL_PHYS
&& (next_phy_in_wide_port = scif_sas_smp_phy_find_next_phy_in_wide_port(
fw_device->protocol_device.smp_device.config_route_smp_phy_anchor)
)!= NULL
)
{
fw_device->protocol_device.smp_device.config_route_smp_phy_anchor =
next_phy_in_wide_port;
fw_device->protocol_device.smp_device.current_activity_phy_index =
fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->phy_identifier;
fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy =
sci_fast_list_get_head(destination_smp_phy_list);
if (fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->config_route_table_index_anchor != 0)
fw_device->protocol_device.smp_device.curr_config_route_index =
fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->config_route_table_index_anchor + 1;
else
fw_device->protocol_device.smp_device.curr_config_route_index = 0;
scif_sas_smp_remote_device_configure_route_table(fw_device);
}
else if ( fw_device->protocol_device.smp_device.is_route_table_cleaned == FALSE)
{
fw_device->protocol_device.smp_device.current_activity =
SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAN_ROUTE_TABLE;
scif_sas_smp_remote_device_clean_route_table(fw_device);
}
else
{
fw_device->protocol_device.smp_device.current_activity =
SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE;
scif_sas_domain_continue_discover(fw_device->domain);
}
}
else if (fw_device->protocol_device.smp_device.current_activity ==
SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAN_ROUTE_TABLE)
{
scif_sas_smp_remote_device_clean_route_table(fw_device);
}
else if (fw_device->protocol_device.smp_device.current_activity ==
SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAR_AFFILIATION)
{
scif_sas_smp_remote_device_continue_clear_affiliation(fw_device);
}
}
void scif_sas_smp_remote_device_continue_discover(
SCIF_SAS_REMOTE_DEVICE_T * fw_device
)
{
SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain;
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"scif_sas_smp_remote_device_continue_discover(0x%x) enter\n",
fw_device
));
switch (fw_device->protocol_device.smp_device.current_smp_request)
{
case SMP_FUNCTION_REPORT_GENERAL:
fw_device->protocol_device.smp_device.current_smp_request =
SMP_FUNCTION_REPORT_MANUFACTURER_INFORMATION;
scif_sas_smp_request_construct_report_manufacturer_info(
fw_domain->controller, fw_device
);
break;
case SMP_FUNCTION_REPORT_MANUFACTURER_INFORMATION:
fw_device->protocol_device.smp_device.current_activity_phy_index = 0;
fw_device->protocol_device.smp_device.current_smp_request =
SMP_FUNCTION_DISCOVER;
scif_sas_smp_request_construct_discover(
fw_domain->controller,
fw_device,
fw_device->protocol_device.smp_device.current_activity_phy_index,
NULL, NULL
);
break;
case SMP_FUNCTION_DISCOVER:
fw_device->protocol_device.smp_device.current_activity_phy_index++;
if ( (fw_device->protocol_device.smp_device.current_activity_phy_index <
fw_device->protocol_device.smp_device.number_of_phys) )
{
scif_sas_smp_request_construct_discover(
fw_domain->controller,
fw_device,
fw_device->protocol_device.smp_device.current_activity_phy_index,
NULL, NULL
);
}
else
scif_sas_smp_remote_device_finish_initial_discover(fw_device);
break;
case SMP_FUNCTION_REPORT_PHY_SATA:
scif_sas_smp_request_construct_report_phy_sata(
fw_device->domain->controller,
fw_device,
fw_device->protocol_device.smp_device.current_activity_phy_index
);
break;
case SMP_FUNCTION_PHY_CONTROL:
scif_sas_smp_request_construct_phy_control(
fw_device->domain->controller,
fw_device,
PHY_OPERATION_HARD_RESET,
fw_device->protocol_device.smp_device.current_activity_phy_index,
NULL,
NULL
);
break;
default:
break;
}
}
void scif_sas_smp_remote_device_finish_initial_discover(
SCIF_SAS_REMOTE_DEVICE_T * fw_device
)
{
SCIF_SAS_REMOTE_DEVICE_T * device_in_sata_spinup_hold =
scif_sas_domain_find_device_in_spinup_hold(fw_device->domain);
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"scif_sas_smp_remote_device_finish_initial_discover(0x%x) enter\n",
fw_device
));
if ( device_in_sata_spinup_hold != NULL )
{
scif_sas_smp_remote_device_clear(fw_device);
fw_device->protocol_device.smp_device.current_activity =
SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_SATA_SPINUP_HOLD_RELEASE;
if (fw_device->protocol_device.smp_device.smp_activity_timer == NULL)
{
fw_device->protocol_device.smp_device.smp_activity_timer =
scif_cb_timer_create(
(SCI_CONTROLLER_HANDLE_T *)fw_device->domain->controller,
(SCI_TIMER_CALLBACK_T)scif_sas_smp_remote_device_sata_spinup_hold_release,
(void*)fw_device
);
}
else
{
ASSERT (0);
}
scif_cb_timer_start(
(SCI_CONTROLLER_HANDLE_T)fw_device->domain->controller,
fw_device->protocol_device.smp_device.smp_activity_timer,
SMP_SPINUP_HOLD_RELEASE_WAIT_DURATION
);
}
else
scif_sas_smp_remote_device_finish_discover(fw_device);
}
void scif_sas_smp_remote_device_finish_discover(
SCIF_SAS_REMOTE_DEVICE_T * fw_device
)
{
SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain;
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"scif_sas_smp_remote_device_finish_discover(0x%x) enter\n",
fw_device
));
if ( fw_domain->is_config_route_table_needed
&& fw_device->protocol_device.smp_device.smp_phy_list.list_head != NULL)
scif_sas_smp_remote_device_configure_upstream_expander_route_info(fw_device);
scif_sas_smp_remote_device_clear(fw_device);
#ifdef SCI_SMP_PHY_LIST_DEBUG_PRINT
scif_sas_smp_remote_device_print_smp_phy_list(fw_device);
#endif
scif_sas_domain_continue_discover(fw_domain);
}
void scif_sas_smp_remote_device_continue_target_reset(
SCIF_SAS_REMOTE_DEVICE_T * fw_device,
SCIF_SAS_REQUEST_T * fw_request
)
{
SCIF_SAS_CONTROLLER_T * fw_controller = fw_device->domain->controller;
SCIF_SAS_REMOTE_DEVICE_T * target_device =
scif_sas_domain_get_device_by_containing_device(
fw_device->domain,
fw_device,
fw_device->protocol_device.smp_device.current_activity_phy_index
);
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"scif_sas_smp_remote_device_continue_target_reset(0x%x, 0x%x) enter\n",
fw_device, fw_request
));
if (fw_device->protocol_device.smp_device.current_smp_request ==
SMP_FUNCTION_PHY_CONTROL)
{
U32 delay =
(scic_remote_device_get_suggested_reset_timeout(target_device->core_object)/8);
if (fw_device->protocol_device.smp_device.smp_activity_timer == NULL)
{
fw_device->protocol_device.smp_device.smp_activity_timer =
scif_cb_timer_create(
(SCI_CONTROLLER_HANDLE_T *)fw_controller,
(SCI_TIMER_CALLBACK_T)scif_sas_smp_remote_device_target_reset_poll,
(void*)fw_request
);
}
else
{
ASSERT(0);
}
scif_cb_timer_start(
(SCI_CONTROLLER_HANDLE_T)fw_controller,
fw_device->protocol_device.smp_device.smp_activity_timer,
delay
);
}
else if (fw_device->protocol_device.smp_device.current_smp_request ==
SMP_FUNCTION_DISCOVER)
{
scif_sas_remote_device_target_reset_complete(
target_device, fw_request, SCI_SUCCESS);
}
}
void scif_sas_smp_remote_device_target_reset_poll(
SCIF_SAS_REQUEST_T * fw_request
)
{
SCIF_SAS_REMOTE_DEVICE_T * fw_device = fw_request->device;
SCIF_SAS_CONTROLLER_T * fw_controller = fw_device->domain->controller;
void * new_command_handle;
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"scif_sas_smp_remote_device_target_reset_poll(0x%x) enter\n",
fw_request
));
sci_fast_list_remove_element(&fw_request->list_element);
fw_device->protocol_device.smp_device.current_smp_request =
SMP_FUNCTION_DISCOVER;
new_command_handle = scif_sas_smp_request_construct_discover(
fw_device->domain->controller,
fw_device,
fw_device->protocol_device.smp_device.current_activity_phy_index,
(void *)sci_object_get_association(fw_request),
(void *)fw_request
);
sci_pool_put(fw_controller->hprq.pool, (POINTER_UINT) new_command_handle);
scif_cb_start_internal_io_task_schedule(
fw_controller, scif_sas_controller_start_high_priority_io, fw_controller
);
}
void scif_sas_smp_remote_device_fail_discover(
SCIF_SAS_REMOTE_DEVICE_T * fw_device
)
{
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"scif_sas_smp_remote_device_fail_discover(0x%x) enter\n",
fw_device
));
switch (fw_device->protocol_device.smp_device.current_smp_request)
{
case SMP_FUNCTION_REPORT_GENERAL:
case SMP_FUNCTION_REPORT_MANUFACTURER_INFORMATION:
scif_sas_smp_remote_device_finish_discover(fw_device);
break;
case SMP_FUNCTION_DISCOVER:
case SMP_FUNCTION_REPORT_PHY_SATA:
fw_device->protocol_device.smp_device.current_smp_request =
SMP_FUNCTION_DISCOVER;
scif_sas_smp_remote_device_continue_discover(fw_device);
break;
default:
break;
}
}
void scif_sas_smp_remote_device_fail_target_reset(
SCIF_SAS_REMOTE_DEVICE_T * fw_device,
SCIF_SAS_REQUEST_T * fw_request
)
{
SCIF_SAS_REMOTE_DEVICE_T * target_device =
scif_sas_domain_get_device_by_containing_device(
fw_device->domain,
fw_device,
fw_device->protocol_device.smp_device.current_activity_phy_index
);
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"scif_sas_smp_remote_device_fail_target_reset(0x%x, 0x%x, 0x%x) enter\n",
fw_device, target_device, fw_request
));
scif_sas_remote_device_target_reset_complete(
target_device, fw_request, SCI_FAILURE);
}
void scif_sas_smp_remote_device_sata_spinup_hold_release(
SCIF_SAS_REMOTE_DEVICE_T * fw_device
)
{
SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain;
SCIF_SAS_CONTROLLER_T * fw_controller = fw_domain->controller;
SCIF_SAS_REMOTE_DEVICE_T * device_to_poll = NULL;
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"scif_sas_smp_remote_device_sata_spinup_hold_release(0x%x) enter\n",
fw_device
));
device_to_poll = scif_sas_domain_find_device_in_spinup_hold(fw_domain);
if (device_to_poll != NULL)
{
fw_device->protocol_device.smp_device.current_smp_request =
SMP_FUNCTION_DISCOVER;
fw_device->protocol_device.smp_device.current_activity_phy_index =
device_to_poll->expander_phy_identifier;
scif_sas_smp_request_construct_discover(
fw_domain->controller,
fw_device,
fw_device->protocol_device.smp_device.current_activity_phy_index,
NULL, NULL
);
scif_cb_start_internal_io_task_schedule(
fw_controller, scif_sas_controller_start_high_priority_io, fw_controller
);
}
else
scif_sas_smp_remote_device_finish_discover (fw_device);
}
void scif_sas_smp_remote_device_fail_target_spinup_hold_release(
SCIF_SAS_REMOTE_DEVICE_T * fw_device,
SCIF_SAS_REMOTE_DEVICE_T * target_device
)
{
SCIF_SAS_DOMAIN_T * fw_domain = fw_device->domain;
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"scif_sas_smp_remote_device_fail_target_spinup_hold_release(0x%x, 0x%x) enter\n",
fw_device, target_device
));
scif_cb_domain_device_removed(
fw_domain->controller, fw_domain, target_device
);
scif_sas_smp_remote_device_sata_spinup_hold_release(fw_device);
}
void scif_sas_smp_remote_device_retry_internal_io(
SCIF_SAS_REMOTE_DEVICE_T * fw_device,
U8 io_retry_count,
U32 delay
)
{
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"scif_sas_smp_remote_device_retry_internal_io(0x%x, 0x%x, 0x%x) enter\n",
fw_device, io_retry_count, delay
));
fw_device->protocol_device.smp_device.io_retry_count =
io_retry_count;
if (fw_device->protocol_device.smp_device.smp_activity_timer == NULL)
{
fw_device->protocol_device.smp_device.smp_activity_timer =
scif_cb_timer_create(
(SCI_CONTROLLER_HANDLE_T *)fw_device->domain->controller,
(SCI_TIMER_CALLBACK_T)scif_sas_smp_internal_request_retry,
(void*)fw_device
);
}
else
{
ASSERT(0);
}
scif_cb_timer_start(
(SCI_CONTROLLER_HANDLE_T)fw_device->domain->controller,
fw_device->protocol_device.smp_device.smp_activity_timer,
delay
);
}
BOOL scif_sas_smp_remote_device_is_in_activity(
SCIF_SAS_REMOTE_DEVICE_T * fw_device
)
{
return(fw_device->protocol_device.smp_device.current_activity
!= SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE);
}
SCIF_SAS_SMP_PHY_T * scif_sas_smp_remote_device_find_smp_phy_by_id(
U8 phy_identifier,
SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device
)
{
SCI_FAST_LIST_ELEMENT_T * element = smp_remote_device->smp_phy_list.list_head;
SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL;
ASSERT(phy_identifier < smp_remote_device->smp_phy_list.number_of_phys);
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->phy_identifier == phy_identifier)
return curr_smp_phy;
}
return NULL;
}
void scif_sas_smp_remote_device_removed(
SCIF_SAS_REMOTE_DEVICE_T * this_device
)
{
SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device =
&this_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_LOG_TRACE((
sci_base_object_get_logger(this_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"scif_sas_smp_remote_device_removed(0x%x) enter\n",
this_device
));
while (element != NULL)
{
curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element);
element = sci_fast_list_get_next(element);
scif_sas_smp_phy_destruct(curr_smp_phy);
}
this_device->protocol_device.smp_device.number_of_phys = 0;
this_device->protocol_device.smp_device.expander_route_indexes = 0;
this_device->protocol_device.smp_device.is_table_to_table_supported = FALSE;
this_device->protocol_device.smp_device.is_externally_configurable = FALSE;
this_device->protocol_device.smp_device.is_able_to_config_others = FALSE;
scif_sas_smp_remote_device_clear(this_device);
}
void scif_sas_smp_remote_device_terminated_request_handler(
SCIF_SAS_REMOTE_DEVICE_T * fw_device,
SCIF_SAS_REQUEST_T * fw_request
)
{
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"scif_sas_smp_remote_device_terminated_request_handler(0x%x, 0x%x) enter\n",
fw_device, fw_request
));
scif_sas_smp_remote_device_decode_smp_response(
fw_device, fw_request, NULL, SCI_IO_FAILURE_RETRY_REQUIRED
);
}
void scif_sas_smp_remote_device_populate_smp_phy_list(
SCIF_SAS_REMOTE_DEVICE_T * fw_device
)
{
SCIF_SAS_SMP_PHY_T * this_smp_phy = NULL;
U8 expander_phy_id = 0;
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"scif_sas_smp_remote_device_populate_smp_phy_list(0x%x) enter\n",
fw_device
));
for ( expander_phy_id = 0;
expander_phy_id < fw_device->protocol_device.smp_device.number_of_phys;
expander_phy_id++ )
{
this_smp_phy =
scif_sas_controller_allocate_smp_phy(fw_device->domain->controller);
ASSERT( this_smp_phy != NULL );
if ( this_smp_phy != NULL )
scif_sas_smp_phy_construct(this_smp_phy, fw_device, expander_phy_id);
}
}
SCI_STATUS scif_sas_smp_remote_device_save_smp_phy_info(
SCIF_SAS_REMOTE_DEVICE_T * fw_device,
SMP_RESPONSE_DISCOVER_T * discover_response
)
{
SCI_STATUS status = SCI_SUCCESS;
SCIF_SAS_SMP_PHY_T * smp_phy = NULL;
SCIF_SAS_REMOTE_DEVICE_T * attached_device = NULL;
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"scif_sas_smp_remote_device_save_smp_phy_info(0x%x, 0x%x) enter\n",
fw_device, discover_response
));
smp_phy = scif_sas_smp_remote_device_find_smp_phy_by_id(
discover_response->phy_identifier,
&fw_device->protocol_device.smp_device
);
ASSERT( smp_phy != NULL );
attached_device = (SCIF_SAS_REMOTE_DEVICE_T *)
scif_domain_get_device_by_sas_address(
fw_device->domain, &discover_response->attached_sas_address);
scif_sas_smp_phy_save_information(
smp_phy, attached_device, discover_response);
if ( discover_response->protocols.u.bits.attached_smp_target )
{
if ( attached_device != NULL
&& attached_device == fw_device->containing_device )
{
status = scif_sas_smp_phy_set_attached_phy(
smp_phy,
discover_response->attached_phy_identifier,
attached_device
);
if (status == SCI_SUCCESS)
{
if ( scif_sas_smp_phy_verify_routing_attribute(
smp_phy, smp_phy->u.attached_phy) != SCI_SUCCESS )
return SCI_FAILURE_ILLEGAL_ROUTING_ATTRIBUTE_CONFIGURATION;
}
}
}
return status;
}
#ifdef SCI_SMP_PHY_LIST_DEBUG_PRINT
void scif_sas_smp_remote_device_print_smp_phy_list(
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_LOG_ERROR((
sci_base_object_get_logger(fw_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE,
"==========EXPANDER DEVICE (0x%x) smp phy list========== \n",
fw_device
));
while (element != NULL)
{
curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element);
element = sci_fast_list_get_next(element);
SCIF_LOG_ERROR((
sci_base_object_get_logger(fw_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE,
"SMP_PHY_%d (0x%x), attached device(0x%x), attached_sas_address(%x%x) attached_device_type(%d), routing_attribute(%d)\n",
curr_smp_phy->phy_identifier, curr_smp_phy,
curr_smp_phy->u.end_device,
curr_smp_phy->attached_sas_address.high, curr_smp_phy->attached_sas_address.low,
curr_smp_phy->attached_device_type,
curr_smp_phy->routing_attribute
));
}
}
#endif
void scif_sas_smp_remote_device_configure_upstream_expander_route_info(
SCIF_SAS_REMOTE_DEVICE_T * this_device
)
{
SCIF_SAS_REMOTE_DEVICE_T * curr_child_expander = this_device;
SCIF_SAS_REMOTE_DEVICE_T * curr_parent_expander =
scif_sas_remote_device_find_upstream_expander(this_device);
SCIF_SAS_REMOTE_DEVICE_T * curr_config_route_info_expander = NULL;
SCIF_LOG_TRACE((
sci_base_object_get_logger(this_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"scif_sas_smp_remote_device_configure_upstream_expander_route_info(0x%x) enter\n",
this_device
));
while(curr_parent_expander != NULL )
{
curr_parent_expander->protocol_device.smp_device.curr_config_route_destination_smp_phy =
(SCIF_SAS_SMP_PHY_T*)sci_fast_list_get_object(
this_device->protocol_device.smp_device.smp_phy_list.list_head);
curr_child_expander = curr_parent_expander;
curr_parent_expander = scif_sas_remote_device_find_upstream_expander(curr_child_expander);
}
curr_config_route_info_expander = curr_child_expander;
while ( curr_config_route_info_expander != NULL
&& curr_config_route_info_expander != this_device
&& curr_config_route_info_expander->protocol_device.smp_device.scheduled_activity
== SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE
)
{
if (curr_config_route_info_expander->protocol_device.smp_device.is_externally_configurable)
{
SCIF_SAS_SMP_PHY_T * phy_being_config =
curr_config_route_info_expander->protocol_device.smp_device.config_route_smp_phy_anchor;
curr_config_route_info_expander->protocol_device.smp_device.curr_config_route_index =
phy_being_config->config_route_table_index_anchor;
if (curr_config_route_info_expander->protocol_device.smp_device.curr_config_route_index != 0)
curr_config_route_info_expander->protocol_device.smp_device.curr_config_route_index++;
curr_config_route_info_expander->protocol_device.smp_device.scheduled_activity =
SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE;
curr_config_route_info_expander = scif_sas_remote_device_find_downstream_expander(
curr_config_route_info_expander);
}
else if (curr_config_route_info_expander->protocol_device.smp_device.is_able_to_config_others)
{
SCIF_SAS_REMOTE_DEVICE_T * curr_downstream_expander =
scif_sas_remote_device_find_downstream_expander(
curr_config_route_info_expander);
scif_sas_smp_remote_device_clear(curr_config_route_info_expander);
while ( curr_downstream_expander != NULL
&& curr_downstream_expander != this_device )
{
scif_sas_smp_remote_device_clear(curr_downstream_expander);
curr_downstream_expander =
scif_sas_remote_device_find_downstream_expander(
curr_config_route_info_expander);
}
break;
}
else
{
curr_config_route_info_expander = scif_sas_remote_device_find_downstream_expander(
curr_config_route_info_expander);
}
}
}
SCIF_SAS_REMOTE_DEVICE_T * scif_sas_remote_device_find_upstream_expander(
SCIF_SAS_REMOTE_DEVICE_T * this_device
)
{
SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device =
&this_device->protocol_device.smp_device;
SCIF_SAS_REMOTE_DEVICE_T * upstream_expander = NULL;
SCI_FAST_LIST_ELEMENT_T * element = smp_remote_device->smp_phy_list.list_head;
SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL;
SCIF_LOG_TRACE((
sci_base_object_get_logger(this_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"scif_sas_smp_remote_device_configure_upstream_expander_route_info(0x%x) enter\n",
this_device
));
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->routing_attribute == SUBTRACTIVE_ROUTING_ATTRIBUTE
&& ( curr_smp_phy->attached_device_type == SMP_EDGE_EXPANDER_DEVICE
|| curr_smp_phy->attached_device_type == SMP_FANOUT_EXPANDER_DEVICE)
&& curr_smp_phy->u.attached_phy != NULL
&& curr_smp_phy->u.attached_phy->routing_attribute == TABLE_ROUTING_ATTRIBUTE )
{
upstream_expander = curr_smp_phy->u.attached_phy->owning_device;
upstream_expander->protocol_device.smp_device.current_smp_request =
SMP_FUNCTION_CONFIGURE_ROUTE_INFORMATION;
upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor =
scif_sas_smp_remote_device_find_smp_phy_by_id(
curr_smp_phy->u.attached_phy->phy_identifier,
&(curr_smp_phy->u.attached_phy->owning_device->protocol_device.smp_device)
);
if ( scif_sas_smp_remote_device_get_config_route_table_method(upstream_expander)
== SCIF_SAS_CONFIG_ROUTE_TABLE_MIDDLE_PHY_ONLY )
{
upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor =
scif_sas_smp_phy_find_middle_phy_in_wide_port (
upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor
);
}
else if ( scif_sas_smp_remote_device_get_config_route_table_method(upstream_expander)
== SCIF_SAS_CONFIG_ROUTE_TABLE_HIGHEST_PHY_ONLY )
{
upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor =
scif_sas_smp_phy_find_highest_phy_in_wide_port (
upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor
);
}
upstream_expander->protocol_device.smp_device.current_activity_phy_index =
upstream_expander->protocol_device.smp_device.config_route_smp_phy_anchor->phy_identifier;
return upstream_expander;
}
}
return NULL;
}
SCIF_SAS_REMOTE_DEVICE_T * scif_sas_remote_device_find_downstream_expander(
SCIF_SAS_REMOTE_DEVICE_T * this_device
)
{
SCIF_SAS_SMP_REMOTE_DEVICE_T * this_smp_remote_device =
&this_device->protocol_device.smp_device;
SCIF_SAS_REMOTE_DEVICE_T * downstream_expander = NULL;
SCI_FAST_LIST_ELEMENT_T * element = this_smp_remote_device->smp_phy_list.list_head;
SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL;
SCIF_LOG_TRACE((
sci_base_object_get_logger(this_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"scif_sas_remote_device_find_downstream_expander(0x%x) enter\n",
this_device
));
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->routing_attribute == TABLE_ROUTING_ATTRIBUTE
&& curr_smp_phy->attached_device_type == SMP_EDGE_EXPANDER_DEVICE
&& curr_smp_phy->u.attached_phy != NULL)
{
downstream_expander = curr_smp_phy->u.attached_phy->owning_device;
if ( downstream_expander->protocol_device.smp_device.curr_config_route_destination_smp_phy != NULL
&& downstream_expander->protocol_device.smp_device.curr_config_route_destination_smp_phy->owning_device ==
this_smp_remote_device->curr_config_route_destination_smp_phy->owning_device )
return downstream_expander;
}
}
return NULL;
}
BOOL scif_sas_smp_remote_device_do_config_route_info(
SCIF_SAS_REMOTE_DEVICE_T * device_being_config,
SCIF_SAS_SMP_PHY_T * destination_smp_phy
)
{
SCI_SAS_ADDRESS_T device_being_config_sas_address;
SCIF_LOG_TRACE((
sci_base_object_get_logger(device_being_config),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"scif_sas_smp_remote_device_do_config_route_info(0x%x, 0x%x) enter\n",
device_being_config, destination_smp_phy
));
scic_remote_device_get_sas_address(
device_being_config->core_object, &device_being_config_sas_address
);
if ((destination_smp_phy->attached_sas_address.low == 0
&& destination_smp_phy->attached_sas_address.high == 0)
&& (destination_smp_phy->attached_device_type == SMP_NO_DEVICE_ATTACHED))
{
return FALSE;
}
if (destination_smp_phy->attached_sas_address.high ==
device_being_config_sas_address.high
&& destination_smp_phy->attached_sas_address.low ==
device_being_config_sas_address.low)
{
return FALSE;
}
return TRUE;
}
void scif_sas_smp_remote_device_configure_route_table(
SCIF_SAS_REMOTE_DEVICE_T * device_being_config
)
{
SCI_FAST_LIST_ELEMENT_T * element =
&(device_being_config->protocol_device.smp_device.curr_config_route_destination_smp_phy->list_element);
SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL;
SCIF_LOG_TRACE((
sci_base_object_get_logger(device_being_config),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"scif_sas_smp_remote_device_configure_route_table(0x%x) enter\n",
device_being_config
));
device_being_config->protocol_device.smp_device.current_activity =
SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE;
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 (scif_sas_smp_remote_device_do_config_route_info(
device_being_config, curr_smp_phy) == TRUE )
{
SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device =
&device_being_config->protocol_device.smp_device;
smp_remote_device->curr_config_route_destination_smp_phy =
curr_smp_phy;
scif_sas_smp_request_construct_config_route_info(
device_being_config->domain->controller,
device_being_config,
smp_remote_device->current_activity_phy_index,
smp_remote_device->curr_config_route_index,
curr_smp_phy->attached_sas_address,
FALSE
);
scif_cb_start_internal_io_task_schedule(
device_being_config->domain->controller,
scif_sas_controller_start_high_priority_io,
device_being_config->domain->controller
);
break;
}
}
}
void scif_sas_smp_remote_device_clean_route_table(
SCIF_SAS_REMOTE_DEVICE_T * fw_device
)
{
SCIF_SAS_SMP_PHY_T * smp_phy_being_config;
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"scif_sas_smp_remote_device_clean_route_table(0x%x) enter\n",
fw_device
));
fw_device->protocol_device.smp_device.curr_config_route_index++;
if ( fw_device->protocol_device.smp_device.curr_config_route_index >=
fw_device->protocol_device.smp_device.expander_route_indexes )
{
fw_device->protocol_device.smp_device.curr_config_route_index = 0;
do
{
fw_device->protocol_device.smp_device.current_activity_phy_index++;
if (fw_device->protocol_device.smp_device.current_activity_phy_index ==
fw_device->protocol_device.smp_device.number_of_phys)
fw_device->protocol_device.smp_device.current_activity_phy_index=0;
smp_phy_being_config =
scif_sas_smp_remote_device_find_smp_phy_by_id(
fw_device->protocol_device.smp_device.current_activity_phy_index,
&(fw_device->protocol_device.smp_device)
);
} while( smp_phy_being_config->routing_attribute != TABLE_ROUTING_ATTRIBUTE );
if ( smp_phy_being_config->phy_identifier !=
fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->phy_identifier)
{
if (smp_phy_being_config->config_route_table_index_anchor != 0)
fw_device->protocol_device.smp_device.curr_config_route_index =
smp_phy_being_config->config_route_table_index_anchor + 1;
else
fw_device->protocol_device.smp_device.curr_config_route_index = 0;
}
}
if ( !(fw_device->protocol_device.smp_device.current_activity_phy_index ==
fw_device->protocol_device.smp_device.config_route_smp_phy_anchor->phy_identifier
&& fw_device->protocol_device.smp_device.curr_config_route_index == 0)
)
{
scif_sas_smp_remote_device_clean_route_table_entry(fw_device);
}
else
{
fw_device->protocol_device.smp_device.is_route_table_cleaned = TRUE;
fw_device->protocol_device.smp_device.current_activity =
SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE;
scif_sas_domain_continue_discover(fw_device->domain);
}
}
void scif_sas_smp_remote_device_clean_route_table_entry(
SCIF_SAS_REMOTE_DEVICE_T * fw_device
)
{
SCI_SAS_ADDRESS_T empty_sas_address;
SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device =
&(fw_device->protocol_device.smp_device);
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"scif_sas_smp_remote_device_clean_route_table(0x%x) enter\n",
fw_device
));
empty_sas_address.high = 0;
empty_sas_address.low = 0;
scif_sas_smp_request_construct_config_route_info(
fw_device->domain->controller,
fw_device,
smp_remote_device->current_activity_phy_index,
smp_remote_device->curr_config_route_index,
empty_sas_address,
TRUE
);
scif_cb_start_internal_io_task_schedule(
fw_device->domain->controller,
scif_sas_controller_start_high_priority_io,
fw_device->domain->controller
);
}
void scif_sas_smp_remote_device_cancel_config_route_table_activity(
SCIF_SAS_REMOTE_DEVICE_T * fw_device
)
{
SCI_FAST_LIST_ELEMENT_T * element =
&(fw_device->protocol_device.smp_device.curr_config_route_destination_smp_phy->list_element);
SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL;
SCIF_SAS_REMOTE_DEVICE_T * curr_attached_device = NULL;
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"scif_sas_smp_remote_device_cancel_config_route_table_activity(0x%x) enter\n",
fw_device
));
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 (scif_sas_smp_remote_device_do_config_route_info(
fw_device, curr_smp_phy) == TRUE )
{
curr_attached_device = (SCIF_SAS_REMOTE_DEVICE_T *)
scif_domain_get_device_by_sas_address(
fw_device->domain, &(curr_smp_phy->attached_sas_address));
if (curr_attached_device != NULL)
curr_attached_device->is_currently_discovered = FALSE;
}
}
}
void scif_sas_smp_remote_device_cancel_smp_activity(
SCIF_SAS_REMOTE_DEVICE_T * fw_device
)
{
SCIF_LOG_TRACE((
sci_base_object_get_logger(fw_device),
SCIF_LOG_OBJECT_REMOTE_DEVICE | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
"scif_sas_smp_remote_device_cancel_smp_activity(0x%x) enter\n",
fw_device
));
scif_sas_domain_terminate_requests(
fw_device->domain, fw_device, NULL, NULL
);
if (fw_device->protocol_device.smp_device.current_activity ==
SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE)
scif_sas_smp_remote_device_cancel_config_route_table_activity(fw_device);
scif_sas_smp_remote_device_clear(fw_device);
}
U8 scif_sas_smp_remote_device_get_config_route_table_method(
SCIF_SAS_REMOTE_DEVICE_T * fw_device
)
{
U8 config_route_table_method;
config_route_table_method = SCIF_SAS_CONFIG_ROUTE_TABLE_ALL_PHYS;
return config_route_table_method;
}
void scif_sas_smp_remote_device_start_target_reset(
SCIF_SAS_REMOTE_DEVICE_T * expander_device,
SCIF_SAS_REMOTE_DEVICE_T * target_device,
SCIF_SAS_REQUEST_T * fw_request
)
{
SCIF_SAS_CONTROLLER_T * fw_controller = expander_device->domain->controller;
expander_device->protocol_device.smp_device.current_activity =
SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_TARGET_RESET;
expander_device->protocol_device.smp_device.current_smp_request =
SMP_FUNCTION_PHY_CONTROL;
expander_device->protocol_device.smp_device.current_activity_phy_index =
target_device->expander_phy_identifier;
fw_controller->state_handlers->start_high_priority_io_handler(
(SCI_BASE_CONTROLLER_T*) fw_controller,
(SCI_BASE_REMOTE_DEVICE_T*) expander_device,
(SCI_BASE_REQUEST_T*) fw_request,
SCI_CONTROLLER_INVALID_IO_TAG
);
}