/* * 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. * * Neither the name of Intel Corporation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * 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 <linux/circ_buf.h> #include <linux/device.h> #include <scsi/sas.h> #include "host.h" #include "isci.h" #include "port.h" #include "probe_roms.h" #include "remote_device.h" #include "request.h" #include "scu_completion_codes.h" #include "scu_event_codes.h" #include "registers.h" #include "scu_remote_node_context.h" #include "scu_task_context.h" #define SCU_CONTEXT_RAM_INIT_STALL_TIME … #define smu_max_ports(dcc_value) … #define smu_max_task_contexts(dcc_value) … #define smu_max_rncs(dcc_value) … #define SCIC_SDS_CONTROLLER_PHY_START_TIMEOUT … /* * The number of milliseconds to wait while a given phy is consuming power * before allowing another set of phys to consume power. Ultimately, this will * be specified by OEM parameter. */ #define SCIC_SDS_CONTROLLER_POWER_CONTROL_INTERVAL … /* * NORMALIZE_PUT_POINTER() - * * This macro will normalize the completion queue put pointer so its value can * be used as an array inde */ #define NORMALIZE_PUT_POINTER(x) … /* * NORMALIZE_EVENT_POINTER() - * * This macro will normalize the completion queue event entry so its value can * be used as an index. */ #define NORMALIZE_EVENT_POINTER(x) … /* * NORMALIZE_GET_POINTER() - * * This macro will normalize the completion queue get pointer so its value can * be used as an index into an array */ #define NORMALIZE_GET_POINTER(x) … /* * NORMALIZE_GET_POINTER_CYCLE_BIT() - * * This macro will normalize the completion queue cycle pointer so it matches * the completion queue cycle bit */ #define NORMALIZE_GET_POINTER_CYCLE_BIT(x) … /* * COMPLETION_QUEUE_CYCLE_BIT() - * * This macro will return the cycle bit of the completion queue entry */ #define COMPLETION_QUEUE_CYCLE_BIT(x) … /* Init the state machine and call the state entry function (if any) */ void sci_init_sm(struct sci_base_state_machine *sm, const struct sci_base_state *state_table, u32 initial_state) { … } /* Call the state exit fn, update the current state, call the state entry fn */ void sci_change_state(struct sci_base_state_machine *sm, u32 next_state) { … } static bool sci_controller_completion_queue_has_entries(struct isci_host *ihost) { … } static bool sci_controller_isr(struct isci_host *ihost) { … } irqreturn_t isci_msix_isr(int vec, void *data) { … } static bool sci_controller_error_isr(struct isci_host *ihost) { … } static void sci_controller_task_completion(struct isci_host *ihost, u32 ent) { … } static void sci_controller_sdma_completion(struct isci_host *ihost, u32 ent) { … } static void sci_controller_unsolicited_frame(struct isci_host *ihost, u32 ent) { … } static void sci_controller_event_completion(struct isci_host *ihost, u32 ent) { … } static void sci_controller_process_completions(struct isci_host *ihost) { … } static void sci_controller_error_handler(struct isci_host *ihost) { … } irqreturn_t isci_intx_isr(int vec, void *data) { … } irqreturn_t isci_error_isr(int vec, void *data) { … } /** * isci_host_start_complete() - This function is called by the core library, * through the ISCI Module, to indicate controller start status. * @ihost: This parameter specifies the ISCI host object * @completion_status: This parameter specifies the completion status from the * core library. * */ static void isci_host_start_complete(struct isci_host *ihost, enum sci_status completion_status) { … } int isci_host_scan_finished(struct Scsi_Host *shost, unsigned long time) { … } /** * sci_controller_get_suggested_start_timeout() - This method returns the * suggested sci_controller_start() timeout amount. The user is free to * use any timeout value, but this method provides the suggested minimum * start timeout value. The returned value is based upon empirical * information determined as a result of interoperability testing. * @ihost: the handle to the controller object for which to return the * suggested start timeout. * * This method returns the number of milliseconds for the suggested start * operation timeout. */ static u32 sci_controller_get_suggested_start_timeout(struct isci_host *ihost) { … } static void sci_controller_enable_interrupts(struct isci_host *ihost) { … } void sci_controller_disable_interrupts(struct isci_host *ihost) { … } static void sci_controller_enable_port_task_scheduler(struct isci_host *ihost) { … } static void sci_controller_assign_task_entries(struct isci_host *ihost) { … } static void sci_controller_initialize_completion_queue(struct isci_host *ihost) { … } static void sci_controller_initialize_unsolicited_frame_queue(struct isci_host *ihost) { … } void sci_controller_transition_to_ready(struct isci_host *ihost, enum sci_status status) { … } static bool is_phy_starting(struct isci_phy *iphy) { … } bool is_controller_start_complete(struct isci_host *ihost) { … } /** * sci_controller_start_next_phy - start phy * @ihost: controller * * If all the phys have been started, then attempt to transition the * controller to the READY state and inform the user * (sci_cb_controller_start_complete()). */ static enum sci_status sci_controller_start_next_phy(struct isci_host *ihost) { … } static void phy_startup_timeout(struct timer_list *t) { … } static u16 isci_tci_active(struct isci_host *ihost) { … } static enum sci_status sci_controller_start(struct isci_host *ihost, u32 timeout) { … } void isci_host_start(struct Scsi_Host *shost) { … } static void isci_host_stop_complete(struct isci_host *ihost) { … } static void sci_controller_completion_handler(struct isci_host *ihost) { … } void ireq_done(struct isci_host *ihost, struct isci_request *ireq, struct sas_task *task) { … } /** * isci_host_completion_routine() - This function is the delayed service * routine that calls the sci core library's completion handler. It's * scheduled as a tasklet from the interrupt service routine when interrupts * in use, or set as the timeout function in polled mode. * @data: This parameter specifies the ISCI host object * */ void isci_host_completion_routine(unsigned long data) { … } /** * sci_controller_stop() - This method will stop an individual controller * object.This method will invoke the associated user callback upon * completion. The completion callback is called when the following * conditions are met: -# the method return status is SCI_SUCCESS. -# the * controller has been quiesced. This method will ensure that all IO * requests are quiesced, phys are stopped, and all additional operation by * the hardware is halted. * @ihost: the handle to the controller object to stop. * @timeout: This parameter specifies the number of milliseconds in which the * stop operation should complete. * * The controller must be in the STARTED or STOPPED state. Indicate if the * controller stop method succeeded or failed in some way. SCI_SUCCESS if the * stop operation successfully began. SCI_WARNING_ALREADY_IN_STATE if the * controller is already in the STOPPED state. SCI_FAILURE_INVALID_STATE if the * controller is not either in the STARTED or STOPPED states. */ static enum sci_status sci_controller_stop(struct isci_host *ihost, u32 timeout) { … } /** * sci_controller_reset() - This method will reset the supplied core * controller regardless of the state of said controller. This operation is * considered destructive. In other words, all current operations are wiped * out. No IO completions for outstanding devices occur. Outstanding IO * requests are not aborted or completed at the actual remote device. * @ihost: the handle to the controller object to reset. * * Indicate if the controller reset method succeeded or failed in some way. * SCI_SUCCESS if the reset operation successfully started. SCI_FATAL_ERROR if * the controller reset operation is unable to complete. */ static enum sci_status sci_controller_reset(struct isci_host *ihost) { … } static enum sci_status sci_controller_stop_phys(struct isci_host *ihost) { … } /** * isci_host_deinit - shutdown frame reception and dma * @ihost: host to take down * * This is called in either the driver shutdown or the suspend path. In * the shutdown case libsas went through port teardown and normal device * removal (i.e. physical links stayed up to service scsi_device removal * commands). In the suspend case we disable the hardware without * notifying libsas of the link down events since we want libsas to * remember the domain across the suspend/resume cycle */ void isci_host_deinit(struct isci_host *ihost) { … } static void __iomem *scu_base(struct isci_host *isci_host) { … } static void __iomem *smu_base(struct isci_host *isci_host) { … } static void sci_controller_initial_state_enter(struct sci_base_state_machine *sm) { … } static inline void sci_controller_starting_state_exit(struct sci_base_state_machine *sm) { … } #define INTERRUPT_COALESCE_TIMEOUT_BASE_RANGE_LOWER_BOUND_NS … #define INTERRUPT_COALESCE_TIMEOUT_BASE_RANGE_UPPER_BOUND_NS … #define INTERRUPT_COALESCE_TIMEOUT_MAX_US … #define INTERRUPT_COALESCE_NUMBER_MAX … #define INTERRUPT_COALESCE_TIMEOUT_ENCODE_MIN … #define INTERRUPT_COALESCE_TIMEOUT_ENCODE_MAX … /** * sci_controller_set_interrupt_coalescence() - This method allows the user to * configure the interrupt coalescence. * @ihost: This parameter represents the handle to the controller object * for which its interrupt coalesce register is overridden. * @coalesce_number: Used to control the number of entries in the Completion * Queue before an interrupt is generated. If the number of entries exceed * this number, an interrupt will be generated. The valid range of the input * is [0, 256]. A setting of 0 results in coalescing being disabled. * @coalesce_timeout: Timeout value in microseconds. The valid range of the * input is [0, 2700000] . A setting of 0 is allowed and results in no * interrupt coalescing timeout. * * Indicate if the user successfully set the interrupt coalesce parameters. * SCI_SUCCESS The user successfully updated the interrutp coalescence. * SCI_FAILURE_INVALID_PARAMETER_VALUE The user input value is out of range. */ static enum sci_status sci_controller_set_interrupt_coalescence(struct isci_host *ihost, u32 coalesce_number, u32 coalesce_timeout) { … } static void sci_controller_ready_state_enter(struct sci_base_state_machine *sm) { … } static void sci_controller_ready_state_exit(struct sci_base_state_machine *sm) { … } static enum sci_status sci_controller_stop_ports(struct isci_host *ihost) { … } static enum sci_status sci_controller_stop_devices(struct isci_host *ihost) { … } static void sci_controller_stopping_state_enter(struct sci_base_state_machine *sm) { … } static void sci_controller_stopping_state_exit(struct sci_base_state_machine *sm) { … } static void sci_controller_reset_hardware(struct isci_host *ihost) { … } static void sci_controller_resetting_state_enter(struct sci_base_state_machine *sm) { … } static const struct sci_base_state sci_controller_state_table[] = …; static void controller_timeout(struct timer_list *t) { … } static enum sci_status sci_controller_construct(struct isci_host *ihost, void __iomem *scu_base, void __iomem *smu_base) { … } int sci_oem_parameters_validate(struct sci_oem_params *oem, u8 version) { … } static u8 max_spin_up(struct isci_host *ihost) { … } static void power_control_timeout(struct timer_list *t) { … } void sci_controller_power_control_queue_insert(struct isci_host *ihost, struct isci_phy *iphy) { … } void sci_controller_power_control_queue_remove(struct isci_host *ihost, struct isci_phy *iphy) { … } static int is_long_cable(int phy, unsigned char selection_byte) { … } static int is_medium_cable(int phy, unsigned char selection_byte) { … } static enum cable_selections decode_selection_byte( int phy, unsigned char selection_byte) { … } static unsigned char *to_cable_select(struct isci_host *ihost) { … } enum cable_selections decode_cable_selection(struct isci_host *ihost, int phy) { … } char *lookup_cable_names(enum cable_selections selection) { … } #define AFE_REGISTER_WRITE_DELAY … static void sci_controller_afe_initialization(struct isci_host *ihost) { … } static void sci_controller_initialize_power_control(struct isci_host *ihost) { … } static enum sci_status sci_controller_initialize(struct isci_host *ihost) { … } static int sci_controller_dma_alloc(struct isci_host *ihost) { … } static int sci_controller_mem_init(struct isci_host *ihost) { … } /** * isci_host_init - (re-)initialize hardware and internal (private) state * @ihost: host to init * * Any public facing objects (like asd_sas_port, and asd_sas_phys), or * one-time initialization objects like locks and waitqueues, are * not touched (they are initialized in isci_host_alloc) */ int isci_host_init(struct isci_host *ihost) { … } void sci_controller_link_up(struct isci_host *ihost, struct isci_port *iport, struct isci_phy *iphy) { … } void sci_controller_link_down(struct isci_host *ihost, struct isci_port *iport, struct isci_phy *iphy) { … } bool sci_controller_has_remote_devices_stopping(struct isci_host *ihost) { … } void sci_controller_remote_device_stopped(struct isci_host *ihost, struct isci_remote_device *idev) { … } void sci_controller_post_request(struct isci_host *ihost, u32 request) { … } struct isci_request *sci_request_by_tag(struct isci_host *ihost, u16 io_tag) { … } /** * sci_controller_allocate_remote_node_context() * This method allocates remote node index and the reserves the remote node * context space for use. This method can fail if there are no more remote * node index available. * @ihost: This is the controller object which contains the set of * free remote node ids * @idev: This is the device object which is requesting the a remote node * id * @node_id: This is the remote node id that is assinged to the device if one * is available * * enum sci_status SCI_FAILURE_OUT_OF_RESOURCES if there are no available remote * node index available. */ enum sci_status sci_controller_allocate_remote_node_context(struct isci_host *ihost, struct isci_remote_device *idev, u16 *node_id) { … } void sci_controller_free_remote_node_context(struct isci_host *ihost, struct isci_remote_device *idev, u16 node_id) { … } void sci_controller_copy_sata_response(void *response_buffer, void *frame_header, void *frame_buffer) { … } void sci_controller_release_frame(struct isci_host *ihost, u32 frame_index) { … } void isci_tci_free(struct isci_host *ihost, u16 tci) { … } static u16 isci_tci_alloc(struct isci_host *ihost) { … } static u16 isci_tci_space(struct isci_host *ihost) { … } u16 isci_alloc_tag(struct isci_host *ihost) { … } enum sci_status isci_free_tag(struct isci_host *ihost, u16 io_tag) { … } enum sci_status sci_controller_start_io(struct isci_host *ihost, struct isci_remote_device *idev, struct isci_request *ireq) { … } enum sci_status sci_controller_terminate_request(struct isci_host *ihost, struct isci_remote_device *idev, struct isci_request *ireq) { … } /** * sci_controller_complete_io() - This method will perform core specific * completion operations for an IO request. After this method is invoked, * the user should consider the IO request as invalid until it is properly * reused (i.e. re-constructed). * @ihost: The handle to the controller object for which to complete the * IO request. * @idev: The handle to the remote device object for which to complete * the IO request. * @ireq: the handle to the io request object to complete. */ enum sci_status sci_controller_complete_io(struct isci_host *ihost, struct isci_remote_device *idev, struct isci_request *ireq) { … } enum sci_status sci_controller_continue_io(struct isci_request *ireq) { … } /** * sci_controller_start_task() - This method is called by the SCIC user to * send/start a framework task management request. * @ihost: the handle to the controller object for which to start the task * management request. * @idev: the handle to the remote device object for which to start * the task management request. * @ireq: the handle to the task request object to start. */ enum sci_status sci_controller_start_task(struct isci_host *ihost, struct isci_remote_device *idev, struct isci_request *ireq) { … } static int sci_write_gpio_tx_gp(struct isci_host *ihost, u8 reg_index, u8 reg_count, u8 *write_data) { … } int isci_gpio_write(struct sas_ha_struct *sas_ha, u8 reg_type, u8 reg_index, u8 reg_count, u8 *write_data) { … }