// SPDX-License-Identifier: GPL-2.0-or-later /* * * Linux MegaRAID device driver * * Copyright (c) 2002 LSI Logic Corporation. * * Copyright (c) 2002 Red Hat, Inc. All rights reserved. * - fixes * - speed-ups (list handling fixes, issued_list, optimizations.) * - lots of cleanups. * * Copyright (c) 2003 Christoph Hellwig <[email protected]> * - new-style, hotplug-aware pci probing and scsi registration * * Version : v2.00.4 Mon Nov 14 14:02:43 EST 2005 - Seokmann Ju * <[email protected]> * * Description: Linux device driver for LSI Logic MegaRAID controller * * Supported controllers: MegaRAID 418, 428, 438, 466, 762, 467, 471, 490, 493 * 518, 520, 531, 532 * * This driver is supported by LSI Logic, with assistance from Red Hat, Dell, * and others. Please send updates to the mailing list * [email protected] . */ #include <linux/mm.h> #include <linux/fs.h> #include <linux/blkdev.h> #include <linux/uaccess.h> #include <asm/io.h> #include <linux/completion.h> #include <linux/delay.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/reboot.h> #include <linux/module.h> #include <linux/list.h> #include <linux/interrupt.h> #include <linux/pci.h> #include <linux/init.h> #include <linux/dma-mapping.h> #include <linux/mutex.h> #include <linux/slab.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> #include <scsi/scsi_device.h> #include <scsi/scsi_eh.h> #include <scsi/scsi_host.h> #include <scsi/scsi_tcq.h> #include <scsi/scsicam.h> #include "megaraid.h" #define MEGARAID_MODULE_VERSION … MODULE_AUTHOR(…) …; MODULE_DESCRIPTION(…) …; MODULE_LICENSE(…) …; MODULE_VERSION(…); static DEFINE_MUTEX(megadev_mutex); static unsigned int max_cmd_per_lun = …; module_param(max_cmd_per_lun, uint, 0); MODULE_PARM_DESC(…) …; static unsigned short int max_sectors_per_io = …; module_param(max_sectors_per_io, ushort, 0); MODULE_PARM_DESC(…) …; static unsigned short int max_mbox_busy_wait = …; module_param(max_mbox_busy_wait, ushort, 0); MODULE_PARM_DESC(…) …; #define RDINDOOR(adapter) … #define RDOUTDOOR(adapter) … #define WRINDOOR(adapter,value) … #define WROUTDOOR(adapter,value) … /* * Global variables */ static int hba_count; static adapter_t *hba_soft_state[MAX_CONTROLLERS]; static struct proc_dir_entry *mega_proc_dir_entry; /* For controller re-ordering */ static struct mega_hbas mega_hbas[MAX_CONTROLLERS]; static long megadev_unlocked_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); /* * The File Operations structure for the serial/ioctl interface of the driver */ static const struct file_operations megadev_fops = …; /* * Array to structures for storing the information about the controllers. This * information is sent to the user level applications, when they do an ioctl * for this information. */ static struct mcontroller mcontroller[MAX_CONTROLLERS]; /* The current driver version */ static u32 driver_ver = …; /* major number used by the device for character interface */ static int major; #define IS_RAID_CH(hba, ch) … /* * Debug variable to print some diagnostic messages */ static int trace_level; /** * mega_setup_mailbox() * @adapter: pointer to our soft state * * Allocates a 8 byte aligned memory for the handshake mailbox. */ static int mega_setup_mailbox(adapter_t *adapter) { … } /* * mega_query_adapter() * @adapter - pointer to our soft state * * Issue the adapter inquiry commands to the controller and find out * information and parameter about the devices attached */ static int mega_query_adapter(adapter_t *adapter) { … } /** * mega_runpendq() * @adapter: pointer to our soft state * * Runs through the list of pending requests. */ static inline void mega_runpendq(adapter_t *adapter) { … } /* * megaraid_queue() * @scmd - Issue this scsi command * @done - the callback hook into the scsi mid-layer * * The command queuing entry point for the mid-layer. */ static int megaraid_queue_lck(struct scsi_cmnd *scmd) { … } static DEF_SCSI_QCMD(megaraid_queue) /** * mega_allocate_scb() * @adapter: pointer to our soft state * @cmd: scsi command from the mid-layer * * Allocate a SCB structure. This is the central structure for controller * commands. */ static inline scb_t * mega_allocate_scb(adapter_t *adapter, struct scsi_cmnd *cmd) { … } /** * mega_get_ldrv_num() * @adapter: pointer to our soft state * @cmd: scsi mid layer command * @channel: channel on the controller * * Calculate the logical drive number based on the information in scsi command * and the channel number. */ static inline int mega_get_ldrv_num(adapter_t *adapter, struct scsi_cmnd *cmd, int channel) { … } /** * mega_build_cmd() * @adapter: pointer to our soft state * @cmd: Prepare using this scsi command * @busy: busy flag if no resources * * Prepares a command and scatter gather list for the controller. This routine * also finds out if the commands is intended for a logical drive or a * physical device and prepares the controller command accordingly. * * We also re-order the logical drives and physical devices based on their * boot settings. */ static scb_t * mega_build_cmd(adapter_t *adapter, struct scsi_cmnd *cmd, int *busy) { … } /** * mega_prepare_passthru() * @adapter: pointer to our soft state * @scb: our scsi control block * @cmd: scsi command from the mid-layer * @channel: actual channel on the controller * @target: actual id on the controller. * * prepare a command for the scsi physical devices. */ static mega_passthru * mega_prepare_passthru(adapter_t *adapter, scb_t *scb, struct scsi_cmnd *cmd, int channel, int target) { … } /** * mega_prepare_extpassthru() * @adapter: pointer to our soft state * @scb: our scsi control block * @cmd: scsi command from the mid-layer * @channel: actual channel on the controller * @target: actual id on the controller. * * prepare a command for the scsi physical devices. This rountine prepares * commands for devices which can take extended CDBs (>10 bytes) */ static mega_ext_passthru * mega_prepare_extpassthru(adapter_t *adapter, scb_t *scb, struct scsi_cmnd *cmd, int channel, int target) { … } static void __mega_runpendq(adapter_t *adapter) { … } /** * issue_scb() * @adapter: pointer to our soft state * @scb: scsi control block * * Post a command to the card if the mailbox is available, otherwise return * busy. We also take the scb from the pending list if the mailbox is * available. */ static int issue_scb(adapter_t *adapter, scb_t *scb) { … } /* * Wait until the controller's mailbox is available */ static inline int mega_busywait_mbox (adapter_t *adapter) { … } /** * issue_scb_block() * @adapter: pointer to our soft state * @raw_mbox: the mailbox * * Issue a scb in synchronous and non-interrupt mode */ static int issue_scb_block(adapter_t *adapter, u_char *raw_mbox) { … } /** * megaraid_isr_iomapped() * @irq: irq * @devp: pointer to our soft state * * Interrupt service routine for io-mapped controllers. * Find out if our device is interrupting. If yes, acknowledge the interrupt * and service the completed commands. */ static irqreturn_t megaraid_isr_iomapped(int irq, void *devp) { … } /** * megaraid_isr_memmapped() * @irq: irq * @devp: pointer to our soft state * * Interrupt service routine for memory-mapped controllers. * Find out if our device is interrupting. If yes, acknowledge the interrupt * and service the completed commands. */ static irqreturn_t megaraid_isr_memmapped(int irq, void *devp) { … } /** * mega_cmd_done() * @adapter: pointer to our soft state * @completed: array of ids of completed commands * @nstatus: number of completed commands * @status: status of the last command completed * * Complete the commands and call the scsi mid-layer callback hooks. */ static void mega_cmd_done(adapter_t *adapter, u8 completed[], int nstatus, int status) { … } /* * mega_runpendq() * * Run through the list of completed requests and finish it */ static void mega_rundoneq (adapter_t *adapter) { … } /* * Free a SCB structure * Note: We assume the scsi commands associated with this scb is not free yet. */ static void mega_free_scb(adapter_t *adapter, scb_t *scb) { … } static int __mega_busywait_mbox (adapter_t *adapter) { … } /* * Copies data to SGLIST * Note: For 64 bit cards, we need a minimum of one SG element for read/write */ static int mega_build_sglist(adapter_t *adapter, scb_t *scb, u32 *buf, u32 *len) { … } /* * mega_8_to_40ld() * * takes all info in AdapterInquiry structure and puts it into ProductInfo and * Enquiry3 structures for later use */ static void mega_8_to_40ld(mraid_inquiry *inquiry, mega_inquiry3 *enquiry3, mega_product_info *product_info) { … } static inline void mega_free_sgl(adapter_t *adapter) { … } /* * Get information about the card/driver */ const char * megaraid_info(struct Scsi_Host *host) { … } /* * Abort a previous SCSI request. Only commands on the pending list can be * aborted. All the commands issued to the F/W must complete. */ static int megaraid_abort(struct scsi_cmnd *cmd) { … } static int megaraid_reset(struct scsi_cmnd *cmd) { … } /** * megaraid_abort_and_reset() * @adapter: megaraid soft state * @cmd: scsi command to be aborted or reset * @aor: abort or reset flag * * Try to locate the scsi command in the pending queue. If found and is not * issued to the controller, abort/reset it. Otherwise return failure */ static int megaraid_abort_and_reset(adapter_t *adapter, struct scsi_cmnd *cmd, int aor) { … } static inline int make_local_pdev(adapter_t *adapter, struct pci_dev **pdev) { … } static inline void free_local_pdev(struct pci_dev *pdev) { … } /** * mega_allocate_inquiry() * @dma_handle: handle returned for dma address * @pdev: handle to pci device * * allocates memory for inquiry structure */ static inline void * mega_allocate_inquiry(dma_addr_t *dma_handle, struct pci_dev *pdev) { … } static inline void mega_free_inquiry(void *inquiry, dma_addr_t dma_handle, struct pci_dev *pdev) { … } #ifdef CONFIG_PROC_FS /* Following code handles /proc fs */ /** * proc_show_config() * @m: Synthetic file construction data * @v: File iterator * * Display configuration information about the controller. */ static int proc_show_config(struct seq_file *m, void *v) { … } /** * proc_show_stat() * @m: Synthetic file construction data * @v: File iterator * * Display statistical information about the I/O activity. */ static int proc_show_stat(struct seq_file *m, void *v) { … } /** * proc_show_mbox() * @m: Synthetic file construction data * @v: File iterator * * Display mailbox information for the last command issued. This information * is good for debugging. */ static int proc_show_mbox(struct seq_file *m, void *v) { … } /** * proc_show_rebuild_rate() * @m: Synthetic file construction data * @v: File iterator * * Display current rebuild rate */ static int proc_show_rebuild_rate(struct seq_file *m, void *v) { … } /** * proc_show_battery() * @m: Synthetic file construction data * @v: File iterator * * Display information about the battery module on the controller. */ static int proc_show_battery(struct seq_file *m, void *v) { … } /* * Display scsi inquiry */ static void mega_print_inquiry(struct seq_file *m, char *scsi_inq) { … } /** * proc_show_pdrv() * @m: Synthetic file construction data * @adapter: pointer to our soft state * @channel: channel * * Display information about the physical drives. */ static int proc_show_pdrv(struct seq_file *m, adapter_t *adapter, int channel) { … } /** * proc_show_pdrv_ch0() * @m: Synthetic file construction data * @v: File iterator * * Display information about the physical drives on physical channel 0. */ static int proc_show_pdrv_ch0(struct seq_file *m, void *v) { … } /** * proc_show_pdrv_ch1() * @m: Synthetic file construction data * @v: File iterator * * Display information about the physical drives on physical channel 1. */ static int proc_show_pdrv_ch1(struct seq_file *m, void *v) { … } /** * proc_show_pdrv_ch2() * @m: Synthetic file construction data * @v: File iterator * * Display information about the physical drives on physical channel 2. */ static int proc_show_pdrv_ch2(struct seq_file *m, void *v) { … } /** * proc_show_pdrv_ch3() * @m: Synthetic file construction data * @v: File iterator * * Display information about the physical drives on physical channel 3. */ static int proc_show_pdrv_ch3(struct seq_file *m, void *v) { … } /** * proc_show_rdrv() * @m: Synthetic file construction data * @adapter: pointer to our soft state * @start: starting logical drive to display * @end: ending logical drive to display * * We do not print the inquiry information since its already available through * /proc/scsi/scsi interface */ static int proc_show_rdrv(struct seq_file *m, adapter_t *adapter, int start, int end ) { … } /** * proc_show_rdrv_10() * @m: Synthetic file construction data * @v: File iterator * * Display real time information about the logical drives 0 through 9. */ static int proc_show_rdrv_10(struct seq_file *m, void *v) { … } /** * proc_show_rdrv_20() * @m: Synthetic file construction data * @v: File iterator * * Display real time information about the logical drives 0 through 9. */ static int proc_show_rdrv_20(struct seq_file *m, void *v) { … } /** * proc_show_rdrv_30() * @m: Synthetic file construction data * @v: File iterator * * Display real time information about the logical drives 0 through 9. */ static int proc_show_rdrv_30(struct seq_file *m, void *v) { … } /** * proc_show_rdrv_40() * @m: Synthetic file construction data * @v: File iterator * * Display real time information about the logical drives 0 through 9. */ static int proc_show_rdrv_40(struct seq_file *m, void *v) { … } /** * mega_create_proc_entry() * @index: index in soft state array * @parent: parent node for this /proc entry * * Creates /proc entries for our controllers. */ static void mega_create_proc_entry(int index, struct proc_dir_entry *parent) { … } #else static inline void mega_create_proc_entry(int index, struct proc_dir_entry *parent) { } #endif /* * megaraid_biosparam() * * Return the disk geometry for a particular disk */ static int megaraid_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[]) { … } /** * mega_init_scb() * @adapter: pointer to our soft state * * Allocate memory for the various pointers in the scb structures: * scatter-gather list pointer, passthru and extended passthru structure * pointers. */ static int mega_init_scb(adapter_t *adapter) { … } /** * megadev_open() * @inode: unused * @filep: unused * * Routines for the character/ioctl interface to the driver. Find out if this * is a valid open. */ static int megadev_open (struct inode *inode, struct file *filep) { … } /** * megadev_ioctl() * @filep: Our device file * @cmd: ioctl command * @arg: user buffer * * ioctl entry point for our private ioctl interface. We move the data in from * the user space, prepare the command (if necessary, convert the old MIMD * ioctl to new ioctl command), and issue a synchronous command to the * controller. */ static int megadev_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) { … } static long megadev_unlocked_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) { … } /** * mega_m_to_n() * @arg: user address * @uioc: new ioctl structure * * A thin layer to convert older mimd interface ioctl structure to NIT ioctl * structure * * Converts the older mimd ioctl structure to newer NIT structure */ static int mega_m_to_n(void __user *arg, nitioctl_t *uioc) { … } /* * mega_n_to_m() * @arg: user address * @mc: mailbox command * * Updates the status information to the application, depending on application * conforms to older mimd ioctl interface or newer NIT ioctl interface */ static int mega_n_to_m(void __user *arg, megacmd_t *mc) { … } /* * MEGARAID 'FW' commands. */ /** * mega_is_bios_enabled() * @adapter: pointer to our soft state * * issue command to find out if the BIOS is enabled for this controller */ static int mega_is_bios_enabled(adapter_t *adapter) { … } /** * mega_enum_raid_scsi() * @adapter: pointer to our soft state * * Find out what channels are RAID/SCSI. This information is used to * differentiate the virtual channels and physical channels and to support * ROMB feature and non-disk devices. */ static void mega_enum_raid_scsi(adapter_t *adapter) { … } /** * mega_get_boot_drv() * @adapter: pointer to our soft state * * Find out which device is the boot device. Note, any logical drive or any * phyical device (e.g., a CDROM) can be designated as a boot device. */ static void mega_get_boot_drv(adapter_t *adapter) { … } /** * mega_support_random_del() * @adapter: pointer to our soft state * * Find out if this controller supports random deletion and addition of * logical drives */ static int mega_support_random_del(adapter_t *adapter) { … } /** * mega_support_ext_cdb() * @adapter: pointer to our soft state * * Find out if this firmware support cdblen > 10 */ static int mega_support_ext_cdb(adapter_t *adapter) { … } /** * mega_del_logdrv() * @adapter: pointer to our soft state * @logdrv: logical drive to be deleted * * Delete the specified logical drive. It is the responsibility of the user * app to let the OS know about this operation. */ static int mega_del_logdrv(adapter_t *adapter, int logdrv) { … } static int mega_do_del_logdrv(adapter_t *adapter, int logdrv) { … } /** * mega_get_max_sgl() * @adapter: pointer to our soft state * * Find out the maximum number of scatter-gather elements supported by this * version of the firmware */ static void mega_get_max_sgl(adapter_t *adapter) { … } /** * mega_support_cluster() * @adapter: pointer to our soft state * * Find out if this firmware support cluster calls. */ static int mega_support_cluster(adapter_t *adapter) { … } #ifdef CONFIG_PROC_FS /** * mega_adapinq() * @adapter: pointer to our soft state * @dma_handle: DMA address of the buffer * * Issue internal commands while interrupts are available. * We only issue direct mailbox commands from within the driver. ioctl() * interface using these routines can issue passthru commands. */ static int mega_adapinq(adapter_t *adapter, dma_addr_t dma_handle) { … } /** * mega_internal_dev_inquiry() * @adapter: pointer to our soft state * @ch: channel for this device * @tgt: ID of this device * @buf_dma_handle: DMA address of the buffer * * Issue the scsi inquiry for the specified device. */ static int mega_internal_dev_inquiry(adapter_t *adapter, u8 ch, u8 tgt, dma_addr_t buf_dma_handle) { … } #endif /** * mega_internal_command() * @adapter: pointer to our soft state * @mc: the mailbox command * @pthru: Passthru structure for DCDB commands * * Issue the internal commands in interrupt mode. * The last argument is the address of the passthru structure if the command * to be fired is a passthru command * * Note: parameter 'pthru' is null for non-passthru commands. */ static int mega_internal_command(adapter_t *adapter, megacmd_t *mc, mega_passthru *pthru) { … } static const struct scsi_host_template megaraid_template = …; static int megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) { … } static void __megaraid_shutdown(adapter_t *adapter) { … } static void megaraid_remove_one(struct pci_dev *pdev) { … } static void megaraid_shutdown(struct pci_dev *pdev) { … } static struct pci_device_id megaraid_pci_tbl[] = …; MODULE_DEVICE_TABLE(pci, megaraid_pci_tbl); static struct pci_driver megaraid_pci_driver = …; static int __init megaraid_init(void) { … } static void __exit megaraid_exit(void) { … } module_init(…) …; module_exit(megaraid_exit); /* vi: set ts=8 sw=8 tw=78: */