linux/drivers/scsi/sg.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 *  History:
 *  Started: Aug 9 by Lawrence Foard ([email protected]),
 *           to allow user process control of SCSI devices.
 *  Development Sponsored by Killy Corp. NY NY
 *
 * Original driver (sg.c):
 *        Copyright (C) 1992 Lawrence Foard
 * Version 2 and 3 extensions to driver:
 *        Copyright (C) 1998 - 2014 Douglas Gilbert
 */

static int sg_version_num =;	/* 2 digits for each component */
#define SG_VERSION_STR

/*
 *  D. P. Gilbert ([email protected]), notes:
 *      - scsi logging is available via SCSI_LOG_TIMEOUT macros. First
 *        the kernel/module needs to be built with CONFIG_SCSI_LOGGING
 *        (otherwise the macros compile to empty statements).
 *
 */
#include <linux/module.h>

#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/mtio.h>
#include <linux/ioctl.h>
#include <linux/major.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/moduleparam.h>
#include <linux/cdev.h>
#include <linux/idr.h>
#include <linux/seq_file.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/blktrace_api.h>
#include <linux/mutex.h>
#include <linux/atomic.h>
#include <linux/ratelimit.h>
#include <linux/uio.h>
#include <linux/cred.h> /* for sg_check_file_access() */

#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_dbg.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_driver.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_ioctl.h>
#include <scsi/scsi_tcq.h>
#include <scsi/sg.h>

#include "scsi_logging.h"

#ifdef CONFIG_SCSI_PROC_FS
#include <linux/proc_fs.h>
static char *sg_version_date =;

static int sg_proc_init(void);
#endif

#define SG_ALLOW_DIO_DEF

#define SG_MAX_DEVS

/* SG_MAX_CDB_SIZE should be 260 (spc4r37 section 3.1.30) however the type
 * of sg_io_hdr::cmd_len can only represent 255. All SCSI commands greater
 * than 16 bytes are "variable length" whose length is a multiple of 4
 */
#define SG_MAX_CDB_SIZE

#define SG_DEFAULT_TIMEOUT

static int sg_big_buff =;
/* N.B. This variable is readable and writeable via
   /proc/scsi/sg/def_reserved_size . Each time sg_open() is called a buffer
   of this size (or less if there is not enough memory) will be reserved
   for use by this file descriptor. [Deprecated usage: this variable is also
   readable via /proc/sys/kernel/sg-big-buff if the sg driver is built into
   the kernel (i.e. it is not a module).] */
static int def_reserved_size =;	/* picks up init parameter */
static int sg_allow_dio =;

static int scatter_elem_sz =;
static int scatter_elem_sz_prev =;

#define SG_SECTOR_SZ

static int sg_add_device(struct device *);
static void sg_remove_device(struct device *);

static DEFINE_IDR(sg_index_idr);
static DEFINE_RWLOCK(sg_index_lock);	/* Also used to lock
							   file descriptor list for device */

static struct class_interface sg_interface =;

Sg_scatter_hold;

struct sg_device;		/* forward declarations */
struct sg_fd;

Sg_request;

Sg_fd;

Sg_device;

/* tasklet or soft irq callback */
static enum rq_end_io_ret sg_rq_end_io(struct request *rq, blk_status_t status);
static int sg_start_req(Sg_request *srp, unsigned char *cmd);
static int sg_finish_rem_req(Sg_request * srp);
static int sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size);
static ssize_t sg_new_read(Sg_fd * sfp, char __user *buf, size_t count,
			   Sg_request * srp);
static ssize_t sg_new_write(Sg_fd *sfp, struct file *file,
			const char __user *buf, size_t count, int blocking,
			int read_only, int sg_io_owned, Sg_request **o_srp);
static int sg_common_write(Sg_fd * sfp, Sg_request * srp,
			   unsigned char *cmnd, int timeout, int blocking);
static int sg_read_oxfer(Sg_request * srp, char __user *outp, int num_read_xfer);
static void sg_remove_scat(Sg_fd * sfp, Sg_scatter_hold * schp);
static void sg_build_reserve(Sg_fd * sfp, int req_size);
static void sg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size);
static void sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp);
static Sg_fd *sg_add_sfp(Sg_device * sdp);
static void sg_remove_sfp(struct kref *);
static Sg_request *sg_get_rq_mark(Sg_fd * sfp, int pack_id, bool *busy);
static Sg_request *sg_add_request(Sg_fd * sfp);
static int sg_remove_request(Sg_fd * sfp, Sg_request * srp);
static Sg_device *sg_get_dev(int dev);
static void sg_device_destroy(struct kref *kref);

