diff options
Diffstat (limited to 'sys/dev/isci/scil/scic_sds_smp_request.c')
-rw-r--r-- | sys/dev/isci/scil/scic_sds_smp_request.c | 872 |
1 files changed, 872 insertions, 0 deletions
diff --git a/sys/dev/isci/scil/scic_sds_smp_request.c b/sys/dev/isci/scil/scic_sds_smp_request.c new file mode 100644 index 0000000..d6990e5 --- /dev/null +++ b/sys/dev/isci/scil/scic_sds_smp_request.c @@ -0,0 +1,872 @@ +/*- + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * BSD LICENSE + * + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#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> + +/** + * This method return the memory space required for STP PIO requests. + * + * @return U32 + */ +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; +} + +/** + * This macro returns the address of the smp command buffer in the smp request + * memory. No need to cast to SMP request type. + */ +#define scic_sds_smp_request_get_command_buffer_unaligned(memory) \ + ( ((char *)(memory)) + sizeof(SCIC_SDS_REQUEST_T) ) + +/** + * This macro aligns the smp command buffer in DWORD alignment +*/ +#define scic_sds_smp_request_align_command_buffer(address) \ + ((char *)( \ + (((POINTER_UINT)(address)) + (sizeof(U32) - 1)) \ + & ~(sizeof(U32)- 1) \ + )) + +/** + * This macro returns the DWORD-aligned smp command buffer +*/ +#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) \ + ))) + +/** + * This macro returns the address of the smp response buffer in the smp request + * memory. + */ +#define scic_sds_smp_request_get_response_buffer_unaligned(memory) \ + ( ((char *)(scic_sds_smp_request_get_command_buffer(memory))) \ + + sizeof(SMP_REQUEST_T) ) + +/** + * This macro aligns the smp command buffer in DWORD alignment +*/ +#define scic_sds_smp_request_align_response_buffer(address) \ + ((char *)( \ + (((POINTER_UINT)(address)) + (sizeof(U32) - 1)) \ + & ~(sizeof(U32)- 1) \ + )) + +/** + * This macro returns the DWORD-aligned smp resposne buffer +*/ +#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) \ + ))) + +/** + * This macro returs the task context buffer for the SMP request. + */ +#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) \ + )) + +/** + * This macro returns the dword-aligned smp task context buffer + */ +#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)) \ + ))) + +/** + * @brief This method build the remainder of the IO request object. + * + * @pre The scic_sds_general_request_construct() must be called before this + * call is valid. + * + * @param[in] this_request This parameter specifies the request object being + * constructed. + * + * @return none + */ + +void scic_sds_smp_request_assign_buffers( + SCIC_SDS_REQUEST_T *this_request +) +{ + // Assign all of the buffer pointers + 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); + } + +} +/** + * @brief This method is called by the SCI user to build an SMP + * IO request. + * + * @pre + * - The user must have previously called scic_io_request_construct() + * on the supplied IO request. + * + * @param[in] scic_io_request This parameter specifies the handle to the + * io request object to be built. + * + * @return Indicate if the controller successfully built the IO request. + * @retval SCI_SUCCESS This value is returned if the IO request was + * successfully built. + * @retval SCI_FAILURE_UNSUPPORTED_PROTOCOL This value is returned if the + * remote_device does not support the SMP protocol. + * @retval SCI_FAILURE_INVALID_ASSOCIATION This value is returned if the + * user did not properly set the association between the SCIC IO + * request and the user's IO request. Please refer to the + * sci_object_set_association() routine for more + * information. + */ +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; + + // Construct the started sub-state machine. + 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 + ); + + // Construct the SMP SCU Task Context + memcpy((char *)&smp_request, + this_request->command_buffer, + sizeof(SMP_REQUEST_T)); + + // Look at the SMP requests' header fields; for certain SAS 1.x SMP + // functions under SAS 2.0, a zero request length really indicates + // a non-zero default length. + 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; + // Default - zero is a valid default for 2.0. + } + } + + 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; +} + +/** + * @brief This method is called by the SCI user to build an SMP pass-through + * IO request. + * + * @pre + * - The user must have previously called scic_io_request_construct() + * on the supplied IO request. + * + * @param[in] scic_smp_request This parameter specifies the handle to the + * io request object to be built. + * + * @param[in] passthru_cb This parameter specifies the pointer to the callback + * structure that contains the function pointers + * + * @return Indicate if the controller successfully built the IO request. + */ +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; + + // Call the callback function to retrieve the SMP passthrough request + request_buffer_length_in_bytes = passthru_cb->scic_cb_smp_passthru_get_request ( + (void *)this_request, + &request_buffer + ); + + //copy the request to smp request + memcpy((char *)&smp_request.request.vendor_specific_request, + request_buffer, + request_buffer_length_in_bytes); + + //the header length in smp_request is in dwords - the sas spec has similar way, + //but the csmi header contains the number of bytes, so we need to convert the + //number of bytes to number of dwords + smp_request.header.request_length = (U8) (request_buffer_length_in_bytes / sizeof (U32)); + + //Grab the other needed fields from the smp request using callbacks + 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); + + // Construct the started sub-state machine. + 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 + ); + + // Construct the SMP SCU Task Context + 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; +} + +/** + * @brief This method will fill in the SCU Task Context for a SMP request. The + * following important settings are utilized: + * + * -# task_type == SCU_TASK_TYPE_SMP. This simply indicates + * that a normal request type (i.e. non-raw frame) is being + * utilized to perform task management. + * -# control_frame == 1. This ensures that the proper endianess + * is set so that the bytes are transmitted in the right order + * for a smp request frame. + * + * @param[in] this_request This parameter specifies the smp request object + * being constructed. + * + * @return none + */ +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; + + //byte swap the smp request. + 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 + )); + + // Fill in the TC with the its required data + // 00h + 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; + + //04h + 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; + + //08h + 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; + + //0ch + task_context->address_modifier = 0; + + //10h + task_context->ssp_command_iu_length = smp_request->header.request_length; + + //14h + task_context->transfer_length_bytes = 0; + + //18h ~ 30h, protocol specific + // since commandIU has been build by framework at this point, we just + // copy the frist DWord from command IU to this location. + memcpy((void *)(&task_context->type.smp), this_request->command_buffer, sizeof(U32) ); + + //40h + // "For SMP you could program it to zero. We would prefer that way so that + // done code will be consistent." - Venki + task_context->task_phase = 0; + + if (this_request->was_tag_assigned_by_user) + { + // Build the task context now since we have already read the data + 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 + { + // Build the task context now since we have already read the data + 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 + ) + // This is not assigned because we have to wait until we get a TCi + ); + } + + // Copy the physical address for the command buffer to the SCU Task Context + // command buffer should not contain command header. + 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); + + + //SMP response comes as UF, so no need to set response IU address. + task_context->response_iu_upper = 0; + task_context->response_iu_lower = 0; +} + +//****************************************************************************** +//* SMP REQUEST STATE MACHINE +//****************************************************************************** + +/** + * @brief This method processes an unsolicited frame while the SMP request is + * waiting for a response frame. It will copy the response data, release + * the unsolicited frame, and transition the request to the + * SCI_BASE_REQUEST_STATE_COMPLETED state. + * + * @param[in] this_request This parameter specifies the request for which + * the unsolicited frame was received. + * @param[in] frame_index This parameter indicates the unsolicited frame + * index that should contain the response. + * + * @return This method returns an indication of whether the response + * frame was handled successfully or not. + * @retval SCI_SUCCESS Currently this value is always returned and indicates + * successful processing of the TC response. + */ +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; + + // Save off the controller, so that we do not touch the request after it + // is completed. + 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 + ); + + //byte swap the 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; + + // Some expanders only report an attached SATA device, and + // not an STP target. Since the core depends on the STP + // target attribute to correctly build I/O, set the bit now + // if necessary. + 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 + )); + } + } + + //Don't need to copy to user space. User instead will refer to + //core request's response buffer. + + //copy the smp response to framework smp request's response buffer. + //scic_sds_smp_request_copy_response(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 + { + // This was not a response frame why did it get forwarded? + 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; +} + + +/** + * @brief This method processes an abnormal TC completion while the SMP + * request is waiting for a response frame. It decides what + * happened to the IO based on TC completion status. + * + * @param[in] this_request This parameter specifies the request for which + * the TC completion was received. + * @param[in] completion_code This parameter indicates the completion status + * information for the TC. + * + * @return Indicate if the tc completion handler was successful. + * @retval SCI_SUCCESS currently this method always returns 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): + //In the AWAIT RESPONSE state, any TC completion is unexpected. + //but if the TC has success status, we complete the IO anyway. + 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): + //These status has been seen in a specific LSI expander, which sometimes + //is not able to send smp response within 2 ms. This causes our hardware + //break the connection and set TC completion with one of these SMP_XXX_XX_ERR + //status. For these type of error, we ask scic user to retry the request. + 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: + // All other completion status cause the IO to be complete. If a NAK + // was received, then it is up to the user to retry the request. + 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; +} + + +/** + * @brief This method processes the completions transport layer (TL) status + * to determine if the SMP request was sent successfully. If the SMP + * request was sent successfully, then the state for the SMP request + * transits to waiting for a response frame. + * + * @param[in] this_request This parameter specifies the request for which + * the TC completion was received. + * @param[in] completion_code This parameter indicates the completion status + * information for the TC. + * + * @return Indicate if the tc completion handler was successful. + * @retval SCI_SUCCESS currently this method always returns 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: + // All other completion status cause the IO to be complete. If a NAK + // was received, then it is up to the user to retry the request. + 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_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE + { + { + 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_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION + { + { + 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 + } +}; + +/** + * @brief This method performs the actions required when entering the + * SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_RESPONSE sub-state. + * This includes setting the IO request state handlers for this + * sub-state. + * + * @param[in] object This parameter specifies the request object for which + * the sub-state change is occuring. + * + * @return none. + */ +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 + ); +} + +/** + * @brief This method performs the actions required when entering the + * SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION + * sub-state. This includes setting the SMP request state handlers for + * this sub-state. + * + * @param[in] object This parameter specifies the request object for which + * the sub-state change is occuring. + * + * @return none. + */ +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 + } +}; + + |