#include <sys/cdefs.h>
#include <dev/isci/scil/scic_sds_smp_request.h>
#include <dev/isci/scil/scic_sds_logger.h>
#include <dev/isci/scil/scic_sds_controller.h>
#include <dev/isci/scil/scic_sds_remote_device.h>
#include <dev/isci/scil/scic_remote_device.h>
#include <dev/isci/scil/sci_util.h>
#include <dev/isci/sci_environment.h>
#include <dev/isci/scil/intel_sas.h>
#include <dev/isci/scil/scic_sds_request.h>
#include <dev/isci/scil/scic_controller.h>
#include <dev/isci/scil/scu_completion_codes.h>
#include <dev/isci/scil/scu_task_context.h>
#include <dev/isci/scil/sci_base_state_machine.h>
U32 scic_sds_smp_request_get_object_size(void)
{
return sizeof(SCIC_SDS_REQUEST_T)
+ sizeof(SMP_REQUEST_T)
+ sizeof(U32)
+ sizeof(SMP_RESPONSE_T)
+ sizeof(U32)
+ sizeof(SCU_TASK_CONTEXT_T)
+ CACHE_LINE_SIZE;
}
#define scic_sds_smp_request_get_command_buffer_unaligned(memory) \
( ((char *)(memory)) + sizeof(SCIC_SDS_REQUEST_T) )
#define scic_sds_smp_request_align_command_buffer(address) \
((char *)( \
(((POINTER_UINT)(address)) + (sizeof(U32) - 1)) \
& ~(sizeof(U32)- 1) \
))
#define scic_sds_smp_request_get_command_buffer(memory) \
((char *) \
((char *)scic_sds_smp_request_align_command_buffer( \
(char *) scic_sds_smp_request_get_command_buffer_unaligned(memory) \
)))
#define scic_sds_smp_request_get_response_buffer_unaligned(memory) \
( ((char *)(scic_sds_smp_request_get_command_buffer(memory))) \
+ sizeof(SMP_REQUEST_T) )
#define scic_sds_smp_request_align_response_buffer(address) \
((char *)( \
(((POINTER_UINT)(address)) + (sizeof(U32) - 1)) \
& ~(sizeof(U32)- 1) \
))
#define scic_sds_smp_request_get_response_buffer(memory) \
((char *) \
((char *)scic_sds_smp_request_align_response_buffer( \
(char *) scic_sds_smp_request_get_response_buffer_unaligned(memory) \
)))
#define scic_sds_smp_request_get_task_context_buffer_unaligned(memory) \
((SCU_TASK_CONTEXT_T *)( \
((char *)(scic_sds_smp_request_get_response_buffer(memory))) \
+ sizeof(SMP_RESPONSE_T) \
))
#define scic_sds_smp_request_get_task_context_buffer(memory) \
((SCU_TASK_CONTEXT_T *)( \
((char *)scic_sds_request_align_task_context_buffer( \
(char *)scic_sds_smp_request_get_task_context_buffer_unaligned(memory)) \
)))
void scic_sds_smp_request_assign_buffers(
SCIC_SDS_REQUEST_T *this_request
)
{
this_request->command_buffer =
scic_sds_smp_request_get_command_buffer(this_request);
this_request->response_buffer =
scic_sds_smp_request_get_response_buffer(this_request);
this_request->sgl_element_pair_buffer = NULL;
if (this_request->was_tag_assigned_by_user == FALSE)
{
this_request->task_context_buffer =
scic_sds_smp_request_get_task_context_buffer(this_request);
}
}
SCI_STATUS scic_io_request_construct_smp(
SCI_IO_REQUEST_HANDLE_T scic_smp_request
)
{
SMP_REQUEST_T smp_request;
SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *) scic_smp_request;
SCIC_LOG_TRACE((
sci_base_object_get_logger(this_request),
SCIC_LOG_OBJECT_SMP_IO_REQUEST,
"scic_io_request_construct_smp(0x%x) enter\n",
this_request
));
this_request->protocol = SCIC_SMP_PROTOCOL;
this_request->has_started_substate_machine = TRUE;
sci_base_state_machine_construct(
&this_request->started_substate_machine,
&this_request->parent.parent,
scic_sds_smp_request_started_substate_table,
SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE
);
memcpy((char *)&smp_request,
this_request->command_buffer,
sizeof(SMP_REQUEST_T));
if( smp_request.header.request_length == 0 )
{
switch( smp_request.header.function )
{
case SMP_FUNCTION_DISCOVER:
case SMP_FUNCTION_REPORT_PHY_ERROR_LOG:
case SMP_FUNCTION_REPORT_PHY_SATA:
case SMP_FUNCTION_REPORT_ROUTE_INFORMATION:
smp_request.header.request_length = 2;
break;
case SMP_FUNCTION_CONFIGURE_ROUTE_INFORMATION:
case SMP_FUNCTION_PHY_CONTROL:
case SMP_FUNCTION_PHY_TEST:
smp_request.header.request_length = 9;
break;
}
}
scu_smp_request_construct_task_context(
this_request,
&smp_request
);
sci_base_state_machine_change_state(
&this_request->parent.state_machine,
SCI_BASE_REQUEST_STATE_CONSTRUCTED
);
return SCI_SUCCESS;
}
SCI_STATUS scic_io_request_construct_smp_pass_through(
SCI_IO_REQUEST_HANDLE_T scic_smp_request,
SCIC_SMP_PASSTHRU_REQUEST_CALLBACKS_T *passthru_cb
)
{
SMP_REQUEST_T smp_request;
U8 * request_buffer;
U32 request_buffer_length_in_bytes;
SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *) scic_smp_request;
SCIC_LOG_TRACE((
sci_base_object_get_logger(this_request),
SCIC_LOG_OBJECT_SMP_IO_REQUEST,
"scic_io_request_construct_smp_pass_through(0x%x) enter\n",
this_request
));
this_request->protocol = SCIC_SMP_PROTOCOL;
this_request->has_started_substate_machine = TRUE;
request_buffer_length_in_bytes = passthru_cb->scic_cb_smp_passthru_get_request (
(void *)this_request,
&request_buffer
);
memcpy((char *)&smp_request.request.vendor_specific_request,
request_buffer,
request_buffer_length_in_bytes);
smp_request.header.request_length = (U8) (request_buffer_length_in_bytes / sizeof (U32));
smp_request.header.smp_frame_type = passthru_cb->scic_cb_smp_passthru_get_frame_type ((void *)this_request);
smp_request.header.function = passthru_cb->scic_cb_smp_passthru_get_function ((void *)this_request);
smp_request.header.allocated_response_length = passthru_cb->scic_cb_smp_passthru_get_allocated_response_length((void *)this_request);
sci_base_state_machine_construct(
&this_request->started_substate_machine,
&this_request->parent.parent,
scic_sds_smp_request_started_substate_table,
SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE
);
scu_smp_request_construct_task_context (this_request, &smp_request);
sci_base_state_machine_change_state(
&this_request->parent.state_machine,
SCI_BASE_REQUEST_STATE_CONSTRUCTED
);
return SCI_SUCCESS;
}
void scu_smp_request_construct_task_context(
SCIC_SDS_REQUEST_T *this_request,
SMP_REQUEST_T *smp_request
)
{
SCI_PHYSICAL_ADDRESS physical_address;
SCIC_SDS_CONTROLLER_T *owning_controller;
SCIC_SDS_REMOTE_DEVICE_T *target_device;
SCIC_SDS_PORT_T *target_port;
SCU_TASK_CONTEXT_T *task_context;
scic_word_copy_with_swap(
this_request->command_buffer,
(U32*) smp_request,
sizeof(SMP_REQUEST_T)/sizeof(U32)
);
task_context = scic_sds_request_get_task_context(this_request);
owning_controller = scic_sds_request_get_controller(this_request);
target_device = scic_sds_request_get_device(this_request);
target_port = scic_sds_request_get_port(this_request);
SCIC_LOG_TRACE((
sci_base_object_get_logger(this_request),
SCIC_LOG_OBJECT_SMP_IO_REQUEST,
"scu_smp_request_construct_task_context(0x%x) contents\n"
" reqlen=%x; function=%x;\n",
this_request,
smp_request->header.request_length,
smp_request->header.function
));
task_context->priority = 0;
task_context->initiator_request = 1;
task_context->connection_rate =
scic_remote_device_get_connection_rate(target_device);
task_context->protocol_engine_index =
scic_sds_controller_get_protocol_engine_group(owning_controller);
task_context->logical_port_index =
scic_sds_port_get_index(target_port);
task_context->protocol_type = SCU_TASK_CONTEXT_PROTOCOL_SMP;
task_context->abort = 0;
task_context->valid = SCU_TASK_CONTEXT_VALID;
task_context->context_type = SCU_TASK_CONTEXT_TYPE;
task_context->remote_node_index = this_request->target_device->rnc->remote_node_index;
task_context->command_code = 0;
task_context->task_type = SCU_TASK_TYPE_SMP_REQUEST;
task_context->link_layer_control = 0;
task_context->do_not_dma_ssp_good_response = 1;
task_context->strict_ordering = 0;
task_context->control_frame = 1;
task_context->timeout_enable = 0;
task_context->block_guard_enable = 0;
task_context->address_modifier = 0;
task_context->ssp_command_iu_length = smp_request->header.request_length;
task_context->transfer_length_bytes = 0;
memcpy((void *)(&task_context->type.smp), this_request->command_buffer, sizeof(U32) );
task_context->task_phase = 0;
if (this_request->was_tag_assigned_by_user)
{
this_request->post_context = (
SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC
| (
scic_sds_controller_get_protocol_engine_group(owning_controller)
<< SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT
)
| (
scic_sds_port_get_index(target_port)
<< SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT
)
| scic_sds_io_tag_get_index(this_request->io_tag)
);
}
else
{
this_request->post_context = (
SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC
| (
scic_sds_controller_get_protocol_engine_group(owning_controller)
<< SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT
)
| (
scic_sds_port_get_index(target_port)
<< SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT
)
);
}
scic_cb_io_request_get_physical_address(
scic_sds_request_get_controller(this_request),
this_request,
((char *)(this_request->command_buffer) + sizeof(U32)),
&physical_address
);
task_context->command_iu_upper =
sci_cb_physical_address_upper(physical_address);
task_context->command_iu_lower =
sci_cb_physical_address_lower(physical_address);
task_context->response_iu_upper = 0;
task_context->response_iu_lower = 0;
}
static
SCI_STATUS scic_sds_smp_request_await_response_frame_handler(
SCIC_SDS_REQUEST_T * this_request,
U32 frame_index
)
{
SCI_STATUS status;
void * frame_header;
SMP_RESPONSE_HEADER_T * this_frame_header;
U8 * user_smp_buffer = this_request->response_buffer;
SCIC_SDS_CONTROLLER_T * controller = scic_sds_request_get_controller(this_request);
SCIC_LOG_TRACE((
sci_base_object_get_logger(this_request),
SCIC_LOG_OBJECT_SMP_IO_REQUEST,
"scic_sds_smp_request_await_response_frame_handler(0x%x, 0x%x) enter\n",
this_request, frame_index
));
status = scic_sds_unsolicited_frame_control_get_header(
&(controller->uf_control),
frame_index,
&frame_header
);
scic_word_copy_with_swap(
(U32*) user_smp_buffer,
frame_header,
sizeof(SMP_RESPONSE_HEADER_T)/sizeof(U32)
);
this_frame_header = (SMP_RESPONSE_HEADER_T*) user_smp_buffer;
if (this_frame_header->smp_frame_type == SMP_FRAME_TYPE_RESPONSE)
{
void * smp_response_buffer;
status = scic_sds_unsolicited_frame_control_get_buffer(
&(controller->uf_control),
frame_index,
&smp_response_buffer
);
scic_word_copy_with_swap(
(U32*) (user_smp_buffer + sizeof(SMP_RESPONSE_HEADER_T)),
smp_response_buffer,
sizeof(SMP_RESPONSE_BODY_T)/sizeof(U32)
);
if (this_frame_header->function == SMP_FUNCTION_DISCOVER)
{
SMP_RESPONSE_T * this_smp_response;
this_smp_response = (SMP_RESPONSE_T *)user_smp_buffer;
if (this_smp_response->response.discover.protocols.u.bits.attached_sata_device
&& !this_smp_response->response.discover.protocols.u.bits.attached_stp_target)
{
this_smp_response->response.discover.protocols.u.bits.attached_stp_target = 1;
SCIC_LOG_TRACE((
sci_base_object_get_logger(this_request),
SCIC_LOG_OBJECT_SMP_IO_REQUEST,
"scic_sds_smp_request_await_response_frame_handler(0x%x) Found SATA dev, setting STP bit.\n",
this_request
));
}
}
scic_sds_request_set_status(
this_request, SCU_TASK_DONE_GOOD, SCI_SUCCESS
);
sci_base_state_machine_change_state(
&this_request->started_substate_machine,
SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION
);
}
else
{
SCIC_LOG_ERROR((
sci_base_object_get_logger(this_request),
SCIC_LOG_OBJECT_SMP_IO_REQUEST,
"SCIC SMP Request 0x%08x received unexpected frame %d type 0x%02x\n",
this_request, frame_index, this_frame_header->smp_frame_type
));
scic_sds_request_set_status(
this_request,
SCU_TASK_DONE_SMP_FRM_TYPE_ERR,
SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR
);
sci_base_state_machine_change_state(
&this_request->parent.state_machine,
SCI_BASE_REQUEST_STATE_COMPLETED
);
}
scic_sds_controller_release_frame(
controller, frame_index
);
return SCI_SUCCESS;
}
static
SCI_STATUS scic_sds_smp_request_await_response_tc_completion_handler(
SCIC_SDS_REQUEST_T * this_request,
U32 completion_code
)
{
SCIC_LOG_TRACE((
sci_base_object_get_logger(this_request),
SCIC_LOG_OBJECT_SMP_IO_REQUEST,
"scic_sds_smp_request_await_response_tc_completion_handler(0x%x, 0x%x) enter\n",
this_request, completion_code
));
switch (SCU_GET_COMPLETION_TL_STATUS(completion_code))
{
case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD):
scic_sds_request_set_status(
this_request, SCU_TASK_DONE_GOOD, SCI_SUCCESS
);
sci_base_state_machine_change_state(
&this_request->parent.state_machine,
SCI_BASE_REQUEST_STATE_COMPLETED
);
break;
case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_RESP_TO_ERR):
case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_UFI_ERR):
case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_FRM_TYPE_ERR):
case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_LL_RX_ERR):
scic_sds_request_set_status(
this_request, SCU_TASK_DONE_SMP_RESP_TO_ERR, SCI_FAILURE_RETRY_REQUIRED
);
sci_base_state_machine_change_state(
&this_request->parent.state_machine,
SCI_BASE_REQUEST_STATE_COMPLETED
);
break;
default:
scic_sds_request_set_status(
this_request,
SCU_NORMALIZE_COMPLETION_STATUS(completion_code),
SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR
);
sci_base_state_machine_change_state(
&this_request->parent.state_machine,
SCI_BASE_REQUEST_STATE_COMPLETED
);
break;
}
return SCI_SUCCESS;
}
static
SCI_STATUS scic_sds_smp_request_await_tc_completion_tc_completion_handler(
SCIC_SDS_REQUEST_T * this_request,
U32 completion_code
)
{
SCIC_LOG_TRACE((
sci_base_object_get_logger(this_request),
SCIC_LOG_OBJECT_SMP_IO_REQUEST,
"scic_sds_smp_request_await_tc_completion_tc_completion_handler(0x%x, 0x%x) enter\n",
this_request, completion_code
));
switch (SCU_GET_COMPLETION_TL_STATUS(completion_code))
{
case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD):
scic_sds_request_set_status(
this_request, SCU_TASK_DONE_GOOD, SCI_SUCCESS
);
sci_base_state_machine_change_state(
&this_request->parent.state_machine,
SCI_BASE_REQUEST_STATE_COMPLETED
);
break;
default:
scic_sds_request_set_status(
this_request,
SCU_NORMALIZE_COMPLETION_STATUS(completion_code),
SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR
);
sci_base_state_machine_change_state(
&this_request->parent.state_machine,
SCI_BASE_REQUEST_STATE_COMPLETED
);
break;
}
return SCI_SUCCESS;
}
SCIC_SDS_IO_REQUEST_STATE_HANDLER_T
scic_sds_smp_request_started_substate_handler_table
[SCIC_SDS_SMP_REQUEST_STARTED_MAX_SUBSTATES] =
{
{
{
scic_sds_request_default_start_handler,
scic_sds_request_started_state_abort_handler,
scic_sds_request_default_complete_handler,
scic_sds_request_default_destruct_handler
},
scic_sds_smp_request_await_response_tc_completion_handler,
scic_sds_request_default_event_handler,
scic_sds_smp_request_await_response_frame_handler
},
{
{
scic_sds_request_default_start_handler,
scic_sds_request_started_state_abort_handler,
scic_sds_request_default_complete_handler,
scic_sds_request_default_destruct_handler
},
scic_sds_smp_request_await_tc_completion_tc_completion_handler,
scic_sds_request_default_event_handler,
scic_sds_request_default_frame_handler
}
};
static
void scic_sds_smp_request_started_await_response_substate_enter(
SCI_BASE_OBJECT_T *object
)
{
SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)object;
SET_STATE_HANDLER(
this_request,
scic_sds_smp_request_started_substate_handler_table,
SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE
);
}
static
void scic_sds_smp_request_started_await_tc_completion_substate_enter(
SCI_BASE_OBJECT_T *object
)
{
SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)object;
SET_STATE_HANDLER(
this_request,
scic_sds_smp_request_started_substate_handler_table,
SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION
);
}
SCI_BASE_STATE_T scic_sds_smp_request_started_substate_table
[SCIC_SDS_SMP_REQUEST_STARTED_MAX_SUBSTATES] =
{
{
SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE,
scic_sds_smp_request_started_await_response_substate_enter,
NULL
},
{
SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION,
scic_sds_smp_request_started_await_tc_completion_substate_enter,
NULL
}
};