#define SZ_SG_HEADER
#define SZ_SG_IO_HDR
#define SZ_SG_IOVEC
#define SZ_SG_REQ_INFO

#define sg_printk(prefix, sdp, fmt, a...)

/*
 * The SCSI interfaces that use read() and write() as an asynchronous variant of
 * ioctl(..., SG_IO, ...) are fundamentally unsafe, since there are lots of ways
 * to trigger read() and write() calls from various contexts with elevated
 * privileges. This can lead to kernel memory corruption (e.g. if these
 * interfaces are called through splice()) and privilege escalation inside
 * userspace (e.g. if a process with access to such a device passes a file
 * descriptor to a SUID binary as stdin/stdout/stderr).
 *
 * This function provides protection for the legacy API by restricting the
 * calling context.
 */
static int sg_check_file_access(struct file *filp, const char *caller)
{}

static int sg_allow_access(struct file *filp, unsigned char *cmd)
{}

static int
open_wait(Sg_device *sdp, int flags)
{}

/* Returns 0 on success, else a negated errno value */
static int
sg_open(struct inode *inode, struct file *filp)
{}

/* Release resources associated with a successful sg_open()
 * Returns 0 on success, else a negated errno value */
static int
sg_release(struct inode *inode, struct file *filp)
{}

static int get_sg_io_pack_id(int *pack_id, void __user *buf, size_t count)
{}

static ssize_t
sg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
{}

static ssize_t
sg_new_read(Sg_fd * sfp, char __user *buf, size_t count, Sg_request * srp)
{}

static ssize_t
sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
{}

static ssize_t
sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf,
		 size_t count, int blocking, int read_only, int sg_io_owned,
		 Sg_request **o_srp)
{}

static int
sg_common_write(Sg_fd * sfp, Sg_request * srp,
		unsigned char *cmnd, int timeout, int blocking)
{}

static int srp_done(Sg_fd *sfp, Sg_request *srp)
{}

static int max_sectors_bytes(struct request_queue *q)
{}

static void
sg_fill_request_table(Sg_fd *sfp, sg_req_info_t *rinfo)
{}

#ifdef CONFIG_COMPAT
struct compat_sg_req_info {};

static int put_compat_request_table(struct compat_sg_req_info __user *o,
				    struct sg_req_info *rinfo)
{}
#endif

static long
sg_ioctl_common(struct file *filp, Sg_device *sdp, Sg_fd *sfp,
		unsigned int cmd_in, void __user *p)
{}

static long
sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
{}

static __poll_t
sg_poll(struct file *filp, poll_table * wait)
{}

static int
sg_fasync(int fd, struct file *filp, int mode)
{}

static vm_fault_t
sg_vma_fault(struct vm_fault *vmf)
{}

static const struct vm_operations_struct sg_mmap_vm_ops =;

static int
sg_mmap(struct file *filp, struct vm_area_struct *vma)
{}

static void
sg_rq_end_io_usercontext(struct work_struct *work)
{}

/*
 * This function is a "bottom half" handler that is called by the mid
 * level when a command is completed (or has failed).
 */
static enum rq_end_io_ret
sg_rq_end_io(struct request *rq, blk_status_t status)
{}

static const struct file_operations sg_fops =;

static const struct class sg_sysfs_class =;

static int sg_sysfs_valid =;

static Sg_device *
sg_alloc(struct scsi_device *scsidp)
{}

static int
sg_add_device(struct device *cl_dev)
{}

static void
sg_device_destroy(struct kref *kref)
{}

static void
sg_remove_device(struct device *cl_dev)
{}

module_param_named(scatter_elem_sz, scatter_elem_sz, int, S_IRUGO | S_IWUSR);
module_param_named(def_reserved_size, def_reserved_size, int,
		   S_IRUGO | S_IWUSR);
module_param_named(allow_dio, sg_allow_dio, int, S_IRUGO | S_IWUSR);

MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();
MODULE_VERSION();
MODULE_ALIAS_CHARDEV_MAJOR();

MODULE_PARM_DESC();
MODULE_PARM_DESC();
MODULE_PARM_DESC();

#ifdef CONFIG_SYSCTL
#include <linux/sysctl.h>

static struct ctl_table sg_sysctls[] =;

static struct ctl_table_header *hdr;
static void register_sg_sysctls(void)
{}

