/* * PMC-Sierra SPCv/ve 8088/8089 SAS/SATA based host adapters driver * * Copyright (c) 2008-2009 PMC-Sierra, Inc., * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification. * 2. Redistributions in binary form must reproduce at minimum a disclaimer * substantially similar to the "NO WARRANTY" disclaimer below * ("Disclaimer") and any redistribution must be conditioned upon * including a substantially similar Disclaimer requirement for further * binary redistribution. * 3. Neither the names of the above-listed copyright holders nor the names * of any contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * Alternatively, this software may be distributed under the terms of the * GNU General Public License ("GPL") version 2 as published by the Free * Software Foundation. * * NO WARRANTY * 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 MERCHANTIBILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. * */ #include <linux/slab.h> #include "pm8001_sas.h" #include "pm80xx_hwi.h" #include "pm8001_chips.h" #include "pm8001_ctl.h" #include "pm80xx_tracepoints.h" #define SMP_DIRECT … #define SMP_INDIRECT … int pm80xx_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shift_value) { … } static void pm80xx_pci_mem_copy(struct pm8001_hba_info *pm8001_ha, u32 soffset, __le32 *destination, u32 dw_count, u32 bus_base_number) { … } ssize_t pm80xx_get_fatal_dump(struct device *cdev, struct device_attribute *attr, char *buf) { … } /* pm80xx_get_non_fatal_dump - dump the nonfatal data from the dma * location by the firmware. */ ssize_t pm80xx_get_non_fatal_dump(struct device *cdev, struct device_attribute *attr, char *buf) { … } /** * read_main_config_table - read the configure table and save it. * @pm8001_ha: our hba card information */ static void read_main_config_table(struct pm8001_hba_info *pm8001_ha) { … } /** * read_general_status_table - read the general status table and save it. * @pm8001_ha: our hba card information */ static void read_general_status_table(struct pm8001_hba_info *pm8001_ha) { … } /** * read_phy_attr_table - read the phy attribute table and save it. * @pm8001_ha: our hba card information */ static void read_phy_attr_table(struct pm8001_hba_info *pm8001_ha) { … } /** * read_inbnd_queue_table - read the inbound queue table and save it. * @pm8001_ha: our hba card information */ static void read_inbnd_queue_table(struct pm8001_hba_info *pm8001_ha) { … } /** * read_outbnd_queue_table - read the outbound queue table and save it. * @pm8001_ha: our hba card information */ static void read_outbnd_queue_table(struct pm8001_hba_info *pm8001_ha) { … } /** * init_default_table_values - init the default table. * @pm8001_ha: our hba card information */ static void init_default_table_values(struct pm8001_hba_info *pm8001_ha) { … } /** * update_main_config_table - update the main default table to the HBA. * @pm8001_ha: our hba card information */ static void update_main_config_table(struct pm8001_hba_info *pm8001_ha) { … } /** * update_inbnd_queue_table - update the inbound queue table to the HBA. * @pm8001_ha: our hba card information * @number: entry in the queue */ static void update_inbnd_queue_table(struct pm8001_hba_info *pm8001_ha, int number) { … } /** * update_outbnd_queue_table - update the outbound queue table to the HBA. * @pm8001_ha: our hba card information * @number: entry in the queue */ static void update_outbnd_queue_table(struct pm8001_hba_info *pm8001_ha, int number) { … } /** * mpi_init_check - check firmware initialization status. * @pm8001_ha: our hba card information */ static int mpi_init_check(struct pm8001_hba_info *pm8001_ha) { … } /** * check_fw_ready - The LLDD check if the FW is ready, if not, return error. * This function sleeps hence it must not be used in atomic context. * @pm8001_ha: our hba card information */ static int check_fw_ready(struct pm8001_hba_info *pm8001_ha) { … } static int init_pci_device_addresses(struct pm8001_hba_info *pm8001_ha) { … } /** * pm80xx_set_thermal_config - support the thermal configuration * @pm8001_ha: our hba card information. */ int pm80xx_set_thermal_config(struct pm8001_hba_info *pm8001_ha) { … } /** * pm80xx_set_sas_protocol_timer_config - support the SAS Protocol * Timer configuration page * @pm8001_ha: our hba card information. */ static int pm80xx_set_sas_protocol_timer_config(struct pm8001_hba_info *pm8001_ha) { … } /** * pm80xx_get_encrypt_info - Check for encryption * @pm8001_ha: our hba card information. */ static int pm80xx_get_encrypt_info(struct pm8001_hba_info *pm8001_ha) { … } /** * pm80xx_encrypt_update - update flash with encryption information * @pm8001_ha: our hba card information. */ static int pm80xx_encrypt_update(struct pm8001_hba_info *pm8001_ha) { … } /** * pm80xx_chip_init - the main init function that initializes whole PM8001 chip. * @pm8001_ha: our hba card information */ static int pm80xx_chip_init(struct pm8001_hba_info *pm8001_ha) { … } static void pm80xx_chip_post_init(struct pm8001_hba_info *pm8001_ha) { … } static int mpi_uninit_check(struct pm8001_hba_info *pm8001_ha) { … } /** * pm80xx_fatal_errors - returns non-zero *ONLY* when fatal errors * @pm8001_ha: our hba card information * * Fatal errors are recoverable only after a host reboot. */ int pm80xx_fatal_errors(struct pm8001_hba_info *pm8001_ha) { … } /** * pm80xx_chip_soft_rst - soft reset the PM8001 chip, so that all * FW register status are reset to the originated status. * @pm8001_ha: our hba card information */ static int pm80xx_chip_soft_rst(struct pm8001_hba_info *pm8001_ha) { … } static void pm80xx_hw_chip_rst(struct pm8001_hba_info *pm8001_ha) { … } /** * pm80xx_chip_interrupt_enable - enable PM8001 chip interrupt * @pm8001_ha: our hba card information * @vec: interrupt number to enable */ static void pm80xx_chip_interrupt_enable(struct pm8001_hba_info *pm8001_ha, u8 vec) { … } /** * pm80xx_chip_interrupt_disable - disable PM8001 chip interrupt * @pm8001_ha: our hba card information * @vec: interrupt number to disable */ static void pm80xx_chip_interrupt_disable(struct pm8001_hba_info *pm8001_ha, u8 vec) { … } /** * mpi_ssp_completion - process the event that FW response to the SSP request. * @pm8001_ha: our hba card information * @piomb: the message contents of this outbound message. * * When FW has completed a ssp request for example a IO request, after it has * filled the SG data with the data, it will trigger this event representing * that he has finished the job; please check the corresponding buffer. * So we will tell the caller who maybe waiting the result to tell upper layer * that the task has been finished. */ static void mpi_ssp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) { … } /*See the comments for mpi_ssp_completion */ static void mpi_ssp_event(struct pm8001_hba_info *pm8001_ha, void *piomb) { … } /*See the comments for mpi_ssp_completion */ static void mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, struct outbound_queue_table *circularQ, void *piomb) { … } /*See the comments for mpi_ssp_completion */ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha, struct outbound_queue_table *circularQ, void *piomb) { … } /*See the comments for mpi_ssp_completion */ static void mpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) { … } /** * pm80xx_hw_event_ack_req- For PM8001, some events need to acknowledge to FW. * @pm8001_ha: our hba card information * @Qnum: the outbound queue message number. * @SEA: source of event to ack * @port_id: port id. * @phyId: phy id. * @param0: parameter 0. * @param1: parameter 1. */ static void pm80xx_hw_event_ack_req(struct pm8001_hba_info *pm8001_ha, u32 Qnum, u32 SEA, u32 port_id, u32 phyId, u32 param0, u32 param1) { … } static int pm80xx_chip_phy_ctl_req(struct pm8001_hba_info *pm8001_ha, u32 phyId, u32 phy_op); static void hw_event_port_recover(struct pm8001_hba_info *pm8001_ha, void *piomb) { … } /** * hw_event_sas_phy_up - FW tells me a SAS phy up event. * @pm8001_ha: our hba card information * @piomb: IO message buffer */ static void hw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) { … } /** * hw_event_sata_phy_up - FW tells me a SATA phy up event. * @pm8001_ha: our hba card information * @piomb: IO message buffer */ static void hw_event_sata_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) { … } /** * hw_event_phy_down - we should notify the libsas the phy is down. * @pm8001_ha: our hba card information * @piomb: IO message buffer */ static void hw_event_phy_down(struct pm8001_hba_info *pm8001_ha, void *piomb) { … } static int mpi_phy_start_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) { … } /** * mpi_thermal_hw_event - a thermal hw event has come. * @pm8001_ha: our hba card information * @piomb: IO message buffer */ static int mpi_thermal_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb) { … } /** * mpi_hw_event - The hw event has come. * @pm8001_ha: our hba card information * @piomb: IO message buffer */ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb) { … } /** * mpi_phy_stop_resp - SPCv specific * @pm8001_ha: our hba card information * @piomb: IO message buffer */ static int mpi_phy_stop_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) { … } /** * mpi_set_controller_config_resp - SPCv specific * @pm8001_ha: our hba card information * @piomb: IO message buffer */ static int mpi_set_controller_config_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) { … } /** * mpi_get_controller_config_resp - SPCv specific * @pm8001_ha: our hba card information * @piomb: IO message buffer */ static int mpi_get_controller_config_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) { … } /** * mpi_get_phy_profile_resp - SPCv specific * @pm8001_ha: our hba card information * @piomb: IO message buffer */ static int mpi_get_phy_profile_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) { … } /** * mpi_flash_op_ext_resp - SPCv specific * @pm8001_ha: our hba card information * @piomb: IO message buffer */ static int mpi_flash_op_ext_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) { … } /** * mpi_set_phy_profile_resp - SPCv specific * @pm8001_ha: our hba card information * @piomb: IO message buffer */ static int mpi_set_phy_profile_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) { … } /** * mpi_kek_management_resp - SPCv specific * @pm8001_ha: our hba card information * @piomb: IO message buffer */ static int mpi_kek_management_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) { … } /** * mpi_dek_management_resp - SPCv specific * @pm8001_ha: our hba card information * @piomb: IO message buffer */ static int mpi_dek_management_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) { … } /** * ssp_coalesced_comp_resp - SPCv specific * @pm8001_ha: our hba card information * @piomb: IO message buffer */ static int ssp_coalesced_comp_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) { … } /** * process_one_iomb - process one outbound Queue memory block * @pm8001_ha: our hba card information * @circularQ: outbound circular queue * @piomb: IO message buffer */ static void process_one_iomb(struct pm8001_hba_info *pm8001_ha, struct outbound_queue_table *circularQ, void *piomb) { … } static void print_scratchpad_registers(struct pm8001_hba_info *pm8001_ha) { … } static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec) { … } /* DMA_... to our direction translation. */ static const u8 data_dir_flags[] = …; static void build_smp_cmd(u32 deviceID, __le32 hTag, struct smp_req *psmp_cmd, int mode, int length) { … } /** * pm80xx_chip_smp_req - send an SMP task to FW * @pm8001_ha: our hba card information. * @ccb: the ccb information this request used. */ static int pm80xx_chip_smp_req(struct pm8001_hba_info *pm8001_ha, struct pm8001_ccb_info *ccb) { … } static int check_enc_sas_cmd(struct sas_task *task) { … } static int check_enc_sat_cmd(struct sas_task *task) { … } static u32 pm80xx_chip_get_q_index(struct sas_task *task) { … } /** * pm80xx_chip_ssp_io_req - send an SSP task to FW * @pm8001_ha: our hba card information. * @ccb: the ccb information this request used. */ static int pm80xx_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha, struct pm8001_ccb_info *ccb) { … } static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha, struct pm8001_ccb_info *ccb) { … } /** * pm80xx_chip_phy_start_req - start phy via PHY_START COMMAND * @pm8001_ha: our hba card information. * @phy_id: the phy id which we wanted to start up. */ static int pm80xx_chip_phy_start_req(struct pm8001_hba_info *pm8001_ha, u8 phy_id) { … } /** * pm80xx_chip_phy_stop_req - start phy via PHY_STOP COMMAND * @pm8001_ha: our hba card information. * @phy_id: the phy id which we wanted to start up. */ static int pm80xx_chip_phy_stop_req(struct pm8001_hba_info *pm8001_ha, u8 phy_id) { … } /* * see comments on pm8001_mpi_reg_resp. */ static int pm80xx_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha, struct pm8001_device *pm8001_dev, u32 flag) { … } /** * pm80xx_chip_phy_ctl_req - support the local phy operation * @pm8001_ha: our hba card information. * @phyId: the phy id which we wanted to operate * @phy_op: phy operation to request */ static int pm80xx_chip_phy_ctl_req(struct pm8001_hba_info *pm8001_ha, u32 phyId, u32 phy_op) { … } static u32 pm80xx_chip_is_our_interrupt(struct pm8001_hba_info *pm8001_ha) { … } /** * pm80xx_chip_isr - PM8001 isr handler. * @pm8001_ha: our hba card information. * @vec: irq number. */ static irqreturn_t pm80xx_chip_isr(struct pm8001_hba_info *pm8001_ha, u8 vec) { … } static void mpi_set_phy_profile_req(struct pm8001_hba_info *pm8001_ha, u32 operation, u32 phyid, u32 length, u32 *buf) { … } void pm8001_set_phy_profile(struct pm8001_hba_info *pm8001_ha, u32 length, u8 *buf) { … } void pm8001_set_phy_profile_single(struct pm8001_hba_info *pm8001_ha, u32 phy, u32 length, u32 *buf) { … } const struct pm8001_dispatch pm8001_80xx_dispatch = …;