// SPDX-License-Identifier: GPL-2.0-or-later /* * Driver for Broadcom MPI3 Storage Controllers * * Copyright (C) 2017-2023 Broadcom Inc. * (mailto: [email protected]) * */ #include "mpi3mr.h" #include <linux/io-64-nonatomic-lo-hi.h> static int mpi3mr_issue_reset(struct mpi3mr_ioc *mrioc, u16 reset_type, u16 reset_reason); static int mpi3mr_setup_admin_qpair(struct mpi3mr_ioc *mrioc); static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc, struct mpi3_ioc_facts_data *facts_data); static void mpi3mr_pel_wait_complete(struct mpi3mr_ioc *mrioc, struct mpi3mr_drv_cmd *drv_cmd); static int poll_queues; module_param(poll_queues, int, 0444); MODULE_PARM_DESC(…) …; #if defined(writeq) && defined(CONFIG_64BIT) static inline void mpi3mr_writeq(__u64 b, volatile void __iomem *addr) { … } #else static inline void mpi3mr_writeq(__u64 b, volatile void __iomem *addr) { __u64 data_out = b; writel((u32)(data_out), addr); writel((u32)(data_out >> 32), (addr + 4)); } #endif static inline bool mpi3mr_check_req_qfull(struct op_req_qinfo *op_req_q) { … } static void mpi3mr_sync_irqs(struct mpi3mr_ioc *mrioc) { … } void mpi3mr_ioc_disable_intr(struct mpi3mr_ioc *mrioc) { … } void mpi3mr_ioc_enable_intr(struct mpi3mr_ioc *mrioc) { … } static void mpi3mr_cleanup_isr(struct mpi3mr_ioc *mrioc) { … } void mpi3mr_add_sg_single(void *paddr, u8 flags, u32 length, dma_addr_t dma_addr) { … } void mpi3mr_build_zero_len_sge(void *paddr) { … } void *mpi3mr_get_reply_virt_addr(struct mpi3mr_ioc *mrioc, dma_addr_t phys_addr) { … } void *mpi3mr_get_sensebuf_virt_addr(struct mpi3mr_ioc *mrioc, dma_addr_t phys_addr) { … } static void mpi3mr_repost_reply_buf(struct mpi3mr_ioc *mrioc, u64 reply_dma) { … } void mpi3mr_repost_sense_buf(struct mpi3mr_ioc *mrioc, u64 sense_buf_dma) { … } static void mpi3mr_print_event_data(struct mpi3mr_ioc *mrioc, struct mpi3_event_notification_reply *event_reply) { … } static void mpi3mr_handle_events(struct mpi3mr_ioc *mrioc, struct mpi3_default_reply *def_reply) { … } static struct mpi3mr_drv_cmd * mpi3mr_get_drv_cmd(struct mpi3mr_ioc *mrioc, u16 host_tag, struct mpi3_default_reply *def_reply) { … } static void mpi3mr_process_admin_reply_desc(struct mpi3mr_ioc *mrioc, struct mpi3_default_reply_descriptor *reply_desc, u64 *reply_dma) { … } int mpi3mr_process_admin_reply_q(struct mpi3mr_ioc *mrioc) { … } /** * mpi3mr_get_reply_desc - get reply descriptor frame corresponding to * queue's consumer index from operational reply descriptor queue. * @op_reply_q: op_reply_qinfo object * @reply_ci: operational reply descriptor's queue consumer index * * Returns: reply descriptor frame address */ static inline struct mpi3_default_reply_descriptor * mpi3mr_get_reply_desc(struct op_reply_qinfo *op_reply_q, u32 reply_ci) { … } /** * mpi3mr_process_op_reply_q - Operational reply queue handler * @mrioc: Adapter instance reference * @op_reply_q: Operational reply queue info * * Checks the specific operational reply queue and drains the * reply queue entries until the queue is empty and process the * individual reply descriptors. * * Return: 0 if queue is already processed,or number of reply * descriptors processed. */ int mpi3mr_process_op_reply_q(struct mpi3mr_ioc *mrioc, struct op_reply_qinfo *op_reply_q) { … } /** * mpi3mr_blk_mq_poll - Operational reply queue handler * @shost: SCSI Host reference * @queue_num: Request queue number (w.r.t OS it is hardware context number) * * Checks the specific operational reply queue and drains the * reply queue entries until the queue is empty and process the * individual reply descriptors. * * Return: 0 if queue is already processed,or number of reply * descriptors processed. */ int mpi3mr_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num) { … } static irqreturn_t mpi3mr_isr_primary(int irq, void *privdata) { … } #ifndef CONFIG_PREEMPT_RT static irqreturn_t mpi3mr_isr(int irq, void *privdata) { … } /** * mpi3mr_isr_poll - Reply queue polling routine * @irq: IRQ * @privdata: Interrupt info * * poll for pending I/O completions in a loop until pending I/Os * present or controller queue depth I/Os are processed. * * Return: IRQ_NONE or IRQ_HANDLED */ static irqreturn_t mpi3mr_isr_poll(int irq, void *privdata) { … } #endif /** * mpi3mr_request_irq - Request IRQ and register ISR * @mrioc: Adapter instance reference * @index: IRQ vector index * * Request threaded ISR with primary ISR and secondary * * Return: 0 on success and non zero on failures. */ static inline int mpi3mr_request_irq(struct mpi3mr_ioc *mrioc, u16 index) { … } static void mpi3mr_calc_poll_queues(struct mpi3mr_ioc *mrioc, u16 max_vectors) { … } /** * mpi3mr_setup_isr - Setup ISR for the controller * @mrioc: Adapter instance reference * @setup_one: Request one IRQ or more * * Allocate IRQ vectors and call mpi3mr_request_irq to setup ISR * * Return: 0 on success and non zero on failures. */ static int mpi3mr_setup_isr(struct mpi3mr_ioc *mrioc, u8 setup_one) { … } static const struct { … } mrioc_states[] = …; static const char *mpi3mr_iocstate_name(enum mpi3mr_iocstate mrioc_state) { … } /* Reset reason to name mapper structure*/ static const struct { … } mpi3mr_reset_reason_codes[] = …; /** * mpi3mr_reset_rc_name - get reset reason code name * @reason_code: reset reason code value * * Map reset reason to an NULL terminated ASCII string * * Return: name corresponding to reset reason value or NULL. */ static const char *mpi3mr_reset_rc_name(enum mpi3mr_reset_reason reason_code) { … } /* Reset type to name mapper structure*/ static const struct { … } mpi3mr_reset_types[] = …; /** * mpi3mr_reset_type_name - get reset type name * @reset_type: reset type value * * Map reset type to an NULL terminated ASCII string * * Return: name corresponding to reset type value or NULL. */ static const char *mpi3mr_reset_type_name(u16 reset_type) { … } /** * mpi3mr_print_fault_info - Display fault information * @mrioc: Adapter instance reference * * Display the controller fault information if there is a * controller fault. * * Return: Nothing. */ void mpi3mr_print_fault_info(struct mpi3mr_ioc *mrioc) { … } /** * mpi3mr_get_iocstate - Get IOC State * @mrioc: Adapter instance reference * * Return a proper IOC state enum based on the IOC status and * IOC configuration and unrcoverable state of the controller. * * Return: Current IOC state. */ enum mpi3mr_iocstate mpi3mr_get_iocstate(struct mpi3mr_ioc *mrioc) { … } /** * mpi3mr_free_ioctl_dma_memory - free memory for ioctl dma * @mrioc: Adapter instance reference * * Free the DMA memory allocated for IOCTL handling purpose. * * Return: None */ static void mpi3mr_free_ioctl_dma_memory(struct mpi3mr_ioc *mrioc) { … } /** * mpi3mr_alloc_ioctl_dma_memory - Alloc memory for ioctl dma * @mrioc: Adapter instance reference * * This function allocates dmaable memory required to handle the * application issued MPI3 IOCTL requests. * * Return: None */ static void mpi3mr_alloc_ioctl_dma_memory(struct mpi3mr_ioc *mrioc) { … } /** * mpi3mr_clear_reset_history - clear reset history * @mrioc: Adapter instance reference * * Write the reset history bit in IOC status to clear the bit, * if it is already set. * * Return: Nothing. */ static inline void mpi3mr_clear_reset_history(struct mpi3mr_ioc *mrioc) { … } /** * mpi3mr_issue_and_process_mur - Message unit Reset handler * @mrioc: Adapter instance reference * @reset_reason: Reset reason code * * Issue Message unit Reset to the controller and wait for it to * be complete. * * Return: 0 on success, -1 on failure. */ static int mpi3mr_issue_and_process_mur(struct mpi3mr_ioc *mrioc, u32 reset_reason) { … } /** * mpi3mr_revalidate_factsdata - validate IOCFacts parameters * during reset/resume * @mrioc: Adapter instance reference * * Return: zero if the new IOCFacts parameters value is compatible with * older values else return -EPERM */ static int mpi3mr_revalidate_factsdata(struct mpi3mr_ioc *mrioc) { … } /** * mpi3mr_bring_ioc_ready - Bring controller to ready state * @mrioc: Adapter instance reference * * Set Enable IOC bit in IOC configuration register and wait for * the controller to become ready. * * Return: 0 on success, appropriate error on failure. */ static int mpi3mr_bring_ioc_ready(struct mpi3mr_ioc *mrioc) { … } /** * mpi3mr_soft_reset_success - Check softreset is success or not * @ioc_status: IOC status register value * @ioc_config: IOC config register value * * Check whether the soft reset is successful or not based on * IOC status and IOC config register values. * * Return: True when the soft reset is success, false otherwise. */ static inline bool mpi3mr_soft_reset_success(u32 ioc_status, u32 ioc_config) { … } /** * mpi3mr_diagfault_success - Check diag fault is success or not * @mrioc: Adapter reference * @ioc_status: IOC status register value * * Check whether the controller hit diag reset fault code. * * Return: True when there is diag fault, false otherwise. */ static inline bool mpi3mr_diagfault_success(struct mpi3mr_ioc *mrioc, u32 ioc_status) { … } /** * mpi3mr_set_diagsave - Set diag save bit for snapdump * @mrioc: Adapter reference * * Set diag save bit in IOC configuration register to enable * snapdump. * * Return: Nothing. */ static inline void mpi3mr_set_diagsave(struct mpi3mr_ioc *mrioc) { … } /** * mpi3mr_issue_reset - Issue reset to the controller * @mrioc: Adapter reference * @reset_type: Reset type * @reset_reason: Reset reason code * * Unlock the host diagnostic registers and write the specific * reset type to that, wait for reset acknowledgment from the * controller, if the reset is not successful retry for the * predefined number of times. * * Return: 0 on success, non-zero on failure. */ static int mpi3mr_issue_reset(struct mpi3mr_ioc *mrioc, u16 reset_type, u16 reset_reason) { … } /** * mpi3mr_admin_request_post - Post request to admin queue * @mrioc: Adapter reference * @admin_req: MPI3 request * @admin_req_sz: Request size * @ignore_reset: Ignore reset in process * * Post the MPI3 request into admin request queue and * inform the controller, if the queue is full return * appropriate error. * * Return: 0 on success, non-zero on failure. */ int mpi3mr_admin_request_post(struct mpi3mr_ioc *mrioc, void *admin_req, u16 admin_req_sz, u8 ignore_reset) { … } /** * mpi3mr_free_op_req_q_segments - free request memory segments * @mrioc: Adapter instance reference * @q_idx: operational request queue index * * Free memory segments allocated for operational request queue * * Return: Nothing. */ static void mpi3mr_free_op_req_q_segments(struct mpi3mr_ioc *mrioc, u16 q_idx) { … } /** * mpi3mr_free_op_reply_q_segments - free reply memory segments * @mrioc: Adapter instance reference * @q_idx: operational reply queue index * * Free memory segments allocated for operational reply queue * * Return: Nothing. */ static void mpi3mr_free_op_reply_q_segments(struct mpi3mr_ioc *mrioc, u16 q_idx) { … } /** * mpi3mr_delete_op_reply_q - delete operational reply queue * @mrioc: Adapter instance reference * @qidx: operational reply queue index * * Delete operatinal reply queue by issuing MPI request * through admin queue. * * Return: 0 on success, non-zero on failure. */ static int mpi3mr_delete_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx) { … } /** * mpi3mr_alloc_op_reply_q_segments -Alloc segmented reply pool * @mrioc: Adapter instance reference * @qidx: request queue index * * Allocate segmented memory pools for operational reply * queue. * * Return: 0 on success, non-zero on failure. */ static int mpi3mr_alloc_op_reply_q_segments(struct mpi3mr_ioc *mrioc, u16 qidx) { … } /** * mpi3mr_alloc_op_req_q_segments - Alloc segmented req pool. * @mrioc: Adapter instance reference * @qidx: request queue index * * Allocate segmented memory pools for operational request * queue. * * Return: 0 on success, non-zero on failure. */ static int mpi3mr_alloc_op_req_q_segments(struct mpi3mr_ioc *mrioc, u16 qidx) { … } /** * mpi3mr_create_op_reply_q - create operational reply queue * @mrioc: Adapter instance reference * @qidx: operational reply queue index * * Create operatinal reply queue by issuing MPI request * through admin queue. * * Return: 0 on success, non-zero on failure. */ static int mpi3mr_create_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx) { … } /** * mpi3mr_create_op_req_q - create operational request queue * @mrioc: Adapter instance reference * @idx: operational request queue index * @reply_qid: Reply queue ID * * Create operatinal request queue by issuing MPI request * through admin queue. * * Return: 0 on success, non-zero on failure. */ static int mpi3mr_create_op_req_q(struct mpi3mr_ioc *mrioc, u16 idx, u16 reply_qid) { … } /** * mpi3mr_create_op_queues - create operational queue pairs * @mrioc: Adapter instance reference * * Allocate memory for operational queue meta data and call * create request and reply queue functions. * * Return: 0 on success, non-zero on failures. */ static int mpi3mr_create_op_queues(struct mpi3mr_ioc *mrioc) { … } /** * mpi3mr_op_request_post - Post request to operational queue * @mrioc: Adapter reference * @op_req_q: Operational request queue info * @req: MPI3 request * * Post the MPI3 request into operational request queue and * inform the controller, if the queue is full return * appropriate error. * * Return: 0 on success, non-zero on failure. */ int mpi3mr_op_request_post(struct mpi3mr_ioc *mrioc, struct op_req_qinfo *op_req_q, u8 *req) { … } /** * mpi3mr_check_rh_fault_ioc - check reset history and fault * controller * @mrioc: Adapter instance reference * @reason_code: reason code for the fault. * * This routine will save snapdump and fault the controller with * the given reason code if it is not already in the fault or * not asynchronosuly reset. This will be used to handle * initilaization time faults/resets/timeout as in those cases * immediate soft reset invocation is not required. * * Return: None. */ void mpi3mr_check_rh_fault_ioc(struct mpi3mr_ioc *mrioc, u32 reason_code) { … } /** * mpi3mr_sync_timestamp - Issue time stamp sync request * @mrioc: Adapter reference * * Issue IO unit control MPI request to synchornize firmware * timestamp with host time. * * Return: 0 on success, non-zero on failure. */ static int mpi3mr_sync_timestamp(struct mpi3mr_ioc *mrioc) { … } /** * mpi3mr_print_pkg_ver - display controller fw package version * @mrioc: Adapter reference * * Retrieve firmware package version from the component image * header of the controller flash and display it. * * Return: 0 on success and non-zero on failure. */ static int mpi3mr_print_pkg_ver(struct mpi3mr_ioc *mrioc) { … } /** * mpi3mr_watchdog_work - watchdog thread to monitor faults * @work: work struct * * Watch dog work periodically executed (1 second interval) to * monitor firmware fault and to issue periodic timer sync to * the firmware. * * Return: Nothing. */ static void mpi3mr_watchdog_work(struct work_struct *work) { … } /** * mpi3mr_start_watchdog - Start watchdog * @mrioc: Adapter instance reference * * Create and start the watchdog thread to monitor controller * faults. * * Return: Nothing. */ void mpi3mr_start_watchdog(struct mpi3mr_ioc *mrioc) { … } /** * mpi3mr_stop_watchdog - Stop watchdog * @mrioc: Adapter instance reference * * Stop the watchdog thread created to monitor controller * faults. * * Return: Nothing. */ void mpi3mr_stop_watchdog(struct mpi3mr_ioc *mrioc) { … } /** * mpi3mr_setup_admin_qpair - Setup admin queue pair * @mrioc: Adapter instance reference * * Allocate memory for admin queue pair if required and register * the admin queue with the controller. * * Return: 0 on success, non-zero on failures. */ static int mpi3mr_setup_admin_qpair(struct mpi3mr_ioc *mrioc) { … } /** * mpi3mr_issue_iocfacts - Send IOC Facts * @mrioc: Adapter instance reference * @facts_data: Cached IOC facts data * * Issue IOC Facts MPI request through admin queue and wait for * the completion of it or time out. * * Return: 0 on success, non-zero on failures. */ static int mpi3mr_issue_iocfacts(struct mpi3mr_ioc *mrioc, struct mpi3_ioc_facts_data *facts_data) { … } /** * mpi3mr_check_reset_dma_mask - Process IOC facts data * @mrioc: Adapter instance reference * * Check whether the new DMA mask requested through IOCFacts by * firmware needs to be set, if so set it . * * Return: 0 on success, non-zero on failure. */ static inline int mpi3mr_check_reset_dma_mask(struct mpi3mr_ioc *mrioc) { … } /** * mpi3mr_process_factsdata - Process IOC facts data * @mrioc: Adapter instance reference * @facts_data: Cached IOC facts data * * Convert IOC facts data into cpu endianness and cache it in * the driver . * * Return: Nothing. */ static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc, struct mpi3_ioc_facts_data *facts_data) { … } /** * mpi3mr_alloc_reply_sense_bufs - Send IOC Init * @mrioc: Adapter instance reference * * Allocate and initialize the reply free buffers, sense * buffers, reply free queue and sense buffer queue. * * Return: 0 on success, non-zero on failures. */ static int mpi3mr_alloc_reply_sense_bufs(struct mpi3mr_ioc *mrioc) { … } /** * mpimr_initialize_reply_sbuf_queues - initialize reply sense * buffers * @mrioc: Adapter instance reference * * Helper function to initialize reply and sense buffers along * with some debug prints. * * Return: None. */ static void mpimr_initialize_reply_sbuf_queues(struct mpi3mr_ioc *mrioc) { … } /** * mpi3mr_issue_iocinit - Send IOC Init * @mrioc: Adapter instance reference * * Issue IOC Init MPI request through admin queue and wait for * the completion of it or time out. * * Return: 0 on success, non-zero on failures. */ static int mpi3mr_issue_iocinit(struct mpi3mr_ioc *mrioc) { … } /** * mpi3mr_unmask_events - Unmask events in event mask bitmap * @mrioc: Adapter instance reference * @event: MPI event ID * * Un mask the specific event by resetting the event_mask * bitmap. * * Return: 0 on success, non-zero on failures. */ static void mpi3mr_unmask_events(struct mpi3mr_ioc *mrioc, u16 event) { … } /** * mpi3mr_issue_event_notification - Send event notification * @mrioc: Adapter instance reference * * Issue event notification MPI request through admin queue and * wait for the completion of it or time out. * * Return: 0 on success, non-zero on failures. */ static int mpi3mr_issue_event_notification(struct mpi3mr_ioc *mrioc) { … } /** * mpi3mr_process_event_ack - Process event acknowledgment * @mrioc: Adapter instance reference * @event: MPI3 event ID * @event_ctx: event context * * Send event acknowledgment through admin queue and wait for * it to complete. * * Return: 0 on success, non-zero on failures. */ int mpi3mr_process_event_ack(struct mpi3mr_ioc *mrioc, u8 event, u32 event_ctx) { … } /** * mpi3mr_alloc_chain_bufs - Allocate chain buffers * @mrioc: Adapter instance reference * * Allocate chain buffers and set a bitmap to indicate free * chain buffers. Chain buffers are used to pass the SGE * information along with MPI3 SCSI IO requests for host I/O. * * Return: 0 on success, non-zero on failure */ static int mpi3mr_alloc_chain_bufs(struct mpi3mr_ioc *mrioc) { … } /** * mpi3mr_port_enable_complete - Mark port enable complete * @mrioc: Adapter instance reference * @drv_cmd: Internal command tracker * * Call back for asynchronous port enable request sets the * driver command to indicate port enable request is complete. * * Return: Nothing */ static void mpi3mr_port_enable_complete(struct mpi3mr_ioc *mrioc, struct mpi3mr_drv_cmd *drv_cmd) { … } /** * mpi3mr_issue_port_enable - Issue Port Enable * @mrioc: Adapter instance reference * @async: Flag to wait for completion or not * * Issue Port Enable MPI request through admin queue and if the * async flag is not set wait for the completion of the port * enable or time out. * * Return: 0 on success, non-zero on failures. */ int mpi3mr_issue_port_enable(struct mpi3mr_ioc *mrioc, u8 async) { … } /* Protocol type to name mapper structure */ static const struct { … } mpi3mr_protocols[] = …; /* Capability to name mapper structure*/ static const struct { … } mpi3mr_capabilities[] = …; /** * mpi3mr_repost_diag_bufs - repost host diag buffers * @mrioc: Adapter instance reference * * repost firmware and trace diag buffers based on global * trigger flag from driver page 2 * * Return: 0 on success, non-zero on failures. */ static int mpi3mr_repost_diag_bufs(struct mpi3mr_ioc *mrioc) { … } /** * mpi3mr_print_ioc_info - Display controller information * @mrioc: Adapter instance reference * * Display controller personality, capability, supported * protocols etc. * * Return: Nothing */ static void mpi3mr_print_ioc_info(struct mpi3mr_ioc *mrioc) { … } /** * mpi3mr_cleanup_resources - Free PCI resources * @mrioc: Adapter instance reference * * Unmap PCI device memory and disable PCI device. * * Return: 0 on success and non-zero on failure. */ void mpi3mr_cleanup_resources(struct mpi3mr_ioc *mrioc) { … } /** * mpi3mr_setup_resources - Enable PCI resources * @mrioc: Adapter instance reference * * Enable PCI device memory, MSI-x registers and set DMA mask. * * Return: 0 on success and non-zero on failure. */ int mpi3mr_setup_resources(struct mpi3mr_ioc *mrioc) { … } /** * mpi3mr_enable_events - Enable required events * @mrioc: Adapter instance reference * * This routine unmasks the events required by the driver by * sennding appropriate event mask bitmapt through an event * notification request. * * Return: 0 on success and non-zero on failure. */ static int mpi3mr_enable_events(struct mpi3mr_ioc *mrioc) { … } /** * mpi3mr_init_ioc - Initialize the controller * @mrioc: Adapter instance reference * * This the controller initialization routine, executed either * after soft reset or from pci probe callback. * Setup the required resources, memory map the controller * registers, create admin and operational reply queue pairs, * allocate required memory for reply pool, sense buffer pool, * issue IOC init request to the firmware, unmask the events and * issue port enable to discover SAS/SATA/NVMe devies and RAID * volumes. * * Return: 0 on success and non-zero on failure. */ int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc) { … } /** * mpi3mr_reinit_ioc - Re-Initialize the controller * @mrioc: Adapter instance reference * @is_resume: Called from resume or reset path * * This the controller re-initialization routine, executed from * the soft reset handler or resume callback. Creates * operational reply queue pairs, allocate required memory for * reply pool, sense buffer pool, issue IOC init request to the * firmware, unmask the events and issue port enable to discover * SAS/SATA/NVMe devices and RAID volumes. * * Return: 0 on success and non-zero on failure. */ int mpi3mr_reinit_ioc(struct mpi3mr_ioc *mrioc, u8 is_resume) { … } /** * mpi3mr_memset_op_reply_q_buffers - memset the operational reply queue's * segments * @mrioc: Adapter instance reference * @qidx: Operational reply queue index * * Return: Nothing. */ static void mpi3mr_memset_op_reply_q_buffers(struct mpi3mr_ioc *mrioc, u16 qidx) { … } /** * mpi3mr_memset_op_req_q_buffers - memset the operational request queue's * segments * @mrioc: Adapter instance reference * @qidx: Operational request queue index * * Return: Nothing. */ static void mpi3mr_memset_op_req_q_buffers(struct mpi3mr_ioc *mrioc, u16 qidx) { … } /** * mpi3mr_memset_buffers - memset memory for a controller * @mrioc: Adapter instance reference * * clear all the memory allocated for a controller, typically * called post reset to reuse the memory allocated during the * controller init. * * Return: Nothing. */ void mpi3mr_memset_buffers(struct mpi3mr_ioc *mrioc) { … } /** * mpi3mr_free_mem - Free memory allocated for a controller * @mrioc: Adapter instance reference * * Free all the memory allocated for a controller. * * Return: Nothing. */ void mpi3mr_free_mem(struct mpi3mr_ioc *mrioc) { … } /** * mpi3mr_issue_ioc_shutdown - shutdown controller * @mrioc: Adapter instance reference * * Send shutodwn notification to the controller and wait for the * shutdown_timeout for it to be completed. * * Return: Nothing. */ static void mpi3mr_issue_ioc_shutdown(struct mpi3mr_ioc *mrioc) { … } /** * mpi3mr_cleanup_ioc - Cleanup controller * @mrioc: Adapter instance reference * * controller cleanup handler, Message unit reset or soft reset * and shutdown notification is issued to the controller. * * Return: Nothing. */ void mpi3mr_cleanup_ioc(struct mpi3mr_ioc *mrioc) { … } /** * mpi3mr_drv_cmd_comp_reset - Flush a internal driver command * @mrioc: Adapter instance reference * @cmdptr: Internal command tracker * * Complete an internal driver commands with state indicating it * is completed due to reset. * * Return: Nothing. */ static inline void mpi3mr_drv_cmd_comp_reset(struct mpi3mr_ioc *mrioc, struct mpi3mr_drv_cmd *cmdptr) { … } /** * mpi3mr_flush_drv_cmds - Flush internaldriver commands * @mrioc: Adapter instance reference * * Flush all internal driver commands post reset * * Return: Nothing. */ void mpi3mr_flush_drv_cmds(struct mpi3mr_ioc *mrioc) { … } /** * mpi3mr_pel_wait_post - Issue PEL Wait * @mrioc: Adapter instance reference * @drv_cmd: Internal command tracker * * Issue PEL Wait MPI request through admin queue and return. * * Return: Nothing. */ static void mpi3mr_pel_wait_post(struct mpi3mr_ioc *mrioc, struct mpi3mr_drv_cmd *drv_cmd) { … } /** * mpi3mr_pel_get_seqnum_post - Issue PEL Get Sequence number * @mrioc: Adapter instance reference * @drv_cmd: Internal command tracker * * Issue PEL get sequence number MPI request through admin queue * and return. * * Return: 0 on success, non-zero on failure. */ int mpi3mr_pel_get_seqnum_post(struct mpi3mr_ioc *mrioc, struct mpi3mr_drv_cmd *drv_cmd) { … } /** * mpi3mr_pel_wait_complete - PELWait Completion callback * @mrioc: Adapter instance reference * @drv_cmd: Internal command tracker * * This is a callback handler for the PELWait request and * firmware completes a PELWait request when it is aborted or a * new PEL entry is available. This sends AEN to the application * and if the PELwait completion is not due to PELAbort then * this will send a request for new PEL Sequence number * * Return: Nothing. */ static void mpi3mr_pel_wait_complete(struct mpi3mr_ioc *mrioc, struct mpi3mr_drv_cmd *drv_cmd) { … } /** * mpi3mr_pel_get_seqnum_complete - PELGetSeqNum Completion callback * @mrioc: Adapter instance reference * @drv_cmd: Internal command tracker * * This is a callback handler for the PEL get sequence number * request and a new PEL wait request will be issued to the * firmware from this * * Return: Nothing. */ void mpi3mr_pel_get_seqnum_complete(struct mpi3mr_ioc *mrioc, struct mpi3mr_drv_cmd *drv_cmd) { … } /** * mpi3mr_soft_reset_handler - Reset the controller * @mrioc: Adapter instance reference * @reset_reason: Reset reason code * @snapdump: Flag to generate snapdump in firmware or not * * This is an handler for recovering controller by issuing soft * reset are diag fault reset. This is a blocking function and * when one reset is executed if any other resets they will be * blocked. All BSG requests will be blocked during the reset. If * controller reset is successful then the controller will be * reinitalized, otherwise the controller will be marked as not * recoverable * * In snapdump bit is set, the controller is issued with diag * fault reset so that the firmware can create a snap dump and * post that the firmware will result in F000 fault and the * driver will issue soft reset to recover from that. * * Return: 0 on success, non-zero on failure. */ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc, u16 reset_reason, u8 snapdump) { … } /** * mpi3mr_free_config_dma_memory - free memory for config page * @mrioc: Adapter instance reference * @mem_desc: memory descriptor structure * * Check whether the size of the buffer specified by the memory * descriptor is greater than the default page size if so then * free the memory pointed by the descriptor. * * Return: Nothing. */ static void mpi3mr_free_config_dma_memory(struct mpi3mr_ioc *mrioc, struct dma_memory_desc *mem_desc) { … } /** * mpi3mr_alloc_config_dma_memory - Alloc memory for config page * @mrioc: Adapter instance reference * @mem_desc: Memory descriptor to hold dma memory info * * This function allocates new dmaable memory or provides the * default config page dmaable memory based on the memory size * described by the descriptor. * * Return: 0 on success, non-zero on failure. */ static int mpi3mr_alloc_config_dma_memory(struct mpi3mr_ioc *mrioc, struct dma_memory_desc *mem_desc) { … } /** * mpi3mr_post_cfg_req - Issue config requests and wait * @mrioc: Adapter instance reference * @cfg_req: Configuration request * @timeout: Timeout in seconds * @ioc_status: Pointer to return ioc status * * A generic function for posting MPI3 configuration request to * the firmware. This blocks for the completion of request for * timeout seconds and if the request times out this function * faults the controller with proper reason code. * * On successful completion of the request this function returns * appropriate ioc status from the firmware back to the caller. * * Return: 0 on success, non-zero on failure. */ static int mpi3mr_post_cfg_req(struct mpi3mr_ioc *mrioc, struct mpi3_config_request *cfg_req, int timeout, u16 *ioc_status) { … } /** * mpi3mr_process_cfg_req - config page request processor * @mrioc: Adapter instance reference * @cfg_req: Configuration request * @cfg_hdr: Configuration page header * @timeout: Timeout in seconds * @ioc_status: Pointer to return ioc status * @cfg_buf: Memory pointer to copy config page or header * @cfg_buf_sz: Size of the memory to get config page or header * * This is handler for config page read, write and config page * header read operations. * * This function expects the cfg_req to be populated with page * type, page number, action for the header read and with page * address for all other operations. * * The cfg_hdr can be passed as null for reading required header * details for read/write pages the cfg_hdr should point valid * configuration page header. * * This allocates dmaable memory based on the size of the config * buffer and set the SGE of the cfg_req. * * For write actions, the config page data has to be passed in * the cfg_buf and size of the data has to be mentioned in the * cfg_buf_sz. * * For read/header actions, on successful completion of the * request with successful ioc_status the data will be copied * into the cfg_buf limited to a minimum of actual page size and * cfg_buf_sz * * * Return: 0 on success, non-zero on failure. */ static int mpi3mr_process_cfg_req(struct mpi3mr_ioc *mrioc, struct mpi3_config_request *cfg_req, struct mpi3_config_page_header *cfg_hdr, int timeout, u16 *ioc_status, void *cfg_buf, u32 cfg_buf_sz) { … } /** * mpi3mr_cfg_get_dev_pg0 - Read current device page0 * @mrioc: Adapter instance reference * @ioc_status: Pointer to return ioc status * @dev_pg0: Pointer to return device page 0 * @pg_sz: Size of the memory allocated to the page pointer * @form: The form to be used for addressing the page * @form_spec: Form specific information like device handle * * This is handler for config page read for a specific device * page0. The ioc_status has the controller returned ioc_status. * This routine doesn't check ioc_status to decide whether the * page read is success or not and it is the callers * responsibility. * * Return: 0 on success, non-zero on failure. */ int mpi3mr_cfg_get_dev_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status, struct mpi3_device_page0 *dev_pg0, u16 pg_sz, u32 form, u32 form_spec) { … } /** * mpi3mr_cfg_get_sas_phy_pg0 - Read current SAS Phy page0 * @mrioc: Adapter instance reference * @ioc_status: Pointer to return ioc status * @phy_pg0: Pointer to return SAS Phy page 0 * @pg_sz: Size of the memory allocated to the page pointer * @form: The form to be used for addressing the page * @form_spec: Form specific information like phy number * * This is handler for config page read for a specific SAS Phy * page0. The ioc_status has the controller returned ioc_status. * This routine doesn't check ioc_status to decide whether the * page read is success or not and it is the callers * responsibility. * * Return: 0 on success, non-zero on failure. */ int mpi3mr_cfg_get_sas_phy_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status, struct mpi3_sas_phy_page0 *phy_pg0, u16 pg_sz, u32 form, u32 form_spec) { … } /** * mpi3mr_cfg_get_sas_phy_pg1 - Read current SAS Phy page1 * @mrioc: Adapter instance reference * @ioc_status: Pointer to return ioc status * @phy_pg1: Pointer to return SAS Phy page 1 * @pg_sz: Size of the memory allocated to the page pointer * @form: The form to be used for addressing the page * @form_spec: Form specific information like phy number * * This is handler for config page read for a specific SAS Phy * page1. The ioc_status has the controller returned ioc_status. * This routine doesn't check ioc_status to decide whether the * page read is success or not and it is the callers * responsibility. * * Return: 0 on success, non-zero on failure. */ int mpi3mr_cfg_get_sas_phy_pg1(struct mpi3mr_ioc *mrioc, u16 *ioc_status, struct mpi3_sas_phy_page1 *phy_pg1, u16 pg_sz, u32 form, u32 form_spec) { … } /** * mpi3mr_cfg_get_sas_exp_pg0 - Read current SAS Expander page0 * @mrioc: Adapter instance reference * @ioc_status: Pointer to return ioc status * @exp_pg0: Pointer to return SAS Expander page 0 * @pg_sz: Size of the memory allocated to the page pointer * @form: The form to be used for addressing the page * @form_spec: Form specific information like device handle * * This is handler for config page read for a specific SAS * Expander page0. The ioc_status has the controller returned * ioc_status. This routine doesn't check ioc_status to decide * whether the page read is success or not and it is the callers * responsibility. * * Return: 0 on success, non-zero on failure. */ int mpi3mr_cfg_get_sas_exp_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status, struct mpi3_sas_expander_page0 *exp_pg0, u16 pg_sz, u32 form, u32 form_spec) { … } /** * mpi3mr_cfg_get_sas_exp_pg1 - Read current SAS Expander page1 * @mrioc: Adapter instance reference * @ioc_status: Pointer to return ioc status * @exp_pg1: Pointer to return SAS Expander page 1 * @pg_sz: Size of the memory allocated to the page pointer * @form: The form to be used for addressing the page * @form_spec: Form specific information like phy number * * This is handler for config page read for a specific SAS * Expander page1. The ioc_status has the controller returned * ioc_status. This routine doesn't check ioc_status to decide * whether the page read is success or not and it is the callers * responsibility. * * Return: 0 on success, non-zero on failure. */ int mpi3mr_cfg_get_sas_exp_pg1(struct mpi3mr_ioc *mrioc, u16 *ioc_status, struct mpi3_sas_expander_page1 *exp_pg1, u16 pg_sz, u32 form, u32 form_spec) { … } /** * mpi3mr_cfg_get_enclosure_pg0 - Read current Enclosure page0 * @mrioc: Adapter instance reference * @ioc_status: Pointer to return ioc status * @encl_pg0: Pointer to return Enclosure page 0 * @pg_sz: Size of the memory allocated to the page pointer * @form: The form to be used for addressing the page * @form_spec: Form specific information like device handle * * This is handler for config page read for a specific Enclosure * page0. The ioc_status has the controller returned ioc_status. * This routine doesn't check ioc_status to decide whether the * page read is success or not and it is the callers * responsibility. * * Return: 0 on success, non-zero on failure. */ int mpi3mr_cfg_get_enclosure_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status, struct mpi3_enclosure_page0 *encl_pg0, u16 pg_sz, u32 form, u32 form_spec) { … } /** * mpi3mr_cfg_get_sas_io_unit_pg0 - Read current SASIOUnit page0 * @mrioc: Adapter instance reference * @sas_io_unit_pg0: Pointer to return SAS IO Unit page 0 * @pg_sz: Size of the memory allocated to the page pointer * * This is handler for config page read for the SAS IO Unit * page0. This routine checks ioc_status to decide whether the * page read is success or not. * * Return: 0 on success, non-zero on failure. */ int mpi3mr_cfg_get_sas_io_unit_pg0(struct mpi3mr_ioc *mrioc, struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0, u16 pg_sz) { … } /** * mpi3mr_cfg_get_sas_io_unit_pg1 - Read current SASIOUnit page1 * @mrioc: Adapter instance reference * @sas_io_unit_pg1: Pointer to return SAS IO Unit page 1 * @pg_sz: Size of the memory allocated to the page pointer * * This is handler for config page read for the SAS IO Unit * page1. This routine checks ioc_status to decide whether the * page read is success or not. * * Return: 0 on success, non-zero on failure. */ int mpi3mr_cfg_get_sas_io_unit_pg1(struct mpi3mr_ioc *mrioc, struct mpi3_sas_io_unit_page1 *sas_io_unit_pg1, u16 pg_sz) { … } /** * mpi3mr_cfg_set_sas_io_unit_pg1 - Write SASIOUnit page1 * @mrioc: Adapter instance reference * @sas_io_unit_pg1: Pointer to the SAS IO Unit page 1 to write * @pg_sz: Size of the memory allocated to the page pointer * * This is handler for config page write for the SAS IO Unit * page1. This routine checks ioc_status to decide whether the * page read is success or not. This will modify both current * and persistent page. * * Return: 0 on success, non-zero on failure. */ int mpi3mr_cfg_set_sas_io_unit_pg1(struct mpi3mr_ioc *mrioc, struct mpi3_sas_io_unit_page1 *sas_io_unit_pg1, u16 pg_sz) { … } /** * mpi3mr_cfg_get_driver_pg1 - Read current Driver page1 * @mrioc: Adapter instance reference * @driver_pg1: Pointer to return Driver page 1 * @pg_sz: Size of the memory allocated to the page pointer * * This is handler for config page read for the Driver page1. * This routine checks ioc_status to decide whether the page * read is success or not. * * Return: 0 on success, non-zero on failure. */ int mpi3mr_cfg_get_driver_pg1(struct mpi3mr_ioc *mrioc, struct mpi3_driver_page1 *driver_pg1, u16 pg_sz) { … } /** * mpi3mr_cfg_get_driver_pg2 - Read current driver page2 * @mrioc: Adapter instance reference * @driver_pg2: Pointer to return driver page 2 * @pg_sz: Size of the memory allocated to the page pointer * @page_action: Page action * * This is handler for config page read for the driver page2. * This routine checks ioc_status to decide whether the page * read is success or not. * * Return: 0 on success, non-zero on failure. */ int mpi3mr_cfg_get_driver_pg2(struct mpi3mr_ioc *mrioc, struct mpi3_driver_page2 *driver_pg2, u16 pg_sz, u8 page_action) { … }