/* * PMC-Sierra SPC 8001 SAS/SATA based host adapters driver * * Copyright (c) 2008-2009 USI Co., Ltd. * 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 "pm8001_hwi.h" #include "pm8001_chips.h" #include "pm8001_ctl.h" #include "pm80xx_tracepoints.h" /** * 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_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) { … } /** * pm8001_bar4_shift - function is called to shift BAR base address * @pm8001_ha : our hba card information * @shiftValue : shifting value in memory bar. */ int pm8001_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue) { … } /** * mpi_set_phys_g3_with_ssc * @pm8001_ha: our hba card information * @SSCbit: set SSCbit to 0 to disable all phys ssc; 1 to enable all phys ssc. */ static void mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha, u32 SSCbit) { … } /** * mpi_set_open_retry_interval_reg * @pm8001_ha: our hba card information * @interval: interval time for each OPEN_REJECT (RETRY). The units are in 1us. */ static void mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha, u32 interval) { … } /** * 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. * @pm8001_ha: our hba card information */ static int check_fw_ready(struct pm8001_hba_info *pm8001_ha) { … } static void init_pci_device_addresses(struct pm8001_hba_info *pm8001_ha) { … } /** * pm8001_chip_init - the main init function that initialize whole PM8001 chip. * @pm8001_ha: our hba card information */ static int pm8001_chip_init(struct pm8001_hba_info *pm8001_ha) { … } static void pm8001_chip_post_init(struct pm8001_hba_info *pm8001_ha) { … } static int mpi_uninit_check(struct pm8001_hba_info *pm8001_ha) { … } /** * soft_reset_ready_check - Function to check FW is ready for soft reset. * @pm8001_ha: our hba card information */ static u32 soft_reset_ready_check(struct pm8001_hba_info *pm8001_ha) { … } /** * pm8001_chip_soft_rst - soft reset the PM8001 chip, so that the clear all * the FW register status to the originated status. * @pm8001_ha: our hba card information */ static int pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha) { … } static void pm8001_hw_chip_rst(struct pm8001_hba_info *pm8001_ha) { … } /** * pm8001_chip_iounmap - which mapped when initialized. * @pm8001_ha: our hba card information */ void pm8001_chip_iounmap(struct pm8001_hba_info *pm8001_ha) { … } /** * pm8001_chip_interrupt_enable - enable PM8001 chip interrupt * @pm8001_ha: our hba card information * @vec: unused */ static void pm8001_chip_interrupt_enable(struct pm8001_hba_info *pm8001_ha, u8 vec) { … } /** * pm8001_chip_interrupt_disable - disable PM8001 chip interrupt * @pm8001_ha: our hba card information * @vec: unused */ static void pm8001_chip_interrupt_disable(struct pm8001_hba_info *pm8001_ha, u8 vec) { … } /** * pm8001_mpi_msg_free_get - get the free message buffer for transfer * inbound queue. * @circularQ: the inbound queue we want to transfer to HBA. * @messageSize: the message size of this transfer, normally it is 64 bytes * @messagePtr: the pointer to message. */ int pm8001_mpi_msg_free_get(struct inbound_queue_table *circularQ, u16 messageSize, void **messagePtr) { … } /** * pm8001_mpi_build_cmd- build the message queue for transfer, update the PI to * FW to tell the fw to get this message from IOMB. * @pm8001_ha: our hba card information * @q_index: the index in the inbound queue we want to transfer to HBA. * @opCode: the operation code represents commands which LLDD and fw recognized. * @payload: the command payload of each operation command. * @nb: size in bytes of the command payload * @responseQueue: queue to interrupt on w/ command response (if any) */ int pm8001_mpi_build_cmd(struct pm8001_hba_info *pm8001_ha, u32 q_index, u32 opCode, void *payload, size_t nb, u32 responseQueue) { … } u32 pm8001_mpi_msg_free_set(struct pm8001_hba_info *pm8001_ha, void *pMsg, struct outbound_queue_table *circularQ, u8 bc) { … } /** * pm8001_mpi_msg_consume- get the MPI message from outbound queue * message table. * @pm8001_ha: our hba card information * @circularQ: the outbound queue table. * @messagePtr1: the message contents of this outbound message. * @pBC: the message size. */ u32 pm8001_mpi_msg_consume(struct pm8001_hba_info *pm8001_ha, struct outbound_queue_table *circularQ, void **messagePtr1, u8 *pBC) { … } void pm8001_work_fn(struct work_struct *work) { … } int pm8001_handle_event(struct pm8001_hba_info *pm8001_ha, void *data, int handler) { … } /** * 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, void *piomb) { … } /*See the comments for mpi_ssp_completion */ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha, void *piomb) { … } /*See the comments for mpi_ssp_completion */ static void mpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) { … } void pm8001_mpi_set_dev_state_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) { … } void pm8001_mpi_set_nvmd_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) { … } void pm8001_mpi_get_nvmd_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) { … } int pm8001_mpi_local_phy_ctl(struct pm8001_hba_info *pm8001_ha, void *piomb) { … } /** * pm8001_bytes_dmaed - one of the interface function communication with libsas * @pm8001_ha: our hba card information * @i: which phy that received the event. * * when HBA driver received the identify done event or initiate FIS received * event(for SATA), it will invoke this function to notify the sas layer that * the sas toplogy has formed, please discover the whole sas domain, * while receive a broadcast(change) primitive just tell the sas * layer to discover the changed domain rather than the whole domain. */ void pm8001_bytes_dmaed(struct pm8001_hba_info *pm8001_ha, int i) { … } /* Get the link rate speed */ void pm8001_get_lrate_mode(struct pm8001_phy *phy, u8 link_rate) { … } /** * pm8001_get_attached_sas_addr - extract/generate attached SAS address * @phy: pointer to asd_phy * @sas_addr: pointer to buffer where the SAS address is to be written * * This function extracts the SAS address from an IDENTIFY frame * received. If OOB is SATA, then a SAS address is generated from the * HA tables. * * LOCKING: the frame_rcvd_lock needs to be held since this parses the frame * buffer. */ void pm8001_get_attached_sas_addr(struct pm8001_phy *phy, u8 *sas_addr) { … } /** * pm8001_hw_event_ack_req- For PM8001,some events need to acknowage 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 pm8001_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 pm8001_chip_phy_ctl_req(struct pm8001_hba_info *pm8001_ha, u32 phyId, u32 phy_op); /** * 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) { … } /** * pm8001_mpi_reg_resp -process register device ID response. * @pm8001_ha: our hba card information * @piomb: IO message buffer * * when sas layer find a device it will notify LLDD, then the driver register * the domain device to FW, this event is the return device ID which the FW * has assigned, from now, inter-communication with FW is no longer using the * SAS address, use device ID which FW assigned. */ int pm8001_mpi_reg_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) { … } int pm8001_mpi_dereg_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) { … } /** * pm8001_mpi_fw_flash_update_resp - Response from FW for flash update command. * @pm8001_ha: our hba card information * @piomb: IO message buffer */ int pm8001_mpi_fw_flash_update_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) { … } int pm8001_mpi_general_event(struct pm8001_hba_info *pm8001_ha, void *piomb) { … } int pm8001_mpi_task_abort_resp(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) { … } /** * process_one_iomb - process one outbound Queue memory block * @pm8001_ha: our hba card information * @piomb: IO message buffer */ static void process_one_iomb(struct pm8001_hba_info *pm8001_ha, void *piomb) { … } static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec) { … } /* DMA_... to our direction translation. */ static const u8 data_dir_flags[] = …; void pm8001_chip_make_sg(struct scatterlist *scatter, int nr, void *prd) { … } static void build_smp_cmd(u32 deviceID, __le32 hTag, struct smp_req *psmp_cmd) { … } /** * pm8001_chip_smp_req - send a SMP task to FW * @pm8001_ha: our hba card information. * @ccb: the ccb information this request used. */ static int pm8001_chip_smp_req(struct pm8001_hba_info *pm8001_ha, struct pm8001_ccb_info *ccb) { … } /** * pm8001_chip_ssp_io_req - send a SSP task to FW * @pm8001_ha: our hba card information. * @ccb: the ccb information this request used. */ static int pm8001_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha, struct pm8001_ccb_info *ccb) { … } static int pm8001_chip_sata_req(struct pm8001_hba_info *pm8001_ha, struct pm8001_ccb_info *ccb) { … } /** * pm8001_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 pm8001_chip_phy_start_req(struct pm8001_hba_info *pm8001_ha, u8 phy_id) { … } /** * pm8001_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 pm8001_chip_phy_stop_req(struct pm8001_hba_info *pm8001_ha, u8 phy_id) { … } /* * see comments on pm8001_mpi_reg_resp. */ static int pm8001_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha, struct pm8001_device *pm8001_dev, u32 flag) { … } /* * see comments on pm8001_mpi_reg_resp. */ int pm8001_chip_dereg_dev_req(struct pm8001_hba_info *pm8001_ha, u32 device_id) { … } /** * pm8001_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: the phy operation to request */ static int pm8001_chip_phy_ctl_req(struct pm8001_hba_info *pm8001_ha, u32 phyId, u32 phy_op) { … } static u32 pm8001_chip_is_our_interrupt(struct pm8001_hba_info *pm8001_ha) { … } /** * pm8001_chip_isr - PM8001 isr handler. * @pm8001_ha: our hba card information. * @vec: IRQ number */ static irqreturn_t pm8001_chip_isr(struct pm8001_hba_info *pm8001_ha, u8 vec) { … } static int send_task_abort(struct pm8001_hba_info *pm8001_ha, u32 opc, u32 dev_id, enum sas_internal_abort type, u32 task_tag, u32 cmd_tag) { … } /* * pm8001_chip_abort_task - SAS abort task when error or exception happened. */ int pm8001_chip_abort_task(struct pm8001_hba_info *pm8001_ha, struct pm8001_ccb_info *ccb) { … } /** * pm8001_chip_ssp_tm_req - built the task management command. * @pm8001_ha: our hba card information. * @ccb: the ccb information. * @tmf: task management function. */ int pm8001_chip_ssp_tm_req(struct pm8001_hba_info *pm8001_ha, struct pm8001_ccb_info *ccb, struct sas_tmf_task *tmf) { … } int pm8001_chip_get_nvmd_req(struct pm8001_hba_info *pm8001_ha, void *payload) { … } int pm8001_chip_set_nvmd_req(struct pm8001_hba_info *pm8001_ha, void *payload) { … } /** * pm8001_chip_fw_flash_update_build - support the firmware update operation * @pm8001_ha: our hba card information. * @fw_flash_updata_info: firmware flash update param * @tag: Tag to apply to the payload */ int pm8001_chip_fw_flash_update_build(struct pm8001_hba_info *pm8001_ha, void *fw_flash_updata_info, u32 tag) { … } int pm8001_chip_fw_flash_update_req(struct pm8001_hba_info *pm8001_ha, void *payload) { … } ssize_t pm8001_get_gsm_dump(struct device *cdev, u32 length, char *buf) { … } int pm8001_chip_set_dev_state_req(struct pm8001_hba_info *pm8001_ha, struct pm8001_device *pm8001_dev, u32 state) { … } static int pm8001_chip_sas_re_initialization(struct pm8001_hba_info *pm8001_ha) { … } const struct pm8001_dispatch pm8001_8001_dispatch = …;