// SPDX-License-Identifier: GPL-2.0-or-later /* * pmcraid.c -- driver for PMC Sierra MaxRAID controller adapters * * Written By: Anil Ravindranath<[email protected]> * PMC-Sierra Inc * * Copyright (C) 2008, 2009 PMC Sierra Inc */ #include <linux/fs.h> #include <linux/init.h> #include <linux/types.h> #include <linux/errno.h> #include <linux/kernel.h> #include <linux/ioport.h> #include <linux/delay.h> #include <linux/pci.h> #include <linux/wait.h> #include <linux/spinlock.h> #include <linux/sched.h> #include <linux/interrupt.h> #include <linux/blkdev.h> #include <linux/firmware.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/hdreg.h> #include <linux/io.h> #include <linux/slab.h> #include <asm/irq.h> #include <asm/processor.h> #include <linux/libata.h> #include <linux/mutex.h> #include <linux/ktime.h> #include <scsi/scsi.h> #include <scsi/scsi_host.h> #include <scsi/scsi_device.h> #include <scsi/scsi_tcq.h> #include <scsi/scsi_eh.h> #include <scsi/scsi_cmnd.h> #include <scsi/scsicam.h> #include "pmcraid.h" /* * Module configuration parameters */ static unsigned int pmcraid_debug_log; static unsigned int pmcraid_disable_aen; static unsigned int pmcraid_log_level = …; static unsigned int pmcraid_enable_msix; /* * Data structures to support multiple adapters by the LLD. * pmcraid_adapter_count - count of configured adapters */ static atomic_t pmcraid_adapter_count = …; /* * Supporting user-level control interface through IOCTL commands. * pmcraid_major - major number to use * pmcraid_minor - minor number(s) to use */ static unsigned int pmcraid_major; static const struct class pmcraid_class = …; static DECLARE_BITMAP(pmcraid_minor, PMCRAID_MAX_ADAPTERS); /* * Module parameters */ MODULE_AUTHOR(…) …; MODULE_DESCRIPTION(…) …; MODULE_LICENSE(…) …; MODULE_VERSION(…); module_param_named(log_level, pmcraid_log_level, uint, (S_IRUGO | S_IWUSR)); MODULE_PARM_DESC(…) …; module_param_named(debug, pmcraid_debug_log, uint, (S_IRUGO | S_IWUSR)); MODULE_PARM_DESC(…) …; module_param_named(disable_aen, pmcraid_disable_aen, uint, (S_IRUGO | S_IWUSR)); MODULE_PARM_DESC(…) …; /* chip specific constants for PMC MaxRAID controllers (same for * 0x5220 and 0x8010 */ static struct pmcraid_chip_details pmcraid_chip_cfg[] = …; /* * PCI device ids supported by pmcraid driver */ static struct pci_device_id pmcraid_pci_table[] = …; MODULE_DEVICE_TABLE(pci, pmcraid_pci_table); /** * pmcraid_slave_alloc - Prepare for commands to a device * @scsi_dev: scsi device struct * * This function is called by mid-layer prior to sending any command to the new * device. Stores resource entry details of the device in scsi_device struct. * Queuecommand uses the resource handle and other details to fill up IOARCB * while sending commands to the device. * * Return value: * 0 on success / -ENXIO if device does not exist */ static int pmcraid_slave_alloc(struct scsi_device *scsi_dev) { … } /** * pmcraid_device_configure - Configures a SCSI device * @scsi_dev: scsi device struct * @lim: queue limits * * This function is executed by SCSI mid layer just after a device is first * scanned (i.e. it has responded to an INQUIRY). For VSET resources, the * timeout value (default 30s) will be over-written to a higher value (60s) * and max_sectors value will be over-written to 512. It also sets queue depth * to host->cmd_per_lun value * * Return value: * 0 on success */ static int pmcraid_device_configure(struct scsi_device *scsi_dev, struct queue_limits *lim) { … } /** * pmcraid_slave_destroy - Unconfigure a SCSI device before removing it * * @scsi_dev: scsi device struct * * This is called by mid-layer before removing a device. Pointer assignments * done in pmcraid_slave_alloc will be reset to NULL here. * * Return value * none */ static void pmcraid_slave_destroy(struct scsi_device *scsi_dev) { … } /** * pmcraid_change_queue_depth - Change the device's queue depth * @scsi_dev: scsi device struct * @depth: depth to set * * Return value * actual depth set */ static int pmcraid_change_queue_depth(struct scsi_device *scsi_dev, int depth) { … } /** * pmcraid_init_cmdblk - initializes a command block * * @cmd: pointer to struct pmcraid_cmd to be initialized * @index: if >=0 first time initialization; otherwise reinitialization * * Return Value * None */ static void pmcraid_init_cmdblk(struct pmcraid_cmd *cmd, int index) { … } /** * pmcraid_reinit_cmdblk - reinitialize a command block * * @cmd: pointer to struct pmcraid_cmd to be reinitialized * * Return Value * None */ static void pmcraid_reinit_cmdblk(struct pmcraid_cmd *cmd) { … } /** * pmcraid_get_free_cmd - get a free cmd block from command block pool * @pinstance: adapter instance structure * * Return Value: * returns pointer to cmd block or NULL if no blocks are available */ static struct pmcraid_cmd *pmcraid_get_free_cmd( struct pmcraid_instance *pinstance ) { … } /** * pmcraid_return_cmd - return a completed command block back into free pool * @cmd: pointer to the command block * * Return Value: * nothing */ static void pmcraid_return_cmd(struct pmcraid_cmd *cmd) { … } /** * pmcraid_read_interrupts - reads IOA interrupts * * @pinstance: pointer to adapter instance structure * * Return value * interrupts read from IOA */ static u32 pmcraid_read_interrupts(struct pmcraid_instance *pinstance) { … } /** * pmcraid_disable_interrupts - Masks and clears all specified interrupts * * @pinstance: pointer to per adapter instance structure * @intrs: interrupts to disable * * Return Value * None */ static void pmcraid_disable_interrupts( struct pmcraid_instance *pinstance, u32 intrs ) { … } /** * pmcraid_enable_interrupts - Enables specified interrupts * * @pinstance: pointer to per adapter instance structure * @intrs: interrupts to enable * * Return Value * None */ static void pmcraid_enable_interrupts( struct pmcraid_instance *pinstance, u32 intrs) { … } /** * pmcraid_clr_trans_op - clear trans to op interrupt * * @pinstance: pointer to per adapter instance structure * * Return Value * None */ static void pmcraid_clr_trans_op( struct pmcraid_instance *pinstance ) { … } /** * pmcraid_reset_type - Determine the required reset type * @pinstance: pointer to adapter instance structure * * IOA requires hard reset if any of the following conditions is true. * 1. If HRRQ valid interrupt is not masked * 2. IOA reset alert doorbell is set * 3. If there are any error interrupts */ static void pmcraid_reset_type(struct pmcraid_instance *pinstance) { … } static void pmcraid_ioa_reset(struct pmcraid_cmd *); /** * pmcraid_bist_done - completion function for PCI BIST * @t: pointer to reset command * Return Value * none */ static void pmcraid_bist_done(struct timer_list *t) { … } /** * pmcraid_start_bist - starts BIST * @cmd: pointer to reset cmd * Return Value * none */ static void pmcraid_start_bist(struct pmcraid_cmd *cmd) { … } /** * pmcraid_reset_alert_done - completion routine for reset_alert * @t: pointer to command block used in reset sequence * Return value * None */ static void pmcraid_reset_alert_done(struct timer_list *t) { … } static void pmcraid_notify_ioastate(struct pmcraid_instance *, u32); /** * pmcraid_reset_alert - alerts IOA for a possible reset * @cmd: command block to be used for reset sequence. * * Return Value * returns 0 if pci config-space is accessible and RESET_DOORBELL is * successfully written to IOA. Returns non-zero in case pci_config_space * is not accessible */ static void pmcraid_reset_alert(struct pmcraid_cmd *cmd) { … } /** * pmcraid_timeout_handler - Timeout handler for internally generated ops * * @t: pointer to command structure, that got timedout * * This function blocks host requests and initiates an adapter reset. * * Return value: * None */ static void pmcraid_timeout_handler(struct timer_list *t) { … } /** * pmcraid_internal_done - completion routine for internally generated cmds * * @cmd: command that got response from IOA * * Return Value: * none */ static void pmcraid_internal_done(struct pmcraid_cmd *cmd) { … } /** * pmcraid_reinit_cfgtable_done - done function for cfg table reinitialization * * @cmd: command that got response from IOA * * This routine is called after driver re-reads configuration table due to a * lost CCN. It returns the command block back to free pool and schedules * worker thread to add/delete devices into the system. * * Return Value: * none */ static void pmcraid_reinit_cfgtable_done(struct pmcraid_cmd *cmd) { … } /** * pmcraid_erp_done - Process completion of SCSI error response from device * @cmd: pmcraid_command * * This function copies the sense buffer into the scsi_cmd struct and completes * scsi_cmd by calling scsi_done function. * * Return value: * none */ static void pmcraid_erp_done(struct pmcraid_cmd *cmd) { … } /** * _pmcraid_fire_command - sends an IOA command to adapter * * This function adds the given block into pending command list * and returns without waiting * * @cmd : command to be sent to the device * * Return Value * None */ static void _pmcraid_fire_command(struct pmcraid_cmd *cmd) { … } /** * pmcraid_send_cmd - fires a command to IOA * * This function also sets up timeout function, and command completion * function * * @cmd: pointer to the command block to be fired to IOA * @cmd_done: command completion function, called once IOA responds * @timeout: timeout to wait for this command completion * @timeout_func: timeout handler * * Return value * none */ static void pmcraid_send_cmd( struct pmcraid_cmd *cmd, void (*cmd_done) (struct pmcraid_cmd *), unsigned long timeout, void (*timeout_func) (struct timer_list *) ) { … } /** * pmcraid_ioa_shutdown_done - completion function for IOA shutdown command * @cmd: pointer to the command block used for sending IOA shutdown command * * Return value * None */ static void pmcraid_ioa_shutdown_done(struct pmcraid_cmd *cmd) { … } /** * pmcraid_ioa_shutdown - sends SHUTDOWN command to ioa * * @cmd: pointer to the command block used as part of reset sequence * * Return Value * None */ static void pmcraid_ioa_shutdown(struct pmcraid_cmd *cmd) { … } static void pmcraid_querycfg(struct pmcraid_cmd *); /** * pmcraid_get_fwversion_done - completion function for get_fwversion * * @cmd: pointer to command block used to send INQUIRY command * * Return Value * none */ static void pmcraid_get_fwversion_done(struct pmcraid_cmd *cmd) { … } /** * pmcraid_get_fwversion - reads firmware version information * * @cmd: pointer to command block used to send INQUIRY command * * Return Value * none */ static void pmcraid_get_fwversion(struct pmcraid_cmd *cmd) { … } /** * pmcraid_identify_hrrq - registers host rrq buffers with IOA * @cmd: pointer to command block to be used for identify hrrq * * Return Value * none */ static void pmcraid_identify_hrrq(struct pmcraid_cmd *cmd) { … } static void pmcraid_process_ccn(struct pmcraid_cmd *cmd); static void pmcraid_process_ldn(struct pmcraid_cmd *cmd); /** * pmcraid_send_hcam_cmd - send an initialized command block(HCAM) to IOA * * @cmd: initialized command block pointer * * Return Value * none */ static void pmcraid_send_hcam_cmd(struct pmcraid_cmd *cmd) { … } /** * pmcraid_init_hcam - send an initialized command block(HCAM) to IOA * * @pinstance: pointer to adapter instance structure * @type: HCAM type * * Return Value * pointer to initialized pmcraid_cmd structure or NULL */ static struct pmcraid_cmd *pmcraid_init_hcam ( struct pmcraid_instance *pinstance, u8 type ) { … } /** * pmcraid_send_hcam - Send an HCAM to IOA * @pinstance: ioa config struct * @type: HCAM type * * This function will send a Host Controlled Async command to IOA. * * Return value: * none */ static void pmcraid_send_hcam(struct pmcraid_instance *pinstance, u8 type) { … } /** * pmcraid_prepare_cancel_cmd - prepares a command block to abort another * * @cmd: pointer to cmd that is used as cancelling command * @cmd_to_cancel: pointer to the command that needs to be cancelled */ static void pmcraid_prepare_cancel_cmd( struct pmcraid_cmd *cmd, struct pmcraid_cmd *cmd_to_cancel ) { … } /** * pmcraid_cancel_hcam - sends ABORT task to abort a given HCAM * * @cmd: command to be used as cancelling command * @type: HCAM type * @cmd_done: op done function for the cancelling command */ static void pmcraid_cancel_hcam( struct pmcraid_cmd *cmd, u8 type, void (*cmd_done) (struct pmcraid_cmd *) ) { … } /** * pmcraid_cancel_ccn - cancel CCN HCAM already registered with IOA * * @cmd: command block to be used for cancelling the HCAM */ static void pmcraid_cancel_ccn(struct pmcraid_cmd *cmd) { … } /** * pmcraid_cancel_ldn - cancel LDN HCAM already registered with IOA * * @cmd: command block to be used for cancelling the HCAM */ static void pmcraid_cancel_ldn(struct pmcraid_cmd *cmd) { … } /** * pmcraid_expose_resource - check if the resource can be exposed to OS * * @fw_version: firmware version code * @cfgte: pointer to configuration table entry of the resource * * Return value: * true if resource can be added to midlayer, false(0) otherwise */ static int pmcraid_expose_resource(u16 fw_version, struct pmcraid_config_table_entry *cfgte) { … } /* attributes supported by pmcraid_event_family */ enum { … }; #define PMCRAID_AEN_ATTR_MAX … /* commands supported by pmcraid_event_family */ enum { … }; #define PMCRAID_AEN_CMD_MAX … static struct genl_multicast_group pmcraid_mcgrps[] = …; static struct genl_family pmcraid_event_family __ro_after_init = …; /** * pmcraid_netlink_init - registers pmcraid_event_family * * Return value: * 0 if the pmcraid_event_family is successfully registered * with netlink generic, non-zero otherwise */ static int __init pmcraid_netlink_init(void) { … } /** * pmcraid_netlink_release - unregisters pmcraid_event_family * * Return value: * none */ static void pmcraid_netlink_release(void) { … } /* * pmcraid_notify_aen - sends event msg to user space application * @pinstance: pointer to adapter instance structure * * Return value: * 0 if success, error value in case of any failure. */ static int pmcraid_notify_aen( struct pmcraid_instance *pinstance, struct pmcraid_aen_msg *aen_msg, u32 data_size) { … } /** * pmcraid_notify_ccn - notifies about CCN event msg to user space * @pinstance: pointer adapter instance structure * * Return value: * 0 if success, error value in case of any failure */ static int pmcraid_notify_ccn(struct pmcraid_instance *pinstance) { … } /** * pmcraid_notify_ldn - notifies about CCN event msg to user space * @pinstance: pointer adapter instance structure * * Return value: * 0 if success, error value in case of any failure */ static int pmcraid_notify_ldn(struct pmcraid_instance *pinstance) { … } /** * pmcraid_notify_ioastate - sends IOA state event msg to user space * @pinstance: pointer adapter instance structure * @evt: controller state event to be sent * * Return value: * 0 if success, error value in case of any failure */ static void pmcraid_notify_ioastate(struct pmcraid_instance *pinstance, u32 evt) { … } /** * pmcraid_handle_config_change - Handle a config change from the adapter * @pinstance: pointer to per adapter instance structure * * Return value: * none */ static void pmcraid_handle_config_change(struct pmcraid_instance *pinstance) { … } /** * pmcraid_get_error_info - return error string for an ioasc * @ioasc: ioasc code * Return Value * none */ static struct pmcraid_ioasc_error *pmcraid_get_error_info(u32 ioasc) { … } /** * pmcraid_ioasc_logger - log IOASC information based user-settings * @ioasc: ioasc code * @cmd: pointer to command that resulted in 'ioasc' */ static void pmcraid_ioasc_logger(u32 ioasc, struct pmcraid_cmd *cmd) { … } /** * pmcraid_handle_error_log - Handle a config change (error log) from the IOA * * @pinstance: pointer to per adapter instance structure * * Return value: * none */ static void pmcraid_handle_error_log(struct pmcraid_instance *pinstance) { … } /** * pmcraid_process_ccn - Op done function for a CCN. * @cmd: pointer to command struct * * This function is the op done function for a configuration * change notification * * Return value: * none */ static void pmcraid_process_ccn(struct pmcraid_cmd *cmd) { … } static void pmcraid_initiate_reset(struct pmcraid_instance *); static void pmcraid_set_timestamp(struct pmcraid_cmd *cmd); /** * pmcraid_process_ldn - op done function for an LDN * @cmd: pointer to command block * * Return value * none */ static void pmcraid_process_ldn(struct pmcraid_cmd *cmd) { … } /** * pmcraid_register_hcams - register HCAMs for CCN and LDN * * @pinstance: pointer per adapter instance structure * * Return Value * none */ static void pmcraid_register_hcams(struct pmcraid_instance *pinstance) { … } /** * pmcraid_unregister_hcams - cancel HCAMs registered already * @cmd: pointer to command used as part of reset sequence */ static void pmcraid_unregister_hcams(struct pmcraid_cmd *cmd) { … } static void pmcraid_reinit_buffers(struct pmcraid_instance *); /** * pmcraid_reset_enable_ioa - re-enable IOA after a hard reset * @pinstance: pointer to adapter instance structure * Return Value * 1 if TRANSITION_TO_OPERATIONAL is active, otherwise 0 */ static int pmcraid_reset_enable_ioa(struct pmcraid_instance *pinstance) { … } /** * pmcraid_soft_reset - performs a soft reset and makes IOA become ready * @cmd : pointer to reset command block * * Return Value * none */ static void pmcraid_soft_reset(struct pmcraid_cmd *cmd) { … } /** * pmcraid_get_dump - retrieves IOA dump in case of Unit Check interrupt * * @pinstance: pointer to adapter instance structure * * Return Value * none */ static void pmcraid_get_dump(struct pmcraid_instance *pinstance) { … } /** * pmcraid_fail_outstanding_cmds - Fails all outstanding ops. * @pinstance: pointer to adapter instance structure * * This function fails all outstanding ops. If they are submitted to IOA * already, it sends cancel all messages if IOA is still accepting IOARCBs, * otherwise just completes the commands and returns the cmd blocks to free * pool. * * Return value: * none */ static void pmcraid_fail_outstanding_cmds(struct pmcraid_instance *pinstance) { … } /** * pmcraid_ioa_reset - Implementation of IOA reset logic * * @cmd: pointer to the cmd block to be used for entire reset process * * This function executes most of the steps required for IOA reset. This gets * called by user threads (modprobe/insmod/rmmod) timer, tasklet and midlayer's * 'eh_' thread. Access to variables used for controlling the reset sequence is * synchronized using host lock. Various functions called during reset process * would make use of a single command block, pointer to which is also stored in * adapter instance structure. * * Return Value * None */ static void pmcraid_ioa_reset(struct pmcraid_cmd *cmd) { … } /** * pmcraid_initiate_reset - initiates reset sequence. This is called from * ISR/tasklet during error interrupts including IOA unit check. If reset * is already in progress, it just returns, otherwise initiates IOA reset * to bring IOA up to operational state. * * @pinstance: pointer to adapter instance structure * * Return value * none */ static void pmcraid_initiate_reset(struct pmcraid_instance *pinstance) { … } /** * pmcraid_reset_reload - utility routine for doing IOA reset either to bringup * or bringdown IOA * @pinstance: pointer adapter instance structure * @shutdown_type: shutdown type to be used NONE, NORMAL or ABRREV * @target_state: expected target state after reset * * Note: This command initiates reset and waits for its completion. Hence this * should not be called from isr/timer/tasklet functions (timeout handlers, * error response handlers and interrupt handlers). * * Return Value * 1 in case ioa_state is not target_state, 0 otherwise. */ static int pmcraid_reset_reload( struct pmcraid_instance *pinstance, u8 shutdown_type, u8 target_state ) { … } /** * pmcraid_reset_bringdown - wrapper over pmcraid_reset_reload to bringdown IOA * * @pinstance: pointer to adapter instance structure * * Return Value * whatever is returned from pmcraid_reset_reload */ static int pmcraid_reset_bringdown(struct pmcraid_instance *pinstance) { … } /** * pmcraid_reset_bringup - wrapper over pmcraid_reset_reload to bring up IOA * * @pinstance: pointer to adapter instance structure * * Return Value * whatever is returned from pmcraid_reset_reload */ static int pmcraid_reset_bringup(struct pmcraid_instance *pinstance) { … } /** * pmcraid_request_sense - Send request sense to a device * @cmd: pmcraid command struct * * This function sends a request sense to a device as a result of a check * condition. This method re-uses the same command block that failed earlier. */ static void pmcraid_request_sense(struct pmcraid_cmd *cmd) { … } /** * pmcraid_cancel_all - cancel all outstanding IOARCBs as part of error recovery * @cmd: command that failed * @need_sense: true if request_sense is required after cancel all * * This function sends a cancel all to a device to clear the queue. */ static void pmcraid_cancel_all(struct pmcraid_cmd *cmd, bool need_sense) { … } /** * pmcraid_frame_auto_sense: frame fixed format sense information * * @cmd: pointer to failing command block * * Return value * none */ static void pmcraid_frame_auto_sense(struct pmcraid_cmd *cmd) { … } /** * pmcraid_error_handler - Error response handlers for a SCSI op * @cmd: pointer to pmcraid_cmd that has failed * * This function determines whether or not to initiate ERP on the affected * device. This is called from a tasklet, which doesn't hold any locks. * * Return value: * 0 it caller can complete the request, otherwise 1 where in error * handler itself completes the request and returns the command block * back to free-pool */ static int pmcraid_error_handler(struct pmcraid_cmd *cmd) { … } /** * pmcraid_reset_device - device reset handler functions * * @scsi_dev: scsi device struct * @timeout: command timeout * @modifier: reset modifier indicating the reset sequence to be performed * * This function issues a device reset to the affected device. * A LUN reset will be sent to the device first. If that does * not work, a target reset will be sent. * * Return value: * SUCCESS / FAILED */ static int pmcraid_reset_device( struct scsi_device *scsi_dev, unsigned long timeout, u8 modifier) { … } /** * _pmcraid_io_done - helper for pmcraid_io_done function * * @cmd: pointer to pmcraid command struct * @reslen: residual data length to be set in the ioasa * @ioasc: ioasc either returned by IOA or set by driver itself. * * This function is invoked by pmcraid_io_done to complete mid-layer * scsi ops. * * Return value: * 0 if caller is required to return it to free_pool. Returns 1 if * caller need not worry about freeing command block as error handler * will take care of that. */ static int _pmcraid_io_done(struct pmcraid_cmd *cmd, int reslen, int ioasc) { … } /** * pmcraid_io_done - SCSI completion function * * @cmd: pointer to pmcraid command struct * * This function is invoked by tasklet/mid-layer error handler to completing * the SCSI ops sent from mid-layer. * * Return value * none */ static void pmcraid_io_done(struct pmcraid_cmd *cmd) { … } /** * pmcraid_abort_cmd - Aborts a single IOARCB already submitted to IOA * * @cmd: command block of the command to be aborted * * Return Value: * returns pointer to command structure used as cancelling cmd */ static struct pmcraid_cmd *pmcraid_abort_cmd(struct pmcraid_cmd *cmd) { … } /** * pmcraid_abort_complete - Waits for ABORT TASK completion * * @cancel_cmd: command block use as cancelling command * * Return Value: * returns SUCCESS if ABORT TASK has good completion * otherwise FAILED */ static int pmcraid_abort_complete(struct pmcraid_cmd *cancel_cmd) { … } /** * pmcraid_eh_abort_handler - entry point for aborting a single task on errors * * @scsi_cmd: scsi command struct given by mid-layer. When this is called * mid-layer ensures that no other commands are queued. This * never gets called under interrupt, but a separate eh thread. * * Return value: * SUCCESS / FAILED */ static int pmcraid_eh_abort_handler(struct scsi_cmnd *scsi_cmd) { … } /** * pmcraid_eh_device_reset_handler - bus/target/device reset handler callbacks * * @scmd: pointer to scsi_cmd that was sent to the resource to be reset. * * All these routines invokve pmcraid_reset_device with appropriate parameters. * Since these are called from mid-layer EH thread, no other IO will be queued * to the resource being reset. However, control path (IOCTL) may be active so * it is necessary to synchronize IOARRIN writes which pmcraid_reset_device * takes care by locking/unlocking host_lock. * * Return value * SUCCESS or FAILED */ static int pmcraid_eh_device_reset_handler(struct scsi_cmnd *scmd) { … } static int pmcraid_eh_bus_reset_handler(struct scsi_cmnd *scmd) { … } static int pmcraid_eh_target_reset_handler(struct scsi_cmnd *scmd) { … } /** * pmcraid_eh_host_reset_handler - adapter reset handler callback * * @scmd: pointer to scsi_cmd that was sent to a resource of adapter * * Initiates adapter reset to bring it up to operational state * * Return value * SUCCESS or FAILED */ static int pmcraid_eh_host_reset_handler(struct scsi_cmnd *scmd) { … } /** * pmcraid_init_ioadls - initializes IOADL related fields in IOARCB * @cmd: pmcraid command struct * @sgcount: count of scatter-gather elements * * Return value * returns pointer pmcraid_ioadl_desc, initialized to point to internal * or external IOADLs */ static struct pmcraid_ioadl_desc * pmcraid_init_ioadls(struct pmcraid_cmd *cmd, int sgcount) { … } /** * pmcraid_build_ioadl - Build a scatter/gather list and map the buffer * @pinstance: pointer to adapter instance structure * @cmd: pmcraid command struct * * This function is invoked by queuecommand entry point while sending a command * to firmware. This builds ioadl descriptors and sets up ioarcb fields. * * Return value: * 0 on success or -1 on failure */ static int pmcraid_build_ioadl( struct pmcraid_instance *pinstance, struct pmcraid_cmd *cmd ) { … } /** * pmcraid_queuecommand_lck - Queue a mid-layer request * @scsi_cmd: scsi command struct * * This function queues a request generated by the mid-layer. Midlayer calls * this routine within host->lock. Some of the functions called by queuecommand * would use cmd block queue locks (free_pool_lock and pending_pool_lock) * * Return value: * 0 on success * SCSI_MLQUEUE_DEVICE_BUSY if device is busy * SCSI_MLQUEUE_HOST_BUSY if host is busy */ static int pmcraid_queuecommand_lck(struct scsi_cmnd *scsi_cmd) { … } static DEF_SCSI_QCMD(pmcraid_queuecommand) /* * pmcraid_open -char node "open" entry, allowed only users with admin access */ static int pmcraid_chr_open(struct inode *inode, struct file *filep) { … } /* * pmcraid_fasync - Async notifier registration from applications * * This function adds the calling process to a driver global queue. When an * event occurs, SIGIO will be sent to all processes in this queue. */ static int pmcraid_chr_fasync(int fd, struct file *filep, int mode) { … } /** * pmcraid_ioctl_driver - ioctl handler for commands handled by driver itself * * @pinstance: pointer to adapter instance structure * @cmd: ioctl command passed in * @buflen: length of user_buffer * @user_buffer: user buffer pointer * * Return Value * 0 in case of success, otherwise appropriate error code */ static long pmcraid_ioctl_driver( struct pmcraid_instance *pinstance, unsigned int cmd, unsigned int buflen, void __user *user_buffer ) { … } /** * pmcraid_check_ioctl_buffer - check for proper access to user buffer * * @cmd: ioctl command * @arg: user buffer * @hdr: pointer to kernel memory for pmcraid_ioctl_header * * Return Value * negetive error code if there are access issues, otherwise zero. * Upon success, returns ioctl header copied out of user buffer. */ static int pmcraid_check_ioctl_buffer( int cmd, void __user *arg, struct pmcraid_ioctl_header *hdr ) { … } /* * pmcraid_ioctl - char node ioctl entry point */ static long pmcraid_chr_ioctl( struct file *filep, unsigned int cmd, unsigned long arg ) { … } /* * File operations structure for management interface */ static const struct file_operations pmcraid_fops = …; /** * pmcraid_show_log_level - Display adapter's error logging level * @dev: class device struct * @attr: unused * @buf: buffer * * Return value: * number of bytes printed to buffer */ static ssize_t pmcraid_show_log_level( struct device *dev, struct device_attribute *attr, char *buf) { … } /** * pmcraid_store_log_level - Change the adapter's error logging level * @dev: class device struct * @attr: unused * @buf: buffer * @count: not used * * Return value: * number of bytes printed to buffer */ static ssize_t pmcraid_store_log_level( struct device *dev, struct device_attribute *attr, const char *buf, size_t count ) { … } static struct device_attribute pmcraid_log_level_attr = …; /** * pmcraid_show_drv_version - Display driver version * @dev: class device struct * @attr: unused * @buf: buffer * * Return value: * number of bytes printed to buffer */ static ssize_t pmcraid_show_drv_version( struct device *dev, struct device_attribute *attr, char *buf ) { … } static struct device_attribute pmcraid_driver_version_attr = …; /** * pmcraid_show_adapter_id - Display driver assigned adapter id * @dev: class device struct * @attr: unused * @buf: buffer * * Return value: * number of bytes printed to buffer */ static ssize_t pmcraid_show_adapter_id( struct device *dev, struct device_attribute *attr, char *buf ) { … } static struct device_attribute pmcraid_adapter_id_attr = …; static struct attribute *pmcraid_host_attrs[] = …; ATTRIBUTE_GROUPS(…); /* host template structure for pmcraid driver */ static const struct scsi_host_template pmcraid_host_template = …; /* * pmcraid_isr_msix - implements MSI-X interrupt handling routine * @irq: interrupt vector number * @dev_id: pointer hrrq_vector * * Return Value * IRQ_HANDLED if interrupt is handled or IRQ_NONE if ignored */ static irqreturn_t pmcraid_isr_msix(int irq, void *dev_id) { … } /** * pmcraid_isr - implements legacy interrupt handling routine * * @irq: interrupt vector number * @dev_id: pointer hrrq_vector * * Return Value * IRQ_HANDLED if interrupt is handled or IRQ_NONE if ignored */ static irqreturn_t pmcraid_isr(int irq, void *dev_id) { … } /** * pmcraid_worker_function - worker thread function * * @workp: pointer to struct work queue * * Return Value * None */ static void pmcraid_worker_function(struct work_struct *workp) { … } /** * pmcraid_tasklet_function - Tasklet function * * @instance: pointer to msix param structure * * Return Value * None */ static void pmcraid_tasklet_function(unsigned long instance) { … } /** * pmcraid_unregister_interrupt_handler - de-register interrupts handlers * @pinstance: pointer to adapter instance structure * * This routine un-registers registered interrupt handler and * also frees irqs/vectors. * * Retun Value * None */ static void pmcraid_unregister_interrupt_handler(struct pmcraid_instance *pinstance) { … } /** * pmcraid_register_interrupt_handler - registers interrupt handler * @pinstance: pointer to per-adapter instance structure * * Return Value * 0 on success, non-zero error code otherwise. */ static int pmcraid_register_interrupt_handler(struct pmcraid_instance *pinstance) { … } /** * pmcraid_release_cmd_blocks - release buufers allocated for command blocks * @pinstance: per adapter instance structure pointer * @max_index: number of buffer blocks to release * * Return Value * None */ static void pmcraid_release_cmd_blocks(struct pmcraid_instance *pinstance, int max_index) { … } /** * pmcraid_release_control_blocks - releases buffers alloced for control blocks * @pinstance: pointer to per adapter instance structure * @max_index: number of buffers (from 0 onwards) to release * * This function assumes that the command blocks for which control blocks are * linked are not released. * * Return Value * None */ static void pmcraid_release_control_blocks( struct pmcraid_instance *pinstance, int max_index ) { … } /** * pmcraid_allocate_cmd_blocks - allocate memory for cmd block structures * @pinstance: pointer to per adapter instance structure * * Allocates memory for command blocks using kernel slab allocator. * * Return Value * 0 in case of success; -ENOMEM in case of failure */ static int pmcraid_allocate_cmd_blocks(struct pmcraid_instance *pinstance) { … } /** * pmcraid_allocate_control_blocks - allocates memory control blocks * @pinstance : pointer to per adapter instance structure * * This function allocates PCI memory for DMAable buffers like IOARCB, IOADLs * and IOASAs. This is called after command blocks are already allocated. * * Return Value * 0 in case it can allocate all control blocks, otherwise -ENOMEM */ static int pmcraid_allocate_control_blocks(struct pmcraid_instance *pinstance) { … } /** * pmcraid_release_host_rrqs - release memory allocated for hrrq buffer(s) * @pinstance: pointer to per adapter instance structure * @maxindex: size of hrrq buffer pointer array * * Return Value * None */ static void pmcraid_release_host_rrqs(struct pmcraid_instance *pinstance, int maxindex) { … } /** * pmcraid_allocate_host_rrqs - Allocate and initialize host RRQ buffers * @pinstance: pointer to per adapter instance structure * * Return value * 0 hrrq buffers are allocated, -ENOMEM otherwise. */ static int pmcraid_allocate_host_rrqs(struct pmcraid_instance *pinstance) { … } /** * pmcraid_release_hcams - release HCAM buffers * * @pinstance: pointer to per adapter instance structure * * Return value * none */ static void pmcraid_release_hcams(struct pmcraid_instance *pinstance) { … } /** * pmcraid_allocate_hcams - allocates HCAM buffers * @pinstance : pointer to per adapter instance structure * * Return Value: * 0 in case of successful allocation, non-zero otherwise */ static int pmcraid_allocate_hcams(struct pmcraid_instance *pinstance) { … } /** * pmcraid_release_config_buffers - release config.table buffers * @pinstance: pointer to per adapter instance structure * * Return Value * none */ static void pmcraid_release_config_buffers(struct pmcraid_instance *pinstance) { … } /** * pmcraid_allocate_config_buffers - allocates DMAable memory for config table * @pinstance : pointer to per adapter instance structure * * Return Value * 0 for successful allocation, -ENOMEM for any failure */ static int pmcraid_allocate_config_buffers(struct pmcraid_instance *pinstance) { … } /** * pmcraid_init_tasklets - registers tasklets for response handling * * @pinstance: pointer adapter instance structure * * Return value * none */ static void pmcraid_init_tasklets(struct pmcraid_instance *pinstance) { … } /** * pmcraid_kill_tasklets - destroys tasklets registered for response handling * * @pinstance: pointer to adapter instance structure * * Return value * none */ static void pmcraid_kill_tasklets(struct pmcraid_instance *pinstance) { … } /** * pmcraid_release_buffers - release per-adapter buffers allocated * * @pinstance: pointer to adapter soft state * * Return Value * none */ static void pmcraid_release_buffers(struct pmcraid_instance *pinstance) { … } /** * pmcraid_init_buffers - allocates memory and initializes various structures * @pinstance: pointer to per adapter instance structure * * This routine pre-allocates memory based on the type of block as below: * cmdblocks(PMCRAID_MAX_CMD): kernel memory using kernel's slab_allocator, * IOARCBs(PMCRAID_MAX_CMD) : DMAable memory, using pci pool allocator * config-table entries : DMAable memory using dma_alloc_coherent * HostRRQs : DMAable memory, using dma_alloc_coherent * * Return Value * 0 in case all of the blocks are allocated, -ENOMEM otherwise. */ static int pmcraid_init_buffers(struct pmcraid_instance *pinstance) { … } /** * pmcraid_reinit_buffers - resets various buffer pointers * @pinstance: pointer to adapter instance * Return value * none */ static void pmcraid_reinit_buffers(struct pmcraid_instance *pinstance) { … } /** * pmcraid_init_instance - initialize per instance data structure * @pdev: pointer to pci device structure * @host: pointer to Scsi_Host structure * @mapped_pci_addr: memory mapped IOA configuration registers * * Return Value * 0 on success, non-zero in case of any failure */ static int pmcraid_init_instance(struct pci_dev *pdev, struct Scsi_Host *host, void __iomem *mapped_pci_addr) { … } /** * pmcraid_shutdown - shutdown adapter controller. * @pdev: pci device struct * * Issues an adapter shutdown to the card waits for its completion * * Return value * none */ static void pmcraid_shutdown(struct pci_dev *pdev) { … } /* * pmcraid_get_minor - returns unused minor number from minor number bitmap */ static unsigned short pmcraid_get_minor(void) { … } /* * pmcraid_release_minor - releases given minor back to minor number bitmap */ static void pmcraid_release_minor(unsigned short minor) { … } /** * pmcraid_setup_chrdev - allocates a minor number and registers a char device * * @pinstance: pointer to adapter instance for which to register device * * Return value * 0 in case of success, otherwise non-zero */ static int pmcraid_setup_chrdev(struct pmcraid_instance *pinstance) { … } /** * pmcraid_release_chrdev - unregisters per-adapter management interface * * @pinstance: pointer to adapter instance structure * * Return value * none */ static void pmcraid_release_chrdev(struct pmcraid_instance *pinstance) { … } /** * pmcraid_remove - IOA hot plug remove entry point * @pdev: pci device struct * * Return value * none */ static void pmcraid_remove(struct pci_dev *pdev) { … } /** * pmcraid_suspend - driver suspend entry point for power management * @dev: Device structure * * Return Value - 0 always */ static int __maybe_unused pmcraid_suspend(struct device *dev) { … } /** * pmcraid_resume - driver resume entry point PCI power management * @dev: Device structure * * Return Value - 0 in case of success. Error code in case of any failure */ static int __maybe_unused pmcraid_resume(struct device *dev) { … } /** * pmcraid_complete_ioa_reset - Called by either timer or tasklet during * completion of the ioa reset * @cmd: pointer to reset command block */ static void pmcraid_complete_ioa_reset(struct pmcraid_cmd *cmd) { … } /** * pmcraid_set_supported_devs - sends SET SUPPORTED DEVICES to IOAFP * * @cmd: pointer to pmcraid_cmd structure * * Return Value * 0 for success or non-zero for failure cases */ static void pmcraid_set_supported_devs(struct pmcraid_cmd *cmd) { … } /** * pmcraid_set_timestamp - set the timestamp to IOAFP * * @cmd: pointer to pmcraid_cmd structure * * Return Value * 0 for success or non-zero for failure cases */ static void pmcraid_set_timestamp(struct pmcraid_cmd *cmd) { … } /** * pmcraid_init_res_table - Initialize the resource table * @cmd: pointer to pmcraid command struct * * This function looks through the existing resource table, comparing * it with the config table. This function will take care of old/new * devices and schedule adding/removing them from the mid-layer * as appropriate. * * Return value * None */ static void pmcraid_init_res_table(struct pmcraid_cmd *cmd) { … } /** * pmcraid_querycfg - Send a Query IOA Config to the adapter. * @cmd: pointer pmcraid_cmd struct * * This function sends a Query IOA Configuration command to the adapter to * retrieve the IOA configuration table. * * Return value: * none */ static void pmcraid_querycfg(struct pmcraid_cmd *cmd) { … } /** * pmcraid_probe - PCI probe entry pointer for PMC MaxRAID controller driver * @pdev: pointer to pci device structure * @dev_id: pointer to device ids structure * * Return Value * returns 0 if the device is claimed and successfully configured. * returns non-zero error code in case of any failure */ static int pmcraid_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) { … } static SIMPLE_DEV_PM_OPS(pmcraid_pm_ops, pmcraid_suspend, pmcraid_resume); /* * PCI driver structure of pmcraid driver */ static struct pci_driver pmcraid_driver = …; /** * pmcraid_init - module load entry point */ static int __init pmcraid_init(void) { … } /** * pmcraid_exit - module unload entry point */ static void __exit pmcraid_exit(void) { … } module_init(…) …; module_exit(pmcraid_exit);