/* * SAS Transport Layer for MPT (Message Passing Technology) based controllers * * This code is based on drivers/scsi/mpt3sas/mpt3sas_transport.c * Copyright (C) 2012-2014 LSI Corporation * Copyright (C) 2013-2014 Avago Technologies * (mailto: [email protected]) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * 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. * * NO WARRANTY * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is * solely responsible for determining the appropriateness of using and * distributing the Program and assumes all risks associated with its * exercise of rights under this Agreement, including but not limited to * the risks and costs of program errors, damage to or loss of data, * programs or equipment, and unavailability or interruption of operations. * DISCLAIMER OF LIABILITY * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES * 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 Street, Fifth Floor, Boston, MA 02110-1301, * USA. */ #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/errno.h> #include <linux/sched.h> #include <linux/workqueue.h> #include <linux/delay.h> #include <linux/pci.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> #include <scsi/scsi_device.h> #include <scsi/scsi_host.h> #include <scsi/scsi_transport_sas.h> #include <scsi/scsi_dbg.h> #include "mpt3sas_base.h" /** * _transport_get_port_id_by_sas_phy - get zone's port id that Phy belong to * @phy: sas_phy object * * Return Port number */ static inline u8 _transport_get_port_id_by_sas_phy(struct sas_phy *phy) { … } /** * _transport_sas_node_find_by_sas_address - sas node search * @ioc: per adapter object * @sas_address: sas address of expander or sas host * @port: hba port entry * Context: Calling function should acquire ioc->sas_node_lock. * * Search for either hba phys or expander device based on handle, then returns * the sas_node object. */ static struct _sas_node * _transport_sas_node_find_by_sas_address(struct MPT3SAS_ADAPTER *ioc, u64 sas_address, struct hba_port *port) { … } /** * _transport_get_port_id_by_rphy - Get Port number from rphy object * @ioc: per adapter object * @rphy: sas_rphy object * * Returns Port number. */ static u8 _transport_get_port_id_by_rphy(struct MPT3SAS_ADAPTER *ioc, struct sas_rphy *rphy) { … } /** * _transport_convert_phy_link_rate - * @link_rate: link rate returned from mpt firmware * * Convert link_rate from mpi fusion into sas_transport form. */ static enum sas_linkrate _transport_convert_phy_link_rate(u8 link_rate) { … } /** * _transport_set_identify - set identify for phys and end devices * @ioc: per adapter object * @handle: device handle * @identify: sas identify info * * Populates sas identify info. * * Return: 0 for success, non-zero for failure. */ static int _transport_set_identify(struct MPT3SAS_ADAPTER *ioc, u16 handle, struct sas_identify *identify) { … } /** * mpt3sas_transport_done - internal transport layer callback handler. * @ioc: per adapter object * @smid: system request message index * @msix_index: MSIX table index supplied by the OS * @reply: reply message frame(lower 32bit addr) * * Callback handler when sending internal generated transport cmds. * The callback index passed is `ioc->transport_cb_idx` * * Return: 1 meaning mf should be freed from _base_interrupt * 0 means the mf is freed from this function. */ u8 mpt3sas_transport_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) { … } /* report manufacture request structure */ struct rep_manu_request { … }; /* report manufacture reply structure */ struct rep_manu_reply { … }; /** * _transport_expander_report_manufacture - obtain SMP report_manufacture * @ioc: per adapter object * @sas_address: expander sas address * @edev: the sas_expander_device object * @port_id: Port ID number * * Fills in the sas_expander_device object when SMP port is created. * * Return: 0 for success, non-zero for failure. */ static int _transport_expander_report_manufacture(struct MPT3SAS_ADAPTER *ioc, u64 sas_address, struct sas_expander_device *edev, u8 port_id) { … } /** * _transport_delete_port - helper function to removing a port * @ioc: per adapter object * @mpt3sas_port: mpt3sas per port object */ static void _transport_delete_port(struct MPT3SAS_ADAPTER *ioc, struct _sas_port *mpt3sas_port) { … } /** * _transport_delete_phy - helper function to removing single phy from port * @ioc: per adapter object * @mpt3sas_port: mpt3sas per port object * @mpt3sas_phy: mpt3sas per phy object */ static void _transport_delete_phy(struct MPT3SAS_ADAPTER *ioc, struct _sas_port *mpt3sas_port, struct _sas_phy *mpt3sas_phy) { … } /** * _transport_add_phy - helper function to adding single phy to port * @ioc: per adapter object * @mpt3sas_port: mpt3sas per port object * @mpt3sas_phy: mpt3sas per phy object */ static void _transport_add_phy(struct MPT3SAS_ADAPTER *ioc, struct _sas_port *mpt3sas_port, struct _sas_phy *mpt3sas_phy) { … } /** * mpt3sas_transport_add_phy_to_an_existing_port - adding new phy to existing port * @ioc: per adapter object * @sas_node: sas node object (either expander or sas host) * @mpt3sas_phy: mpt3sas per phy object * @sas_address: sas address of device/expander were phy needs to be added to * @port: hba port entry */ void mpt3sas_transport_add_phy_to_an_existing_port(struct MPT3SAS_ADAPTER *ioc, struct _sas_node *sas_node, struct _sas_phy *mpt3sas_phy, u64 sas_address, struct hba_port *port) { … } /** * mpt3sas_transport_del_phy_from_an_existing_port - delete phy from existing port * @ioc: per adapter object * @sas_node: sas node object (either expander or sas host) * @mpt3sas_phy: mpt3sas per phy object */ void mpt3sas_transport_del_phy_from_an_existing_port(struct MPT3SAS_ADAPTER *ioc, struct _sas_node *sas_node, struct _sas_phy *mpt3sas_phy) { … } /** * _transport_sanity_check - sanity check when adding a new port * @ioc: per adapter object * @sas_node: sas node object (either expander or sas host) * @sas_address: sas address of device being added * @port: hba port entry * * See the explanation above from _transport_delete_duplicate_port */ static void _transport_sanity_check(struct MPT3SAS_ADAPTER *ioc, struct _sas_node *sas_node, u64 sas_address, struct hba_port *port) { … } /** * mpt3sas_transport_port_add - insert port to the list * @ioc: per adapter object * @handle: handle of attached device * @sas_address: sas address of parent expander or sas host * @hba_port: hba port entry * Context: This function will acquire ioc->sas_node_lock. * * Adding new port object to the sas_node->sas_port_list. * * Return: mpt3sas_port. */ struct _sas_port * mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle, u64 sas_address, struct hba_port *hba_port) { … } /** * mpt3sas_transport_port_remove - remove port from the list * @ioc: per adapter object * @sas_address: sas address of attached device * @sas_address_parent: sas address of parent expander or sas host * @port: hba port entry * Context: This function will acquire ioc->sas_node_lock. * * Removing object and freeing associated memory from the * ioc->sas_port_list. */ void mpt3sas_transport_port_remove(struct MPT3SAS_ADAPTER *ioc, u64 sas_address, u64 sas_address_parent, struct hba_port *port) { … } /** * mpt3sas_transport_add_host_phy - report sas_host phy to transport * @ioc: per adapter object * @mpt3sas_phy: mpt3sas per phy object * @phy_pg0: sas phy page 0 * @parent_dev: parent device class object * * Return: 0 for success, non-zero for failure. */ int mpt3sas_transport_add_host_phy(struct MPT3SAS_ADAPTER *ioc, struct _sas_phy *mpt3sas_phy, Mpi2SasPhyPage0_t phy_pg0, struct device *parent_dev) { … } /** * mpt3sas_transport_add_expander_phy - report expander phy to transport * @ioc: per adapter object * @mpt3sas_phy: mpt3sas per phy object * @expander_pg1: expander page 1 * @parent_dev: parent device class object * * Return: 0 for success, non-zero for failure. */ int mpt3sas_transport_add_expander_phy(struct MPT3SAS_ADAPTER *ioc, struct _sas_phy *mpt3sas_phy, Mpi2ExpanderPage1_t expander_pg1, struct device *parent_dev) { … } /** * mpt3sas_transport_update_links - refreshing phy link changes * @ioc: per adapter object * @sas_address: sas address of parent expander or sas host * @handle: attached device handle * @phy_number: phy number * @link_rate: new link rate * @port: hba port entry * * Return nothing. */ void mpt3sas_transport_update_links(struct MPT3SAS_ADAPTER *ioc, u64 sas_address, u16 handle, u8 phy_number, u8 link_rate, struct hba_port *port) { … } static inline void * phy_to_ioc(struct sas_phy *phy) { … } static inline void * rphy_to_ioc(struct sas_rphy *rphy) { … } /* report phy error log structure */ struct phy_error_log_request { … }; /* report phy error log reply structure */ struct phy_error_log_reply { … }; /** * _transport_get_expander_phy_error_log - return expander counters * @ioc: per adapter object * @phy: The sas phy object * * Return: 0 for success, non-zero for failure. * */ static int _transport_get_expander_phy_error_log(struct MPT3SAS_ADAPTER *ioc, struct sas_phy *phy) { … } /** * _transport_get_linkerrors - return phy counters for both hba and expanders * @phy: The sas phy object * * Return: 0 for success, non-zero for failure. * */ static int _transport_get_linkerrors(struct sas_phy *phy) { … } /** * _transport_get_enclosure_identifier - * @rphy: The sas phy object * @identifier: ? * * Obtain the enclosure logical id for an expander. * Return: 0 for success, non-zero for failure. */ static int _transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier) { … } /** * _transport_get_bay_identifier - * @rphy: The sas phy object * * Return: the slot id for a device that resides inside an enclosure. */ static int _transport_get_bay_identifier(struct sas_rphy *rphy) { … } /* phy control request structure */ struct phy_control_request { … }; /* phy control reply structure */ struct phy_control_reply { … }; #define SMP_PHY_CONTROL_LINK_RESET … #define SMP_PHY_CONTROL_HARD_RESET … #define SMP_PHY_CONTROL_DISABLE … /** * _transport_expander_phy_control - expander phy control * @ioc: per adapter object * @phy: The sas phy object * @phy_operation: ? * * Return: 0 for success, non-zero for failure. * */ static int _transport_expander_phy_control(struct MPT3SAS_ADAPTER *ioc, struct sas_phy *phy, u8 phy_operation) { … } /** * _transport_phy_reset - * @phy: The sas phy object * @hard_reset: * * Return: 0 for success, non-zero for failure. */ static int _transport_phy_reset(struct sas_phy *phy, int hard_reset) { … } /** * _transport_phy_enable - enable/disable phys * @phy: The sas phy object * @enable: enable phy when true * * Only support sas_host direct attached phys. * Return: 0 for success, non-zero for failure. */ static int _transport_phy_enable(struct sas_phy *phy, int enable) { … } /** * _transport_phy_speed - set phy min/max link rates * @phy: The sas phy object * @rates: rates defined in sas_phy_linkrates * * Only support sas_host direct attached phys. * * Return: 0 for success, non-zero for failure. */ static int _transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates) { … } static int _transport_map_smp_buffer(struct device *dev, struct bsg_buffer *buf, dma_addr_t *dma_addr, size_t *dma_len, void **p) { … } static void _transport_unmap_smp_buffer(struct device *dev, struct bsg_buffer *buf, dma_addr_t dma_addr, void *p) { … } /** * _transport_smp_handler - transport portal for smp passthru * @job: ? * @shost: shost object * @rphy: sas transport rphy object * * This used primarily for smp_utils. * Example: * smp_rep_general /sys/class/bsg/expander-5:0 */ static void _transport_smp_handler(struct bsg_job *job, struct Scsi_Host *shost, struct sas_rphy *rphy) { … } struct sas_function_template mpt3sas_transport_functions = …; struct scsi_transport_template *mpt3sas_transport_template;