/* * 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 "isci.h" #include "port.h" #include "request.h" #define SCIC_SDS_PORT_HARD_RESET_TIMEOUT … #define SCU_DUMMY_INDEX … #undef C #define C … static const char *port_state_name(enum sci_port_states state) { … } #undef C static struct device *sciport_to_dev(struct isci_port *iport) { … } static void sci_port_get_protocols(struct isci_port *iport, struct sci_phy_proto *proto) { … } static u32 sci_port_get_phys(struct isci_port *iport) { … } /** * sci_port_get_properties() - This method simply returns the properties * regarding the port, such as: physical index, protocols, sas address, etc. * @iport: this parameter specifies the port for which to retrieve the physical * index. * @prop: This parameter specifies the properties structure into which to * copy the requested information. * * Indicate if the user specified a valid port. SCI_SUCCESS This value is * returned if the specified port was valid. SCI_FAILURE_INVALID_PORT This * value is returned if the specified port is not valid. When this value is * returned, no data is copied to the properties output parameter. */ enum sci_status sci_port_get_properties(struct isci_port *iport, struct sci_port_properties *prop) { … } static void sci_port_bcn_enable(struct isci_port *iport) { … } static void isci_port_bc_change_received(struct isci_host *ihost, struct isci_port *iport, struct isci_phy *iphy) { … } static void isci_port_link_up(struct isci_host *isci_host, struct isci_port *iport, struct isci_phy *iphy) { … } /** * isci_port_link_down() - This function is called by the sci core when a link * becomes inactive. * @isci_host: This parameter specifies the isci host object. * @isci_phy: This parameter specifies the isci phy with the active link. * @isci_port: This parameter specifies the isci port with the active link. * */ static void isci_port_link_down(struct isci_host *isci_host, struct isci_phy *isci_phy, struct isci_port *isci_port) { … } static bool is_port_ready_state(enum sci_port_states state) { … } /* flag dummy rnc hanling when exiting a ready state */ static void port_state_machine_change(struct isci_port *iport, enum sci_port_states state) { … } /** * isci_port_hard_reset_complete() - This function is called by the sci core * when the hard reset complete notification has been received. * @isci_port: This parameter specifies the sci port with the active link. * @completion_status: This parameter specifies the core status for the reset * process. * */ static void isci_port_hard_reset_complete(struct isci_port *isci_port, enum sci_status completion_status) { … } /* This method will return a true value if the specified phy can be assigned to * this port The following is a list of phys for each port that are allowed: - * Port 0 - 3 2 1 0 - Port 1 - 1 - Port 2 - 3 2 - Port 3 - 3 This method * doesn't preclude all configurations. It merely ensures that a phy is part * of the allowable set of phy identifiers for that port. For example, one * could assign phy 3 to port 0 and no other phys. Please refer to * sci_port_is_phy_mask_valid() for information regarding whether the * phy_mask for a port can be supported. bool true if this is a valid phy * assignment for the port false if this is not a valid phy assignment for the * port */ bool sci_port_is_valid_phy_assignment(struct isci_port *iport, u32 phy_index) { … } /** * sci_port_is_phy_mask_valid() * @iport: This is the port object for which to determine if the phy mask * can be supported. * @phy_mask: Phy mask belonging to this port * * This method will return a true value if the port's phy mask can be supported * by the SCU. The following is a list of valid PHY mask configurations for * each port: - Port 0 - [[3 2] 1] 0 - Port 1 - [1] - Port 2 - [[3] 2] * - Port 3 - [3] This method returns a boolean indication specifying if the * phy mask can be supported. true if this is a valid phy assignment for the * port false if this is not a valid phy assignment for the port */ static bool sci_port_is_phy_mask_valid( struct isci_port *iport, u32 phy_mask) { … } /* * This method retrieves a currently active (i.e. connected) phy contained in * the port. Currently, the lowest order phy that is connected is returned. * This method returns a pointer to a SCIS_SDS_PHY object. NULL This value is * returned if there are no currently active (i.e. connected to a remote end * point) phys contained in the port. All other values specify a struct sci_phy * object that is active in the port. */ static struct isci_phy *sci_port_get_a_connected_phy(struct isci_port *iport) { … } static enum sci_status sci_port_set_phy(struct isci_port *iport, struct isci_phy *iphy) { … } static enum sci_status sci_port_clear_phy(struct isci_port *iport, struct isci_phy *iphy) { … } void sci_port_get_sas_address(struct isci_port *iport, struct sci_sas_address *sas) { … } void sci_port_get_attached_sas_address(struct isci_port *iport, struct sci_sas_address *sas) { … } /** * sci_port_construct_dummy_rnc() - create dummy rnc for si workaround * * @iport: logical port on which we need to create the remote node context * @rni: remote node index for this remote node context. * * This routine will construct a dummy remote node context data structure * This structure will be posted to the hardware to work around a scheduler * error in the hardware. */ static void sci_port_construct_dummy_rnc(struct isci_port *iport, u16 rni) { … } /* * construct a dummy task context data structure. This * structure will be posted to the hardwre to work around a scheduler error * in the hardware. */ static void sci_port_construct_dummy_task(struct isci_port *iport, u16 tag) { … } static void sci_port_destroy_dummy_resources(struct isci_port *iport) { … } void sci_port_setup_transports(struct isci_port *iport, u32 device_id) { … } static void sci_port_resume_phy(struct isci_port *iport, struct isci_phy *iphy) { … } static void sci_port_activate_phy(struct isci_port *iport, struct isci_phy *iphy, u8 flags) { … } void sci_port_deactivate_phy(struct isci_port *iport, struct isci_phy *iphy, bool do_notify_user) { … } static void sci_port_invalid_link_up(struct isci_port *iport, struct isci_phy *iphy) { … } /** * sci_port_general_link_up_handler - phy can be assigned to port? * @iport: sci_port object for which has a phy that has gone link up. * @iphy: This is the struct isci_phy object that has gone link up. * @flags: PF_RESUME, PF_NOTIFY to sci_port_activate_phy * * Determine if this phy can be assigned to this port . If the phy is * not a valid PHY for this port then the function will notify the user. * A PHY can only be part of a port if it's attached SAS ADDRESS is the * same as all other PHYs in the same port. */ static void sci_port_general_link_up_handler(struct isci_port *iport, struct isci_phy *iphy, u8 flags) { … } /** * sci_port_is_wide() * This method returns false if the port only has a single phy object assigned. * If there are no phys or more than one phy then the method will return * true. * @iport: The port for which the wide port condition is to be checked. * * bool true Is returned if this is a wide ported port. false Is returned if * this is a narrow port. */ static bool sci_port_is_wide(struct isci_port *iport) { … } /** * sci_port_link_detected() * This method is called by the PHY object when the link is detected. if the * port wants the PHY to continue on to the link up state then the port * layer must return true. If the port object returns false the phy object * must halt its attempt to go link up. * @iport: The port associated with the phy object. * @iphy: The phy object that is trying to go link up. * * true if the phy object can continue to the link up condition. true Is * returned if this phy can continue to the ready state. false Is returned if * can not continue on to the ready state. This notification is in place for * wide ports and direct attached phys. Since there are no wide ported SATA * devices this could become an invalid port configuration. */ bool sci_port_link_detected(struct isci_port *iport, struct isci_phy *iphy) { … } static void port_timeout(struct timer_list *t) { … } /* --------------------------------------------------------------------------- */ /* * This function updates the hardwares VIIT entry for this port. */ static void sci_port_update_viit_entry(struct isci_port *iport) { … } enum sas_linkrate sci_port_get_max_allowed_speed(struct isci_port *iport) { … } static void sci_port_suspend_port_task_scheduler(struct isci_port *iport) { … } /** * sci_port_post_dummy_request() - post dummy/workaround request * @iport: port to post task * * Prevent the hardware scheduler from posting new requests to the front * of the scheduler queue causing a starvation problem for currently * ongoing requests. * */ static void sci_port_post_dummy_request(struct isci_port *iport) { … } /** * sci_port_abort_dummy_request() * This routine will abort the dummy request. This will allow the hardware to * power down parts of the silicon to save power. * * @iport: The port on which the task must be aborted. * */ static void sci_port_abort_dummy_request(struct isci_port *iport) { … } /** * sci_port_resume_port_task_scheduler() * @iport: This is the struct isci_port object to resume. * * This method will resume the port task scheduler for this port object. none */ static void sci_port_resume_port_task_scheduler(struct isci_port *iport) { … } static void sci_port_ready_substate_waiting_enter(struct sci_base_state_machine *sm) { … } static void scic_sds_port_ready_substate_waiting_exit( struct sci_base_state_machine *sm) { … } static void sci_port_ready_substate_operational_enter(struct sci_base_state_machine *sm) { … } static void sci_port_invalidate_dummy_remote_node(struct isci_port *iport) { … } /** * sci_port_ready_substate_operational_exit() * @sm: This is the object which is cast to a struct isci_port object. * * This method will perform the actions required by the struct isci_port on * exiting the SCI_PORT_SUB_OPERATIONAL. This function reports * the port not ready and suspends the port task scheduler. none */ static void sci_port_ready_substate_operational_exit(struct sci_base_state_machine *sm) { … } static void sci_port_ready_substate_configuring_enter(struct sci_base_state_machine *sm) { … } enum sci_status sci_port_start(struct isci_port *iport) { … } enum sci_status sci_port_stop(struct isci_port *iport) { … } static enum sci_status sci_port_hard_reset(struct isci_port *iport, u32 timeout) { … } /** * sci_port_add_phy() * @iport: This parameter specifies the port in which the phy will be added. * @iphy: This parameter is the phy which is to be added to the port. * * This method will add a PHY to the selected port. This method returns an * enum sci_status. SCI_SUCCESS the phy has been added to the port. Any other * status is a failure to add the phy to the port. */ enum sci_status sci_port_add_phy(struct isci_port *iport, struct isci_phy *iphy) { … } /** * sci_port_remove_phy() * @iport: This parameter specifies the port in which the phy will be added. * @iphy: This parameter is the phy which is to be added to the port. * * This method will remove the PHY from the selected PORT. This method returns * an enum sci_status. SCI_SUCCESS the phy has been removed from the port. Any * other status is a failure to add the phy to the port. */ enum sci_status sci_port_remove_phy(struct isci_port *iport, struct isci_phy *iphy) { … } enum sci_status sci_port_link_up(struct isci_port *iport, struct isci_phy *iphy) { … } enum sci_status sci_port_link_down(struct isci_port *iport, struct isci_phy *iphy) { … } enum sci_status sci_port_start_io(struct isci_port *iport, struct isci_remote_device *idev, struct isci_request *ireq) { … } enum sci_status sci_port_complete_io(struct isci_port *iport, struct isci_remote_device *idev, struct isci_request *ireq) { … } static void sci_port_enable_port_task_scheduler(struct isci_port *iport) { … } static void sci_port_disable_port_task_scheduler(struct isci_port *iport) { … } static void sci_port_post_dummy_remote_node(struct isci_port *iport) { … } static void sci_port_stopped_state_enter(struct sci_base_state_machine *sm) { … } static void sci_port_stopped_state_exit(struct sci_base_state_machine *sm) { … } static void sci_port_ready_state_enter(struct sci_base_state_machine *sm) { … } static void sci_port_resetting_state_exit(struct sci_base_state_machine *sm) { … } static void sci_port_stopping_state_exit(struct sci_base_state_machine *sm) { … } static void sci_port_failed_state_enter(struct sci_base_state_machine *sm) { … } void sci_port_set_hang_detection_timeout(struct isci_port *iport, u32 timeout) { … } /* --------------------------------------------------------------------------- */ static const struct sci_base_state sci_port_state_table[] = …; void sci_port_construct(struct isci_port *iport, u8 index, struct isci_host *ihost) { … } void sci_port_broadcast_change_received(struct isci_port *iport, struct isci_phy *iphy) { … } static void wait_port_reset(struct isci_host *ihost, struct isci_port *iport) { … } int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *iport, struct isci_phy *iphy) { … } int isci_ata_check_ready(struct domain_device *dev) { … } void isci_port_deformed(struct asd_sas_phy *phy) { … } void isci_port_formed(struct asd_sas_phy *phy) { … }