#include <sys/cdefs.h>
#include <dev/isci/types.h>
#include <dev/isci/scil/sci_util.h>
#include <dev/isci/scil/scic_controller.h>
#include <dev/isci/scil/scic_port.h>
#include <dev/isci/scil/scic_phy.h>
#include <dev/isci/scil/scic_remote_device.h>
#include <dev/isci/scil/scic_user_callback.h>
#include <dev/isci/scil/scic_sds_pci.h>
#include <dev/isci/scil/scic_sds_library.h>
#include <dev/isci/scil/scic_sds_controller.h>
#include <dev/isci/scil/scic_sds_controller_registers.h>
#include <dev/isci/scil/scic_sds_port.h>
#include <dev/isci/scil/scic_sds_phy.h>
#include <dev/isci/scil/scic_sds_remote_device.h>
#include <dev/isci/scil/scic_sds_request.h>
#include <dev/isci/scil/scic_sds_logger.h>
#include <dev/isci/scil/scic_sds_port_configuration_agent.h>
#include <dev/isci/scil/scu_constants.h>
#include <dev/isci/scil/scu_event_codes.h>
#include <dev/isci/scil/scu_completion_codes.h>
#include <dev/isci/scil/scu_task_context.h>
#include <dev/isci/scil/scu_remote_node_context.h>
#include <dev/isci/scil/scu_unsolicited_frame.h>
#include <dev/isci/scil/intel_pci.h>
#include <dev/isci/scil/scic_sgpio.h>
#include <dev/isci/scil/scic_sds_phy_registers.h>
#define SCU_CONTEXT_RAM_INIT_STALL_TIME 200
#define SCIC_SDS_CONTROLLER_MIN_TIMER_COUNT 3
#define SCIC_SDS_CONTROLLER_MAX_TIMER_COUNT 3
#define SCU_MAX_ZPT_DWORD_INDEX 131
#define SCIC_SDS_CONTROLLER_PHY_START_TIMEOUT 100
#define SCIC_SDS_CONTROLLER_POWER_CONTROL_INTERVAL 500
#define COMPLETION_QUEUE_CYCLE_BIT(x) ((x) & 0x80000000)
#define NORMALIZE_GET_POINTER(x) \
((x) & SMU_COMPLETION_QUEUE_GET_POINTER_MASK)
#define NORMALIZE_PUT_POINTER(x) \
((x) & SMU_COMPLETION_QUEUE_PUT_POINTER_MASK)
#define NORMALIZE_GET_POINTER_CYCLE_BIT(x) \
(((U32)(SMU_CQGR_CYCLE_BIT & (x))) << (31 - SMU_COMPLETION_QUEUE_GET_CYCLE_BIT_SHIFT))
#define NORMALIZE_EVENT_POINTER(x) \
( \
((U32)((x) & SMU_COMPLETION_QUEUE_GET_EVENT_POINTER_MASK)) \
>> SMU_COMPLETION_QUEUE_GET_EVENT_POINTER_SHIFT \
)
#define INCREMENT_COMPLETION_QUEUE_GET(controller, index, cycle) \
INCREMENT_QUEUE_GET( \
(index), \
(cycle), \
(controller)->completion_queue_entries, \
SMU_CQGR_CYCLE_BIT \
)
#define INCREMENT_EVENT_QUEUE_GET(controller, index, cycle) \
INCREMENT_QUEUE_GET( \
(index), \
(cycle), \
(controller)->completion_event_entries, \
SMU_CQGR_EVENT_CYCLE_BIT \
)
static
void scic_sds_controller_phy_startup_timeout_handler(
void *controller
)
{
SCI_STATUS status;
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
this_controller->phy_startup_timer_pending = FALSE;
status = SCI_FAILURE;
while (status != SCI_SUCCESS)
{
status = scic_sds_controller_start_next_phy(this_controller);
}
}
static
SCI_STATUS scic_sds_controller_initialize_phy_startup(
SCIC_SDS_CONTROLLER_T *this_controller
)
{
this_controller->phy_startup_timer = scic_cb_timer_create(
this_controller,
scic_sds_controller_phy_startup_timeout_handler,
this_controller
);
if (this_controller->phy_startup_timer == NULL)
{
return SCI_FAILURE_INSUFFICIENT_RESOURCES;
}
else
{
this_controller->next_phy_to_start = 0;
this_controller->phy_startup_timer_pending = FALSE;
}
return SCI_SUCCESS;
}
void scic_sds_controller_initialize_power_control(
SCIC_SDS_CONTROLLER_T *this_controller
)
{
this_controller->power_control.timer = scic_cb_timer_create(
this_controller,
scic_sds_controller_power_control_timer_handler,
this_controller
);
memset(
this_controller->power_control.requesters,
0,
sizeof(this_controller->power_control.requesters)
);
this_controller->power_control.phys_waiting = 0;
this_controller->power_control.remote_devices_granted_power = 0;
}
#define SCU_REMOTE_NODE_CONTEXT_ALIGNMENT (32)
#define SCU_TASK_CONTEXT_ALIGNMENT (256)
#define SCU_UNSOLICITED_FRAME_ADDRESS_ALIGNMENT (64)
#define SCU_UNSOLICITED_FRAME_BUFFER_ALIGNMENT (1024)
#define SCU_UNSOLICITED_FRAME_HEADER_ALIGNMENT (64)
void scic_sds_controller_build_memory_descriptor_table(
SCIC_SDS_CONTROLLER_T *this_controller
)
{
sci_base_mde_construct(
&this_controller->memory_descriptors[SCU_MDE_COMPLETION_QUEUE],
SCU_COMPLETION_RAM_ALIGNMENT,
(sizeof(U32) * this_controller->completion_queue_entries),
(SCI_MDE_ATTRIBUTE_CACHEABLE | SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS)
);
sci_base_mde_construct(
&this_controller->memory_descriptors[SCU_MDE_REMOTE_NODE_CONTEXT],
SCU_REMOTE_NODE_CONTEXT_ALIGNMENT,
this_controller->remote_node_entries * sizeof(SCU_REMOTE_NODE_CONTEXT_T),
SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS
);
sci_base_mde_construct(
&this_controller->memory_descriptors[SCU_MDE_TASK_CONTEXT],
SCU_TASK_CONTEXT_ALIGNMENT,
this_controller->task_context_entries * sizeof(SCU_TASK_CONTEXT_T),
SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS
);
scic_sds_unsolicited_frame_control_set_address_table_count(
&this_controller->uf_control
);
sci_base_mde_construct(
&this_controller->memory_descriptors[SCU_MDE_UF_BUFFER],
SCU_UNSOLICITED_FRAME_BUFFER_ALIGNMENT,
scic_sds_unsolicited_frame_control_get_mde_size(this_controller->uf_control),
SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS
);
}
SCI_STATUS scic_sds_controller_validate_memory_descriptor_table(
SCIC_SDS_CONTROLLER_T *this_controller
)
{
BOOL mde_list_valid;
mde_list_valid = sci_base_mde_is_valid(
&this_controller->memory_descriptors[SCU_MDE_COMPLETION_QUEUE],
SCU_COMPLETION_RAM_ALIGNMENT,
(sizeof(U32) * this_controller->completion_queue_entries),
(SCI_MDE_ATTRIBUTE_CACHEABLE | SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS)
);
if (mde_list_valid == FALSE)
return SCI_FAILURE_UNSUPPORTED_INFORMATION_FIELD;
mde_list_valid = sci_base_mde_is_valid(
&this_controller->memory_descriptors[SCU_MDE_REMOTE_NODE_CONTEXT],
SCU_REMOTE_NODE_CONTEXT_ALIGNMENT,
this_controller->remote_node_entries * sizeof(SCU_REMOTE_NODE_CONTEXT_T),
SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS
);
if (mde_list_valid == FALSE)
return SCI_FAILURE_UNSUPPORTED_INFORMATION_FIELD;
mde_list_valid = sci_base_mde_is_valid(
&this_controller->memory_descriptors[SCU_MDE_TASK_CONTEXT],
SCU_TASK_CONTEXT_ALIGNMENT,
this_controller->task_context_entries * sizeof(SCU_TASK_CONTEXT_T),
SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS
);
if (mde_list_valid == FALSE)
return SCI_FAILURE_UNSUPPORTED_INFORMATION_FIELD;
mde_list_valid = sci_base_mde_is_valid(
&this_controller->memory_descriptors[SCU_MDE_UF_BUFFER],
SCU_UNSOLICITED_FRAME_BUFFER_ALIGNMENT,
scic_sds_unsolicited_frame_control_get_mde_size(this_controller->uf_control),
SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS
);
if (mde_list_valid == FALSE)
return SCI_FAILURE_UNSUPPORTED_INFORMATION_FIELD;
return SCI_SUCCESS;
}
void scic_sds_controller_ram_initialization(
SCIC_SDS_CONTROLLER_T *this_controller
)
{
SCI_PHYSICAL_MEMORY_DESCRIPTOR_T *mde;
mde = &this_controller->memory_descriptors[SCU_MDE_COMPLETION_QUEUE];
this_controller->completion_queue = (U32*) mde->virtual_address;
SMU_CQBAR_WRITE(this_controller, mde->physical_address);
mde = &this_controller->memory_descriptors[SCU_MDE_REMOTE_NODE_CONTEXT];
this_controller->remote_node_context_table = (SCU_REMOTE_NODE_CONTEXT_T *)
mde->virtual_address;
SMU_RNCBAR_WRITE(this_controller, mde->physical_address);
mde = &this_controller->memory_descriptors[SCU_MDE_TASK_CONTEXT];
this_controller->task_context_table = (SCU_TASK_CONTEXT_T *)
mde->virtual_address;
SMU_HTTBAR_WRITE(this_controller, mde->physical_address);
mde = &this_controller->memory_descriptors[SCU_MDE_UF_BUFFER];
scic_sds_unsolicited_frame_control_construct(
&this_controller->uf_control, mde, this_controller
);
SCU_UFHBAR_WRITE(
this_controller,
this_controller->uf_control.headers.physical_address);
SCU_PUFATHAR_WRITE(
this_controller,
this_controller->uf_control.address_table.physical_address);
SCU_SECR0_WRITE(
this_controller,
(SIGNLE_BIT_ERROR_CORRECTION_ENABLE
| MULTI_BIT_ERROR_REPORTING_ENABLE
| SINGLE_BIT_ERROR_REPORTING_ENABLE) );
SCU_SECR1_WRITE(
this_controller,
(SIGNLE_BIT_ERROR_CORRECTION_ENABLE
| MULTI_BIT_ERROR_REPORTING_ENABLE
| SINGLE_BIT_ERROR_REPORTING_ENABLE) );
}
void scic_sds_controller_assign_task_entries(
SCIC_SDS_CONTROLLER_T *this_controller
)
{
U32 task_assignment;
task_assignment = SMU_TCA_READ(this_controller, 0);
task_assignment =
(
task_assignment
| (SMU_TCA_GEN_VAL(STARTING, 0))
| (SMU_TCA_GEN_VAL(ENDING, this_controller->task_context_entries - 1))
| (SMU_TCA_GEN_BIT(RANGE_CHECK_ENABLE))
);
SMU_TCA_WRITE(this_controller, 0, task_assignment);
}
void scic_sds_controller_initialize_completion_queue(
SCIC_SDS_CONTROLLER_T *this_controller
)
{
U32 index;
U32 completion_queue_control_value;
U32 completion_queue_get_value;
U32 completion_queue_put_value;
this_controller->completion_queue_get = 0;
completion_queue_control_value = (
SMU_CQC_QUEUE_LIMIT_SET(this_controller->completion_queue_entries - 1)
| SMU_CQC_EVENT_LIMIT_SET(this_controller->completion_event_entries - 1)
);
SMU_CQC_WRITE(this_controller, completion_queue_control_value);
completion_queue_get_value = (
(SMU_CQGR_GEN_VAL(POINTER, 0))
| (SMU_CQGR_GEN_VAL(EVENT_POINTER, 0))
| (SMU_CQGR_GEN_BIT(ENABLE))
| (SMU_CQGR_GEN_BIT(EVENT_ENABLE))
);
SMU_CQGR_WRITE(this_controller, completion_queue_get_value);
this_controller->completion_queue_get = completion_queue_get_value;
completion_queue_put_value = (
(SMU_CQPR_GEN_VAL(POINTER, 0))
| (SMU_CQPR_GEN_VAL(EVENT_POINTER, 0))
);
SMU_CQPR_WRITE(this_controller, completion_queue_put_value);
for (index = 0; index < this_controller->completion_queue_entries; index++)
{
this_controller->completion_queue[index] = 0x80000000;
}
}
void scic_sds_controller_initialize_unsolicited_frame_queue(
SCIC_SDS_CONTROLLER_T *this_controller
)
{
U32 frame_queue_control_value;
U32 frame_queue_get_value;
U32 frame_queue_put_value;
frame_queue_control_value =
SCU_UFQC_GEN_VAL(QUEUE_SIZE, this_controller->uf_control.address_table.count);
SCU_UFQC_WRITE(this_controller, frame_queue_control_value);
frame_queue_get_value = (
SCU_UFQGP_GEN_VAL(POINTER, 0)
| SCU_UFQGP_GEN_BIT(ENABLE_BIT)
);
SCU_UFQGP_WRITE(this_controller, frame_queue_get_value);
frame_queue_put_value = SCU_UFQPP_GEN_VAL(POINTER, 0);
SCU_UFQPP_WRITE(this_controller, frame_queue_put_value);
}
void scic_sds_controller_enable_port_task_scheduler(
SCIC_SDS_CONTROLLER_T *this_controller
)
{
U32 port_task_scheduler_value;
port_task_scheduler_value = SCU_PTSGCR_READ(this_controller);
port_task_scheduler_value |=
(SCU_PTSGCR_GEN_BIT(ETM_ENABLE) | SCU_PTSGCR_GEN_BIT(PTSG_ENABLE));
SCU_PTSGCR_WRITE(this_controller, port_task_scheduler_value);
}
#ifdef ARLINGTON_BUILD
void scic_sds_controller_lex_status_read_fence(
SCIC_SDS_CONTROLLER_T *this_controller
)
{
U32 lex_status;
lex_status = lex_register_read(
this_controller, this_controller->lex_registers + 0xC4);
SCIC_LOG_TRACE((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_CONTROLLER,
"Controller 0x%x lex_status = 0x%08x\n",
this_controller, lex_status
));
}
void scic_sds_controller_lex_atux_initialization(
SCIC_SDS_CONTROLLER_T *this_controller
)
{
lex_register_write(
this_controller, this_controller->lex_registers + 0x28, 0x0020FFFF) ;
lex_register_write(
this_controller, this_controller->lex_registers + 0xC0, 0x00000700);
scic_sds_controller_lex_status_read_fence(this_controller);
lex_register_write(
this_controller, this_controller->lex_registers + 0x70, 0x00000002);
lex_register_write(
this_controller, this_controller->lex_registers + 0xC0, 0x00000300);
scic_sds_controller_lex_status_read_fence(this_controller);
lex_register_write(
this_controller, this_controller->lex_registers + 0x28, 0x0000FFFF);
scic_sds_controller_afe_initialization(this_controller);
scic_sds_controller_lex_status_read_fence(this_controller);
#if 0
lex_register_write(
this_controller, this_controller->lex_registers + 0x28, 0x0000FFFF);
#endif
lex_register_write(
this_controller, this_controller->lex_registers + 0x28, 0x0040FFFF) ;
scic_sds_controller_afe_initialization(this_controller);
scic_sds_controller_lex_status_read_fence(this_controller);
#if 0
lex_register_write(
this_controller, this_controller->lex_registers + 0x28, 0x0040FFFF) ;
#endif
lex_register_write(
this_controller, this_controller->lex_registers + 0xC0, 0x00000100);
scic_sds_controller_lex_status_read_fence(this_controller);
lex_register_write(
this_controller, this_controller->lex_registers + 0xC0, 0x00000000);
scic_sds_controller_lex_status_read_fence(this_controller);
#if !defined(DISABLE_INTERRUPTS)
lex_register_write(
this_controller, this_controller->lex_registers + 0xC0, 0x00000800);
scic_sds_controller_lex_status_read_fence(this_controller);
#endif
#if 0
lex_register_write(
this_controller, this_controller->lex_registers + 0xC0, 0x27800000);
#endif
lex_register_write(
this_controller, this_controller->lex_registers + 0x28, 0x0000FF77);
lex_register_write(
this_controller, this_controller->lex_registers + 0x28, 0x0000FF55);
lex_register_write(
this_controller, this_controller->lex_registers + 0x28, 0x0000FF11);
lex_register_write(
this_controller, this_controller->lex_registers + 0x28, 0x0000FF00);
lex_register_write(
this_controller, this_controller->lex_registers + 0x28, 0x0003FF00);
}
#endif
#ifdef ARLINGTON_BUILD
void scic_sds_controller_enable_chipwatch(
SCIC_SDS_CONTROLLER_T *this_controller
)
{
lex_register_write(
this_controller, this_controller->lex_registers + 0x88, 0x09090909);
lex_register_write(
this_controller, this_controller->lex_registers + 0x8C, 0xcac9c862);
}
#endif
#define AFE_REGISTER_WRITE_DELAY 10
#if defined(ARLINGTON_BUILD)
void scic_sds_controller_afe_initialization(
SCIC_SDS_CONTROLLER_T *this_controller
)
{
scu_afe_register_write(
this_controller, afe_pll_control, 0x00247506);
scu_afe_register_write(
this_controller, afe_dfx_transceiver_status_clear, 0x00000000);
scu_afe_register_write(
this_controller, afe_transceiver_control0[0], 0x0700141e);
scu_afe_register_write(this_controller, afe_pll_control, 0x00200506);
scu_afe_register_write(this_controller, afe_pll_dfx_control, 0x10000080);
scu_afe_register_write(this_controller, afe_bias_control[0], 0x00124814);
scu_afe_register_write(this_controller, afe_bias_control[1], 0x24900000);
scu_afe_register_write(
this_controller, afe_transceiver_control0[0], 0x0702941e);
scu_afe_register_write(
this_controller, afe_transceiver_control1[0], 0x0000000a);
scu_afe_register_write(
this_controller, afe_transceiver_equalization_control[0], 0x00ba2223);
scu_afe_register_write(
this_controller, reserved_0028_003c[2], 0x00000000);
scu_afe_register_write(
this_controller, afe_dfx_transmit_control_register[0], 0x03815428);
scu_afe_register_write(
this_controller, afe_dfx_transceiver_status_clear, 0x00000010);
scu_afe_register_write(this_controller, afe_pll_control, 0x00200504);
scu_afe_register_write(this_controller, afe_pll_control, 0x00200505);
scu_afe_register_write(this_controller, afe_pll_control, 0x00200501);
while ((scu_afe_register_read(this_controller, afe_common_status) & 0x03) != 0x03)
{
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
}
scu_afe_register_write(
this_controller, afe_transceiver_control0[0], 0x07028c11);
}
#elif defined(PLEASANT_RIDGE_BUILD)
void scic_sds_controller_afe_initialization(
SCIC_SDS_CONTROLLER_T *this_controller
)
{
U32 afe_status;
U32 phy_id;
#if defined(SPREADSHEET_AFE_SETTINGS)
scu_afe_register_write(
this_controller, afe_dfx_master_control0, 0x0000000f);
scu_afe_register_write(
this_controller, afe_bias_control, 0x0000aa00);
scu_afe_register_write(
this_controller, afe_pll_control0, 0x80000908);
do
{
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
afe_status = scu_afe_register_read(
this_controller, afe_common_block_status);
}
while((afe_status & 0x00001000) == 0);
for (phy_id = 0; phy_id < SCI_MAX_PHYS; phy_id++)
{
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_channel_control, 0x00000157);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x38016d1a);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control1, 0x01501014);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_tx_control, 0x00000000);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control0, 0x000bdd08);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control1, 0x000ffc00);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control2, 0x000b7c09);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control3, 0x000afc6e);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_tx_ssc_control, 0x00000000);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_rx_ssc_control0, 0x3208903f);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_channel_control, 0x00000154);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x3801611a);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x3801631a);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x38016318);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x38016319);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x38016319);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
}
scu_afe_register_write(
this_controller, afe_dfx_master_control0, 0x00010f00);
#else
scu_afe_register_write(
this_controller, afe_dfx_master_control0, 0x0081000f);
scu_afe_register_write(
this_controller, afe_bias_control, 0x0000aa00);
scu_afe_register_write(
this_controller, afe_pll_control0, 0x80000908);
do
{
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
afe_status = scu_afe_register_read(
this_controller, afe_common_block_status);
}
while((afe_status & 0x00001000) == 0);
scu_afe_register_write(
this_controller, afe_dfx_master_control1, 0x00000000);
scu_afe_register_write(
this_controller, afe_pmsn_master_control0, 0x7bd316ad);
for (phy_id = 0; phy_id < SCI_MAX_PHYS; phy_id++)
{
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_channel_control, 0x00000174);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_tx_ssc_control, 0x00030000);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x0000651a);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00006518);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00006518);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
#if 0
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_tx_control, 0x00000000);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control0, 0x000bdd08);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control1, 0x000ffc00);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control2, 0x000b7c09);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control3, 0x000afc6e);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_channel_control, 0x00000154);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_dfx_rx_control1, 0x00000080);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_dfx_rx_control1, 0x01041042);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_rx_ssc_control0, 0x320891bf);
#endif
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00006118);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00006108);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_rx_ssc_control0, 0x0317108f);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control1, 0x01e00021);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00006109);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00006009);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00006209);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
}
scu_afe_register_write(
this_controller, afe_dfx_master_control0, 0x00010f00);
#endif
}
#elif defined(PBG_HBA_A0_BUILD) || defined(PBG_HBA_A2_BUILD) || defined(PBG_HBA_BETA_BUILD) || defined(PBG_BUILD)
void scic_sds_controller_afe_initialization(
SCIC_SDS_CONTROLLER_T *this_controller
)
{
U32 afe_status;
U32 phy_id;
U8 cable_selection_mask;
if (
(this_controller->pci_revision != SCIC_SDS_PCI_REVISION_A0)
&& (this_controller->pci_revision != SCIC_SDS_PCI_REVISION_A2)
&& (this_controller->pci_revision != SCIC_SDS_PCI_REVISION_B0)
&& (this_controller->pci_revision != SCIC_SDS_PCI_REVISION_C0)
&& (this_controller->pci_revision != SCIC_SDS_PCI_REVISION_C1)
)
{
ASSERT(FALSE);
this_controller->pci_revision = SCIC_SDS_PCI_REVISION_C1;
}
cable_selection_mask =
this_controller->oem_parameters.sds1.controller.cable_selection_mask;
scu_afe_register_write(
this_controller, afe_dfx_master_control0, 0x0081000f);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
if (
(this_controller->pci_revision == SCIC_SDS_PCI_REVISION_B0)
|| (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C0)
|| (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C1)
)
{
scu_afe_register_write(
this_controller, afe_pmsn_master_control2, 0x0007FFFF);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
}
if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A0)
scu_afe_register_write(this_controller, afe_bias_control, 0x00005500);
else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A2)
scu_afe_register_write(this_controller, afe_bias_control, 0x00005A00);
else if ( (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_B0)
|| (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C0) )
scu_afe_register_write(this_controller, afe_bias_control, 0x00005F00);
else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C1)
scu_afe_register_write(this_controller, afe_bias_control, 0x00005500);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
if ( (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A0)
|| (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A2) )
{
scu_afe_register_write(this_controller, afe_pll_control0, 0x80040908);
}
else if ( (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_B0)
|| (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C0) )
{
scu_afe_register_write(this_controller, afe_pll_control0, 0x80040A08);
}
else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C1)
{
scu_afe_register_write(this_controller, afe_pll_control0, 0x80000b08);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
scu_afe_register_write(this_controller, afe_pll_control0, 0x00000b08);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
scu_afe_register_write(this_controller, afe_pll_control0, 0x80000b08);
}
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
do
{
afe_status = scu_afe_register_read(
this_controller, afe_common_block_status);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
}
while((afe_status & 0x00001000) == 0);
if ( (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A0)
|| (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A2) )
{
scu_afe_register_write(
this_controller, afe_pmsn_master_control0, 0x7bcc96ad);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
}
for (phy_id = 0; phy_id < SCI_MAX_PHYS; phy_id++)
{
U8 cable_length_long = (cable_selection_mask >> phy_id) & 1;
U8 cable_length_medium = (cable_selection_mask >> (phy_id + 4)) & 1;
if ( (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A0)
|| (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A2) )
{
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00004512
);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control1, 0x0050100F
);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
}
else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_B0)
{
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_tx_ssc_control, 0x00030000
);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
}
else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C0)
{
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_tx_ssc_control, 0x00010202
);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00014500
);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
}
else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C1)
{
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_tx_ssc_control, 0x00010202
);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x0001C500
);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
}
if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A0)
{
scu_afe_register_write(
this_controller,
scu_afe_xcvr[phy_id].afe_channel_control,
0x000003D4
);
}
else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A2)
{
scu_afe_register_write(
this_controller,
scu_afe_xcvr[phy_id].afe_channel_control,
0x000003F0
);
}
else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_B0)
{
scu_afe_register_write(
this_controller,
scu_afe_xcvr[phy_id].afe_channel_control,
0x000003d7
);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
scu_afe_register_write(
this_controller,
scu_afe_xcvr[phy_id].afe_channel_control,
0x000003d4
);
}
else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C0)
{
scu_afe_register_write(
this_controller,
scu_afe_xcvr[phy_id].afe_channel_control,
0x000001e7
);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
scu_afe_register_write(
this_controller,
scu_afe_xcvr[phy_id].afe_channel_control,
0x000001e4
);
}
else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C1)
{
scu_afe_register_write(
this_controller,
scu_afe_xcvr[phy_id].afe_channel_control,
cable_length_long ? 0x000002F7 :
cable_length_medium ? 0x000001F7 : 0x000001F7
);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
scu_afe_register_write(
this_controller,
scu_afe_xcvr[phy_id].afe_channel_control,
cable_length_long ? 0x000002F4 :
cable_length_medium ? 0x000001F4 : 0x000001F4
);
}
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
if ( (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A0)
|| (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A2) )
{
scu_afe_register_write(
this_controller,
scu_afe_xcvr[phy_id].afe_tx_control,
0x00040000
);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
}
if ( (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A0)
|| (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A2)
|| (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_B0) )
{
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00004100);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
}
else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C0)
{
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00014100);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
}
else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C1)
{
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x0001c100);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
}
if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A0)
{
scu_afe_register_write(
this_controller,
scu_afe_xcvr[phy_id].afe_rx_ssc_control0,
0x3F09983F
);
}
else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A2)
{
scu_afe_register_write(
this_controller,
scu_afe_xcvr[phy_id].afe_rx_ssc_control0,
0x3F11103F
);
}
else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_B0)
{
scu_afe_register_write(
this_controller,
scu_afe_xcvr[phy_id].afe_rx_ssc_control0,
0x3F11103F
);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_tx_control, 0x00040000);
}
else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C0)
{
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control1, 0x01400c0f);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_rx_ssc_control0, 0x3f6f103f);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_tx_control, 0x00040000);
}
else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C1)
{
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control1,
cable_length_long ? 0x01500C0C :
cable_length_medium ? 0x01400C0D : 0x02400C0D
);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_dfx_rx_control1, 0x000003e0);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_rx_ssc_control0,
cable_length_long ? 0x33091C1F :
cable_length_medium ? 0x3315181F : 0x2B17161F
);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_tx_control, 0x00040000);
}
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control0,
this_controller->oem_parameters.sds1.phys[phy_id].afe_tx_amp_control0
);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control1,
this_controller->oem_parameters.sds1.phys[phy_id].afe_tx_amp_control1
);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control2,
this_controller->oem_parameters.sds1.phys[phy_id].afe_tx_amp_control2
);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
scu_afe_register_write(
this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control3,
this_controller->oem_parameters.sds1.phys[phy_id].afe_tx_amp_control3
);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
}
scu_afe_register_write(
this_controller, afe_dfx_master_control0, 0x00010f00);
scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
}
#else
#error "Unsupported board type"
#endif
static
void scic_sds_controller_transition_to_ready(
SCIC_SDS_CONTROLLER_T *this_controller,
SCI_STATUS status
)
{
SCIC_LOG_TRACE((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_CONTROLLER,
"scic_sds_controller_transition_to_ready(0x%x, 0x%x) enter\n",
this_controller, status
));
if (this_controller->parent.state_machine.current_state_id
== SCI_BASE_CONTROLLER_STATE_STARTING)
{
sci_base_state_machine_change_state(
scic_sds_controller_get_base_state_machine(this_controller),
SCI_BASE_CONTROLLER_STATE_READY
);
scic_cb_controller_start_complete(this_controller, status);
}
}
void scic_sds_controller_timeout_handler(
SCI_CONTROLLER_HANDLE_T controller
)
{
SCI_BASE_CONTROLLER_STATES current_state;
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
current_state = sci_base_state_machine_get_state(
scic_sds_controller_get_base_state_machine(this_controller)
);
if (current_state == SCI_BASE_CONTROLLER_STATE_STARTING)
{
scic_sds_controller_transition_to_ready(
this_controller, SCI_FAILURE_TIMEOUT
);
}
else if (current_state == SCI_BASE_CONTROLLER_STATE_STOPPING)
{
sci_base_state_machine_change_state(
scic_sds_controller_get_base_state_machine(this_controller),
SCI_BASE_CONTROLLER_STATE_FAILED
);
scic_cb_controller_stop_complete(controller, SCI_FAILURE_TIMEOUT);
}
else
{
SCIC_LOG_ERROR((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_CONTROLLER,
"Controller timer fired when controller was not in a state being timed.\n"
));
}
}
SCI_STATUS scic_sds_controller_stop_ports(
SCIC_SDS_CONTROLLER_T *this_controller
)
{
U32 index;
SCI_STATUS status;
SCI_STATUS port_status;
status = SCI_SUCCESS;
for (index = 0; index < this_controller->logical_port_entries; index++)
{
port_status = this_controller->port_table[index].
state_handlers->parent.stop_handler(&this_controller->port_table[index].parent);
if (
(port_status != SCI_SUCCESS)
&& (port_status != SCI_FAILURE_INVALID_STATE)
)
{
status = SCI_FAILURE;
SCIC_LOG_WARNING((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT,
"Controller stop operation failed to stop port %d because of status %d.\n",
this_controller->port_table[index].logical_port_index, port_status
));
}
}
return status;
}
static
void scic_sds_controller_phy_timer_start(
SCIC_SDS_CONTROLLER_T *this_controller
)
{
scic_cb_timer_start(
this_controller,
this_controller->phy_startup_timer,
SCIC_SDS_CONTROLLER_PHY_START_TIMEOUT
);
this_controller->phy_startup_timer_pending = TRUE;
}
void scic_sds_controller_phy_timer_stop(
SCIC_SDS_CONTROLLER_T *this_controller
)
{
scic_cb_timer_stop(
this_controller,
this_controller->phy_startup_timer
);
this_controller->phy_startup_timer_pending = FALSE;
}
BOOL scic_sds_controller_is_start_complete(
SCIC_SDS_CONTROLLER_T *this_controller
)
{
U8 index;
for (index = 0; index < SCI_MAX_PHYS; index++)
{
SCIC_SDS_PHY_T *the_phy = & this_controller->phy_table[index];
if (
(
this_controller->oem_parameters.sds1.controller.mode_type
== SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE
)
|| (
(
this_controller->oem_parameters.sds1.controller.mode_type
== SCIC_PORT_MANUAL_CONFIGURATION_MODE
)
&& (scic_sds_phy_get_port(the_phy) != SCI_INVALID_HANDLE)
)
)
{
if (
(
(the_phy->is_in_link_training == FALSE)
&& (the_phy->parent.state_machine.current_state_id
== SCI_BASE_PHY_STATE_INITIAL)
)
|| (
(the_phy->is_in_link_training == FALSE)
&& (the_phy->parent.state_machine.current_state_id
== SCI_BASE_PHY_STATE_STOPPED)
)
|| (
(the_phy->is_in_link_training == TRUE)
&& (the_phy->parent.state_machine.current_state_id
== SCI_BASE_PHY_STATE_STARTING)
)
|| (
this_controller->port_agent.phy_ready_mask
!= this_controller->port_agent.phy_configured_mask
)
)
{
return FALSE;
}
}
}
return TRUE;
}
SCI_STATUS scic_sds_controller_start_next_phy(
SCIC_SDS_CONTROLLER_T *this_controller
)
{
SCI_STATUS status;
status = SCI_SUCCESS;
if (this_controller->phy_startup_timer_pending == FALSE)
{
if (this_controller->next_phy_to_start == SCI_MAX_PHYS)
{
if (scic_sds_controller_is_start_complete(this_controller) == TRUE)
{
scic_sds_controller_transition_to_ready(
this_controller, SCI_SUCCESS
);
}
}
else
{
SCIC_SDS_PHY_T * the_phy;
the_phy = &this_controller->phy_table[this_controller->next_phy_to_start];
if (
this_controller->oem_parameters.sds1.controller.mode_type
== SCIC_PORT_MANUAL_CONFIGURATION_MODE
)
{
if (scic_sds_phy_get_port(the_phy) == SCI_INVALID_HANDLE)
{
this_controller->next_phy_to_start++;
return scic_sds_controller_start_next_phy(this_controller);
}
}
status = scic_phy_start(the_phy);
if (status == SCI_SUCCESS)
{
scic_sds_controller_phy_timer_start(this_controller);
}
else
{
SCIC_LOG_WARNING((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PHY,
"Controller stop operation failed to stop phy %d because of status %d.\n",
this_controller->phy_table[this_controller->next_phy_to_start].phy_index,
status
));
}
this_controller->next_phy_to_start++;
}
}
return status;
}
SCI_STATUS scic_sds_controller_stop_phys(
SCIC_SDS_CONTROLLER_T *this_controller
)
{
U32 index;
SCI_STATUS status;
SCI_STATUS phy_status;
status = SCI_SUCCESS;
for (index = 0; index < SCI_MAX_PHYS; index++)
{
phy_status = scic_phy_stop(&this_controller->phy_table[index]);
if (
(phy_status != SCI_SUCCESS)
&& (phy_status != SCI_FAILURE_INVALID_STATE)
)
{
status = SCI_FAILURE;
SCIC_LOG_WARNING((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PHY,
"Controller stop operation failed to stop phy %d because of status %d.\n",
this_controller->phy_table[index].phy_index, phy_status
));
}
}
return status;
}
SCI_STATUS scic_sds_controller_stop_devices(
SCIC_SDS_CONTROLLER_T *this_controller
)
{
U32 index;
SCI_STATUS status;
SCI_STATUS device_status;
status = SCI_SUCCESS;
for (index = 0; index < this_controller->remote_node_entries; index++)
{
if (this_controller->device_table[index] != SCI_INVALID_HANDLE)
{
device_status = scic_remote_device_stop(this_controller->device_table[index], 0);
if (
(device_status != SCI_SUCCESS)
&& (device_status != SCI_FAILURE_INVALID_STATE)
)
{
SCIC_LOG_WARNING((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_SSP_REMOTE_TARGET,
"Controller stop operation failed to stop device 0x%x because of status %d.\n",
this_controller->device_table[index], device_status
));
}
}
}
return status;
}
static
void scic_sds_controller_power_control_timer_start(
SCIC_SDS_CONTROLLER_T *this_controller
)
{
scic_cb_timer_start(
this_controller, this_controller->power_control.timer,
SCIC_SDS_CONTROLLER_POWER_CONTROL_INTERVAL
);
this_controller->power_control.timer_started = TRUE;
}
static
void scic_sds_controller_power_control_timer_stop(
SCIC_SDS_CONTROLLER_T *this_controller
)
{
if (this_controller->power_control.timer_started)
{
scic_cb_timer_stop(
this_controller, this_controller->power_control.timer
);
this_controller->power_control.timer_started = FALSE;
}
}
static
void scic_sds_controller_power_control_timer_restart(
SCIC_SDS_CONTROLLER_T *this_controller
)
{
scic_sds_controller_power_control_timer_stop(this_controller);
scic_sds_controller_power_control_timer_start(this_controller);
}
void scic_sds_controller_power_control_timer_handler(
void *controller
)
{
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
this_controller->power_control.remote_devices_granted_power = 0;
if (this_controller->power_control.phys_waiting == 0)
{
this_controller->power_control.timer_started = FALSE;
}
else
{
SCIC_SDS_PHY_T *the_phy = NULL;
U8 i;
for (i=0;
(i < SCI_MAX_PHYS)
&& (this_controller->power_control.phys_waiting != 0);
i++)
{
if (this_controller->power_control.requesters[i] != NULL)
{
if ( this_controller->power_control.remote_devices_granted_power <
this_controller->oem_parameters.sds1.controller.max_number_concurrent_device_spin_up
)
{
the_phy = this_controller->power_control.requesters[i];
this_controller->power_control.requesters[i] = NULL;
this_controller->power_control.phys_waiting--;
this_controller->power_control.remote_devices_granted_power ++;
scic_sds_phy_consume_power_handler(the_phy);
if (the_phy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS)
{
U8 j;
SCIC_SDS_PHY_T * current_requester_phy;
for (j = 0; j < SCI_MAX_PHYS; j++)
{
current_requester_phy = this_controller->power_control.requesters[j];
if (current_requester_phy != NULL &&
current_requester_phy != the_phy &&
current_requester_phy->phy_type.sas.identify_address_frame_buffer.sas_address.high
== the_phy->phy_type.sas.identify_address_frame_buffer.sas_address.high &&
current_requester_phy->phy_type.sas.identify_address_frame_buffer.sas_address.low
== the_phy->phy_type.sas.identify_address_frame_buffer.sas_address.low)
{
this_controller->power_control.requesters[j] = NULL;
this_controller->power_control.phys_waiting--;
scic_sds_phy_consume_power_handler(current_requester_phy);
}
}
}
}
else
{
break;
}
}
}
scic_sds_controller_power_control_timer_start(this_controller);
}
}
void scic_sds_controller_power_control_queue_insert(
SCIC_SDS_CONTROLLER_T *this_controller,
SCIC_SDS_PHY_T *the_phy
)
{
ASSERT (the_phy != NULL);
if( this_controller->power_control.remote_devices_granted_power <
this_controller->oem_parameters.sds1.controller.max_number_concurrent_device_spin_up
)
{
this_controller->power_control.remote_devices_granted_power ++;
scic_sds_phy_consume_power_handler(the_phy);
scic_sds_controller_power_control_timer_restart (this_controller);
}
else
{
U8 i;
SCIC_SDS_PHY_T * current_phy;
for(i = 0; i < SCI_MAX_PHYS; i++)
{
current_phy = &this_controller->phy_table[i];
if (current_phy->parent.state_machine.current_state_id == SCI_BASE_PHY_STATE_READY &&
current_phy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS &&
current_phy->phy_type.sas.identify_address_frame_buffer.sas_address.high
== the_phy->phy_type.sas.identify_address_frame_buffer.sas_address.high &&
current_phy->phy_type.sas.identify_address_frame_buffer.sas_address.low
== the_phy->phy_type.sas.identify_address_frame_buffer.sas_address.low)
{
scic_sds_phy_consume_power_handler(the_phy);
break;
}
}
if (i == SCI_MAX_PHYS)
{
this_controller->power_control.requesters[the_phy->phy_index] = the_phy;
this_controller->power_control.phys_waiting++;
}
}
}
void scic_sds_controller_power_control_queue_remove(
SCIC_SDS_CONTROLLER_T *this_controller,
SCIC_SDS_PHY_T *the_phy
)
{
ASSERT (the_phy != NULL);
if (this_controller->power_control.requesters[the_phy->phy_index] != NULL)
{
this_controller->power_control.phys_waiting--;
}
this_controller->power_control.requesters[the_phy->phy_index] = NULL;
}
static
BOOL scic_sds_controller_completion_queue_has_entries(
SCIC_SDS_CONTROLLER_T *this_controller
)
{
U32 get_value = this_controller->completion_queue_get;
U32 get_index = get_value & SMU_COMPLETION_QUEUE_GET_POINTER_MASK;
if (
NORMALIZE_GET_POINTER_CYCLE_BIT(get_value)
== COMPLETION_QUEUE_CYCLE_BIT(this_controller->completion_queue[get_index])
)
{
return TRUE;
}
return FALSE;
}
static
void scic_sds_controller_task_completion(
SCIC_SDS_CONTROLLER_T *this_controller,
U32 completion_entry
)
{
U32 index;
SCIC_SDS_REQUEST_T *io_request;
index = SCU_GET_COMPLETION_INDEX(completion_entry);
io_request = this_controller->io_request_table[index];
if (
(io_request != SCI_INVALID_HANDLE)
&& (io_request->io_tag != SCI_CONTROLLER_INVALID_IO_TAG)
&& (
scic_sds_io_tag_get_sequence(io_request->io_tag)
== this_controller->io_request_sequence[index]
)
)
{
scic_sds_io_request_tc_completion(io_request, completion_entry);
}
}
static
void scic_sds_controller_sdma_completion(
SCIC_SDS_CONTROLLER_T *this_controller,
U32 completion_entry
)
{
U32 index;
SCIC_SDS_REQUEST_T *io_request;
SCIC_SDS_REMOTE_DEVICE_T *device;
index = SCU_GET_COMPLETION_INDEX(completion_entry);
switch (scu_get_command_request_type(completion_entry))
{
case SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC:
case SCU_CONTEXT_COMMAND_REQUEST_TYPE_DUMP_TC:
io_request = this_controller->io_request_table[index];
SCIC_LOG_ERROR((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_CONTROLLER
| SCIC_LOG_OBJECT_SMP_IO_REQUEST
| SCIC_LOG_OBJECT_SSP_IO_REQUEST
| SCIC_LOG_OBJECT_STP_IO_REQUEST,
"SCIC SDS Completion type SDMA %x for io request %x\n",
completion_entry,
io_request
));
break;
case SCU_CONTEXT_COMMAND_REQUEST_TYPE_DUMP_RNC:
case SCU_CONTEXT_COMMAND_REQUEST_TYPE_OTHER_RNC:
case SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_RNC:
device = this_controller->device_table[index];
SCIC_LOG_ERROR((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_CONTROLLER
| SCIC_LOG_OBJECT_SSP_REMOTE_TARGET
| SCIC_LOG_OBJECT_SMP_REMOTE_TARGET
| SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
"SCIC SDS Completion type SDMA %x for remote device %x\n",
completion_entry,
device
));
break;
default:
SCIC_LOG_ERROR((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_CONTROLLER,
"SCIC SDS Completion unknown SDMA completion type %x\n",
completion_entry
));
break;
}
sci_base_state_machine_change_state(
scic_sds_controller_get_base_state_machine(this_controller),
SCI_BASE_CONTROLLER_STATE_FAILED
);
}
static
void scic_sds_controller_unsolicited_frame(
SCIC_SDS_CONTROLLER_T *this_controller,
U32 completion_entry
)
{
U32 index;
U32 frame_index;
SCU_UNSOLICITED_FRAME_HEADER_T * frame_header;
SCIC_SDS_PHY_T * phy;
SCIC_SDS_REMOTE_DEVICE_T * device;
SCI_STATUS result = SCI_FAILURE;
frame_index = SCU_GET_FRAME_INDEX(completion_entry);
frame_header
= this_controller->uf_control.buffers.array[frame_index].header;
this_controller->uf_control.buffers.array[frame_index].state
= UNSOLICITED_FRAME_IN_USE;
if (SCU_GET_FRAME_ERROR(completion_entry))
{
scic_sds_controller_release_frame(this_controller, frame_index);
return;
}
if (frame_header->is_address_frame)
{
index = SCU_GET_PROTOCOL_ENGINE_INDEX(completion_entry);
phy = &this_controller->phy_table[index];
if (phy != NULL)
{
result = scic_sds_phy_frame_handler(phy, frame_index);
}
}
else
{
index = SCU_GET_COMPLETION_INDEX(completion_entry);
if (index == SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX)
{
index = SCU_GET_PROTOCOL_ENGINE_INDEX(completion_entry);
phy = &this_controller->phy_table[index];
result = scic_sds_phy_frame_handler(phy, frame_index);
}
else
{
if (index < this_controller->remote_node_entries)
device = this_controller->device_table[index];
else
device = NULL;
if (device != NULL)
result = scic_sds_remote_device_frame_handler(device, frame_index);
else
scic_sds_controller_release_frame(this_controller, frame_index);
}
}
if (result != SCI_SUCCESS)
{
}
}
static
void scic_sds_controller_event_completion(
SCIC_SDS_CONTROLLER_T *this_controller,
U32 completion_entry
)
{
U32 index;
SCIC_SDS_REQUEST_T *io_request;
SCIC_SDS_REMOTE_DEVICE_T *device;
SCIC_SDS_PHY_T *phy;
index = SCU_GET_COMPLETION_INDEX(completion_entry);
switch (scu_get_event_type(completion_entry))
{
case SCU_EVENT_TYPE_SMU_COMMAND_ERROR:
SCIC_LOG_ERROR((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_CONTROLLER,
"SCIC Controller 0x%x received SMU command error 0x%x\n",
this_controller, completion_entry
));
break;
case SCU_EVENT_TYPE_FATAL_MEMORY_ERROR:
this_controller->parent.error = SCI_CONTROLLER_FATAL_MEMORY_ERROR;
sci_base_state_machine_change_state(
scic_sds_controller_get_base_state_machine(this_controller),
SCI_BASE_CONTROLLER_STATE_FAILED
);
case SCU_EVENT_TYPE_SMU_PCQ_ERROR:
case SCU_EVENT_TYPE_SMU_ERROR:
SCIC_LOG_ERROR((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_CONTROLLER,
"SCIC Controller 0x%x received fatal controller event 0x%x\n",
this_controller, completion_entry
));
break;
case SCU_EVENT_TYPE_TRANSPORT_ERROR:
io_request = this_controller->io_request_table[index];
scic_sds_io_request_event_handler(io_request, completion_entry);
break;
case SCU_EVENT_TYPE_PTX_SCHEDULE_EVENT:
switch (scu_get_event_specifier(completion_entry))
{
case SCU_EVENT_SPECIFIC_SMP_RESPONSE_NO_PE:
case SCU_EVENT_SPECIFIC_TASK_TIMEOUT:
io_request = this_controller->io_request_table[index];
if (io_request != SCI_INVALID_HANDLE)
{
scic_sds_io_request_event_handler(io_request, completion_entry);
}
else
{
SCIC_LOG_WARNING((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_CONTROLLER |
SCIC_LOG_OBJECT_SMP_IO_REQUEST |
SCIC_LOG_OBJECT_SSP_IO_REQUEST |
SCIC_LOG_OBJECT_STP_IO_REQUEST,
"SCIC Controller 0x%x received event 0x%x for io request object that doesnt exist.\n",
this_controller, completion_entry
));
}
break;
case SCU_EVENT_SPECIFIC_IT_NEXUS_TIMEOUT:
device = this_controller->device_table[index];
if (device != SCI_INVALID_HANDLE)
{
scic_sds_remote_device_event_handler(device, completion_entry);
}
else
{
SCIC_LOG_WARNING((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_CONTROLLER |
SCIC_LOG_OBJECT_SMP_REMOTE_TARGET |
SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
"SCIC Controller 0x%x received event 0x%x for remote device object that doesnt exist.\n",
this_controller, completion_entry
));
}
break;
}
break;
case SCU_EVENT_TYPE_BROADCAST_CHANGE:
case SCU_EVENT_TYPE_ERR_CNT_EVENT:
case SCU_EVENT_TYPE_OSSP_EVENT:
index = SCU_GET_PROTOCOL_ENGINE_INDEX(completion_entry);
phy = &this_controller->phy_table[index];
scic_sds_phy_event_handler(phy, completion_entry);
break;
case SCU_EVENT_TYPE_RNC_SUSPEND_TX:
case SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX:
case SCU_EVENT_TYPE_RNC_OPS_MISC:
if (index < this_controller->remote_node_entries)
{
device = this_controller->device_table[index];
if (device != NULL)
{
scic_sds_remote_device_event_handler(device, completion_entry);
}
}
else
{
SCIC_LOG_ERROR((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_CONTROLLER |
SCIC_LOG_OBJECT_SMP_REMOTE_TARGET |
SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
"SCIC Controller 0x%x received event 0x%x for remote device object 0x%0x that doesnt exist.\n",
this_controller, completion_entry, index
));
}
break;
default:
SCIC_LOG_WARNING((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_CONTROLLER,
"SCIC Controller received unknown event code %x\n",
completion_entry
));
break;
}
}
static
void scic_sds_controller_process_completions(
SCIC_SDS_CONTROLLER_T *this_controller
)
{
U32 completion_count = 0;
U32 completion_entry;
U32 get_index;
U32 get_cycle;
U32 event_index;
U32 event_cycle;
SCIC_LOG_TRACE((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_CONTROLLER,
"scic_sds_controller_process_completions(0x%x) enter\n",
this_controller
));
SCIC_LOG_TRACE((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_COMPLETION_QUEUE,
"completion queue beginning get : 0x%08x\n",
this_controller->completion_queue_get
));
get_index = NORMALIZE_GET_POINTER(this_controller->completion_queue_get);
get_cycle = SMU_CQGR_CYCLE_BIT & this_controller->completion_queue_get;
event_index = NORMALIZE_EVENT_POINTER(this_controller->completion_queue_get);
event_cycle = SMU_CQGR_EVENT_CYCLE_BIT & this_controller->completion_queue_get;
while (
NORMALIZE_GET_POINTER_CYCLE_BIT(get_cycle)
== COMPLETION_QUEUE_CYCLE_BIT(this_controller->completion_queue[get_index])
)
{
completion_count++;
completion_entry = this_controller->completion_queue[get_index];
INCREMENT_COMPLETION_QUEUE_GET(this_controller, get_index, get_cycle);
SCIC_LOG_TRACE((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_COMPLETION_QUEUE,
"completion queue entry : 0x%08x\n",
completion_entry
));
switch (SCU_GET_COMPLETION_TYPE(completion_entry))
{
case SCU_COMPLETION_TYPE_TASK:
scic_sds_controller_task_completion(this_controller, completion_entry);
break;
case SCU_COMPLETION_TYPE_SDMA:
scic_sds_controller_sdma_completion(this_controller, completion_entry);
break;
case SCU_COMPLETION_TYPE_UFI:
scic_sds_controller_unsolicited_frame(this_controller, completion_entry);
break;
case SCU_COMPLETION_TYPE_EVENT:
scic_sds_controller_event_completion(this_controller, completion_entry);
break;
case SCU_COMPLETION_TYPE_NOTIFY:
INCREMENT_EVENT_QUEUE_GET(this_controller, event_index, event_cycle);
scic_sds_controller_event_completion(this_controller, completion_entry);
break;
default:
SCIC_LOG_WARNING((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_CONTROLLER,
"SCIC Controller received unknown completion type %x\n",
completion_entry
));
break;
}
}
if (completion_count > 0)
{
this_controller->completion_queue_get =
SMU_CQGR_GEN_BIT(ENABLE)
| SMU_CQGR_GEN_BIT(EVENT_ENABLE)
| event_cycle | SMU_CQGR_GEN_VAL(EVENT_POINTER, event_index)
| get_cycle | SMU_CQGR_GEN_VAL(POINTER, get_index) ;
SMU_CQGR_WRITE(this_controller, this_controller->completion_queue_get);
}
SCIC_LOG_TRACE((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_COMPLETION_QUEUE,
"completion queue ending get : 0x%08x\n",
this_controller->completion_queue_get
));
}
static
void scic_sds_controller_transitioned_process_completions(
SCIC_SDS_CONTROLLER_T * this_controller
)
{
U32 completion_count = 0;
U32 completion_entry;
U32 get_index;
U32 get_cycle;
U32 event_index;
U32 event_cycle;
SCIC_LOG_TRACE((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_CONTROLLER,
"scic_sds_controller_transitioned_process_completions(0x%x) enter\n",
this_controller
));
SCIC_LOG_TRACE((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_COMPLETION_QUEUE,
"completion queue beginning get : 0x%08x\n",
this_controller->completion_queue_get
));
get_index = NORMALIZE_GET_POINTER(this_controller->completion_queue_get);
get_cycle = SMU_CQGR_CYCLE_BIT & this_controller->completion_queue_get;
event_index = NORMALIZE_EVENT_POINTER(this_controller->completion_queue_get);
event_cycle = SMU_CQGR_EVENT_CYCLE_BIT & this_controller->completion_queue_get;
while (
NORMALIZE_GET_POINTER_CYCLE_BIT(get_cycle)
== COMPLETION_QUEUE_CYCLE_BIT(
this_controller->completion_queue[get_index])
)
{
completion_count++;
completion_entry = this_controller->completion_queue[get_index];
INCREMENT_COMPLETION_QUEUE_GET(this_controller, get_index, get_cycle);
SCIC_LOG_TRACE((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_COMPLETION_QUEUE,
"completion queue entry : 0x%08x\n",
completion_entry
));
switch (SCU_GET_COMPLETION_TYPE(completion_entry))
{
case SCU_COMPLETION_TYPE_TASK:
scic_sds_controller_task_completion(this_controller, completion_entry);
break;
case SCU_COMPLETION_TYPE_NOTIFY:
INCREMENT_EVENT_QUEUE_GET(this_controller, event_index, event_cycle);
case SCU_COMPLETION_TYPE_EVENT:
case SCU_COMPLETION_TYPE_SDMA:
case SCU_COMPLETION_TYPE_UFI:
default:
SCIC_LOG_WARNING((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_CONTROLLER,
"SCIC Controller ignoring completion type %x\n",
completion_entry
));
break;
}
}
if (completion_count > 0)
{
this_controller->completion_queue_get =
SMU_CQGR_GEN_BIT(ENABLE)
| SMU_CQGR_GEN_BIT(EVENT_ENABLE)
| event_cycle | SMU_CQGR_GEN_VAL(EVENT_POINTER, event_index)
| get_cycle | SMU_CQGR_GEN_VAL(POINTER, get_index) ;
SMU_CQGR_WRITE(this_controller, this_controller->completion_queue_get);
}
SCIC_LOG_TRACE((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_COMPLETION_QUEUE,
"completion queue ending get : 0x%08x\n",
this_controller->completion_queue_get
));
}
static
BOOL scic_sds_controller_standard_interrupt_handler(
SCIC_SDS_CONTROLLER_T *this_controller,
U32 interrupt_status
)
{
BOOL is_completion_needed = FALSE;
SCIC_LOG_TRACE((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_CONTROLLER,
"scic_sds_controller_standard_interrupt_handler(0x%d,0x%d) enter\n",
this_controller, interrupt_status
));
if (
(interrupt_status & SMU_ISR_QUEUE_ERROR)
|| (
(interrupt_status & SMU_ISR_QUEUE_SUSPEND)
&& (!scic_sds_controller_completion_queue_has_entries(this_controller))
)
)
{
is_completion_needed = TRUE;
this_controller->encountered_fatal_error = TRUE;
}
if (scic_sds_controller_completion_queue_has_entries(this_controller))
{
is_completion_needed = TRUE;
}
return is_completion_needed;
}
static
BOOL scic_sds_controller_polling_interrupt_handler(
SCI_CONTROLLER_HANDLE_T controller
)
{
U32 interrupt_status;
SCIC_SDS_CONTROLLER_T *this_controller = (SCIC_SDS_CONTROLLER_T*)controller;
SCIC_LOG_TRACE((
sci_base_object_get_logger(controller),
SCIC_LOG_OBJECT_CONTROLLER,
"scic_sds_controller_polling_interrupt_handler(0x%d) enter\n",
controller
));
interrupt_status = SMU_ISR_READ(this_controller);
if ((interrupt_status &
(SMU_ISR_COMPLETION |
SMU_ISR_QUEUE_ERROR |
SMU_ISR_QUEUE_SUSPEND)) == 0)
{
return FALSE;
}
return scic_sds_controller_standard_interrupt_handler(
controller, interrupt_status
);
}
static
void scic_sds_controller_polling_completion_handler(
SCI_CONTROLLER_HANDLE_T controller
)
{
SCIC_SDS_CONTROLLER_T *this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
SCIC_LOG_TRACE((
sci_base_object_get_logger(controller),
SCIC_LOG_OBJECT_CONTROLLER,
"scic_sds_controller_polling_completion_handler(0x%d) enter\n",
controller
));
if (this_controller->encountered_fatal_error == TRUE)
{
SCIC_LOG_ERROR((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_CONTROLLER,
"SCIC Controller has encountered a fatal error.\n"
));
sci_base_state_machine_change_state(
scic_sds_controller_get_base_state_machine(this_controller),
SCI_BASE_CONTROLLER_STATE_FAILED
);
}
else if (scic_sds_controller_completion_queue_has_entries(this_controller))
{
if (this_controller->restrict_completions == FALSE)
scic_sds_controller_process_completions(this_controller);
else
scic_sds_controller_transitioned_process_completions(this_controller);
}
SMU_ISR_WRITE(
this_controller,
(U32)(SMU_ISR_COMPLETION | SMU_ISR_QUEUE_ERROR | SMU_ISR_QUEUE_SUSPEND)
);
}
#if !defined(DISABLE_INTERRUPTS)
static
BOOL scic_sds_controller_legacy_interrupt_handler(
SCI_CONTROLLER_HANDLE_T controller
)
{
U32 interrupt_status;
BOOL is_completion_needed;
SCIC_SDS_CONTROLLER_T *this_controller = (SCIC_SDS_CONTROLLER_T*)controller;
interrupt_status = SMU_ISR_READ(this_controller);
is_completion_needed = scic_sds_controller_standard_interrupt_handler(
this_controller, interrupt_status
);
return is_completion_needed;
}
static
void scic_sds_controller_legacy_completion_handler(
SCI_CONTROLLER_HANDLE_T controller
)
{
SCIC_SDS_CONTROLLER_T *this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
SCIC_LOG_TRACE((
sci_base_object_get_logger(controller),
SCIC_LOG_OBJECT_CONTROLLER,
"scic_sds_controller_legacy_completion_handler(0x%d) enter\n",
controller
));
scic_sds_controller_polling_completion_handler(controller);
SMU_IMR_WRITE(this_controller, 0x00000000);
#ifdef IMR_READ_FENCE
{
volatile U32 int_mask_value = 0;
ULONG count = 0;
do
{
int_mask_value = SMU_IMR_READ(this_controler);
if (count++ > 10)
{
#ifdef ALLOW_ENTER_DEBUGGER
__debugbreak();
#endif
break;
}
} while (int_mask_value != 0);
}
#endif
}
static
BOOL scic_sds_controller_single_vector_interrupt_handler(
SCI_CONTROLLER_HANDLE_T controller
)
{
U32 interrupt_status;
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
SMU_IMR_WRITE(this_controller, 0xFFFFFFFF);
interrupt_status = SMU_ISR_READ(this_controller);
interrupt_status &= (SMU_ISR_QUEUE_ERROR | SMU_ISR_QUEUE_SUSPEND);
if (
(interrupt_status == 0)
&& scic_sds_controller_completion_queue_has_entries(this_controller)
)
{
SMU_ISR_WRITE(this_controller, SMU_ISR_COMPLETION);
return TRUE;
}
if (interrupt_status != 0)
{
return TRUE;
}
SMU_ISR_WRITE(this_controller, 0x00000000);
SMU_IMR_WRITE(this_controller, 0x00000000);
return FALSE;
}
static
void scic_sds_controller_single_vector_completion_handler(
SCI_CONTROLLER_HANDLE_T controller
)
{
U32 interrupt_status;
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
SCIC_LOG_TRACE((
sci_base_object_get_logger(controller),
SCIC_LOG_OBJECT_CONTROLLER,
"scic_sds_controller_single_vector_completion_handler(0x%d) enter\n",
controller
));
interrupt_status = SMU_ISR_READ(this_controller);
interrupt_status &= (SMU_ISR_QUEUE_ERROR | SMU_ISR_QUEUE_SUSPEND);
if (interrupt_status & SMU_ISR_QUEUE_ERROR)
{
SCIC_LOG_ERROR((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_CONTROLLER,
"SCIC Controller has encountered a fatal error.\n"
));
sci_base_state_machine_change_state(
scic_sds_controller_get_base_state_machine(this_controller),
SCI_BASE_CONTROLLER_STATE_FAILED
);
return;
}
if (
(interrupt_status & SMU_ISR_QUEUE_SUSPEND)
&& !scic_sds_controller_completion_queue_has_entries(this_controller)
)
{
SCIC_LOG_ERROR((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_CONTROLLER,
"SCIC Controller has encountered a fatal error.\n"
));
sci_base_state_machine_change_state(
scic_sds_controller_get_base_state_machine(this_controller),
SCI_BASE_CONTROLLER_STATE_FAILED
);
return;
}
if (scic_sds_controller_completion_queue_has_entries(this_controller))
{
scic_sds_controller_process_completions(this_controller);
SMU_ISR_WRITE(
this_controller,
(SMU_ISR_COMPLETION | SMU_ISR_QUEUE_SUSPEND)
);
}
SMU_IMR_WRITE(this_controller, 0x00000000);
}
static
BOOL scic_sds_controller_normal_vector_interrupt_handler(
SCI_CONTROLLER_HANDLE_T controller
)
{
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
if (scic_sds_controller_completion_queue_has_entries(this_controller))
{
return TRUE;
}
else
{
SMU_ISR_WRITE(this_controller, SMU_ISR_COMPLETION);
SMU_IMR_WRITE(this_controller, 0xFF000000);
SMU_IMR_WRITE(this_controller, 0x00000000);
}
return FALSE;
}
static
void scic_sds_controller_normal_vector_completion_handler(
SCI_CONTROLLER_HANDLE_T controller
)
{
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
SCIC_LOG_TRACE((
sci_base_object_get_logger(controller),
SCIC_LOG_OBJECT_CONTROLLER,
"scic_sds_controller_normal_vector_completion_handler(0x%d) enter\n",
controller
));
if (scic_sds_controller_completion_queue_has_entries(this_controller))
{
scic_sds_controller_process_completions(this_controller);
}
SMU_ISR_WRITE(this_controller, SMU_ISR_COMPLETION);
SMU_IMR_WRITE(this_controller, 0xFF000000);
SMU_IMR_WRITE(this_controller, 0x00000000);
}
static
BOOL scic_sds_controller_error_vector_interrupt_handler(
SCI_CONTROLLER_HANDLE_T controller
)
{
U32 interrupt_status;
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
interrupt_status = SMU_ISR_READ(this_controller);
interrupt_status &= (SMU_ISR_QUEUE_ERROR | SMU_ISR_QUEUE_SUSPEND);
if (interrupt_status != 0)
{
return TRUE;
}
SMU_IMR_WRITE(this_controller, 0x000000FF);
SMU_IMR_WRITE(this_controller, 0x00000000);
return FALSE;
}
static
void scic_sds_controller_error_vector_completion_handler(
SCI_CONTROLLER_HANDLE_T controller
)
{
U32 interrupt_status;
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
SCIC_LOG_TRACE((
sci_base_object_get_logger(controller),
SCIC_LOG_OBJECT_CONTROLLER,
"scic_sds_controller_error_vector_completion_handler(0x%d) enter\n",
controller
));
interrupt_status = SMU_ISR_READ(this_controller);
if (
(interrupt_status & SMU_ISR_QUEUE_SUSPEND)
&& scic_sds_controller_completion_queue_has_entries(this_controller)
)
{
scic_sds_controller_process_completions(this_controller);
SMU_ISR_WRITE(this_controller, SMU_ISR_QUEUE_SUSPEND);
}
else
{
SCIC_LOG_ERROR((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_CONTROLLER,
"SCIC Controller reports CRC error on completion ISR %x\n",
interrupt_status
));
sci_base_state_machine_change_state(
scic_sds_controller_get_base_state_machine(this_controller),
SCI_BASE_CONTROLLER_STATE_FAILED
);
return;
}
SMU_IMR_WRITE(this_controller, 0x00000000);
}
#endif
U32 scic_sds_controller_get_object_size(void)
{
return sizeof(SCIC_SDS_CONTROLLER_T);
}
U32 scic_sds_controller_get_min_timer_count(void)
{
return SCIC_SDS_CONTROLLER_MIN_TIMER_COUNT
+ scic_sds_port_get_min_timer_count()
+ scic_sds_phy_get_min_timer_count();
}
U32 scic_sds_controller_get_max_timer_count(void)
{
return SCIC_SDS_CONTROLLER_MAX_TIMER_COUNT
+ scic_sds_port_get_max_timer_count()
+ scic_sds_phy_get_max_timer_count();
}
void scic_sds_controller_link_up(
SCIC_SDS_CONTROLLER_T *this_controller,
SCIC_SDS_PORT_T *the_port,
SCIC_SDS_PHY_T *the_phy
)
{
if (this_controller->state_handlers->link_up_handler != NULL)
{
this_controller->state_handlers->link_up_handler(
this_controller, the_port, the_phy);
}
else
{
SCIC_LOG_INFO((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_CONTROLLER,
"SCIC Controller linkup event from phy %d in unexpected state %d\n",
the_phy->phy_index,
sci_base_state_machine_get_state(
scic_sds_controller_get_base_state_machine(this_controller))
));
}
}
void scic_sds_controller_link_down(
SCIC_SDS_CONTROLLER_T *this_controller,
SCIC_SDS_PORT_T *the_port,
SCIC_SDS_PHY_T *the_phy
)
{
if (this_controller->state_handlers->link_down_handler != NULL)
{
this_controller->state_handlers->link_down_handler(
this_controller, the_port, the_phy);
}
else
{
SCIC_LOG_INFO((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_CONTROLLER,
"SCIC Controller linkdown event from phy %d in unexpected state %d\n",
the_phy->phy_index,
sci_base_state_machine_get_state(
scic_sds_controller_get_base_state_machine(this_controller))
));
}
}
void scic_sds_controller_remote_device_started(
SCIC_SDS_CONTROLLER_T * this_controller,
SCIC_SDS_REMOTE_DEVICE_T * the_device
)
{
if (this_controller->state_handlers->remote_device_started_handler != NULL)
{
this_controller->state_handlers->remote_device_started_handler(
this_controller, the_device
);
}
else
{
SCIC_LOG_INFO((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_CONTROLLER,
"SCIC Controller 0x%x remote device started event from device 0x%x in unexpected state %d\n",
this_controller,
the_device,
sci_base_state_machine_get_state(
scic_sds_controller_get_base_state_machine(this_controller))
));
}
}
BOOL scic_sds_controller_has_remote_devices_stopping(
SCIC_SDS_CONTROLLER_T * this_controller
)
{
U32 index;
for (index = 0; index < this_controller->remote_node_entries; index++)
{
if (
(this_controller->device_table[index] != NULL)
&& (
this_controller->device_table[index]->parent.state_machine.current_state_id
== SCI_BASE_REMOTE_DEVICE_STATE_STOPPING
)
)
{
return TRUE;
}
}
return FALSE;
}
void scic_sds_controller_remote_device_stopped(
SCIC_SDS_CONTROLLER_T * this_controller,
SCIC_SDS_REMOTE_DEVICE_T * the_device
)
{
if (this_controller->state_handlers->remote_device_stopped_handler != NULL)
{
this_controller->state_handlers->remote_device_stopped_handler(
this_controller, the_device
);
}
else
{
SCIC_LOG_INFO((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_CONTROLLER,
"SCIC Controller 0x%x remote device stopped event from device 0x%x in unexpected state %d\n",
this_controller,
the_device,
sci_base_state_machine_get_state(
scic_sds_controller_get_base_state_machine(this_controller))
));
}
}
void scic_sds_controller_post_request(
SCIC_SDS_CONTROLLER_T *this_controller,
U32 request
)
{
SCIC_LOG_INFO((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_COMPLETION_QUEUE,
"SCIC Controller 0x%08x post request 0x%08x\n",
this_controller, request
));
SMU_PCP_WRITE(this_controller, request);
}
void scic_sds_controller_copy_task_context(
SCIC_SDS_CONTROLLER_T *this_controller,
SCIC_SDS_REQUEST_T *this_request
)
{
SCU_TASK_CONTEXT_T *task_context_buffer;
task_context_buffer = scic_sds_controller_get_task_context_buffer(
this_controller, this_request->io_tag
);
memcpy(
task_context_buffer,
this_request->task_context_buffer,
SCI_FIELD_OFFSET(SCU_TASK_CONTEXT_T, sgl_snapshot_ac)
);
this_request->task_context_buffer = task_context_buffer;
}
SCU_TASK_CONTEXT_T * scic_sds_controller_get_task_context_buffer(
SCIC_SDS_CONTROLLER_T * this_controller,
U16 io_tag
)
{
U16 task_index = scic_sds_io_tag_get_index(io_tag);
if (task_index < this_controller->task_context_entries)
{
return &this_controller->task_context_table[task_index];
}
return NULL;
}
U16 scic_sds_controller_get_io_sequence_from_tag(
SCIC_SDS_CONTROLLER_T *this_controller,
U16 io_tag
)
{
return scic_sds_io_tag_get_sequence(io_tag);
}
SCIC_SDS_REQUEST_T *scic_sds_controller_get_io_request_from_tag(
SCIC_SDS_CONTROLLER_T *this_controller,
U16 io_tag
)
{
U16 task_index;
U16 task_sequence;
task_index = scic_sds_io_tag_get_index(io_tag);
if (task_index < this_controller->task_context_entries)
{
if (this_controller->io_request_table[task_index] != SCI_INVALID_HANDLE)
{
task_sequence = scic_sds_io_tag_get_sequence(io_tag);
if (task_sequence == this_controller->io_request_sequence[task_index])
{
return this_controller->io_request_table[task_index];
}
}
}
return SCI_INVALID_HANDLE;
}
SCI_STATUS scic_sds_controller_allocate_remote_node_context(
SCIC_SDS_CONTROLLER_T * this_controller,
SCIC_SDS_REMOTE_DEVICE_T * the_device,
U16 * node_id
)
{
U16 node_index;
U32 remote_node_count = scic_sds_remote_device_node_count(the_device);
node_index = scic_sds_remote_node_table_allocate_remote_node(
&this_controller->available_remote_nodes, remote_node_count
);
if (node_index != SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX)
{
this_controller->device_table[node_index] = the_device;
*node_id = node_index;
return SCI_SUCCESS;
}
return SCI_FAILURE_INSUFFICIENT_RESOURCES;
}
void scic_sds_controller_free_remote_node_context(
SCIC_SDS_CONTROLLER_T * this_controller,
SCIC_SDS_REMOTE_DEVICE_T * the_device,
U16 node_id
)
{
U32 remote_node_count = scic_sds_remote_device_node_count(the_device);
if (this_controller->device_table[node_id] == the_device)
{
this_controller->device_table[node_id] = SCI_INVALID_HANDLE;
scic_sds_remote_node_table_release_remote_node_index(
&this_controller->available_remote_nodes, remote_node_count, node_id
);
}
}
SCU_REMOTE_NODE_CONTEXT_T *scic_sds_controller_get_remote_node_context_buffer(
SCIC_SDS_CONTROLLER_T *this_controller,
U16 node_id
)
{
if (
(node_id < this_controller->remote_node_entries)
&& (this_controller->device_table[node_id] != SCI_INVALID_HANDLE)
)
{
return &this_controller->remote_node_context_table[node_id];
}
return NULL;
}
void scic_sds_controller_copy_sata_response(
void * response_buffer,
void * frame_header,
void * frame_buffer
)
{
memcpy(
response_buffer,
frame_header,
sizeof(U32)
);
memcpy(
(char *)((char *)response_buffer + sizeof(U32)),
frame_buffer,
sizeof(SATA_FIS_REG_D2H_T) - sizeof(U32)
);
}
void scic_sds_controller_release_frame(
SCIC_SDS_CONTROLLER_T *this_controller,
U32 frame_index
)
{
if (scic_sds_unsolicited_frame_control_release_frame(
&this_controller->uf_control, frame_index) == TRUE)
SCU_UFQGP_WRITE(this_controller, this_controller->uf_control.get);
}
#ifdef SCI_LOGGING
void scic_sds_controller_initialize_state_logging(
SCIC_SDS_CONTROLLER_T *this_controller
)
{
sci_base_state_machine_logger_initialize(
&this_controller->parent.state_machine_logger,
&this_controller->parent.state_machine,
&this_controller->parent.parent,
scic_cb_logger_log_states,
"SCIC_SDS_CONTROLLER_T", "base state machine",
SCIC_LOG_OBJECT_CONTROLLER
);
}
void scic_sds_controller_deinitialize_state_logging(
SCIC_SDS_CONTROLLER_T *this_controller
)
{
sci_base_state_machine_logger_deinitialize(
&this_controller->parent.state_machine_logger,
&this_controller->parent.state_machine
);
}
#endif
static
void scic_sds_controller_set_default_config_parameters(
SCIC_SDS_CONTROLLER_T *this_controller
)
{
U16 index;
this_controller->oem_parameters.sds1.controller.mode_type = SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE;
this_controller->oem_parameters.sds1.controller.max_number_concurrent_device_spin_up = 1;
this_controller->oem_parameters.sds1.controller.ssc_sata_tx_spread_level = 0;
this_controller->oem_parameters.sds1.controller.ssc_sas_tx_spread_level = 0;
this_controller->oem_parameters.sds1.controller.ssc_sas_tx_type = 0;
this_controller->oem_parameters.sds1.controller.cable_selection_mask = 0;
for (index = 0; index < SCI_MAX_PORTS; index++)
{
this_controller->oem_parameters.sds1.ports[index].phy_mask = 0;
}
for (index = 0; index < SCI_MAX_PHYS; index++)
{
this_controller->user_parameters.sds1.phys[index].max_speed_generation = 2;
this_controller->user_parameters.sds1.phys[index].align_insertion_frequency = 0x7f;
this_controller->user_parameters.sds1.phys[index].in_connection_align_insertion_frequency = 0xff;
this_controller->user_parameters.sds1.phys[index].notify_enable_spin_up_insertion_frequency = 0x33;
this_controller->oem_parameters.sds1.phys[index].sas_address.sci_format.high
= 0x5FCFFFFF;
this_controller->oem_parameters.sds1.phys[index].sas_address.sci_format.low
= 0x00000001 + this_controller->controller_index;
if ( (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A0)
|| (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A2)
|| (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_B0) )
{
this_controller->oem_parameters.sds1.phys[index].afe_tx_amp_control0 = 0x000E7C03;
this_controller->oem_parameters.sds1.phys[index].afe_tx_amp_control1 = 0x000E7C03;
this_controller->oem_parameters.sds1.phys[index].afe_tx_amp_control2 = 0x000E7C03;
this_controller->oem_parameters.sds1.phys[index].afe_tx_amp_control3 = 0x000E7C03;
}
else
{
this_controller->oem_parameters.sds1.phys[index].afe_tx_amp_control0 = 0x000BDD08;
this_controller->oem_parameters.sds1.phys[index].afe_tx_amp_control1 = 0x000B7069;
this_controller->oem_parameters.sds1.phys[index].afe_tx_amp_control2 = 0x000B7C09;
this_controller->oem_parameters.sds1.phys[index].afe_tx_amp_control3 = 0x000AFC6E;
}
}
this_controller->user_parameters.sds1.stp_inactivity_timeout = 5;
this_controller->user_parameters.sds1.ssp_inactivity_timeout = 5;
this_controller->user_parameters.sds1.stp_max_occupancy_timeout = 5;
this_controller->user_parameters.sds1.ssp_max_occupancy_timeout = 20;
this_controller->user_parameters.sds1.no_outbound_task_timeout = 20;
}
static
SCI_STATUS scic_sds_controller_release_resource(
SCIC_SDS_CONTROLLER_T * this_controller
)
{
SCIC_SDS_PORT_T * port;
SCIC_SDS_PHY_T * phy;
U8 index;
SCIC_LOG_TRACE((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_INITIALIZATION,
"scic_sds_controller_release_resource(0x%x) enter\n",
this_controller
));
if(this_controller->phy_startup_timer != NULL)
{
scic_cb_timer_destroy(this_controller, this_controller->phy_startup_timer);
this_controller->phy_startup_timer = NULL;
}
if(this_controller->power_control.timer != NULL)
{
scic_cb_timer_destroy(this_controller, this_controller->power_control.timer);
this_controller->power_control.timer = NULL;
}
if(this_controller->timeout_timer != NULL)
{
scic_cb_timer_destroy(this_controller, this_controller->timeout_timer);
this_controller->timeout_timer = NULL;
}
scic_sds_port_configuration_agent_release_resource(
this_controller,
&this_controller->port_agent);
for(index = 0; index < SCI_MAX_PORTS+1; index++)
{
port = &this_controller->port_table[index];
scic_sds_port_release_resource(this_controller, port);
}
for(index = 0; index < SCI_MAX_PHYS; index++)
{
phy = &this_controller->phy_table[index];
scic_sds_phy_release_resource(this_controller, phy);
}
return SCI_SUCCESS;
}
void scic_sds_controller_port_agent_configured_ports(
SCIC_SDS_CONTROLLER_T * this_controller
)
{
scic_sds_controller_transition_to_ready(
this_controller, SCI_SUCCESS
);
}
SCI_STATUS scic_controller_construct(
SCI_LIBRARY_HANDLE_T library,
SCI_CONTROLLER_HANDLE_T controller,
void * user_object
)
{
SCIC_SDS_LIBRARY_T *my_library;
SCIC_SDS_CONTROLLER_T *this_controller;
my_library = (SCIC_SDS_LIBRARY_T *)library;
this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
SCIC_LOG_TRACE((
sci_base_object_get_logger(library),
SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_INITIALIZATION,
"scic_controller_construct(0x%x, 0x%x) enter\n",
library, controller
));
memset(this_controller, 0, sizeof(SCIC_SDS_CONTROLLER_T));
this_controller->controller_index =
scic_sds_library_get_controller_index(my_library, this_controller);
this_controller->pci_revision = my_library->pci_revision;
sci_base_controller_construct(
&this_controller->parent,
sci_base_object_get_logger(my_library),
scic_sds_controller_state_table,
this_controller->memory_descriptors,
ARRAY_SIZE(this_controller->memory_descriptors),
NULL
);
sci_object_set_association(controller, user_object);
scic_sds_controller_initialize_state_logging(this_controller);
scic_sds_pci_bar_initialization(this_controller);
return SCI_SUCCESS;
}
SCI_STATUS scic_controller_initialize(
SCI_CONTROLLER_HANDLE_T controller
)
{
SCI_STATUS status = SCI_FAILURE_INVALID_STATE;
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
SCIC_LOG_TRACE((
sci_base_object_get_logger(controller),
SCIC_LOG_OBJECT_CONTROLLER,
"scic_controller_initialize(0x%x, 0x%d) enter\n",
controller
));
if (this_controller->state_handlers->parent.initialize_handler != NULL)
{
status = this_controller->state_handlers->parent.initialize_handler(
(SCI_BASE_CONTROLLER_T *)controller
);
}
else
{
SCIC_LOG_WARNING((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_CONTROLLER,
"SCIC Controller initialize operation requested in invalid state %d\n",
sci_base_state_machine_get_state(
scic_sds_controller_get_base_state_machine(this_controller))
));
}
return status;
}
U32 scic_controller_get_suggested_start_timeout(
SCI_CONTROLLER_HANDLE_T controller
)
{
if (controller == SCI_INVALID_HANDLE)
return 0;
return (SCIC_SDS_SIGNATURE_FIS_TIMEOUT
+ SCIC_SDS_CONTROLLER_PHY_START_TIMEOUT
+ ((SCI_MAX_PHYS-1) * SCIC_SDS_CONTROLLER_POWER_CONTROL_INTERVAL));
}
SCI_STATUS scic_controller_start(
SCI_CONTROLLER_HANDLE_T controller,
U32 timeout
)
{
SCI_STATUS status = SCI_FAILURE_INVALID_STATE;
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
SCIC_LOG_TRACE((
sci_base_object_get_logger(controller),
SCIC_LOG_OBJECT_CONTROLLER,
"scic_controller_start(0x%x, 0x%d) enter\n",
controller, timeout
));
if (this_controller->state_handlers->parent.start_handler != NULL)
{
status = this_controller->state_handlers->parent.start_handler(
(SCI_BASE_CONTROLLER_T *)controller, timeout
);
}
else
{
SCIC_LOG_WARNING((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_CONTROLLER,
"SCIC Controller start operation requested in invalid state %d\n",
sci_base_state_machine_get_state(
scic_sds_controller_get_base_state_machine(this_controller))
));
}
return status;
}
SCI_STATUS scic_controller_stop(
SCI_CONTROLLER_HANDLE_T controller,
U32 timeout
)
{
SCI_STATUS status = SCI_FAILURE_INVALID_STATE;
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
SCIC_LOG_TRACE((
sci_base_object_get_logger(controller),
SCIC_LOG_OBJECT_CONTROLLER,
"scic_controller_stop(0x%x, 0x%d) enter\n",
controller, timeout
));
if (this_controller->state_handlers->parent.stop_handler != NULL)
{
status = this_controller->state_handlers->parent.stop_handler(
(SCI_BASE_CONTROLLER_T *)controller, timeout
);
}
else
{
SCIC_LOG_WARNING((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_CONTROLLER,
"SCIC Controller stop operation requested in invalid state %d\n",
sci_base_state_machine_get_state(
scic_sds_controller_get_base_state_machine(this_controller))
));
}
return status;
}
SCI_STATUS scic_controller_reset(
SCI_CONTROLLER_HANDLE_T controller
)
{
SCI_STATUS status = SCI_FAILURE_INVALID_STATE;
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
SCIC_LOG_TRACE((
sci_base_object_get_logger(controller),
SCIC_LOG_OBJECT_CONTROLLER,
"scic_controller_reset(0x%x) enter\n",
controller
));
if (this_controller->state_handlers->parent.reset_handler != NULL)
{
status = this_controller->state_handlers->parent.reset_handler(
(SCI_BASE_CONTROLLER_T *)controller
);
}
else
{
SCIC_LOG_WARNING((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_CONTROLLER,
"SCIC Controller reset operation requested in invalid state %d\n",
sci_base_state_machine_get_state(
scic_sds_controller_get_base_state_machine(this_controller))
));
}
return status;
}
SCI_STATUS scic_controller_get_handler_methods(
SCIC_INTERRUPT_TYPE interrupt_type,
U16 message_count,
SCIC_CONTROLLER_HANDLER_METHODS_T *handler_methods
)
{
SCI_STATUS status = SCI_FAILURE_UNSUPPORTED_MESSAGE_COUNT;
switch (interrupt_type)
{
#if !defined(DISABLE_INTERRUPTS)
case SCIC_LEGACY_LINE_INTERRUPT_TYPE:
if (message_count == 0)
{
handler_methods[0].interrupt_handler
= scic_sds_controller_legacy_interrupt_handler;
handler_methods[0].completion_handler
= scic_sds_controller_legacy_completion_handler;
status = SCI_SUCCESS;
}
break;
case SCIC_MSIX_INTERRUPT_TYPE:
if (message_count == 1)
{
handler_methods[0].interrupt_handler
= scic_sds_controller_single_vector_interrupt_handler;
handler_methods[0].completion_handler
= scic_sds_controller_single_vector_completion_handler;
status = SCI_SUCCESS;
}
else if (message_count == 2)
{
handler_methods[0].interrupt_handler
= scic_sds_controller_normal_vector_interrupt_handler;
handler_methods[0].completion_handler
= scic_sds_controller_normal_vector_completion_handler;
handler_methods[1].interrupt_handler
= scic_sds_controller_error_vector_interrupt_handler;
handler_methods[1].completion_handler
= scic_sds_controller_error_vector_completion_handler;
status = SCI_SUCCESS;
}
break;
#endif
case SCIC_NO_INTERRUPTS:
if (message_count == 0)
{
handler_methods[0].interrupt_handler
= scic_sds_controller_polling_interrupt_handler;
handler_methods[0].completion_handler
= scic_sds_controller_polling_completion_handler;
status = SCI_SUCCESS;
}
break;
default:
status = SCI_FAILURE_INVALID_PARAMETER_VALUE;
break;
}
return status;
}
SCI_IO_STATUS scic_controller_start_io(
SCI_CONTROLLER_HANDLE_T controller,
SCI_REMOTE_DEVICE_HANDLE_T remote_device,
SCI_IO_REQUEST_HANDLE_T io_request,
U16 io_tag
)
{
SCI_STATUS status;
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
SCIC_LOG_TRACE((
sci_base_object_get_logger(controller),
SCIC_LOG_OBJECT_CONTROLLER,
"scic_controller_start_io(0x%x, 0x%x, 0x%x, 0x%x) enter\n",
controller, remote_device, io_request, io_tag
));
status = this_controller->state_handlers->parent.start_io_handler(
&this_controller->parent,
(SCI_BASE_REMOTE_DEVICE_T *)remote_device,
(SCI_BASE_REQUEST_T *)io_request,
io_tag
);
return (SCI_IO_STATUS)status;
}
SCI_STATUS scic_controller_terminate_request(
SCI_CONTROLLER_HANDLE_T controller,
SCI_REMOTE_DEVICE_HANDLE_T remote_device,
SCI_IO_REQUEST_HANDLE_T request
)
{
SCI_STATUS status;
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
SCIC_LOG_TRACE((
sci_base_object_get_logger(controller),
SCIC_LOG_OBJECT_CONTROLLER,
"scic_controller_terminate_request(0x%x, 0x%x, 0x%x) enter\n",
controller, remote_device, request
));
status = this_controller->state_handlers->terminate_request_handler(
&this_controller->parent,
(SCI_BASE_REMOTE_DEVICE_T *)remote_device,
(SCI_BASE_REQUEST_T *)request
);
return status;
}
SCI_STATUS scic_controller_complete_io(
SCI_CONTROLLER_HANDLE_T controller,
SCI_REMOTE_DEVICE_HANDLE_T remote_device,
SCI_IO_REQUEST_HANDLE_T io_request
)
{
SCI_STATUS status;
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
SCIC_LOG_TRACE((
sci_base_object_get_logger(controller),
SCIC_LOG_OBJECT_CONTROLLER,
"scic_controller_complete_io(0x%x, 0x%x, 0x%x) enter\n",
controller, remote_device, io_request
));
status = this_controller->state_handlers->parent.complete_io_handler(
&this_controller->parent,
(SCI_BASE_REMOTE_DEVICE_T *)remote_device,
(SCI_BASE_REQUEST_T *)io_request
);
return status;
}
#if !defined(DISABLE_TASK_MANAGEMENT)
SCI_TASK_STATUS scic_controller_start_task(
SCI_CONTROLLER_HANDLE_T controller,
SCI_REMOTE_DEVICE_HANDLE_T remote_device,
SCI_TASK_REQUEST_HANDLE_T task_request,
U16 task_tag
)
{
SCI_STATUS status = SCI_FAILURE_INVALID_STATE;
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
SCIC_LOG_TRACE((
sci_base_object_get_logger(controller),
SCIC_LOG_OBJECT_CONTROLLER,
"scic_controller_start_task(0x%x, 0x%x, 0x%x, 0x%x) enter\n",
controller, remote_device, task_request, task_tag
));
if (this_controller->state_handlers->parent.start_task_handler != NULL)
{
status = this_controller->state_handlers->parent.start_task_handler(
&this_controller->parent,
(SCI_BASE_REMOTE_DEVICE_T *)remote_device,
(SCI_BASE_REQUEST_T *)task_request,
task_tag
);
}
else
{
SCIC_LOG_INFO((
sci_base_object_get_logger(controller),
SCIC_LOG_OBJECT_CONTROLLER,
"SCIC Controller starting task from invalid state\n"
));
}
return (SCI_TASK_STATUS)status;
}
SCI_STATUS scic_controller_complete_task(
SCI_CONTROLLER_HANDLE_T controller,
SCI_REMOTE_DEVICE_HANDLE_T remote_device,
SCI_TASK_REQUEST_HANDLE_T task_request
)
{
SCI_STATUS status = SCI_FAILURE_INVALID_STATE;
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
SCIC_LOG_TRACE((
sci_base_object_get_logger(controller),
SCIC_LOG_OBJECT_CONTROLLER,
"scic_controller_complete_task(0x%x, 0x%x, 0x%x) enter\n",
controller, remote_device, task_request
));
if (this_controller->state_handlers->parent.complete_task_handler != NULL)
{
status = this_controller->state_handlers->parent.complete_task_handler(
&this_controller->parent,
(SCI_BASE_REMOTE_DEVICE_T *)remote_device,
(SCI_BASE_REQUEST_T *)task_request
);
}
else
{
SCIC_LOG_INFO((
sci_base_object_get_logger(controller),
SCIC_LOG_OBJECT_CONTROLLER,
"SCIC Controller completing task from invalid state\n"
));
}
return status;
}
#endif
SCI_STATUS scic_controller_get_port_handle(
SCI_CONTROLLER_HANDLE_T controller,
U8 port_index,
SCI_PORT_HANDLE_T * port_handle
)
{
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
SCIC_LOG_TRACE((
sci_base_object_get_logger(controller),
SCIC_LOG_OBJECT_CONTROLLER,
"scic_controller_get_port_handle(0x%x, 0x%x, 0x%x) enter\n",
controller, port_index, port_handle
));
if (port_index < this_controller->logical_port_entries)
{
*port_handle = &this_controller->port_table[port_index];
return SCI_SUCCESS;
}
return SCI_FAILURE_INVALID_PORT;
}
SCI_STATUS scic_controller_get_phy_handle(
SCI_CONTROLLER_HANDLE_T controller,
U8 phy_index,
SCI_PHY_HANDLE_T * phy_handle
)
{
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
SCIC_LOG_TRACE((
sci_base_object_get_logger(controller),
SCIC_LOG_OBJECT_CONTROLLER,
"scic_controller_get_phy_handle(0x%x, 0x%x, 0x%x) enter\n",
controller, phy_index, phy_handle
));
if (phy_index < ARRAY_SIZE(this_controller->phy_table))
{
*phy_handle = &this_controller->phy_table[phy_index];
return SCI_SUCCESS;
}
SCIC_LOG_ERROR((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_PORT | SCIC_LOG_OBJECT_CONTROLLER,
"Controller:0x%x PhyId:0x%x invalid phy index\n",
this_controller, phy_index
));
return SCI_FAILURE_INVALID_PHY;
}
U16 scic_controller_allocate_io_tag(
SCI_CONTROLLER_HANDLE_T controller
)
{
U16 task_context;
U16 sequence_count;
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
SCIC_LOG_TRACE((
sci_base_object_get_logger(controller),
SCIC_LOG_OBJECT_CONTROLLER,
"scic_controller_allocate_io_tag(0x%x) enter\n",
controller
));
if (!sci_pool_empty(this_controller->tci_pool))
{
sci_pool_get(this_controller->tci_pool, task_context);
sequence_count = this_controller->io_request_sequence[task_context];
return scic_sds_io_tag_construct(sequence_count, task_context);
}
return SCI_CONTROLLER_INVALID_IO_TAG;
}
SCI_STATUS scic_controller_free_io_tag(
SCI_CONTROLLER_HANDLE_T controller,
U16 io_tag
)
{
U16 sequence;
U16 index;
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
ASSERT(io_tag != SCI_CONTROLLER_INVALID_IO_TAG);
SCIC_LOG_TRACE((
sci_base_object_get_logger(controller),
SCIC_LOG_OBJECT_CONTROLLER,
"scic_controller_free_io_tag(0x%x, 0x%x) enter\n",
controller, io_tag
));
sequence = scic_sds_io_tag_get_sequence(io_tag);
index = scic_sds_io_tag_get_index(io_tag);
if (!sci_pool_full(this_controller->tci_pool))
{
if (sequence == this_controller->io_request_sequence[index])
{
scic_sds_io_sequence_increment(
this_controller->io_request_sequence[index]);
sci_pool_put(this_controller->tci_pool, index);
return SCI_SUCCESS;
}
}
return SCI_FAILURE_INVALID_IO_TAG;
}
void scic_controller_enable_interrupts(
SCI_CONTROLLER_HANDLE_T controller
)
{
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
ASSERT(this_controller->smu_registers != NULL);
SMU_IMR_WRITE(this_controller, 0x00000000);
}
void scic_controller_disable_interrupts(
SCI_CONTROLLER_HANDLE_T controller
)
{
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
ASSERT(this_controller->smu_registers != NULL);
SMU_IMR_WRITE(this_controller, 0xffffffff);
}
SCI_STATUS scic_controller_set_mode(
SCI_CONTROLLER_HANDLE_T controller,
SCI_CONTROLLER_MODE operating_mode
)
{
SCIC_SDS_CONTROLLER_T *this_controller = (SCIC_SDS_CONTROLLER_T*)controller;
SCI_STATUS status = SCI_SUCCESS;
SCIC_LOG_TRACE((
sci_base_object_get_logger(controller),
SCIC_LOG_OBJECT_CONTROLLER,
"scic_controller_set_mode(0x%x, 0x%x) enter\n",
controller, operating_mode
));
if (
(this_controller->parent.state_machine.current_state_id
== SCI_BASE_CONTROLLER_STATE_INITIALIZING)
|| (this_controller->parent.state_machine.current_state_id
== SCI_BASE_CONTROLLER_STATE_INITIALIZED)
)
{
switch (operating_mode)
{
case SCI_MODE_SPEED:
this_controller->remote_node_entries =
MIN(this_controller->remote_node_entries, SCI_MAX_REMOTE_DEVICES);
this_controller->task_context_entries =
MIN(this_controller->task_context_entries, SCU_IO_REQUEST_COUNT);
this_controller->uf_control.buffers.count =
MIN(this_controller->uf_control.buffers.count, SCU_UNSOLICITED_FRAME_COUNT);
this_controller->completion_event_entries =
MIN(this_controller->completion_event_entries, SCU_EVENT_COUNT);
this_controller->completion_queue_entries =
MIN(this_controller->completion_queue_entries, SCU_COMPLETION_QUEUE_COUNT);
scic_sds_controller_build_memory_descriptor_table(this_controller);
break;
case SCI_MODE_SIZE:
this_controller->remote_node_entries =
MIN(this_controller->remote_node_entries, SCI_MIN_REMOTE_DEVICES);
this_controller->task_context_entries =
MIN(this_controller->task_context_entries, SCI_MIN_IO_REQUESTS);
this_controller->uf_control.buffers.count =
MIN(this_controller->uf_control.buffers.count, SCU_MIN_UNSOLICITED_FRAMES);
this_controller->completion_event_entries =
MIN(this_controller->completion_event_entries, SCU_MIN_EVENTS);
this_controller->completion_queue_entries =
MIN(this_controller->completion_queue_entries, SCU_MIN_COMPLETION_QUEUE_ENTRIES);
scic_sds_controller_build_memory_descriptor_table(this_controller);
break;
default:
status = SCI_FAILURE_INVALID_PARAMETER_VALUE;
break;
}
}
else
status = SCI_FAILURE_INVALID_STATE;
return status;
}
void scic_sds_controller_reset_hardware(
SCIC_SDS_CONTROLLER_T * this_controller
)
{
scic_controller_disable_interrupts(this_controller);
SMU_SMUSRCR_WRITE(this_controller, 0xFFFFFFFF);
scic_cb_stall_execution(1000);
SMU_CQGR_WRITE(this_controller, 0x00000000);
SCU_UFQGP_WRITE(this_controller, 0x00000000);
}
SCI_STATUS scic_user_parameters_set(
SCI_CONTROLLER_HANDLE_T controller,
SCIC_USER_PARAMETERS_T * scic_parms
)
{
SCIC_SDS_CONTROLLER_T * this_controller = (SCIC_SDS_CONTROLLER_T*)controller;
if (
(this_controller->parent.state_machine.current_state_id
== SCI_BASE_CONTROLLER_STATE_RESET)
|| (this_controller->parent.state_machine.current_state_id
== SCI_BASE_CONTROLLER_STATE_INITIALIZING)
|| (this_controller->parent.state_machine.current_state_id
== SCI_BASE_CONTROLLER_STATE_INITIALIZED)
)
{
U16 index;
for (index = 0; index < SCI_MAX_PHYS; index++)
{
if (!
( scic_parms->sds1.phys[index].max_speed_generation
<= SCIC_SDS_PARM_MAX_SPEED
&& scic_parms->sds1.phys[index].max_speed_generation
> SCIC_SDS_PARM_NO_SPEED
)
)
return SCI_FAILURE_INVALID_PARAMETER_VALUE;
if (
(scic_parms->sds1.phys[index].in_connection_align_insertion_frequency < 3) ||
(scic_parms->sds1.phys[index].align_insertion_frequency == 0) ||
(scic_parms->sds1.phys[index].notify_enable_spin_up_insertion_frequency == 0)
)
{
return SCI_FAILURE_INVALID_PARAMETER_VALUE;
}
}
if (
(scic_parms->sds1.stp_inactivity_timeout == 0) ||
(scic_parms->sds1.ssp_inactivity_timeout == 0) ||
(scic_parms->sds1.stp_max_occupancy_timeout == 0) ||
(scic_parms->sds1.ssp_max_occupancy_timeout == 0) ||
(scic_parms->sds1.no_outbound_task_timeout == 0)
)
{
return SCI_FAILURE_INVALID_PARAMETER_VALUE;
}
memcpy(
(&this_controller->user_parameters), scic_parms, sizeof(*scic_parms));
return SCI_SUCCESS;
}
return SCI_FAILURE_INVALID_STATE;
}
void scic_user_parameters_get(
SCI_CONTROLLER_HANDLE_T controller,
SCIC_USER_PARAMETERS_T * scic_parms
)
{
SCIC_SDS_CONTROLLER_T * this_controller = (SCIC_SDS_CONTROLLER_T*)controller;
memcpy(scic_parms, (&this_controller->user_parameters), sizeof(*scic_parms));
}
SCI_STATUS scic_oem_parameters_set(
SCI_CONTROLLER_HANDLE_T controller,
SCIC_OEM_PARAMETERS_T * scic_parms,
U8 scic_parms_version
)
{
SCIC_SDS_CONTROLLER_T * this_controller = (SCIC_SDS_CONTROLLER_T*)controller;
SCI_BIOS_OEM_PARAM_ELEMENT_T *old_oem_params =
(SCI_BIOS_OEM_PARAM_ELEMENT_T *)(&(scic_parms->sds1));
if (
(this_controller->parent.state_machine.current_state_id
== SCI_BASE_CONTROLLER_STATE_RESET)
|| (this_controller->parent.state_machine.current_state_id
== SCI_BASE_CONTROLLER_STATE_INITIALIZING)
|| (this_controller->parent.state_machine.current_state_id
== SCI_BASE_CONTROLLER_STATE_INITIALIZED)
)
{
U16 index;
U8 combined_phy_mask = 0;
this_controller->oem_parameters_version = scic_parms_version;
for(index=0; index<SCI_MAX_PORTS; index++)
{
if (scic_parms->sds1.ports[index].phy_mask > SCIC_SDS_PARM_PHY_MASK_MAX)
{
return SCI_FAILURE_INVALID_PARAMETER_VALUE;
}
}
for(index=0; index<SCI_MAX_PHYS; index++)
{
if (
scic_parms->sds1.phys[index].sas_address.sci_format.high == 0
&& scic_parms->sds1.phys[index].sas_address.sci_format.low == 0
)
{
return SCI_FAILURE_INVALID_PARAMETER_VALUE;
}
#if defined(PBG_HBA_A0_BUILD) || defined(PBG_HBA_A2_BUILD) || defined(PBG_HBA_BETA_BUILD) || defined(PBG_BUILD)
if (
(scic_parms->sds1.phys[index].afe_tx_amp_control0 == 0) ||
(scic_parms->sds1.phys[index].afe_tx_amp_control1 == 0) ||
(scic_parms->sds1.phys[index].afe_tx_amp_control2 == 0) ||
(scic_parms->sds1.phys[index].afe_tx_amp_control3 == 0)
)
{
return SCI_FAILURE_INVALID_PARAMETER_VALUE;
}
#endif
}
if (scic_parms->sds1.controller.mode_type == SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE)
{
for(index=0; index<SCI_MAX_PHYS; index++)
{
if (scic_parms->sds1.ports[index].phy_mask != 0)
{
return SCI_FAILURE_INVALID_PARAMETER_VALUE;
}
}
}
else if (scic_parms->sds1.controller.mode_type == SCIC_PORT_MANUAL_CONFIGURATION_MODE)
{
for(index=0; index<SCI_MAX_PHYS; index++)
{
combined_phy_mask |= scic_parms->sds1.ports[index].phy_mask;
}
if (combined_phy_mask == 0)
{
return SCI_FAILURE_INVALID_PARAMETER_VALUE;
}
}
else
{
return SCI_FAILURE_INVALID_PARAMETER_VALUE;
}
if (scic_parms->sds1.controller.max_number_concurrent_device_spin_up > MAX_CONCURRENT_DEVICE_SPIN_UP_COUNT)
{
return SCI_FAILURE_INVALID_PARAMETER_VALUE;
}
if (old_oem_params->controller.do_enable_ssc != 0)
{
if ( (scic_parms_version == SCI_OEM_PARAM_VER_1_0)
&& (old_oem_params->controller.do_enable_ssc != 0x01))
return SCI_FAILURE_INVALID_PARAMETER_VALUE;
if (scic_parms_version >= SCI_OEM_PARAM_VER_1_1)
{
SCI_BIOS_OEM_PARAM_ELEMENT_v_1_1_T *oem_params =
(SCI_BIOS_OEM_PARAM_ELEMENT_v_1_1_T*)(&(scic_parms->sds1));
U8 test = oem_params->controller.ssc_sata_tx_spread_level;
if ( !((test == 0x0) || (test == 0x2) || (test == 0x3) ||
(test == 0x6) || (test == 0x7)) )
return SCI_FAILURE_INVALID_PARAMETER_VALUE;
test = oem_params->controller.ssc_sas_tx_spread_level;
if (oem_params->controller.ssc_sas_tx_type == 0)
{
if ( !((test == 0x0) || (test == 0x2) || (test == 0x3)) )
return SCI_FAILURE_INVALID_PARAMETER_VALUE;
}
else
if (oem_params->controller.ssc_sas_tx_type == 1)
{
if ( !((test == 0x0) || (test == 0x3) || (test == 0x6)) )
return SCI_FAILURE_INVALID_PARAMETER_VALUE;
}
}
}
memcpy(
(&this_controller->oem_parameters), scic_parms, sizeof(*scic_parms));
return SCI_SUCCESS;
}
return SCI_FAILURE_INVALID_STATE;
}
void scic_oem_parameters_get(
SCI_CONTROLLER_HANDLE_T controller,
SCIC_OEM_PARAMETERS_T * scic_parms
)
{
SCIC_SDS_CONTROLLER_T * this_controller = (SCIC_SDS_CONTROLLER_T*)controller;
memcpy(scic_parms, (&this_controller->oem_parameters), sizeof(*scic_parms));
}
#if !defined(DISABLE_INTERRUPTS)
#define INTERRUPT_COALESCE_TIMEOUT_BASE_RANGE_LOWER_BOUND_NS 853
#define INTERRUPT_COALESCE_TIMEOUT_BASE_RANGE_UPPER_BOUND_NS 1280
#define INTERRUPT_COALESCE_TIMEOUT_MAX_US 2700000
#define INTERRUPT_COALESCE_NUMBER_MAX 256
#define INTERRUPT_COALESCE_TIMEOUT_ENCODE_MIN 7
#define INTERRUPT_COALESCE_TIMEOUT_ENCODE_MAX 28
SCI_STATUS scic_controller_set_interrupt_coalescence(
SCI_CONTROLLER_HANDLE_T controller,
U32 coalesce_number,
U32 coalesce_timeout
)
{
SCIC_SDS_CONTROLLER_T * scic_controller = (SCIC_SDS_CONTROLLER_T *)controller;
U8 timeout_encode = 0;
U32 min = 0;
U32 max = 0;
if (coalesce_number > INTERRUPT_COALESCE_NUMBER_MAX)
return SCI_FAILURE_INVALID_PARAMETER_VALUE;
if (coalesce_timeout == 0)
timeout_encode = 0;
else
{
coalesce_timeout = coalesce_timeout * 100;
min = INTERRUPT_COALESCE_TIMEOUT_BASE_RANGE_LOWER_BOUND_NS / 10;
max = INTERRUPT_COALESCE_TIMEOUT_BASE_RANGE_UPPER_BOUND_NS / 10;
for ( timeout_encode = INTERRUPT_COALESCE_TIMEOUT_ENCODE_MIN;
timeout_encode <= INTERRUPT_COALESCE_TIMEOUT_ENCODE_MAX;
timeout_encode++ )
{
if (min <= coalesce_timeout && max > coalesce_timeout)
break;
else if (coalesce_timeout >= max && coalesce_timeout < min*2
&& coalesce_timeout <= INTERRUPT_COALESCE_TIMEOUT_MAX_US*100)
{
if ( (coalesce_timeout-max) < (2*min - coalesce_timeout) )
break;
else
{
timeout_encode++;
break;
}
}
else
{
max = max*2;
min = min*2;
}
}
if ( timeout_encode == INTERRUPT_COALESCE_TIMEOUT_ENCODE_MAX+1 )
return SCI_FAILURE_INVALID_PARAMETER_VALUE;
}
SMU_ICC_WRITE(
scic_controller,
(SMU_ICC_GEN_VAL(NUMBER, coalesce_number)|
SMU_ICC_GEN_VAL(TIMER, timeout_encode))
);
scic_controller->interrupt_coalesce_number = (U16)coalesce_number;
scic_controller->interrupt_coalesce_timeout = coalesce_timeout/100;
return SCI_SUCCESS;
}
void scic_controller_get_interrupt_coalescence(
SCI_CONTROLLER_HANDLE_T controller,
U32 * coalesce_number,
U32 * coalesce_timeout
)
{
SCIC_SDS_CONTROLLER_T * scic_controller = (SCIC_SDS_CONTROLLER_T *)controller;
*coalesce_number = scic_controller->interrupt_coalesce_number;
*coalesce_timeout = scic_controller->interrupt_coalesce_timeout;
}
#endif
U32 scic_controller_get_scratch_ram_size(
SCI_CONTROLLER_HANDLE_T controller
)
{
return SCU_SCRATCH_RAM_SIZE_IN_DWORDS;
}
SCI_STATUS scic_controller_read_scratch_ram_dword(
SCI_CONTROLLER_HANDLE_T controller,
U32 offset,
U32 * value
)
{
U32 zpt_index;
SCIC_SDS_CONTROLLER_T * scic_controller = (SCIC_SDS_CONTROLLER_T *)controller;
U32 status = SMU_SMUCSR_READ(scic_controller);
if ((status & SCU_RAM_INIT_COMPLETED) != SCU_RAM_INIT_COMPLETED)
{
*value = 0x00000000;
return SCI_SUCCESS;
}
if (offset < scic_controller_get_scratch_ram_size(controller))
{
if(offset <= SCU_MAX_ZPT_DWORD_INDEX)
{
zpt_index = offset + (offset - (offset % 4)) + 4;
*value = scu_controller_scratch_ram_register_read(scic_controller,zpt_index);
}
else
{
offset = offset - 132;
zpt_index = offset + (offset - (offset % 4)) + 4;
*value = scu_controller_scratch_ram_register_read_ext(scic_controller,zpt_index);
}
return SCI_SUCCESS;
}
else
{
return SCI_FAILURE_INVALID_PARAMETER_VALUE;
}
}
SCI_STATUS scic_controller_write_scratch_ram_dword(
SCI_CONTROLLER_HANDLE_T controller,
U32 offset,
U32 value
)
{
U32 zpt_index;
if (offset < scic_controller_get_scratch_ram_size(controller))
{
SCIC_SDS_CONTROLLER_T * scic_controller = (SCIC_SDS_CONTROLLER_T *)controller;
if(offset <= SCU_MAX_ZPT_DWORD_INDEX)
{
zpt_index = offset + (offset - (offset % 4)) + 4;
scu_controller_scratch_ram_register_write(scic_controller,zpt_index,value);
}
else
{
offset = offset - 132;
zpt_index = offset + (offset - (offset % 4)) + 4;
scu_controller_scratch_ram_register_write_ext(scic_controller,zpt_index,value);
}
return SCI_SUCCESS;
}
else
{
return SCI_FAILURE_INVALID_PARAMETER_VALUE;
}
}
SCI_STATUS scic_controller_suspend(
SCI_CONTROLLER_HANDLE_T controller
)
{
SCIC_SDS_CONTROLLER_T * this_controller = (SCIC_SDS_CONTROLLER_T*)controller;
U8 index;
scic_controller_disable_interrupts(controller);
for (index = 0; index < SCI_MAX_PORTS; index++)
scic_sds_port_suspend_port_task_scheduler(
&(this_controller->port_table[index]));
SMU_CQGR_WRITE(this_controller, 0x00000000);
SCU_UFQGP_WRITE(this_controller, 0x00000000);
SMU_ISR_WRITE(this_controller, 0xFFFFFFFF);
this_controller->completion_queue_get = 0;
return SCI_SUCCESS;
}
SCI_STATUS scic_controller_resume(
SCI_CONTROLLER_HANDLE_T controller
)
{
SCIC_SDS_CONTROLLER_T * this_controller = (SCIC_SDS_CONTROLLER_T*)controller;
U8 index;
scic_sds_controller_initialize_completion_queue(this_controller);
scic_sds_controller_initialize_unsolicited_frame_queue(this_controller);
this_controller->restrict_completions = FALSE;
for (index = 0; index < SCI_MAX_PORTS; index++)
scic_sds_port_resume_port_task_scheduler(
&(this_controller->port_table[index]));
for (index = 0; index < SCI_MAX_PHYS; index ++)
{
SCIC_SDS_PHY_T * curr_phy = &this_controller->phy_table[index];
U32 link_layer_status = SCU_SAS_LLSTA_READ(curr_phy);
if ((link_layer_status & SCU_SAS_LLSTA_DWORD_SYNCA_BIT) == 0)
{
scic_sds_phy_restart_starting_state(curr_phy);
}
}
return SCI_SUCCESS;
}
SCI_STATUS scic_controller_transition(
SCI_CONTROLLER_HANDLE_T controller,
BOOL restrict_completions
)
{
SCI_STATUS result = SCI_FAILURE_INVALID_STATE;
SCIC_SDS_CONTROLLER_T * this_controller = (SCIC_SDS_CONTROLLER_T*)controller;
U8 index;
SCIC_LOG_TRACE((
sci_base_object_get_logger(controller),
SCIC_LOG_OBJECT_CONTROLLER,
"scic_controller_transition(0x%x) enter\n",
controller
));
if (this_controller->parent.state_machine.current_state_id
== SCI_BASE_CONTROLLER_STATE_READY)
{
for (index = 0; index < SCI_MAX_PORTS; index++)
{
if (this_controller->port_table[index].started_request_count != 0)
return result;
}
scic_controller_suspend(controller);
result = scic_sds_controller_validate_memory_descriptor_table(
this_controller);
if (result == SCI_SUCCESS)
{
scic_sds_controller_ram_initialization(this_controller);
this_controller->restrict_completions = restrict_completions;
}
scic_controller_resume(controller);
}
return result;
}
SCI_STATUS scic_controller_get_max_ports(
SCI_CONTROLLER_HANDLE_T controller,
U8 * count
)
{
*count = SCI_MAX_PORTS;
return SCI_SUCCESS;
}
SCI_STATUS scic_controller_get_max_phys(
SCI_CONTROLLER_HANDLE_T controller,
U8 * count
)
{
*count = SCI_MAX_PHYS;
return SCI_SUCCESS;
}
#define smu_dcc_get_max_ports(dcc_value) \
( \
( ((U32)((dcc_value) & SMU_DEVICE_CONTEXT_CAPACITY_MAX_LP_MASK)) \
>> SMU_DEVICE_CONTEXT_CAPACITY_MAX_LP_SHIFT ) + 1\
)
#define smu_dcc_get_max_task_context(dcc_value) \
( \
( ((U32)((dcc_value) & SMU_DEVICE_CONTEXT_CAPACITY_MAX_TC_MASK)) \
>> SMU_DEVICE_CONTEXT_CAPACITY_MAX_TC_SHIFT ) + 1\
)
#define smu_dcc_get_max_remote_node_context(dcc_value) \
( \
( ( (U32)((dcc_value) & SMU_DEVICE_CONTEXT_CAPACITY_MAX_RNC_MASK) )\
>> SMU_DEVICE_CONTEXT_CAPACITY_MAX_RNC_SHIFT ) + 1\
)
static
SCI_STATUS scic_sds_controller_default_start_operation_handler(
SCI_BASE_CONTROLLER_T *controller,
SCI_BASE_REMOTE_DEVICE_T *remote_device,
SCI_BASE_REQUEST_T *io_request,
U16 io_tag
)
{
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
SCIC_LOG_WARNING((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_CONTROLLER,
"SCIC Controller requested to start an io/task from invalid state %d\n",
sci_base_state_machine_get_state(
scic_sds_controller_get_base_state_machine(this_controller))
));
return SCI_FAILURE_INVALID_STATE;
}
static
SCI_STATUS scic_sds_controller_default_request_handler(
SCI_BASE_CONTROLLER_T *controller,
SCI_BASE_REMOTE_DEVICE_T *remote_device,
SCI_BASE_REQUEST_T *io_request
)
{
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
SCIC_LOG_WARNING((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_CONTROLLER,
"SCIC Controller request operation from invalid state %d\n",
sci_base_state_machine_get_state(
scic_sds_controller_get_base_state_machine(this_controller))
));
return SCI_FAILURE_INVALID_STATE;
}
static
SCI_STATUS scic_sds_controller_general_reset_handler(
SCI_BASE_CONTROLLER_T *controller
)
{
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
SCIC_LOG_TRACE((
sci_base_object_get_logger(controller),
SCIC_LOG_OBJECT_CONTROLLER,
"scic_sds_controller_resetting_state_enter(0x%x) enter\n",
controller
));
scic_sds_controller_release_resource(this_controller);
sci_base_state_machine_change_state(
scic_sds_controller_get_base_state_machine(this_controller),
SCI_BASE_CONTROLLER_STATE_RESETTING
);
return SCI_SUCCESS;
}
static
SCI_STATUS scic_sds_controller_reset_state_initialize_handler(
SCI_BASE_CONTROLLER_T *controller
)
{
U32 index;
SCI_STATUS result = SCI_SUCCESS;
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
SCIC_LOG_TRACE((
sci_base_object_get_logger(controller),
SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_INITIALIZATION,
"scic_sds_controller_reset_state_initialize_handler(0x%x) enter\n",
controller
));
sci_base_state_machine_change_state(
scic_sds_controller_get_base_state_machine(this_controller),
SCI_BASE_CONTROLLER_STATE_INITIALIZING
);
this_controller->timeout_timer = scic_cb_timer_create(
controller,
scic_sds_controller_timeout_handler,
controller
);
scic_sds_controller_initialize_power_control(this_controller);
scic_sds_controller_reset_hardware(this_controller);
#if defined(ARLINGTON_BUILD)
scic_sds_controller_lex_atux_initialization(this_controller);
#elif defined(PLEASANT_RIDGE_BUILD) \
|| defined(PBG_HBA_A0_BUILD) \
|| defined(PBG_HBA_A2_BUILD)
scic_sds_controller_afe_initialization(this_controller);
#elif defined(PBG_HBA_BETA_BUILD) || defined(PBG_BUILD)
scic_sds_controller_afe_initialization(this_controller);
#else
#endif
if (SCI_SUCCESS == result)
{
U32 status;
U32 terminate_loop;
SMU_SMUSRCR_WRITE(this_controller, 0x00000000);
result = SCI_FAILURE;
terminate_loop = 100;
while (terminate_loop-- && (result != SCI_SUCCESS))
{
scic_cb_stall_execution(SCU_CONTEXT_RAM_INIT_STALL_TIME);
status = SMU_SMUCSR_READ(this_controller);
if ((status & SCU_RAM_INIT_COMPLETED) == SCU_RAM_INIT_COMPLETED)
{
result = SCI_SUCCESS;
}
}
}
#ifdef ARLINGTON_BUILD
scic_sds_controller_enable_chipwatch(this_controller);
#endif
if (result == SCI_SUCCESS)
{
U32 max_supported_ports;
U32 max_supported_devices;
U32 max_supported_io_requests;
U32 device_context_capacity;
device_context_capacity = SMU_DCC_READ(this_controller);
max_supported_ports =
smu_dcc_get_max_ports(device_context_capacity);
max_supported_devices =
smu_dcc_get_max_remote_node_context(device_context_capacity);
max_supported_io_requests =
smu_dcc_get_max_task_context(device_context_capacity);
for (index = 0; index < max_supported_ports; index++)
{
scu_register_write(
this_controller,
this_controller->scu_registers->peg0.ptsg.protocol_engine[index],
index
);
}
scic_controller_set_mode(this_controller, SCI_MODE_SPEED);
this_controller->logical_port_entries =
MIN(max_supported_ports, this_controller->logical_port_entries);
this_controller->task_context_entries =
MIN(max_supported_io_requests, this_controller->task_context_entries);
this_controller->remote_node_entries =
MIN(max_supported_devices, this_controller->remote_node_entries);
}
if (result == SCI_SUCCESS)
{
U32 dma_configuration;
dma_configuration = SCU_PDMACR_READ(this_controller);
dma_configuration |= SCU_PDMACR_GEN_BIT(PCI_RELAXED_ORDERING_ENABLE);
SCU_PDMACR_WRITE(this_controller, dma_configuration);
dma_configuration = SCU_CDMACR_READ(this_controller);
dma_configuration |= SCU_CDMACR_GEN_BIT(PCI_RELAXED_ORDERING_ENABLE);
SCU_CDMACR_WRITE(this_controller, dma_configuration);
}
if (result == SCI_SUCCESS)
{
for (index = 0;
(result == SCI_SUCCESS) && (index < SCI_MAX_PHYS);
index++)
{
result = scic_sds_phy_initialize(
&this_controller->phy_table[index],
&this_controller->scu_registers->peg0.pe[index].tl,
&this_controller->scu_registers->peg0.pe[index].ll
);
}
}
if(result == SCI_SUCCESS)
{
scic_sgpio_hardware_initialize(this_controller);
}
if (result == SCI_SUCCESS)
{
for (index = 0;
(index < this_controller->logical_port_entries)
&& (result == SCI_SUCCESS);
index++)
{
result = scic_sds_port_initialize(
&this_controller->port_table[index],
&this_controller->scu_registers->peg0.ptsg.port[index],
&this_controller->scu_registers->peg0.ptsg.protocol_engine,
&this_controller->scu_registers->peg0.viit[index]
);
}
}
if (SCI_SUCCESS == result)
{
result = scic_sds_port_configuration_agent_initialize(
this_controller,
&this_controller->port_agent
);
}
if (result == SCI_SUCCESS)
{
sci_base_state_machine_change_state(
scic_sds_controller_get_base_state_machine(this_controller),
SCI_BASE_CONTROLLER_STATE_INITIALIZED
);
}
else
{
scic_sds_controller_release_resource(this_controller);
SCIC_LOG_TRACE((
sci_base_object_get_logger(controller),
SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_INITIALIZATION,
"Invalid Port Configuration from scic_sds_controller_reset_state_initialize_handler(0x%x) \n",
controller
));
}
return result;
}
static
SCI_STATUS scic_sds_controller_initialized_state_start_handler(
SCI_BASE_CONTROLLER_T * controller,
U32 timeout
)
{
U16 index;
SCI_STATUS result;
SCIC_SDS_CONTROLLER_T * this_controller;
this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
result = scic_sds_controller_validate_memory_descriptor_table(this_controller);
if (result == SCI_SUCCESS)
{
scic_sds_controller_ram_initialization(this_controller);
}
if (SCI_SUCCESS == result)
{
sci_pool_initialize(this_controller->tci_pool);
for (index = 0; index < this_controller->task_context_entries; index++)
{
sci_pool_put(this_controller->tci_pool, index);
}
scic_sds_remote_node_table_initialize(
&this_controller->available_remote_nodes,
this_controller->remote_node_entries
);
}
if (SCI_SUCCESS == result)
{
scic_controller_disable_interrupts(controller);
scic_sds_controller_enable_port_task_scheduler(this_controller);
scic_sds_controller_assign_task_entries(this_controller);
scic_sds_controller_initialize_completion_queue(this_controller);
scic_sds_controller_initialize_unsolicited_frame_queue(this_controller);
result = scic_sds_controller_initialize_phy_startup(this_controller);
}
for (
index = 0;
(index < this_controller->logical_port_entries) && (result == SCI_SUCCESS);
index++
)
{
result = this_controller->port_table[index].
state_handlers->parent.start_handler(&this_controller->port_table[index].parent);
}
if (SCI_SUCCESS == result)
{
scic_sds_controller_start_next_phy(this_controller);
if (timeout != 0)
scic_cb_timer_start(controller, this_controller->timeout_timer, timeout);
sci_base_state_machine_change_state(
scic_sds_controller_get_base_state_machine(this_controller),
SCI_BASE_CONTROLLER_STATE_STARTING
);
}
return result;
}
static
void scic_sds_controller_starting_state_link_up_handler(
SCIC_SDS_CONTROLLER_T *this_controller,
SCIC_SDS_PORT_T *port,
SCIC_SDS_PHY_T *phy
)
{
scic_sds_controller_phy_timer_stop(this_controller);
this_controller->port_agent.link_up_handler(
this_controller, &this_controller->port_agent, port, phy
);
scic_sds_controller_start_next_phy(this_controller);
}
static
void scic_sds_controller_starting_state_link_down_handler(
SCIC_SDS_CONTROLLER_T *this_controller,
SCIC_SDS_PORT_T *port,
SCIC_SDS_PHY_T *phy
)
{
this_controller->port_agent.link_down_handler(
this_controller, &this_controller->port_agent, port, phy
);
}
static
SCI_STATUS scic_sds_controller_ready_state_stop_handler(
SCI_BASE_CONTROLLER_T *controller,
U32 timeout
)
{
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
if (timeout != 0)
scic_cb_timer_start(controller, this_controller->timeout_timer, timeout);
sci_base_state_machine_change_state(
scic_sds_controller_get_base_state_machine(this_controller),
SCI_BASE_CONTROLLER_STATE_STOPPING
);
return SCI_SUCCESS;
}
static
SCI_STATUS scic_sds_controller_ready_state_start_io_handler(
SCI_BASE_CONTROLLER_T *controller,
SCI_BASE_REMOTE_DEVICE_T *remote_device,
SCI_BASE_REQUEST_T *io_request,
U16 io_tag
)
{
SCI_STATUS status;
SCIC_SDS_CONTROLLER_T *this_controller;
SCIC_SDS_REQUEST_T *the_request;
SCIC_SDS_REMOTE_DEVICE_T *the_device;
this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
the_request = (SCIC_SDS_REQUEST_T *)io_request;
the_device = (SCIC_SDS_REMOTE_DEVICE_T *)remote_device;
status = scic_sds_remote_device_start_io(this_controller, the_device, the_request);
if (status == SCI_SUCCESS)
{
this_controller->io_request_table[
scic_sds_io_tag_get_index(the_request->io_tag)] = the_request;
scic_sds_controller_post_request(
this_controller,
scic_sds_request_get_post_context(the_request)
);
}
return status;
}
static
SCI_STATUS scic_sds_controller_ready_state_complete_io_handler(
SCI_BASE_CONTROLLER_T *controller,
SCI_BASE_REMOTE_DEVICE_T *remote_device,
SCI_BASE_REQUEST_T *io_request
)
{
U16 index;
SCI_STATUS status;
SCIC_SDS_CONTROLLER_T *this_controller;
SCIC_SDS_REQUEST_T *the_request;
SCIC_SDS_REMOTE_DEVICE_T *the_device;
this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
the_request = (SCIC_SDS_REQUEST_T *)io_request;
the_device = (SCIC_SDS_REMOTE_DEVICE_T *)remote_device;
status = scic_sds_remote_device_complete_io(
this_controller, the_device, the_request);
if (status == SCI_SUCCESS)
{
index = scic_sds_io_tag_get_index(the_request->io_tag);
this_controller->io_request_table[index] = SCI_INVALID_HANDLE;
}
return status;
}
static
SCI_STATUS scic_sds_controller_ready_state_continue_io_handler(
SCI_BASE_CONTROLLER_T *controller,
SCI_BASE_REMOTE_DEVICE_T *remote_device,
SCI_BASE_REQUEST_T *io_request
)
{
SCIC_SDS_CONTROLLER_T *this_controller;
SCIC_SDS_REQUEST_T *the_request;
the_request = (SCIC_SDS_REQUEST_T *)io_request;
this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
this_controller->io_request_table[
scic_sds_io_tag_get_index(the_request->io_tag)] = the_request;
scic_sds_controller_post_request(
this_controller,
scic_sds_request_get_post_context(the_request)
);
return SCI_SUCCESS;
}
static
SCI_STATUS scic_sds_controller_ready_state_start_task_handler(
SCI_BASE_CONTROLLER_T *controller,
SCI_BASE_REMOTE_DEVICE_T *remote_device,
SCI_BASE_REQUEST_T *io_request,
U16 task_tag
)
{
SCIC_SDS_CONTROLLER_T *this_controller = (SCIC_SDS_CONTROLLER_T *)
controller;
SCIC_SDS_REQUEST_T *the_request = (SCIC_SDS_REQUEST_T *)
io_request;
SCIC_SDS_REMOTE_DEVICE_T *the_device = (SCIC_SDS_REMOTE_DEVICE_T *)
remote_device;
SCI_STATUS status;
status = scic_sds_remote_device_start_task(
this_controller, the_device, the_request
);
if (status == SCI_SUCCESS)
{
this_controller->io_request_table[
scic_sds_io_tag_get_index(the_request->io_tag)] = the_request;
scic_sds_controller_post_request(
this_controller,
scic_sds_request_get_post_context(the_request)
);
}
else if (status == SCI_FAILURE_RESET_DEVICE_PARTIAL_SUCCESS)
{
this_controller->io_request_table[
scic_sds_io_tag_get_index(the_request->io_tag)] = the_request;
status = SCI_SUCCESS;
}
return status;
}
static
SCI_STATUS scic_sds_controller_ready_state_terminate_request_handler(
SCI_BASE_CONTROLLER_T *controller,
SCI_BASE_REMOTE_DEVICE_T *remote_device,
SCI_BASE_REQUEST_T *io_request
)
{
SCIC_SDS_CONTROLLER_T *this_controller = (SCIC_SDS_CONTROLLER_T *)
controller;
SCIC_SDS_REQUEST_T *the_request = (SCIC_SDS_REQUEST_T *)
io_request;
SCI_STATUS status;
status = scic_sds_io_request_terminate(the_request);
if (status == SCI_SUCCESS)
{
scic_sds_controller_post_request(
this_controller,
scic_sds_request_get_post_context(the_request)
| SCU_CONTEXT_COMMAND_REQUEST_POST_TC_ABORT
);
}
return status;
}
static
void scic_sds_controller_ready_state_link_up_handler(
SCIC_SDS_CONTROLLER_T *this_controller,
SCIC_SDS_PORT_T *port,
SCIC_SDS_PHY_T *phy
)
{
this_controller->port_agent.link_up_handler(
this_controller, &this_controller->port_agent, port, phy
);
}
static
void scic_sds_controller_ready_state_link_down_handler(
SCIC_SDS_CONTROLLER_T *this_controller,
SCIC_SDS_PORT_T *port,
SCIC_SDS_PHY_T *phy
)
{
this_controller->port_agent.link_down_handler(
this_controller, &this_controller->port_agent, port, phy
);
}
static
SCI_STATUS scic_sds_controller_stopping_state_complete_io_handler(
SCI_BASE_CONTROLLER_T *controller,
SCI_BASE_REMOTE_DEVICE_T *remote_device,
SCI_BASE_REQUEST_T *io_request
)
{
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
return SCI_FAILURE;
}
static
void scic_sds_controller_stopping_state_device_stopped_handler(
SCIC_SDS_CONTROLLER_T * controller,
SCIC_SDS_REMOTE_DEVICE_T * remote_device
)
{
if (!scic_sds_controller_has_remote_devices_stopping(controller))
{
sci_base_state_machine_change_state(
&controller->parent.state_machine,
SCI_BASE_CONTROLLER_STATE_STOPPED
);
}
}
static
SCI_STATUS scic_sds_controller_failed_state_start_operation_handler(
SCI_BASE_CONTROLLER_T *controller,
SCI_BASE_REMOTE_DEVICE_T *remote_device,
SCI_BASE_REQUEST_T *io_request,
U16 io_tag
)
{
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
SCIC_LOG_WARNING((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_CONTROLLER,
"SCIC Controller requested to start an io/task from failed state %d\n",
sci_base_state_machine_get_state(
scic_sds_controller_get_base_state_machine(this_controller))
));
return SCI_FAILURE;
}
static
SCI_STATUS scic_sds_controller_failed_state_reset_handler(
SCI_BASE_CONTROLLER_T *controller
)
{
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
if (this_controller->parent.error == SCI_CONTROLLER_FATAL_MEMORY_ERROR) {
SCIC_LOG_TRACE((
sci_base_object_get_logger(controller),
SCIC_LOG_OBJECT_CONTROLLER,
"scic_sds_controller_resetting_state_enter(0x%x) enter\n not allowed with fatal memory error",
controller
));
return SCI_FAILURE;
} else {
return scic_sds_controller_general_reset_handler(controller);
}
}
static
SCI_STATUS scic_sds_controller_failed_state_terminate_request_handler(
SCI_BASE_CONTROLLER_T *controller,
SCI_BASE_REMOTE_DEVICE_T *remote_device,
SCI_BASE_REQUEST_T *io_request
)
{
SCIC_SDS_REQUEST_T *the_request = (SCIC_SDS_REQUEST_T *)
io_request;
return scic_sds_io_request_terminate(the_request);
}
SCIC_SDS_CONTROLLER_STATE_HANDLER_T
scic_sds_controller_state_handler_table[SCI_BASE_CONTROLLER_MAX_STATES] =
{
{
{
NULL,
NULL,
NULL,
NULL,
scic_sds_controller_default_start_operation_handler,
scic_sds_controller_default_start_operation_handler,
scic_sds_controller_default_request_handler,
scic_sds_controller_default_request_handler,
scic_sds_controller_default_request_handler,
NULL,
NULL
},
scic_sds_controller_default_request_handler,
NULL,
NULL,
NULL,
NULL
},
{
{
NULL,
NULL,
NULL,
scic_sds_controller_reset_state_initialize_handler,
scic_sds_controller_default_start_operation_handler,
scic_sds_controller_default_start_operation_handler,
scic_sds_controller_default_request_handler,
scic_sds_controller_default_request_handler,
scic_sds_controller_default_request_handler,
NULL,
NULL
},
scic_sds_controller_default_request_handler,
NULL,
NULL,
NULL,
NULL
},
{
{
NULL,
NULL,
NULL,
NULL,
scic_sds_controller_default_start_operation_handler,
scic_sds_controller_default_start_operation_handler,
scic_sds_controller_default_request_handler,
scic_sds_controller_default_request_handler,
scic_sds_controller_default_request_handler,
NULL,
NULL
},
scic_sds_controller_default_request_handler,
NULL,
NULL,
NULL,
NULL
},
{
{
scic_sds_controller_initialized_state_start_handler,
NULL,
NULL,
NULL,
scic_sds_controller_default_start_operation_handler,
scic_sds_controller_default_start_operation_handler,
scic_sds_controller_default_request_handler,
scic_sds_controller_default_request_handler,
scic_sds_controller_default_request_handler,
NULL,
NULL
},
scic_sds_controller_default_request_handler,
NULL,
NULL,
NULL,
NULL
},
{
{
NULL,
NULL,
NULL,
NULL,
scic_sds_controller_default_start_operation_handler,
scic_sds_controller_default_start_operation_handler,
scic_sds_controller_default_request_handler,
scic_sds_controller_default_request_handler,
scic_sds_controller_default_request_handler,
NULL,
NULL
},
scic_sds_controller_default_request_handler,
scic_sds_controller_starting_state_link_up_handler,
scic_sds_controller_starting_state_link_down_handler,
NULL,
NULL
},
{
{
NULL,
scic_sds_controller_ready_state_stop_handler,
scic_sds_controller_general_reset_handler,
NULL,
scic_sds_controller_ready_state_start_io_handler,
scic_sds_controller_default_start_operation_handler,
scic_sds_controller_ready_state_complete_io_handler,
scic_sds_controller_default_request_handler,
scic_sds_controller_ready_state_continue_io_handler,
scic_sds_controller_ready_state_start_task_handler,
scic_sds_controller_ready_state_complete_io_handler
},
scic_sds_controller_ready_state_terminate_request_handler,
scic_sds_controller_ready_state_link_up_handler,
scic_sds_controller_ready_state_link_down_handler,
NULL,
NULL
},
{
{
NULL,
NULL,
NULL,
NULL,
scic_sds_controller_default_start_operation_handler,
scic_sds_controller_default_start_operation_handler,
scic_sds_controller_default_request_handler,
scic_sds_controller_default_request_handler,
scic_sds_controller_default_request_handler,
NULL,
NULL
},
scic_sds_controller_default_request_handler,
NULL,
NULL,
NULL,
NULL
},
{
{
NULL,
NULL,
NULL,
NULL,
scic_sds_controller_default_start_operation_handler,
scic_sds_controller_default_start_operation_handler,
scic_sds_controller_stopping_state_complete_io_handler,
scic_sds_controller_default_request_handler,
scic_sds_controller_default_request_handler,
NULL,
NULL
},
scic_sds_controller_default_request_handler,
NULL,
NULL,
NULL,
scic_sds_controller_stopping_state_device_stopped_handler
},
{
{
NULL,
NULL,
scic_sds_controller_failed_state_reset_handler,
NULL,
scic_sds_controller_default_start_operation_handler,
scic_sds_controller_default_start_operation_handler,
scic_sds_controller_default_request_handler,
scic_sds_controller_default_request_handler,
scic_sds_controller_default_request_handler,
NULL,
NULL
},
scic_sds_controller_default_request_handler,
NULL,
NULL,
NULL,
NULL
},
{
{
NULL,
NULL,
scic_sds_controller_general_reset_handler,
NULL,
scic_sds_controller_failed_state_start_operation_handler,
scic_sds_controller_failed_state_start_operation_handler,
scic_sds_controller_default_request_handler,
scic_sds_controller_default_request_handler,
scic_sds_controller_default_request_handler,
NULL,
NULL
},
scic_sds_controller_failed_state_terminate_request_handler,
NULL,
NULL,
NULL
}
};
static
void scic_sds_controller_initial_state_enter(
SCI_BASE_OBJECT_T *object
)
{
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller= (SCIC_SDS_CONTROLLER_T *)object;
scic_sds_controller_set_base_state_handlers(
this_controller, SCI_BASE_CONTROLLER_STATE_INITIAL);
sci_base_state_machine_change_state(
&this_controller->parent.state_machine, SCI_BASE_CONTROLLER_STATE_RESET);
}
static
void scic_sds_controller_reset_state_enter(
SCI_BASE_OBJECT_T *object
)
{
U8 index;
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller= (SCIC_SDS_CONTROLLER_T *)object;
scic_sds_controller_set_base_state_handlers(
this_controller, SCI_BASE_CONTROLLER_STATE_RESET);
scic_sds_port_configuration_agent_construct(&this_controller->port_agent);
for (index = 0; index < (SCI_MAX_PORTS + 1); index++)
{
scic_sds_port_construct(
&this_controller->port_table[index],
(index == SCI_MAX_PORTS) ? SCIC_SDS_DUMMY_PORT : index,
this_controller
);
}
for (index = 0; index < SCI_MAX_PHYS; index++)
{
scic_sds_phy_construct(
&this_controller->phy_table[index],
&this_controller->port_table[SCI_MAX_PORTS],
index
);
}
this_controller->invalid_phy_mask = 0;
this_controller->completion_event_entries = SCU_EVENT_COUNT;
this_controller->completion_queue_entries = SCU_COMPLETION_QUEUE_COUNT;
this_controller->remote_node_entries = SCI_MAX_REMOTE_DEVICES;
this_controller->logical_port_entries = SCI_MAX_PORTS;
this_controller->task_context_entries = SCU_IO_REQUEST_COUNT;
this_controller->uf_control.buffers.count = SCU_UNSOLICITED_FRAME_COUNT;
this_controller->uf_control.address_table.count= SCU_UNSOLICITED_FRAME_COUNT;
scic_sds_controller_set_default_config_parameters(this_controller);
}
static
void scic_sds_controller_initializing_state_enter(
SCI_BASE_OBJECT_T *object
)
{
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller= (SCIC_SDS_CONTROLLER_T *)object;
scic_sds_controller_set_base_state_handlers(
this_controller, SCI_BASE_CONTROLLER_STATE_INITIALIZING);
}
static
void scic_sds_controller_initialized_state_enter(
SCI_BASE_OBJECT_T *object
)
{
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller= (SCIC_SDS_CONTROLLER_T *)object;
scic_sds_controller_set_base_state_handlers(
this_controller, SCI_BASE_CONTROLLER_STATE_INITIALIZED);
}
static
void scic_sds_controller_starting_state_enter(
SCI_BASE_OBJECT_T *object
)
{
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller= (SCIC_SDS_CONTROLLER_T *)object;
scic_sds_controller_set_base_state_handlers(
this_controller, SCI_BASE_CONTROLLER_STATE_STARTING);
}
static
void scic_sds_controller_starting_state_exit(
SCI_BASE_OBJECT_T *object
)
{
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller= (SCIC_SDS_CONTROLLER_T *)object;
scic_cb_timer_stop(object, this_controller->timeout_timer);
scic_cb_timer_destroy(
this_controller,
this_controller->phy_startup_timer
);
this_controller->phy_startup_timer = NULL;
}
static
void scic_sds_controller_ready_state_enter(
SCI_BASE_OBJECT_T *object
)
{
U32 clock_gating_unit_value;
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller= (SCIC_SDS_CONTROLLER_T *)object;
scic_sds_controller_set_base_state_handlers(
this_controller, SCI_BASE_CONTROLLER_STATE_READY);
clock_gating_unit_value = SMU_CGUCR_READ(this_controller);
clock_gating_unit_value &= ~( SMU_CGUCR_GEN_BIT(REGCLK_ENABLE)
| SMU_CGUCR_GEN_BIT(TXCLK_ENABLE)
| SMU_CGUCR_GEN_BIT(XCLK_ENABLE) );
clock_gating_unit_value |= SMU_CGUCR_GEN_BIT(IDLE_ENABLE);
SMU_CGUCR_WRITE(this_controller, clock_gating_unit_value);
scic_controller_set_interrupt_coalescence(
this_controller, 0x10, 250);
}
static
void scic_sds_controller_ready_state_exit(
SCI_BASE_OBJECT_T *object
)
{
U32 clock_gating_unit_value;
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller= (SCIC_SDS_CONTROLLER_T *)object;
clock_gating_unit_value = SMU_CGUCR_READ(this_controller);
clock_gating_unit_value &= ~SMU_CGUCR_GEN_BIT(IDLE_ENABLE);
clock_gating_unit_value |= ( SMU_CGUCR_GEN_BIT(REGCLK_ENABLE)
| SMU_CGUCR_GEN_BIT(TXCLK_ENABLE)
| SMU_CGUCR_GEN_BIT(XCLK_ENABLE) );
SMU_CGUCR_WRITE(this_controller, clock_gating_unit_value);
scic_controller_set_interrupt_coalescence(this_controller, 0, 0);
}
static
void scic_sds_controller_stopping_state_enter(
SCI_BASE_OBJECT_T *object
)
{
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller= (SCIC_SDS_CONTROLLER_T *)object;
scic_sds_controller_set_base_state_handlers(
this_controller, SCI_BASE_CONTROLLER_STATE_STOPPING);
scic_sds_controller_stop_devices(this_controller);
scic_sds_controller_stop_ports(this_controller);
if (!scic_sds_controller_has_remote_devices_stopping(this_controller))
{
sci_base_state_machine_change_state(
&this_controller->parent.state_machine,
SCI_BASE_CONTROLLER_STATE_STOPPED
);
}
}
static
void scic_sds_controller_stopping_state_exit(
SCI_BASE_OBJECT_T *object
)
{
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller= (SCIC_SDS_CONTROLLER_T *)object;
scic_cb_timer_stop(this_controller, this_controller->timeout_timer);
}
static
void scic_sds_controller_stopped_state_enter(
SCI_BASE_OBJECT_T *object
)
{
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller= (SCIC_SDS_CONTROLLER_T *)object;
scic_sds_controller_set_base_state_handlers(
this_controller, SCI_BASE_CONTROLLER_STATE_STOPPED);
scic_cb_timer_destroy(
this_controller,
this_controller->timeout_timer
);
this_controller->timeout_timer = NULL;
scic_sds_controller_stop_phys(this_controller);
scic_sds_port_configuration_agent_destroy(
this_controller,
&this_controller->port_agent
);
scic_cb_controller_stop_complete(this_controller, SCI_SUCCESS);
}
static
void scic_sds_controller_resetting_state_enter(
SCI_BASE_OBJECT_T *object
)
{
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller= (SCIC_SDS_CONTROLLER_T *)object;
SCIC_LOG_TRACE((
sci_base_object_get_logger(this_controller),
SCIC_LOG_OBJECT_CONTROLLER,
"scic_sds_controller_resetting_state_enter(0x%x) enter\n",
this_controller
));
scic_sds_controller_set_base_state_handlers(
this_controller, SCI_BASE_CONTROLLER_STATE_RESETTING);
scic_sds_controller_reset_hardware(this_controller);
sci_base_state_machine_change_state(
scic_sds_controller_get_base_state_machine(this_controller),
SCI_BASE_CONTROLLER_STATE_RESET
);
}
static
SCI_STATUS scic_sds_abort_reqests(
SCIC_SDS_CONTROLLER_T * controller,
SCIC_SDS_REMOTE_DEVICE_T * remote_device,
SCIC_SDS_PORT_T * port
)
{
SCI_STATUS status = SCI_SUCCESS;
SCI_STATUS terminate_status = SCI_SUCCESS;
SCIC_SDS_REQUEST_T *the_request;
U32 index;
U32 request_count;
if (remote_device != NULL)
request_count = remote_device->started_request_count;
else if (port != NULL)
request_count = port->started_request_count;
else
request_count = SCI_MAX_IO_REQUESTS;
for (index = 0;
(index < SCI_MAX_IO_REQUESTS) && (request_count > 0);
index++)
{
the_request = controller->io_request_table[index];
if (the_request != NULL)
{
if (the_request->target_device == remote_device
|| the_request->target_device->owning_port == port
|| (remote_device == NULL && port == NULL))
{
terminate_status = scic_controller_terminate_request(
controller,
the_request->target_device,
the_request
);
if (terminate_status != SCI_SUCCESS)
status = terminate_status;
request_count--;
}
}
}
return status;
}
SCI_STATUS scic_sds_terminate_reqests(
SCIC_SDS_CONTROLLER_T *this_controller,
SCIC_SDS_REMOTE_DEVICE_T *this_remote_device,
SCIC_SDS_PORT_T *this_port
)
{
SCI_STATUS status = SCI_SUCCESS;
SCI_STATUS abort_status = SCI_SUCCESS;
abort_status = scic_sds_abort_reqests(this_controller, this_remote_device, this_port);
if (abort_status != SCI_SUCCESS)
status = abort_status;
if (this_controller->parent.error == SCI_CONTROLLER_FATAL_MEMORY_ERROR)
abort_status = scic_sds_abort_reqests(this_controller, this_remote_device, this_port);
if (abort_status != SCI_SUCCESS)
status = abort_status;
return status;
}
static
SCI_STATUS scic_sds_terminate_all_requests(
SCIC_SDS_CONTROLLER_T * controller
)
{
return scic_sds_terminate_reqests(controller, NULL, NULL);
}
static
void scic_sds_controller_failed_state_enter(
SCI_BASE_OBJECT_T *object
)
{
SCIC_SDS_CONTROLLER_T *this_controller;
this_controller= (SCIC_SDS_CONTROLLER_T *)object;
scic_sds_controller_set_base_state_handlers(
this_controller, SCI_BASE_CONTROLLER_STATE_FAILED);
if (this_controller->parent.error == SCI_CONTROLLER_FATAL_MEMORY_ERROR)
scic_sds_terminate_all_requests(this_controller);
else
scic_sds_controller_release_resource(this_controller);
scic_cb_controller_error(this_controller,
this_controller->parent.error);
}
SCI_BASE_STATE_T
scic_sds_controller_state_table[SCI_BASE_CONTROLLER_MAX_STATES] =
{
{
SCI_BASE_CONTROLLER_STATE_INITIAL,
scic_sds_controller_initial_state_enter,
NULL,
},
{
SCI_BASE_CONTROLLER_STATE_RESET,
scic_sds_controller_reset_state_enter,
NULL,
},
{
SCI_BASE_CONTROLLER_STATE_INITIALIZING,
scic_sds_controller_initializing_state_enter,
NULL,
},
{
SCI_BASE_CONTROLLER_STATE_INITIALIZED,
scic_sds_controller_initialized_state_enter,
NULL,
},
{
SCI_BASE_CONTROLLER_STATE_STARTING,
scic_sds_controller_starting_state_enter,
scic_sds_controller_starting_state_exit,
},
{
SCI_BASE_CONTROLLER_STATE_READY,
scic_sds_controller_ready_state_enter,
scic_sds_controller_ready_state_exit,
},
{
SCI_BASE_CONTROLLER_STATE_RESETTING,
scic_sds_controller_resetting_state_enter,
NULL,
},
{
SCI_BASE_CONTROLLER_STATE_STOPPING,
scic_sds_controller_stopping_state_enter,
scic_sds_controller_stopping_state_exit,
},
{
SCI_BASE_CONTROLLER_STATE_STOPPED,
scic_sds_controller_stopped_state_enter,
NULL,
},
{
SCI_BASE_CONTROLLER_STATE_FAILED,
scic_sds_controller_failed_state_enter,
NULL,
}
};