forked from Minki/linux
scsi: mpi3mr: Base driver code
Implement basic pci device driver requirements: Device probing, memory allocation, mapping system registers, allocate irq lines, etc. Source is managed in mainly three different files: - mpi3mr_fw.c: Common code which interacts with underlying fw/hw. - mpi3mr_os.c: Common code which interacts with SCSI midlayer. - mpi3mr_app.c: Common code which interacts with application/ioctl. This is currently work in progress. Link: https://lore.kernel.org/r/20210520152545.2710479-3-kashyap.desai@broadcom.com Cc: sathya.prakash@broadcom.com Cc: bvanassche@acm.org Reviewed-by: Hannes Reinecke <hare@suse.de> Reviewed-by: Tomas Henzl <thenzl@redhat.com> Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Signed-off-by: Kashyap Desai <kashyap.desai@broadcom.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
parent
c4f7ac6461
commit
824a156633
4
drivers/scsi/mpi3mr/Makefile
Normal file
4
drivers/scsi/mpi3mr/Makefile
Normal file
@ -0,0 +1,4 @@
|
||||
# mpi3mr makefile
|
||||
obj-m += mpi3mr.o
|
||||
mpi3mr-y += mpi3mr_os.o \
|
||||
mpi3mr_fw.o \
|
528
drivers/scsi/mpi3mr/mpi3mr.h
Normal file
528
drivers/scsi/mpi3mr/mpi3mr.h
Normal file
@ -0,0 +1,528 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Driver for Broadcom MPI3 Storage Controllers
|
||||
*
|
||||
* Copyright (C) 2017-2021 Broadcom Inc.
|
||||
* (mailto: mpi3mr-linuxdrv.pdl@broadcom.com)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MPI3MR_H_INCLUDED
|
||||
#define MPI3MR_H_INCLUDED
|
||||
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/blk-mq.h>
|
||||
#include <linux/blk-mq-pci.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dmapool.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/utsname.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include <scsi/scsi.h>
|
||||
#include <scsi/scsi_cmnd.h>
|
||||
#include <scsi/scsi_dbg.h>
|
||||
#include <scsi/scsi_device.h>
|
||||
#include <scsi/scsi_host.h>
|
||||
#include <scsi/scsi_tcq.h>
|
||||
|
||||
#include "mpi/mpi30_transport.h"
|
||||
#include "mpi/mpi30_image.h"
|
||||
#include "mpi/mpi30_init.h"
|
||||
#include "mpi/mpi30_ioc.h"
|
||||
#include "mpi3mr_debug.h"
|
||||
|
||||
/* Global list and lock for storing multiple adapters managed by the driver */
|
||||
extern spinlock_t mrioc_list_lock;
|
||||
extern struct list_head mrioc_list;
|
||||
|
||||
#define MPI3MR_DRIVER_VERSION "00.255.45.01"
|
||||
#define MPI3MR_DRIVER_RELDATE "12-December-2020"
|
||||
|
||||
#define MPI3MR_DRIVER_NAME "mpi3mr"
|
||||
#define MPI3MR_DRIVER_LICENSE "GPL"
|
||||
#define MPI3MR_DRIVER_AUTHOR "Broadcom Inc. <mpi3mr-linuxdrv.pdl@broadcom.com>"
|
||||
#define MPI3MR_DRIVER_DESC "MPI3 Storage Controller Device Driver"
|
||||
|
||||
#define MPI3MR_NAME_LENGTH 32
|
||||
#define IOCNAME "%s: "
|
||||
|
||||
/* Definitions for internal SGL and Chain SGL buffers */
|
||||
#define MPI3MR_PAGE_SIZE_4K 4096
|
||||
#define MPI3MR_SG_DEPTH (MPI3MR_PAGE_SIZE_4K / sizeof(struct mpi3_sge_common))
|
||||
|
||||
/* Definitions for MAX values for shost */
|
||||
#define MPI3MR_MAX_CMDS_LUN 7
|
||||
#define MPI3MR_MAX_CDB_LENGTH 32
|
||||
|
||||
/* Admin queue management definitions */
|
||||
#define MPI3MR_ADMIN_REQ_Q_SIZE (2 * MPI3MR_PAGE_SIZE_4K)
|
||||
#define MPI3MR_ADMIN_REPLY_Q_SIZE (4 * MPI3MR_PAGE_SIZE_4K)
|
||||
#define MPI3MR_ADMIN_REQ_FRAME_SZ 128
|
||||
#define MPI3MR_ADMIN_REPLY_FRAME_SZ 16
|
||||
|
||||
|
||||
/* Reserved Host Tag definitions */
|
||||
#define MPI3MR_HOSTTAG_INVALID 0xFFFF
|
||||
#define MPI3MR_HOSTTAG_INITCMDS 1
|
||||
#define MPI3MR_HOSTTAG_IOCTLCMDS 2
|
||||
#define MPI3MR_HOSTTAG_BLK_TMS 5
|
||||
|
||||
#define MPI3MR_NUM_DEVRMCMD 1
|
||||
#define MPI3MR_HOSTTAG_DEVRMCMD_MIN (MPI3MR_HOSTTAG_BLK_TMS + 1)
|
||||
#define MPI3MR_HOSTTAG_DEVRMCMD_MAX (MPI3MR_HOSTTAG_DEVRMCMD_MIN + \
|
||||
MPI3MR_NUM_DEVRMCMD - 1)
|
||||
|
||||
#define MPI3MR_INTERNAL_CMDS_RESVD MPI3MR_HOSTTAG_DEVRMCMD_MAX
|
||||
|
||||
/* Reduced resource count definition for crash kernel */
|
||||
#define MPI3MR_HOST_IOS_KDUMP 128
|
||||
|
||||
/* command/controller interaction timeout definitions in seconds */
|
||||
#define MPI3MR_INTADMCMD_TIMEOUT 10
|
||||
#define MPI3MR_RESETTM_TIMEOUT 30
|
||||
#define MPI3MR_DEFAULT_SHUTDOWN_TIME 120
|
||||
|
||||
#define MPI3MR_WATCHDOG_INTERVAL 1000 /* in milli seconds */
|
||||
|
||||
/* Internal admin command state definitions*/
|
||||
#define MPI3MR_CMD_NOTUSED 0x8000
|
||||
#define MPI3MR_CMD_COMPLETE 0x0001
|
||||
#define MPI3MR_CMD_PENDING 0x0002
|
||||
#define MPI3MR_CMD_REPLY_VALID 0x0004
|
||||
#define MPI3MR_CMD_RESET 0x0008
|
||||
|
||||
/* Definitions for Event replies and sense buffer allocated per controller */
|
||||
#define MPI3MR_NUM_EVT_REPLIES 64
|
||||
#define MPI3MR_SENSEBUF_SZ 256
|
||||
#define MPI3MR_SENSEBUF_FACTOR 3
|
||||
#define MPI3MR_CHAINBUF_FACTOR 3
|
||||
|
||||
/* Invalid target device handle */
|
||||
#define MPI3MR_INVALID_DEV_HANDLE 0xFFFF
|
||||
|
||||
/* Controller Reset related definitions */
|
||||
#define MPI3MR_HOSTDIAG_UNLOCK_RETRY_COUNT 5
|
||||
#define MPI3MR_MAX_RESET_RETRY_COUNT 3
|
||||
|
||||
/* ResponseCode definitions */
|
||||
#define MPI3MR_RI_MASK_RESPCODE (0x000000FF)
|
||||
#define MPI3MR_RSP_TM_COMPLETE 0x00
|
||||
#define MPI3MR_RSP_INVALID_FRAME 0x02
|
||||
#define MPI3MR_RSP_TM_NOT_SUPPORTED 0x04
|
||||
#define MPI3MR_RSP_TM_FAILED 0x05
|
||||
#define MPI3MR_RSP_TM_SUCCEEDED 0x08
|
||||
#define MPI3MR_RSP_TM_INVALID_LUN 0x09
|
||||
#define MPI3MR_RSP_TM_OVERLAPPED_TAG 0x0A
|
||||
#define MPI3MR_RSP_IO_QUEUED_ON_IOC \
|
||||
MPI3_SCSITASKMGMT_RSPCODE_IO_QUEUED_ON_IOC
|
||||
|
||||
/* SGE Flag definition */
|
||||
#define MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST \
|
||||
(MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE | MPI3_SGE_FLAGS_DLAS_SYSTEM | \
|
||||
MPI3_SGE_FLAGS_END_OF_LIST)
|
||||
|
||||
/* IOC State definitions */
|
||||
enum mpi3mr_iocstate {
|
||||
MRIOC_STATE_READY = 1,
|
||||
MRIOC_STATE_RESET,
|
||||
MRIOC_STATE_FAULT,
|
||||
MRIOC_STATE_BECOMING_READY,
|
||||
MRIOC_STATE_RESET_REQUESTED,
|
||||
MRIOC_STATE_UNRECOVERABLE,
|
||||
};
|
||||
|
||||
/* Reset reason code definitions*/
|
||||
enum mpi3mr_reset_reason {
|
||||
MPI3MR_RESET_FROM_BRINGUP = 1,
|
||||
MPI3MR_RESET_FROM_FAULT_WATCH = 2,
|
||||
MPI3MR_RESET_FROM_IOCTL = 3,
|
||||
MPI3MR_RESET_FROM_EH_HOS = 4,
|
||||
MPI3MR_RESET_FROM_TM_TIMEOUT = 5,
|
||||
MPI3MR_RESET_FROM_IOCTL_TIMEOUT = 6,
|
||||
MPI3MR_RESET_FROM_MUR_FAILURE = 7,
|
||||
MPI3MR_RESET_FROM_CTLR_CLEANUP = 8,
|
||||
MPI3MR_RESET_FROM_CIACTIV_FAULT = 9,
|
||||
MPI3MR_RESET_FROM_PE_TIMEOUT = 10,
|
||||
MPI3MR_RESET_FROM_TSU_TIMEOUT = 11,
|
||||
MPI3MR_RESET_FROM_DELREQQ_TIMEOUT = 12,
|
||||
MPI3MR_RESET_FROM_DELREPQ_TIMEOUT = 13,
|
||||
MPI3MR_RESET_FROM_CREATEREPQ_TIMEOUT = 14,
|
||||
MPI3MR_RESET_FROM_CREATEREQQ_TIMEOUT = 15,
|
||||
MPI3MR_RESET_FROM_IOCFACTS_TIMEOUT = 16,
|
||||
MPI3MR_RESET_FROM_IOCINIT_TIMEOUT = 17,
|
||||
MPI3MR_RESET_FROM_EVTNOTIFY_TIMEOUT = 18,
|
||||
MPI3MR_RESET_FROM_EVTACK_TIMEOUT = 19,
|
||||
MPI3MR_RESET_FROM_CIACTVRST_TIMER = 20,
|
||||
MPI3MR_RESET_FROM_GETPKGVER_TIMEOUT = 21,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mpi3mr_compimg_ver - replica of component image
|
||||
* version defined in mpi30_image.h in host endianness
|
||||
*
|
||||
*/
|
||||
struct mpi3mr_compimg_ver {
|
||||
u16 build_num;
|
||||
u16 cust_id;
|
||||
u8 ph_minor;
|
||||
u8 ph_major;
|
||||
u8 gen_minor;
|
||||
u8 gen_major;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mpi3mr_ioc_facs - replica of component image version
|
||||
* defined in mpi30_ioc.h in host endianness
|
||||
*
|
||||
*/
|
||||
struct mpi3mr_ioc_facts {
|
||||
u32 ioc_capabilities;
|
||||
struct mpi3mr_compimg_ver fw_ver;
|
||||
u32 mpi_version;
|
||||
u16 max_reqs;
|
||||
u16 product_id;
|
||||
u16 op_req_sz;
|
||||
u16 reply_sz;
|
||||
u16 exceptions;
|
||||
u16 max_perids;
|
||||
u16 max_pds;
|
||||
u16 max_sasexpanders;
|
||||
u16 max_sasinitiators;
|
||||
u16 max_enclosures;
|
||||
u16 max_pcie_switches;
|
||||
u16 max_nvme;
|
||||
u16 max_vds;
|
||||
u16 max_hpds;
|
||||
u16 max_advhpds;
|
||||
u16 max_raidpds;
|
||||
u16 min_devhandle;
|
||||
u16 max_devhandle;
|
||||
u16 max_op_req_q;
|
||||
u16 max_op_reply_q;
|
||||
u16 shutdown_timeout;
|
||||
u8 ioc_num;
|
||||
u8 who_init;
|
||||
u16 max_msix_vectors;
|
||||
u8 personality;
|
||||
u8 dma_mask;
|
||||
u8 protocol_flags;
|
||||
u8 sge_mod_mask;
|
||||
u8 sge_mod_value;
|
||||
u8 sge_mod_shift;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct op_req_qinfo - Operational Request Queue Information
|
||||
*
|
||||
* @ci: consumer index
|
||||
* @pi: producer index
|
||||
*/
|
||||
struct op_req_qinfo {
|
||||
u16 ci;
|
||||
u16 pi;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct op_reply_qinfo - Operational Reply Queue Information
|
||||
*
|
||||
* @ci: consumer index
|
||||
* @qid: Queue Id starting from 1
|
||||
*/
|
||||
struct op_reply_qinfo {
|
||||
u16 ci;
|
||||
u16 qid;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mpi3mr_intr_info - Interrupt cookie information
|
||||
*
|
||||
* @mrioc: Adapter instance reference
|
||||
* @msix_index: MSIx index
|
||||
* @op_reply_q: Associated operational reply queue
|
||||
* @name: Dev name for the irq claiming device
|
||||
*/
|
||||
struct mpi3mr_intr_info {
|
||||
struct mpi3mr_ioc *mrioc;
|
||||
u16 msix_index;
|
||||
struct op_reply_qinfo *op_reply_q;
|
||||
char name[MPI3MR_NAME_LENGTH];
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* struct mpi3mr_drv_cmd - Internal command tracker
|
||||
*
|
||||
* @mutex: Command mutex
|
||||
* @done: Completeor for wakeup
|
||||
* @reply: Firmware reply for internal commands
|
||||
* @sensebuf: Sensebuf for SCSI IO commands
|
||||
* @state: Command State
|
||||
* @dev_handle: Firmware handle for device specific commands
|
||||
* @ioc_status: IOC status from the firmware
|
||||
* @ioc_loginfo:IOC log info from the firmware
|
||||
* @is_waiting: Is the command issued in block mode
|
||||
* @retry_count: Retry count for retriable commands
|
||||
* @host_tag: Host tag used by the command
|
||||
* @callback: Callback for non blocking commands
|
||||
*/
|
||||
struct mpi3mr_drv_cmd {
|
||||
struct mutex mutex;
|
||||
struct completion done;
|
||||
void *reply;
|
||||
u8 *sensebuf;
|
||||
u16 state;
|
||||
u16 dev_handle;
|
||||
u16 ioc_status;
|
||||
u32 ioc_loginfo;
|
||||
u8 is_waiting;
|
||||
u8 retry_count;
|
||||
u16 host_tag;
|
||||
|
||||
void (*callback)(struct mpi3mr_ioc *mrioc,
|
||||
struct mpi3mr_drv_cmd *drv_cmd);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* struct chain_element - memory descriptor structure to store
|
||||
* virtual and dma addresses for chain elements.
|
||||
*
|
||||
* @addr: virtual address
|
||||
* @dma_addr: dma address
|
||||
*/
|
||||
struct chain_element {
|
||||
void *addr;
|
||||
dma_addr_t dma_addr;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct scmd_priv - SCSI command private data
|
||||
*
|
||||
* @host_tag: Host tag specific to operational queue
|
||||
* @in_lld_scope: Command in LLD scope or not
|
||||
* @scmd: SCSI Command pointer
|
||||
* @req_q_idx: Operational request queue index
|
||||
* @chain_idx: Chain frame index
|
||||
* @mpi3mr_scsiio_req: MPI SCSI IO request
|
||||
*/
|
||||
struct scmd_priv {
|
||||
u16 host_tag;
|
||||
u8 in_lld_scope;
|
||||
struct scsi_cmnd *scmd;
|
||||
u16 req_q_idx;
|
||||
int chain_idx;
|
||||
u8 mpi3mr_scsiio_req[MPI3MR_ADMIN_REQ_FRAME_SZ];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mpi3mr_ioc - Adapter anchor structure stored in shost
|
||||
* private data
|
||||
*
|
||||
* @list: List pointer
|
||||
* @pdev: PCI device pointer
|
||||
* @shost: Scsi_Host pointer
|
||||
* @id: Controller ID
|
||||
* @cpu_count: Number of online CPUs
|
||||
* @name: Controller ASCII name
|
||||
* @driver_name: Driver ASCII name
|
||||
* @sysif_regs: System interface registers virtual address
|
||||
* @sysif_regs_phys: System interface registers physical address
|
||||
* @bars: PCI BARS
|
||||
* @dma_mask: DMA mask
|
||||
* @msix_count: Number of MSIX vectors used
|
||||
* @intr_enabled: Is interrupts enabled
|
||||
* @num_admin_req: Number of admin requests
|
||||
* @admin_req_q_sz: Admin request queue size
|
||||
* @admin_req_pi: Admin request queue producer index
|
||||
* @admin_req_ci: Admin request queue consumer index
|
||||
* @admin_req_base: Admin request queue base virtual address
|
||||
* @admin_req_dma: Admin request queue base dma address
|
||||
* @admin_req_lock: Admin queue access lock
|
||||
* @num_admin_replies: Number of admin replies
|
||||
* @admin_reply_q_sz: Admin reply queue size
|
||||
* @admin_reply_ci: Admin reply queue consumer index
|
||||
* @admin_reply_ephase:Admin reply queue expected phase
|
||||
* @admin_reply_base: Admin reply queue base virtual address
|
||||
* @admin_reply_dma: Admin reply queue base dma address
|
||||
* @ready_timeout: Controller ready timeout
|
||||
* @intr_info: Interrupt cookie pointer
|
||||
* @intr_info_count: Number of interrupt cookies
|
||||
* @num_queues: Number of operational queues
|
||||
* @num_op_req_q: Number of operational request queues
|
||||
* @req_qinfo: Operational request queue info pointer
|
||||
* @num_op_reply_q: Number of operational reply queues
|
||||
* @op_reply_qinfo: Operational reply queue info pointer
|
||||
* @init_cmds: Command tracker for initialization commands
|
||||
* @facts: Cached IOC facts data
|
||||
* @op_reply_desc_sz: Operational reply descriptor size
|
||||
* @num_reply_bufs: Number of reply buffers allocated
|
||||
* @reply_buf_pool: Reply buffer pool
|
||||
* @reply_buf: Reply buffer base virtual address
|
||||
* @reply_buf_dma: Reply buffer DMA address
|
||||
* @reply_buf_dma_max_address: Reply DMA address max limit
|
||||
* @reply_free_qsz: Reply free queue size
|
||||
* @reply_free_q_pool: Reply free queue pool
|
||||
* @reply_free_q: Reply free queue base virtual address
|
||||
* @reply_free_q_dma: Reply free queue base DMA address
|
||||
* @reply_free_queue_lock: Reply free queue lock
|
||||
* @reply_free_queue_host_index: Reply free queue host index
|
||||
* @num_sense_bufs: Number of sense buffers
|
||||
* @sense_buf_pool: Sense buffer pool
|
||||
* @sense_buf: Sense buffer base virtual address
|
||||
* @sense_buf_dma: Sense buffer base DMA address
|
||||
* @sense_buf_q_sz: Sense buffer queue size
|
||||
* @sense_buf_q_pool: Sense buffer queue pool
|
||||
* @sense_buf_q: Sense buffer queue virtual address
|
||||
* @sense_buf_q_dma: Sense buffer queue DMA address
|
||||
* @sbq_lock: Sense buffer queue lock
|
||||
* @sbq_host_index: Sense buffer queuehost index
|
||||
* @is_driver_loading: Is driver still loading
|
||||
* @max_host_ios: Maximum host I/O count
|
||||
* @chain_buf_count: Chain buffer count
|
||||
* @chain_buf_pool: Chain buffer pool
|
||||
* @chain_sgl_list: Chain SGL list
|
||||
* @chain_bitmap_sz: Chain buffer allocator bitmap size
|
||||
* @chain_bitmap: Chain buffer allocator bitmap
|
||||
* @reset_in_progress: Reset in progress flag
|
||||
* @unrecoverable: Controller unrecoverable flag
|
||||
* @logging_level: Controller debug logging level
|
||||
* @current_event: Firmware event currently in process
|
||||
* @driver_info: Driver, Kernel, OS information to firmware
|
||||
* @change_count: Topology change count
|
||||
*/
|
||||
struct mpi3mr_ioc {
|
||||
struct list_head list;
|
||||
struct pci_dev *pdev;
|
||||
struct Scsi_Host *shost;
|
||||
u8 id;
|
||||
int cpu_count;
|
||||
|
||||
char name[MPI3MR_NAME_LENGTH];
|
||||
char driver_name[MPI3MR_NAME_LENGTH];
|
||||
|
||||
volatile struct mpi3_sysif_registers __iomem *sysif_regs;
|
||||
resource_size_t sysif_regs_phys;
|
||||
int bars;
|
||||
u64 dma_mask;
|
||||
|
||||
u16 msix_count;
|
||||
u8 intr_enabled;
|
||||
|
||||
u16 num_admin_req;
|
||||
u32 admin_req_q_sz;
|
||||
u16 admin_req_pi;
|
||||
u16 admin_req_ci;
|
||||
void *admin_req_base;
|
||||
dma_addr_t admin_req_dma;
|
||||
spinlock_t admin_req_lock;
|
||||
|
||||
u16 num_admin_replies;
|
||||
u32 admin_reply_q_sz;
|
||||
u16 admin_reply_ci;
|
||||
u8 admin_reply_ephase;
|
||||
void *admin_reply_base;
|
||||
dma_addr_t admin_reply_dma;
|
||||
|
||||
u32 ready_timeout;
|
||||
|
||||
struct mpi3mr_intr_info *intr_info;
|
||||
u16 intr_info_count;
|
||||
|
||||
u16 num_queues;
|
||||
u16 num_op_req_q;
|
||||
struct op_req_qinfo *req_qinfo;
|
||||
|
||||
u16 num_op_reply_q;
|
||||
struct op_reply_qinfo *op_reply_qinfo;
|
||||
|
||||
struct mpi3mr_drv_cmd init_cmds;
|
||||
struct mpi3mr_ioc_facts facts;
|
||||
u16 op_reply_desc_sz;
|
||||
|
||||
u32 num_reply_bufs;
|
||||
struct dma_pool *reply_buf_pool;
|
||||
u8 *reply_buf;
|
||||
dma_addr_t reply_buf_dma;
|
||||
dma_addr_t reply_buf_dma_max_address;
|
||||
|
||||
u16 reply_free_qsz;
|
||||
struct dma_pool *reply_free_q_pool;
|
||||
__le64 *reply_free_q;
|
||||
dma_addr_t reply_free_q_dma;
|
||||
spinlock_t reply_free_queue_lock;
|
||||
u32 reply_free_queue_host_index;
|
||||
|
||||
u32 num_sense_bufs;
|
||||
struct dma_pool *sense_buf_pool;
|
||||
u8 *sense_buf;
|
||||
dma_addr_t sense_buf_dma;
|
||||
|
||||
u16 sense_buf_q_sz;
|
||||
struct dma_pool *sense_buf_q_pool;
|
||||
__le64 *sense_buf_q;
|
||||
dma_addr_t sense_buf_q_dma;
|
||||
spinlock_t sbq_lock;
|
||||
u32 sbq_host_index;
|
||||
|
||||
u8 is_driver_loading;
|
||||
|
||||
u16 max_host_ios;
|
||||
|
||||
u32 chain_buf_count;
|
||||
struct dma_pool *chain_buf_pool;
|
||||
struct chain_element *chain_sgl_list;
|
||||
u16 chain_bitmap_sz;
|
||||
void *chain_bitmap;
|
||||
|
||||
u8 reset_in_progress;
|
||||
u8 unrecoverable;
|
||||
|
||||
int logging_level;
|
||||
|
||||
struct mpi3mr_fwevt *current_event;
|
||||
struct mpi3_driver_info_layout driver_info;
|
||||
u16 change_count;
|
||||
};
|
||||
|
||||
int mpi3mr_setup_resources(struct mpi3mr_ioc *mrioc);
|
||||
void mpi3mr_cleanup_resources(struct mpi3mr_ioc *mrioc);
|
||||
int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc);
|
||||
void mpi3mr_cleanup_ioc(struct mpi3mr_ioc *mrioc);
|
||||
int mpi3mr_admin_request_post(struct mpi3mr_ioc *mrioc, void *admin_req,
|
||||
u16 admin_req_sz, u8 ignore_reset);
|
||||
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_sensebuf_virt_addr(struct mpi3mr_ioc *mrioc,
|
||||
dma_addr_t phys_addr);
|
||||
void *mpi3mr_get_reply_virt_addr(struct mpi3mr_ioc *mrioc,
|
||||
dma_addr_t phys_addr);
|
||||
void mpi3mr_repost_sense_buf(struct mpi3mr_ioc *mrioc,
|
||||
u64 sense_buf_dma);
|
||||
|
||||
void mpi3mr_start_watchdog(struct mpi3mr_ioc *mrioc);
|
||||
void mpi3mr_stop_watchdog(struct mpi3mr_ioc *mrioc);
|
||||
|
||||
int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc,
|
||||
u32 reset_reason, u8 snapdump);
|
||||
void mpi3mr_ioc_disable_intr(struct mpi3mr_ioc *mrioc);
|
||||
void mpi3mr_ioc_enable_intr(struct mpi3mr_ioc *mrioc);
|
||||
|
||||
enum mpi3mr_iocstate mpi3mr_get_iocstate(struct mpi3mr_ioc *mrioc);
|
||||
|
||||
#endif /*MPI3MR_H_INCLUDED*/
|
60
drivers/scsi/mpi3mr/mpi3mr_debug.h
Normal file
60
drivers/scsi/mpi3mr/mpi3mr_debug.h
Normal file
@ -0,0 +1,60 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Driver for Broadcom MPI3 Storage Controllers
|
||||
*
|
||||
* Copyright (C) 2017-2021 Broadcom Inc.
|
||||
* (mailto: mpi3mr-linuxdrv.pdl@broadcom.com)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MPI3SAS_DEBUG_H_INCLUDED
|
||||
|
||||
#define MPI3SAS_DEBUG_H_INCLUDED
|
||||
|
||||
/*
|
||||
* debug levels
|
||||
*/
|
||||
#define MPI3_DEBUG 0x00000001
|
||||
#define MPI3_DEBUG_MSG_FRAME 0x00000002
|
||||
#define MPI3_DEBUG_SG 0x00000004
|
||||
#define MPI3_DEBUG_EVENTS 0x00000008
|
||||
#define MPI3_DEBUG_EVENT_WORK_TASK 0x00000010
|
||||
#define MPI3_DEBUG_INIT 0x00000020
|
||||
#define MPI3_DEBUG_EXIT 0x00000040
|
||||
#define MPI3_DEBUG_FAIL 0x00000080
|
||||
#define MPI3_DEBUG_TM 0x00000100
|
||||
#define MPI3_DEBUG_REPLY 0x00000200
|
||||
#define MPI3_DEBUG_HANDSHAKE 0x00000400
|
||||
#define MPI3_DEBUG_CONFIG 0x00000800
|
||||
#define MPI3_DEBUG_DL 0x00001000
|
||||
#define MPI3_DEBUG_RESET 0x00002000
|
||||
#define MPI3_DEBUG_SCSI 0x00004000
|
||||
#define MPI3_DEBUG_IOCTL 0x00008000
|
||||
#define MPI3_DEBUG_CSMISAS 0x00010000
|
||||
#define MPI3_DEBUG_SAS 0x00020000
|
||||
#define MPI3_DEBUG_TRANSPORT 0x00040000
|
||||
#define MPI3_DEBUG_TASK_SET_FULL 0x00080000
|
||||
#define MPI3_DEBUG_TRIGGER_DIAG 0x00200000
|
||||
|
||||
|
||||
/*
|
||||
* debug macros
|
||||
*/
|
||||
|
||||
#define ioc_err(ioc, fmt, ...) \
|
||||
pr_err("%s: " fmt, (ioc)->name, ##__VA_ARGS__)
|
||||
#define ioc_notice(ioc, fmt, ...) \
|
||||
pr_notice("%s: " fmt, (ioc)->name, ##__VA_ARGS__)
|
||||
#define ioc_warn(ioc, fmt, ...) \
|
||||
pr_warn("%s: " fmt, (ioc)->name, ##__VA_ARGS__)
|
||||
#define ioc_info(ioc, fmt, ...) \
|
||||
pr_info("%s: " fmt, (ioc)->name, ##__VA_ARGS__)
|
||||
|
||||
|
||||
#define dbgprint(IOC, FMT, ...) \
|
||||
do { \
|
||||
if (IOC->logging_level & MPI3_DEBUG) \
|
||||
pr_info("%s: " FMT, (IOC)->name, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#endif /* MPT3SAS_DEBUG_H_INCLUDED */
|
1805
drivers/scsi/mpi3mr/mpi3mr_fw.c
Normal file
1805
drivers/scsi/mpi3mr/mpi3mr_fw.c
Normal file
File diff suppressed because it is too large
Load Diff
364
drivers/scsi/mpi3mr/mpi3mr_os.c
Normal file
364
drivers/scsi/mpi3mr/mpi3mr_os.c
Normal file
@ -0,0 +1,364 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Driver for Broadcom MPI3 Storage Controllers
|
||||
*
|
||||
* Copyright (C) 2017-2021 Broadcom Inc.
|
||||
* (mailto: mpi3mr-linuxdrv.pdl@broadcom.com)
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mpi3mr.h"
|
||||
|
||||
/* global driver scop variables */
|
||||
LIST_HEAD(mrioc_list);
|
||||
DEFINE_SPINLOCK(mrioc_list_lock);
|
||||
static int mrioc_ids;
|
||||
static int warn_non_secure_ctlr;
|
||||
|
||||
MODULE_AUTHOR(MPI3MR_DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(MPI3MR_DRIVER_DESC);
|
||||
MODULE_LICENSE(MPI3MR_DRIVER_LICENSE);
|
||||
MODULE_VERSION(MPI3MR_DRIVER_VERSION);
|
||||
|
||||
/* Module parameters*/
|
||||
int logging_level;
|
||||
module_param(logging_level, int, 0);
|
||||
MODULE_PARM_DESC(logging_level,
|
||||
" bits for enabling additional logging info (default=0)");
|
||||
|
||||
/**
|
||||
* mpi3mr_map_queues - Map queues callback handler
|
||||
* @shost: SCSI host reference
|
||||
*
|
||||
* Call the blk_mq_pci_map_queues with from which operational
|
||||
* queue the mapping has to be done
|
||||
*
|
||||
* Return: return of blk_mq_pci_map_queues
|
||||
*/
|
||||
static int mpi3mr_map_queues(struct Scsi_Host *shost)
|
||||
{
|
||||
struct mpi3mr_ioc *mrioc = shost_priv(shost);
|
||||
|
||||
return blk_mq_pci_map_queues(&shost->tag_set.map[HCTX_TYPE_DEFAULT],
|
||||
mrioc->pdev, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* mpi3mr_slave_destroy - Slave destroy callback handler
|
||||
* @sdev: SCSI device reference
|
||||
*
|
||||
* Cleanup and free per device(lun) private data.
|
||||
*
|
||||
* Return: Nothing.
|
||||
*/
|
||||
static void mpi3mr_slave_destroy(struct scsi_device *sdev)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* mpi3mr_target_destroy - Target destroy callback handler
|
||||
* @starget: SCSI target reference
|
||||
*
|
||||
* Cleanup and free per target private data.
|
||||
*
|
||||
* Return: Nothing.
|
||||
*/
|
||||
static void mpi3mr_target_destroy(struct scsi_target *starget)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* mpi3mr_slave_configure - Slave configure callback handler
|
||||
* @sdev: SCSI device reference
|
||||
*
|
||||
* Configure queue depth, max hardware sectors and virt boundary
|
||||
* as required
|
||||
*
|
||||
* Return: 0 always.
|
||||
*/
|
||||
static int mpi3mr_slave_configure(struct scsi_device *sdev)
|
||||
{
|
||||
int retval = 0;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* mpi3mr_slave_alloc -Slave alloc callback handler
|
||||
* @sdev: SCSI device reference
|
||||
*
|
||||
* Allocate per device(lun) private data and initialize it.
|
||||
*
|
||||
* Return: 0 on success -ENOMEM on memory allocation failure.
|
||||
*/
|
||||
static int mpi3mr_slave_alloc(struct scsi_device *sdev)
|
||||
{
|
||||
int retval = 0;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* mpi3mr_target_alloc - Target alloc callback handler
|
||||
* @starget: SCSI target reference
|
||||
*
|
||||
* Allocate per target private data and initialize it.
|
||||
*
|
||||
* Return: 0 on success -ENOMEM on memory allocation failure.
|
||||
*/
|
||||
static int mpi3mr_target_alloc(struct scsi_target *starget)
|
||||
{
|
||||
int retval = -ENODEV;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* mpi3mr_qcmd - I/O request despatcher
|
||||
* @shost: SCSI Host reference
|
||||
* @scmd: SCSI Command reference
|
||||
*
|
||||
* Issues the SCSI Command as an MPI3 request.
|
||||
*
|
||||
* Return: 0 on successful queueing of the request or if the
|
||||
* request is completed with failure.
|
||||
* SCSI_MLQUEUE_DEVICE_BUSY when the device is busy.
|
||||
* SCSI_MLQUEUE_HOST_BUSY when the host queue is full.
|
||||
*/
|
||||
static int mpi3mr_qcmd(struct Scsi_Host *shost,
|
||||
struct scsi_cmnd *scmd)
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
scmd->result = DID_NO_CONNECT << 16;
|
||||
scmd->scsi_done(scmd);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static struct scsi_host_template mpi3mr_driver_template = {
|
||||
.module = THIS_MODULE,
|
||||
.name = "MPI3 Storage Controller",
|
||||
.proc_name = MPI3MR_DRIVER_NAME,
|
||||
.queuecommand = mpi3mr_qcmd,
|
||||
.target_alloc = mpi3mr_target_alloc,
|
||||
.slave_alloc = mpi3mr_slave_alloc,
|
||||
.slave_configure = mpi3mr_slave_configure,
|
||||
.target_destroy = mpi3mr_target_destroy,
|
||||
.slave_destroy = mpi3mr_slave_destroy,
|
||||
.map_queues = mpi3mr_map_queues,
|
||||
.no_write_same = 1,
|
||||
.can_queue = 1,
|
||||
.this_id = -1,
|
||||
.sg_tablesize = MPI3MR_SG_DEPTH,
|
||||
/* max xfer supported is 1M (2K in 512 byte sized sectors)
|
||||
*/
|
||||
.max_sectors = 2048,
|
||||
.cmd_per_lun = MPI3MR_MAX_CMDS_LUN,
|
||||
.track_queue_depth = 1,
|
||||
.cmd_size = sizeof(struct scmd_priv),
|
||||
};
|
||||
|
||||
/**
|
||||
* mpi3mr_init_drv_cmd - Initialize internal command tracker
|
||||
* @cmdptr: Internal command tracker
|
||||
* @host_tag: Host tag used for the specific command
|
||||
*
|
||||
* Initialize the internal command tracker structure with
|
||||
* specified host tag.
|
||||
*
|
||||
* Return: Nothing.
|
||||
*/
|
||||
static inline void mpi3mr_init_drv_cmd(struct mpi3mr_drv_cmd *cmdptr,
|
||||
u16 host_tag)
|
||||
{
|
||||
mutex_init(&cmdptr->mutex);
|
||||
cmdptr->reply = NULL;
|
||||
cmdptr->state = MPI3MR_CMD_NOTUSED;
|
||||
cmdptr->dev_handle = MPI3MR_INVALID_DEV_HANDLE;
|
||||
cmdptr->host_tag = host_tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* mpi3mr_probe - PCI probe callback
|
||||
* @pdev: PCI device instance
|
||||
* @id: PCI device ID details
|
||||
*
|
||||
* controller initialization routine. Checks the security status
|
||||
* of the controller and if it is invalid or tampered return the
|
||||
* probe without initializing the controller. Otherwise,
|
||||
* allocate per adapter instance through shost_priv and
|
||||
* initialize controller specific data structures, initializae
|
||||
* the controller hardware, add shost to the SCSI subsystem.
|
||||
*
|
||||
* Return: 0 on success, non-zero on failure.
|
||||
*/
|
||||
|
||||
static int
|
||||
mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
{
|
||||
struct mpi3mr_ioc *mrioc = NULL;
|
||||
struct Scsi_Host *shost = NULL;
|
||||
int retval = 0;
|
||||
|
||||
shost = scsi_host_alloc(&mpi3mr_driver_template,
|
||||
sizeof(struct mpi3mr_ioc));
|
||||
if (!shost) {
|
||||
retval = -ENODEV;
|
||||
goto shost_failed;
|
||||
}
|
||||
|
||||
mrioc = shost_priv(shost);
|
||||
mrioc->id = mrioc_ids++;
|
||||
sprintf(mrioc->driver_name, "%s", MPI3MR_DRIVER_NAME);
|
||||
sprintf(mrioc->name, "%s%d", mrioc->driver_name, mrioc->id);
|
||||
INIT_LIST_HEAD(&mrioc->list);
|
||||
spin_lock(&mrioc_list_lock);
|
||||
list_add_tail(&mrioc->list, &mrioc_list);
|
||||
spin_unlock(&mrioc_list_lock);
|
||||
|
||||
spin_lock_init(&mrioc->admin_req_lock);
|
||||
spin_lock_init(&mrioc->reply_free_queue_lock);
|
||||
spin_lock_init(&mrioc->sbq_lock);
|
||||
|
||||
mpi3mr_init_drv_cmd(&mrioc->init_cmds, MPI3MR_HOSTTAG_INITCMDS);
|
||||
|
||||
mrioc->logging_level = logging_level;
|
||||
mrioc->shost = shost;
|
||||
mrioc->pdev = pdev;
|
||||
|
||||
/* init shost parameters */
|
||||
shost->max_cmd_len = MPI3MR_MAX_CDB_LENGTH;
|
||||
shost->max_lun = -1;
|
||||
shost->unique_id = mrioc->id;
|
||||
|
||||
shost->max_channel = 1;
|
||||
shost->max_id = 0xFFFFFFFF;
|
||||
|
||||
mrioc->is_driver_loading = 1;
|
||||
if (mpi3mr_init_ioc(mrioc)) {
|
||||
ioc_err(mrioc, "failure at %s:%d/%s()!\n",
|
||||
__FILE__, __LINE__, __func__);
|
||||
retval = -ENODEV;
|
||||
goto out_iocinit_failed;
|
||||
}
|
||||
|
||||
shost->nr_hw_queues = mrioc->num_op_reply_q;
|
||||
shost->can_queue = mrioc->max_host_ios;
|
||||
shost->sg_tablesize = MPI3MR_SG_DEPTH;
|
||||
shost->max_id = mrioc->facts.max_perids;
|
||||
|
||||
retval = scsi_add_host(shost, &pdev->dev);
|
||||
if (retval) {
|
||||
ioc_err(mrioc, "failure at %s:%d/%s()!\n",
|
||||
__FILE__, __LINE__, __func__);
|
||||
goto addhost_failed;
|
||||
}
|
||||
|
||||
scsi_scan_host(shost);
|
||||
return retval;
|
||||
|
||||
addhost_failed:
|
||||
mpi3mr_cleanup_ioc(mrioc);
|
||||
out_iocinit_failed:
|
||||
spin_lock(&mrioc_list_lock);
|
||||
list_del(&mrioc->list);
|
||||
spin_unlock(&mrioc_list_lock);
|
||||
scsi_host_put(shost);
|
||||
shost_failed:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* mpi3mr_remove - PCI remove callback
|
||||
* @pdev: PCI device instance
|
||||
*
|
||||
* Free up all memory and resources associated with the
|
||||
* controllerand target devices, unregister the shost.
|
||||
*
|
||||
* Return: Nothing.
|
||||
*/
|
||||
static void mpi3mr_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct Scsi_Host *shost = pci_get_drvdata(pdev);
|
||||
struct mpi3mr_ioc *mrioc;
|
||||
|
||||
mrioc = shost_priv(shost);
|
||||
while (mrioc->reset_in_progress || mrioc->is_driver_loading)
|
||||
ssleep(1);
|
||||
|
||||
scsi_remove_host(shost);
|
||||
|
||||
mpi3mr_cleanup_ioc(mrioc);
|
||||
|
||||
spin_lock(&mrioc_list_lock);
|
||||
list_del(&mrioc->list);
|
||||
spin_unlock(&mrioc_list_lock);
|
||||
|
||||
scsi_host_put(shost);
|
||||
}
|
||||
|
||||
/**
|
||||
* mpi3mr_shutdown - PCI shutdown callback
|
||||
* @pdev: PCI device instance
|
||||
*
|
||||
* Free up all memory and resources associated with the
|
||||
* controller
|
||||
*
|
||||
* Return: Nothing.
|
||||
*/
|
||||
static void mpi3mr_shutdown(struct pci_dev *pdev)
|
||||
{
|
||||
struct Scsi_Host *shost = pci_get_drvdata(pdev);
|
||||
struct mpi3mr_ioc *mrioc;
|
||||
|
||||
if (!shost)
|
||||
return;
|
||||
|
||||
mrioc = shost_priv(shost);
|
||||
while (mrioc->reset_in_progress || mrioc->is_driver_loading)
|
||||
ssleep(1);
|
||||
|
||||
mpi3mr_cleanup_ioc(mrioc);
|
||||
}
|
||||
|
||||
static const struct pci_device_id mpi3mr_pci_id_table[] = {
|
||||
{
|
||||
PCI_DEVICE_SUB(PCI_VENDOR_ID_LSI_LOGIC, 0x00A5,
|
||||
PCI_ANY_ID, PCI_ANY_ID)
|
||||
},
|
||||
{ 0 }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, mpi3mr_pci_id_table);
|
||||
|
||||
static struct pci_driver mpi3mr_pci_driver = {
|
||||
.name = MPI3MR_DRIVER_NAME,
|
||||
.id_table = mpi3mr_pci_id_table,
|
||||
.probe = mpi3mr_probe,
|
||||
.remove = mpi3mr_remove,
|
||||
.shutdown = mpi3mr_shutdown,
|
||||
};
|
||||
|
||||
static int __init mpi3mr_init(void)
|
||||
{
|
||||
int ret_val;
|
||||
|
||||
pr_info("Loading %s version %s\n", MPI3MR_DRIVER_NAME,
|
||||
MPI3MR_DRIVER_VERSION);
|
||||
|
||||
ret_val = pci_register_driver(&mpi3mr_pci_driver);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
static void __exit mpi3mr_exit(void)
|
||||
{
|
||||
if (warn_non_secure_ctlr)
|
||||
pr_warn(
|
||||
"Unloading %s version %s while managing a non secure controller\n",
|
||||
MPI3MR_DRIVER_NAME, MPI3MR_DRIVER_VERSION);
|
||||
else
|
||||
pr_info("Unloading %s version %s\n", MPI3MR_DRIVER_NAME,
|
||||
MPI3MR_DRIVER_VERSION);
|
||||
|
||||
pci_unregister_driver(&mpi3mr_pci_driver);
|
||||
}
|
||||
|
||||
module_init(mpi3mr_init);
|
||||
module_exit(mpi3mr_exit);
|
Loading…
Reference in New Issue
Block a user