static void unregister_sg_sysctls(void)
{}
#else
#define register_sg_sysctls
#define unregister_sg_sysctls
#endif /* CONFIG_SYSCTL */

static int __init
init_sg(void)
{}

static void __exit
exit_sg(void)
{}

static int
sg_start_req(Sg_request *srp, unsigned char *cmd)
{}

static int
sg_finish_rem_req(Sg_request *srp)
{}

static int
sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp, int tablesize)
{}

static int
sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size)
{}

static void
sg_remove_scat(Sg_fd * sfp, Sg_scatter_hold * schp)
{}

static int
sg_read_oxfer(Sg_request * srp, char __user *outp, int num_read_xfer)
{}

static void
sg_build_reserve(Sg_fd * sfp, int req_size)
{}

static void
sg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size)
{}

static void
sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp)
{}

static Sg_request *
sg_get_rq_mark(Sg_fd * sfp, int pack_id, bool *busy)
{}

/* always adds to end of list */
static Sg_request *
sg_add_request(Sg_fd * sfp)
{}

/* Return of 1 for found; 0 for not found */
static int
sg_remove_request(Sg_fd * sfp, Sg_request * srp)
{}

static Sg_fd *
sg_add_sfp(Sg_device * sdp)
{}

static void
sg_remove_sfp_usercontext(struct work_struct *work)
{}

static void
sg_remove_sfp(struct kref *kref)
{}

#ifdef CONFIG_SCSI_PROC_FS
static int
sg_idr_max_id(int id, void *p, void *data)
{}

static int
sg_last_dev(void)
{}
#endif

/* must be called with sg_index_lock held */
static Sg_device *sg_lookup_dev(int dev)
{}

static Sg_device *
sg_get_dev(int dev)
{}

#ifdef CONFIG_SCSI_PROC_FS
static int sg_proc_seq_show_int(struct seq_file *s, void *v);

static int sg_proc_single_open_adio(struct inode *inode, struct file *file);
static ssize_t sg_proc_write_adio(struct file *filp, const char __user *buffer,
			          size_t count, loff_t *off);
static const struct proc_ops adio_proc_ops =;

static int sg_proc_single_open_dressz(struct inode *inode, struct file *file);
static ssize_t sg_proc_write_dressz(struct file *filp, 
		const char __user *buffer, size_t count, loff_t *off);
static const struct proc_ops dressz_proc_ops =;

static int sg_proc_seq_show_version(struct seq_file *s, void *v);
static int sg_proc_seq_show_devhdr(struct seq_file *s, void *v);
static int sg_proc_seq_show_dev(struct seq_file *s, void *v);
static void * dev_seq_start(struct seq_file *s, loff_t *pos);
static void * dev_seq_next(struct seq_file *s, void *v, loff_t *pos);
static void dev_seq_stop(struct seq_file *s, void *v);
static const struct seq_operations dev_seq_ops =;

static int sg_proc_seq_show_devstrs(struct seq_file *s, void *v);
static const struct seq_operations devstrs_seq_ops =;

static int sg_proc_seq_show_debug(struct seq_file *s, void *v);
static const struct seq_operations debug_seq_ops =;

static int
sg_proc_init(void)
{}


static int sg_proc_seq_show_int(struct seq_file *s, void *v)
{}

static int sg_proc_single_open_adio(struct inode *inode, struct file *file)
{}

static ssize_t 
sg_proc_write_adio(struct file *filp, const char __user *buffer,
		   size_t count, loff_t *off)
{}

static int sg_proc_single_open_dressz(struct inode *inode, struct file *file)
{}

static ssize_t 
sg_proc_write_dressz(struct file *filp, const char __user *buffer,
		     size_t count, loff_t *off)
{}

static int sg_proc_seq_show_version(struct seq_file *s, void *v)
{}

static int sg_proc_seq_show_devhdr(struct seq_file *s, void *v)
{}

struct sg_proc_deviter {};

static void * dev_seq_start(struct seq_file *s, loff_t *pos)
{}

static void * dev_seq_next(struct seq_file *s, void *v, loff_t *pos)
{}

static void dev_seq_stop(struct seq_file *s, void *v)
{}

static int sg_proc_seq_show_dev(struct seq_file *s, void *v)
{}

static int sg_proc_seq_show_devstrs(struct seq_file *s, void *v)
{}

/* must be called while holding sg_index_lock */
static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp)
{}

static int sg_proc_seq_show_debug(struct seq_file *s, void *v)
{}

#endif				/* CONFIG_SCSI_PROC_FS */

module_init();
module_exit(exit_sg);