diff options
Diffstat (limited to 'sys/dev/isci/scil/scif_sas_smp_io_request.c')
-rw-r--r-- | sys/dev/isci/scil/scif_sas_smp_io_request.c | 600 |
1 files changed, 600 insertions, 0 deletions
diff --git a/sys/dev/isci/scil/scif_sas_smp_io_request.c b/sys/dev/isci/scil/scif_sas_smp_io_request.c new file mode 100644 index 0000000..9a05232 --- /dev/null +++ b/sys/dev/isci/scil/scif_sas_smp_io_request.c @@ -0,0 +1,600 @@ +/*- + * 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$"); + +/** + * @file + * + * @brief This file contains the method implementations for the + * SCIF_SAS_SMP_IO_REQUEST object. The contents will implement SMP + * specific functionality. + */ + +#include <dev/isci/scil/scif_sas_smp_io_request.h> +#include <dev/isci/scil/scif_sas_logger.h> +#include <dev/isci/scil/scif_sas_controller.h> +#include <dev/isci/scil/sci_controller.h> + +#include <dev/isci/scil/sci_status.h> +#include <dev/isci/scil/scic_io_request.h> +#include <dev/isci/scil/scic_user_callback.h> + +#include <dev/isci/scil/intel_sas.h> + +/** + * @brief This routine is to fill in the space given by core the SMP command + * frame. Then it calls core's construction. + * + * @param[in] fw_io The smp io request to be constructed. + * @param[in] smp_command The SMP request filled according to SAS spec. + * + * @return none + */ +void scif_sas_smp_request_construct( + SCIF_SAS_REQUEST_T * fw_request, + SMP_REQUEST_T * smp_command +) +{ + void * command_iu_address = + scic_io_request_get_command_iu_address(fw_request->core_object); + + //copy the smp_command to the address; + memcpy( (char*) command_iu_address, + smp_command, + sizeof(SMP_REQUEST_T) + ); + + scic_io_request_construct_smp(fw_request->core_object); + + fw_request->protocol_complete_handler + = NULL; +} + +/** + * @brief This method will perform all of the construction common to all + * SMP requests (e.g. filling in the frame type, zero-out memory, + * etc.). + * + * @param[out] smp_request This parameter specifies the SMP request + * structure containing the SMP request to be sent to the + * SMP target. + * @param[in] smp_function This parameter specifies the SMP function to + * sent. + * @param[in] smp_response_length This parameter specifies the length of + * the response (in DWORDs) that will be returned for this + * SMP request. + * @param[in] smp_request_length This parameter specifies the length of + * the request (in DWORDs) that will be sent. + */ +static +void scif_sas_smp_protocol_request_construct( + SMP_REQUEST_T * smp_request, + U8 smp_function, + U8 smp_response_length, + U8 smp_request_length +) +{ + memset((char*)smp_request, 0, sizeof(SMP_REQUEST_T)); + + smp_request->header.smp_frame_type = SMP_FRAME_TYPE_REQUEST; + smp_request->header.function = smp_function; + smp_request->header.allocated_response_length = smp_response_length; + smp_request->header.request_length = smp_request_length; +} + + +/** + * @brief This method will allocate the internal IO request object and + * construct its contents based upon the supplied SMP request. + * + * @param[in] fw_controller This parameter specifies the controller object + * from which to allocate the internal IO request. + * @param[in] fw_device This parameter specifies the remote device for + * which the internal IO request is destined. + * @param[in] smp_request This parameter specifies the SMP request contents + * to be sent to the SMP target. + * + * @return void * The address of built scif sas smp request. + */ +static +void * scif_sas_smp_request_build( + SCIF_SAS_CONTROLLER_T * fw_controller, + SCIF_SAS_REMOTE_DEVICE_T * fw_device, + SMP_REQUEST_T * smp_request, + void * external_request_object, + void * external_memory +) +{ + if (external_memory != NULL && external_request_object != NULL) + { + scif_sas_io_request_construct_smp( + fw_controller, + fw_device, + external_memory, + (char *)external_memory + sizeof(SCIF_SAS_IO_REQUEST_T), + SCI_CONTROLLER_INVALID_IO_TAG, + smp_request, + external_request_object + ); + + return external_memory; + } + else + { + void * internal_io_memory; + internal_io_memory = scif_sas_controller_allocate_internal_request(fw_controller); + ASSERT(internal_io_memory != NULL); + + if (internal_io_memory != NULL) + { + //construct, only when we got valid io memory. + scif_sas_internal_io_request_construct_smp( + fw_controller, + fw_device, + internal_io_memory, + SCI_CONTROLLER_INVALID_IO_TAG, + smp_request + ); + } + else + { + SCIF_LOG_ERROR(( + sci_base_object_get_logger(fw_controller), + SCIF_LOG_OBJECT_IO_REQUEST, + "scif_sas_smp_request_build, no memory available!\n" + )); + } + + return internal_io_memory; + } +} + +/** + * @brief construct a smp Report Genernal command to the fw_device. + * + * @param[in] fw_controller The framework controller object. + * @param[in] fw_device the framework device that the REPORT GENERAL command + * targets to. + * + * @return void * address to the built scif sas smp request. + */ +void * scif_sas_smp_request_construct_report_general( + SCIF_SAS_CONTROLLER_T * fw_controller, + SCIF_SAS_REMOTE_DEVICE_T * fw_device +) +{ + SMP_REQUEST_T smp_report_general; + + // Build the REPORT GENERAL request. + scif_sas_smp_protocol_request_construct( + &smp_report_general, + SMP_FUNCTION_REPORT_GENERAL, + sizeof(SMP_RESPONSE_REPORT_GENERAL_T) / sizeof(U32), + 0 + ); + + smp_report_general.request.report_general.crc = 0; + + SCIF_LOG_INFO(( + sci_base_object_get_logger(fw_device), + SCIF_LOG_OBJECT_IO_REQUEST | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, + "SMP REPORT GENERAL - Device:0x%x\n", + fw_device + )); + + return scif_sas_smp_request_build( + fw_controller, fw_device, &smp_report_general, NULL, NULL); +} + +/** + * @brief construct a SMP Report Manufacturer Info request to the fw_device. + * + * @param[in] fw_controller The framework controller object. + * @param[in] fw_device the framework device that the REPORT MANUFACTURER + * INFO targets to. + * + * @return void * address to the built scif sas smp request. + */ +void * scif_sas_smp_request_construct_report_manufacturer_info( + SCIF_SAS_CONTROLLER_T * fw_controller, + SCIF_SAS_REMOTE_DEVICE_T * fw_device +) +{ + SMP_REQUEST_T smp_report_manufacturer_info; + + scif_sas_smp_protocol_request_construct( + &smp_report_manufacturer_info, + SMP_FUNCTION_REPORT_MANUFACTURER_INFORMATION, + sizeof(SMP_RESPONSE_REPORT_MANUFACTURER_INFORMATION_T) / sizeof(U32), + 0 + ); + + smp_report_manufacturer_info.request.report_general.crc = 0; + + SCIF_LOG_INFO(( + sci_base_object_get_logger(fw_device), + SCIF_LOG_OBJECT_IO_REQUEST | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, + "SMP REPORT MANUFACTURER_INFO - Device:0x%x\n", + fw_device + )); + + return scif_sas_smp_request_build( + fw_controller, fw_device, &smp_report_manufacturer_info, NULL, NULL + ); +} + +/** + * @brief construct a smp Discover command to the fw_device. + * @param[in] fw_controller The framework controller object. + * @param[in] fw_device the framework smp device that DISCOVER command targets + * to. + * @param[in] phy_identifier The phy index the DISCOVER command targets to. + * + * @return void * address to the built scif sas smp request. + */ +void * scif_sas_smp_request_construct_discover( + SCIF_SAS_CONTROLLER_T * fw_controller, + SCIF_SAS_REMOTE_DEVICE_T * fw_device, + U8 phy_identifier, + void * external_request_object, + void * external_memory +) +{ + SMP_REQUEST_T smp_discover; + + scif_sas_smp_protocol_request_construct( + &smp_discover, + SMP_FUNCTION_DISCOVER, + sizeof(SMP_RESPONSE_DISCOVER_T) / sizeof(U32), + sizeof(SMP_REQUEST_PHY_IDENTIFIER_T) / sizeof(U32) + ); + + smp_discover.request.discover.phy_identifier = phy_identifier; + + SCIF_LOG_INFO(( + sci_base_object_get_logger(fw_device), + SCIF_LOG_OBJECT_IO_REQUEST | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, + "SMP DISCOVER - Device:0x%x PhyId:0x%x\n", + fw_device, phy_identifier + )); + + return scif_sas_smp_request_build( + fw_controller, fw_device, &smp_discover, + external_request_object, external_memory + ); +} + + +/** + * @brief construct a smp REPORT PHY SATA command to the fw_device. + * @param[in] fw_controller The framework controller object. + * @param[in] fw_device the framework smp device that DISCOVER command targets + * to. + * @param[in] phy_identifier The phy index the DISCOVER command targets to. + * + * @return void * address to the built scif sas smp request. + */ +void * scif_sas_smp_request_construct_report_phy_sata( + SCIF_SAS_CONTROLLER_T * fw_controller, + SCIF_SAS_REMOTE_DEVICE_T * fw_device, + U8 phy_identifier +) +{ + SMP_REQUEST_T report_phy_sata; + + scif_sas_smp_protocol_request_construct( + &report_phy_sata, + SMP_FUNCTION_REPORT_PHY_SATA, + sizeof(SMP_RESPONSE_REPORT_PHY_SATA_T) / sizeof(U32), + sizeof(SMP_REQUEST_PHY_IDENTIFIER_T) / sizeof(U32) + ); + + report_phy_sata.request.report_phy_sata.phy_identifier = phy_identifier; + + SCIF_LOG_INFO(( + sci_base_object_get_logger(fw_device), + SCIF_LOG_OBJECT_IO_REQUEST | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, + "SMP REPORT PHY SATA - Device:0x%x PhyId:0x%x\n", + fw_device, phy_identifier + )); + + return scif_sas_smp_request_build( + fw_controller, fw_device, &report_phy_sata, NULL, NULL); +} + + +/** + * @brief construct a smp REPORT PHY SATA command to the fw_device. + * @param[in] fw_controller The framework controller object. + * @param[in] fw_device the framework smp device that PHY CONTROL command + * targets to. + * @param[in] phy_identifier The phy index the DISCOVER command targets to. + * + * @return void * address to the built scif sas smp request. + */ +void * scif_sas_smp_request_construct_phy_control( + SCIF_SAS_CONTROLLER_T * fw_controller, + SCIF_SAS_REMOTE_DEVICE_T * fw_device, + U8 phy_operation, + U8 phy_identifier, + void * external_request_object, + void * external_memory +) +{ + SMP_REQUEST_T phy_control; + + scif_sas_smp_protocol_request_construct( + &phy_control, + SMP_FUNCTION_PHY_CONTROL, + 0, + sizeof(SMP_REQUEST_PHY_CONTROL_T) / sizeof(U32) + ); + + phy_control.request.phy_control.phy_operation = phy_operation; + phy_control.request.phy_control.phy_identifier = phy_identifier; + + return scif_sas_smp_request_build( + fw_controller, fw_device, &phy_control, + external_request_object, external_memory + ); +} + + +/** + * @brief construct a smp CONFIG ROUTE INFO command to the fw_device. + * + * @param[in] fw_controller The framework controller object. + * @param[in] fw_device the framework smp device that PHY CONTROL command + * targets to. + * @param[in] phy_id The phy, whose route entry at route_index is to be configured. + * @param[in] route_index The index of a phy's route entry that is to be configured. + * @param[in] destination_sas_address A sas address for an route table entry + * + * @return void * address to the built scif sas smp request. + */ +void * scif_sas_smp_request_construct_config_route_info( + struct SCIF_SAS_CONTROLLER * fw_controller, + struct SCIF_SAS_REMOTE_DEVICE * fw_device, + U8 phy_id, + U16 route_index, + SCI_SAS_ADDRESS_T destination_sas_address, + BOOL disable_expander_route_entry +) +{ + SMP_REQUEST_T config_route_info; + + scif_sas_smp_protocol_request_construct( + &config_route_info, + SMP_FUNCTION_CONFIGURE_ROUTE_INFORMATION, + 0, + sizeof(SMP_REQUEST_CONFIGURE_ROUTE_INFORMATION_T) / sizeof(U32) + ); + + config_route_info.request.configure_route_information.phy_identifier = phy_id; + config_route_info.request.configure_route_information.expander_route_index_high = + ((route_index & 0xff00) >> 8); + config_route_info.request.configure_route_information.expander_route_index = + route_index & 0xff; + config_route_info.request.configure_route_information.routed_sas_address[0] = + destination_sas_address.high; + config_route_info.request.configure_route_information.routed_sas_address[1] = + destination_sas_address.low; + + if (disable_expander_route_entry == TRUE) + config_route_info.request.configure_route_information.disable_route_entry = 1; + + return scif_sas_smp_request_build( + fw_controller, fw_device, &config_route_info, + NULL, NULL + ); +} + +/** + * @brief This method retry the internal smp request. + * + * @param[in] fw_device This parameter specifies the remote device for + * which the internal IO request is destined. + * @param[in] retry_count This parameter specifies how many times the + * old smp request has been retried. + * + * @return none. + */ +SCI_STATUS scif_sas_smp_internal_request_retry( + SCIF_SAS_REMOTE_DEVICE_T * fw_device +) +{ + SCIF_SAS_CONTROLLER_T * fw_controller; + SCIF_SAS_IO_REQUEST_T * new_io; + void * new_request_memory = NULL; + U8 retry_count = fw_device->protocol_device.smp_device.io_retry_count; + + SCIF_LOG_TRACE(( + sci_base_object_get_logger(fw_device), + SCIF_LOG_OBJECT_IO_REQUEST | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, + "scif_sas_smp_internal_request_retry(0x%x, 0x%x) time %d!\n", + fw_device, retry_count + )); + + fw_controller = fw_device->domain->controller; + + switch (fw_device->protocol_device.smp_device.current_smp_request) + { + case SMP_FUNCTION_REPORT_GENERAL: + new_request_memory = scif_sas_smp_request_construct_report_general( + fw_controller, fw_device + ); + break; + + case SMP_FUNCTION_DISCOVER: + //We are retrying an internal io. So we are going to allocate + //a new memory from internal io memory pool. + new_request_memory = scif_sas_smp_request_construct_discover( + fw_controller, fw_device, + fw_device->protocol_device.smp_device.current_activity_phy_index, + NULL, NULL + ); + + break; + + case SMP_FUNCTION_REPORT_PHY_SATA: + new_request_memory = scif_sas_smp_request_construct_report_phy_sata( + fw_controller, fw_device, + fw_device->protocol_device.smp_device.current_activity_phy_index + ); + break; + + default: + //unsupported case, TBD + break; + } //end of switch + + if (new_request_memory != NULL) + { + //set the retry count to new built smp request. + new_io = (SCIF_SAS_IO_REQUEST_T *) new_request_memory; + new_io->retry_count = ++retry_count; + + //need to schedule the DPC here. + scif_cb_start_internal_io_task_schedule( + fw_controller, + scif_sas_controller_start_high_priority_io, + fw_controller + ); + + return SCI_SUCCESS; + } + else + return SCI_FAILURE_INSUFFICIENT_RESOURCES; + +} + +/** + * @brief This method retry the external smp request. + * + * @param[in] fw_device This parameter specifies the remote device for + * which the internal IO request is destined. + * @param[in] old_internal_io This parameter specifies the old smp request to be + * retried. + * + * @return none. + */ +SCI_STATUS scif_sas_smp_external_request_retry( + SCIF_SAS_IO_REQUEST_T * old_io +) +{ + SCIF_SAS_REMOTE_DEVICE_T * fw_device = old_io->parent.device; + SCIF_SAS_CONTROLLER_T * fw_controller; + SCIF_SAS_IO_REQUEST_T * new_io; + void * new_request_memory = NULL; + U8 retry_count = old_io->retry_count; + + SCIF_LOG_TRACE(( + sci_base_object_get_logger(fw_device), + SCIF_LOG_OBJECT_IO_REQUEST | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, + "scif_sas_smp_external_request_retry(0x%x) time %d!\n", + old_io + )); + + fw_controller = fw_device->domain->controller; + + // Before we construct new io using the same memory, we need to + // remove the IO from the list of outstanding requests on the domain + // so that we don't damage the domain's fast list of request. + sci_fast_list_remove_element(&old_io->parent.list_element); + + switch (fw_device->protocol_device.smp_device.current_smp_request) + { + case SMP_FUNCTION_DISCOVER: + //we are retrying an external io, we are going to reuse the + //old io's memory. new_request_memory is same as old_io. + new_request_memory = scif_sas_smp_request_construct_discover( + fw_controller, fw_device, + fw_device->protocol_device.smp_device.current_activity_phy_index, + (void *)sci_object_get_association(old_io), + (void *)old_io + ); + + break; + + case SMP_FUNCTION_PHY_CONTROL: + //Phy Control command always uses external io memory. + new_request_memory = scif_sas_smp_request_construct_phy_control( + fw_controller, fw_device, PHY_OPERATION_HARD_RESET, + fw_device->protocol_device.smp_device.current_activity_phy_index, + (void *)sci_object_get_association(old_io), + (void *)old_io + ); + + break; + + default: + //unsupported case, TBD + break; + } //end of switch + + //set the retry count to new built smp request. + new_io = (SCIF_SAS_IO_REQUEST_T *) new_request_memory; + new_io->retry_count = ++retry_count; + + //put into the high priority queue. + sci_pool_put(fw_controller->hprq.pool, (POINTER_UINT) new_request_memory); + + //schedule the DPC to start new io. + scif_cb_start_internal_io_task_schedule( + fw_controller, scif_sas_controller_start_high_priority_io, fw_controller + ); + + return SCI_SUCCESS; +} + |