linux/drivers/scsi/megaraid.c

// 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: */