162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  History:
462306a36Sopenharmony_ci *  Started: Aug 9 by Lawrence Foard (entropy@world.std.com),
562306a36Sopenharmony_ci *           to allow user process control of SCSI devices.
662306a36Sopenharmony_ci *  Development Sponsored by Killy Corp. NY NY
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Original driver (sg.c):
962306a36Sopenharmony_ci *        Copyright (C) 1992 Lawrence Foard
1062306a36Sopenharmony_ci * Version 2 and 3 extensions to driver:
1162306a36Sopenharmony_ci *        Copyright (C) 1998 - 2014 Douglas Gilbert
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_cistatic int sg_version_num = 30536;	/* 2 digits for each component */
1562306a36Sopenharmony_ci#define SG_VERSION_STR "3.5.36"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci/*
1862306a36Sopenharmony_ci *  D. P. Gilbert (dgilbert@interlog.com), notes:
1962306a36Sopenharmony_ci *      - scsi logging is available via SCSI_LOG_TIMEOUT macros. First
2062306a36Sopenharmony_ci *        the kernel/module needs to be built with CONFIG_SCSI_LOGGING
2162306a36Sopenharmony_ci *        (otherwise the macros compile to empty statements).
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci */
2462306a36Sopenharmony_ci#include <linux/module.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#include <linux/fs.h>
2762306a36Sopenharmony_ci#include <linux/kernel.h>
2862306a36Sopenharmony_ci#include <linux/sched.h>
2962306a36Sopenharmony_ci#include <linux/string.h>
3062306a36Sopenharmony_ci#include <linux/mm.h>
3162306a36Sopenharmony_ci#include <linux/errno.h>
3262306a36Sopenharmony_ci#include <linux/mtio.h>
3362306a36Sopenharmony_ci#include <linux/ioctl.h>
3462306a36Sopenharmony_ci#include <linux/major.h>
3562306a36Sopenharmony_ci#include <linux/slab.h>
3662306a36Sopenharmony_ci#include <linux/fcntl.h>
3762306a36Sopenharmony_ci#include <linux/init.h>
3862306a36Sopenharmony_ci#include <linux/poll.h>
3962306a36Sopenharmony_ci#include <linux/moduleparam.h>
4062306a36Sopenharmony_ci#include <linux/cdev.h>
4162306a36Sopenharmony_ci#include <linux/idr.h>
4262306a36Sopenharmony_ci#include <linux/seq_file.h>
4362306a36Sopenharmony_ci#include <linux/blkdev.h>
4462306a36Sopenharmony_ci#include <linux/delay.h>
4562306a36Sopenharmony_ci#include <linux/blktrace_api.h>
4662306a36Sopenharmony_ci#include <linux/mutex.h>
4762306a36Sopenharmony_ci#include <linux/atomic.h>
4862306a36Sopenharmony_ci#include <linux/ratelimit.h>
4962306a36Sopenharmony_ci#include <linux/uio.h>
5062306a36Sopenharmony_ci#include <linux/cred.h> /* for sg_check_file_access() */
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#include <scsi/scsi.h>
5362306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h>
5462306a36Sopenharmony_ci#include <scsi/scsi_dbg.h>
5562306a36Sopenharmony_ci#include <scsi/scsi_device.h>
5662306a36Sopenharmony_ci#include <scsi/scsi_driver.h>
5762306a36Sopenharmony_ci#include <scsi/scsi_eh.h>
5862306a36Sopenharmony_ci#include <scsi/scsi_host.h>
5962306a36Sopenharmony_ci#include <scsi/scsi_ioctl.h>
6062306a36Sopenharmony_ci#include <scsi/scsi_tcq.h>
6162306a36Sopenharmony_ci#include <scsi/sg.h>
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci#include "scsi_logging.h"
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci#ifdef CONFIG_SCSI_PROC_FS
6662306a36Sopenharmony_ci#include <linux/proc_fs.h>
6762306a36Sopenharmony_cistatic char *sg_version_date = "20140603";
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic int sg_proc_init(void);
7062306a36Sopenharmony_ci#endif
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci#define SG_ALLOW_DIO_DEF 0
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci#define SG_MAX_DEVS (1 << MINORBITS)
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci/* SG_MAX_CDB_SIZE should be 260 (spc4r37 section 3.1.30) however the type
7762306a36Sopenharmony_ci * of sg_io_hdr::cmd_len can only represent 255. All SCSI commands greater
7862306a36Sopenharmony_ci * than 16 bytes are "variable length" whose length is a multiple of 4
7962306a36Sopenharmony_ci */
8062306a36Sopenharmony_ci#define SG_MAX_CDB_SIZE 252
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci#define SG_DEFAULT_TIMEOUT mult_frac(SG_DEFAULT_TIMEOUT_USER, HZ, USER_HZ)
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic int sg_big_buff = SG_DEF_RESERVED_SIZE;
8562306a36Sopenharmony_ci/* N.B. This variable is readable and writeable via
8662306a36Sopenharmony_ci   /proc/scsi/sg/def_reserved_size . Each time sg_open() is called a buffer
8762306a36Sopenharmony_ci   of this size (or less if there is not enough memory) will be reserved
8862306a36Sopenharmony_ci   for use by this file descriptor. [Deprecated usage: this variable is also
8962306a36Sopenharmony_ci   readable via /proc/sys/kernel/sg-big-buff if the sg driver is built into
9062306a36Sopenharmony_ci   the kernel (i.e. it is not a module).] */
9162306a36Sopenharmony_cistatic int def_reserved_size = -1;	/* picks up init parameter */
9262306a36Sopenharmony_cistatic int sg_allow_dio = SG_ALLOW_DIO_DEF;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistatic int scatter_elem_sz = SG_SCATTER_SZ;
9562306a36Sopenharmony_cistatic int scatter_elem_sz_prev = SG_SCATTER_SZ;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci#define SG_SECTOR_SZ 512
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cistatic int sg_add_device(struct device *);
10062306a36Sopenharmony_cistatic void sg_remove_device(struct device *);
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic DEFINE_IDR(sg_index_idr);
10362306a36Sopenharmony_cistatic DEFINE_RWLOCK(sg_index_lock);	/* Also used to lock
10462306a36Sopenharmony_ci							   file descriptor list for device */
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cistatic struct class_interface sg_interface = {
10762306a36Sopenharmony_ci	.add_dev        = sg_add_device,
10862306a36Sopenharmony_ci	.remove_dev     = sg_remove_device,
10962306a36Sopenharmony_ci};
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_citypedef struct sg_scatter_hold { /* holding area for scsi scatter gather info */
11262306a36Sopenharmony_ci	unsigned short k_use_sg; /* Count of kernel scatter-gather pieces */
11362306a36Sopenharmony_ci	unsigned sglist_len; /* size of malloc'd scatter-gather list ++ */
11462306a36Sopenharmony_ci	unsigned bufflen;	/* Size of (aggregate) data buffer */
11562306a36Sopenharmony_ci	struct page **pages;
11662306a36Sopenharmony_ci	int page_order;
11762306a36Sopenharmony_ci	char dio_in_use;	/* 0->indirect IO (or mmap), 1->dio */
11862306a36Sopenharmony_ci	unsigned char cmd_opcode; /* first byte of command */
11962306a36Sopenharmony_ci} Sg_scatter_hold;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistruct sg_device;		/* forward declarations */
12262306a36Sopenharmony_cistruct sg_fd;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_citypedef struct sg_request {	/* SG_MAX_QUEUE requests outstanding per file */
12562306a36Sopenharmony_ci	struct list_head entry;	/* list entry */
12662306a36Sopenharmony_ci	struct sg_fd *parentfp;	/* NULL -> not in use */
12762306a36Sopenharmony_ci	Sg_scatter_hold data;	/* hold buffer, perhaps scatter list */
12862306a36Sopenharmony_ci	sg_io_hdr_t header;	/* scsi command+info, see <scsi/sg.h> */
12962306a36Sopenharmony_ci	unsigned char sense_b[SCSI_SENSE_BUFFERSIZE];
13062306a36Sopenharmony_ci	char res_used;		/* 1 -> using reserve buffer, 0 -> not ... */
13162306a36Sopenharmony_ci	char orphan;		/* 1 -> drop on sight, 0 -> normal */
13262306a36Sopenharmony_ci	char sg_io_owned;	/* 1 -> packet belongs to SG_IO */
13362306a36Sopenharmony_ci	/* done protected by rq_list_lock */
13462306a36Sopenharmony_ci	char done;		/* 0->before bh, 1->before read, 2->read */
13562306a36Sopenharmony_ci	struct request *rq;
13662306a36Sopenharmony_ci	struct bio *bio;
13762306a36Sopenharmony_ci	struct execute_work ew;
13862306a36Sopenharmony_ci} Sg_request;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_citypedef struct sg_fd {		/* holds the state of a file descriptor */
14162306a36Sopenharmony_ci	struct list_head sfd_siblings;  /* protected by device's sfd_lock */
14262306a36Sopenharmony_ci	struct sg_device *parentdp;	/* owning device */
14362306a36Sopenharmony_ci	wait_queue_head_t read_wait;	/* queue read until command done */
14462306a36Sopenharmony_ci	rwlock_t rq_list_lock;	/* protect access to list in req_arr */
14562306a36Sopenharmony_ci	struct mutex f_mutex;	/* protect against changes in this fd */
14662306a36Sopenharmony_ci	int timeout;		/* defaults to SG_DEFAULT_TIMEOUT      */
14762306a36Sopenharmony_ci	int timeout_user;	/* defaults to SG_DEFAULT_TIMEOUT_USER */
14862306a36Sopenharmony_ci	Sg_scatter_hold reserve;	/* buffer held for this file descriptor */
14962306a36Sopenharmony_ci	struct list_head rq_list; /* head of request list */
15062306a36Sopenharmony_ci	struct fasync_struct *async_qp;	/* used by asynchronous notification */
15162306a36Sopenharmony_ci	Sg_request req_arr[SG_MAX_QUEUE];	/* used as singly-linked list */
15262306a36Sopenharmony_ci	char force_packid;	/* 1 -> pack_id input to read(), 0 -> ignored */
15362306a36Sopenharmony_ci	char cmd_q;		/* 1 -> allow command queuing, 0 -> don't */
15462306a36Sopenharmony_ci	unsigned char next_cmd_len; /* 0: automatic, >0: use on next write() */
15562306a36Sopenharmony_ci	char keep_orphan;	/* 0 -> drop orphan (def), 1 -> keep for read() */
15662306a36Sopenharmony_ci	char mmap_called;	/* 0 -> mmap() never called on this fd */
15762306a36Sopenharmony_ci	char res_in_use;	/* 1 -> 'reserve' array in use */
15862306a36Sopenharmony_ci	struct kref f_ref;
15962306a36Sopenharmony_ci	struct execute_work ew;
16062306a36Sopenharmony_ci} Sg_fd;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_citypedef struct sg_device { /* holds the state of each scsi generic device */
16362306a36Sopenharmony_ci	struct scsi_device *device;
16462306a36Sopenharmony_ci	wait_queue_head_t open_wait;    /* queue open() when O_EXCL present */
16562306a36Sopenharmony_ci	struct mutex open_rel_lock;     /* held when in open() or release() */
16662306a36Sopenharmony_ci	int sg_tablesize;	/* adapter's max scatter-gather table size */
16762306a36Sopenharmony_ci	u32 index;		/* device index number */
16862306a36Sopenharmony_ci	struct list_head sfds;
16962306a36Sopenharmony_ci	rwlock_t sfd_lock;      /* protect access to sfd list */
17062306a36Sopenharmony_ci	atomic_t detaching;     /* 0->device usable, 1->device detaching */
17162306a36Sopenharmony_ci	bool exclude;		/* 1->open(O_EXCL) succeeded and is active */
17262306a36Sopenharmony_ci	int open_cnt;		/* count of opens (perhaps < num(sfds) ) */
17362306a36Sopenharmony_ci	char sgdebug;		/* 0->off, 1->sense, 9->dump dev, 10-> all devs */
17462306a36Sopenharmony_ci	char name[DISK_NAME_LEN];
17562306a36Sopenharmony_ci	struct cdev * cdev;	/* char_dev [sysfs: /sys/cdev/major/sg<n>] */
17662306a36Sopenharmony_ci	struct kref d_ref;
17762306a36Sopenharmony_ci} Sg_device;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci/* tasklet or soft irq callback */
18062306a36Sopenharmony_cistatic enum rq_end_io_ret sg_rq_end_io(struct request *rq, blk_status_t status);
18162306a36Sopenharmony_cistatic int sg_start_req(Sg_request *srp, unsigned char *cmd);
18262306a36Sopenharmony_cistatic int sg_finish_rem_req(Sg_request * srp);
18362306a36Sopenharmony_cistatic int sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size);
18462306a36Sopenharmony_cistatic ssize_t sg_new_read(Sg_fd * sfp, char __user *buf, size_t count,
18562306a36Sopenharmony_ci			   Sg_request * srp);
18662306a36Sopenharmony_cistatic ssize_t sg_new_write(Sg_fd *sfp, struct file *file,
18762306a36Sopenharmony_ci			const char __user *buf, size_t count, int blocking,
18862306a36Sopenharmony_ci			int read_only, int sg_io_owned, Sg_request **o_srp);
18962306a36Sopenharmony_cistatic int sg_common_write(Sg_fd * sfp, Sg_request * srp,
19062306a36Sopenharmony_ci			   unsigned char *cmnd, int timeout, int blocking);
19162306a36Sopenharmony_cistatic int sg_read_oxfer(Sg_request * srp, char __user *outp, int num_read_xfer);
19262306a36Sopenharmony_cistatic void sg_remove_scat(Sg_fd * sfp, Sg_scatter_hold * schp);
19362306a36Sopenharmony_cistatic void sg_build_reserve(Sg_fd * sfp, int req_size);
19462306a36Sopenharmony_cistatic void sg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size);
19562306a36Sopenharmony_cistatic void sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp);
19662306a36Sopenharmony_cistatic Sg_fd *sg_add_sfp(Sg_device * sdp);
19762306a36Sopenharmony_cistatic void sg_remove_sfp(struct kref *);
19862306a36Sopenharmony_cistatic Sg_request *sg_get_rq_mark(Sg_fd * sfp, int pack_id, bool *busy);
19962306a36Sopenharmony_cistatic Sg_request *sg_add_request(Sg_fd * sfp);
20062306a36Sopenharmony_cistatic int sg_remove_request(Sg_fd * sfp, Sg_request * srp);
20162306a36Sopenharmony_cistatic Sg_device *sg_get_dev(int dev);
20262306a36Sopenharmony_cistatic void sg_device_destroy(struct kref *kref);
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci#define SZ_SG_HEADER sizeof(struct sg_header)
20562306a36Sopenharmony_ci#define SZ_SG_IO_HDR sizeof(sg_io_hdr_t)
20662306a36Sopenharmony_ci#define SZ_SG_IOVEC sizeof(sg_iovec_t)
20762306a36Sopenharmony_ci#define SZ_SG_REQ_INFO sizeof(sg_req_info_t)
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci#define sg_printk(prefix, sdp, fmt, a...) \
21062306a36Sopenharmony_ci	sdev_prefix_printk(prefix, (sdp)->device, (sdp)->name, fmt, ##a)
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci/*
21362306a36Sopenharmony_ci * The SCSI interfaces that use read() and write() as an asynchronous variant of
21462306a36Sopenharmony_ci * ioctl(..., SG_IO, ...) are fundamentally unsafe, since there are lots of ways
21562306a36Sopenharmony_ci * to trigger read() and write() calls from various contexts with elevated
21662306a36Sopenharmony_ci * privileges. This can lead to kernel memory corruption (e.g. if these
21762306a36Sopenharmony_ci * interfaces are called through splice()) and privilege escalation inside
21862306a36Sopenharmony_ci * userspace (e.g. if a process with access to such a device passes a file
21962306a36Sopenharmony_ci * descriptor to a SUID binary as stdin/stdout/stderr).
22062306a36Sopenharmony_ci *
22162306a36Sopenharmony_ci * This function provides protection for the legacy API by restricting the
22262306a36Sopenharmony_ci * calling context.
22362306a36Sopenharmony_ci */
22462306a36Sopenharmony_cistatic int sg_check_file_access(struct file *filp, const char *caller)
22562306a36Sopenharmony_ci{
22662306a36Sopenharmony_ci	if (filp->f_cred != current_real_cred()) {
22762306a36Sopenharmony_ci		pr_err_once("%s: process %d (%s) changed security contexts after opening file descriptor, this is not allowed.\n",
22862306a36Sopenharmony_ci			caller, task_tgid_vnr(current), current->comm);
22962306a36Sopenharmony_ci		return -EPERM;
23062306a36Sopenharmony_ci	}
23162306a36Sopenharmony_ci	return 0;
23262306a36Sopenharmony_ci}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_cistatic int sg_allow_access(struct file *filp, unsigned char *cmd)
23562306a36Sopenharmony_ci{
23662306a36Sopenharmony_ci	struct sg_fd *sfp = filp->private_data;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	if (sfp->parentdp->device->type == TYPE_SCANNER)
23962306a36Sopenharmony_ci		return 0;
24062306a36Sopenharmony_ci	if (!scsi_cmd_allowed(cmd, filp->f_mode & FMODE_WRITE))
24162306a36Sopenharmony_ci		return -EPERM;
24262306a36Sopenharmony_ci	return 0;
24362306a36Sopenharmony_ci}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_cistatic int
24662306a36Sopenharmony_ciopen_wait(Sg_device *sdp, int flags)
24762306a36Sopenharmony_ci{
24862306a36Sopenharmony_ci	int retval = 0;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	if (flags & O_EXCL) {
25162306a36Sopenharmony_ci		while (sdp->open_cnt > 0) {
25262306a36Sopenharmony_ci			mutex_unlock(&sdp->open_rel_lock);
25362306a36Sopenharmony_ci			retval = wait_event_interruptible(sdp->open_wait,
25462306a36Sopenharmony_ci					(atomic_read(&sdp->detaching) ||
25562306a36Sopenharmony_ci					 !sdp->open_cnt));
25662306a36Sopenharmony_ci			mutex_lock(&sdp->open_rel_lock);
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci			if (retval) /* -ERESTARTSYS */
25962306a36Sopenharmony_ci				return retval;
26062306a36Sopenharmony_ci			if (atomic_read(&sdp->detaching))
26162306a36Sopenharmony_ci				return -ENODEV;
26262306a36Sopenharmony_ci		}
26362306a36Sopenharmony_ci	} else {
26462306a36Sopenharmony_ci		while (sdp->exclude) {
26562306a36Sopenharmony_ci			mutex_unlock(&sdp->open_rel_lock);
26662306a36Sopenharmony_ci			retval = wait_event_interruptible(sdp->open_wait,
26762306a36Sopenharmony_ci					(atomic_read(&sdp->detaching) ||
26862306a36Sopenharmony_ci					 !sdp->exclude));
26962306a36Sopenharmony_ci			mutex_lock(&sdp->open_rel_lock);
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci			if (retval) /* -ERESTARTSYS */
27262306a36Sopenharmony_ci				return retval;
27362306a36Sopenharmony_ci			if (atomic_read(&sdp->detaching))
27462306a36Sopenharmony_ci				return -ENODEV;
27562306a36Sopenharmony_ci		}
27662306a36Sopenharmony_ci	}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	return retval;
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci/* Returns 0 on success, else a negated errno value */
28262306a36Sopenharmony_cistatic int
28362306a36Sopenharmony_cisg_open(struct inode *inode, struct file *filp)
28462306a36Sopenharmony_ci{
28562306a36Sopenharmony_ci	int dev = iminor(inode);
28662306a36Sopenharmony_ci	int flags = filp->f_flags;
28762306a36Sopenharmony_ci	struct request_queue *q;
28862306a36Sopenharmony_ci	Sg_device *sdp;
28962306a36Sopenharmony_ci	Sg_fd *sfp;
29062306a36Sopenharmony_ci	int retval;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	nonseekable_open(inode, filp);
29362306a36Sopenharmony_ci	if ((flags & O_EXCL) && (O_RDONLY == (flags & O_ACCMODE)))
29462306a36Sopenharmony_ci		return -EPERM; /* Can't lock it with read only access */
29562306a36Sopenharmony_ci	sdp = sg_get_dev(dev);
29662306a36Sopenharmony_ci	if (IS_ERR(sdp))
29762306a36Sopenharmony_ci		return PTR_ERR(sdp);
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp,
30062306a36Sopenharmony_ci				      "sg_open: flags=0x%x\n", flags));
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	/* This driver's module count bumped by fops_get in <linux/fs.h> */
30362306a36Sopenharmony_ci	/* Prevent the device driver from vanishing while we sleep */
30462306a36Sopenharmony_ci	retval = scsi_device_get(sdp->device);
30562306a36Sopenharmony_ci	if (retval)
30662306a36Sopenharmony_ci		goto sg_put;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	retval = scsi_autopm_get_device(sdp->device);
30962306a36Sopenharmony_ci	if (retval)
31062306a36Sopenharmony_ci		goto sdp_put;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	/* scsi_block_when_processing_errors() may block so bypass
31362306a36Sopenharmony_ci	 * check if O_NONBLOCK. Permits SCSI commands to be issued
31462306a36Sopenharmony_ci	 * during error recovery. Tread carefully. */
31562306a36Sopenharmony_ci	if (!((flags & O_NONBLOCK) ||
31662306a36Sopenharmony_ci	      scsi_block_when_processing_errors(sdp->device))) {
31762306a36Sopenharmony_ci		retval = -ENXIO;
31862306a36Sopenharmony_ci		/* we are in error recovery for this device */
31962306a36Sopenharmony_ci		goto error_out;
32062306a36Sopenharmony_ci	}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	mutex_lock(&sdp->open_rel_lock);
32362306a36Sopenharmony_ci	if (flags & O_NONBLOCK) {
32462306a36Sopenharmony_ci		if (flags & O_EXCL) {
32562306a36Sopenharmony_ci			if (sdp->open_cnt > 0) {
32662306a36Sopenharmony_ci				retval = -EBUSY;
32762306a36Sopenharmony_ci				goto error_mutex_locked;
32862306a36Sopenharmony_ci			}
32962306a36Sopenharmony_ci		} else {
33062306a36Sopenharmony_ci			if (sdp->exclude) {
33162306a36Sopenharmony_ci				retval = -EBUSY;
33262306a36Sopenharmony_ci				goto error_mutex_locked;
33362306a36Sopenharmony_ci			}
33462306a36Sopenharmony_ci		}
33562306a36Sopenharmony_ci	} else {
33662306a36Sopenharmony_ci		retval = open_wait(sdp, flags);
33762306a36Sopenharmony_ci		if (retval) /* -ERESTARTSYS or -ENODEV */
33862306a36Sopenharmony_ci			goto error_mutex_locked;
33962306a36Sopenharmony_ci	}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	/* N.B. at this point we are holding the open_rel_lock */
34262306a36Sopenharmony_ci	if (flags & O_EXCL)
34362306a36Sopenharmony_ci		sdp->exclude = true;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	if (sdp->open_cnt < 1) {  /* no existing opens */
34662306a36Sopenharmony_ci		sdp->sgdebug = 0;
34762306a36Sopenharmony_ci		q = sdp->device->request_queue;
34862306a36Sopenharmony_ci		sdp->sg_tablesize = queue_max_segments(q);
34962306a36Sopenharmony_ci	}
35062306a36Sopenharmony_ci	sfp = sg_add_sfp(sdp);
35162306a36Sopenharmony_ci	if (IS_ERR(sfp)) {
35262306a36Sopenharmony_ci		retval = PTR_ERR(sfp);
35362306a36Sopenharmony_ci		goto out_undo;
35462306a36Sopenharmony_ci	}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	filp->private_data = sfp;
35762306a36Sopenharmony_ci	sdp->open_cnt++;
35862306a36Sopenharmony_ci	mutex_unlock(&sdp->open_rel_lock);
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	retval = 0;
36162306a36Sopenharmony_cisg_put:
36262306a36Sopenharmony_ci	kref_put(&sdp->d_ref, sg_device_destroy);
36362306a36Sopenharmony_ci	return retval;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ciout_undo:
36662306a36Sopenharmony_ci	if (flags & O_EXCL) {
36762306a36Sopenharmony_ci		sdp->exclude = false;   /* undo if error */
36862306a36Sopenharmony_ci		wake_up_interruptible(&sdp->open_wait);
36962306a36Sopenharmony_ci	}
37062306a36Sopenharmony_cierror_mutex_locked:
37162306a36Sopenharmony_ci	mutex_unlock(&sdp->open_rel_lock);
37262306a36Sopenharmony_cierror_out:
37362306a36Sopenharmony_ci	scsi_autopm_put_device(sdp->device);
37462306a36Sopenharmony_cisdp_put:
37562306a36Sopenharmony_ci	scsi_device_put(sdp->device);
37662306a36Sopenharmony_ci	goto sg_put;
37762306a36Sopenharmony_ci}
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci/* Release resources associated with a successful sg_open()
38062306a36Sopenharmony_ci * Returns 0 on success, else a negated errno value */
38162306a36Sopenharmony_cistatic int
38262306a36Sopenharmony_cisg_release(struct inode *inode, struct file *filp)
38362306a36Sopenharmony_ci{
38462306a36Sopenharmony_ci	Sg_device *sdp;
38562306a36Sopenharmony_ci	Sg_fd *sfp;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
38862306a36Sopenharmony_ci		return -ENXIO;
38962306a36Sopenharmony_ci	SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp, "sg_release\n"));
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	mutex_lock(&sdp->open_rel_lock);
39262306a36Sopenharmony_ci	scsi_autopm_put_device(sdp->device);
39362306a36Sopenharmony_ci	kref_put(&sfp->f_ref, sg_remove_sfp);
39462306a36Sopenharmony_ci	sdp->open_cnt--;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	/* possibly many open()s waiting on exlude clearing, start many;
39762306a36Sopenharmony_ci	 * only open(O_EXCL)s wait on 0==open_cnt so only start one */
39862306a36Sopenharmony_ci	if (sdp->exclude) {
39962306a36Sopenharmony_ci		sdp->exclude = false;
40062306a36Sopenharmony_ci		wake_up_interruptible_all(&sdp->open_wait);
40162306a36Sopenharmony_ci	} else if (0 == sdp->open_cnt) {
40262306a36Sopenharmony_ci		wake_up_interruptible(&sdp->open_wait);
40362306a36Sopenharmony_ci	}
40462306a36Sopenharmony_ci	mutex_unlock(&sdp->open_rel_lock);
40562306a36Sopenharmony_ci	return 0;
40662306a36Sopenharmony_ci}
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_cistatic int get_sg_io_pack_id(int *pack_id, void __user *buf, size_t count)
40962306a36Sopenharmony_ci{
41062306a36Sopenharmony_ci	struct sg_header __user *old_hdr = buf;
41162306a36Sopenharmony_ci	int reply_len;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	if (count >= SZ_SG_HEADER) {
41462306a36Sopenharmony_ci		/* negative reply_len means v3 format, otherwise v1/v2 */
41562306a36Sopenharmony_ci		if (get_user(reply_len, &old_hdr->reply_len))
41662306a36Sopenharmony_ci			return -EFAULT;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci		if (reply_len >= 0)
41962306a36Sopenharmony_ci			return get_user(*pack_id, &old_hdr->pack_id);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci		if (in_compat_syscall() &&
42262306a36Sopenharmony_ci		    count >= sizeof(struct compat_sg_io_hdr)) {
42362306a36Sopenharmony_ci			struct compat_sg_io_hdr __user *hp = buf;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci			return get_user(*pack_id, &hp->pack_id);
42662306a36Sopenharmony_ci		}
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci		if (count >= sizeof(struct sg_io_hdr)) {
42962306a36Sopenharmony_ci			struct sg_io_hdr __user *hp = buf;
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci			return get_user(*pack_id, &hp->pack_id);
43262306a36Sopenharmony_ci		}
43362306a36Sopenharmony_ci	}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	/* no valid header was passed, so ignore the pack_id */
43662306a36Sopenharmony_ci	*pack_id = -1;
43762306a36Sopenharmony_ci	return 0;
43862306a36Sopenharmony_ci}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_cistatic ssize_t
44162306a36Sopenharmony_cisg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
44262306a36Sopenharmony_ci{
44362306a36Sopenharmony_ci	Sg_device *sdp;
44462306a36Sopenharmony_ci	Sg_fd *sfp;
44562306a36Sopenharmony_ci	Sg_request *srp;
44662306a36Sopenharmony_ci	int req_pack_id = -1;
44762306a36Sopenharmony_ci	bool busy;
44862306a36Sopenharmony_ci	sg_io_hdr_t *hp;
44962306a36Sopenharmony_ci	struct sg_header *old_hdr;
45062306a36Sopenharmony_ci	int retval;
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	/*
45362306a36Sopenharmony_ci	 * This could cause a response to be stranded. Close the associated
45462306a36Sopenharmony_ci	 * file descriptor to free up any resources being held.
45562306a36Sopenharmony_ci	 */
45662306a36Sopenharmony_ci	retval = sg_check_file_access(filp, __func__);
45762306a36Sopenharmony_ci	if (retval)
45862306a36Sopenharmony_ci		return retval;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
46162306a36Sopenharmony_ci		return -ENXIO;
46262306a36Sopenharmony_ci	SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp,
46362306a36Sopenharmony_ci				      "sg_read: count=%d\n", (int) count));
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	if (sfp->force_packid)
46662306a36Sopenharmony_ci		retval = get_sg_io_pack_id(&req_pack_id, buf, count);
46762306a36Sopenharmony_ci	if (retval)
46862306a36Sopenharmony_ci		return retval;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	srp = sg_get_rq_mark(sfp, req_pack_id, &busy);
47162306a36Sopenharmony_ci	if (!srp) {		/* now wait on packet to arrive */
47262306a36Sopenharmony_ci		if (filp->f_flags & O_NONBLOCK)
47362306a36Sopenharmony_ci			return -EAGAIN;
47462306a36Sopenharmony_ci		retval = wait_event_interruptible(sfp->read_wait,
47562306a36Sopenharmony_ci			((srp = sg_get_rq_mark(sfp, req_pack_id, &busy)) ||
47662306a36Sopenharmony_ci			(!busy && atomic_read(&sdp->detaching))));
47762306a36Sopenharmony_ci		if (!srp)
47862306a36Sopenharmony_ci			/* signal or detaching */
47962306a36Sopenharmony_ci			return retval ? retval : -ENODEV;
48062306a36Sopenharmony_ci	}
48162306a36Sopenharmony_ci	if (srp->header.interface_id != '\0')
48262306a36Sopenharmony_ci		return sg_new_read(sfp, buf, count, srp);
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	hp = &srp->header;
48562306a36Sopenharmony_ci	old_hdr = kzalloc(SZ_SG_HEADER, GFP_KERNEL);
48662306a36Sopenharmony_ci	if (!old_hdr)
48762306a36Sopenharmony_ci		return -ENOMEM;
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	old_hdr->reply_len = (int) hp->timeout;
49062306a36Sopenharmony_ci	old_hdr->pack_len = old_hdr->reply_len; /* old, strange behaviour */
49162306a36Sopenharmony_ci	old_hdr->pack_id = hp->pack_id;
49262306a36Sopenharmony_ci	old_hdr->twelve_byte =
49362306a36Sopenharmony_ci	    ((srp->data.cmd_opcode >= 0xc0) && (12 == hp->cmd_len)) ? 1 : 0;
49462306a36Sopenharmony_ci	old_hdr->target_status = hp->masked_status;
49562306a36Sopenharmony_ci	old_hdr->host_status = hp->host_status;
49662306a36Sopenharmony_ci	old_hdr->driver_status = hp->driver_status;
49762306a36Sopenharmony_ci	if ((CHECK_CONDITION & hp->masked_status) ||
49862306a36Sopenharmony_ci	    (srp->sense_b[0] & 0x70) == 0x70) {
49962306a36Sopenharmony_ci		old_hdr->driver_status = DRIVER_SENSE;
50062306a36Sopenharmony_ci		memcpy(old_hdr->sense_buffer, srp->sense_b,
50162306a36Sopenharmony_ci		       sizeof (old_hdr->sense_buffer));
50262306a36Sopenharmony_ci	}
50362306a36Sopenharmony_ci	switch (hp->host_status) {
50462306a36Sopenharmony_ci	/* This setup of 'result' is for backward compatibility and is best
50562306a36Sopenharmony_ci	   ignored by the user who should use target, host + driver status */
50662306a36Sopenharmony_ci	case DID_OK:
50762306a36Sopenharmony_ci	case DID_PASSTHROUGH:
50862306a36Sopenharmony_ci	case DID_SOFT_ERROR:
50962306a36Sopenharmony_ci		old_hdr->result = 0;
51062306a36Sopenharmony_ci		break;
51162306a36Sopenharmony_ci	case DID_NO_CONNECT:
51262306a36Sopenharmony_ci	case DID_BUS_BUSY:
51362306a36Sopenharmony_ci	case DID_TIME_OUT:
51462306a36Sopenharmony_ci		old_hdr->result = EBUSY;
51562306a36Sopenharmony_ci		break;
51662306a36Sopenharmony_ci	case DID_BAD_TARGET:
51762306a36Sopenharmony_ci	case DID_ABORT:
51862306a36Sopenharmony_ci	case DID_PARITY:
51962306a36Sopenharmony_ci	case DID_RESET:
52062306a36Sopenharmony_ci	case DID_BAD_INTR:
52162306a36Sopenharmony_ci		old_hdr->result = EIO;
52262306a36Sopenharmony_ci		break;
52362306a36Sopenharmony_ci	case DID_ERROR:
52462306a36Sopenharmony_ci		old_hdr->result = (srp->sense_b[0] == 0 &&
52562306a36Sopenharmony_ci				  hp->masked_status == GOOD) ? 0 : EIO;
52662306a36Sopenharmony_ci		break;
52762306a36Sopenharmony_ci	default:
52862306a36Sopenharmony_ci		old_hdr->result = EIO;
52962306a36Sopenharmony_ci		break;
53062306a36Sopenharmony_ci	}
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	/* Now copy the result back to the user buffer.  */
53362306a36Sopenharmony_ci	if (count >= SZ_SG_HEADER) {
53462306a36Sopenharmony_ci		if (copy_to_user(buf, old_hdr, SZ_SG_HEADER)) {
53562306a36Sopenharmony_ci			retval = -EFAULT;
53662306a36Sopenharmony_ci			goto free_old_hdr;
53762306a36Sopenharmony_ci		}
53862306a36Sopenharmony_ci		buf += SZ_SG_HEADER;
53962306a36Sopenharmony_ci		if (count > old_hdr->reply_len)
54062306a36Sopenharmony_ci			count = old_hdr->reply_len;
54162306a36Sopenharmony_ci		if (count > SZ_SG_HEADER) {
54262306a36Sopenharmony_ci			if (sg_read_oxfer(srp, buf, count - SZ_SG_HEADER)) {
54362306a36Sopenharmony_ci				retval = -EFAULT;
54462306a36Sopenharmony_ci				goto free_old_hdr;
54562306a36Sopenharmony_ci			}
54662306a36Sopenharmony_ci		}
54762306a36Sopenharmony_ci	} else
54862306a36Sopenharmony_ci		count = (old_hdr->result == 0) ? 0 : -EIO;
54962306a36Sopenharmony_ci	sg_finish_rem_req(srp);
55062306a36Sopenharmony_ci	sg_remove_request(sfp, srp);
55162306a36Sopenharmony_ci	retval = count;
55262306a36Sopenharmony_cifree_old_hdr:
55362306a36Sopenharmony_ci	kfree(old_hdr);
55462306a36Sopenharmony_ci	return retval;
55562306a36Sopenharmony_ci}
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_cistatic ssize_t
55862306a36Sopenharmony_cisg_new_read(Sg_fd * sfp, char __user *buf, size_t count, Sg_request * srp)
55962306a36Sopenharmony_ci{
56062306a36Sopenharmony_ci	sg_io_hdr_t *hp = &srp->header;
56162306a36Sopenharmony_ci	int err = 0, err2;
56262306a36Sopenharmony_ci	int len;
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	if (in_compat_syscall()) {
56562306a36Sopenharmony_ci		if (count < sizeof(struct compat_sg_io_hdr)) {
56662306a36Sopenharmony_ci			err = -EINVAL;
56762306a36Sopenharmony_ci			goto err_out;
56862306a36Sopenharmony_ci		}
56962306a36Sopenharmony_ci	} else if (count < SZ_SG_IO_HDR) {
57062306a36Sopenharmony_ci		err = -EINVAL;
57162306a36Sopenharmony_ci		goto err_out;
57262306a36Sopenharmony_ci	}
57362306a36Sopenharmony_ci	hp->sb_len_wr = 0;
57462306a36Sopenharmony_ci	if ((hp->mx_sb_len > 0) && hp->sbp) {
57562306a36Sopenharmony_ci		if ((CHECK_CONDITION & hp->masked_status) ||
57662306a36Sopenharmony_ci		    (srp->sense_b[0] & 0x70) == 0x70) {
57762306a36Sopenharmony_ci			int sb_len = SCSI_SENSE_BUFFERSIZE;
57862306a36Sopenharmony_ci			sb_len = (hp->mx_sb_len > sb_len) ? sb_len : hp->mx_sb_len;
57962306a36Sopenharmony_ci			len = 8 + (int) srp->sense_b[7];	/* Additional sense length field */
58062306a36Sopenharmony_ci			len = (len > sb_len) ? sb_len : len;
58162306a36Sopenharmony_ci			if (copy_to_user(hp->sbp, srp->sense_b, len)) {
58262306a36Sopenharmony_ci				err = -EFAULT;
58362306a36Sopenharmony_ci				goto err_out;
58462306a36Sopenharmony_ci			}
58562306a36Sopenharmony_ci			hp->driver_status = DRIVER_SENSE;
58662306a36Sopenharmony_ci			hp->sb_len_wr = len;
58762306a36Sopenharmony_ci		}
58862306a36Sopenharmony_ci	}
58962306a36Sopenharmony_ci	if (hp->masked_status || hp->host_status || hp->driver_status)
59062306a36Sopenharmony_ci		hp->info |= SG_INFO_CHECK;
59162306a36Sopenharmony_ci	err = put_sg_io_hdr(hp, buf);
59262306a36Sopenharmony_cierr_out:
59362306a36Sopenharmony_ci	err2 = sg_finish_rem_req(srp);
59462306a36Sopenharmony_ci	sg_remove_request(sfp, srp);
59562306a36Sopenharmony_ci	return err ? : err2 ? : count;
59662306a36Sopenharmony_ci}
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_cistatic ssize_t
59962306a36Sopenharmony_cisg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
60062306a36Sopenharmony_ci{
60162306a36Sopenharmony_ci	int mxsize, cmd_size, k;
60262306a36Sopenharmony_ci	int input_size, blocking;
60362306a36Sopenharmony_ci	unsigned char opcode;
60462306a36Sopenharmony_ci	Sg_device *sdp;
60562306a36Sopenharmony_ci	Sg_fd *sfp;
60662306a36Sopenharmony_ci	Sg_request *srp;
60762306a36Sopenharmony_ci	struct sg_header old_hdr;
60862306a36Sopenharmony_ci	sg_io_hdr_t *hp;
60962306a36Sopenharmony_ci	unsigned char cmnd[SG_MAX_CDB_SIZE];
61062306a36Sopenharmony_ci	int retval;
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	retval = sg_check_file_access(filp, __func__);
61362306a36Sopenharmony_ci	if (retval)
61462306a36Sopenharmony_ci		return retval;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
61762306a36Sopenharmony_ci		return -ENXIO;
61862306a36Sopenharmony_ci	SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp,
61962306a36Sopenharmony_ci				      "sg_write: count=%d\n", (int) count));
62062306a36Sopenharmony_ci	if (atomic_read(&sdp->detaching))
62162306a36Sopenharmony_ci		return -ENODEV;
62262306a36Sopenharmony_ci	if (!((filp->f_flags & O_NONBLOCK) ||
62362306a36Sopenharmony_ci	      scsi_block_when_processing_errors(sdp->device)))
62462306a36Sopenharmony_ci		return -ENXIO;
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	if (count < SZ_SG_HEADER)
62762306a36Sopenharmony_ci		return -EIO;
62862306a36Sopenharmony_ci	if (copy_from_user(&old_hdr, buf, SZ_SG_HEADER))
62962306a36Sopenharmony_ci		return -EFAULT;
63062306a36Sopenharmony_ci	blocking = !(filp->f_flags & O_NONBLOCK);
63162306a36Sopenharmony_ci	if (old_hdr.reply_len < 0)
63262306a36Sopenharmony_ci		return sg_new_write(sfp, filp, buf, count,
63362306a36Sopenharmony_ci				    blocking, 0, 0, NULL);
63462306a36Sopenharmony_ci	if (count < (SZ_SG_HEADER + 6))
63562306a36Sopenharmony_ci		return -EIO;	/* The minimum scsi command length is 6 bytes. */
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	buf += SZ_SG_HEADER;
63862306a36Sopenharmony_ci	if (get_user(opcode, buf))
63962306a36Sopenharmony_ci		return -EFAULT;
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	if (!(srp = sg_add_request(sfp))) {
64262306a36Sopenharmony_ci		SCSI_LOG_TIMEOUT(1, sg_printk(KERN_INFO, sdp,
64362306a36Sopenharmony_ci					      "sg_write: queue full\n"));
64462306a36Sopenharmony_ci		return -EDOM;
64562306a36Sopenharmony_ci	}
64662306a36Sopenharmony_ci	mutex_lock(&sfp->f_mutex);
64762306a36Sopenharmony_ci	if (sfp->next_cmd_len > 0) {
64862306a36Sopenharmony_ci		cmd_size = sfp->next_cmd_len;
64962306a36Sopenharmony_ci		sfp->next_cmd_len = 0;	/* reset so only this write() effected */
65062306a36Sopenharmony_ci	} else {
65162306a36Sopenharmony_ci		cmd_size = COMMAND_SIZE(opcode);	/* based on SCSI command group */
65262306a36Sopenharmony_ci		if ((opcode >= 0xc0) && old_hdr.twelve_byte)
65362306a36Sopenharmony_ci			cmd_size = 12;
65462306a36Sopenharmony_ci	}
65562306a36Sopenharmony_ci	mutex_unlock(&sfp->f_mutex);
65662306a36Sopenharmony_ci	SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sdp,
65762306a36Sopenharmony_ci		"sg_write:   scsi opcode=0x%02x, cmd_size=%d\n", (int) opcode, cmd_size));
65862306a36Sopenharmony_ci/* Determine buffer size.  */
65962306a36Sopenharmony_ci	input_size = count - cmd_size;
66062306a36Sopenharmony_ci	mxsize = (input_size > old_hdr.reply_len) ? input_size : old_hdr.reply_len;
66162306a36Sopenharmony_ci	mxsize -= SZ_SG_HEADER;
66262306a36Sopenharmony_ci	input_size -= SZ_SG_HEADER;
66362306a36Sopenharmony_ci	if (input_size < 0) {
66462306a36Sopenharmony_ci		sg_remove_request(sfp, srp);
66562306a36Sopenharmony_ci		return -EIO;	/* User did not pass enough bytes for this command. */
66662306a36Sopenharmony_ci	}
66762306a36Sopenharmony_ci	hp = &srp->header;
66862306a36Sopenharmony_ci	hp->interface_id = '\0';	/* indicator of old interface tunnelled */
66962306a36Sopenharmony_ci	hp->cmd_len = (unsigned char) cmd_size;
67062306a36Sopenharmony_ci	hp->iovec_count = 0;
67162306a36Sopenharmony_ci	hp->mx_sb_len = 0;
67262306a36Sopenharmony_ci	if (input_size > 0)
67362306a36Sopenharmony_ci		hp->dxfer_direction = (old_hdr.reply_len > SZ_SG_HEADER) ?
67462306a36Sopenharmony_ci		    SG_DXFER_TO_FROM_DEV : SG_DXFER_TO_DEV;
67562306a36Sopenharmony_ci	else
67662306a36Sopenharmony_ci		hp->dxfer_direction = (mxsize > 0) ? SG_DXFER_FROM_DEV : SG_DXFER_NONE;
67762306a36Sopenharmony_ci	hp->dxfer_len = mxsize;
67862306a36Sopenharmony_ci	if ((hp->dxfer_direction == SG_DXFER_TO_DEV) ||
67962306a36Sopenharmony_ci	    (hp->dxfer_direction == SG_DXFER_TO_FROM_DEV))
68062306a36Sopenharmony_ci		hp->dxferp = (char __user *)buf + cmd_size;
68162306a36Sopenharmony_ci	else
68262306a36Sopenharmony_ci		hp->dxferp = NULL;
68362306a36Sopenharmony_ci	hp->sbp = NULL;
68462306a36Sopenharmony_ci	hp->timeout = old_hdr.reply_len;	/* structure abuse ... */
68562306a36Sopenharmony_ci	hp->flags = input_size;	/* structure abuse ... */
68662306a36Sopenharmony_ci	hp->pack_id = old_hdr.pack_id;
68762306a36Sopenharmony_ci	hp->usr_ptr = NULL;
68862306a36Sopenharmony_ci	if (copy_from_user(cmnd, buf, cmd_size)) {
68962306a36Sopenharmony_ci		sg_remove_request(sfp, srp);
69062306a36Sopenharmony_ci		return -EFAULT;
69162306a36Sopenharmony_ci	}
69262306a36Sopenharmony_ci	/*
69362306a36Sopenharmony_ci	 * SG_DXFER_TO_FROM_DEV is functionally equivalent to SG_DXFER_FROM_DEV,
69462306a36Sopenharmony_ci	 * but is is possible that the app intended SG_DXFER_TO_DEV, because there
69562306a36Sopenharmony_ci	 * is a non-zero input_size, so emit a warning.
69662306a36Sopenharmony_ci	 */
69762306a36Sopenharmony_ci	if (hp->dxfer_direction == SG_DXFER_TO_FROM_DEV) {
69862306a36Sopenharmony_ci		printk_ratelimited(KERN_WARNING
69962306a36Sopenharmony_ci				   "sg_write: data in/out %d/%d bytes "
70062306a36Sopenharmony_ci				   "for SCSI command 0x%x-- guessing "
70162306a36Sopenharmony_ci				   "data in;\n   program %s not setting "
70262306a36Sopenharmony_ci				   "count and/or reply_len properly\n",
70362306a36Sopenharmony_ci				   old_hdr.reply_len - (int)SZ_SG_HEADER,
70462306a36Sopenharmony_ci				   input_size, (unsigned int) cmnd[0],
70562306a36Sopenharmony_ci				   current->comm);
70662306a36Sopenharmony_ci	}
70762306a36Sopenharmony_ci	k = sg_common_write(sfp, srp, cmnd, sfp->timeout, blocking);
70862306a36Sopenharmony_ci	return (k < 0) ? k : count;
70962306a36Sopenharmony_ci}
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_cistatic ssize_t
71262306a36Sopenharmony_cisg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf,
71362306a36Sopenharmony_ci		 size_t count, int blocking, int read_only, int sg_io_owned,
71462306a36Sopenharmony_ci		 Sg_request **o_srp)
71562306a36Sopenharmony_ci{
71662306a36Sopenharmony_ci	int k;
71762306a36Sopenharmony_ci	Sg_request *srp;
71862306a36Sopenharmony_ci	sg_io_hdr_t *hp;
71962306a36Sopenharmony_ci	unsigned char cmnd[SG_MAX_CDB_SIZE];
72062306a36Sopenharmony_ci	int timeout;
72162306a36Sopenharmony_ci	unsigned long ul_timeout;
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	if (count < SZ_SG_IO_HDR)
72462306a36Sopenharmony_ci		return -EINVAL;
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	sfp->cmd_q = 1;	/* when sg_io_hdr seen, set command queuing on */
72762306a36Sopenharmony_ci	if (!(srp = sg_add_request(sfp))) {
72862306a36Sopenharmony_ci		SCSI_LOG_TIMEOUT(1, sg_printk(KERN_INFO, sfp->parentdp,
72962306a36Sopenharmony_ci					      "sg_new_write: queue full\n"));
73062306a36Sopenharmony_ci		return -EDOM;
73162306a36Sopenharmony_ci	}
73262306a36Sopenharmony_ci	srp->sg_io_owned = sg_io_owned;
73362306a36Sopenharmony_ci	hp = &srp->header;
73462306a36Sopenharmony_ci	if (get_sg_io_hdr(hp, buf)) {
73562306a36Sopenharmony_ci		sg_remove_request(sfp, srp);
73662306a36Sopenharmony_ci		return -EFAULT;
73762306a36Sopenharmony_ci	}
73862306a36Sopenharmony_ci	if (hp->interface_id != 'S') {
73962306a36Sopenharmony_ci		sg_remove_request(sfp, srp);
74062306a36Sopenharmony_ci		return -ENOSYS;
74162306a36Sopenharmony_ci	}
74262306a36Sopenharmony_ci	if (hp->flags & SG_FLAG_MMAP_IO) {
74362306a36Sopenharmony_ci		if (hp->dxfer_len > sfp->reserve.bufflen) {
74462306a36Sopenharmony_ci			sg_remove_request(sfp, srp);
74562306a36Sopenharmony_ci			return -ENOMEM;	/* MMAP_IO size must fit in reserve buffer */
74662306a36Sopenharmony_ci		}
74762306a36Sopenharmony_ci		if (hp->flags & SG_FLAG_DIRECT_IO) {
74862306a36Sopenharmony_ci			sg_remove_request(sfp, srp);
74962306a36Sopenharmony_ci			return -EINVAL;	/* either MMAP_IO or DIRECT_IO (not both) */
75062306a36Sopenharmony_ci		}
75162306a36Sopenharmony_ci		if (sfp->res_in_use) {
75262306a36Sopenharmony_ci			sg_remove_request(sfp, srp);
75362306a36Sopenharmony_ci			return -EBUSY;	/* reserve buffer already being used */
75462306a36Sopenharmony_ci		}
75562306a36Sopenharmony_ci	}
75662306a36Sopenharmony_ci	ul_timeout = msecs_to_jiffies(srp->header.timeout);
75762306a36Sopenharmony_ci	timeout = (ul_timeout < INT_MAX) ? ul_timeout : INT_MAX;
75862306a36Sopenharmony_ci	if ((!hp->cmdp) || (hp->cmd_len < 6) || (hp->cmd_len > sizeof (cmnd))) {
75962306a36Sopenharmony_ci		sg_remove_request(sfp, srp);
76062306a36Sopenharmony_ci		return -EMSGSIZE;
76162306a36Sopenharmony_ci	}
76262306a36Sopenharmony_ci	if (copy_from_user(cmnd, hp->cmdp, hp->cmd_len)) {
76362306a36Sopenharmony_ci		sg_remove_request(sfp, srp);
76462306a36Sopenharmony_ci		return -EFAULT;
76562306a36Sopenharmony_ci	}
76662306a36Sopenharmony_ci	if (read_only && sg_allow_access(file, cmnd)) {
76762306a36Sopenharmony_ci		sg_remove_request(sfp, srp);
76862306a36Sopenharmony_ci		return -EPERM;
76962306a36Sopenharmony_ci	}
77062306a36Sopenharmony_ci	k = sg_common_write(sfp, srp, cmnd, timeout, blocking);
77162306a36Sopenharmony_ci	if (k < 0)
77262306a36Sopenharmony_ci		return k;
77362306a36Sopenharmony_ci	if (o_srp)
77462306a36Sopenharmony_ci		*o_srp = srp;
77562306a36Sopenharmony_ci	return count;
77662306a36Sopenharmony_ci}
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_cistatic int
77962306a36Sopenharmony_cisg_common_write(Sg_fd * sfp, Sg_request * srp,
78062306a36Sopenharmony_ci		unsigned char *cmnd, int timeout, int blocking)
78162306a36Sopenharmony_ci{
78262306a36Sopenharmony_ci	int k, at_head;
78362306a36Sopenharmony_ci	Sg_device *sdp = sfp->parentdp;
78462306a36Sopenharmony_ci	sg_io_hdr_t *hp = &srp->header;
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	srp->data.cmd_opcode = cmnd[0];	/* hold opcode of command */
78762306a36Sopenharmony_ci	hp->status = 0;
78862306a36Sopenharmony_ci	hp->masked_status = 0;
78962306a36Sopenharmony_ci	hp->msg_status = 0;
79062306a36Sopenharmony_ci	hp->info = 0;
79162306a36Sopenharmony_ci	hp->host_status = 0;
79262306a36Sopenharmony_ci	hp->driver_status = 0;
79362306a36Sopenharmony_ci	hp->resid = 0;
79462306a36Sopenharmony_ci	SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sfp->parentdp,
79562306a36Sopenharmony_ci			"sg_common_write:  scsi opcode=0x%02x, cmd_size=%d\n",
79662306a36Sopenharmony_ci			(int) cmnd[0], (int) hp->cmd_len));
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	if (hp->dxfer_len >= SZ_256M) {
79962306a36Sopenharmony_ci		sg_remove_request(sfp, srp);
80062306a36Sopenharmony_ci		return -EINVAL;
80162306a36Sopenharmony_ci	}
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	k = sg_start_req(srp, cmnd);
80462306a36Sopenharmony_ci	if (k) {
80562306a36Sopenharmony_ci		SCSI_LOG_TIMEOUT(1, sg_printk(KERN_INFO, sfp->parentdp,
80662306a36Sopenharmony_ci			"sg_common_write: start_req err=%d\n", k));
80762306a36Sopenharmony_ci		sg_finish_rem_req(srp);
80862306a36Sopenharmony_ci		sg_remove_request(sfp, srp);
80962306a36Sopenharmony_ci		return k;	/* probably out of space --> ENOMEM */
81062306a36Sopenharmony_ci	}
81162306a36Sopenharmony_ci	if (atomic_read(&sdp->detaching)) {
81262306a36Sopenharmony_ci		if (srp->bio) {
81362306a36Sopenharmony_ci			blk_mq_free_request(srp->rq);
81462306a36Sopenharmony_ci			srp->rq = NULL;
81562306a36Sopenharmony_ci		}
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci		sg_finish_rem_req(srp);
81862306a36Sopenharmony_ci		sg_remove_request(sfp, srp);
81962306a36Sopenharmony_ci		return -ENODEV;
82062306a36Sopenharmony_ci	}
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci	hp->duration = jiffies_to_msecs(jiffies);
82362306a36Sopenharmony_ci	if (hp->interface_id != '\0' &&	/* v3 (or later) interface */
82462306a36Sopenharmony_ci	    (SG_FLAG_Q_AT_TAIL & hp->flags))
82562306a36Sopenharmony_ci		at_head = 0;
82662306a36Sopenharmony_ci	else
82762306a36Sopenharmony_ci		at_head = 1;
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	srp->rq->timeout = timeout;
83062306a36Sopenharmony_ci	kref_get(&sfp->f_ref); /* sg_rq_end_io() does kref_put(). */
83162306a36Sopenharmony_ci	srp->rq->end_io = sg_rq_end_io;
83262306a36Sopenharmony_ci	blk_execute_rq_nowait(srp->rq, at_head);
83362306a36Sopenharmony_ci	return 0;
83462306a36Sopenharmony_ci}
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_cistatic int srp_done(Sg_fd *sfp, Sg_request *srp)
83762306a36Sopenharmony_ci{
83862306a36Sopenharmony_ci	unsigned long flags;
83962306a36Sopenharmony_ci	int ret;
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci	read_lock_irqsave(&sfp->rq_list_lock, flags);
84262306a36Sopenharmony_ci	ret = srp->done;
84362306a36Sopenharmony_ci	read_unlock_irqrestore(&sfp->rq_list_lock, flags);
84462306a36Sopenharmony_ci	return ret;
84562306a36Sopenharmony_ci}
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_cistatic int max_sectors_bytes(struct request_queue *q)
84862306a36Sopenharmony_ci{
84962306a36Sopenharmony_ci	unsigned int max_sectors = queue_max_sectors(q);
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	max_sectors = min_t(unsigned int, max_sectors, INT_MAX >> 9);
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	return max_sectors << 9;
85462306a36Sopenharmony_ci}
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_cistatic void
85762306a36Sopenharmony_cisg_fill_request_table(Sg_fd *sfp, sg_req_info_t *rinfo)
85862306a36Sopenharmony_ci{
85962306a36Sopenharmony_ci	Sg_request *srp;
86062306a36Sopenharmony_ci	int val;
86162306a36Sopenharmony_ci	unsigned int ms;
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	val = 0;
86462306a36Sopenharmony_ci	list_for_each_entry(srp, &sfp->rq_list, entry) {
86562306a36Sopenharmony_ci		if (val >= SG_MAX_QUEUE)
86662306a36Sopenharmony_ci			break;
86762306a36Sopenharmony_ci		rinfo[val].req_state = srp->done + 1;
86862306a36Sopenharmony_ci		rinfo[val].problem =
86962306a36Sopenharmony_ci			srp->header.masked_status &
87062306a36Sopenharmony_ci			srp->header.host_status &
87162306a36Sopenharmony_ci			srp->header.driver_status;
87262306a36Sopenharmony_ci		if (srp->done)
87362306a36Sopenharmony_ci			rinfo[val].duration =
87462306a36Sopenharmony_ci				srp->header.duration;
87562306a36Sopenharmony_ci		else {
87662306a36Sopenharmony_ci			ms = jiffies_to_msecs(jiffies);
87762306a36Sopenharmony_ci			rinfo[val].duration =
87862306a36Sopenharmony_ci				(ms > srp->header.duration) ?
87962306a36Sopenharmony_ci				(ms - srp->header.duration) : 0;
88062306a36Sopenharmony_ci		}
88162306a36Sopenharmony_ci		rinfo[val].orphan = srp->orphan;
88262306a36Sopenharmony_ci		rinfo[val].sg_io_owned = srp->sg_io_owned;
88362306a36Sopenharmony_ci		rinfo[val].pack_id = srp->header.pack_id;
88462306a36Sopenharmony_ci		rinfo[val].usr_ptr = srp->header.usr_ptr;
88562306a36Sopenharmony_ci		val++;
88662306a36Sopenharmony_ci	}
88762306a36Sopenharmony_ci}
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci#ifdef CONFIG_COMPAT
89062306a36Sopenharmony_cistruct compat_sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */
89162306a36Sopenharmony_ci	char req_state;
89262306a36Sopenharmony_ci	char orphan;
89362306a36Sopenharmony_ci	char sg_io_owned;
89462306a36Sopenharmony_ci	char problem;
89562306a36Sopenharmony_ci	int pack_id;
89662306a36Sopenharmony_ci	compat_uptr_t usr_ptr;
89762306a36Sopenharmony_ci	unsigned int duration;
89862306a36Sopenharmony_ci	int unused;
89962306a36Sopenharmony_ci};
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_cistatic int put_compat_request_table(struct compat_sg_req_info __user *o,
90262306a36Sopenharmony_ci				    struct sg_req_info *rinfo)
90362306a36Sopenharmony_ci{
90462306a36Sopenharmony_ci	int i;
90562306a36Sopenharmony_ci	for (i = 0; i < SG_MAX_QUEUE; i++) {
90662306a36Sopenharmony_ci		if (copy_to_user(o + i, rinfo + i, offsetof(sg_req_info_t, usr_ptr)) ||
90762306a36Sopenharmony_ci		    put_user((uintptr_t)rinfo[i].usr_ptr, &o[i].usr_ptr) ||
90862306a36Sopenharmony_ci		    put_user(rinfo[i].duration, &o[i].duration) ||
90962306a36Sopenharmony_ci		    put_user(rinfo[i].unused, &o[i].unused))
91062306a36Sopenharmony_ci			return -EFAULT;
91162306a36Sopenharmony_ci	}
91262306a36Sopenharmony_ci	return 0;
91362306a36Sopenharmony_ci}
91462306a36Sopenharmony_ci#endif
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_cistatic long
91762306a36Sopenharmony_cisg_ioctl_common(struct file *filp, Sg_device *sdp, Sg_fd *sfp,
91862306a36Sopenharmony_ci		unsigned int cmd_in, void __user *p)
91962306a36Sopenharmony_ci{
92062306a36Sopenharmony_ci	int __user *ip = p;
92162306a36Sopenharmony_ci	int result, val, read_only;
92262306a36Sopenharmony_ci	Sg_request *srp;
92362306a36Sopenharmony_ci	unsigned long iflags;
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp,
92662306a36Sopenharmony_ci				   "sg_ioctl: cmd=0x%x\n", (int) cmd_in));
92762306a36Sopenharmony_ci	read_only = (O_RDWR != (filp->f_flags & O_ACCMODE));
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	switch (cmd_in) {
93062306a36Sopenharmony_ci	case SG_IO:
93162306a36Sopenharmony_ci		if (atomic_read(&sdp->detaching))
93262306a36Sopenharmony_ci			return -ENODEV;
93362306a36Sopenharmony_ci		if (!scsi_block_when_processing_errors(sdp->device))
93462306a36Sopenharmony_ci			return -ENXIO;
93562306a36Sopenharmony_ci		result = sg_new_write(sfp, filp, p, SZ_SG_IO_HDR,
93662306a36Sopenharmony_ci				 1, read_only, 1, &srp);
93762306a36Sopenharmony_ci		if (result < 0)
93862306a36Sopenharmony_ci			return result;
93962306a36Sopenharmony_ci		result = wait_event_interruptible(sfp->read_wait,
94062306a36Sopenharmony_ci			srp_done(sfp, srp));
94162306a36Sopenharmony_ci		write_lock_irq(&sfp->rq_list_lock);
94262306a36Sopenharmony_ci		if (srp->done) {
94362306a36Sopenharmony_ci			srp->done = 2;
94462306a36Sopenharmony_ci			write_unlock_irq(&sfp->rq_list_lock);
94562306a36Sopenharmony_ci			result = sg_new_read(sfp, p, SZ_SG_IO_HDR, srp);
94662306a36Sopenharmony_ci			return (result < 0) ? result : 0;
94762306a36Sopenharmony_ci		}
94862306a36Sopenharmony_ci		srp->orphan = 1;
94962306a36Sopenharmony_ci		write_unlock_irq(&sfp->rq_list_lock);
95062306a36Sopenharmony_ci		return result;	/* -ERESTARTSYS because signal hit process */
95162306a36Sopenharmony_ci	case SG_SET_TIMEOUT:
95262306a36Sopenharmony_ci		result = get_user(val, ip);
95362306a36Sopenharmony_ci		if (result)
95462306a36Sopenharmony_ci			return result;
95562306a36Sopenharmony_ci		if (val < 0)
95662306a36Sopenharmony_ci			return -EIO;
95762306a36Sopenharmony_ci		if (val >= mult_frac((s64)INT_MAX, USER_HZ, HZ))
95862306a36Sopenharmony_ci			val = min_t(s64, mult_frac((s64)INT_MAX, USER_HZ, HZ),
95962306a36Sopenharmony_ci				    INT_MAX);
96062306a36Sopenharmony_ci		sfp->timeout_user = val;
96162306a36Sopenharmony_ci		sfp->timeout = mult_frac(val, HZ, USER_HZ);
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci		return 0;
96462306a36Sopenharmony_ci	case SG_GET_TIMEOUT:	/* N.B. User receives timeout as return value */
96562306a36Sopenharmony_ci				/* strange ..., for backward compatibility */
96662306a36Sopenharmony_ci		return sfp->timeout_user;
96762306a36Sopenharmony_ci	case SG_SET_FORCE_LOW_DMA:
96862306a36Sopenharmony_ci		/*
96962306a36Sopenharmony_ci		 * N.B. This ioctl never worked properly, but failed to
97062306a36Sopenharmony_ci		 * return an error value. So returning '0' to keep compability
97162306a36Sopenharmony_ci		 * with legacy applications.
97262306a36Sopenharmony_ci		 */
97362306a36Sopenharmony_ci		return 0;
97462306a36Sopenharmony_ci	case SG_GET_LOW_DMA:
97562306a36Sopenharmony_ci		return put_user(0, ip);
97662306a36Sopenharmony_ci	case SG_GET_SCSI_ID:
97762306a36Sopenharmony_ci		{
97862306a36Sopenharmony_ci			sg_scsi_id_t v;
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci			if (atomic_read(&sdp->detaching))
98162306a36Sopenharmony_ci				return -ENODEV;
98262306a36Sopenharmony_ci			memset(&v, 0, sizeof(v));
98362306a36Sopenharmony_ci			v.host_no = sdp->device->host->host_no;
98462306a36Sopenharmony_ci			v.channel = sdp->device->channel;
98562306a36Sopenharmony_ci			v.scsi_id = sdp->device->id;
98662306a36Sopenharmony_ci			v.lun = sdp->device->lun;
98762306a36Sopenharmony_ci			v.scsi_type = sdp->device->type;
98862306a36Sopenharmony_ci			v.h_cmd_per_lun = sdp->device->host->cmd_per_lun;
98962306a36Sopenharmony_ci			v.d_queue_depth = sdp->device->queue_depth;
99062306a36Sopenharmony_ci			if (copy_to_user(p, &v, sizeof(sg_scsi_id_t)))
99162306a36Sopenharmony_ci				return -EFAULT;
99262306a36Sopenharmony_ci			return 0;
99362306a36Sopenharmony_ci		}
99462306a36Sopenharmony_ci	case SG_SET_FORCE_PACK_ID:
99562306a36Sopenharmony_ci		result = get_user(val, ip);
99662306a36Sopenharmony_ci		if (result)
99762306a36Sopenharmony_ci			return result;
99862306a36Sopenharmony_ci		sfp->force_packid = val ? 1 : 0;
99962306a36Sopenharmony_ci		return 0;
100062306a36Sopenharmony_ci	case SG_GET_PACK_ID:
100162306a36Sopenharmony_ci		read_lock_irqsave(&sfp->rq_list_lock, iflags);
100262306a36Sopenharmony_ci		list_for_each_entry(srp, &sfp->rq_list, entry) {
100362306a36Sopenharmony_ci			if ((1 == srp->done) && (!srp->sg_io_owned)) {
100462306a36Sopenharmony_ci				read_unlock_irqrestore(&sfp->rq_list_lock,
100562306a36Sopenharmony_ci						       iflags);
100662306a36Sopenharmony_ci				return put_user(srp->header.pack_id, ip);
100762306a36Sopenharmony_ci			}
100862306a36Sopenharmony_ci		}
100962306a36Sopenharmony_ci		read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
101062306a36Sopenharmony_ci		return put_user(-1, ip);
101162306a36Sopenharmony_ci	case SG_GET_NUM_WAITING:
101262306a36Sopenharmony_ci		read_lock_irqsave(&sfp->rq_list_lock, iflags);
101362306a36Sopenharmony_ci		val = 0;
101462306a36Sopenharmony_ci		list_for_each_entry(srp, &sfp->rq_list, entry) {
101562306a36Sopenharmony_ci			if ((1 == srp->done) && (!srp->sg_io_owned))
101662306a36Sopenharmony_ci				++val;
101762306a36Sopenharmony_ci		}
101862306a36Sopenharmony_ci		read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
101962306a36Sopenharmony_ci		return put_user(val, ip);
102062306a36Sopenharmony_ci	case SG_GET_SG_TABLESIZE:
102162306a36Sopenharmony_ci		return put_user(sdp->sg_tablesize, ip);
102262306a36Sopenharmony_ci	case SG_SET_RESERVED_SIZE:
102362306a36Sopenharmony_ci		result = get_user(val, ip);
102462306a36Sopenharmony_ci		if (result)
102562306a36Sopenharmony_ci			return result;
102662306a36Sopenharmony_ci                if (val < 0)
102762306a36Sopenharmony_ci                        return -EINVAL;
102862306a36Sopenharmony_ci		val = min_t(int, val,
102962306a36Sopenharmony_ci			    max_sectors_bytes(sdp->device->request_queue));
103062306a36Sopenharmony_ci		mutex_lock(&sfp->f_mutex);
103162306a36Sopenharmony_ci		if (val != sfp->reserve.bufflen) {
103262306a36Sopenharmony_ci			if (sfp->mmap_called ||
103362306a36Sopenharmony_ci			    sfp->res_in_use) {
103462306a36Sopenharmony_ci				mutex_unlock(&sfp->f_mutex);
103562306a36Sopenharmony_ci				return -EBUSY;
103662306a36Sopenharmony_ci			}
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci			sg_remove_scat(sfp, &sfp->reserve);
103962306a36Sopenharmony_ci			sg_build_reserve(sfp, val);
104062306a36Sopenharmony_ci		}
104162306a36Sopenharmony_ci		mutex_unlock(&sfp->f_mutex);
104262306a36Sopenharmony_ci		return 0;
104362306a36Sopenharmony_ci	case SG_GET_RESERVED_SIZE:
104462306a36Sopenharmony_ci		val = min_t(int, sfp->reserve.bufflen,
104562306a36Sopenharmony_ci			    max_sectors_bytes(sdp->device->request_queue));
104662306a36Sopenharmony_ci		return put_user(val, ip);
104762306a36Sopenharmony_ci	case SG_SET_COMMAND_Q:
104862306a36Sopenharmony_ci		result = get_user(val, ip);
104962306a36Sopenharmony_ci		if (result)
105062306a36Sopenharmony_ci			return result;
105162306a36Sopenharmony_ci		sfp->cmd_q = val ? 1 : 0;
105262306a36Sopenharmony_ci		return 0;
105362306a36Sopenharmony_ci	case SG_GET_COMMAND_Q:
105462306a36Sopenharmony_ci		return put_user((int) sfp->cmd_q, ip);
105562306a36Sopenharmony_ci	case SG_SET_KEEP_ORPHAN:
105662306a36Sopenharmony_ci		result = get_user(val, ip);
105762306a36Sopenharmony_ci		if (result)
105862306a36Sopenharmony_ci			return result;
105962306a36Sopenharmony_ci		sfp->keep_orphan = val;
106062306a36Sopenharmony_ci		return 0;
106162306a36Sopenharmony_ci	case SG_GET_KEEP_ORPHAN:
106262306a36Sopenharmony_ci		return put_user((int) sfp->keep_orphan, ip);
106362306a36Sopenharmony_ci	case SG_NEXT_CMD_LEN:
106462306a36Sopenharmony_ci		result = get_user(val, ip);
106562306a36Sopenharmony_ci		if (result)
106662306a36Sopenharmony_ci			return result;
106762306a36Sopenharmony_ci		if (val > SG_MAX_CDB_SIZE)
106862306a36Sopenharmony_ci			return -ENOMEM;
106962306a36Sopenharmony_ci		sfp->next_cmd_len = (val > 0) ? val : 0;
107062306a36Sopenharmony_ci		return 0;
107162306a36Sopenharmony_ci	case SG_GET_VERSION_NUM:
107262306a36Sopenharmony_ci		return put_user(sg_version_num, ip);
107362306a36Sopenharmony_ci	case SG_GET_ACCESS_COUNT:
107462306a36Sopenharmony_ci		/* faked - we don't have a real access count anymore */
107562306a36Sopenharmony_ci		val = (sdp->device ? 1 : 0);
107662306a36Sopenharmony_ci		return put_user(val, ip);
107762306a36Sopenharmony_ci	case SG_GET_REQUEST_TABLE:
107862306a36Sopenharmony_ci		{
107962306a36Sopenharmony_ci			sg_req_info_t *rinfo;
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci			rinfo = kcalloc(SG_MAX_QUEUE, SZ_SG_REQ_INFO,
108262306a36Sopenharmony_ci					GFP_KERNEL);
108362306a36Sopenharmony_ci			if (!rinfo)
108462306a36Sopenharmony_ci				return -ENOMEM;
108562306a36Sopenharmony_ci			read_lock_irqsave(&sfp->rq_list_lock, iflags);
108662306a36Sopenharmony_ci			sg_fill_request_table(sfp, rinfo);
108762306a36Sopenharmony_ci			read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
108862306a36Sopenharmony_ci	#ifdef CONFIG_COMPAT
108962306a36Sopenharmony_ci			if (in_compat_syscall())
109062306a36Sopenharmony_ci				result = put_compat_request_table(p, rinfo);
109162306a36Sopenharmony_ci			else
109262306a36Sopenharmony_ci	#endif
109362306a36Sopenharmony_ci				result = copy_to_user(p, rinfo,
109462306a36Sopenharmony_ci						      SZ_SG_REQ_INFO * SG_MAX_QUEUE);
109562306a36Sopenharmony_ci			result = result ? -EFAULT : 0;
109662306a36Sopenharmony_ci			kfree(rinfo);
109762306a36Sopenharmony_ci			return result;
109862306a36Sopenharmony_ci		}
109962306a36Sopenharmony_ci	case SG_EMULATED_HOST:
110062306a36Sopenharmony_ci		if (atomic_read(&sdp->detaching))
110162306a36Sopenharmony_ci			return -ENODEV;
110262306a36Sopenharmony_ci		return put_user(sdp->device->host->hostt->emulated, ip);
110362306a36Sopenharmony_ci	case SCSI_IOCTL_SEND_COMMAND:
110462306a36Sopenharmony_ci		if (atomic_read(&sdp->detaching))
110562306a36Sopenharmony_ci			return -ENODEV;
110662306a36Sopenharmony_ci		return scsi_ioctl(sdp->device, filp->f_mode & FMODE_WRITE,
110762306a36Sopenharmony_ci				  cmd_in, p);
110862306a36Sopenharmony_ci	case SG_SET_DEBUG:
110962306a36Sopenharmony_ci		result = get_user(val, ip);
111062306a36Sopenharmony_ci		if (result)
111162306a36Sopenharmony_ci			return result;
111262306a36Sopenharmony_ci		sdp->sgdebug = (char) val;
111362306a36Sopenharmony_ci		return 0;
111462306a36Sopenharmony_ci	case BLKSECTGET:
111562306a36Sopenharmony_ci		return put_user(max_sectors_bytes(sdp->device->request_queue),
111662306a36Sopenharmony_ci				ip);
111762306a36Sopenharmony_ci	case BLKTRACESETUP:
111862306a36Sopenharmony_ci		return blk_trace_setup(sdp->device->request_queue, sdp->name,
111962306a36Sopenharmony_ci				       MKDEV(SCSI_GENERIC_MAJOR, sdp->index),
112062306a36Sopenharmony_ci				       NULL, p);
112162306a36Sopenharmony_ci	case BLKTRACESTART:
112262306a36Sopenharmony_ci		return blk_trace_startstop(sdp->device->request_queue, 1);
112362306a36Sopenharmony_ci	case BLKTRACESTOP:
112462306a36Sopenharmony_ci		return blk_trace_startstop(sdp->device->request_queue, 0);
112562306a36Sopenharmony_ci	case BLKTRACETEARDOWN:
112662306a36Sopenharmony_ci		return blk_trace_remove(sdp->device->request_queue);
112762306a36Sopenharmony_ci	case SCSI_IOCTL_GET_IDLUN:
112862306a36Sopenharmony_ci	case SCSI_IOCTL_GET_BUS_NUMBER:
112962306a36Sopenharmony_ci	case SCSI_IOCTL_PROBE_HOST:
113062306a36Sopenharmony_ci	case SG_GET_TRANSFORM:
113162306a36Sopenharmony_ci	case SG_SCSI_RESET:
113262306a36Sopenharmony_ci		if (atomic_read(&sdp->detaching))
113362306a36Sopenharmony_ci			return -ENODEV;
113462306a36Sopenharmony_ci		break;
113562306a36Sopenharmony_ci	default:
113662306a36Sopenharmony_ci		if (read_only)
113762306a36Sopenharmony_ci			return -EPERM;	/* don't know so take safe approach */
113862306a36Sopenharmony_ci		break;
113962306a36Sopenharmony_ci	}
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci	result = scsi_ioctl_block_when_processing_errors(sdp->device,
114262306a36Sopenharmony_ci			cmd_in, filp->f_flags & O_NDELAY);
114362306a36Sopenharmony_ci	if (result)
114462306a36Sopenharmony_ci		return result;
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci	return -ENOIOCTLCMD;
114762306a36Sopenharmony_ci}
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_cistatic long
115062306a36Sopenharmony_cisg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
115162306a36Sopenharmony_ci{
115262306a36Sopenharmony_ci	void __user *p = (void __user *)arg;
115362306a36Sopenharmony_ci	Sg_device *sdp;
115462306a36Sopenharmony_ci	Sg_fd *sfp;
115562306a36Sopenharmony_ci	int ret;
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
115862306a36Sopenharmony_ci		return -ENXIO;
115962306a36Sopenharmony_ci
116062306a36Sopenharmony_ci	ret = sg_ioctl_common(filp, sdp, sfp, cmd_in, p);
116162306a36Sopenharmony_ci	if (ret != -ENOIOCTLCMD)
116262306a36Sopenharmony_ci		return ret;
116362306a36Sopenharmony_ci	return scsi_ioctl(sdp->device, filp->f_mode & FMODE_WRITE, cmd_in, p);
116462306a36Sopenharmony_ci}
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_cistatic __poll_t
116762306a36Sopenharmony_cisg_poll(struct file *filp, poll_table * wait)
116862306a36Sopenharmony_ci{
116962306a36Sopenharmony_ci	__poll_t res = 0;
117062306a36Sopenharmony_ci	Sg_device *sdp;
117162306a36Sopenharmony_ci	Sg_fd *sfp;
117262306a36Sopenharmony_ci	Sg_request *srp;
117362306a36Sopenharmony_ci	int count = 0;
117462306a36Sopenharmony_ci	unsigned long iflags;
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci	sfp = filp->private_data;
117762306a36Sopenharmony_ci	if (!sfp)
117862306a36Sopenharmony_ci		return EPOLLERR;
117962306a36Sopenharmony_ci	sdp = sfp->parentdp;
118062306a36Sopenharmony_ci	if (!sdp)
118162306a36Sopenharmony_ci		return EPOLLERR;
118262306a36Sopenharmony_ci	poll_wait(filp, &sfp->read_wait, wait);
118362306a36Sopenharmony_ci	read_lock_irqsave(&sfp->rq_list_lock, iflags);
118462306a36Sopenharmony_ci	list_for_each_entry(srp, &sfp->rq_list, entry) {
118562306a36Sopenharmony_ci		/* if any read waiting, flag it */
118662306a36Sopenharmony_ci		if ((0 == res) && (1 == srp->done) && (!srp->sg_io_owned))
118762306a36Sopenharmony_ci			res = EPOLLIN | EPOLLRDNORM;
118862306a36Sopenharmony_ci		++count;
118962306a36Sopenharmony_ci	}
119062306a36Sopenharmony_ci	read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci	if (atomic_read(&sdp->detaching))
119362306a36Sopenharmony_ci		res |= EPOLLHUP;
119462306a36Sopenharmony_ci	else if (!sfp->cmd_q) {
119562306a36Sopenharmony_ci		if (0 == count)
119662306a36Sopenharmony_ci			res |= EPOLLOUT | EPOLLWRNORM;
119762306a36Sopenharmony_ci	} else if (count < SG_MAX_QUEUE)
119862306a36Sopenharmony_ci		res |= EPOLLOUT | EPOLLWRNORM;
119962306a36Sopenharmony_ci	SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp,
120062306a36Sopenharmony_ci				      "sg_poll: res=0x%x\n", (__force u32) res));
120162306a36Sopenharmony_ci	return res;
120262306a36Sopenharmony_ci}
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_cistatic int
120562306a36Sopenharmony_cisg_fasync(int fd, struct file *filp, int mode)
120662306a36Sopenharmony_ci{
120762306a36Sopenharmony_ci	Sg_device *sdp;
120862306a36Sopenharmony_ci	Sg_fd *sfp;
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
121162306a36Sopenharmony_ci		return -ENXIO;
121262306a36Sopenharmony_ci	SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp,
121362306a36Sopenharmony_ci				      "sg_fasync: mode=%d\n", mode));
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ci	return fasync_helper(fd, filp, mode, &sfp->async_qp);
121662306a36Sopenharmony_ci}
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_cistatic vm_fault_t
121962306a36Sopenharmony_cisg_vma_fault(struct vm_fault *vmf)
122062306a36Sopenharmony_ci{
122162306a36Sopenharmony_ci	struct vm_area_struct *vma = vmf->vma;
122262306a36Sopenharmony_ci	Sg_fd *sfp;
122362306a36Sopenharmony_ci	unsigned long offset, len, sa;
122462306a36Sopenharmony_ci	Sg_scatter_hold *rsv_schp;
122562306a36Sopenharmony_ci	int k, length;
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ci	if ((NULL == vma) || (!(sfp = (Sg_fd *) vma->vm_private_data)))
122862306a36Sopenharmony_ci		return VM_FAULT_SIGBUS;
122962306a36Sopenharmony_ci	rsv_schp = &sfp->reserve;
123062306a36Sopenharmony_ci	offset = vmf->pgoff << PAGE_SHIFT;
123162306a36Sopenharmony_ci	if (offset >= rsv_schp->bufflen)
123262306a36Sopenharmony_ci		return VM_FAULT_SIGBUS;
123362306a36Sopenharmony_ci	SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sfp->parentdp,
123462306a36Sopenharmony_ci				      "sg_vma_fault: offset=%lu, scatg=%d\n",
123562306a36Sopenharmony_ci				      offset, rsv_schp->k_use_sg));
123662306a36Sopenharmony_ci	sa = vma->vm_start;
123762306a36Sopenharmony_ci	length = 1 << (PAGE_SHIFT + rsv_schp->page_order);
123862306a36Sopenharmony_ci	for (k = 0; k < rsv_schp->k_use_sg && sa < vma->vm_end; k++) {
123962306a36Sopenharmony_ci		len = vma->vm_end - sa;
124062306a36Sopenharmony_ci		len = (len < length) ? len : length;
124162306a36Sopenharmony_ci		if (offset < len) {
124262306a36Sopenharmony_ci			struct page *page = nth_page(rsv_schp->pages[k],
124362306a36Sopenharmony_ci						     offset >> PAGE_SHIFT);
124462306a36Sopenharmony_ci			get_page(page);	/* increment page count */
124562306a36Sopenharmony_ci			vmf->page = page;
124662306a36Sopenharmony_ci			return 0; /* success */
124762306a36Sopenharmony_ci		}
124862306a36Sopenharmony_ci		sa += len;
124962306a36Sopenharmony_ci		offset -= len;
125062306a36Sopenharmony_ci	}
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci	return VM_FAULT_SIGBUS;
125362306a36Sopenharmony_ci}
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_cistatic const struct vm_operations_struct sg_mmap_vm_ops = {
125662306a36Sopenharmony_ci	.fault = sg_vma_fault,
125762306a36Sopenharmony_ci};
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_cistatic int
126062306a36Sopenharmony_cisg_mmap(struct file *filp, struct vm_area_struct *vma)
126162306a36Sopenharmony_ci{
126262306a36Sopenharmony_ci	Sg_fd *sfp;
126362306a36Sopenharmony_ci	unsigned long req_sz, len, sa;
126462306a36Sopenharmony_ci	Sg_scatter_hold *rsv_schp;
126562306a36Sopenharmony_ci	int k, length;
126662306a36Sopenharmony_ci	int ret = 0;
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci	if ((!filp) || (!vma) || (!(sfp = (Sg_fd *) filp->private_data)))
126962306a36Sopenharmony_ci		return -ENXIO;
127062306a36Sopenharmony_ci	req_sz = vma->vm_end - vma->vm_start;
127162306a36Sopenharmony_ci	SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sfp->parentdp,
127262306a36Sopenharmony_ci				      "sg_mmap starting, vm_start=%p, len=%d\n",
127362306a36Sopenharmony_ci				      (void *) vma->vm_start, (int) req_sz));
127462306a36Sopenharmony_ci	if (vma->vm_pgoff)
127562306a36Sopenharmony_ci		return -EINVAL;	/* want no offset */
127662306a36Sopenharmony_ci	rsv_schp = &sfp->reserve;
127762306a36Sopenharmony_ci	mutex_lock(&sfp->f_mutex);
127862306a36Sopenharmony_ci	if (req_sz > rsv_schp->bufflen) {
127962306a36Sopenharmony_ci		ret = -ENOMEM;	/* cannot map more than reserved buffer */
128062306a36Sopenharmony_ci		goto out;
128162306a36Sopenharmony_ci	}
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci	sa = vma->vm_start;
128462306a36Sopenharmony_ci	length = 1 << (PAGE_SHIFT + rsv_schp->page_order);
128562306a36Sopenharmony_ci	for (k = 0; k < rsv_schp->k_use_sg && sa < vma->vm_end; k++) {
128662306a36Sopenharmony_ci		len = vma->vm_end - sa;
128762306a36Sopenharmony_ci		len = (len < length) ? len : length;
128862306a36Sopenharmony_ci		sa += len;
128962306a36Sopenharmony_ci	}
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	sfp->mmap_called = 1;
129262306a36Sopenharmony_ci	vm_flags_set(vma, VM_IO | VM_DONTEXPAND | VM_DONTDUMP);
129362306a36Sopenharmony_ci	vma->vm_private_data = sfp;
129462306a36Sopenharmony_ci	vma->vm_ops = &sg_mmap_vm_ops;
129562306a36Sopenharmony_ciout:
129662306a36Sopenharmony_ci	mutex_unlock(&sfp->f_mutex);
129762306a36Sopenharmony_ci	return ret;
129862306a36Sopenharmony_ci}
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_cistatic void
130162306a36Sopenharmony_cisg_rq_end_io_usercontext(struct work_struct *work)
130262306a36Sopenharmony_ci{
130362306a36Sopenharmony_ci	struct sg_request *srp = container_of(work, struct sg_request, ew.work);
130462306a36Sopenharmony_ci	struct sg_fd *sfp = srp->parentfp;
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci	sg_finish_rem_req(srp);
130762306a36Sopenharmony_ci	sg_remove_request(sfp, srp);
130862306a36Sopenharmony_ci	kref_put(&sfp->f_ref, sg_remove_sfp);
130962306a36Sopenharmony_ci}
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci/*
131262306a36Sopenharmony_ci * This function is a "bottom half" handler that is called by the mid
131362306a36Sopenharmony_ci * level when a command is completed (or has failed).
131462306a36Sopenharmony_ci */
131562306a36Sopenharmony_cistatic enum rq_end_io_ret
131662306a36Sopenharmony_cisg_rq_end_io(struct request *rq, blk_status_t status)
131762306a36Sopenharmony_ci{
131862306a36Sopenharmony_ci	struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(rq);
131962306a36Sopenharmony_ci	struct sg_request *srp = rq->end_io_data;
132062306a36Sopenharmony_ci	Sg_device *sdp;
132162306a36Sopenharmony_ci	Sg_fd *sfp;
132262306a36Sopenharmony_ci	unsigned long iflags;
132362306a36Sopenharmony_ci	unsigned int ms;
132462306a36Sopenharmony_ci	char *sense;
132562306a36Sopenharmony_ci	int result, resid, done = 1;
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci	if (WARN_ON(srp->done != 0))
132862306a36Sopenharmony_ci		return RQ_END_IO_NONE;
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci	sfp = srp->parentfp;
133162306a36Sopenharmony_ci	if (WARN_ON(sfp == NULL))
133262306a36Sopenharmony_ci		return RQ_END_IO_NONE;
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci	sdp = sfp->parentdp;
133562306a36Sopenharmony_ci	if (unlikely(atomic_read(&sdp->detaching)))
133662306a36Sopenharmony_ci		pr_info("%s: device detaching\n", __func__);
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	sense = scmd->sense_buffer;
133962306a36Sopenharmony_ci	result = scmd->result;
134062306a36Sopenharmony_ci	resid = scmd->resid_len;
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci	SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sdp,
134362306a36Sopenharmony_ci				      "sg_cmd_done: pack_id=%d, res=0x%x\n",
134462306a36Sopenharmony_ci				      srp->header.pack_id, result));
134562306a36Sopenharmony_ci	srp->header.resid = resid;
134662306a36Sopenharmony_ci	ms = jiffies_to_msecs(jiffies);
134762306a36Sopenharmony_ci	srp->header.duration = (ms > srp->header.duration) ?
134862306a36Sopenharmony_ci				(ms - srp->header.duration) : 0;
134962306a36Sopenharmony_ci	if (0 != result) {
135062306a36Sopenharmony_ci		struct scsi_sense_hdr sshdr;
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci		srp->header.status = 0xff & result;
135362306a36Sopenharmony_ci		srp->header.masked_status = sg_status_byte(result);
135462306a36Sopenharmony_ci		srp->header.msg_status = COMMAND_COMPLETE;
135562306a36Sopenharmony_ci		srp->header.host_status = host_byte(result);
135662306a36Sopenharmony_ci		srp->header.driver_status = driver_byte(result);
135762306a36Sopenharmony_ci		if ((sdp->sgdebug > 0) &&
135862306a36Sopenharmony_ci		    ((CHECK_CONDITION == srp->header.masked_status) ||
135962306a36Sopenharmony_ci		     (COMMAND_TERMINATED == srp->header.masked_status)))
136062306a36Sopenharmony_ci			__scsi_print_sense(sdp->device, __func__, sense,
136162306a36Sopenharmony_ci					   SCSI_SENSE_BUFFERSIZE);
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci		/* Following if statement is a patch supplied by Eric Youngdale */
136462306a36Sopenharmony_ci		if (driver_byte(result) != 0
136562306a36Sopenharmony_ci		    && scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr)
136662306a36Sopenharmony_ci		    && !scsi_sense_is_deferred(&sshdr)
136762306a36Sopenharmony_ci		    && sshdr.sense_key == UNIT_ATTENTION
136862306a36Sopenharmony_ci		    && sdp->device->removable) {
136962306a36Sopenharmony_ci			/* Detected possible disc change. Set the bit - this */
137062306a36Sopenharmony_ci			/* may be used if there are filesystems using this device */
137162306a36Sopenharmony_ci			sdp->device->changed = 1;
137262306a36Sopenharmony_ci		}
137362306a36Sopenharmony_ci	}
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci	if (scmd->sense_len)
137662306a36Sopenharmony_ci		memcpy(srp->sense_b, scmd->sense_buffer, SCSI_SENSE_BUFFERSIZE);
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_ci	/* Rely on write phase to clean out srp status values, so no "else" */
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_ci	/*
138162306a36Sopenharmony_ci	 * Free the request as soon as it is complete so that its resources
138262306a36Sopenharmony_ci	 * can be reused without waiting for userspace to read() the
138362306a36Sopenharmony_ci	 * result.  But keep the associated bio (if any) around until
138462306a36Sopenharmony_ci	 * blk_rq_unmap_user() can be called from user context.
138562306a36Sopenharmony_ci	 */
138662306a36Sopenharmony_ci	srp->rq = NULL;
138762306a36Sopenharmony_ci	blk_mq_free_request(rq);
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci	write_lock_irqsave(&sfp->rq_list_lock, iflags);
139062306a36Sopenharmony_ci	if (unlikely(srp->orphan)) {
139162306a36Sopenharmony_ci		if (sfp->keep_orphan)
139262306a36Sopenharmony_ci			srp->sg_io_owned = 0;
139362306a36Sopenharmony_ci		else
139462306a36Sopenharmony_ci			done = 0;
139562306a36Sopenharmony_ci	}
139662306a36Sopenharmony_ci	srp->done = done;
139762306a36Sopenharmony_ci	write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci	if (likely(done)) {
140062306a36Sopenharmony_ci		/* Now wake up any sg_read() that is waiting for this
140162306a36Sopenharmony_ci		 * packet.
140262306a36Sopenharmony_ci		 */
140362306a36Sopenharmony_ci		wake_up_interruptible(&sfp->read_wait);
140462306a36Sopenharmony_ci		kill_fasync(&sfp->async_qp, SIGPOLL, POLL_IN);
140562306a36Sopenharmony_ci		kref_put(&sfp->f_ref, sg_remove_sfp);
140662306a36Sopenharmony_ci	} else {
140762306a36Sopenharmony_ci		INIT_WORK(&srp->ew.work, sg_rq_end_io_usercontext);
140862306a36Sopenharmony_ci		schedule_work(&srp->ew.work);
140962306a36Sopenharmony_ci	}
141062306a36Sopenharmony_ci	return RQ_END_IO_NONE;
141162306a36Sopenharmony_ci}
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_cistatic const struct file_operations sg_fops = {
141462306a36Sopenharmony_ci	.owner = THIS_MODULE,
141562306a36Sopenharmony_ci	.read = sg_read,
141662306a36Sopenharmony_ci	.write = sg_write,
141762306a36Sopenharmony_ci	.poll = sg_poll,
141862306a36Sopenharmony_ci	.unlocked_ioctl = sg_ioctl,
141962306a36Sopenharmony_ci	.compat_ioctl = compat_ptr_ioctl,
142062306a36Sopenharmony_ci	.open = sg_open,
142162306a36Sopenharmony_ci	.mmap = sg_mmap,
142262306a36Sopenharmony_ci	.release = sg_release,
142362306a36Sopenharmony_ci	.fasync = sg_fasync,
142462306a36Sopenharmony_ci	.llseek = no_llseek,
142562306a36Sopenharmony_ci};
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_cistatic struct class *sg_sysfs_class;
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_cistatic int sg_sysfs_valid = 0;
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_cistatic Sg_device *
143262306a36Sopenharmony_cisg_alloc(struct scsi_device *scsidp)
143362306a36Sopenharmony_ci{
143462306a36Sopenharmony_ci	struct request_queue *q = scsidp->request_queue;
143562306a36Sopenharmony_ci	Sg_device *sdp;
143662306a36Sopenharmony_ci	unsigned long iflags;
143762306a36Sopenharmony_ci	int error;
143862306a36Sopenharmony_ci	u32 k;
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci	sdp = kzalloc(sizeof(Sg_device), GFP_KERNEL);
144162306a36Sopenharmony_ci	if (!sdp) {
144262306a36Sopenharmony_ci		sdev_printk(KERN_WARNING, scsidp, "%s: kmalloc Sg_device "
144362306a36Sopenharmony_ci			    "failure\n", __func__);
144462306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
144562306a36Sopenharmony_ci	}
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci	idr_preload(GFP_KERNEL);
144862306a36Sopenharmony_ci	write_lock_irqsave(&sg_index_lock, iflags);
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_ci	error = idr_alloc(&sg_index_idr, sdp, 0, SG_MAX_DEVS, GFP_NOWAIT);
145162306a36Sopenharmony_ci	if (error < 0) {
145262306a36Sopenharmony_ci		if (error == -ENOSPC) {
145362306a36Sopenharmony_ci			sdev_printk(KERN_WARNING, scsidp,
145462306a36Sopenharmony_ci				    "Unable to attach sg device type=%d, minor number exceeds %d\n",
145562306a36Sopenharmony_ci				    scsidp->type, SG_MAX_DEVS - 1);
145662306a36Sopenharmony_ci			error = -ENODEV;
145762306a36Sopenharmony_ci		} else {
145862306a36Sopenharmony_ci			sdev_printk(KERN_WARNING, scsidp, "%s: idr "
145962306a36Sopenharmony_ci				    "allocation Sg_device failure: %d\n",
146062306a36Sopenharmony_ci				    __func__, error);
146162306a36Sopenharmony_ci		}
146262306a36Sopenharmony_ci		goto out_unlock;
146362306a36Sopenharmony_ci	}
146462306a36Sopenharmony_ci	k = error;
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci	SCSI_LOG_TIMEOUT(3, sdev_printk(KERN_INFO, scsidp,
146762306a36Sopenharmony_ci					"sg_alloc: dev=%d \n", k));
146862306a36Sopenharmony_ci	sprintf(sdp->name, "sg%d", k);
146962306a36Sopenharmony_ci	sdp->device = scsidp;
147062306a36Sopenharmony_ci	mutex_init(&sdp->open_rel_lock);
147162306a36Sopenharmony_ci	INIT_LIST_HEAD(&sdp->sfds);
147262306a36Sopenharmony_ci	init_waitqueue_head(&sdp->open_wait);
147362306a36Sopenharmony_ci	atomic_set(&sdp->detaching, 0);
147462306a36Sopenharmony_ci	rwlock_init(&sdp->sfd_lock);
147562306a36Sopenharmony_ci	sdp->sg_tablesize = queue_max_segments(q);
147662306a36Sopenharmony_ci	sdp->index = k;
147762306a36Sopenharmony_ci	kref_init(&sdp->d_ref);
147862306a36Sopenharmony_ci	error = 0;
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_ciout_unlock:
148162306a36Sopenharmony_ci	write_unlock_irqrestore(&sg_index_lock, iflags);
148262306a36Sopenharmony_ci	idr_preload_end();
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_ci	if (error) {
148562306a36Sopenharmony_ci		kfree(sdp);
148662306a36Sopenharmony_ci		return ERR_PTR(error);
148762306a36Sopenharmony_ci	}
148862306a36Sopenharmony_ci	return sdp;
148962306a36Sopenharmony_ci}
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_cistatic int
149262306a36Sopenharmony_cisg_add_device(struct device *cl_dev)
149362306a36Sopenharmony_ci{
149462306a36Sopenharmony_ci	struct scsi_device *scsidp = to_scsi_device(cl_dev->parent);
149562306a36Sopenharmony_ci	Sg_device *sdp = NULL;
149662306a36Sopenharmony_ci	struct cdev * cdev = NULL;
149762306a36Sopenharmony_ci	int error;
149862306a36Sopenharmony_ci	unsigned long iflags;
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci	if (!blk_get_queue(scsidp->request_queue)) {
150162306a36Sopenharmony_ci		pr_warn("%s: get scsi_device queue failed\n", __func__);
150262306a36Sopenharmony_ci		return -ENODEV;
150362306a36Sopenharmony_ci	}
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ci	error = -ENOMEM;
150662306a36Sopenharmony_ci	cdev = cdev_alloc();
150762306a36Sopenharmony_ci	if (!cdev) {
150862306a36Sopenharmony_ci		pr_warn("%s: cdev_alloc failed\n", __func__);
150962306a36Sopenharmony_ci		goto out;
151062306a36Sopenharmony_ci	}
151162306a36Sopenharmony_ci	cdev->owner = THIS_MODULE;
151262306a36Sopenharmony_ci	cdev->ops = &sg_fops;
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci	sdp = sg_alloc(scsidp);
151562306a36Sopenharmony_ci	if (IS_ERR(sdp)) {
151662306a36Sopenharmony_ci		pr_warn("%s: sg_alloc failed\n", __func__);
151762306a36Sopenharmony_ci		error = PTR_ERR(sdp);
151862306a36Sopenharmony_ci		goto out;
151962306a36Sopenharmony_ci	}
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	error = cdev_add(cdev, MKDEV(SCSI_GENERIC_MAJOR, sdp->index), 1);
152262306a36Sopenharmony_ci	if (error)
152362306a36Sopenharmony_ci		goto cdev_add_err;
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_ci	sdp->cdev = cdev;
152662306a36Sopenharmony_ci	if (sg_sysfs_valid) {
152762306a36Sopenharmony_ci		struct device *sg_class_member;
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci		sg_class_member = device_create(sg_sysfs_class, cl_dev->parent,
153062306a36Sopenharmony_ci						MKDEV(SCSI_GENERIC_MAJOR,
153162306a36Sopenharmony_ci						      sdp->index),
153262306a36Sopenharmony_ci						sdp, "%s", sdp->name);
153362306a36Sopenharmony_ci		if (IS_ERR(sg_class_member)) {
153462306a36Sopenharmony_ci			pr_err("%s: device_create failed\n", __func__);
153562306a36Sopenharmony_ci			error = PTR_ERR(sg_class_member);
153662306a36Sopenharmony_ci			goto cdev_add_err;
153762306a36Sopenharmony_ci		}
153862306a36Sopenharmony_ci		error = sysfs_create_link(&scsidp->sdev_gendev.kobj,
153962306a36Sopenharmony_ci					  &sg_class_member->kobj, "generic");
154062306a36Sopenharmony_ci		if (error)
154162306a36Sopenharmony_ci			pr_err("%s: unable to make symlink 'generic' back "
154262306a36Sopenharmony_ci			       "to sg%d\n", __func__, sdp->index);
154362306a36Sopenharmony_ci	} else
154462306a36Sopenharmony_ci		pr_warn("%s: sg_sys Invalid\n", __func__);
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci	sdev_printk(KERN_NOTICE, scsidp, "Attached scsi generic sg%d "
154762306a36Sopenharmony_ci		    "type %d\n", sdp->index, scsidp->type);
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci	dev_set_drvdata(cl_dev, sdp);
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_ci	return 0;
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_cicdev_add_err:
155462306a36Sopenharmony_ci	write_lock_irqsave(&sg_index_lock, iflags);
155562306a36Sopenharmony_ci	idr_remove(&sg_index_idr, sdp->index);
155662306a36Sopenharmony_ci	write_unlock_irqrestore(&sg_index_lock, iflags);
155762306a36Sopenharmony_ci	kfree(sdp);
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_ciout:
156062306a36Sopenharmony_ci	if (cdev)
156162306a36Sopenharmony_ci		cdev_del(cdev);
156262306a36Sopenharmony_ci	blk_put_queue(scsidp->request_queue);
156362306a36Sopenharmony_ci	return error;
156462306a36Sopenharmony_ci}
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_cistatic void
156762306a36Sopenharmony_cisg_device_destroy(struct kref *kref)
156862306a36Sopenharmony_ci{
156962306a36Sopenharmony_ci	struct sg_device *sdp = container_of(kref, struct sg_device, d_ref);
157062306a36Sopenharmony_ci	struct request_queue *q = sdp->device->request_queue;
157162306a36Sopenharmony_ci	unsigned long flags;
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_ci	/* CAUTION!  Note that the device can still be found via idr_find()
157462306a36Sopenharmony_ci	 * even though the refcount is 0.  Therefore, do idr_remove() BEFORE
157562306a36Sopenharmony_ci	 * any other cleanup.
157662306a36Sopenharmony_ci	 */
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ci	blk_trace_remove(q);
157962306a36Sopenharmony_ci	blk_put_queue(q);
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_ci	write_lock_irqsave(&sg_index_lock, flags);
158262306a36Sopenharmony_ci	idr_remove(&sg_index_idr, sdp->index);
158362306a36Sopenharmony_ci	write_unlock_irqrestore(&sg_index_lock, flags);
158462306a36Sopenharmony_ci
158562306a36Sopenharmony_ci	SCSI_LOG_TIMEOUT(3,
158662306a36Sopenharmony_ci		sg_printk(KERN_INFO, sdp, "sg_device_destroy\n"));
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_ci	kfree(sdp);
158962306a36Sopenharmony_ci}
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_cistatic void
159262306a36Sopenharmony_cisg_remove_device(struct device *cl_dev)
159362306a36Sopenharmony_ci{
159462306a36Sopenharmony_ci	struct scsi_device *scsidp = to_scsi_device(cl_dev->parent);
159562306a36Sopenharmony_ci	Sg_device *sdp = dev_get_drvdata(cl_dev);
159662306a36Sopenharmony_ci	unsigned long iflags;
159762306a36Sopenharmony_ci	Sg_fd *sfp;
159862306a36Sopenharmony_ci	int val;
159962306a36Sopenharmony_ci
160062306a36Sopenharmony_ci	if (!sdp)
160162306a36Sopenharmony_ci		return;
160262306a36Sopenharmony_ci	/* want sdp->detaching non-zero as soon as possible */
160362306a36Sopenharmony_ci	val = atomic_inc_return(&sdp->detaching);
160462306a36Sopenharmony_ci	if (val > 1)
160562306a36Sopenharmony_ci		return; /* only want to do following once per device */
160662306a36Sopenharmony_ci
160762306a36Sopenharmony_ci	SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp,
160862306a36Sopenharmony_ci				      "%s\n", __func__));
160962306a36Sopenharmony_ci
161062306a36Sopenharmony_ci	read_lock_irqsave(&sdp->sfd_lock, iflags);
161162306a36Sopenharmony_ci	list_for_each_entry(sfp, &sdp->sfds, sfd_siblings) {
161262306a36Sopenharmony_ci		wake_up_interruptible_all(&sfp->read_wait);
161362306a36Sopenharmony_ci		kill_fasync(&sfp->async_qp, SIGPOLL, POLL_HUP);
161462306a36Sopenharmony_ci	}
161562306a36Sopenharmony_ci	wake_up_interruptible_all(&sdp->open_wait);
161662306a36Sopenharmony_ci	read_unlock_irqrestore(&sdp->sfd_lock, iflags);
161762306a36Sopenharmony_ci
161862306a36Sopenharmony_ci	sysfs_remove_link(&scsidp->sdev_gendev.kobj, "generic");
161962306a36Sopenharmony_ci	device_destroy(sg_sysfs_class, MKDEV(SCSI_GENERIC_MAJOR, sdp->index));
162062306a36Sopenharmony_ci	cdev_del(sdp->cdev);
162162306a36Sopenharmony_ci	sdp->cdev = NULL;
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_ci	kref_put(&sdp->d_ref, sg_device_destroy);
162462306a36Sopenharmony_ci}
162562306a36Sopenharmony_ci
162662306a36Sopenharmony_cimodule_param_named(scatter_elem_sz, scatter_elem_sz, int, S_IRUGO | S_IWUSR);
162762306a36Sopenharmony_cimodule_param_named(def_reserved_size, def_reserved_size, int,
162862306a36Sopenharmony_ci		   S_IRUGO | S_IWUSR);
162962306a36Sopenharmony_cimodule_param_named(allow_dio, sg_allow_dio, int, S_IRUGO | S_IWUSR);
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ciMODULE_AUTHOR("Douglas Gilbert");
163262306a36Sopenharmony_ciMODULE_DESCRIPTION("SCSI generic (sg) driver");
163362306a36Sopenharmony_ciMODULE_LICENSE("GPL");
163462306a36Sopenharmony_ciMODULE_VERSION(SG_VERSION_STR);
163562306a36Sopenharmony_ciMODULE_ALIAS_CHARDEV_MAJOR(SCSI_GENERIC_MAJOR);
163662306a36Sopenharmony_ci
163762306a36Sopenharmony_ciMODULE_PARM_DESC(scatter_elem_sz, "scatter gather element "
163862306a36Sopenharmony_ci                "size (default: max(SG_SCATTER_SZ, PAGE_SIZE))");
163962306a36Sopenharmony_ciMODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd");
164062306a36Sopenharmony_ciMODULE_PARM_DESC(allow_dio, "allow direct I/O (default: 0 (disallow))");
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci#ifdef CONFIG_SYSCTL
164362306a36Sopenharmony_ci#include <linux/sysctl.h>
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_cistatic struct ctl_table sg_sysctls[] = {
164662306a36Sopenharmony_ci	{
164762306a36Sopenharmony_ci		.procname	= "sg-big-buff",
164862306a36Sopenharmony_ci		.data		= &sg_big_buff,
164962306a36Sopenharmony_ci		.maxlen		= sizeof(int),
165062306a36Sopenharmony_ci		.mode		= 0444,
165162306a36Sopenharmony_ci		.proc_handler	= proc_dointvec,
165262306a36Sopenharmony_ci	},
165362306a36Sopenharmony_ci	{}
165462306a36Sopenharmony_ci};
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_cistatic struct ctl_table_header *hdr;
165762306a36Sopenharmony_cistatic void register_sg_sysctls(void)
165862306a36Sopenharmony_ci{
165962306a36Sopenharmony_ci	if (!hdr)
166062306a36Sopenharmony_ci		hdr = register_sysctl("kernel", sg_sysctls);
166162306a36Sopenharmony_ci}
166262306a36Sopenharmony_ci
166362306a36Sopenharmony_cistatic void unregister_sg_sysctls(void)
166462306a36Sopenharmony_ci{
166562306a36Sopenharmony_ci	if (hdr)
166662306a36Sopenharmony_ci		unregister_sysctl_table(hdr);
166762306a36Sopenharmony_ci}
166862306a36Sopenharmony_ci#else
166962306a36Sopenharmony_ci#define register_sg_sysctls() do { } while (0)
167062306a36Sopenharmony_ci#define unregister_sg_sysctls() do { } while (0)
167162306a36Sopenharmony_ci#endif /* CONFIG_SYSCTL */
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_cistatic int __init
167462306a36Sopenharmony_ciinit_sg(void)
167562306a36Sopenharmony_ci{
167662306a36Sopenharmony_ci	int rc;
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ci	if (scatter_elem_sz < PAGE_SIZE) {
167962306a36Sopenharmony_ci		scatter_elem_sz = PAGE_SIZE;
168062306a36Sopenharmony_ci		scatter_elem_sz_prev = scatter_elem_sz;
168162306a36Sopenharmony_ci	}
168262306a36Sopenharmony_ci	if (def_reserved_size >= 0)
168362306a36Sopenharmony_ci		sg_big_buff = def_reserved_size;
168462306a36Sopenharmony_ci	else
168562306a36Sopenharmony_ci		def_reserved_size = sg_big_buff;
168662306a36Sopenharmony_ci
168762306a36Sopenharmony_ci	rc = register_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0),
168862306a36Sopenharmony_ci				    SG_MAX_DEVS, "sg");
168962306a36Sopenharmony_ci	if (rc)
169062306a36Sopenharmony_ci		return rc;
169162306a36Sopenharmony_ci        sg_sysfs_class = class_create("scsi_generic");
169262306a36Sopenharmony_ci        if ( IS_ERR(sg_sysfs_class) ) {
169362306a36Sopenharmony_ci		rc = PTR_ERR(sg_sysfs_class);
169462306a36Sopenharmony_ci		goto err_out;
169562306a36Sopenharmony_ci        }
169662306a36Sopenharmony_ci	sg_sysfs_valid = 1;
169762306a36Sopenharmony_ci	rc = scsi_register_interface(&sg_interface);
169862306a36Sopenharmony_ci	if (0 == rc) {
169962306a36Sopenharmony_ci#ifdef CONFIG_SCSI_PROC_FS
170062306a36Sopenharmony_ci		sg_proc_init();
170162306a36Sopenharmony_ci#endif				/* CONFIG_SCSI_PROC_FS */
170262306a36Sopenharmony_ci		return 0;
170362306a36Sopenharmony_ci	}
170462306a36Sopenharmony_ci	class_destroy(sg_sysfs_class);
170562306a36Sopenharmony_ci	register_sg_sysctls();
170662306a36Sopenharmony_cierr_out:
170762306a36Sopenharmony_ci	unregister_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0), SG_MAX_DEVS);
170862306a36Sopenharmony_ci	return rc;
170962306a36Sopenharmony_ci}
171062306a36Sopenharmony_ci
171162306a36Sopenharmony_cistatic void __exit
171262306a36Sopenharmony_ciexit_sg(void)
171362306a36Sopenharmony_ci{
171462306a36Sopenharmony_ci	unregister_sg_sysctls();
171562306a36Sopenharmony_ci#ifdef CONFIG_SCSI_PROC_FS
171662306a36Sopenharmony_ci	remove_proc_subtree("scsi/sg", NULL);
171762306a36Sopenharmony_ci#endif				/* CONFIG_SCSI_PROC_FS */
171862306a36Sopenharmony_ci	scsi_unregister_interface(&sg_interface);
171962306a36Sopenharmony_ci	class_destroy(sg_sysfs_class);
172062306a36Sopenharmony_ci	sg_sysfs_valid = 0;
172162306a36Sopenharmony_ci	unregister_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0),
172262306a36Sopenharmony_ci				 SG_MAX_DEVS);
172362306a36Sopenharmony_ci	idr_destroy(&sg_index_idr);
172462306a36Sopenharmony_ci}
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_cistatic int
172762306a36Sopenharmony_cisg_start_req(Sg_request *srp, unsigned char *cmd)
172862306a36Sopenharmony_ci{
172962306a36Sopenharmony_ci	int res;
173062306a36Sopenharmony_ci	struct request *rq;
173162306a36Sopenharmony_ci	Sg_fd *sfp = srp->parentfp;
173262306a36Sopenharmony_ci	sg_io_hdr_t *hp = &srp->header;
173362306a36Sopenharmony_ci	int dxfer_len = (int) hp->dxfer_len;
173462306a36Sopenharmony_ci	int dxfer_dir = hp->dxfer_direction;
173562306a36Sopenharmony_ci	unsigned int iov_count = hp->iovec_count;
173662306a36Sopenharmony_ci	Sg_scatter_hold *req_schp = &srp->data;
173762306a36Sopenharmony_ci	Sg_scatter_hold *rsv_schp = &sfp->reserve;
173862306a36Sopenharmony_ci	struct request_queue *q = sfp->parentdp->device->request_queue;
173962306a36Sopenharmony_ci	struct rq_map_data *md, map_data;
174062306a36Sopenharmony_ci	int rw = hp->dxfer_direction == SG_DXFER_TO_DEV ? ITER_SOURCE : ITER_DEST;
174162306a36Sopenharmony_ci	struct scsi_cmnd *scmd;
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_ci	SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sfp->parentdp,
174462306a36Sopenharmony_ci				      "sg_start_req: dxfer_len=%d\n",
174562306a36Sopenharmony_ci				      dxfer_len));
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_ci	/*
174862306a36Sopenharmony_ci	 * NOTE
174962306a36Sopenharmony_ci	 *
175062306a36Sopenharmony_ci	 * With scsi-mq enabled, there are a fixed number of preallocated
175162306a36Sopenharmony_ci	 * requests equal in number to shost->can_queue.  If all of the
175262306a36Sopenharmony_ci	 * preallocated requests are already in use, then scsi_alloc_request()
175362306a36Sopenharmony_ci	 * will sleep until an active command completes, freeing up a request.
175462306a36Sopenharmony_ci	 * Although waiting in an asynchronous interface is less than ideal, we
175562306a36Sopenharmony_ci	 * do not want to use BLK_MQ_REQ_NOWAIT here because userspace might
175662306a36Sopenharmony_ci	 * not expect an EWOULDBLOCK from this condition.
175762306a36Sopenharmony_ci	 */
175862306a36Sopenharmony_ci	rq = scsi_alloc_request(q, hp->dxfer_direction == SG_DXFER_TO_DEV ?
175962306a36Sopenharmony_ci			REQ_OP_DRV_OUT : REQ_OP_DRV_IN, 0);
176062306a36Sopenharmony_ci	if (IS_ERR(rq))
176162306a36Sopenharmony_ci		return PTR_ERR(rq);
176262306a36Sopenharmony_ci	scmd = blk_mq_rq_to_pdu(rq);
176362306a36Sopenharmony_ci
176462306a36Sopenharmony_ci	if (hp->cmd_len > sizeof(scmd->cmnd)) {
176562306a36Sopenharmony_ci		blk_mq_free_request(rq);
176662306a36Sopenharmony_ci		return -EINVAL;
176762306a36Sopenharmony_ci	}
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_ci	memcpy(scmd->cmnd, cmd, hp->cmd_len);
177062306a36Sopenharmony_ci	scmd->cmd_len = hp->cmd_len;
177162306a36Sopenharmony_ci
177262306a36Sopenharmony_ci	srp->rq = rq;
177362306a36Sopenharmony_ci	rq->end_io_data = srp;
177462306a36Sopenharmony_ci	scmd->allowed = SG_DEFAULT_RETRIES;
177562306a36Sopenharmony_ci
177662306a36Sopenharmony_ci	if ((dxfer_len <= 0) || (dxfer_dir == SG_DXFER_NONE))
177762306a36Sopenharmony_ci		return 0;
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_ci	if (sg_allow_dio && hp->flags & SG_FLAG_DIRECT_IO &&
178062306a36Sopenharmony_ci	    dxfer_dir != SG_DXFER_UNKNOWN && !iov_count &&
178162306a36Sopenharmony_ci	    blk_rq_aligned(q, (unsigned long)hp->dxferp, dxfer_len))
178262306a36Sopenharmony_ci		md = NULL;
178362306a36Sopenharmony_ci	else
178462306a36Sopenharmony_ci		md = &map_data;
178562306a36Sopenharmony_ci
178662306a36Sopenharmony_ci	if (md) {
178762306a36Sopenharmony_ci		mutex_lock(&sfp->f_mutex);
178862306a36Sopenharmony_ci		if (dxfer_len <= rsv_schp->bufflen &&
178962306a36Sopenharmony_ci		    !sfp->res_in_use) {
179062306a36Sopenharmony_ci			sfp->res_in_use = 1;
179162306a36Sopenharmony_ci			sg_link_reserve(sfp, srp, dxfer_len);
179262306a36Sopenharmony_ci		} else if (hp->flags & SG_FLAG_MMAP_IO) {
179362306a36Sopenharmony_ci			res = -EBUSY; /* sfp->res_in_use == 1 */
179462306a36Sopenharmony_ci			if (dxfer_len > rsv_schp->bufflen)
179562306a36Sopenharmony_ci				res = -ENOMEM;
179662306a36Sopenharmony_ci			mutex_unlock(&sfp->f_mutex);
179762306a36Sopenharmony_ci			return res;
179862306a36Sopenharmony_ci		} else {
179962306a36Sopenharmony_ci			res = sg_build_indirect(req_schp, sfp, dxfer_len);
180062306a36Sopenharmony_ci			if (res) {
180162306a36Sopenharmony_ci				mutex_unlock(&sfp->f_mutex);
180262306a36Sopenharmony_ci				return res;
180362306a36Sopenharmony_ci			}
180462306a36Sopenharmony_ci		}
180562306a36Sopenharmony_ci		mutex_unlock(&sfp->f_mutex);
180662306a36Sopenharmony_ci
180762306a36Sopenharmony_ci		md->pages = req_schp->pages;
180862306a36Sopenharmony_ci		md->page_order = req_schp->page_order;
180962306a36Sopenharmony_ci		md->nr_entries = req_schp->k_use_sg;
181062306a36Sopenharmony_ci		md->offset = 0;
181162306a36Sopenharmony_ci		md->null_mapped = hp->dxferp ? 0 : 1;
181262306a36Sopenharmony_ci		if (dxfer_dir == SG_DXFER_TO_FROM_DEV)
181362306a36Sopenharmony_ci			md->from_user = 1;
181462306a36Sopenharmony_ci		else
181562306a36Sopenharmony_ci			md->from_user = 0;
181662306a36Sopenharmony_ci	}
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_ci	res = blk_rq_map_user_io(rq, md, hp->dxferp, hp->dxfer_len,
181962306a36Sopenharmony_ci			GFP_ATOMIC, iov_count, iov_count, 1, rw);
182062306a36Sopenharmony_ci	if (!res) {
182162306a36Sopenharmony_ci		srp->bio = rq->bio;
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci		if (!md) {
182462306a36Sopenharmony_ci			req_schp->dio_in_use = 1;
182562306a36Sopenharmony_ci			hp->info |= SG_INFO_DIRECT_IO;
182662306a36Sopenharmony_ci		}
182762306a36Sopenharmony_ci	}
182862306a36Sopenharmony_ci	return res;
182962306a36Sopenharmony_ci}
183062306a36Sopenharmony_ci
183162306a36Sopenharmony_cistatic int
183262306a36Sopenharmony_cisg_finish_rem_req(Sg_request *srp)
183362306a36Sopenharmony_ci{
183462306a36Sopenharmony_ci	int ret = 0;
183562306a36Sopenharmony_ci
183662306a36Sopenharmony_ci	Sg_fd *sfp = srp->parentfp;
183762306a36Sopenharmony_ci	Sg_scatter_hold *req_schp = &srp->data;
183862306a36Sopenharmony_ci
183962306a36Sopenharmony_ci	SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sfp->parentdp,
184062306a36Sopenharmony_ci				      "sg_finish_rem_req: res_used=%d\n",
184162306a36Sopenharmony_ci				      (int) srp->res_used));
184262306a36Sopenharmony_ci	if (srp->bio)
184362306a36Sopenharmony_ci		ret = blk_rq_unmap_user(srp->bio);
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_ci	if (srp->rq)
184662306a36Sopenharmony_ci		blk_mq_free_request(srp->rq);
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_ci	if (srp->res_used)
184962306a36Sopenharmony_ci		sg_unlink_reserve(sfp, srp);
185062306a36Sopenharmony_ci	else
185162306a36Sopenharmony_ci		sg_remove_scat(sfp, req_schp);
185262306a36Sopenharmony_ci
185362306a36Sopenharmony_ci	return ret;
185462306a36Sopenharmony_ci}
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_cistatic int
185762306a36Sopenharmony_cisg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp, int tablesize)
185862306a36Sopenharmony_ci{
185962306a36Sopenharmony_ci	int sg_bufflen = tablesize * sizeof(struct page *);
186062306a36Sopenharmony_ci	gfp_t gfp_flags = GFP_ATOMIC | __GFP_NOWARN;
186162306a36Sopenharmony_ci
186262306a36Sopenharmony_ci	schp->pages = kzalloc(sg_bufflen, gfp_flags);
186362306a36Sopenharmony_ci	if (!schp->pages)
186462306a36Sopenharmony_ci		return -ENOMEM;
186562306a36Sopenharmony_ci	schp->sglist_len = sg_bufflen;
186662306a36Sopenharmony_ci	return tablesize;	/* number of scat_gath elements allocated */
186762306a36Sopenharmony_ci}
186862306a36Sopenharmony_ci
186962306a36Sopenharmony_cistatic int
187062306a36Sopenharmony_cisg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size)
187162306a36Sopenharmony_ci{
187262306a36Sopenharmony_ci	int ret_sz = 0, i, k, rem_sz, num, mx_sc_elems;
187362306a36Sopenharmony_ci	int sg_tablesize = sfp->parentdp->sg_tablesize;
187462306a36Sopenharmony_ci	int blk_size = buff_size, order;
187562306a36Sopenharmony_ci	gfp_t gfp_mask = GFP_ATOMIC | __GFP_COMP | __GFP_NOWARN | __GFP_ZERO;
187662306a36Sopenharmony_ci
187762306a36Sopenharmony_ci	if (blk_size < 0)
187862306a36Sopenharmony_ci		return -EFAULT;
187962306a36Sopenharmony_ci	if (0 == blk_size)
188062306a36Sopenharmony_ci		++blk_size;	/* don't know why */
188162306a36Sopenharmony_ci	/* round request up to next highest SG_SECTOR_SZ byte boundary */
188262306a36Sopenharmony_ci	blk_size = ALIGN(blk_size, SG_SECTOR_SZ);
188362306a36Sopenharmony_ci	SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sfp->parentdp,
188462306a36Sopenharmony_ci		"sg_build_indirect: buff_size=%d, blk_size=%d\n",
188562306a36Sopenharmony_ci		buff_size, blk_size));
188662306a36Sopenharmony_ci
188762306a36Sopenharmony_ci	/* N.B. ret_sz carried into this block ... */
188862306a36Sopenharmony_ci	mx_sc_elems = sg_build_sgat(schp, sfp, sg_tablesize);
188962306a36Sopenharmony_ci	if (mx_sc_elems < 0)
189062306a36Sopenharmony_ci		return mx_sc_elems;	/* most likely -ENOMEM */
189162306a36Sopenharmony_ci
189262306a36Sopenharmony_ci	num = scatter_elem_sz;
189362306a36Sopenharmony_ci	if (unlikely(num != scatter_elem_sz_prev)) {
189462306a36Sopenharmony_ci		if (num < PAGE_SIZE) {
189562306a36Sopenharmony_ci			scatter_elem_sz = PAGE_SIZE;
189662306a36Sopenharmony_ci			scatter_elem_sz_prev = PAGE_SIZE;
189762306a36Sopenharmony_ci		} else
189862306a36Sopenharmony_ci			scatter_elem_sz_prev = num;
189962306a36Sopenharmony_ci	}
190062306a36Sopenharmony_ci
190162306a36Sopenharmony_ci	order = get_order(num);
190262306a36Sopenharmony_ciretry:
190362306a36Sopenharmony_ci	ret_sz = 1 << (PAGE_SHIFT + order);
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_ci	for (k = 0, rem_sz = blk_size; rem_sz > 0 && k < mx_sc_elems;
190662306a36Sopenharmony_ci	     k++, rem_sz -= ret_sz) {
190762306a36Sopenharmony_ci
190862306a36Sopenharmony_ci		num = (rem_sz > scatter_elem_sz_prev) ?
190962306a36Sopenharmony_ci			scatter_elem_sz_prev : rem_sz;
191062306a36Sopenharmony_ci
191162306a36Sopenharmony_ci		schp->pages[k] = alloc_pages(gfp_mask, order);
191262306a36Sopenharmony_ci		if (!schp->pages[k])
191362306a36Sopenharmony_ci			goto out;
191462306a36Sopenharmony_ci
191562306a36Sopenharmony_ci		if (num == scatter_elem_sz_prev) {
191662306a36Sopenharmony_ci			if (unlikely(ret_sz > scatter_elem_sz_prev)) {
191762306a36Sopenharmony_ci				scatter_elem_sz = ret_sz;
191862306a36Sopenharmony_ci				scatter_elem_sz_prev = ret_sz;
191962306a36Sopenharmony_ci			}
192062306a36Sopenharmony_ci		}
192162306a36Sopenharmony_ci
192262306a36Sopenharmony_ci		SCSI_LOG_TIMEOUT(5, sg_printk(KERN_INFO, sfp->parentdp,
192362306a36Sopenharmony_ci				 "sg_build_indirect: k=%d, num=%d, ret_sz=%d\n",
192462306a36Sopenharmony_ci				 k, num, ret_sz));
192562306a36Sopenharmony_ci	}		/* end of for loop */
192662306a36Sopenharmony_ci
192762306a36Sopenharmony_ci	schp->page_order = order;
192862306a36Sopenharmony_ci	schp->k_use_sg = k;
192962306a36Sopenharmony_ci	SCSI_LOG_TIMEOUT(5, sg_printk(KERN_INFO, sfp->parentdp,
193062306a36Sopenharmony_ci			 "sg_build_indirect: k_use_sg=%d, rem_sz=%d\n",
193162306a36Sopenharmony_ci			 k, rem_sz));
193262306a36Sopenharmony_ci
193362306a36Sopenharmony_ci	schp->bufflen = blk_size;
193462306a36Sopenharmony_ci	if (rem_sz > 0)	/* must have failed */
193562306a36Sopenharmony_ci		return -ENOMEM;
193662306a36Sopenharmony_ci	return 0;
193762306a36Sopenharmony_ciout:
193862306a36Sopenharmony_ci	for (i = 0; i < k; i++)
193962306a36Sopenharmony_ci		__free_pages(schp->pages[i], order);
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_ci	if (--order >= 0)
194262306a36Sopenharmony_ci		goto retry;
194362306a36Sopenharmony_ci
194462306a36Sopenharmony_ci	return -ENOMEM;
194562306a36Sopenharmony_ci}
194662306a36Sopenharmony_ci
194762306a36Sopenharmony_cistatic void
194862306a36Sopenharmony_cisg_remove_scat(Sg_fd * sfp, Sg_scatter_hold * schp)
194962306a36Sopenharmony_ci{
195062306a36Sopenharmony_ci	SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sfp->parentdp,
195162306a36Sopenharmony_ci			 "sg_remove_scat: k_use_sg=%d\n", schp->k_use_sg));
195262306a36Sopenharmony_ci	if (schp->pages && schp->sglist_len > 0) {
195362306a36Sopenharmony_ci		if (!schp->dio_in_use) {
195462306a36Sopenharmony_ci			int k;
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_ci			for (k = 0; k < schp->k_use_sg && schp->pages[k]; k++) {
195762306a36Sopenharmony_ci				SCSI_LOG_TIMEOUT(5,
195862306a36Sopenharmony_ci					sg_printk(KERN_INFO, sfp->parentdp,
195962306a36Sopenharmony_ci					"sg_remove_scat: k=%d, pg=0x%p\n",
196062306a36Sopenharmony_ci					k, schp->pages[k]));
196162306a36Sopenharmony_ci				__free_pages(schp->pages[k], schp->page_order);
196262306a36Sopenharmony_ci			}
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_ci			kfree(schp->pages);
196562306a36Sopenharmony_ci		}
196662306a36Sopenharmony_ci	}
196762306a36Sopenharmony_ci	memset(schp, 0, sizeof (*schp));
196862306a36Sopenharmony_ci}
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_cistatic int
197162306a36Sopenharmony_cisg_read_oxfer(Sg_request * srp, char __user *outp, int num_read_xfer)
197262306a36Sopenharmony_ci{
197362306a36Sopenharmony_ci	Sg_scatter_hold *schp = &srp->data;
197462306a36Sopenharmony_ci	int k, num;
197562306a36Sopenharmony_ci
197662306a36Sopenharmony_ci	SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, srp->parentfp->parentdp,
197762306a36Sopenharmony_ci			 "sg_read_oxfer: num_read_xfer=%d\n",
197862306a36Sopenharmony_ci			 num_read_xfer));
197962306a36Sopenharmony_ci	if ((!outp) || (num_read_xfer <= 0))
198062306a36Sopenharmony_ci		return 0;
198162306a36Sopenharmony_ci
198262306a36Sopenharmony_ci	num = 1 << (PAGE_SHIFT + schp->page_order);
198362306a36Sopenharmony_ci	for (k = 0; k < schp->k_use_sg && schp->pages[k]; k++) {
198462306a36Sopenharmony_ci		if (num > num_read_xfer) {
198562306a36Sopenharmony_ci			if (copy_to_user(outp, page_address(schp->pages[k]),
198662306a36Sopenharmony_ci					   num_read_xfer))
198762306a36Sopenharmony_ci				return -EFAULT;
198862306a36Sopenharmony_ci			break;
198962306a36Sopenharmony_ci		} else {
199062306a36Sopenharmony_ci			if (copy_to_user(outp, page_address(schp->pages[k]),
199162306a36Sopenharmony_ci					   num))
199262306a36Sopenharmony_ci				return -EFAULT;
199362306a36Sopenharmony_ci			num_read_xfer -= num;
199462306a36Sopenharmony_ci			if (num_read_xfer <= 0)
199562306a36Sopenharmony_ci				break;
199662306a36Sopenharmony_ci			outp += num;
199762306a36Sopenharmony_ci		}
199862306a36Sopenharmony_ci	}
199962306a36Sopenharmony_ci
200062306a36Sopenharmony_ci	return 0;
200162306a36Sopenharmony_ci}
200262306a36Sopenharmony_ci
200362306a36Sopenharmony_cistatic void
200462306a36Sopenharmony_cisg_build_reserve(Sg_fd * sfp, int req_size)
200562306a36Sopenharmony_ci{
200662306a36Sopenharmony_ci	Sg_scatter_hold *schp = &sfp->reserve;
200762306a36Sopenharmony_ci
200862306a36Sopenharmony_ci	SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sfp->parentdp,
200962306a36Sopenharmony_ci			 "sg_build_reserve: req_size=%d\n", req_size));
201062306a36Sopenharmony_ci	do {
201162306a36Sopenharmony_ci		if (req_size < PAGE_SIZE)
201262306a36Sopenharmony_ci			req_size = PAGE_SIZE;
201362306a36Sopenharmony_ci		if (0 == sg_build_indirect(schp, sfp, req_size))
201462306a36Sopenharmony_ci			return;
201562306a36Sopenharmony_ci		else
201662306a36Sopenharmony_ci			sg_remove_scat(sfp, schp);
201762306a36Sopenharmony_ci		req_size >>= 1;	/* divide by 2 */
201862306a36Sopenharmony_ci	} while (req_size > (PAGE_SIZE / 2));
201962306a36Sopenharmony_ci}
202062306a36Sopenharmony_ci
202162306a36Sopenharmony_cistatic void
202262306a36Sopenharmony_cisg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size)
202362306a36Sopenharmony_ci{
202462306a36Sopenharmony_ci	Sg_scatter_hold *req_schp = &srp->data;
202562306a36Sopenharmony_ci	Sg_scatter_hold *rsv_schp = &sfp->reserve;
202662306a36Sopenharmony_ci	int k, num, rem;
202762306a36Sopenharmony_ci
202862306a36Sopenharmony_ci	srp->res_used = 1;
202962306a36Sopenharmony_ci	SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sfp->parentdp,
203062306a36Sopenharmony_ci			 "sg_link_reserve: size=%d\n", size));
203162306a36Sopenharmony_ci	rem = size;
203262306a36Sopenharmony_ci
203362306a36Sopenharmony_ci	num = 1 << (PAGE_SHIFT + rsv_schp->page_order);
203462306a36Sopenharmony_ci	for (k = 0; k < rsv_schp->k_use_sg; k++) {
203562306a36Sopenharmony_ci		if (rem <= num) {
203662306a36Sopenharmony_ci			req_schp->k_use_sg = k + 1;
203762306a36Sopenharmony_ci			req_schp->sglist_len = rsv_schp->sglist_len;
203862306a36Sopenharmony_ci			req_schp->pages = rsv_schp->pages;
203962306a36Sopenharmony_ci
204062306a36Sopenharmony_ci			req_schp->bufflen = size;
204162306a36Sopenharmony_ci			req_schp->page_order = rsv_schp->page_order;
204262306a36Sopenharmony_ci			break;
204362306a36Sopenharmony_ci		} else
204462306a36Sopenharmony_ci			rem -= num;
204562306a36Sopenharmony_ci	}
204662306a36Sopenharmony_ci
204762306a36Sopenharmony_ci	if (k >= rsv_schp->k_use_sg)
204862306a36Sopenharmony_ci		SCSI_LOG_TIMEOUT(1, sg_printk(KERN_INFO, sfp->parentdp,
204962306a36Sopenharmony_ci				 "sg_link_reserve: BAD size\n"));
205062306a36Sopenharmony_ci}
205162306a36Sopenharmony_ci
205262306a36Sopenharmony_cistatic void
205362306a36Sopenharmony_cisg_unlink_reserve(Sg_fd * sfp, Sg_request * srp)
205462306a36Sopenharmony_ci{
205562306a36Sopenharmony_ci	Sg_scatter_hold *req_schp = &srp->data;
205662306a36Sopenharmony_ci
205762306a36Sopenharmony_ci	SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, srp->parentfp->parentdp,
205862306a36Sopenharmony_ci				      "sg_unlink_reserve: req->k_use_sg=%d\n",
205962306a36Sopenharmony_ci				      (int) req_schp->k_use_sg));
206062306a36Sopenharmony_ci	req_schp->k_use_sg = 0;
206162306a36Sopenharmony_ci	req_schp->bufflen = 0;
206262306a36Sopenharmony_ci	req_schp->pages = NULL;
206362306a36Sopenharmony_ci	req_schp->page_order = 0;
206462306a36Sopenharmony_ci	req_schp->sglist_len = 0;
206562306a36Sopenharmony_ci	srp->res_used = 0;
206662306a36Sopenharmony_ci	/* Called without mutex lock to avoid deadlock */
206762306a36Sopenharmony_ci	sfp->res_in_use = 0;
206862306a36Sopenharmony_ci}
206962306a36Sopenharmony_ci
207062306a36Sopenharmony_cistatic Sg_request *
207162306a36Sopenharmony_cisg_get_rq_mark(Sg_fd * sfp, int pack_id, bool *busy)
207262306a36Sopenharmony_ci{
207362306a36Sopenharmony_ci	Sg_request *resp;
207462306a36Sopenharmony_ci	unsigned long iflags;
207562306a36Sopenharmony_ci
207662306a36Sopenharmony_ci	*busy = false;
207762306a36Sopenharmony_ci	write_lock_irqsave(&sfp->rq_list_lock, iflags);
207862306a36Sopenharmony_ci	list_for_each_entry(resp, &sfp->rq_list, entry) {
207962306a36Sopenharmony_ci		/* look for requests that are not SG_IO owned */
208062306a36Sopenharmony_ci		if ((!resp->sg_io_owned) &&
208162306a36Sopenharmony_ci		    ((-1 == pack_id) || (resp->header.pack_id == pack_id))) {
208262306a36Sopenharmony_ci			switch (resp->done) {
208362306a36Sopenharmony_ci			case 0: /* request active */
208462306a36Sopenharmony_ci				*busy = true;
208562306a36Sopenharmony_ci				break;
208662306a36Sopenharmony_ci			case 1: /* request done; response ready to return */
208762306a36Sopenharmony_ci				resp->done = 2;	/* guard against other readers */
208862306a36Sopenharmony_ci				write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
208962306a36Sopenharmony_ci				return resp;
209062306a36Sopenharmony_ci			case 2: /* response already being returned */
209162306a36Sopenharmony_ci				break;
209262306a36Sopenharmony_ci			}
209362306a36Sopenharmony_ci		}
209462306a36Sopenharmony_ci	}
209562306a36Sopenharmony_ci	write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
209662306a36Sopenharmony_ci	return NULL;
209762306a36Sopenharmony_ci}
209862306a36Sopenharmony_ci
209962306a36Sopenharmony_ci/* always adds to end of list */
210062306a36Sopenharmony_cistatic Sg_request *
210162306a36Sopenharmony_cisg_add_request(Sg_fd * sfp)
210262306a36Sopenharmony_ci{
210362306a36Sopenharmony_ci	int k;
210462306a36Sopenharmony_ci	unsigned long iflags;
210562306a36Sopenharmony_ci	Sg_request *rp = sfp->req_arr;
210662306a36Sopenharmony_ci
210762306a36Sopenharmony_ci	write_lock_irqsave(&sfp->rq_list_lock, iflags);
210862306a36Sopenharmony_ci	if (!list_empty(&sfp->rq_list)) {
210962306a36Sopenharmony_ci		if (!sfp->cmd_q)
211062306a36Sopenharmony_ci			goto out_unlock;
211162306a36Sopenharmony_ci
211262306a36Sopenharmony_ci		for (k = 0; k < SG_MAX_QUEUE; ++k, ++rp) {
211362306a36Sopenharmony_ci			if (!rp->parentfp)
211462306a36Sopenharmony_ci				break;
211562306a36Sopenharmony_ci		}
211662306a36Sopenharmony_ci		if (k >= SG_MAX_QUEUE)
211762306a36Sopenharmony_ci			goto out_unlock;
211862306a36Sopenharmony_ci	}
211962306a36Sopenharmony_ci	memset(rp, 0, sizeof (Sg_request));
212062306a36Sopenharmony_ci	rp->parentfp = sfp;
212162306a36Sopenharmony_ci	rp->header.duration = jiffies_to_msecs(jiffies);
212262306a36Sopenharmony_ci	list_add_tail(&rp->entry, &sfp->rq_list);
212362306a36Sopenharmony_ci	write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
212462306a36Sopenharmony_ci	return rp;
212562306a36Sopenharmony_ciout_unlock:
212662306a36Sopenharmony_ci	write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
212762306a36Sopenharmony_ci	return NULL;
212862306a36Sopenharmony_ci}
212962306a36Sopenharmony_ci
213062306a36Sopenharmony_ci/* Return of 1 for found; 0 for not found */
213162306a36Sopenharmony_cistatic int
213262306a36Sopenharmony_cisg_remove_request(Sg_fd * sfp, Sg_request * srp)
213362306a36Sopenharmony_ci{
213462306a36Sopenharmony_ci	unsigned long iflags;
213562306a36Sopenharmony_ci	int res = 0;
213662306a36Sopenharmony_ci
213762306a36Sopenharmony_ci	if (!sfp || !srp || list_empty(&sfp->rq_list))
213862306a36Sopenharmony_ci		return res;
213962306a36Sopenharmony_ci	write_lock_irqsave(&sfp->rq_list_lock, iflags);
214062306a36Sopenharmony_ci	if (!list_empty(&srp->entry)) {
214162306a36Sopenharmony_ci		list_del(&srp->entry);
214262306a36Sopenharmony_ci		srp->parentfp = NULL;
214362306a36Sopenharmony_ci		res = 1;
214462306a36Sopenharmony_ci	}
214562306a36Sopenharmony_ci	write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
214662306a36Sopenharmony_ci
214762306a36Sopenharmony_ci	/*
214862306a36Sopenharmony_ci	 * If the device is detaching, wakeup any readers in case we just
214962306a36Sopenharmony_ci	 * removed the last response, which would leave nothing for them to
215062306a36Sopenharmony_ci	 * return other than -ENODEV.
215162306a36Sopenharmony_ci	 */
215262306a36Sopenharmony_ci	if (unlikely(atomic_read(&sfp->parentdp->detaching)))
215362306a36Sopenharmony_ci		wake_up_interruptible_all(&sfp->read_wait);
215462306a36Sopenharmony_ci
215562306a36Sopenharmony_ci	return res;
215662306a36Sopenharmony_ci}
215762306a36Sopenharmony_ci
215862306a36Sopenharmony_cistatic Sg_fd *
215962306a36Sopenharmony_cisg_add_sfp(Sg_device * sdp)
216062306a36Sopenharmony_ci{
216162306a36Sopenharmony_ci	Sg_fd *sfp;
216262306a36Sopenharmony_ci	unsigned long iflags;
216362306a36Sopenharmony_ci	int bufflen;
216462306a36Sopenharmony_ci
216562306a36Sopenharmony_ci	sfp = kzalloc(sizeof(*sfp), GFP_ATOMIC | __GFP_NOWARN);
216662306a36Sopenharmony_ci	if (!sfp)
216762306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
216862306a36Sopenharmony_ci
216962306a36Sopenharmony_ci	init_waitqueue_head(&sfp->read_wait);
217062306a36Sopenharmony_ci	rwlock_init(&sfp->rq_list_lock);
217162306a36Sopenharmony_ci	INIT_LIST_HEAD(&sfp->rq_list);
217262306a36Sopenharmony_ci	kref_init(&sfp->f_ref);
217362306a36Sopenharmony_ci	mutex_init(&sfp->f_mutex);
217462306a36Sopenharmony_ci	sfp->timeout = SG_DEFAULT_TIMEOUT;
217562306a36Sopenharmony_ci	sfp->timeout_user = SG_DEFAULT_TIMEOUT_USER;
217662306a36Sopenharmony_ci	sfp->force_packid = SG_DEF_FORCE_PACK_ID;
217762306a36Sopenharmony_ci	sfp->cmd_q = SG_DEF_COMMAND_Q;
217862306a36Sopenharmony_ci	sfp->keep_orphan = SG_DEF_KEEP_ORPHAN;
217962306a36Sopenharmony_ci	sfp->parentdp = sdp;
218062306a36Sopenharmony_ci	write_lock_irqsave(&sdp->sfd_lock, iflags);
218162306a36Sopenharmony_ci	if (atomic_read(&sdp->detaching)) {
218262306a36Sopenharmony_ci		write_unlock_irqrestore(&sdp->sfd_lock, iflags);
218362306a36Sopenharmony_ci		kfree(sfp);
218462306a36Sopenharmony_ci		return ERR_PTR(-ENODEV);
218562306a36Sopenharmony_ci	}
218662306a36Sopenharmony_ci	list_add_tail(&sfp->sfd_siblings, &sdp->sfds);
218762306a36Sopenharmony_ci	write_unlock_irqrestore(&sdp->sfd_lock, iflags);
218862306a36Sopenharmony_ci	SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp,
218962306a36Sopenharmony_ci				      "sg_add_sfp: sfp=0x%p\n", sfp));
219062306a36Sopenharmony_ci	if (unlikely(sg_big_buff != def_reserved_size))
219162306a36Sopenharmony_ci		sg_big_buff = def_reserved_size;
219262306a36Sopenharmony_ci
219362306a36Sopenharmony_ci	bufflen = min_t(int, sg_big_buff,
219462306a36Sopenharmony_ci			max_sectors_bytes(sdp->device->request_queue));
219562306a36Sopenharmony_ci	sg_build_reserve(sfp, bufflen);
219662306a36Sopenharmony_ci	SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp,
219762306a36Sopenharmony_ci				      "sg_add_sfp: bufflen=%d, k_use_sg=%d\n",
219862306a36Sopenharmony_ci				      sfp->reserve.bufflen,
219962306a36Sopenharmony_ci				      sfp->reserve.k_use_sg));
220062306a36Sopenharmony_ci
220162306a36Sopenharmony_ci	kref_get(&sdp->d_ref);
220262306a36Sopenharmony_ci	__module_get(THIS_MODULE);
220362306a36Sopenharmony_ci	return sfp;
220462306a36Sopenharmony_ci}
220562306a36Sopenharmony_ci
220662306a36Sopenharmony_cistatic void
220762306a36Sopenharmony_cisg_remove_sfp_usercontext(struct work_struct *work)
220862306a36Sopenharmony_ci{
220962306a36Sopenharmony_ci	struct sg_fd *sfp = container_of(work, struct sg_fd, ew.work);
221062306a36Sopenharmony_ci	struct sg_device *sdp = sfp->parentdp;
221162306a36Sopenharmony_ci	Sg_request *srp;
221262306a36Sopenharmony_ci	unsigned long iflags;
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_ci	/* Cleanup any responses which were never read(). */
221562306a36Sopenharmony_ci	write_lock_irqsave(&sfp->rq_list_lock, iflags);
221662306a36Sopenharmony_ci	while (!list_empty(&sfp->rq_list)) {
221762306a36Sopenharmony_ci		srp = list_first_entry(&sfp->rq_list, Sg_request, entry);
221862306a36Sopenharmony_ci		sg_finish_rem_req(srp);
221962306a36Sopenharmony_ci		list_del(&srp->entry);
222062306a36Sopenharmony_ci		srp->parentfp = NULL;
222162306a36Sopenharmony_ci	}
222262306a36Sopenharmony_ci	write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
222362306a36Sopenharmony_ci
222462306a36Sopenharmony_ci	if (sfp->reserve.bufflen > 0) {
222562306a36Sopenharmony_ci		SCSI_LOG_TIMEOUT(6, sg_printk(KERN_INFO, sdp,
222662306a36Sopenharmony_ci				"sg_remove_sfp:    bufflen=%d, k_use_sg=%d\n",
222762306a36Sopenharmony_ci				(int) sfp->reserve.bufflen,
222862306a36Sopenharmony_ci				(int) sfp->reserve.k_use_sg));
222962306a36Sopenharmony_ci		sg_remove_scat(sfp, &sfp->reserve);
223062306a36Sopenharmony_ci	}
223162306a36Sopenharmony_ci
223262306a36Sopenharmony_ci	SCSI_LOG_TIMEOUT(6, sg_printk(KERN_INFO, sdp,
223362306a36Sopenharmony_ci			"sg_remove_sfp: sfp=0x%p\n", sfp));
223462306a36Sopenharmony_ci	kfree(sfp);
223562306a36Sopenharmony_ci
223662306a36Sopenharmony_ci	scsi_device_put(sdp->device);
223762306a36Sopenharmony_ci	kref_put(&sdp->d_ref, sg_device_destroy);
223862306a36Sopenharmony_ci	module_put(THIS_MODULE);
223962306a36Sopenharmony_ci}
224062306a36Sopenharmony_ci
224162306a36Sopenharmony_cistatic void
224262306a36Sopenharmony_cisg_remove_sfp(struct kref *kref)
224362306a36Sopenharmony_ci{
224462306a36Sopenharmony_ci	struct sg_fd *sfp = container_of(kref, struct sg_fd, f_ref);
224562306a36Sopenharmony_ci	struct sg_device *sdp = sfp->parentdp;
224662306a36Sopenharmony_ci	unsigned long iflags;
224762306a36Sopenharmony_ci
224862306a36Sopenharmony_ci	write_lock_irqsave(&sdp->sfd_lock, iflags);
224962306a36Sopenharmony_ci	list_del(&sfp->sfd_siblings);
225062306a36Sopenharmony_ci	write_unlock_irqrestore(&sdp->sfd_lock, iflags);
225162306a36Sopenharmony_ci
225262306a36Sopenharmony_ci	INIT_WORK(&sfp->ew.work, sg_remove_sfp_usercontext);
225362306a36Sopenharmony_ci	schedule_work(&sfp->ew.work);
225462306a36Sopenharmony_ci}
225562306a36Sopenharmony_ci
225662306a36Sopenharmony_ci#ifdef CONFIG_SCSI_PROC_FS
225762306a36Sopenharmony_cistatic int
225862306a36Sopenharmony_cisg_idr_max_id(int id, void *p, void *data)
225962306a36Sopenharmony_ci{
226062306a36Sopenharmony_ci	int *k = data;
226162306a36Sopenharmony_ci
226262306a36Sopenharmony_ci	if (*k < id)
226362306a36Sopenharmony_ci		*k = id;
226462306a36Sopenharmony_ci
226562306a36Sopenharmony_ci	return 0;
226662306a36Sopenharmony_ci}
226762306a36Sopenharmony_ci
226862306a36Sopenharmony_cistatic int
226962306a36Sopenharmony_cisg_last_dev(void)
227062306a36Sopenharmony_ci{
227162306a36Sopenharmony_ci	int k = -1;
227262306a36Sopenharmony_ci	unsigned long iflags;
227362306a36Sopenharmony_ci
227462306a36Sopenharmony_ci	read_lock_irqsave(&sg_index_lock, iflags);
227562306a36Sopenharmony_ci	idr_for_each(&sg_index_idr, sg_idr_max_id, &k);
227662306a36Sopenharmony_ci	read_unlock_irqrestore(&sg_index_lock, iflags);
227762306a36Sopenharmony_ci	return k + 1;		/* origin 1 */
227862306a36Sopenharmony_ci}
227962306a36Sopenharmony_ci#endif
228062306a36Sopenharmony_ci
228162306a36Sopenharmony_ci/* must be called with sg_index_lock held */
228262306a36Sopenharmony_cistatic Sg_device *sg_lookup_dev(int dev)
228362306a36Sopenharmony_ci{
228462306a36Sopenharmony_ci	return idr_find(&sg_index_idr, dev);
228562306a36Sopenharmony_ci}
228662306a36Sopenharmony_ci
228762306a36Sopenharmony_cistatic Sg_device *
228862306a36Sopenharmony_cisg_get_dev(int dev)
228962306a36Sopenharmony_ci{
229062306a36Sopenharmony_ci	struct sg_device *sdp;
229162306a36Sopenharmony_ci	unsigned long flags;
229262306a36Sopenharmony_ci
229362306a36Sopenharmony_ci	read_lock_irqsave(&sg_index_lock, flags);
229462306a36Sopenharmony_ci	sdp = sg_lookup_dev(dev);
229562306a36Sopenharmony_ci	if (!sdp)
229662306a36Sopenharmony_ci		sdp = ERR_PTR(-ENXIO);
229762306a36Sopenharmony_ci	else if (atomic_read(&sdp->detaching)) {
229862306a36Sopenharmony_ci		/* If sdp->detaching, then the refcount may already be 0, in
229962306a36Sopenharmony_ci		 * which case it would be a bug to do kref_get().
230062306a36Sopenharmony_ci		 */
230162306a36Sopenharmony_ci		sdp = ERR_PTR(-ENODEV);
230262306a36Sopenharmony_ci	} else
230362306a36Sopenharmony_ci		kref_get(&sdp->d_ref);
230462306a36Sopenharmony_ci	read_unlock_irqrestore(&sg_index_lock, flags);
230562306a36Sopenharmony_ci
230662306a36Sopenharmony_ci	return sdp;
230762306a36Sopenharmony_ci}
230862306a36Sopenharmony_ci
230962306a36Sopenharmony_ci#ifdef CONFIG_SCSI_PROC_FS
231062306a36Sopenharmony_cistatic int sg_proc_seq_show_int(struct seq_file *s, void *v);
231162306a36Sopenharmony_ci
231262306a36Sopenharmony_cistatic int sg_proc_single_open_adio(struct inode *inode, struct file *file);
231362306a36Sopenharmony_cistatic ssize_t sg_proc_write_adio(struct file *filp, const char __user *buffer,
231462306a36Sopenharmony_ci			          size_t count, loff_t *off);
231562306a36Sopenharmony_cistatic const struct proc_ops adio_proc_ops = {
231662306a36Sopenharmony_ci	.proc_open	= sg_proc_single_open_adio,
231762306a36Sopenharmony_ci	.proc_read	= seq_read,
231862306a36Sopenharmony_ci	.proc_lseek	= seq_lseek,
231962306a36Sopenharmony_ci	.proc_write	= sg_proc_write_adio,
232062306a36Sopenharmony_ci	.proc_release	= single_release,
232162306a36Sopenharmony_ci};
232262306a36Sopenharmony_ci
232362306a36Sopenharmony_cistatic int sg_proc_single_open_dressz(struct inode *inode, struct file *file);
232462306a36Sopenharmony_cistatic ssize_t sg_proc_write_dressz(struct file *filp,
232562306a36Sopenharmony_ci		const char __user *buffer, size_t count, loff_t *off);
232662306a36Sopenharmony_cistatic const struct proc_ops dressz_proc_ops = {
232762306a36Sopenharmony_ci	.proc_open	= sg_proc_single_open_dressz,
232862306a36Sopenharmony_ci	.proc_read	= seq_read,
232962306a36Sopenharmony_ci	.proc_lseek	= seq_lseek,
233062306a36Sopenharmony_ci	.proc_write	= sg_proc_write_dressz,
233162306a36Sopenharmony_ci	.proc_release	= single_release,
233262306a36Sopenharmony_ci};
233362306a36Sopenharmony_ci
233462306a36Sopenharmony_cistatic int sg_proc_seq_show_version(struct seq_file *s, void *v);
233562306a36Sopenharmony_cistatic int sg_proc_seq_show_devhdr(struct seq_file *s, void *v);
233662306a36Sopenharmony_cistatic int sg_proc_seq_show_dev(struct seq_file *s, void *v);
233762306a36Sopenharmony_cistatic void * dev_seq_start(struct seq_file *s, loff_t *pos);
233862306a36Sopenharmony_cistatic void * dev_seq_next(struct seq_file *s, void *v, loff_t *pos);
233962306a36Sopenharmony_cistatic void dev_seq_stop(struct seq_file *s, void *v);
234062306a36Sopenharmony_cistatic const struct seq_operations dev_seq_ops = {
234162306a36Sopenharmony_ci	.start = dev_seq_start,
234262306a36Sopenharmony_ci	.next  = dev_seq_next,
234362306a36Sopenharmony_ci	.stop  = dev_seq_stop,
234462306a36Sopenharmony_ci	.show  = sg_proc_seq_show_dev,
234562306a36Sopenharmony_ci};
234662306a36Sopenharmony_ci
234762306a36Sopenharmony_cistatic int sg_proc_seq_show_devstrs(struct seq_file *s, void *v);
234862306a36Sopenharmony_cistatic const struct seq_operations devstrs_seq_ops = {
234962306a36Sopenharmony_ci	.start = dev_seq_start,
235062306a36Sopenharmony_ci	.next  = dev_seq_next,
235162306a36Sopenharmony_ci	.stop  = dev_seq_stop,
235262306a36Sopenharmony_ci	.show  = sg_proc_seq_show_devstrs,
235362306a36Sopenharmony_ci};
235462306a36Sopenharmony_ci
235562306a36Sopenharmony_cistatic int sg_proc_seq_show_debug(struct seq_file *s, void *v);
235662306a36Sopenharmony_cistatic const struct seq_operations debug_seq_ops = {
235762306a36Sopenharmony_ci	.start = dev_seq_start,
235862306a36Sopenharmony_ci	.next  = dev_seq_next,
235962306a36Sopenharmony_ci	.stop  = dev_seq_stop,
236062306a36Sopenharmony_ci	.show  = sg_proc_seq_show_debug,
236162306a36Sopenharmony_ci};
236262306a36Sopenharmony_ci
236362306a36Sopenharmony_cistatic int
236462306a36Sopenharmony_cisg_proc_init(void)
236562306a36Sopenharmony_ci{
236662306a36Sopenharmony_ci	struct proc_dir_entry *p;
236762306a36Sopenharmony_ci
236862306a36Sopenharmony_ci	p = proc_mkdir("scsi/sg", NULL);
236962306a36Sopenharmony_ci	if (!p)
237062306a36Sopenharmony_ci		return 1;
237162306a36Sopenharmony_ci
237262306a36Sopenharmony_ci	proc_create("allow_dio", S_IRUGO | S_IWUSR, p, &adio_proc_ops);
237362306a36Sopenharmony_ci	proc_create_seq("debug", S_IRUGO, p, &debug_seq_ops);
237462306a36Sopenharmony_ci	proc_create("def_reserved_size", S_IRUGO | S_IWUSR, p, &dressz_proc_ops);
237562306a36Sopenharmony_ci	proc_create_single("device_hdr", S_IRUGO, p, sg_proc_seq_show_devhdr);
237662306a36Sopenharmony_ci	proc_create_seq("devices", S_IRUGO, p, &dev_seq_ops);
237762306a36Sopenharmony_ci	proc_create_seq("device_strs", S_IRUGO, p, &devstrs_seq_ops);
237862306a36Sopenharmony_ci	proc_create_single("version", S_IRUGO, p, sg_proc_seq_show_version);
237962306a36Sopenharmony_ci	return 0;
238062306a36Sopenharmony_ci}
238162306a36Sopenharmony_ci
238262306a36Sopenharmony_ci
238362306a36Sopenharmony_cistatic int sg_proc_seq_show_int(struct seq_file *s, void *v)
238462306a36Sopenharmony_ci{
238562306a36Sopenharmony_ci	seq_printf(s, "%d\n", *((int *)s->private));
238662306a36Sopenharmony_ci	return 0;
238762306a36Sopenharmony_ci}
238862306a36Sopenharmony_ci
238962306a36Sopenharmony_cistatic int sg_proc_single_open_adio(struct inode *inode, struct file *file)
239062306a36Sopenharmony_ci{
239162306a36Sopenharmony_ci	return single_open(file, sg_proc_seq_show_int, &sg_allow_dio);
239262306a36Sopenharmony_ci}
239362306a36Sopenharmony_ci
239462306a36Sopenharmony_cistatic ssize_t
239562306a36Sopenharmony_cisg_proc_write_adio(struct file *filp, const char __user *buffer,
239662306a36Sopenharmony_ci		   size_t count, loff_t *off)
239762306a36Sopenharmony_ci{
239862306a36Sopenharmony_ci	int err;
239962306a36Sopenharmony_ci	unsigned long num;
240062306a36Sopenharmony_ci
240162306a36Sopenharmony_ci	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
240262306a36Sopenharmony_ci		return -EACCES;
240362306a36Sopenharmony_ci	err = kstrtoul_from_user(buffer, count, 0, &num);
240462306a36Sopenharmony_ci	if (err)
240562306a36Sopenharmony_ci		return err;
240662306a36Sopenharmony_ci	sg_allow_dio = num ? 1 : 0;
240762306a36Sopenharmony_ci	return count;
240862306a36Sopenharmony_ci}
240962306a36Sopenharmony_ci
241062306a36Sopenharmony_cistatic int sg_proc_single_open_dressz(struct inode *inode, struct file *file)
241162306a36Sopenharmony_ci{
241262306a36Sopenharmony_ci	return single_open(file, sg_proc_seq_show_int, &sg_big_buff);
241362306a36Sopenharmony_ci}
241462306a36Sopenharmony_ci
241562306a36Sopenharmony_cistatic ssize_t
241662306a36Sopenharmony_cisg_proc_write_dressz(struct file *filp, const char __user *buffer,
241762306a36Sopenharmony_ci		     size_t count, loff_t *off)
241862306a36Sopenharmony_ci{
241962306a36Sopenharmony_ci	int err;
242062306a36Sopenharmony_ci	unsigned long k = ULONG_MAX;
242162306a36Sopenharmony_ci
242262306a36Sopenharmony_ci	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
242362306a36Sopenharmony_ci		return -EACCES;
242462306a36Sopenharmony_ci
242562306a36Sopenharmony_ci	err = kstrtoul_from_user(buffer, count, 0, &k);
242662306a36Sopenharmony_ci	if (err)
242762306a36Sopenharmony_ci		return err;
242862306a36Sopenharmony_ci	if (k <= 1048576) {	/* limit "big buff" to 1 MB */
242962306a36Sopenharmony_ci		sg_big_buff = k;
243062306a36Sopenharmony_ci		return count;
243162306a36Sopenharmony_ci	}
243262306a36Sopenharmony_ci	return -ERANGE;
243362306a36Sopenharmony_ci}
243462306a36Sopenharmony_ci
243562306a36Sopenharmony_cistatic int sg_proc_seq_show_version(struct seq_file *s, void *v)
243662306a36Sopenharmony_ci{
243762306a36Sopenharmony_ci	seq_printf(s, "%d\t%s [%s]\n", sg_version_num, SG_VERSION_STR,
243862306a36Sopenharmony_ci		   sg_version_date);
243962306a36Sopenharmony_ci	return 0;
244062306a36Sopenharmony_ci}
244162306a36Sopenharmony_ci
244262306a36Sopenharmony_cistatic int sg_proc_seq_show_devhdr(struct seq_file *s, void *v)
244362306a36Sopenharmony_ci{
244462306a36Sopenharmony_ci	seq_puts(s, "host\tchan\tid\tlun\ttype\topens\tqdepth\tbusy\tonline\n");
244562306a36Sopenharmony_ci	return 0;
244662306a36Sopenharmony_ci}
244762306a36Sopenharmony_ci
244862306a36Sopenharmony_cistruct sg_proc_deviter {
244962306a36Sopenharmony_ci	loff_t	index;
245062306a36Sopenharmony_ci	size_t	max;
245162306a36Sopenharmony_ci};
245262306a36Sopenharmony_ci
245362306a36Sopenharmony_cistatic void * dev_seq_start(struct seq_file *s, loff_t *pos)
245462306a36Sopenharmony_ci{
245562306a36Sopenharmony_ci	struct sg_proc_deviter * it = kmalloc(sizeof(*it), GFP_KERNEL);
245662306a36Sopenharmony_ci
245762306a36Sopenharmony_ci	s->private = it;
245862306a36Sopenharmony_ci	if (! it)
245962306a36Sopenharmony_ci		return NULL;
246062306a36Sopenharmony_ci
246162306a36Sopenharmony_ci	it->index = *pos;
246262306a36Sopenharmony_ci	it->max = sg_last_dev();
246362306a36Sopenharmony_ci	if (it->index >= it->max)
246462306a36Sopenharmony_ci		return NULL;
246562306a36Sopenharmony_ci	return it;
246662306a36Sopenharmony_ci}
246762306a36Sopenharmony_ci
246862306a36Sopenharmony_cistatic void * dev_seq_next(struct seq_file *s, void *v, loff_t *pos)
246962306a36Sopenharmony_ci{
247062306a36Sopenharmony_ci	struct sg_proc_deviter * it = s->private;
247162306a36Sopenharmony_ci
247262306a36Sopenharmony_ci	*pos = ++it->index;
247362306a36Sopenharmony_ci	return (it->index < it->max) ? it : NULL;
247462306a36Sopenharmony_ci}
247562306a36Sopenharmony_ci
247662306a36Sopenharmony_cistatic void dev_seq_stop(struct seq_file *s, void *v)
247762306a36Sopenharmony_ci{
247862306a36Sopenharmony_ci	kfree(s->private);
247962306a36Sopenharmony_ci}
248062306a36Sopenharmony_ci
248162306a36Sopenharmony_cistatic int sg_proc_seq_show_dev(struct seq_file *s, void *v)
248262306a36Sopenharmony_ci{
248362306a36Sopenharmony_ci	struct sg_proc_deviter * it = (struct sg_proc_deviter *) v;
248462306a36Sopenharmony_ci	Sg_device *sdp;
248562306a36Sopenharmony_ci	struct scsi_device *scsidp;
248662306a36Sopenharmony_ci	unsigned long iflags;
248762306a36Sopenharmony_ci
248862306a36Sopenharmony_ci	read_lock_irqsave(&sg_index_lock, iflags);
248962306a36Sopenharmony_ci	sdp = it ? sg_lookup_dev(it->index) : NULL;
249062306a36Sopenharmony_ci	if ((NULL == sdp) || (NULL == sdp->device) ||
249162306a36Sopenharmony_ci	    (atomic_read(&sdp->detaching)))
249262306a36Sopenharmony_ci		seq_puts(s, "-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\n");
249362306a36Sopenharmony_ci	else {
249462306a36Sopenharmony_ci		scsidp = sdp->device;
249562306a36Sopenharmony_ci		seq_printf(s, "%d\t%d\t%d\t%llu\t%d\t%d\t%d\t%d\t%d\n",
249662306a36Sopenharmony_ci			      scsidp->host->host_no, scsidp->channel,
249762306a36Sopenharmony_ci			      scsidp->id, scsidp->lun, (int) scsidp->type,
249862306a36Sopenharmony_ci			      1,
249962306a36Sopenharmony_ci			      (int) scsidp->queue_depth,
250062306a36Sopenharmony_ci			      (int) scsi_device_busy(scsidp),
250162306a36Sopenharmony_ci			      (int) scsi_device_online(scsidp));
250262306a36Sopenharmony_ci	}
250362306a36Sopenharmony_ci	read_unlock_irqrestore(&sg_index_lock, iflags);
250462306a36Sopenharmony_ci	return 0;
250562306a36Sopenharmony_ci}
250662306a36Sopenharmony_ci
250762306a36Sopenharmony_cistatic int sg_proc_seq_show_devstrs(struct seq_file *s, void *v)
250862306a36Sopenharmony_ci{
250962306a36Sopenharmony_ci	struct sg_proc_deviter * it = (struct sg_proc_deviter *) v;
251062306a36Sopenharmony_ci	Sg_device *sdp;
251162306a36Sopenharmony_ci	struct scsi_device *scsidp;
251262306a36Sopenharmony_ci	unsigned long iflags;
251362306a36Sopenharmony_ci
251462306a36Sopenharmony_ci	read_lock_irqsave(&sg_index_lock, iflags);
251562306a36Sopenharmony_ci	sdp = it ? sg_lookup_dev(it->index) : NULL;
251662306a36Sopenharmony_ci	scsidp = sdp ? sdp->device : NULL;
251762306a36Sopenharmony_ci	if (sdp && scsidp && (!atomic_read(&sdp->detaching)))
251862306a36Sopenharmony_ci		seq_printf(s, "%8.8s\t%16.16s\t%4.4s\n",
251962306a36Sopenharmony_ci			   scsidp->vendor, scsidp->model, scsidp->rev);
252062306a36Sopenharmony_ci	else
252162306a36Sopenharmony_ci		seq_puts(s, "<no active device>\n");
252262306a36Sopenharmony_ci	read_unlock_irqrestore(&sg_index_lock, iflags);
252362306a36Sopenharmony_ci	return 0;
252462306a36Sopenharmony_ci}
252562306a36Sopenharmony_ci
252662306a36Sopenharmony_ci/* must be called while holding sg_index_lock */
252762306a36Sopenharmony_cistatic void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp)
252862306a36Sopenharmony_ci{
252962306a36Sopenharmony_ci	int k, new_interface, blen, usg;
253062306a36Sopenharmony_ci	Sg_request *srp;
253162306a36Sopenharmony_ci	Sg_fd *fp;
253262306a36Sopenharmony_ci	const sg_io_hdr_t *hp;
253362306a36Sopenharmony_ci	const char * cp;
253462306a36Sopenharmony_ci	unsigned int ms;
253562306a36Sopenharmony_ci
253662306a36Sopenharmony_ci	k = 0;
253762306a36Sopenharmony_ci	list_for_each_entry(fp, &sdp->sfds, sfd_siblings) {
253862306a36Sopenharmony_ci		k++;
253962306a36Sopenharmony_ci		read_lock(&fp->rq_list_lock); /* irqs already disabled */
254062306a36Sopenharmony_ci		seq_printf(s, "   FD(%d): timeout=%dms bufflen=%d "
254162306a36Sopenharmony_ci			   "(res)sgat=%d low_dma=%d\n", k,
254262306a36Sopenharmony_ci			   jiffies_to_msecs(fp->timeout),
254362306a36Sopenharmony_ci			   fp->reserve.bufflen,
254462306a36Sopenharmony_ci			   (int) fp->reserve.k_use_sg, 0);
254562306a36Sopenharmony_ci		seq_printf(s, "   cmd_q=%d f_packid=%d k_orphan=%d closed=0\n",
254662306a36Sopenharmony_ci			   (int) fp->cmd_q, (int) fp->force_packid,
254762306a36Sopenharmony_ci			   (int) fp->keep_orphan);
254862306a36Sopenharmony_ci		list_for_each_entry(srp, &fp->rq_list, entry) {
254962306a36Sopenharmony_ci			hp = &srp->header;
255062306a36Sopenharmony_ci			new_interface = (hp->interface_id == '\0') ? 0 : 1;
255162306a36Sopenharmony_ci			if (srp->res_used) {
255262306a36Sopenharmony_ci				if (new_interface &&
255362306a36Sopenharmony_ci				    (SG_FLAG_MMAP_IO & hp->flags))
255462306a36Sopenharmony_ci					cp = "     mmap>> ";
255562306a36Sopenharmony_ci				else
255662306a36Sopenharmony_ci					cp = "     rb>> ";
255762306a36Sopenharmony_ci			} else {
255862306a36Sopenharmony_ci				if (SG_INFO_DIRECT_IO_MASK & hp->info)
255962306a36Sopenharmony_ci					cp = "     dio>> ";
256062306a36Sopenharmony_ci				else
256162306a36Sopenharmony_ci					cp = "     ";
256262306a36Sopenharmony_ci			}
256362306a36Sopenharmony_ci			seq_puts(s, cp);
256462306a36Sopenharmony_ci			blen = srp->data.bufflen;
256562306a36Sopenharmony_ci			usg = srp->data.k_use_sg;
256662306a36Sopenharmony_ci			seq_puts(s, srp->done ?
256762306a36Sopenharmony_ci				 ((1 == srp->done) ?  "rcv:" : "fin:")
256862306a36Sopenharmony_ci				  : "act:");
256962306a36Sopenharmony_ci			seq_printf(s, " id=%d blen=%d",
257062306a36Sopenharmony_ci				   srp->header.pack_id, blen);
257162306a36Sopenharmony_ci			if (srp->done)
257262306a36Sopenharmony_ci				seq_printf(s, " dur=%d", hp->duration);
257362306a36Sopenharmony_ci			else {
257462306a36Sopenharmony_ci				ms = jiffies_to_msecs(jiffies);
257562306a36Sopenharmony_ci				seq_printf(s, " t_o/elap=%d/%d",
257662306a36Sopenharmony_ci					(new_interface ? hp->timeout :
257762306a36Sopenharmony_ci						  jiffies_to_msecs(fp->timeout)),
257862306a36Sopenharmony_ci					(ms > hp->duration ? ms - hp->duration : 0));
257962306a36Sopenharmony_ci			}
258062306a36Sopenharmony_ci			seq_printf(s, "ms sgat=%d op=0x%02x\n", usg,
258162306a36Sopenharmony_ci				   (int) srp->data.cmd_opcode);
258262306a36Sopenharmony_ci		}
258362306a36Sopenharmony_ci		if (list_empty(&fp->rq_list))
258462306a36Sopenharmony_ci			seq_puts(s, "     No requests active\n");
258562306a36Sopenharmony_ci		read_unlock(&fp->rq_list_lock);
258662306a36Sopenharmony_ci	}
258762306a36Sopenharmony_ci}
258862306a36Sopenharmony_ci
258962306a36Sopenharmony_cistatic int sg_proc_seq_show_debug(struct seq_file *s, void *v)
259062306a36Sopenharmony_ci{
259162306a36Sopenharmony_ci	struct sg_proc_deviter * it = (struct sg_proc_deviter *) v;
259262306a36Sopenharmony_ci	Sg_device *sdp;
259362306a36Sopenharmony_ci	unsigned long iflags;
259462306a36Sopenharmony_ci
259562306a36Sopenharmony_ci	if (it && (0 == it->index))
259662306a36Sopenharmony_ci		seq_printf(s, "max_active_device=%d  def_reserved_size=%d\n",
259762306a36Sopenharmony_ci			   (int)it->max, sg_big_buff);
259862306a36Sopenharmony_ci
259962306a36Sopenharmony_ci	read_lock_irqsave(&sg_index_lock, iflags);
260062306a36Sopenharmony_ci	sdp = it ? sg_lookup_dev(it->index) : NULL;
260162306a36Sopenharmony_ci	if (NULL == sdp)
260262306a36Sopenharmony_ci		goto skip;
260362306a36Sopenharmony_ci	read_lock(&sdp->sfd_lock);
260462306a36Sopenharmony_ci	if (!list_empty(&sdp->sfds)) {
260562306a36Sopenharmony_ci		seq_printf(s, " >>> device=%s ", sdp->name);
260662306a36Sopenharmony_ci		if (atomic_read(&sdp->detaching))
260762306a36Sopenharmony_ci			seq_puts(s, "detaching pending close ");
260862306a36Sopenharmony_ci		else if (sdp->device) {
260962306a36Sopenharmony_ci			struct scsi_device *scsidp = sdp->device;
261062306a36Sopenharmony_ci
261162306a36Sopenharmony_ci			seq_printf(s, "%d:%d:%d:%llu   em=%d",
261262306a36Sopenharmony_ci				   scsidp->host->host_no,
261362306a36Sopenharmony_ci				   scsidp->channel, scsidp->id,
261462306a36Sopenharmony_ci				   scsidp->lun,
261562306a36Sopenharmony_ci				   scsidp->host->hostt->emulated);
261662306a36Sopenharmony_ci		}
261762306a36Sopenharmony_ci		seq_printf(s, " sg_tablesize=%d excl=%d open_cnt=%d\n",
261862306a36Sopenharmony_ci			   sdp->sg_tablesize, sdp->exclude, sdp->open_cnt);
261962306a36Sopenharmony_ci		sg_proc_debug_helper(s, sdp);
262062306a36Sopenharmony_ci	}
262162306a36Sopenharmony_ci	read_unlock(&sdp->sfd_lock);
262262306a36Sopenharmony_ciskip:
262362306a36Sopenharmony_ci	read_unlock_irqrestore(&sg_index_lock, iflags);
262462306a36Sopenharmony_ci	return 0;
262562306a36Sopenharmony_ci}
262662306a36Sopenharmony_ci
262762306a36Sopenharmony_ci#endif				/* CONFIG_SCSI_PROC_FS */
262862306a36Sopenharmony_ci
262962306a36Sopenharmony_cimodule_init(init_sg);
263062306a36Sopenharmony_cimodule_exit(exit_sg);
2631