18d7c56d0SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * History: 41da177e4SLinus Torvalds * Started: Aug 9 by Lawrence Foard (entropy@world.std.com), 51da177e4SLinus Torvalds * to allow user process control of SCSI devices. 61da177e4SLinus Torvalds * Development Sponsored by Killy Corp. NY NY 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * Original driver (sg.c): 91da177e4SLinus Torvalds * Copyright (C) 1992 Lawrence Foard 101da177e4SLinus Torvalds * Version 2 and 3 extensions to driver: 1165c26a0fSDouglas Gilbert * Copyright (C) 1998 - 2014 Douglas Gilbert 121da177e4SLinus Torvalds */ 131da177e4SLinus Torvalds 1465c26a0fSDouglas Gilbert static int sg_version_num = 30536; /* 2 digits for each component */ 1565c26a0fSDouglas Gilbert #define SG_VERSION_STR "3.5.36" 161da177e4SLinus Torvalds 171da177e4SLinus Torvalds /* 1865c26a0fSDouglas Gilbert * D. P. Gilbert (dgilbert@interlog.com), notes: 191da177e4SLinus Torvalds * - scsi logging is available via SCSI_LOG_TIMEOUT macros. First 201da177e4SLinus Torvalds * the kernel/module needs to be built with CONFIG_SCSI_LOGGING 211da177e4SLinus Torvalds * (otherwise the macros compile to empty statements). 221da177e4SLinus Torvalds * 231da177e4SLinus Torvalds */ 241da177e4SLinus Torvalds #include <linux/module.h> 251da177e4SLinus Torvalds 261da177e4SLinus Torvalds #include <linux/fs.h> 271da177e4SLinus Torvalds #include <linux/kernel.h> 281da177e4SLinus Torvalds #include <linux/sched.h> 291da177e4SLinus Torvalds #include <linux/string.h> 301da177e4SLinus Torvalds #include <linux/mm.h> 311da177e4SLinus Torvalds #include <linux/errno.h> 321da177e4SLinus Torvalds #include <linux/mtio.h> 331da177e4SLinus Torvalds #include <linux/ioctl.h> 34b81e0c23SChristoph Hellwig #include <linux/major.h> 355a0e3ad6STejun Heo #include <linux/slab.h> 361da177e4SLinus Torvalds #include <linux/fcntl.h> 371da177e4SLinus Torvalds #include <linux/init.h> 381da177e4SLinus Torvalds #include <linux/poll.h> 391da177e4SLinus Torvalds #include <linux/moduleparam.h> 401da177e4SLinus Torvalds #include <linux/cdev.h> 417c07d613SJames Bottomley #include <linux/idr.h> 421da177e4SLinus Torvalds #include <linux/seq_file.h> 431da177e4SLinus Torvalds #include <linux/blkdev.h> 441da177e4SLinus Torvalds #include <linux/delay.h> 456da127adSChristof Schmitt #include <linux/blktrace_api.h> 46c45d15d2SArnd Bergmann #include <linux/mutex.h> 47cc833acbSDouglas Gilbert #include <linux/atomic.h> 482fe038e3SChristian Dietrich #include <linux/ratelimit.h> 49e2e40f2cSChristoph Hellwig #include <linux/uio.h> 5026b5b874SJann Horn #include <linux/cred.h> /* for sg_check_file_access() */ 511da177e4SLinus Torvalds 5253555fb7SBart Van Assche #include <scsi/scsi.h> 5353555fb7SBart Van Assche #include <scsi/scsi_cmnd.h> 54db9dff36S #include <scsi/scsi_dbg.h> 5553555fb7SBart Van Assche #include <scsi/scsi_device.h> 561da177e4SLinus Torvalds #include <scsi/scsi_driver.h> 5753555fb7SBart Van Assche #include <scsi/scsi_eh.h> 5853555fb7SBart Van Assche #include <scsi/scsi_host.h> 591da177e4SLinus Torvalds #include <scsi/scsi_ioctl.h> 6053555fb7SBart Van Assche #include <scsi/scsi_tcq.h> 611da177e4SLinus Torvalds #include <scsi/sg.h> 621da177e4SLinus Torvalds 631da177e4SLinus Torvalds #include "scsi_logging.h" 641da177e4SLinus Torvalds 651da177e4SLinus Torvalds #ifdef CONFIG_SCSI_PROC_FS 661da177e4SLinus Torvalds #include <linux/proc_fs.h> 6765c26a0fSDouglas Gilbert static char *sg_version_date = "20140603"; 681da177e4SLinus Torvalds 691da177e4SLinus Torvalds static int sg_proc_init(void); 701da177e4SLinus Torvalds #endif 711da177e4SLinus Torvalds 721da177e4SLinus Torvalds #define SG_ALLOW_DIO_DEF 0 731da177e4SLinus Torvalds 7437c918e0SHannes Reinecke #define SG_MAX_DEVS (1 << MINORBITS) 751da177e4SLinus Torvalds 7665c26a0fSDouglas Gilbert /* SG_MAX_CDB_SIZE should be 260 (spc4r37 section 3.1.30) however the type 7765c26a0fSDouglas Gilbert * of sg_io_hdr::cmd_len can only represent 255. All SCSI commands greater 7865c26a0fSDouglas Gilbert * than 16 bytes are "variable length" whose length is a multiple of 4 7965c26a0fSDouglas Gilbert */ 8065c26a0fSDouglas Gilbert #define SG_MAX_CDB_SIZE 252 8165c26a0fSDouglas Gilbert 82f8630bd7SPaul Burton #define SG_DEFAULT_TIMEOUT mult_frac(SG_DEFAULT_TIMEOUT_USER, HZ, USER_HZ) 831da177e4SLinus Torvalds 8426d1c80fSXiaoming Ni static int sg_big_buff = SG_DEF_RESERVED_SIZE; 851da177e4SLinus Torvalds /* N.B. This variable is readable and writeable via 861da177e4SLinus Torvalds /proc/scsi/sg/def_reserved_size . Each time sg_open() is called a buffer 871da177e4SLinus Torvalds of this size (or less if there is not enough memory) will be reserved 881da177e4SLinus Torvalds for use by this file descriptor. [Deprecated usage: this variable is also 891da177e4SLinus Torvalds readable via /proc/sys/kernel/sg-big-buff if the sg driver is built into 901da177e4SLinus Torvalds the kernel (i.e. it is not a module).] */ 911da177e4SLinus Torvalds static int def_reserved_size = -1; /* picks up init parameter */ 921da177e4SLinus Torvalds static int sg_allow_dio = SG_ALLOW_DIO_DEF; 931da177e4SLinus Torvalds 946460e75aSDouglas Gilbert static int scatter_elem_sz = SG_SCATTER_SZ; 956460e75aSDouglas Gilbert static int scatter_elem_sz_prev = SG_SCATTER_SZ; 966460e75aSDouglas Gilbert 971da177e4SLinus Torvalds #define SG_SECTOR_SZ 512 981da177e4SLinus Torvalds 992243acd5SGreg Kroah-Hartman static int sg_add_device(struct device *); 1002243acd5SGreg Kroah-Hartman static void sg_remove_device(struct device *); 10198481ff0SJames Bottomley 1027c07d613SJames Bottomley static DEFINE_IDR(sg_index_idr); 103c0d3b9c2SJames Bottomley static DEFINE_RWLOCK(sg_index_lock); /* Also used to lock 104c0d3b9c2SJames Bottomley file descriptor list for device */ 1051da177e4SLinus Torvalds 1061da177e4SLinus Torvalds static struct class_interface sg_interface = { 107cc833acbSDouglas Gilbert .add_dev = sg_add_device, 108cc833acbSDouglas Gilbert .remove_dev = sg_remove_device, 1091da177e4SLinus Torvalds }; 1101da177e4SLinus Torvalds 1111da177e4SLinus Torvalds typedef struct sg_scatter_hold { /* holding area for scsi scatter gather info */ 1121da177e4SLinus Torvalds unsigned short k_use_sg; /* Count of kernel scatter-gather pieces */ 113ea312552SFUJITA Tomonori unsigned sglist_len; /* size of malloc'd scatter-gather list ++ */ 1141da177e4SLinus Torvalds unsigned bufflen; /* Size of (aggregate) data buffer */ 11510db10d1SFUJITA Tomonori struct page **pages; 11610db10d1SFUJITA Tomonori int page_order; 1171da177e4SLinus Torvalds char dio_in_use; /* 0->indirect IO (or mmap), 1->dio */ 1181da177e4SLinus Torvalds unsigned char cmd_opcode; /* first byte of command */ 1191da177e4SLinus Torvalds } Sg_scatter_hold; 1201da177e4SLinus Torvalds 1211da177e4SLinus Torvalds struct sg_device; /* forward declarations */ 1221da177e4SLinus Torvalds struct sg_fd; 1231da177e4SLinus Torvalds 1241da177e4SLinus Torvalds typedef struct sg_request { /* SG_MAX_QUEUE requests outstanding per file */ 125109bade9SHannes Reinecke struct list_head entry; /* list entry */ 1261da177e4SLinus Torvalds struct sg_fd *parentfp; /* NULL -> not in use */ 1271da177e4SLinus Torvalds Sg_scatter_hold data; /* hold buffer, perhaps scatter list */ 1281da177e4SLinus Torvalds sg_io_hdr_t header; /* scsi command+info, see <scsi/sg.h> */ 129d6b10348SMike Christie unsigned char sense_b[SCSI_SENSE_BUFFERSIZE]; 1301da177e4SLinus Torvalds char res_used; /* 1 -> using reserve buffer, 0 -> not ... */ 1311da177e4SLinus Torvalds char orphan; /* 1 -> drop on sight, 0 -> normal */ 1321da177e4SLinus Torvalds char sg_io_owned; /* 1 -> packet belongs to SG_IO */ 1336acddc5eSJörn Engel /* done protected by rq_list_lock */ 1346acddc5eSJörn Engel char done; /* 0->before bh, 1->before read, 2->read */ 13510865dfaSFUJITA Tomonori struct request *rq; 1366e5a30cbSFUJITA Tomonori struct bio *bio; 137c96952edSFUJITA Tomonori struct execute_work ew; 1381da177e4SLinus Torvalds } Sg_request; 1391da177e4SLinus Torvalds 1401da177e4SLinus Torvalds typedef struct sg_fd { /* holds the state of a file descriptor */ 141cc833acbSDouglas Gilbert struct list_head sfd_siblings; /* protected by device's sfd_lock */ 1421da177e4SLinus Torvalds struct sg_device *parentdp; /* owning device */ 1431da177e4SLinus Torvalds wait_queue_head_t read_wait; /* queue read until command done */ 1441da177e4SLinus Torvalds rwlock_t rq_list_lock; /* protect access to list in req_arr */ 1451bc0eb04SHannes Reinecke struct mutex f_mutex; /* protect against changes in this fd */ 1461da177e4SLinus Torvalds int timeout; /* defaults to SG_DEFAULT_TIMEOUT */ 1471da177e4SLinus Torvalds int timeout_user; /* defaults to SG_DEFAULT_TIMEOUT_USER */ 1481da177e4SLinus Torvalds Sg_scatter_hold reserve; /* buffer held for this file descriptor */ 149109bade9SHannes Reinecke struct list_head rq_list; /* head of request list */ 1501da177e4SLinus Torvalds struct fasync_struct *async_qp; /* used by asynchronous notification */ 1511da177e4SLinus Torvalds Sg_request req_arr[SG_MAX_QUEUE]; /* used as singly-linked list */ 1521da177e4SLinus Torvalds char force_packid; /* 1 -> pack_id input to read(), 0 -> ignored */ 1531da177e4SLinus Torvalds char cmd_q; /* 1 -> allow command queuing, 0 -> don't */ 15465c26a0fSDouglas Gilbert unsigned char next_cmd_len; /* 0: automatic, >0: use on next write() */ 1551da177e4SLinus Torvalds char keep_orphan; /* 0 -> drop orphan (def), 1 -> keep for read() */ 1561da177e4SLinus Torvalds char mmap_called; /* 0 -> mmap() never called on this fd */ 1571bc0eb04SHannes Reinecke char res_in_use; /* 1 -> 'reserve' array in use */ 158c6517b79STony Battersby struct kref f_ref; 159c6517b79STony Battersby struct execute_work ew; 1601da177e4SLinus Torvalds } Sg_fd; 1611da177e4SLinus Torvalds 1621da177e4SLinus Torvalds typedef struct sg_device { /* holds the state of each scsi generic device */ 1631da177e4SLinus Torvalds struct scsi_device *device; 164cc833acbSDouglas Gilbert wait_queue_head_t open_wait; /* queue open() when O_EXCL present */ 165cc833acbSDouglas Gilbert struct mutex open_rel_lock; /* held when in open() or release() */ 1661da177e4SLinus Torvalds int sg_tablesize; /* adapter's max scatter-gather table size */ 1677c07d613SJames Bottomley u32 index; /* device index number */ 1683442f802SFUJITA Tomonori struct list_head sfds; 169cc833acbSDouglas Gilbert rwlock_t sfd_lock; /* protect access to sfd list */ 170cc833acbSDouglas Gilbert atomic_t detaching; /* 0->device usable, 1->device detaching */ 171cc833acbSDouglas Gilbert bool exclude; /* 1->open(O_EXCL) succeeded and is active */ 172cc833acbSDouglas Gilbert int open_cnt; /* count of opens (perhaps < num(sfds) ) */ 1731da177e4SLinus Torvalds char sgdebug; /* 0->off, 1->sense, 9->dump dev, 10-> all devs */ 174aebbb583SChristoph Hellwig char name[DISK_NAME_LEN]; 1751da177e4SLinus Torvalds struct cdev * cdev; /* char_dev [sysfs: /sys/cdev/major/sg<n>] */ 176c6517b79STony Battersby struct kref d_ref; 1771da177e4SLinus Torvalds } Sg_device; 1781da177e4SLinus Torvalds 179d6b10348SMike Christie /* tasklet or soft irq callback */ 180de671d61SJens Axboe static enum rq_end_io_ret sg_rq_end_io(struct request *rq, blk_status_t status); 18110865dfaSFUJITA Tomonori static int sg_start_req(Sg_request *srp, unsigned char *cmd); 182e7ee4cc0SFUJITA Tomonori static int sg_finish_rem_req(Sg_request * srp); 1831da177e4SLinus Torvalds static int sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size); 1841da177e4SLinus Torvalds static ssize_t sg_new_read(Sg_fd * sfp, char __user *buf, size_t count, 1851da177e4SLinus Torvalds Sg_request * srp); 1860b07de85SAdel Gadllah static ssize_t sg_new_write(Sg_fd *sfp, struct file *file, 1870b07de85SAdel Gadllah const char __user *buf, size_t count, int blocking, 188a2dd3b4cSTony Battersby int read_only, int sg_io_owned, Sg_request **o_srp); 1891da177e4SLinus Torvalds static int sg_common_write(Sg_fd * sfp, Sg_request * srp, 1901da177e4SLinus Torvalds unsigned char *cmnd, int timeout, int blocking); 1911da177e4SLinus Torvalds static int sg_read_oxfer(Sg_request * srp, char __user *outp, int num_read_xfer); 19295e159d6SHannes Reinecke static void sg_remove_scat(Sg_fd * sfp, Sg_scatter_hold * schp); 1931da177e4SLinus Torvalds static void sg_build_reserve(Sg_fd * sfp, int req_size); 1941da177e4SLinus Torvalds static void sg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size); 1951da177e4SLinus Torvalds static void sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp); 19695e159d6SHannes Reinecke static Sg_fd *sg_add_sfp(Sg_device * sdp); 197c6517b79STony Battersby static void sg_remove_sfp(struct kref *); 1983455607fSTony Battersby static Sg_request *sg_get_rq_mark(Sg_fd * sfp, int pack_id, bool *busy); 1991da177e4SLinus Torvalds static Sg_request *sg_add_request(Sg_fd * sfp); 2001da177e4SLinus Torvalds static int sg_remove_request(Sg_fd * sfp, Sg_request * srp); 2011da177e4SLinus Torvalds static Sg_device *sg_get_dev(int dev); 202cc833acbSDouglas Gilbert static void sg_device_destroy(struct kref *kref); 2031da177e4SLinus Torvalds 2041da177e4SLinus Torvalds #define SZ_SG_HEADER sizeof(struct sg_header) 2051da177e4SLinus Torvalds #define SZ_SG_IO_HDR sizeof(sg_io_hdr_t) 2061da177e4SLinus Torvalds #define SZ_SG_IOVEC sizeof(sg_iovec_t) 2071da177e4SLinus Torvalds #define SZ_SG_REQ_INFO sizeof(sg_req_info_t) 2081da177e4SLinus Torvalds 20995e159d6SHannes Reinecke #define sg_printk(prefix, sdp, fmt, a...) \ 210aebbb583SChristoph Hellwig sdev_prefix_printk(prefix, (sdp)->device, (sdp)->name, fmt, ##a) 21195e159d6SHannes Reinecke 21226b5b874SJann Horn /* 21326b5b874SJann Horn * The SCSI interfaces that use read() and write() as an asynchronous variant of 21426b5b874SJann Horn * ioctl(..., SG_IO, ...) are fundamentally unsafe, since there are lots of ways 21526b5b874SJann Horn * to trigger read() and write() calls from various contexts with elevated 21626b5b874SJann Horn * privileges. This can lead to kernel memory corruption (e.g. if these 21726b5b874SJann Horn * interfaces are called through splice()) and privilege escalation inside 21826b5b874SJann Horn * userspace (e.g. if a process with access to such a device passes a file 21926b5b874SJann Horn * descriptor to a SUID binary as stdin/stdout/stderr). 22026b5b874SJann Horn * 22126b5b874SJann Horn * This function provides protection for the legacy API by restricting the 22226b5b874SJann Horn * calling context. 22326b5b874SJann Horn */ 22426b5b874SJann Horn static int sg_check_file_access(struct file *filp, const char *caller) 22526b5b874SJann Horn { 22626b5b874SJann Horn if (filp->f_cred != current_real_cred()) { 22726b5b874SJann Horn pr_err_once("%s: process %d (%s) changed security contexts after opening file descriptor, this is not allowed.\n", 22826b5b874SJann Horn caller, task_tgid_vnr(current), current->comm); 22926b5b874SJann Horn return -EPERM; 23026b5b874SJann Horn } 23126b5b874SJann Horn return 0; 23226b5b874SJann Horn } 23326b5b874SJann Horn 23414e507b8SFUJITA Tomonori static int sg_allow_access(struct file *filp, unsigned char *cmd) 23514e507b8SFUJITA Tomonori { 23635df8397SJoe Perches struct sg_fd *sfp = filp->private_data; 23714e507b8SFUJITA Tomonori 23814e507b8SFUJITA Tomonori if (sfp->parentdp->device->type == TYPE_SCANNER) 23914e507b8SFUJITA Tomonori return 0; 2405f4eb9d5SChristoph Hellwig if (!scsi_cmd_allowed(cmd, filp->f_mode & FMODE_WRITE)) 2417353dc06SChristoph Hellwig return -EPERM; 2427353dc06SChristoph Hellwig return 0; 24314e507b8SFUJITA Tomonori } 24414e507b8SFUJITA Tomonori 245cc833acbSDouglas Gilbert static int 246cc833acbSDouglas Gilbert open_wait(Sg_device *sdp, int flags) 24798481ff0SJames Bottomley { 248cc833acbSDouglas Gilbert int retval = 0; 24998481ff0SJames Bottomley 250cc833acbSDouglas Gilbert if (flags & O_EXCL) { 251cc833acbSDouglas Gilbert while (sdp->open_cnt > 0) { 252cc833acbSDouglas Gilbert mutex_unlock(&sdp->open_rel_lock); 253cc833acbSDouglas Gilbert retval = wait_event_interruptible(sdp->open_wait, 254cc833acbSDouglas Gilbert (atomic_read(&sdp->detaching) || 255cc833acbSDouglas Gilbert !sdp->open_cnt)); 256cc833acbSDouglas Gilbert mutex_lock(&sdp->open_rel_lock); 257cc833acbSDouglas Gilbert 258cc833acbSDouglas Gilbert if (retval) /* -ERESTARTSYS */ 259cc833acbSDouglas Gilbert return retval; 260cc833acbSDouglas Gilbert if (atomic_read(&sdp->detaching)) 261cc833acbSDouglas Gilbert return -ENODEV; 262cc833acbSDouglas Gilbert } 263cc833acbSDouglas Gilbert } else { 264cc833acbSDouglas Gilbert while (sdp->exclude) { 265cc833acbSDouglas Gilbert mutex_unlock(&sdp->open_rel_lock); 266cc833acbSDouglas Gilbert retval = wait_event_interruptible(sdp->open_wait, 267cc833acbSDouglas Gilbert (atomic_read(&sdp->detaching) || 268cc833acbSDouglas Gilbert !sdp->exclude)); 269cc833acbSDouglas Gilbert mutex_lock(&sdp->open_rel_lock); 270cc833acbSDouglas Gilbert 271cc833acbSDouglas Gilbert if (retval) /* -ERESTARTSYS */ 272cc833acbSDouglas Gilbert return retval; 273cc833acbSDouglas Gilbert if (atomic_read(&sdp->detaching)) 274cc833acbSDouglas Gilbert return -ENODEV; 275cc833acbSDouglas Gilbert } 27698481ff0SJames Bottomley } 27798481ff0SJames Bottomley 278cc833acbSDouglas Gilbert return retval; 27998481ff0SJames Bottomley } 28098481ff0SJames Bottomley 281cc833acbSDouglas Gilbert /* Returns 0 on success, else a negated errno value */ 2821da177e4SLinus Torvalds static int 2831da177e4SLinus Torvalds sg_open(struct inode *inode, struct file *filp) 2841da177e4SLinus Torvalds { 2851da177e4SLinus Torvalds int dev = iminor(inode); 2861da177e4SLinus Torvalds int flags = filp->f_flags; 287d6b10348SMike Christie struct request_queue *q; 288*d4e655c4SAlexander Wetzel struct scsi_device *device; 2891da177e4SLinus Torvalds Sg_device *sdp; 2901da177e4SLinus Torvalds Sg_fd *sfp; 2911da177e4SLinus Torvalds int retval; 2921da177e4SLinus Torvalds 2931da177e4SLinus Torvalds nonseekable_open(inode, filp); 294cc833acbSDouglas Gilbert if ((flags & O_EXCL) && (O_RDONLY == (flags & O_ACCMODE))) 295cc833acbSDouglas Gilbert return -EPERM; /* Can't lock it with read only access */ 2961da177e4SLinus Torvalds sdp = sg_get_dev(dev); 297cc833acbSDouglas Gilbert if (IS_ERR(sdp)) 298cc833acbSDouglas Gilbert return PTR_ERR(sdp); 2991da177e4SLinus Torvalds 30095e159d6SHannes Reinecke SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp, 30195e159d6SHannes Reinecke "sg_open: flags=0x%x\n", flags)); 30295e159d6SHannes Reinecke 3031da177e4SLinus Torvalds /* This driver's module count bumped by fops_get in <linux/fs.h> */ 3041da177e4SLinus Torvalds /* Prevent the device driver from vanishing while we sleep */ 305*d4e655c4SAlexander Wetzel device = sdp->device; 306*d4e655c4SAlexander Wetzel retval = scsi_device_get(device); 307c6517b79STony Battersby if (retval) 308c6517b79STony Battersby goto sg_put; 3091da177e4SLinus Torvalds 310*d4e655c4SAlexander Wetzel retval = scsi_autopm_get_device(device); 311bc4f2401SAlan Stern if (retval) 312bc4f2401SAlan Stern goto sdp_put; 313bc4f2401SAlan Stern 314cc833acbSDouglas Gilbert /* scsi_block_when_processing_errors() may block so bypass 315cc833acbSDouglas Gilbert * check if O_NONBLOCK. Permits SCSI commands to be issued 316cc833acbSDouglas Gilbert * during error recovery. Tread carefully. */ 3171da177e4SLinus Torvalds if (!((flags & O_NONBLOCK) || 318*d4e655c4SAlexander Wetzel scsi_block_when_processing_errors(device))) { 3191da177e4SLinus Torvalds retval = -ENXIO; 3201da177e4SLinus Torvalds /* we are in error recovery for this device */ 3211da177e4SLinus Torvalds goto error_out; 3221da177e4SLinus Torvalds } 3231da177e4SLinus Torvalds 324cc833acbSDouglas Gilbert mutex_lock(&sdp->open_rel_lock); 3251da177e4SLinus Torvalds if (flags & O_NONBLOCK) { 326cc833acbSDouglas Gilbert if (flags & O_EXCL) { 327cc833acbSDouglas Gilbert if (sdp->open_cnt > 0) { 3281da177e4SLinus Torvalds retval = -EBUSY; 329cc833acbSDouglas Gilbert goto error_mutex_locked; 3301da177e4SLinus Torvalds } 331cc833acbSDouglas Gilbert } else { 332cc833acbSDouglas Gilbert if (sdp->exclude) { 333cc833acbSDouglas Gilbert retval = -EBUSY; 334cc833acbSDouglas Gilbert goto error_mutex_locked; 3351da177e4SLinus Torvalds } 3361da177e4SLinus Torvalds } 337cc833acbSDouglas Gilbert } else { 338cc833acbSDouglas Gilbert retval = open_wait(sdp, flags); 339cc833acbSDouglas Gilbert if (retval) /* -ERESTARTSYS or -ENODEV */ 340cc833acbSDouglas Gilbert goto error_mutex_locked; 341bafc8ad8SJames Bottomley } 342cc833acbSDouglas Gilbert 343cc833acbSDouglas Gilbert /* N.B. at this point we are holding the open_rel_lock */ 344cc833acbSDouglas Gilbert if (flags & O_EXCL) 345cc833acbSDouglas Gilbert sdp->exclude = true; 346cc833acbSDouglas Gilbert 347cc833acbSDouglas Gilbert if (sdp->open_cnt < 1) { /* no existing opens */ 3481da177e4SLinus Torvalds sdp->sgdebug = 0; 349*d4e655c4SAlexander Wetzel q = device->request_queue; 3508a78362cSMartin K. Petersen sdp->sg_tablesize = queue_max_segments(q); 3511da177e4SLinus Torvalds } 35295e159d6SHannes Reinecke sfp = sg_add_sfp(sdp); 353cc833acbSDouglas Gilbert if (IS_ERR(sfp)) { 354cc833acbSDouglas Gilbert retval = PTR_ERR(sfp); 355cc833acbSDouglas Gilbert goto out_undo; 356cc833acbSDouglas Gilbert } 357cc833acbSDouglas Gilbert 3581da177e4SLinus Torvalds filp->private_data = sfp; 359cc833acbSDouglas Gilbert sdp->open_cnt++; 360cc833acbSDouglas Gilbert mutex_unlock(&sdp->open_rel_lock); 361cc833acbSDouglas Gilbert 362065b4a2fSJames Bottomley retval = 0; 363cc833acbSDouglas Gilbert sg_put: 364cc833acbSDouglas Gilbert kref_put(&sdp->d_ref, sg_device_destroy); 365cc833acbSDouglas Gilbert return retval; 366cc833acbSDouglas Gilbert 367cc833acbSDouglas Gilbert out_undo: 368cc833acbSDouglas Gilbert if (flags & O_EXCL) { 369cc833acbSDouglas Gilbert sdp->exclude = false; /* undo if error */ 370cc833acbSDouglas Gilbert wake_up_interruptible(&sdp->open_wait); 371cc833acbSDouglas Gilbert } 372cc833acbSDouglas Gilbert error_mutex_locked: 373cc833acbSDouglas Gilbert mutex_unlock(&sdp->open_rel_lock); 3741da177e4SLinus Torvalds error_out: 375*d4e655c4SAlexander Wetzel scsi_autopm_put_device(device); 376bc4f2401SAlan Stern sdp_put: 377*d4e655c4SAlexander Wetzel kref_put(&sdp->d_ref, sg_device_destroy); 378*d4e655c4SAlexander Wetzel scsi_device_put(device); 379*d4e655c4SAlexander Wetzel return retval; 3801da177e4SLinus Torvalds } 3811da177e4SLinus Torvalds 382cc833acbSDouglas Gilbert /* Release resources associated with a successful sg_open() 383cc833acbSDouglas Gilbert * Returns 0 on success, else a negated errno value */ 3841da177e4SLinus Torvalds static int 3851da177e4SLinus Torvalds sg_release(struct inode *inode, struct file *filp) 3861da177e4SLinus Torvalds { 3871da177e4SLinus Torvalds Sg_device *sdp; 3881da177e4SLinus Torvalds Sg_fd *sfp; 3891da177e4SLinus Torvalds 3901da177e4SLinus Torvalds if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp))) 3911da177e4SLinus Torvalds return -ENXIO; 39295e159d6SHannes Reinecke SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp, "sg_release\n")); 393c6517b79STony Battersby 394cc833acbSDouglas Gilbert mutex_lock(&sdp->open_rel_lock); 395bc4f2401SAlan Stern scsi_autopm_put_device(sdp->device); 396c6517b79STony Battersby kref_put(&sfp->f_ref, sg_remove_sfp); 397cc833acbSDouglas Gilbert sdp->open_cnt--; 398cc833acbSDouglas Gilbert 399cc833acbSDouglas Gilbert /* possibly many open()s waiting on exlude clearing, start many; 400cc833acbSDouglas Gilbert * only open(O_EXCL)s wait on 0==open_cnt so only start one */ 401cc833acbSDouglas Gilbert if (sdp->exclude) { 402cc833acbSDouglas Gilbert sdp->exclude = false; 403cc833acbSDouglas Gilbert wake_up_interruptible_all(&sdp->open_wait); 404cc833acbSDouglas Gilbert } else if (0 == sdp->open_cnt) { 405cc833acbSDouglas Gilbert wake_up_interruptible(&sdp->open_wait); 406cc833acbSDouglas Gilbert } 407cc833acbSDouglas Gilbert mutex_unlock(&sdp->open_rel_lock); 4081da177e4SLinus Torvalds return 0; 4091da177e4SLinus Torvalds } 4101da177e4SLinus Torvalds 41178ed001dSArnd Bergmann static int get_sg_io_pack_id(int *pack_id, void __user *buf, size_t count) 41278ed001dSArnd Bergmann { 41378ed001dSArnd Bergmann struct sg_header __user *old_hdr = buf; 41478ed001dSArnd Bergmann int reply_len; 41578ed001dSArnd Bergmann 41678ed001dSArnd Bergmann if (count >= SZ_SG_HEADER) { 41778ed001dSArnd Bergmann /* negative reply_len means v3 format, otherwise v1/v2 */ 41878ed001dSArnd Bergmann if (get_user(reply_len, &old_hdr->reply_len)) 41978ed001dSArnd Bergmann return -EFAULT; 42078ed001dSArnd Bergmann 42178ed001dSArnd Bergmann if (reply_len >= 0) 42278ed001dSArnd Bergmann return get_user(*pack_id, &old_hdr->pack_id); 42378ed001dSArnd Bergmann 42478ed001dSArnd Bergmann if (in_compat_syscall() && 42578ed001dSArnd Bergmann count >= sizeof(struct compat_sg_io_hdr)) { 42678ed001dSArnd Bergmann struct compat_sg_io_hdr __user *hp = buf; 42778ed001dSArnd Bergmann 42878ed001dSArnd Bergmann return get_user(*pack_id, &hp->pack_id); 42978ed001dSArnd Bergmann } 43078ed001dSArnd Bergmann 43178ed001dSArnd Bergmann if (count >= sizeof(struct sg_io_hdr)) { 43278ed001dSArnd Bergmann struct sg_io_hdr __user *hp = buf; 43378ed001dSArnd Bergmann 43478ed001dSArnd Bergmann return get_user(*pack_id, &hp->pack_id); 43578ed001dSArnd Bergmann } 43678ed001dSArnd Bergmann } 43778ed001dSArnd Bergmann 43878ed001dSArnd Bergmann /* no valid header was passed, so ignore the pack_id */ 43978ed001dSArnd Bergmann *pack_id = -1; 44078ed001dSArnd Bergmann return 0; 44178ed001dSArnd Bergmann } 44278ed001dSArnd Bergmann 4431da177e4SLinus Torvalds static ssize_t 4441da177e4SLinus Torvalds sg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos) 4451da177e4SLinus Torvalds { 4461da177e4SLinus Torvalds Sg_device *sdp; 4471da177e4SLinus Torvalds Sg_fd *sfp; 4481da177e4SLinus Torvalds Sg_request *srp; 4491da177e4SLinus Torvalds int req_pack_id = -1; 4503455607fSTony Battersby bool busy; 4511da177e4SLinus Torvalds sg_io_hdr_t *hp; 45278ed001dSArnd Bergmann struct sg_header *old_hdr; 45378ed001dSArnd Bergmann int retval; 4541da177e4SLinus Torvalds 45526b5b874SJann Horn /* 45626b5b874SJann Horn * This could cause a response to be stranded. Close the associated 45726b5b874SJann Horn * file descriptor to free up any resources being held. 45826b5b874SJann Horn */ 45926b5b874SJann Horn retval = sg_check_file_access(filp, __func__); 46026b5b874SJann Horn if (retval) 46126b5b874SJann Horn return retval; 46226b5b874SJann Horn 4631da177e4SLinus Torvalds if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp))) 4641da177e4SLinus Torvalds return -ENXIO; 46595e159d6SHannes Reinecke SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp, 46695e159d6SHannes Reinecke "sg_read: count=%d\n", (int) count)); 467d6b10348SMike Christie 46878ed001dSArnd Bergmann if (sfp->force_packid) 46978ed001dSArnd Bergmann retval = get_sg_io_pack_id(&req_pack_id, buf, count); 47078ed001dSArnd Bergmann if (retval) 47178ed001dSArnd Bergmann return retval; 47278ed001dSArnd Bergmann 4733455607fSTony Battersby srp = sg_get_rq_mark(sfp, req_pack_id, &busy); 4741da177e4SLinus Torvalds if (!srp) { /* now wait on packet to arrive */ 47578ed001dSArnd Bergmann if (filp->f_flags & O_NONBLOCK) 47678ed001dSArnd Bergmann return -EAGAIN; 4773f0c6abaSJörn Engel retval = wait_event_interruptible(sfp->read_wait, 4783455607fSTony Battersby ((srp = sg_get_rq_mark(sfp, req_pack_id, &busy)) || 4793455607fSTony Battersby (!busy && atomic_read(&sdp->detaching)))); 4803455607fSTony Battersby if (!srp) 4813455607fSTony Battersby /* signal or detaching */ 4823455607fSTony Battersby return retval ? retval : -ENODEV; 4831da177e4SLinus Torvalds } 48478ed001dSArnd Bergmann if (srp->header.interface_id != '\0') 48578ed001dSArnd Bergmann return sg_new_read(sfp, buf, count, srp); 4861da177e4SLinus Torvalds 4871da177e4SLinus Torvalds hp = &srp->header; 48878ed001dSArnd Bergmann old_hdr = kzalloc(SZ_SG_HEADER, GFP_KERNEL); 48978ed001dSArnd Bergmann if (!old_hdr) 49078ed001dSArnd Bergmann return -ENOMEM; 49178ed001dSArnd Bergmann 492cb59e840S old_hdr->reply_len = (int) hp->timeout; 493cb59e840S old_hdr->pack_len = old_hdr->reply_len; /* old, strange behaviour */ 494cb59e840S old_hdr->pack_id = hp->pack_id; 495cb59e840S old_hdr->twelve_byte = 4961da177e4SLinus Torvalds ((srp->data.cmd_opcode >= 0xc0) && (12 == hp->cmd_len)) ? 1 : 0; 497cb59e840S old_hdr->target_status = hp->masked_status; 498cb59e840S old_hdr->host_status = hp->host_status; 499cb59e840S old_hdr->driver_status = hp->driver_status; 5001da177e4SLinus Torvalds if ((CHECK_CONDITION & hp->masked_status) || 501464a00c9SHannes Reinecke (srp->sense_b[0] & 0x70) == 0x70) { 502464a00c9SHannes Reinecke old_hdr->driver_status = DRIVER_SENSE; 503cb59e840S memcpy(old_hdr->sense_buffer, srp->sense_b, 504cb59e840S sizeof (old_hdr->sense_buffer)); 505464a00c9SHannes Reinecke } 5061da177e4SLinus Torvalds switch (hp->host_status) { 5071da177e4SLinus Torvalds /* This setup of 'result' is for backward compatibility and is best 5081da177e4SLinus Torvalds ignored by the user who should use target, host + driver status */ 5091da177e4SLinus Torvalds case DID_OK: 5101da177e4SLinus Torvalds case DID_PASSTHROUGH: 5111da177e4SLinus Torvalds case DID_SOFT_ERROR: 512cb59e840S old_hdr->result = 0; 5131da177e4SLinus Torvalds break; 5141da177e4SLinus Torvalds case DID_NO_CONNECT: 5151da177e4SLinus Torvalds case DID_BUS_BUSY: 5161da177e4SLinus Torvalds case DID_TIME_OUT: 517cb59e840S old_hdr->result = EBUSY; 5181da177e4SLinus Torvalds break; 5191da177e4SLinus Torvalds case DID_BAD_TARGET: 5201da177e4SLinus Torvalds case DID_ABORT: 5211da177e4SLinus Torvalds case DID_PARITY: 5221da177e4SLinus Torvalds case DID_RESET: 5231da177e4SLinus Torvalds case DID_BAD_INTR: 524cb59e840S old_hdr->result = EIO; 5251da177e4SLinus Torvalds break; 5261da177e4SLinus Torvalds case DID_ERROR: 527cb59e840S old_hdr->result = (srp->sense_b[0] == 0 && 5281da177e4SLinus Torvalds hp->masked_status == GOOD) ? 0 : EIO; 5291da177e4SLinus Torvalds break; 5301da177e4SLinus Torvalds default: 531cb59e840S old_hdr->result = EIO; 5321da177e4SLinus Torvalds break; 5331da177e4SLinus Torvalds } 5341da177e4SLinus Torvalds 5351da177e4SLinus Torvalds /* Now copy the result back to the user buffer. */ 5361da177e4SLinus Torvalds if (count >= SZ_SG_HEADER) { 537c8c12792SAl Viro if (copy_to_user(buf, old_hdr, SZ_SG_HEADER)) { 538cb59e840S retval = -EFAULT; 539cb59e840S goto free_old_hdr; 540cb59e840S } 5411da177e4SLinus Torvalds buf += SZ_SG_HEADER; 542cb59e840S if (count > old_hdr->reply_len) 543cb59e840S count = old_hdr->reply_len; 5441da177e4SLinus Torvalds if (count > SZ_SG_HEADER) { 545cb59e840S if (sg_read_oxfer(srp, buf, count - SZ_SG_HEADER)) { 546cb59e840S retval = -EFAULT; 547cb59e840S goto free_old_hdr; 548cb59e840S } 5491da177e4SLinus Torvalds } 5501da177e4SLinus Torvalds } else 551cb59e840S count = (old_hdr->result == 0) ? 0 : -EIO; 5521da177e4SLinus Torvalds sg_finish_rem_req(srp); 55397d27b0dSHannes Reinecke sg_remove_request(sfp, srp); 554cb59e840S retval = count; 555cb59e840S free_old_hdr: 556cb59e840S kfree(old_hdr); 557cb59e840S return retval; 5581da177e4SLinus Torvalds } 5591da177e4SLinus Torvalds 5601da177e4SLinus Torvalds static ssize_t 5611da177e4SLinus Torvalds sg_new_read(Sg_fd * sfp, char __user *buf, size_t count, Sg_request * srp) 5621da177e4SLinus Torvalds { 5631da177e4SLinus Torvalds sg_io_hdr_t *hp = &srp->header; 5643b524a68STony Battersby int err = 0, err2; 5651da177e4SLinus Torvalds int len; 5661da177e4SLinus Torvalds 56778ed001dSArnd Bergmann if (in_compat_syscall()) { 56878ed001dSArnd Bergmann if (count < sizeof(struct compat_sg_io_hdr)) { 56978ed001dSArnd Bergmann err = -EINVAL; 57078ed001dSArnd Bergmann goto err_out; 57178ed001dSArnd Bergmann } 57278ed001dSArnd Bergmann } else if (count < SZ_SG_IO_HDR) { 5731da177e4SLinus Torvalds err = -EINVAL; 5741da177e4SLinus Torvalds goto err_out; 5751da177e4SLinus Torvalds } 5761da177e4SLinus Torvalds hp->sb_len_wr = 0; 5771da177e4SLinus Torvalds if ((hp->mx_sb_len > 0) && hp->sbp) { 5781da177e4SLinus Torvalds if ((CHECK_CONDITION & hp->masked_status) || 579464a00c9SHannes Reinecke (srp->sense_b[0] & 0x70) == 0x70) { 580d6b10348SMike Christie int sb_len = SCSI_SENSE_BUFFERSIZE; 5811da177e4SLinus Torvalds sb_len = (hp->mx_sb_len > sb_len) ? sb_len : hp->mx_sb_len; 5821da177e4SLinus Torvalds len = 8 + (int) srp->sense_b[7]; /* Additional sense length field */ 5831da177e4SLinus Torvalds len = (len > sb_len) ? sb_len : len; 5841da177e4SLinus Torvalds if (copy_to_user(hp->sbp, srp->sense_b, len)) { 5851da177e4SLinus Torvalds err = -EFAULT; 5861da177e4SLinus Torvalds goto err_out; 5871da177e4SLinus Torvalds } 588464a00c9SHannes Reinecke hp->driver_status = DRIVER_SENSE; 5891da177e4SLinus Torvalds hp->sb_len_wr = len; 5901da177e4SLinus Torvalds } 5911da177e4SLinus Torvalds } 5921da177e4SLinus Torvalds if (hp->masked_status || hp->host_status || hp->driver_status) 5931da177e4SLinus Torvalds hp->info |= SG_INFO_CHECK; 59498aaaec4SArnd Bergmann err = put_sg_io_hdr(hp, buf); 5951da177e4SLinus Torvalds err_out: 5963b524a68STony Battersby err2 = sg_finish_rem_req(srp); 59797d27b0dSHannes Reinecke sg_remove_request(sfp, srp); 5983b524a68STony Battersby return err ? : err2 ? : count; 5991da177e4SLinus Torvalds } 6001da177e4SLinus Torvalds 6011da177e4SLinus Torvalds static ssize_t 6021da177e4SLinus Torvalds sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) 6031da177e4SLinus Torvalds { 6041da177e4SLinus Torvalds int mxsize, cmd_size, k; 6051da177e4SLinus Torvalds int input_size, blocking; 6061da177e4SLinus Torvalds unsigned char opcode; 6071da177e4SLinus Torvalds Sg_device *sdp; 6081da177e4SLinus Torvalds Sg_fd *sfp; 6091da177e4SLinus Torvalds Sg_request *srp; 6101da177e4SLinus Torvalds struct sg_header old_hdr; 6111da177e4SLinus Torvalds sg_io_hdr_t *hp; 61265c26a0fSDouglas Gilbert unsigned char cmnd[SG_MAX_CDB_SIZE]; 61326b5b874SJann Horn int retval; 6141da177e4SLinus Torvalds 61526b5b874SJann Horn retval = sg_check_file_access(filp, __func__); 61626b5b874SJann Horn if (retval) 61726b5b874SJann Horn return retval; 618128394efSAl Viro 6191da177e4SLinus Torvalds if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp))) 6201da177e4SLinus Torvalds return -ENXIO; 62195e159d6SHannes Reinecke SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp, 62295e159d6SHannes Reinecke "sg_write: count=%d\n", (int) count)); 623cc833acbSDouglas Gilbert if (atomic_read(&sdp->detaching)) 6241da177e4SLinus Torvalds return -ENODEV; 6251da177e4SLinus Torvalds if (!((filp->f_flags & O_NONBLOCK) || 6261da177e4SLinus Torvalds scsi_block_when_processing_errors(sdp->device))) 6271da177e4SLinus Torvalds return -ENXIO; 6281da177e4SLinus Torvalds 6291da177e4SLinus Torvalds if (count < SZ_SG_HEADER) 6301da177e4SLinus Torvalds return -EIO; 631a64e5a86SAl Viro if (copy_from_user(&old_hdr, buf, SZ_SG_HEADER)) 6321da177e4SLinus Torvalds return -EFAULT; 6331da177e4SLinus Torvalds blocking = !(filp->f_flags & O_NONBLOCK); 6341da177e4SLinus Torvalds if (old_hdr.reply_len < 0) 635a2dd3b4cSTony Battersby return sg_new_write(sfp, filp, buf, count, 636a2dd3b4cSTony Battersby blocking, 0, 0, NULL); 6371da177e4SLinus Torvalds if (count < (SZ_SG_HEADER + 6)) 6381da177e4SLinus Torvalds return -EIO; /* The minimum scsi command length is 6 bytes. */ 6391da177e4SLinus Torvalds 640062c9d45SAl Viro buf += SZ_SG_HEADER; 641a64e5a86SAl Viro if (get_user(opcode, buf)) 642062c9d45SAl Viro return -EFAULT; 643062c9d45SAl Viro 6441da177e4SLinus Torvalds if (!(srp = sg_add_request(sfp))) { 64595e159d6SHannes Reinecke SCSI_LOG_TIMEOUT(1, sg_printk(KERN_INFO, sdp, 64695e159d6SHannes Reinecke "sg_write: queue full\n")); 6471da177e4SLinus Torvalds return -EDOM; 6481da177e4SLinus Torvalds } 6491bc0eb04SHannes Reinecke mutex_lock(&sfp->f_mutex); 6501da177e4SLinus Torvalds if (sfp->next_cmd_len > 0) { 6511da177e4SLinus Torvalds cmd_size = sfp->next_cmd_len; 6521da177e4SLinus Torvalds sfp->next_cmd_len = 0; /* reset so only this write() effected */ 6531da177e4SLinus Torvalds } else { 6541da177e4SLinus Torvalds cmd_size = COMMAND_SIZE(opcode); /* based on SCSI command group */ 6551da177e4SLinus Torvalds if ((opcode >= 0xc0) && old_hdr.twelve_byte) 6561da177e4SLinus Torvalds cmd_size = 12; 6571da177e4SLinus Torvalds } 6581bc0eb04SHannes Reinecke mutex_unlock(&sfp->f_mutex); 65995e159d6SHannes Reinecke SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sdp, 6601da177e4SLinus Torvalds "sg_write: scsi opcode=0x%02x, cmd_size=%d\n", (int) opcode, cmd_size)); 6611da177e4SLinus Torvalds /* Determine buffer size. */ 6621da177e4SLinus Torvalds input_size = count - cmd_size; 6631da177e4SLinus Torvalds mxsize = (input_size > old_hdr.reply_len) ? input_size : old_hdr.reply_len; 6641da177e4SLinus Torvalds mxsize -= SZ_SG_HEADER; 6651da177e4SLinus Torvalds input_size -= SZ_SG_HEADER; 6661da177e4SLinus Torvalds if (input_size < 0) { 6671da177e4SLinus Torvalds sg_remove_request(sfp, srp); 6681da177e4SLinus Torvalds return -EIO; /* User did not pass enough bytes for this command. */ 6691da177e4SLinus Torvalds } 6701da177e4SLinus Torvalds hp = &srp->header; 6711da177e4SLinus Torvalds hp->interface_id = '\0'; /* indicator of old interface tunnelled */ 6721da177e4SLinus Torvalds hp->cmd_len = (unsigned char) cmd_size; 6731da177e4SLinus Torvalds hp->iovec_count = 0; 6741da177e4SLinus Torvalds hp->mx_sb_len = 0; 6751da177e4SLinus Torvalds if (input_size > 0) 6761da177e4SLinus Torvalds hp->dxfer_direction = (old_hdr.reply_len > SZ_SG_HEADER) ? 6771da177e4SLinus Torvalds SG_DXFER_TO_FROM_DEV : SG_DXFER_TO_DEV; 6781da177e4SLinus Torvalds else 6791da177e4SLinus Torvalds hp->dxfer_direction = (mxsize > 0) ? SG_DXFER_FROM_DEV : SG_DXFER_NONE; 6801da177e4SLinus Torvalds hp->dxfer_len = mxsize; 6815ecee0a3SDouglas Gilbert if ((hp->dxfer_direction == SG_DXFER_TO_DEV) || 6825ecee0a3SDouglas Gilbert (hp->dxfer_direction == SG_DXFER_TO_FROM_DEV)) 6831da177e4SLinus Torvalds hp->dxferp = (char __user *)buf + cmd_size; 684fad7f01eSFUJITA Tomonori else 685fad7f01eSFUJITA Tomonori hp->dxferp = NULL; 6861da177e4SLinus Torvalds hp->sbp = NULL; 6871da177e4SLinus Torvalds hp->timeout = old_hdr.reply_len; /* structure abuse ... */ 6881da177e4SLinus Torvalds hp->flags = input_size; /* structure abuse ... */ 6891da177e4SLinus Torvalds hp->pack_id = old_hdr.pack_id; 6901da177e4SLinus Torvalds hp->usr_ptr = NULL; 69183c6f239SWu Bo if (copy_from_user(cmnd, buf, cmd_size)) { 69283c6f239SWu Bo sg_remove_request(sfp, srp); 6931da177e4SLinus Torvalds return -EFAULT; 69483c6f239SWu Bo } 6951da177e4SLinus Torvalds /* 6961da177e4SLinus Torvalds * SG_DXFER_TO_FROM_DEV is functionally equivalent to SG_DXFER_FROM_DEV, 6971da177e4SLinus Torvalds * but is is possible that the app intended SG_DXFER_TO_DEV, because there 6981da177e4SLinus Torvalds * is a non-zero input_size, so emit a warning. 6991da177e4SLinus Torvalds */ 700eaa3e22eSAndi Kleen if (hp->dxfer_direction == SG_DXFER_TO_FROM_DEV) { 7012fe038e3SChristian Dietrich printk_ratelimited(KERN_WARNING 7022fe038e3SChristian Dietrich "sg_write: data in/out %d/%d bytes " 7032fe038e3SChristian Dietrich "for SCSI command 0x%x-- guessing " 7042fe038e3SChristian Dietrich "data in;\n program %s not setting " 7052fe038e3SChristian Dietrich "count and/or reply_len properly\n", 7061da177e4SLinus Torvalds old_hdr.reply_len - (int)SZ_SG_HEADER, 7071da177e4SLinus Torvalds input_size, (unsigned int) cmnd[0], 7081da177e4SLinus Torvalds current->comm); 709eaa3e22eSAndi Kleen } 7101da177e4SLinus Torvalds k = sg_common_write(sfp, srp, cmnd, sfp->timeout, blocking); 7111da177e4SLinus Torvalds return (k < 0) ? k : count; 7121da177e4SLinus Torvalds } 7131da177e4SLinus Torvalds 7141da177e4SLinus Torvalds static ssize_t 7150b07de85SAdel Gadllah sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf, 716a2dd3b4cSTony Battersby size_t count, int blocking, int read_only, int sg_io_owned, 7170b07de85SAdel Gadllah Sg_request **o_srp) 7181da177e4SLinus Torvalds { 7191da177e4SLinus Torvalds int k; 7201da177e4SLinus Torvalds Sg_request *srp; 7211da177e4SLinus Torvalds sg_io_hdr_t *hp; 72265c26a0fSDouglas Gilbert unsigned char cmnd[SG_MAX_CDB_SIZE]; 7231da177e4SLinus Torvalds int timeout; 7241da177e4SLinus Torvalds unsigned long ul_timeout; 7251da177e4SLinus Torvalds 7261da177e4SLinus Torvalds if (count < SZ_SG_IO_HDR) 7271da177e4SLinus Torvalds return -EINVAL; 7281da177e4SLinus Torvalds 7291da177e4SLinus Torvalds sfp->cmd_q = 1; /* when sg_io_hdr seen, set command queuing on */ 7301da177e4SLinus Torvalds if (!(srp = sg_add_request(sfp))) { 73195e159d6SHannes Reinecke SCSI_LOG_TIMEOUT(1, sg_printk(KERN_INFO, sfp->parentdp, 73295e159d6SHannes Reinecke "sg_new_write: queue full\n")); 7331da177e4SLinus Torvalds return -EDOM; 7341da177e4SLinus Torvalds } 735a2dd3b4cSTony Battersby srp->sg_io_owned = sg_io_owned; 7361da177e4SLinus Torvalds hp = &srp->header; 73798aaaec4SArnd Bergmann if (get_sg_io_hdr(hp, buf)) { 7381da177e4SLinus Torvalds sg_remove_request(sfp, srp); 7391da177e4SLinus Torvalds return -EFAULT; 7401da177e4SLinus Torvalds } 7411da177e4SLinus Torvalds if (hp->interface_id != 'S') { 7421da177e4SLinus Torvalds sg_remove_request(sfp, srp); 7431da177e4SLinus Torvalds return -ENOSYS; 7441da177e4SLinus Torvalds } 7451da177e4SLinus Torvalds if (hp->flags & SG_FLAG_MMAP_IO) { 7461da177e4SLinus Torvalds if (hp->dxfer_len > sfp->reserve.bufflen) { 7471da177e4SLinus Torvalds sg_remove_request(sfp, srp); 7481da177e4SLinus Torvalds return -ENOMEM; /* MMAP_IO size must fit in reserve buffer */ 7491da177e4SLinus Torvalds } 7501da177e4SLinus Torvalds if (hp->flags & SG_FLAG_DIRECT_IO) { 7511da177e4SLinus Torvalds sg_remove_request(sfp, srp); 7521da177e4SLinus Torvalds return -EINVAL; /* either MMAP_IO or DIRECT_IO (not both) */ 7531da177e4SLinus Torvalds } 7541bc0eb04SHannes Reinecke if (sfp->res_in_use) { 7551da177e4SLinus Torvalds sg_remove_request(sfp, srp); 7561da177e4SLinus Torvalds return -EBUSY; /* reserve buffer already being used */ 7571da177e4SLinus Torvalds } 7581da177e4SLinus Torvalds } 7591da177e4SLinus Torvalds ul_timeout = msecs_to_jiffies(srp->header.timeout); 7601da177e4SLinus Torvalds timeout = (ul_timeout < INT_MAX) ? ul_timeout : INT_MAX; 7611da177e4SLinus Torvalds if ((!hp->cmdp) || (hp->cmd_len < 6) || (hp->cmd_len > sizeof (cmnd))) { 7621da177e4SLinus Torvalds sg_remove_request(sfp, srp); 7631da177e4SLinus Torvalds return -EMSGSIZE; 7641da177e4SLinus Torvalds } 765a62726cbSAl Viro if (copy_from_user(cmnd, hp->cmdp, hp->cmd_len)) { 7661da177e4SLinus Torvalds sg_remove_request(sfp, srp); 7671da177e4SLinus Torvalds return -EFAULT; 7681da177e4SLinus Torvalds } 76914e507b8SFUJITA Tomonori if (read_only && sg_allow_access(file, cmnd)) { 7701da177e4SLinus Torvalds sg_remove_request(sfp, srp); 7711da177e4SLinus Torvalds return -EPERM; 7721da177e4SLinus Torvalds } 7731da177e4SLinus Torvalds k = sg_common_write(sfp, srp, cmnd, timeout, blocking); 7741da177e4SLinus Torvalds if (k < 0) 7751da177e4SLinus Torvalds return k; 7761da177e4SLinus Torvalds if (o_srp) 7771da177e4SLinus Torvalds *o_srp = srp; 7781da177e4SLinus Torvalds return count; 7791da177e4SLinus Torvalds } 7801da177e4SLinus Torvalds 7811da177e4SLinus Torvalds static int 7821da177e4SLinus Torvalds sg_common_write(Sg_fd * sfp, Sg_request * srp, 7831da177e4SLinus Torvalds unsigned char *cmnd, int timeout, int blocking) 7841da177e4SLinus Torvalds { 7855af2e382SBart Van Assche int k, at_head; 7861da177e4SLinus Torvalds Sg_device *sdp = sfp->parentdp; 7871da177e4SLinus Torvalds sg_io_hdr_t *hp = &srp->header; 7881da177e4SLinus Torvalds 7891da177e4SLinus Torvalds srp->data.cmd_opcode = cmnd[0]; /* hold opcode of command */ 7901da177e4SLinus Torvalds hp->status = 0; 7911da177e4SLinus Torvalds hp->masked_status = 0; 7921da177e4SLinus Torvalds hp->msg_status = 0; 7931da177e4SLinus Torvalds hp->info = 0; 7941da177e4SLinus Torvalds hp->host_status = 0; 7951da177e4SLinus Torvalds hp->driver_status = 0; 7961da177e4SLinus Torvalds hp->resid = 0; 79795e159d6SHannes Reinecke SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sfp->parentdp, 79895e159d6SHannes Reinecke "sg_common_write: scsi opcode=0x%02x, cmd_size=%d\n", 7991da177e4SLinus Torvalds (int) cmnd[0], (int) hp->cmd_len)); 8001da177e4SLinus Torvalds 801849f8583SLi Bin if (hp->dxfer_len >= SZ_256M) { 802849f8583SLi Bin sg_remove_request(sfp, srp); 80328676d86SJohannes Thumshirn return -EINVAL; 804849f8583SLi Bin } 80528676d86SJohannes Thumshirn 80610865dfaSFUJITA Tomonori k = sg_start_req(srp, cmnd); 80710865dfaSFUJITA Tomonori if (k) { 80895e159d6SHannes Reinecke SCSI_LOG_TIMEOUT(1, sg_printk(KERN_INFO, sfp->parentdp, 80995e159d6SHannes Reinecke "sg_common_write: start_req err=%d\n", k)); 8101da177e4SLinus Torvalds sg_finish_rem_req(srp); 81197d27b0dSHannes Reinecke sg_remove_request(sfp, srp); 8121da177e4SLinus Torvalds return k; /* probably out of space --> ENOMEM */ 8131da177e4SLinus Torvalds } 814cc833acbSDouglas Gilbert if (atomic_read(&sdp->detaching)) { 815f3951a37SCalvin Owens if (srp->bio) { 8160bf6d96cSChristoph Hellwig blk_mq_free_request(srp->rq); 817f3951a37SCalvin Owens srp->rq = NULL; 818f3951a37SCalvin Owens } 819f3951a37SCalvin Owens 8201da177e4SLinus Torvalds sg_finish_rem_req(srp); 82197d27b0dSHannes Reinecke sg_remove_request(sfp, srp); 8221da177e4SLinus Torvalds return -ENODEV; 8231da177e4SLinus Torvalds } 8241da177e4SLinus Torvalds 825cb59e840S hp->duration = jiffies_to_msecs(jiffies); 82616070cc1SDouglas Gilbert if (hp->interface_id != '\0' && /* v3 (or later) interface */ 82716070cc1SDouglas Gilbert (SG_FLAG_Q_AT_TAIL & hp->flags)) 82816070cc1SDouglas Gilbert at_head = 0; 82916070cc1SDouglas Gilbert else 83016070cc1SDouglas Gilbert at_head = 1; 83110db10d1SFUJITA Tomonori 83210865dfaSFUJITA Tomonori srp->rq->timeout = timeout; 833c6517b79STony Battersby kref_get(&sfp->f_ref); /* sg_rq_end_io() does kref_put(). */ 834e2e53086SChristoph Hellwig srp->rq->end_io = sg_rq_end_io; 835e2e53086SChristoph Hellwig blk_execute_rq_nowait(srp->rq, at_head); 83610865dfaSFUJITA Tomonori return 0; 83710865dfaSFUJITA Tomonori } 8381da177e4SLinus Torvalds 8396acddc5eSJörn Engel static int srp_done(Sg_fd *sfp, Sg_request *srp) 8406acddc5eSJörn Engel { 8416acddc5eSJörn Engel unsigned long flags; 8426acddc5eSJörn Engel int ret; 8436acddc5eSJörn Engel 8446acddc5eSJörn Engel read_lock_irqsave(&sfp->rq_list_lock, flags); 8456acddc5eSJörn Engel ret = srp->done; 8466acddc5eSJörn Engel read_unlock_irqrestore(&sfp->rq_list_lock, flags); 8476acddc5eSJörn Engel return ret; 8486acddc5eSJörn Engel } 8496acddc5eSJörn Engel 85046f69e6aSAkinobu Mita static int max_sectors_bytes(struct request_queue *q) 85146f69e6aSAkinobu Mita { 85246f69e6aSAkinobu Mita unsigned int max_sectors = queue_max_sectors(q); 85346f69e6aSAkinobu Mita 85446f69e6aSAkinobu Mita max_sectors = min_t(unsigned int, max_sectors, INT_MAX >> 9); 85546f69e6aSAkinobu Mita 85646f69e6aSAkinobu Mita return max_sectors << 9; 85746f69e6aSAkinobu Mita } 85846f69e6aSAkinobu Mita 8594759df90SHannes Reinecke static void 8604759df90SHannes Reinecke sg_fill_request_table(Sg_fd *sfp, sg_req_info_t *rinfo) 8614759df90SHannes Reinecke { 8624759df90SHannes Reinecke Sg_request *srp; 8634759df90SHannes Reinecke int val; 8644759df90SHannes Reinecke unsigned int ms; 8654759df90SHannes Reinecke 8664759df90SHannes Reinecke val = 0; 8674759df90SHannes Reinecke list_for_each_entry(srp, &sfp->rq_list, entry) { 868587c3c9fSBen Hutchings if (val >= SG_MAX_QUEUE) 8694759df90SHannes Reinecke break; 8704759df90SHannes Reinecke rinfo[val].req_state = srp->done + 1; 8714759df90SHannes Reinecke rinfo[val].problem = 8724759df90SHannes Reinecke srp->header.masked_status & 8734759df90SHannes Reinecke srp->header.host_status & 8744759df90SHannes Reinecke srp->header.driver_status; 8754759df90SHannes Reinecke if (srp->done) 8764759df90SHannes Reinecke rinfo[val].duration = 8774759df90SHannes Reinecke srp->header.duration; 8784759df90SHannes Reinecke else { 8794759df90SHannes Reinecke ms = jiffies_to_msecs(jiffies); 8804759df90SHannes Reinecke rinfo[val].duration = 8814759df90SHannes Reinecke (ms > srp->header.duration) ? 8824759df90SHannes Reinecke (ms - srp->header.duration) : 0; 8834759df90SHannes Reinecke } 8844759df90SHannes Reinecke rinfo[val].orphan = srp->orphan; 8854759df90SHannes Reinecke rinfo[val].sg_io_owned = srp->sg_io_owned; 8864759df90SHannes Reinecke rinfo[val].pack_id = srp->header.pack_id; 8874759df90SHannes Reinecke rinfo[val].usr_ptr = srp->header.usr_ptr; 8884759df90SHannes Reinecke val++; 8894759df90SHannes Reinecke } 8904759df90SHannes Reinecke } 8914759df90SHannes Reinecke 892fd6c3d5aSArnd Bergmann #ifdef CONFIG_COMPAT 893fd6c3d5aSArnd Bergmann struct compat_sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */ 894fd6c3d5aSArnd Bergmann char req_state; 895fd6c3d5aSArnd Bergmann char orphan; 896fd6c3d5aSArnd Bergmann char sg_io_owned; 897fd6c3d5aSArnd Bergmann char problem; 898fd6c3d5aSArnd Bergmann int pack_id; 899fd6c3d5aSArnd Bergmann compat_uptr_t usr_ptr; 900fd6c3d5aSArnd Bergmann unsigned int duration; 901fd6c3d5aSArnd Bergmann int unused; 902fd6c3d5aSArnd Bergmann }; 903fd6c3d5aSArnd Bergmann 904fd6c3d5aSArnd Bergmann static int put_compat_request_table(struct compat_sg_req_info __user *o, 905fd6c3d5aSArnd Bergmann struct sg_req_info *rinfo) 906fd6c3d5aSArnd Bergmann { 907fd6c3d5aSArnd Bergmann int i; 908fd6c3d5aSArnd Bergmann for (i = 0; i < SG_MAX_QUEUE; i++) { 909fd6c3d5aSArnd Bergmann if (copy_to_user(o + i, rinfo + i, offsetof(sg_req_info_t, usr_ptr)) || 910fd6c3d5aSArnd Bergmann put_user((uintptr_t)rinfo[i].usr_ptr, &o[i].usr_ptr) || 911fd6c3d5aSArnd Bergmann put_user(rinfo[i].duration, &o[i].duration) || 912fd6c3d5aSArnd Bergmann put_user(rinfo[i].unused, &o[i].unused)) 913fd6c3d5aSArnd Bergmann return -EFAULT; 914fd6c3d5aSArnd Bergmann } 915fd6c3d5aSArnd Bergmann return 0; 916fd6c3d5aSArnd Bergmann } 917fd6c3d5aSArnd Bergmann #endif 918fd6c3d5aSArnd Bergmann 91937b9d1e0SJörn Engel static long 920d320a955SArnd Bergmann sg_ioctl_common(struct file *filp, Sg_device *sdp, Sg_fd *sfp, 921d320a955SArnd Bergmann unsigned int cmd_in, void __user *p) 9221da177e4SLinus Torvalds { 9231da177e4SLinus Torvalds int __user *ip = p; 924176aa9d6SChristoph Hellwig int result, val, read_only; 9251da177e4SLinus Torvalds Sg_request *srp; 9261da177e4SLinus Torvalds unsigned long iflags; 9271da177e4SLinus Torvalds 92895e159d6SHannes Reinecke SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp, 92995e159d6SHannes Reinecke "sg_ioctl: cmd=0x%x\n", (int) cmd_in)); 9301da177e4SLinus Torvalds read_only = (O_RDWR != (filp->f_flags & O_ACCMODE)); 9311da177e4SLinus Torvalds 9321da177e4SLinus Torvalds switch (cmd_in) { 9331da177e4SLinus Torvalds case SG_IO: 934cc833acbSDouglas Gilbert if (atomic_read(&sdp->detaching)) 9351da177e4SLinus Torvalds return -ENODEV; 9361da177e4SLinus Torvalds if (!scsi_block_when_processing_errors(sdp->device)) 9371da177e4SLinus Torvalds return -ENXIO; 938dddbf8d9SJörn Engel result = sg_new_write(sfp, filp, p, SZ_SG_IO_HDR, 939dddbf8d9SJörn Engel 1, read_only, 1, &srp); 9401da177e4SLinus Torvalds if (result < 0) 9411da177e4SLinus Torvalds return result; 9423f0c6abaSJörn Engel result = wait_event_interruptible(sfp->read_wait, 9433455607fSTony Battersby srp_done(sfp, srp)); 944a2dd3b4cSTony Battersby write_lock_irq(&sfp->rq_list_lock); 945a2dd3b4cSTony Battersby if (srp->done) { 946a2dd3b4cSTony Battersby srp->done = 2; 947a2dd3b4cSTony Battersby write_unlock_irq(&sfp->rq_list_lock); 948794c10faSJörn Engel result = sg_new_read(sfp, p, SZ_SG_IO_HDR, srp); 949794c10faSJörn Engel return (result < 0) ? result : 0; 950a2dd3b4cSTony Battersby } 9511da177e4SLinus Torvalds srp->orphan = 1; 952a2dd3b4cSTony Battersby write_unlock_irq(&sfp->rq_list_lock); 9531da177e4SLinus Torvalds return result; /* -ERESTARTSYS because signal hit process */ 9541da177e4SLinus Torvalds case SG_SET_TIMEOUT: 9551da177e4SLinus Torvalds result = get_user(val, ip); 9561da177e4SLinus Torvalds if (result) 9571da177e4SLinus Torvalds return result; 9581da177e4SLinus Torvalds if (val < 0) 9591da177e4SLinus Torvalds return -EIO; 960f8630bd7SPaul Burton if (val >= mult_frac((s64)INT_MAX, USER_HZ, HZ)) 961f8630bd7SPaul Burton val = min_t(s64, mult_frac((s64)INT_MAX, USER_HZ, HZ), 962b9b6e80aSPaul Burton INT_MAX); 9631da177e4SLinus Torvalds sfp->timeout_user = val; 964f8630bd7SPaul Burton sfp->timeout = mult_frac(val, HZ, USER_HZ); 9651da177e4SLinus Torvalds 9661da177e4SLinus Torvalds return 0; 9671da177e4SLinus Torvalds case SG_GET_TIMEOUT: /* N.B. User receives timeout as return value */ 9681da177e4SLinus Torvalds /* strange ..., for backward compatibility */ 9691da177e4SLinus Torvalds return sfp->timeout_user; 9701da177e4SLinus Torvalds case SG_SET_FORCE_LOW_DMA: 971745dfa0dSHannes Reinecke /* 972745dfa0dSHannes Reinecke * N.B. This ioctl never worked properly, but failed to 973745dfa0dSHannes Reinecke * return an error value. So returning '0' to keep compability 974745dfa0dSHannes Reinecke * with legacy applications. 975745dfa0dSHannes Reinecke */ 9761da177e4SLinus Torvalds return 0; 9771da177e4SLinus Torvalds case SG_GET_LOW_DMA: 978aaff5ebaSChristoph Hellwig return put_user(0, ip); 9791da177e4SLinus Torvalds case SG_GET_SCSI_ID: 980a16a4741SAl Viro { 981a16a4741SAl Viro sg_scsi_id_t v; 9821da177e4SLinus Torvalds 983cc833acbSDouglas Gilbert if (atomic_read(&sdp->detaching)) 9841da177e4SLinus Torvalds return -ENODEV; 985a16a4741SAl Viro memset(&v, 0, sizeof(v)); 986a16a4741SAl Viro v.host_no = sdp->device->host->host_no; 987a16a4741SAl Viro v.channel = sdp->device->channel; 988a16a4741SAl Viro v.scsi_id = sdp->device->id; 989a16a4741SAl Viro v.lun = sdp->device->lun; 990a16a4741SAl Viro v.scsi_type = sdp->device->type; 991a16a4741SAl Viro v.h_cmd_per_lun = sdp->device->host->cmd_per_lun; 992a16a4741SAl Viro v.d_queue_depth = sdp->device->queue_depth; 993a16a4741SAl Viro if (copy_to_user(p, &v, sizeof(sg_scsi_id_t))) 994a16a4741SAl Viro return -EFAULT; 9951da177e4SLinus Torvalds return 0; 9961da177e4SLinus Torvalds } 9971da177e4SLinus Torvalds case SG_SET_FORCE_PACK_ID: 9981da177e4SLinus Torvalds result = get_user(val, ip); 9991da177e4SLinus Torvalds if (result) 10001da177e4SLinus Torvalds return result; 10011da177e4SLinus Torvalds sfp->force_packid = val ? 1 : 0; 10021da177e4SLinus Torvalds return 0; 10031da177e4SLinus Torvalds case SG_GET_PACK_ID: 10041da177e4SLinus Torvalds read_lock_irqsave(&sfp->rq_list_lock, iflags); 1005109bade9SHannes Reinecke list_for_each_entry(srp, &sfp->rq_list, entry) { 10061da177e4SLinus Torvalds if ((1 == srp->done) && (!srp->sg_io_owned)) { 10071da177e4SLinus Torvalds read_unlock_irqrestore(&sfp->rq_list_lock, 10081da177e4SLinus Torvalds iflags); 1009a16a4741SAl Viro return put_user(srp->header.pack_id, ip); 10101da177e4SLinus Torvalds } 10111da177e4SLinus Torvalds } 10121da177e4SLinus Torvalds read_unlock_irqrestore(&sfp->rq_list_lock, iflags); 1013a16a4741SAl Viro return put_user(-1, ip); 10141da177e4SLinus Torvalds case SG_GET_NUM_WAITING: 10151da177e4SLinus Torvalds read_lock_irqsave(&sfp->rq_list_lock, iflags); 1016109bade9SHannes Reinecke val = 0; 1017109bade9SHannes Reinecke list_for_each_entry(srp, &sfp->rq_list, entry) { 10181da177e4SLinus Torvalds if ((1 == srp->done) && (!srp->sg_io_owned)) 10191da177e4SLinus Torvalds ++val; 10201da177e4SLinus Torvalds } 10211da177e4SLinus Torvalds read_unlock_irqrestore(&sfp->rq_list_lock, iflags); 10221da177e4SLinus Torvalds return put_user(val, ip); 10231da177e4SLinus Torvalds case SG_GET_SG_TABLESIZE: 10241da177e4SLinus Torvalds return put_user(sdp->sg_tablesize, ip); 10251da177e4SLinus Torvalds case SG_SET_RESERVED_SIZE: 10261da177e4SLinus Torvalds result = get_user(val, ip); 10271da177e4SLinus Torvalds if (result) 10281da177e4SLinus Torvalds return result; 10291da177e4SLinus Torvalds if (val < 0) 10301da177e4SLinus Torvalds return -EINVAL; 103144ec9542SAlan Stern val = min_t(int, val, 103246f69e6aSAkinobu Mita max_sectors_bytes(sdp->device->request_queue)); 10331bc0eb04SHannes Reinecke mutex_lock(&sfp->f_mutex); 10341da177e4SLinus Torvalds if (val != sfp->reserve.bufflen) { 10351bc0eb04SHannes Reinecke if (sfp->mmap_called || 10361bc0eb04SHannes Reinecke sfp->res_in_use) { 10371bc0eb04SHannes Reinecke mutex_unlock(&sfp->f_mutex); 10381da177e4SLinus Torvalds return -EBUSY; 10391bc0eb04SHannes Reinecke } 10401bc0eb04SHannes Reinecke 104195e159d6SHannes Reinecke sg_remove_scat(sfp, &sfp->reserve); 10421da177e4SLinus Torvalds sg_build_reserve(sfp, val); 10431da177e4SLinus Torvalds } 10441bc0eb04SHannes Reinecke mutex_unlock(&sfp->f_mutex); 10451da177e4SLinus Torvalds return 0; 10461da177e4SLinus Torvalds case SG_GET_RESERVED_SIZE: 104744ec9542SAlan Stern val = min_t(int, sfp->reserve.bufflen, 104846f69e6aSAkinobu Mita max_sectors_bytes(sdp->device->request_queue)); 10491da177e4SLinus Torvalds return put_user(val, ip); 10501da177e4SLinus Torvalds case SG_SET_COMMAND_Q: 10511da177e4SLinus Torvalds result = get_user(val, ip); 10521da177e4SLinus Torvalds if (result) 10531da177e4SLinus Torvalds return result; 10541da177e4SLinus Torvalds sfp->cmd_q = val ? 1 : 0; 10551da177e4SLinus Torvalds return 0; 10561da177e4SLinus Torvalds case SG_GET_COMMAND_Q: 10571da177e4SLinus Torvalds return put_user((int) sfp->cmd_q, ip); 10581da177e4SLinus Torvalds case SG_SET_KEEP_ORPHAN: 10591da177e4SLinus Torvalds result = get_user(val, ip); 10601da177e4SLinus Torvalds if (result) 10611da177e4SLinus Torvalds return result; 10621da177e4SLinus Torvalds sfp->keep_orphan = val; 10631da177e4SLinus Torvalds return 0; 10641da177e4SLinus Torvalds case SG_GET_KEEP_ORPHAN: 10651da177e4SLinus Torvalds return put_user((int) sfp->keep_orphan, ip); 10661da177e4SLinus Torvalds case SG_NEXT_CMD_LEN: 10671da177e4SLinus Torvalds result = get_user(val, ip); 10681da177e4SLinus Torvalds if (result) 10691da177e4SLinus Torvalds return result; 1070bf33f87dSpeter chang if (val > SG_MAX_CDB_SIZE) 1071bf33f87dSpeter chang return -ENOMEM; 10721da177e4SLinus Torvalds sfp->next_cmd_len = (val > 0) ? val : 0; 10731da177e4SLinus Torvalds return 0; 10741da177e4SLinus Torvalds case SG_GET_VERSION_NUM: 10751da177e4SLinus Torvalds return put_user(sg_version_num, ip); 10761da177e4SLinus Torvalds case SG_GET_ACCESS_COUNT: 10771da177e4SLinus Torvalds /* faked - we don't have a real access count anymore */ 10781da177e4SLinus Torvalds val = (sdp->device ? 1 : 0); 10791da177e4SLinus Torvalds return put_user(val, ip); 10801da177e4SLinus Torvalds case SG_GET_REQUEST_TABLE: 1081fd6c3d5aSArnd Bergmann { 1082cb59e840S sg_req_info_t *rinfo; 1083cb59e840S 10846396bb22SKees Cook rinfo = kcalloc(SG_MAX_QUEUE, SZ_SG_REQ_INFO, 1085cb59e840S GFP_KERNEL); 1086cb59e840S if (!rinfo) 1087cb59e840S return -ENOMEM; 10881da177e4SLinus Torvalds read_lock_irqsave(&sfp->rq_list_lock, iflags); 10894759df90SHannes Reinecke sg_fill_request_table(sfp, rinfo); 10901da177e4SLinus Torvalds read_unlock_irqrestore(&sfp->rq_list_lock, iflags); 1091fd6c3d5aSArnd Bergmann #ifdef CONFIG_COMPAT 1092fd6c3d5aSArnd Bergmann if (in_compat_syscall()) 1093fd6c3d5aSArnd Bergmann result = put_compat_request_table(p, rinfo); 1094fd6c3d5aSArnd Bergmann else 1095fd6c3d5aSArnd Bergmann #endif 1096fd6c3d5aSArnd Bergmann result = copy_to_user(p, rinfo, 1097cb59e840S SZ_SG_REQ_INFO * SG_MAX_QUEUE); 1098cb59e840S result = result ? -EFAULT : 0; 1099cb59e840S kfree(rinfo); 1100cb59e840S return result; 11011da177e4SLinus Torvalds } 11021da177e4SLinus Torvalds case SG_EMULATED_HOST: 1103cc833acbSDouglas Gilbert if (atomic_read(&sdp->detaching)) 11041da177e4SLinus Torvalds return -ENODEV; 11051da177e4SLinus Torvalds return put_user(sdp->device->host->hostt->emulated, ip); 11061da177e4SLinus Torvalds case SCSI_IOCTL_SEND_COMMAND: 1107cc833acbSDouglas Gilbert if (atomic_read(&sdp->detaching)) 11081da177e4SLinus Torvalds return -ENODEV; 11092e80089cSChristoph Hellwig return scsi_ioctl(sdp->device, filp->f_mode & FMODE_WRITE, 11102e80089cSChristoph Hellwig cmd_in, p); 11111da177e4SLinus Torvalds case SG_SET_DEBUG: 11121da177e4SLinus Torvalds result = get_user(val, ip); 11131da177e4SLinus Torvalds if (result) 11141da177e4SLinus Torvalds return result; 11151da177e4SLinus Torvalds sdp->sgdebug = (char) val; 11161da177e4SLinus Torvalds return 0; 111744ec9542SAlan Stern case BLKSECTGET: 111846f69e6aSAkinobu Mita return put_user(max_sectors_bytes(sdp->device->request_queue), 111944ec9542SAlan Stern ip); 11206da127adSChristof Schmitt case BLKTRACESETUP: 11211d1cf156SChristoph Hellwig return blk_trace_setup(sdp->device->request_queue, sdp->name, 112276e3a19dSMartin Peschke MKDEV(SCSI_GENERIC_MAJOR, sdp->index), 11237475c8aeSBart Van Assche NULL, p); 11246da127adSChristof Schmitt case BLKTRACESTART: 11256da127adSChristof Schmitt return blk_trace_startstop(sdp->device->request_queue, 1); 11266da127adSChristof Schmitt case BLKTRACESTOP: 11276da127adSChristof Schmitt return blk_trace_startstop(sdp->device->request_queue, 0); 11286da127adSChristof Schmitt case BLKTRACETEARDOWN: 11296da127adSChristof Schmitt return blk_trace_remove(sdp->device->request_queue); 1130906d15fbSChristoph Hellwig case SCSI_IOCTL_GET_IDLUN: 1131906d15fbSChristoph Hellwig case SCSI_IOCTL_GET_BUS_NUMBER: 1132906d15fbSChristoph Hellwig case SCSI_IOCTL_PROBE_HOST: 1133906d15fbSChristoph Hellwig case SG_GET_TRANSFORM: 1134906d15fbSChristoph Hellwig case SG_SCSI_RESET: 1135906d15fbSChristoph Hellwig if (atomic_read(&sdp->detaching)) 1136906d15fbSChristoph Hellwig return -ENODEV; 1137906d15fbSChristoph Hellwig break; 11381da177e4SLinus Torvalds default: 11391da177e4SLinus Torvalds if (read_only) 11401da177e4SLinus Torvalds return -EPERM; /* don't know so take safe approach */ 1141906d15fbSChristoph Hellwig break; 11421da177e4SLinus Torvalds } 1143906d15fbSChristoph Hellwig 1144906d15fbSChristoph Hellwig result = scsi_ioctl_block_when_processing_errors(sdp->device, 1145906d15fbSChristoph Hellwig cmd_in, filp->f_flags & O_NDELAY); 1146906d15fbSChristoph Hellwig if (result) 1147906d15fbSChristoph Hellwig return result; 1148d320a955SArnd Bergmann 1149d320a955SArnd Bergmann return -ENOIOCTLCMD; 1150d320a955SArnd Bergmann } 1151d320a955SArnd Bergmann 1152d320a955SArnd Bergmann static long 1153d320a955SArnd Bergmann sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) 1154d320a955SArnd Bergmann { 1155d320a955SArnd Bergmann void __user *p = (void __user *)arg; 1156d320a955SArnd Bergmann Sg_device *sdp; 1157d320a955SArnd Bergmann Sg_fd *sfp; 1158d320a955SArnd Bergmann int ret; 1159d320a955SArnd Bergmann 1160d320a955SArnd Bergmann if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp))) 1161d320a955SArnd Bergmann return -ENXIO; 1162d320a955SArnd Bergmann 1163d320a955SArnd Bergmann ret = sg_ioctl_common(filp, sdp, sfp, cmd_in, p); 1164d320a955SArnd Bergmann if (ret != -ENOIOCTLCMD) 1165d320a955SArnd Bergmann return ret; 11662e80089cSChristoph Hellwig return scsi_ioctl(sdp->device, filp->f_mode & FMODE_WRITE, cmd_in, p); 11671da177e4SLinus Torvalds } 11681da177e4SLinus Torvalds 1169afc9a42bSAl Viro static __poll_t 11701da177e4SLinus Torvalds sg_poll(struct file *filp, poll_table * wait) 11711da177e4SLinus Torvalds { 1172afc9a42bSAl Viro __poll_t res = 0; 11731da177e4SLinus Torvalds Sg_device *sdp; 11741da177e4SLinus Torvalds Sg_fd *sfp; 11751da177e4SLinus Torvalds Sg_request *srp; 11761da177e4SLinus Torvalds int count = 0; 11771da177e4SLinus Torvalds unsigned long iflags; 11781da177e4SLinus Torvalds 1179ebaf466bSJörn Engel sfp = filp->private_data; 1180ebaf466bSJörn Engel if (!sfp) 1181a9a08845SLinus Torvalds return EPOLLERR; 1182ebaf466bSJörn Engel sdp = sfp->parentdp; 1183ebaf466bSJörn Engel if (!sdp) 1184a9a08845SLinus Torvalds return EPOLLERR; 11851da177e4SLinus Torvalds poll_wait(filp, &sfp->read_wait, wait); 11861da177e4SLinus Torvalds read_lock_irqsave(&sfp->rq_list_lock, iflags); 1187109bade9SHannes Reinecke list_for_each_entry(srp, &sfp->rq_list, entry) { 11881da177e4SLinus Torvalds /* if any read waiting, flag it */ 11891da177e4SLinus Torvalds if ((0 == res) && (1 == srp->done) && (!srp->sg_io_owned)) 1190a9a08845SLinus Torvalds res = EPOLLIN | EPOLLRDNORM; 11911da177e4SLinus Torvalds ++count; 11921da177e4SLinus Torvalds } 11931da177e4SLinus Torvalds read_unlock_irqrestore(&sfp->rq_list_lock, iflags); 11941da177e4SLinus Torvalds 1195cc833acbSDouglas Gilbert if (atomic_read(&sdp->detaching)) 1196a9a08845SLinus Torvalds res |= EPOLLHUP; 11971da177e4SLinus Torvalds else if (!sfp->cmd_q) { 11981da177e4SLinus Torvalds if (0 == count) 1199a9a08845SLinus Torvalds res |= EPOLLOUT | EPOLLWRNORM; 12001da177e4SLinus Torvalds } else if (count < SG_MAX_QUEUE) 1201a9a08845SLinus Torvalds res |= EPOLLOUT | EPOLLWRNORM; 120295e159d6SHannes Reinecke SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp, 1203fcc5a652SAl Viro "sg_poll: res=0x%x\n", (__force u32) res)); 12041da177e4SLinus Torvalds return res; 12051da177e4SLinus Torvalds } 12061da177e4SLinus Torvalds 12071da177e4SLinus Torvalds static int 12081da177e4SLinus Torvalds sg_fasync(int fd, struct file *filp, int mode) 12091da177e4SLinus Torvalds { 12101da177e4SLinus Torvalds Sg_device *sdp; 12111da177e4SLinus Torvalds Sg_fd *sfp; 12121da177e4SLinus Torvalds 12131da177e4SLinus Torvalds if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp))) 12141da177e4SLinus Torvalds return -ENXIO; 121595e159d6SHannes Reinecke SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp, 121695e159d6SHannes Reinecke "sg_fasync: mode=%d\n", mode)); 12171da177e4SLinus Torvalds 121860aa4924SJonathan Corbet return fasync_helper(fd, filp, mode, &sfp->async_qp); 12191da177e4SLinus Torvalds } 12201da177e4SLinus Torvalds 12210cac8e1bSSouptick Joarder static vm_fault_t 122211bac800SDave Jiang sg_vma_fault(struct vm_fault *vmf) 12231da177e4SLinus Torvalds { 122411bac800SDave Jiang struct vm_area_struct *vma = vmf->vma; 12251da177e4SLinus Torvalds Sg_fd *sfp; 1226d6b10348SMike Christie unsigned long offset, len, sa; 12271da177e4SLinus Torvalds Sg_scatter_hold *rsv_schp; 122810db10d1SFUJITA Tomonori int k, length; 12291da177e4SLinus Torvalds 12301da177e4SLinus Torvalds if ((NULL == vma) || (!(sfp = (Sg_fd *) vma->vm_private_data))) 1231a13ff0bbSNick Piggin return VM_FAULT_SIGBUS; 12321da177e4SLinus Torvalds rsv_schp = &sfp->reserve; 1233a13ff0bbSNick Piggin offset = vmf->pgoff << PAGE_SHIFT; 12341da177e4SLinus Torvalds if (offset >= rsv_schp->bufflen) 1235a13ff0bbSNick Piggin return VM_FAULT_SIGBUS; 123695e159d6SHannes Reinecke SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sfp->parentdp, 123795e159d6SHannes Reinecke "sg_vma_fault: offset=%lu, scatg=%d\n", 12381da177e4SLinus Torvalds offset, rsv_schp->k_use_sg)); 1239d6b10348SMike Christie sa = vma->vm_start; 124010db10d1SFUJITA Tomonori length = 1 << (PAGE_SHIFT + rsv_schp->page_order); 124110db10d1SFUJITA Tomonori for (k = 0; k < rsv_schp->k_use_sg && sa < vma->vm_end; k++) { 12421da177e4SLinus Torvalds len = vma->vm_end - sa; 124310db10d1SFUJITA Tomonori len = (len < length) ? len : length; 12441da177e4SLinus Torvalds if (offset < len) { 124510db10d1SFUJITA Tomonori struct page *page = nth_page(rsv_schp->pages[k], 124610db10d1SFUJITA Tomonori offset >> PAGE_SHIFT); 12471da177e4SLinus Torvalds get_page(page); /* increment page count */ 1248a13ff0bbSNick Piggin vmf->page = page; 1249a13ff0bbSNick Piggin return 0; /* success */ 12501da177e4SLinus Torvalds } 12511da177e4SLinus Torvalds sa += len; 12521da177e4SLinus Torvalds offset -= len; 12531da177e4SLinus Torvalds } 1254d6b10348SMike Christie 1255a13ff0bbSNick Piggin return VM_FAULT_SIGBUS; 12561da177e4SLinus Torvalds } 12571da177e4SLinus Torvalds 1258f0f37e2fSAlexey Dobriyan static const struct vm_operations_struct sg_mmap_vm_ops = { 1259a13ff0bbSNick Piggin .fault = sg_vma_fault, 12601da177e4SLinus Torvalds }; 12611da177e4SLinus Torvalds 12621da177e4SLinus Torvalds static int 12631da177e4SLinus Torvalds sg_mmap(struct file *filp, struct vm_area_struct *vma) 12641da177e4SLinus Torvalds { 12651da177e4SLinus Torvalds Sg_fd *sfp; 1266d6b10348SMike Christie unsigned long req_sz, len, sa; 12671da177e4SLinus Torvalds Sg_scatter_hold *rsv_schp; 126810db10d1SFUJITA Tomonori int k, length; 12696a8dadccSTodd Poynor int ret = 0; 12701da177e4SLinus Torvalds 12711da177e4SLinus Torvalds if ((!filp) || (!vma) || (!(sfp = (Sg_fd *) filp->private_data))) 12721da177e4SLinus Torvalds return -ENXIO; 1273cb59e840S req_sz = vma->vm_end - vma->vm_start; 127495e159d6SHannes Reinecke SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sfp->parentdp, 127595e159d6SHannes Reinecke "sg_mmap starting, vm_start=%p, len=%d\n", 12761da177e4SLinus Torvalds (void *) vma->vm_start, (int) req_sz)); 12771da177e4SLinus Torvalds if (vma->vm_pgoff) 12781da177e4SLinus Torvalds return -EINVAL; /* want no offset */ 12791da177e4SLinus Torvalds rsv_schp = &sfp->reserve; 12806a8dadccSTodd Poynor mutex_lock(&sfp->f_mutex); 12816a8dadccSTodd Poynor if (req_sz > rsv_schp->bufflen) { 12826a8dadccSTodd Poynor ret = -ENOMEM; /* cannot map more than reserved buffer */ 12836a8dadccSTodd Poynor goto out; 12846a8dadccSTodd Poynor } 12851da177e4SLinus Torvalds 1286d6b10348SMike Christie sa = vma->vm_start; 128710db10d1SFUJITA Tomonori length = 1 << (PAGE_SHIFT + rsv_schp->page_order); 128810db10d1SFUJITA Tomonori for (k = 0; k < rsv_schp->k_use_sg && sa < vma->vm_end; k++) { 12891da177e4SLinus Torvalds len = vma->vm_end - sa; 129010db10d1SFUJITA Tomonori len = (len < length) ? len : length; 12911da177e4SLinus Torvalds sa += len; 12921da177e4SLinus Torvalds } 1293d6b10348SMike Christie 12941da177e4SLinus Torvalds sfp->mmap_called = 1; 12951c71222eSSuren Baghdasaryan vm_flags_set(vma, VM_IO | VM_DONTEXPAND | VM_DONTDUMP); 12961da177e4SLinus Torvalds vma->vm_private_data = sfp; 12971da177e4SLinus Torvalds vma->vm_ops = &sg_mmap_vm_ops; 12986a8dadccSTodd Poynor out: 12996a8dadccSTodd Poynor mutex_unlock(&sfp->f_mutex); 13006a8dadccSTodd Poynor return ret; 13011da177e4SLinus Torvalds } 13021da177e4SLinus Torvalds 1303cc833acbSDouglas Gilbert static void 1304cc833acbSDouglas Gilbert sg_rq_end_io_usercontext(struct work_struct *work) 1305c96952edSFUJITA Tomonori { 1306c96952edSFUJITA Tomonori struct sg_request *srp = container_of(work, struct sg_request, ew.work); 1307c96952edSFUJITA Tomonori struct sg_fd *sfp = srp->parentfp; 1308c96952edSFUJITA Tomonori 1309c96952edSFUJITA Tomonori sg_finish_rem_req(srp); 131097d27b0dSHannes Reinecke sg_remove_request(sfp, srp); 1311c96952edSFUJITA Tomonori kref_put(&sfp->f_ref, sg_remove_sfp); 1312c96952edSFUJITA Tomonori } 1313c96952edSFUJITA Tomonori 1314a91a3a20SFUJITA Tomonori /* 1315a91a3a20SFUJITA Tomonori * This function is a "bottom half" handler that is called by the mid 1316a91a3a20SFUJITA Tomonori * level when a command is completed (or has failed). 1317a91a3a20SFUJITA Tomonori */ 1318de671d61SJens Axboe static enum rq_end_io_ret 13192a842acaSChristoph Hellwig sg_rq_end_io(struct request *rq, blk_status_t status) 13201da177e4SLinus Torvalds { 13215b794f98SChristoph Hellwig struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(rq); 1322a91a3a20SFUJITA Tomonori struct sg_request *srp = rq->end_io_data; 1323c6517b79STony Battersby Sg_device *sdp; 13241da177e4SLinus Torvalds Sg_fd *sfp; 13251da177e4SLinus Torvalds unsigned long iflags; 1326cb59e840S unsigned int ms; 1327a91a3a20SFUJITA Tomonori char *sense; 1328c6517b79STony Battersby int result, resid, done = 1; 13291da177e4SLinus Torvalds 1330c6517b79STony Battersby if (WARN_ON(srp->done != 0)) 1331de671d61SJens Axboe return RQ_END_IO_NONE; 1332c6517b79STony Battersby 13331da177e4SLinus Torvalds sfp = srp->parentfp; 1334c6517b79STony Battersby if (WARN_ON(sfp == NULL)) 1335de671d61SJens Axboe return RQ_END_IO_NONE; 1336c6517b79STony Battersby 1337c6517b79STony Battersby sdp = sfp->parentdp; 1338cc833acbSDouglas Gilbert if (unlikely(atomic_read(&sdp->detaching))) 1339cc833acbSDouglas Gilbert pr_info("%s: device detaching\n", __func__); 13401da177e4SLinus Torvalds 13415b794f98SChristoph Hellwig sense = scmd->sense_buffer; 1342dbb4c84dSChristoph Hellwig result = scmd->result; 1343a9a4ea11SChristoph Hellwig resid = scmd->resid_len; 13441da177e4SLinus Torvalds 134595e159d6SHannes Reinecke SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sdp, 134695e159d6SHannes Reinecke "sg_cmd_done: pack_id=%d, res=0x%x\n", 134795e159d6SHannes Reinecke srp->header.pack_id, result)); 1348d6b10348SMike Christie srp->header.resid = resid; 1349cb59e840S ms = jiffies_to_msecs(jiffies); 1350cb59e840S srp->header.duration = (ms > srp->header.duration) ? 1351cb59e840S (ms - srp->header.duration) : 0; 1352d6b10348SMike Christie if (0 != result) { 13531da177e4SLinus Torvalds struct scsi_sense_hdr sshdr; 13541da177e4SLinus Torvalds 1355d6b10348SMike Christie srp->header.status = 0xff & result; 1356c9293c11SMike Christie srp->header.masked_status = sg_status_byte(result); 135754cf31d0SHannes Reinecke srp->header.msg_status = COMMAND_COMPLETE; 1358d6b10348SMike Christie srp->header.host_status = host_byte(result); 1359d6b10348SMike Christie srp->header.driver_status = driver_byte(result); 13601da177e4SLinus Torvalds if ((sdp->sgdebug > 0) && 13611da177e4SLinus Torvalds ((CHECK_CONDITION == srp->header.masked_status) || 13621da177e4SLinus Torvalds (COMMAND_TERMINATED == srp->header.masked_status))) 1363d811b848SHannes Reinecke __scsi_print_sense(sdp->device, __func__, sense, 1364d6b10348SMike Christie SCSI_SENSE_BUFFERSIZE); 13651da177e4SLinus Torvalds 13661da177e4SLinus Torvalds /* Following if statement is a patch supplied by Eric Youngdale */ 1367d6b10348SMike Christie if (driver_byte(result) != 0 1368d6b10348SMike Christie && scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr) 13691da177e4SLinus Torvalds && !scsi_sense_is_deferred(&sshdr) 13701da177e4SLinus Torvalds && sshdr.sense_key == UNIT_ATTENTION 13711da177e4SLinus Torvalds && sdp->device->removable) { 13721da177e4SLinus Torvalds /* Detected possible disc change. Set the bit - this */ 13731da177e4SLinus Torvalds /* may be used if there are filesystems using this device */ 13741da177e4SLinus Torvalds sdp->device->changed = 1; 13751da177e4SLinus Torvalds } 13761da177e4SLinus Torvalds } 137782ed4db4SChristoph Hellwig 13785b794f98SChristoph Hellwig if (scmd->sense_len) 13795b794f98SChristoph Hellwig memcpy(srp->sense_b, scmd->sense_buffer, SCSI_SENSE_BUFFERSIZE); 138082ed4db4SChristoph Hellwig 13811da177e4SLinus Torvalds /* Rely on write phase to clean out srp status values, so no "else" */ 13821da177e4SLinus Torvalds 13837568615cSTony Battersby /* 13847568615cSTony Battersby * Free the request as soon as it is complete so that its resources 13857568615cSTony Battersby * can be reused without waiting for userspace to read() the 13867568615cSTony Battersby * result. But keep the associated bio (if any) around until 13877568615cSTony Battersby * blk_rq_unmap_user() can be called from user context. 13887568615cSTony Battersby */ 13897568615cSTony Battersby srp->rq = NULL; 13900bf6d96cSChristoph Hellwig blk_mq_free_request(rq); 13917568615cSTony Battersby 1392c6517b79STony Battersby write_lock_irqsave(&sfp->rq_list_lock, iflags); 1393c6517b79STony Battersby if (unlikely(srp->orphan)) { 13941da177e4SLinus Torvalds if (sfp->keep_orphan) 13951da177e4SLinus Torvalds srp->sg_io_owned = 0; 1396c6517b79STony Battersby else 1397c6517b79STony Battersby done = 0; 13981da177e4SLinus Torvalds } 1399c6517b79STony Battersby srp->done = done; 14001da177e4SLinus Torvalds write_unlock_irqrestore(&sfp->rq_list_lock, iflags); 1401c6517b79STony Battersby 1402c6517b79STony Battersby if (likely(done)) { 1403c6517b79STony Battersby /* Now wake up any sg_read() that is waiting for this 1404c6517b79STony Battersby * packet. 1405c6517b79STony Battersby */ 1406c6517b79STony Battersby wake_up_interruptible(&sfp->read_wait); 1407c6517b79STony Battersby kill_fasync(&sfp->async_qp, SIGPOLL, POLL_IN); 1408c6517b79STony Battersby kref_put(&sfp->f_ref, sg_remove_sfp); 1409015640edSFUJITA Tomonori } else { 1410015640edSFUJITA Tomonori INIT_WORK(&srp->ew.work, sg_rq_end_io_usercontext); 1411015640edSFUJITA Tomonori schedule_work(&srp->ew.work); 1412015640edSFUJITA Tomonori } 1413de671d61SJens Axboe return RQ_END_IO_NONE; 14141da177e4SLinus Torvalds } 14151da177e4SLinus Torvalds 1416828c0950SAlexey Dobriyan static const struct file_operations sg_fops = { 14171da177e4SLinus Torvalds .owner = THIS_MODULE, 14181da177e4SLinus Torvalds .read = sg_read, 14191da177e4SLinus Torvalds .write = sg_write, 14201da177e4SLinus Torvalds .poll = sg_poll, 142137b9d1e0SJörn Engel .unlocked_ioctl = sg_ioctl, 14222c2db2c6SChristoph Hellwig .compat_ioctl = compat_ptr_ioctl, 14231da177e4SLinus Torvalds .open = sg_open, 14241da177e4SLinus Torvalds .mmap = sg_mmap, 14251da177e4SLinus Torvalds .release = sg_release, 14261da177e4SLinus Torvalds .fasync = sg_fasync, 14271da177e4SLinus Torvalds }; 14281da177e4SLinus Torvalds 1429f1fb4176SRicardo B. Marliere static const struct class sg_sysfs_class = { 1430f1fb4176SRicardo B. Marliere .name = "scsi_generic" 1431f1fb4176SRicardo B. Marliere }; 14321da177e4SLinus Torvalds 14331da177e4SLinus Torvalds static int sg_sysfs_valid = 0; 14341da177e4SLinus Torvalds 1435cc833acbSDouglas Gilbert static Sg_device * 1436aebbb583SChristoph Hellwig sg_alloc(struct scsi_device *scsidp) 14371da177e4SLinus Torvalds { 1438d6b10348SMike Christie struct request_queue *q = scsidp->request_queue; 14391da177e4SLinus Torvalds Sg_device *sdp; 14401da177e4SLinus Torvalds unsigned long iflags; 14417c07d613SJames Bottomley int error; 14427c07d613SJames Bottomley u32 k; 14431da177e4SLinus Torvalds 144424669f75SJes Sorensen sdp = kzalloc(sizeof(Sg_device), GFP_KERNEL); 14451da177e4SLinus Torvalds if (!sdp) { 1446cc833acbSDouglas Gilbert sdev_printk(KERN_WARNING, scsidp, "%s: kmalloc Sg_device " 1447cc833acbSDouglas Gilbert "failure\n", __func__); 14487c07d613SJames Bottomley return ERR_PTR(-ENOMEM); 14497c07d613SJames Bottomley } 1450c6517b79STony Battersby 1451b98c52b5STejun Heo idr_preload(GFP_KERNEL); 14527c07d613SJames Bottomley write_lock_irqsave(&sg_index_lock, iflags); 14531da177e4SLinus Torvalds 1454b98c52b5STejun Heo error = idr_alloc(&sg_index_idr, sdp, 0, SG_MAX_DEVS, GFP_NOWAIT); 1455b98c52b5STejun Heo if (error < 0) { 1456b98c52b5STejun Heo if (error == -ENOSPC) { 1457b98c52b5STejun Heo sdev_printk(KERN_WARNING, scsidp, 1458b98c52b5STejun Heo "Unable to attach sg device type=%d, minor number exceeds %d\n", 1459b98c52b5STejun Heo scsidp->type, SG_MAX_DEVS - 1); 1460b98c52b5STejun Heo error = -ENODEV; 1461b98c52b5STejun Heo } else { 1462cc833acbSDouglas Gilbert sdev_printk(KERN_WARNING, scsidp, "%s: idr " 1463cc833acbSDouglas Gilbert "allocation Sg_device failure: %d\n", 1464cc833acbSDouglas Gilbert __func__, error); 14651da177e4SLinus Torvalds } 1466b98c52b5STejun Heo goto out_unlock; 1467b98c52b5STejun Heo } 1468b98c52b5STejun Heo k = error; 14691da177e4SLinus Torvalds 147095e159d6SHannes Reinecke SCSI_LOG_TIMEOUT(3, sdev_printk(KERN_INFO, scsidp, 147195e159d6SHannes Reinecke "sg_alloc: dev=%d \n", k)); 1472aebbb583SChristoph Hellwig sprintf(sdp->name, "sg%d", k); 14731da177e4SLinus Torvalds sdp->device = scsidp; 1474cc833acbSDouglas Gilbert mutex_init(&sdp->open_rel_lock); 14753442f802SFUJITA Tomonori INIT_LIST_HEAD(&sdp->sfds); 1476cc833acbSDouglas Gilbert init_waitqueue_head(&sdp->open_wait); 1477cc833acbSDouglas Gilbert atomic_set(&sdp->detaching, 0); 1478cc833acbSDouglas Gilbert rwlock_init(&sdp->sfd_lock); 14798a78362cSMartin K. Petersen sdp->sg_tablesize = queue_max_segments(q); 14807c07d613SJames Bottomley sdp->index = k; 1481c6517b79STony Battersby kref_init(&sdp->d_ref); 14827c07d613SJames Bottomley error = 0; 1483b98c52b5STejun Heo 1484b98c52b5STejun Heo out_unlock: 1485b98c52b5STejun Heo write_unlock_irqrestore(&sg_index_lock, iflags); 1486b98c52b5STejun Heo idr_preload_end(); 1487b98c52b5STejun Heo 14887c07d613SJames Bottomley if (error) { 14891da177e4SLinus Torvalds kfree(sdp); 14907c07d613SJames Bottomley return ERR_PTR(error); 14917c07d613SJames Bottomley } 14927c07d613SJames Bottomley return sdp; 14931da177e4SLinus Torvalds } 14941da177e4SLinus Torvalds 14951da177e4SLinus Torvalds static int 14962243acd5SGreg Kroah-Hartman sg_add_device(struct device *cl_dev) 14971da177e4SLinus Torvalds { 1498ee959b00STony Jones struct scsi_device *scsidp = to_scsi_device(cl_dev->parent); 14991da177e4SLinus Torvalds Sg_device *sdp = NULL; 15001da177e4SLinus Torvalds struct cdev * cdev = NULL; 15017c07d613SJames Bottomley int error; 1502454e8957SIshai Rabinovitz unsigned long iflags; 15031da177e4SLinus Torvalds 150480b60510SYu Kuai if (!blk_get_queue(scsidp->request_queue)) { 150580b60510SYu Kuai pr_warn("%s: get scsi_device queue failed\n", __func__); 150680b60510SYu Kuai return -ENODEV; 150780b60510SYu Kuai } 1508db59133eSYu Kuai 15091da177e4SLinus Torvalds error = -ENOMEM; 15101da177e4SLinus Torvalds cdev = cdev_alloc(); 15111da177e4SLinus Torvalds if (!cdev) { 1512cc833acbSDouglas Gilbert pr_warn("%s: cdev_alloc failed\n", __func__); 15131da177e4SLinus Torvalds goto out; 15141da177e4SLinus Torvalds } 15151da177e4SLinus Torvalds cdev->owner = THIS_MODULE; 15161da177e4SLinus Torvalds cdev->ops = &sg_fops; 15171da177e4SLinus Torvalds 1518aebbb583SChristoph Hellwig sdp = sg_alloc(scsidp); 15197c07d613SJames Bottomley if (IS_ERR(sdp)) { 1520cc833acbSDouglas Gilbert pr_warn("%s: sg_alloc failed\n", __func__); 15217c07d613SJames Bottomley error = PTR_ERR(sdp); 15221da177e4SLinus Torvalds goto out; 15231da177e4SLinus Torvalds } 15241da177e4SLinus Torvalds 15257c07d613SJames Bottomley error = cdev_add(cdev, MKDEV(SCSI_GENERIC_MAJOR, sdp->index), 1); 15265e3c34c1SGreg KH if (error) 1527454e8957SIshai Rabinovitz goto cdev_add_err; 15285e3c34c1SGreg KH 15291da177e4SLinus Torvalds sdp->cdev = cdev; 15301da177e4SLinus Torvalds if (sg_sysfs_valid) { 1531ee959b00STony Jones struct device *sg_class_member; 15321da177e4SLinus Torvalds 1533f1fb4176SRicardo B. Marliere sg_class_member = device_create(&sg_sysfs_class, cl_dev->parent, 1534ee959b00STony Jones MKDEV(SCSI_GENERIC_MAJOR, 1535ee959b00STony Jones sdp->index), 1536aebbb583SChristoph Hellwig sdp, "%s", sdp->name); 1537d07e0361SFUJITA Tomonori if (IS_ERR(sg_class_member)) { 1538cc833acbSDouglas Gilbert pr_err("%s: device_create failed\n", __func__); 1539d07e0361SFUJITA Tomonori error = PTR_ERR(sg_class_member); 1540d07e0361SFUJITA Tomonori goto cdev_add_err; 1541d07e0361SFUJITA Tomonori } 15421da177e4SLinus Torvalds error = sysfs_create_link(&scsidp->sdev_gendev.kobj, 15431da177e4SLinus Torvalds &sg_class_member->kobj, "generic"); 15441da177e4SLinus Torvalds if (error) 1545cc833acbSDouglas Gilbert pr_err("%s: unable to make symlink 'generic' back " 1546cc833acbSDouglas Gilbert "to sg%d\n", __func__, sdp->index); 15471da177e4SLinus Torvalds } else 1548cc833acbSDouglas Gilbert pr_warn("%s: sg_sys Invalid\n", __func__); 15491da177e4SLinus Torvalds 1550cc833acbSDouglas Gilbert sdev_printk(KERN_NOTICE, scsidp, "Attached scsi generic sg%d " 1551cc833acbSDouglas Gilbert "type %d\n", sdp->index, scsidp->type); 15521da177e4SLinus Torvalds 1553ee959b00STony Jones dev_set_drvdata(cl_dev, sdp); 1554a24484f2SFUJITA Tomonori 15551da177e4SLinus Torvalds return 0; 15561da177e4SLinus Torvalds 1557454e8957SIshai Rabinovitz cdev_add_err: 15587c07d613SJames Bottomley write_lock_irqsave(&sg_index_lock, iflags); 15597c07d613SJames Bottomley idr_remove(&sg_index_idr, sdp->index); 15607c07d613SJames Bottomley write_unlock_irqrestore(&sg_index_lock, iflags); 15617c07d613SJames Bottomley kfree(sdp); 1562454e8957SIshai Rabinovitz 15631da177e4SLinus Torvalds out: 15641da177e4SLinus Torvalds if (cdev) 15651da177e4SLinus Torvalds cdev_del(cdev); 1566fcaa174aSYu Kuai blk_put_queue(scsidp->request_queue); 15671da177e4SLinus Torvalds return error; 15681da177e4SLinus Torvalds } 15691da177e4SLinus Torvalds 1570cc833acbSDouglas Gilbert static void 1571cc833acbSDouglas Gilbert sg_device_destroy(struct kref *kref) 1572c6517b79STony Battersby { 1573c6517b79STony Battersby struct sg_device *sdp = container_of(kref, struct sg_device, d_ref); 1574db59133eSYu Kuai struct request_queue *q = sdp->device->request_queue; 1575c6517b79STony Battersby unsigned long flags; 1576c6517b79STony Battersby 1577c6517b79STony Battersby /* CAUTION! Note that the device can still be found via idr_find() 1578c6517b79STony Battersby * even though the refcount is 0. Therefore, do idr_remove() BEFORE 1579c6517b79STony Battersby * any other cleanup. 1580c6517b79STony Battersby */ 1581c6517b79STony Battersby 1582db59133eSYu Kuai blk_trace_remove(q); 1583fcaa174aSYu Kuai blk_put_queue(q); 1584db59133eSYu Kuai 1585c6517b79STony Battersby write_lock_irqsave(&sg_index_lock, flags); 1586c6517b79STony Battersby idr_remove(&sg_index_idr, sdp->index); 1587c6517b79STony Battersby write_unlock_irqrestore(&sg_index_lock, flags); 1588c6517b79STony Battersby 1589c6517b79STony Battersby SCSI_LOG_TIMEOUT(3, 159095e159d6SHannes Reinecke sg_printk(KERN_INFO, sdp, "sg_device_destroy\n")); 1591c6517b79STony Battersby 1592c6517b79STony Battersby kfree(sdp); 1593c6517b79STony Battersby } 1594c6517b79STony Battersby 1595cc833acbSDouglas Gilbert static void 15962243acd5SGreg Kroah-Hartman sg_remove_device(struct device *cl_dev) 15971da177e4SLinus Torvalds { 1598ee959b00STony Jones struct scsi_device *scsidp = to_scsi_device(cl_dev->parent); 1599ee959b00STony Jones Sg_device *sdp = dev_get_drvdata(cl_dev); 16001da177e4SLinus Torvalds unsigned long iflags; 16011da177e4SLinus Torvalds Sg_fd *sfp; 1602cc833acbSDouglas Gilbert int val; 16031da177e4SLinus Torvalds 1604cc833acbSDouglas Gilbert if (!sdp) 16051da177e4SLinus Torvalds return; 1606cc833acbSDouglas Gilbert /* want sdp->detaching non-zero as soon as possible */ 1607cc833acbSDouglas Gilbert val = atomic_inc_return(&sdp->detaching); 1608cc833acbSDouglas Gilbert if (val > 1) 1609cc833acbSDouglas Gilbert return; /* only want to do following once per device */ 16107c07d613SJames Bottomley 161195e159d6SHannes Reinecke SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp, 161295e159d6SHannes Reinecke "%s\n", __func__)); 1613c6517b79STony Battersby 1614cc833acbSDouglas Gilbert read_lock_irqsave(&sdp->sfd_lock, iflags); 16153442f802SFUJITA Tomonori list_for_each_entry(sfp, &sdp->sfds, sfd_siblings) { 1616cc833acbSDouglas Gilbert wake_up_interruptible_all(&sfp->read_wait); 1617c6517b79STony Battersby kill_fasync(&sfp->async_qp, SIGPOLL, POLL_HUP); 16181da177e4SLinus Torvalds } 1619cc833acbSDouglas Gilbert wake_up_interruptible_all(&sdp->open_wait); 1620cc833acbSDouglas Gilbert read_unlock_irqrestore(&sdp->sfd_lock, iflags); 16211da177e4SLinus Torvalds 16221da177e4SLinus Torvalds sysfs_remove_link(&scsidp->sdev_gendev.kobj, "generic"); 1623f1fb4176SRicardo B. Marliere device_destroy(&sg_sysfs_class, MKDEV(SCSI_GENERIC_MAJOR, sdp->index)); 16241da177e4SLinus Torvalds cdev_del(sdp->cdev); 16251da177e4SLinus Torvalds sdp->cdev = NULL; 16261da177e4SLinus Torvalds 1627cc833acbSDouglas Gilbert kref_put(&sdp->d_ref, sg_device_destroy); 16281da177e4SLinus Torvalds } 16291da177e4SLinus Torvalds 16306460e75aSDouglas Gilbert module_param_named(scatter_elem_sz, scatter_elem_sz, int, S_IRUGO | S_IWUSR); 16316460e75aSDouglas Gilbert module_param_named(def_reserved_size, def_reserved_size, int, 16326460e75aSDouglas Gilbert S_IRUGO | S_IWUSR); 16331da177e4SLinus Torvalds module_param_named(allow_dio, sg_allow_dio, int, S_IRUGO | S_IWUSR); 16341da177e4SLinus Torvalds 16351da177e4SLinus Torvalds MODULE_AUTHOR("Douglas Gilbert"); 16361da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI generic (sg) driver"); 16371da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 16381da177e4SLinus Torvalds MODULE_VERSION(SG_VERSION_STR); 1639f018fa55SRene Herman MODULE_ALIAS_CHARDEV_MAJOR(SCSI_GENERIC_MAJOR); 16401da177e4SLinus Torvalds 16416460e75aSDouglas Gilbert MODULE_PARM_DESC(scatter_elem_sz, "scatter gather element " 16426460e75aSDouglas Gilbert "size (default: max(SG_SCATTER_SZ, PAGE_SIZE))"); 16431da177e4SLinus Torvalds MODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd"); 16441da177e4SLinus Torvalds MODULE_PARM_DESC(allow_dio, "allow direct I/O (default: 0 (disallow))"); 16451da177e4SLinus Torvalds 164626d1c80fSXiaoming Ni #ifdef CONFIG_SYSCTL 164726d1c80fSXiaoming Ni #include <linux/sysctl.h> 164826d1c80fSXiaoming Ni 164926d1c80fSXiaoming Ni static struct ctl_table sg_sysctls[] = { 165026d1c80fSXiaoming Ni { 165126d1c80fSXiaoming Ni .procname = "sg-big-buff", 165226d1c80fSXiaoming Ni .data = &sg_big_buff, 165326d1c80fSXiaoming Ni .maxlen = sizeof(int), 165426d1c80fSXiaoming Ni .mode = 0444, 165526d1c80fSXiaoming Ni .proc_handler = proc_dointvec, 165626d1c80fSXiaoming Ni }, 165726d1c80fSXiaoming Ni }; 165826d1c80fSXiaoming Ni 165926d1c80fSXiaoming Ni static struct ctl_table_header *hdr; 166026d1c80fSXiaoming Ni static void register_sg_sysctls(void) 166126d1c80fSXiaoming Ni { 166226d1c80fSXiaoming Ni if (!hdr) 166326d1c80fSXiaoming Ni hdr = register_sysctl("kernel", sg_sysctls); 166426d1c80fSXiaoming Ni } 166526d1c80fSXiaoming Ni 166626d1c80fSXiaoming Ni static void unregister_sg_sysctls(void) 166726d1c80fSXiaoming Ni { 166826d1c80fSXiaoming Ni if (hdr) 166926d1c80fSXiaoming Ni unregister_sysctl_table(hdr); 167026d1c80fSXiaoming Ni } 167126d1c80fSXiaoming Ni #else 167226d1c80fSXiaoming Ni #define register_sg_sysctls() do { } while (0) 167326d1c80fSXiaoming Ni #define unregister_sg_sysctls() do { } while (0) 167426d1c80fSXiaoming Ni #endif /* CONFIG_SYSCTL */ 167526d1c80fSXiaoming Ni 16761da177e4SLinus Torvalds static int __init 16771da177e4SLinus Torvalds init_sg(void) 16781da177e4SLinus Torvalds { 16791da177e4SLinus Torvalds int rc; 16801da177e4SLinus Torvalds 16816460e75aSDouglas Gilbert if (scatter_elem_sz < PAGE_SIZE) { 16826460e75aSDouglas Gilbert scatter_elem_sz = PAGE_SIZE; 16836460e75aSDouglas Gilbert scatter_elem_sz_prev = scatter_elem_sz; 16846460e75aSDouglas Gilbert } 16851da177e4SLinus Torvalds if (def_reserved_size >= 0) 16861da177e4SLinus Torvalds sg_big_buff = def_reserved_size; 16876460e75aSDouglas Gilbert else 16886460e75aSDouglas Gilbert def_reserved_size = sg_big_buff; 16891da177e4SLinus Torvalds 16901da177e4SLinus Torvalds rc = register_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0), 16911da177e4SLinus Torvalds SG_MAX_DEVS, "sg"); 16921da177e4SLinus Torvalds if (rc) 16931da177e4SLinus Torvalds return rc; 1694f1fb4176SRicardo B. Marliere rc = class_register(&sg_sysfs_class); 1695f1fb4176SRicardo B. Marliere if (rc) 16961da177e4SLinus Torvalds goto err_out; 16971da177e4SLinus Torvalds sg_sysfs_valid = 1; 16981da177e4SLinus Torvalds rc = scsi_register_interface(&sg_interface); 16991da177e4SLinus Torvalds if (0 == rc) { 17001da177e4SLinus Torvalds #ifdef CONFIG_SCSI_PROC_FS 17011da177e4SLinus Torvalds sg_proc_init(); 17021da177e4SLinus Torvalds #endif /* CONFIG_SCSI_PROC_FS */ 17031da177e4SLinus Torvalds return 0; 17041da177e4SLinus Torvalds } 1705f1fb4176SRicardo B. Marliere class_unregister(&sg_sysfs_class); 170626d1c80fSXiaoming Ni register_sg_sysctls(); 17071da177e4SLinus Torvalds err_out: 17081da177e4SLinus Torvalds unregister_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0), SG_MAX_DEVS); 17091da177e4SLinus Torvalds return rc; 17101da177e4SLinus Torvalds } 17111da177e4SLinus Torvalds 17121da177e4SLinus Torvalds static void __exit 17131da177e4SLinus Torvalds exit_sg(void) 17141da177e4SLinus Torvalds { 171526d1c80fSXiaoming Ni unregister_sg_sysctls(); 17161da177e4SLinus Torvalds #ifdef CONFIG_SCSI_PROC_FS 1717b8b1483dSChristoph Hellwig remove_proc_subtree("scsi/sg", NULL); 17181da177e4SLinus Torvalds #endif /* CONFIG_SCSI_PROC_FS */ 17191da177e4SLinus Torvalds scsi_unregister_interface(&sg_interface); 1720f1fb4176SRicardo B. Marliere class_unregister(&sg_sysfs_class); 17211da177e4SLinus Torvalds sg_sysfs_valid = 0; 17221da177e4SLinus Torvalds unregister_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0), 17231da177e4SLinus Torvalds SG_MAX_DEVS); 17247c07d613SJames Bottomley idr_destroy(&sg_index_idr); 17251da177e4SLinus Torvalds } 17261da177e4SLinus Torvalds 1727cc833acbSDouglas Gilbert static int 1728cc833acbSDouglas Gilbert sg_start_req(Sg_request *srp, unsigned char *cmd) 172910865dfaSFUJITA Tomonori { 1730626710c9SFUJITA Tomonori int res; 173110865dfaSFUJITA Tomonori struct request *rq; 173244c7b0eaSFUJITA Tomonori Sg_fd *sfp = srp->parentfp; 173344c7b0eaSFUJITA Tomonori sg_io_hdr_t *hp = &srp->header; 173444c7b0eaSFUJITA Tomonori int dxfer_len = (int) hp->dxfer_len; 173544c7b0eaSFUJITA Tomonori int dxfer_dir = hp->dxfer_direction; 1736626710c9SFUJITA Tomonori unsigned int iov_count = hp->iovec_count; 173744c7b0eaSFUJITA Tomonori Sg_scatter_hold *req_schp = &srp->data; 173844c7b0eaSFUJITA Tomonori Sg_scatter_hold *rsv_schp = &sfp->reserve; 173944c7b0eaSFUJITA Tomonori struct request_queue *q = sfp->parentdp->device->request_queue; 1740626710c9SFUJITA Tomonori struct rq_map_data *md, map_data; 1741de4eda9dSAl Viro int rw = hp->dxfer_direction == SG_DXFER_TO_DEV ? ITER_SOURCE : ITER_DEST; 1742ce70fd9aSChristoph Hellwig struct scsi_cmnd *scmd; 174310865dfaSFUJITA Tomonori 174495e159d6SHannes Reinecke SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sfp->parentdp, 174595e159d6SHannes Reinecke "sg_start_req: dxfer_len=%d\n", 174644c7b0eaSFUJITA Tomonori dxfer_len)); 174744c7b0eaSFUJITA Tomonori 17487772855aSTony Battersby /* 17497772855aSTony Battersby * NOTE 17507772855aSTony Battersby * 17517772855aSTony Battersby * With scsi-mq enabled, there are a fixed number of preallocated 17527772855aSTony Battersby * requests equal in number to shost->can_queue. If all of the 175368ec3b81SChristoph Hellwig * preallocated requests are already in use, then scsi_alloc_request() 17548e4a4189STony Battersby * will sleep until an active command completes, freeing up a request. 17558e4a4189STony Battersby * Although waiting in an asynchronous interface is less than ideal, we 17568e4a4189STony Battersby * do not want to use BLK_MQ_REQ_NOWAIT here because userspace might 17578e4a4189STony Battersby * not expect an EWOULDBLOCK from this condition. 17587772855aSTony Battersby */ 175968ec3b81SChristoph Hellwig rq = scsi_alloc_request(q, hp->dxfer_direction == SG_DXFER_TO_DEV ? 1760da6269daSChristoph Hellwig REQ_OP_DRV_OUT : REQ_OP_DRV_IN, 0); 1761ce70fd9aSChristoph Hellwig if (IS_ERR(rq)) 1762a492f075SJoe Lawrence return PTR_ERR(rq); 1763ce70fd9aSChristoph Hellwig scmd = blk_mq_rq_to_pdu(rq); 176410865dfaSFUJITA Tomonori 1765ce70fd9aSChristoph Hellwig if (hp->cmd_len > sizeof(scmd->cmnd)) { 1766ce70fd9aSChristoph Hellwig blk_mq_free_request(rq); 1767ce70fd9aSChristoph Hellwig return -EINVAL; 1768ce70fd9aSChristoph Hellwig } 1769ce70fd9aSChristoph Hellwig 1770ce70fd9aSChristoph Hellwig memcpy(scmd->cmnd, cmd, hp->cmd_len); 1771ce70fd9aSChristoph Hellwig scmd->cmd_len = hp->cmd_len; 177210865dfaSFUJITA Tomonori 177310865dfaSFUJITA Tomonori srp->rq = rq; 177410865dfaSFUJITA Tomonori rq->end_io_data = srp; 17756aded12bSChristoph Hellwig scmd->allowed = SG_DEFAULT_RETRIES; 177610865dfaSFUJITA Tomonori 17771da177e4SLinus Torvalds if ((dxfer_len <= 0) || (dxfer_dir == SG_DXFER_NONE)) 177810db10d1SFUJITA Tomonori return 0; 177910865dfaSFUJITA Tomonori 1780626710c9SFUJITA Tomonori if (sg_allow_dio && hp->flags & SG_FLAG_DIRECT_IO && 1781626710c9SFUJITA Tomonori dxfer_dir != SG_DXFER_UNKNOWN && !iov_count && 17822610a254SNamhyung Kim blk_rq_aligned(q, (unsigned long)hp->dxferp, dxfer_len)) 1783626710c9SFUJITA Tomonori md = NULL; 1784626710c9SFUJITA Tomonori else 1785626710c9SFUJITA Tomonori md = &map_data; 17867e56cb0fSFUJITA Tomonori 1787626710c9SFUJITA Tomonori if (md) { 17881bc0eb04SHannes Reinecke mutex_lock(&sfp->f_mutex); 17891bc0eb04SHannes Reinecke if (dxfer_len <= rsv_schp->bufflen && 17901bc0eb04SHannes Reinecke !sfp->res_in_use) { 17911bc0eb04SHannes Reinecke sfp->res_in_use = 1; 17921da177e4SLinus Torvalds sg_link_reserve(sfp, srp, dxfer_len); 17938d26f491STodd Poynor } else if (hp->flags & SG_FLAG_MMAP_IO) { 17948d26f491STodd Poynor res = -EBUSY; /* sfp->res_in_use == 1 */ 17958d26f491STodd Poynor if (dxfer_len > rsv_schp->bufflen) 17968d26f491STodd Poynor res = -ENOMEM; 17971bc0eb04SHannes Reinecke mutex_unlock(&sfp->f_mutex); 17988d26f491STodd Poynor return res; 17991bc0eb04SHannes Reinecke } else { 18001da177e4SLinus Torvalds res = sg_build_indirect(req_schp, sfp, dxfer_len); 18011bc0eb04SHannes Reinecke if (res) { 18021bc0eb04SHannes Reinecke mutex_unlock(&sfp->f_mutex); 1803626710c9SFUJITA Tomonori return res; 180410db10d1SFUJITA Tomonori } 18051bc0eb04SHannes Reinecke } 18061bc0eb04SHannes Reinecke mutex_unlock(&sfp->f_mutex); 180710db10d1SFUJITA Tomonori 1808626710c9SFUJITA Tomonori md->pages = req_schp->pages; 1809626710c9SFUJITA Tomonori md->page_order = req_schp->page_order; 1810626710c9SFUJITA Tomonori md->nr_entries = req_schp->k_use_sg; 181156c451f4SFUJITA Tomonori md->offset = 0; 181297ae77a1SFUJITA Tomonori md->null_mapped = hp->dxferp ? 0 : 1; 1813ecb554a8SFUJITA Tomonori if (dxfer_dir == SG_DXFER_TO_FROM_DEV) 1814ecb554a8SFUJITA Tomonori md->from_user = 1; 1815ecb554a8SFUJITA Tomonori else 1816ecb554a8SFUJITA Tomonori md->from_user = 0; 1817626710c9SFUJITA Tomonori } 1818626710c9SFUJITA Tomonori 18196732932cSAnuj Gupta res = blk_rq_map_user_io(rq, md, hp->dxferp, hp->dxfer_len, 18206732932cSAnuj Gupta GFP_ATOMIC, iov_count, iov_count, 1, rw); 1821626710c9SFUJITA Tomonori if (!res) { 1822626710c9SFUJITA Tomonori srp->bio = rq->bio; 1823626710c9SFUJITA Tomonori 1824626710c9SFUJITA Tomonori if (!md) { 1825626710c9SFUJITA Tomonori req_schp->dio_in_use = 1; 1826626710c9SFUJITA Tomonori hp->info |= SG_INFO_DIRECT_IO; 1827626710c9SFUJITA Tomonori } 1828626710c9SFUJITA Tomonori } 18291da177e4SLinus Torvalds return res; 18301da177e4SLinus Torvalds } 18311da177e4SLinus Torvalds 1832cc833acbSDouglas Gilbert static int 1833cc833acbSDouglas Gilbert sg_finish_rem_req(Sg_request *srp) 18341da177e4SLinus Torvalds { 1835e7ee4cc0SFUJITA Tomonori int ret = 0; 1836e7ee4cc0SFUJITA Tomonori 18371da177e4SLinus Torvalds Sg_fd *sfp = srp->parentfp; 18381da177e4SLinus Torvalds Sg_scatter_hold *req_schp = &srp->data; 18391da177e4SLinus Torvalds 184095e159d6SHannes Reinecke SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sfp->parentdp, 184195e159d6SHannes Reinecke "sg_finish_rem_req: res_used=%d\n", 184295e159d6SHannes Reinecke (int) srp->res_used)); 18436e5a30cbSFUJITA Tomonori if (srp->bio) 1844e7ee4cc0SFUJITA Tomonori ret = blk_rq_unmap_user(srp->bio); 184510db10d1SFUJITA Tomonori 1846ce70fd9aSChristoph Hellwig if (srp->rq) 18470bf6d96cSChristoph Hellwig blk_mq_free_request(srp->rq); 184810865dfaSFUJITA Tomonori 1849e27168f8SChristof Schmitt if (srp->res_used) 1850e27168f8SChristof Schmitt sg_unlink_reserve(sfp, srp); 1851e27168f8SChristof Schmitt else 185295e159d6SHannes Reinecke sg_remove_scat(sfp, req_schp); 1853e27168f8SChristof Schmitt 1854e7ee4cc0SFUJITA Tomonori return ret; 18551da177e4SLinus Torvalds } 18561da177e4SLinus Torvalds 18571da177e4SLinus Torvalds static int 18581da177e4SLinus Torvalds sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp, int tablesize) 18591da177e4SLinus Torvalds { 186010db10d1SFUJITA Tomonori int sg_bufflen = tablesize * sizeof(struct page *); 18612d20eaf9SAl Viro gfp_t gfp_flags = GFP_ATOMIC | __GFP_NOWARN; 18621da177e4SLinus Torvalds 186310db10d1SFUJITA Tomonori schp->pages = kzalloc(sg_bufflen, gfp_flags); 186410db10d1SFUJITA Tomonori if (!schp->pages) 18651da177e4SLinus Torvalds return -ENOMEM; 18661da177e4SLinus Torvalds schp->sglist_len = sg_bufflen; 1867d6b10348SMike Christie return tablesize; /* number of scat_gath elements allocated */ 18681da177e4SLinus Torvalds } 18691da177e4SLinus Torvalds 18701da177e4SLinus Torvalds static int 18711da177e4SLinus Torvalds sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size) 18721da177e4SLinus Torvalds { 187310db10d1SFUJITA Tomonori int ret_sz = 0, i, k, rem_sz, num, mx_sc_elems; 1874d6b10348SMike Christie int sg_tablesize = sfp->parentdp->sg_tablesize; 187510db10d1SFUJITA Tomonori int blk_size = buff_size, order; 18765b9d3974SJeff Moyer gfp_t gfp_mask = GFP_ATOMIC | __GFP_COMP | __GFP_NOWARN | __GFP_ZERO; 18771da177e4SLinus Torvalds 1878fb119935SEric Sesterhenn if (blk_size < 0) 18791da177e4SLinus Torvalds return -EFAULT; 18801da177e4SLinus Torvalds if (0 == blk_size) 18811da177e4SLinus Torvalds ++blk_size; /* don't know why */ 18821da177e4SLinus Torvalds /* round request up to next highest SG_SECTOR_SZ byte boundary */ 1883b2ed6c69SFUJITA Tomonori blk_size = ALIGN(blk_size, SG_SECTOR_SZ); 188495e159d6SHannes Reinecke SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sfp->parentdp, 188595e159d6SHannes Reinecke "sg_build_indirect: buff_size=%d, blk_size=%d\n", 18861da177e4SLinus Torvalds buff_size, blk_size)); 18871da177e4SLinus Torvalds 18881da177e4SLinus Torvalds /* N.B. ret_sz carried into this block ... */ 18891da177e4SLinus Torvalds mx_sc_elems = sg_build_sgat(schp, sfp, sg_tablesize); 18901da177e4SLinus Torvalds if (mx_sc_elems < 0) 18911da177e4SLinus Torvalds return mx_sc_elems; /* most likely -ENOMEM */ 18921da177e4SLinus Torvalds 18936460e75aSDouglas Gilbert num = scatter_elem_sz; 18946460e75aSDouglas Gilbert if (unlikely(num != scatter_elem_sz_prev)) { 18956460e75aSDouglas Gilbert if (num < PAGE_SIZE) { 18966460e75aSDouglas Gilbert scatter_elem_sz = PAGE_SIZE; 18976460e75aSDouglas Gilbert scatter_elem_sz_prev = PAGE_SIZE; 18986460e75aSDouglas Gilbert } else 18996460e75aSDouglas Gilbert scatter_elem_sz_prev = num; 19006460e75aSDouglas Gilbert } 190110db10d1SFUJITA Tomonori 190210db10d1SFUJITA Tomonori order = get_order(num); 190310db10d1SFUJITA Tomonori retry: 190410db10d1SFUJITA Tomonori ret_sz = 1 << (PAGE_SHIFT + order); 190510db10d1SFUJITA Tomonori 190610db10d1SFUJITA Tomonori for (k = 0, rem_sz = blk_size; rem_sz > 0 && k < mx_sc_elems; 190710db10d1SFUJITA Tomonori k++, rem_sz -= ret_sz) { 1908d6b10348SMike Christie 19096460e75aSDouglas Gilbert num = (rem_sz > scatter_elem_sz_prev) ? 19106460e75aSDouglas Gilbert scatter_elem_sz_prev : rem_sz; 191110db10d1SFUJITA Tomonori 19125b9d3974SJeff Moyer schp->pages[k] = alloc_pages(gfp_mask, order); 191310db10d1SFUJITA Tomonori if (!schp->pages[k]) 191410db10d1SFUJITA Tomonori goto out; 1915d6b10348SMike Christie 19166460e75aSDouglas Gilbert if (num == scatter_elem_sz_prev) { 19176460e75aSDouglas Gilbert if (unlikely(ret_sz > scatter_elem_sz_prev)) { 19186460e75aSDouglas Gilbert scatter_elem_sz = ret_sz; 19196460e75aSDouglas Gilbert scatter_elem_sz_prev = ret_sz; 19206460e75aSDouglas Gilbert } 19216460e75aSDouglas Gilbert } 19221da177e4SLinus Torvalds 192395e159d6SHannes Reinecke SCSI_LOG_TIMEOUT(5, sg_printk(KERN_INFO, sfp->parentdp, 192495e159d6SHannes Reinecke "sg_build_indirect: k=%d, num=%d, ret_sz=%d\n", 192595e159d6SHannes Reinecke k, num, ret_sz)); 19261da177e4SLinus Torvalds } /* end of for loop */ 1927d6b10348SMike Christie 192810db10d1SFUJITA Tomonori schp->page_order = order; 19291da177e4SLinus Torvalds schp->k_use_sg = k; 193095e159d6SHannes Reinecke SCSI_LOG_TIMEOUT(5, sg_printk(KERN_INFO, sfp->parentdp, 193195e159d6SHannes Reinecke "sg_build_indirect: k_use_sg=%d, rem_sz=%d\n", 193295e159d6SHannes Reinecke k, rem_sz)); 1933d6b10348SMike Christie 19341da177e4SLinus Torvalds schp->bufflen = blk_size; 19351da177e4SLinus Torvalds if (rem_sz > 0) /* must have failed */ 19361da177e4SLinus Torvalds return -ENOMEM; 19371da177e4SLinus Torvalds return 0; 193810db10d1SFUJITA Tomonori out: 193910db10d1SFUJITA Tomonori for (i = 0; i < k; i++) 1940e71044eeSMichal Schmidt __free_pages(schp->pages[i], order); 194110db10d1SFUJITA Tomonori 194210db10d1SFUJITA Tomonori if (--order >= 0) 194310db10d1SFUJITA Tomonori goto retry; 194410db10d1SFUJITA Tomonori 194510db10d1SFUJITA Tomonori return -ENOMEM; 19461da177e4SLinus Torvalds } 19471da177e4SLinus Torvalds 19481da177e4SLinus Torvalds static void 194995e159d6SHannes Reinecke sg_remove_scat(Sg_fd * sfp, Sg_scatter_hold * schp) 19501da177e4SLinus Torvalds { 195195e159d6SHannes Reinecke SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sfp->parentdp, 195295e159d6SHannes Reinecke "sg_remove_scat: k_use_sg=%d\n", schp->k_use_sg)); 195310db10d1SFUJITA Tomonori if (schp->pages && schp->sglist_len > 0) { 19546e5a30cbSFUJITA Tomonori if (!schp->dio_in_use) { 19551da177e4SLinus Torvalds int k; 19561da177e4SLinus Torvalds 195710db10d1SFUJITA Tomonori for (k = 0; k < schp->k_use_sg && schp->pages[k]; k++) { 195895e159d6SHannes Reinecke SCSI_LOG_TIMEOUT(5, 195995e159d6SHannes Reinecke sg_printk(KERN_INFO, sfp->parentdp, 196010db10d1SFUJITA Tomonori "sg_remove_scat: k=%d, pg=0x%p\n", 196110db10d1SFUJITA Tomonori k, schp->pages[k])); 196210db10d1SFUJITA Tomonori __free_pages(schp->pages[k], schp->page_order); 19631da177e4SLinus Torvalds } 19646e5a30cbSFUJITA Tomonori 196510db10d1SFUJITA Tomonori kfree(schp->pages); 1966d6b10348SMike Christie } 19676e5a30cbSFUJITA Tomonori } 19681da177e4SLinus Torvalds memset(schp, 0, sizeof (*schp)); 19691da177e4SLinus Torvalds } 19701da177e4SLinus Torvalds 19711da177e4SLinus Torvalds static int 19721da177e4SLinus Torvalds sg_read_oxfer(Sg_request * srp, char __user *outp, int num_read_xfer) 19731da177e4SLinus Torvalds { 19741da177e4SLinus Torvalds Sg_scatter_hold *schp = &srp->data; 1975d6b10348SMike Christie int k, num; 19761da177e4SLinus Torvalds 197795e159d6SHannes Reinecke SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, srp->parentfp->parentdp, 197895e159d6SHannes Reinecke "sg_read_oxfer: num_read_xfer=%d\n", 19791da177e4SLinus Torvalds num_read_xfer)); 19801da177e4SLinus Torvalds if ((!outp) || (num_read_xfer <= 0)) 19811da177e4SLinus Torvalds return 0; 19821da177e4SLinus Torvalds 198310db10d1SFUJITA Tomonori num = 1 << (PAGE_SHIFT + schp->page_order); 198410db10d1SFUJITA Tomonori for (k = 0; k < schp->k_use_sg && schp->pages[k]; k++) { 19851da177e4SLinus Torvalds if (num > num_read_xfer) { 1986c8c12792SAl Viro if (copy_to_user(outp, page_address(schp->pages[k]), 1987d6b10348SMike Christie num_read_xfer)) 19881da177e4SLinus Torvalds return -EFAULT; 19891da177e4SLinus Torvalds break; 19901da177e4SLinus Torvalds } else { 1991c8c12792SAl Viro if (copy_to_user(outp, page_address(schp->pages[k]), 1992d6b10348SMike Christie num)) 19931da177e4SLinus Torvalds return -EFAULT; 19941da177e4SLinus Torvalds num_read_xfer -= num; 19951da177e4SLinus Torvalds if (num_read_xfer <= 0) 19961da177e4SLinus Torvalds break; 19971da177e4SLinus Torvalds outp += num; 19981da177e4SLinus Torvalds } 19991da177e4SLinus Torvalds } 2000d6b10348SMike Christie 20011da177e4SLinus Torvalds return 0; 20021da177e4SLinus Torvalds } 20031da177e4SLinus Torvalds 20041da177e4SLinus Torvalds static void 20051da177e4SLinus Torvalds sg_build_reserve(Sg_fd * sfp, int req_size) 20061da177e4SLinus Torvalds { 20071da177e4SLinus Torvalds Sg_scatter_hold *schp = &sfp->reserve; 20081da177e4SLinus Torvalds 200995e159d6SHannes Reinecke SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sfp->parentdp, 201095e159d6SHannes Reinecke "sg_build_reserve: req_size=%d\n", req_size)); 20111da177e4SLinus Torvalds do { 20121da177e4SLinus Torvalds if (req_size < PAGE_SIZE) 20131da177e4SLinus Torvalds req_size = PAGE_SIZE; 20141da177e4SLinus Torvalds if (0 == sg_build_indirect(schp, sfp, req_size)) 20151da177e4SLinus Torvalds return; 20161da177e4SLinus Torvalds else 201795e159d6SHannes Reinecke sg_remove_scat(sfp, schp); 20181da177e4SLinus Torvalds req_size >>= 1; /* divide by 2 */ 20191da177e4SLinus Torvalds } while (req_size > (PAGE_SIZE / 2)); 20201da177e4SLinus Torvalds } 20211da177e4SLinus Torvalds 20221da177e4SLinus Torvalds static void 20231da177e4SLinus Torvalds sg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size) 20241da177e4SLinus Torvalds { 20251da177e4SLinus Torvalds Sg_scatter_hold *req_schp = &srp->data; 20261da177e4SLinus Torvalds Sg_scatter_hold *rsv_schp = &sfp->reserve; 2027d6b10348SMike Christie int k, num, rem; 20281da177e4SLinus Torvalds 20291da177e4SLinus Torvalds srp->res_used = 1; 203095e159d6SHannes Reinecke SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sfp->parentdp, 203195e159d6SHannes Reinecke "sg_link_reserve: size=%d\n", size)); 2032eca7be5eSBrian King rem = size; 20331da177e4SLinus Torvalds 203410db10d1SFUJITA Tomonori num = 1 << (PAGE_SHIFT + rsv_schp->page_order); 203510db10d1SFUJITA Tomonori for (k = 0; k < rsv_schp->k_use_sg; k++) { 20361da177e4SLinus Torvalds if (rem <= num) { 20371da177e4SLinus Torvalds req_schp->k_use_sg = k + 1; 2038d6b10348SMike Christie req_schp->sglist_len = rsv_schp->sglist_len; 203910db10d1SFUJITA Tomonori req_schp->pages = rsv_schp->pages; 2040d6b10348SMike Christie 20411da177e4SLinus Torvalds req_schp->bufflen = size; 204210db10d1SFUJITA Tomonori req_schp->page_order = rsv_schp->page_order; 20431da177e4SLinus Torvalds break; 20441da177e4SLinus Torvalds } else 20451da177e4SLinus Torvalds rem -= num; 20461da177e4SLinus Torvalds } 2047d6b10348SMike Christie 20481da177e4SLinus Torvalds if (k >= rsv_schp->k_use_sg) 204995e159d6SHannes Reinecke SCSI_LOG_TIMEOUT(1, sg_printk(KERN_INFO, sfp->parentdp, 205095e159d6SHannes Reinecke "sg_link_reserve: BAD size\n")); 20511da177e4SLinus Torvalds } 20521da177e4SLinus Torvalds 20531da177e4SLinus Torvalds static void 20541da177e4SLinus Torvalds sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp) 20551da177e4SLinus Torvalds { 20561da177e4SLinus Torvalds Sg_scatter_hold *req_schp = &srp->data; 20571da177e4SLinus Torvalds 205895e159d6SHannes Reinecke SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, srp->parentfp->parentdp, 205995e159d6SHannes Reinecke "sg_unlink_reserve: req->k_use_sg=%d\n", 20601da177e4SLinus Torvalds (int) req_schp->k_use_sg)); 20611da177e4SLinus Torvalds req_schp->k_use_sg = 0; 20621da177e4SLinus Torvalds req_schp->bufflen = 0; 206310db10d1SFUJITA Tomonori req_schp->pages = NULL; 206410db10d1SFUJITA Tomonori req_schp->page_order = 0; 20651da177e4SLinus Torvalds req_schp->sglist_len = 0; 20661da177e4SLinus Torvalds srp->res_used = 0; 2067e791ce27SHannes Reinecke /* Called without mutex lock to avoid deadlock */ 2068e791ce27SHannes Reinecke sfp->res_in_use = 0; 20691da177e4SLinus Torvalds } 20701da177e4SLinus Torvalds 20711da177e4SLinus Torvalds static Sg_request * 20723455607fSTony Battersby sg_get_rq_mark(Sg_fd * sfp, int pack_id, bool *busy) 20731da177e4SLinus Torvalds { 20741da177e4SLinus Torvalds Sg_request *resp; 20751da177e4SLinus Torvalds unsigned long iflags; 20761da177e4SLinus Torvalds 20773455607fSTony Battersby *busy = false; 20781da177e4SLinus Torvalds write_lock_irqsave(&sfp->rq_list_lock, iflags); 2079109bade9SHannes Reinecke list_for_each_entry(resp, &sfp->rq_list, entry) { 20803455607fSTony Battersby /* look for requests that are not SG_IO owned */ 20813455607fSTony Battersby if ((!resp->sg_io_owned) && 20821da177e4SLinus Torvalds ((-1 == pack_id) || (resp->header.pack_id == pack_id))) { 20833455607fSTony Battersby switch (resp->done) { 20843455607fSTony Battersby case 0: /* request active */ 20853455607fSTony Battersby *busy = true; 20863455607fSTony Battersby break; 20873455607fSTony Battersby case 1: /* request done; response ready to return */ 20881da177e4SLinus Torvalds resp->done = 2; /* guard against other readers */ 208948ae8484SJohannes Thumshirn write_unlock_irqrestore(&sfp->rq_list_lock, iflags); 209048ae8484SJohannes Thumshirn return resp; 20913455607fSTony Battersby case 2: /* response already being returned */ 20923455607fSTony Battersby break; 20933455607fSTony Battersby } 20941da177e4SLinus Torvalds } 20951da177e4SLinus Torvalds } 20961da177e4SLinus Torvalds write_unlock_irqrestore(&sfp->rq_list_lock, iflags); 209748ae8484SJohannes Thumshirn return NULL; 20981da177e4SLinus Torvalds } 20991da177e4SLinus Torvalds 21001da177e4SLinus Torvalds /* always adds to end of list */ 21011da177e4SLinus Torvalds static Sg_request * 21021da177e4SLinus Torvalds sg_add_request(Sg_fd * sfp) 21031da177e4SLinus Torvalds { 21041da177e4SLinus Torvalds int k; 21051da177e4SLinus Torvalds unsigned long iflags; 21061da177e4SLinus Torvalds Sg_request *rp = sfp->req_arr; 21071da177e4SLinus Torvalds 21081da177e4SLinus Torvalds write_lock_irqsave(&sfp->rq_list_lock, iflags); 2109109bade9SHannes Reinecke if (!list_empty(&sfp->rq_list)) { 2110109bade9SHannes Reinecke if (!sfp->cmd_q) 2111109bade9SHannes Reinecke goto out_unlock; 2112109bade9SHannes Reinecke 21131da177e4SLinus Torvalds for (k = 0; k < SG_MAX_QUEUE; ++k, ++rp) { 21141da177e4SLinus Torvalds if (!rp->parentfp) 21151da177e4SLinus Torvalds break; 21161da177e4SLinus Torvalds } 2117109bade9SHannes Reinecke if (k >= SG_MAX_QUEUE) 2118109bade9SHannes Reinecke goto out_unlock; 2119109bade9SHannes Reinecke } 21201da177e4SLinus Torvalds memset(rp, 0, sizeof (Sg_request)); 21211da177e4SLinus Torvalds rp->parentfp = sfp; 2122109bade9SHannes Reinecke rp->header.duration = jiffies_to_msecs(jiffies); 2123109bade9SHannes Reinecke list_add_tail(&rp->entry, &sfp->rq_list); 21241da177e4SLinus Torvalds write_unlock_irqrestore(&sfp->rq_list_lock, iflags); 2125109bade9SHannes Reinecke return rp; 2126109bade9SHannes Reinecke out_unlock: 2127109bade9SHannes Reinecke write_unlock_irqrestore(&sfp->rq_list_lock, iflags); 2128109bade9SHannes Reinecke return NULL; 21291da177e4SLinus Torvalds } 21301da177e4SLinus Torvalds 21311da177e4SLinus Torvalds /* Return of 1 for found; 0 for not found */ 21321da177e4SLinus Torvalds static int 21331da177e4SLinus Torvalds sg_remove_request(Sg_fd * sfp, Sg_request * srp) 21341da177e4SLinus Torvalds { 21351da177e4SLinus Torvalds unsigned long iflags; 21361da177e4SLinus Torvalds int res = 0; 21371da177e4SLinus Torvalds 2138109bade9SHannes Reinecke if (!sfp || !srp || list_empty(&sfp->rq_list)) 21391da177e4SLinus Torvalds return res; 21401da177e4SLinus Torvalds write_lock_irqsave(&sfp->rq_list_lock, iflags); 2141109bade9SHannes Reinecke if (!list_empty(&srp->entry)) { 2142109bade9SHannes Reinecke list_del(&srp->entry); 2143109bade9SHannes Reinecke srp->parentfp = NULL; 21441da177e4SLinus Torvalds res = 1; 21451da177e4SLinus Torvalds } 21461da177e4SLinus Torvalds write_unlock_irqrestore(&sfp->rq_list_lock, iflags); 21473455607fSTony Battersby 21483455607fSTony Battersby /* 21493455607fSTony Battersby * If the device is detaching, wakeup any readers in case we just 21503455607fSTony Battersby * removed the last response, which would leave nothing for them to 21513455607fSTony Battersby * return other than -ENODEV. 21523455607fSTony Battersby */ 21533455607fSTony Battersby if (unlikely(atomic_read(&sfp->parentdp->detaching))) 21543455607fSTony Battersby wake_up_interruptible_all(&sfp->read_wait); 21553455607fSTony Battersby 21561da177e4SLinus Torvalds return res; 21571da177e4SLinus Torvalds } 21581da177e4SLinus Torvalds 21591da177e4SLinus Torvalds static Sg_fd * 216095e159d6SHannes Reinecke sg_add_sfp(Sg_device * sdp) 21611da177e4SLinus Torvalds { 21621da177e4SLinus Torvalds Sg_fd *sfp; 21631da177e4SLinus Torvalds unsigned long iflags; 216444ec9542SAlan Stern int bufflen; 21651da177e4SLinus Torvalds 2166d6b10348SMike Christie sfp = kzalloc(sizeof(*sfp), GFP_ATOMIC | __GFP_NOWARN); 21671da177e4SLinus Torvalds if (!sfp) 2168cc833acbSDouglas Gilbert return ERR_PTR(-ENOMEM); 2169d6b10348SMike Christie 21701da177e4SLinus Torvalds init_waitqueue_head(&sfp->read_wait); 21711da177e4SLinus Torvalds rwlock_init(&sfp->rq_list_lock); 2172109bade9SHannes Reinecke INIT_LIST_HEAD(&sfp->rq_list); 2173c6517b79STony Battersby kref_init(&sfp->f_ref); 21741bc0eb04SHannes Reinecke mutex_init(&sfp->f_mutex); 21751da177e4SLinus Torvalds sfp->timeout = SG_DEFAULT_TIMEOUT; 21761da177e4SLinus Torvalds sfp->timeout_user = SG_DEFAULT_TIMEOUT_USER; 21771da177e4SLinus Torvalds sfp->force_packid = SG_DEF_FORCE_PACK_ID; 21781da177e4SLinus Torvalds sfp->cmd_q = SG_DEF_COMMAND_Q; 21791da177e4SLinus Torvalds sfp->keep_orphan = SG_DEF_KEEP_ORPHAN; 21801da177e4SLinus Torvalds sfp->parentdp = sdp; 2181cc833acbSDouglas Gilbert write_lock_irqsave(&sdp->sfd_lock, iflags); 2182cc833acbSDouglas Gilbert if (atomic_read(&sdp->detaching)) { 2183cc833acbSDouglas Gilbert write_unlock_irqrestore(&sdp->sfd_lock, iflags); 2184c170e5a8STony Battersby kfree(sfp); 2185cc833acbSDouglas Gilbert return ERR_PTR(-ENODEV); 2186cc833acbSDouglas Gilbert } 21873442f802SFUJITA Tomonori list_add_tail(&sfp->sfd_siblings, &sdp->sfds); 2188cc833acbSDouglas Gilbert write_unlock_irqrestore(&sdp->sfd_lock, iflags); 218995e159d6SHannes Reinecke SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp, 219095e159d6SHannes Reinecke "sg_add_sfp: sfp=0x%p\n", sfp)); 21916460e75aSDouglas Gilbert if (unlikely(sg_big_buff != def_reserved_size)) 21926460e75aSDouglas Gilbert sg_big_buff = def_reserved_size; 21936460e75aSDouglas Gilbert 219444ec9542SAlan Stern bufflen = min_t(int, sg_big_buff, 219546f69e6aSAkinobu Mita max_sectors_bytes(sdp->device->request_queue)); 219644ec9542SAlan Stern sg_build_reserve(sfp, bufflen); 219795e159d6SHannes Reinecke SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp, 219895e159d6SHannes Reinecke "sg_add_sfp: bufflen=%d, k_use_sg=%d\n", 219995e159d6SHannes Reinecke sfp->reserve.bufflen, 220095e159d6SHannes Reinecke sfp->reserve.k_use_sg)); 2201c6517b79STony Battersby 2202c6517b79STony Battersby kref_get(&sdp->d_ref); 2203c6517b79STony Battersby __module_get(THIS_MODULE); 22041da177e4SLinus Torvalds return sfp; 22051da177e4SLinus Torvalds } 22061da177e4SLinus Torvalds 2207cc833acbSDouglas Gilbert static void 2208cc833acbSDouglas Gilbert sg_remove_sfp_usercontext(struct work_struct *work) 22091da177e4SLinus Torvalds { 2210c6517b79STony Battersby struct sg_fd *sfp = container_of(work, struct sg_fd, ew.work); 2211c6517b79STony Battersby struct sg_device *sdp = sfp->parentdp; 221227f58c04SAlexander Wetzel struct scsi_device *device = sdp->device; 2213109bade9SHannes Reinecke Sg_request *srp; 221497d27b0dSHannes Reinecke unsigned long iflags; 22151da177e4SLinus Torvalds 2216c6517b79STony Battersby /* Cleanup any responses which were never read(). */ 221797d27b0dSHannes Reinecke write_lock_irqsave(&sfp->rq_list_lock, iflags); 2218109bade9SHannes Reinecke while (!list_empty(&sfp->rq_list)) { 2219109bade9SHannes Reinecke srp = list_first_entry(&sfp->rq_list, Sg_request, entry); 2220109bade9SHannes Reinecke sg_finish_rem_req(srp); 222197d27b0dSHannes Reinecke list_del(&srp->entry); 222297d27b0dSHannes Reinecke srp->parentfp = NULL; 2223109bade9SHannes Reinecke } 222497d27b0dSHannes Reinecke write_unlock_irqrestore(&sfp->rq_list_lock, iflags); 2225c6517b79STony Battersby 22261da177e4SLinus Torvalds if (sfp->reserve.bufflen > 0) { 222795e159d6SHannes Reinecke SCSI_LOG_TIMEOUT(6, sg_printk(KERN_INFO, sdp, 222895e159d6SHannes Reinecke "sg_remove_sfp: bufflen=%d, k_use_sg=%d\n", 2229c6517b79STony Battersby (int) sfp->reserve.bufflen, 2230c6517b79STony Battersby (int) sfp->reserve.k_use_sg)); 223195e159d6SHannes Reinecke sg_remove_scat(sfp, &sfp->reserve); 22321da177e4SLinus Torvalds } 2233c6517b79STony Battersby 223495e159d6SHannes Reinecke SCSI_LOG_TIMEOUT(6, sg_printk(KERN_INFO, sdp, 223595e159d6SHannes Reinecke "sg_remove_sfp: sfp=0x%p\n", sfp)); 2236d6b10348SMike Christie kfree(sfp); 2237c6517b79STony Battersby 2238cc833acbSDouglas Gilbert kref_put(&sdp->d_ref, sg_device_destroy); 223927f58c04SAlexander Wetzel scsi_device_put(device); 2240c6517b79STony Battersby module_put(THIS_MODULE); 22411da177e4SLinus Torvalds } 22421da177e4SLinus Torvalds 2243cc833acbSDouglas Gilbert static void 2244cc833acbSDouglas Gilbert sg_remove_sfp(struct kref *kref) 22451da177e4SLinus Torvalds { 2246c6517b79STony Battersby struct sg_fd *sfp = container_of(kref, struct sg_fd, f_ref); 2247065b4a2fSJames Bottomley struct sg_device *sdp = sfp->parentdp; 22481da177e4SLinus Torvalds unsigned long iflags; 22491da177e4SLinus Torvalds 2250cc833acbSDouglas Gilbert write_lock_irqsave(&sdp->sfd_lock, iflags); 22513442f802SFUJITA Tomonori list_del(&sfp->sfd_siblings); 2252cc833acbSDouglas Gilbert write_unlock_irqrestore(&sdp->sfd_lock, iflags); 2253c6517b79STony Battersby 2254015640edSFUJITA Tomonori INIT_WORK(&sfp->ew.work, sg_remove_sfp_usercontext); 2255015640edSFUJITA Tomonori schedule_work(&sfp->ew.work); 22561da177e4SLinus Torvalds } 22571da177e4SLinus Torvalds 22581da177e4SLinus Torvalds #ifdef CONFIG_SCSI_PROC_FS 22591da177e4SLinus Torvalds static int 22607c07d613SJames Bottomley sg_idr_max_id(int id, void *p, void *data) 22617c07d613SJames Bottomley { 22627c07d613SJames Bottomley int *k = data; 22637c07d613SJames Bottomley 22647c07d613SJames Bottomley if (*k < id) 22657c07d613SJames Bottomley *k = id; 22667c07d613SJames Bottomley 22677c07d613SJames Bottomley return 0; 22687c07d613SJames Bottomley } 22697c07d613SJames Bottomley 22707c07d613SJames Bottomley static int 22711da177e4SLinus Torvalds sg_last_dev(void) 22721da177e4SLinus Torvalds { 227353474c04STony Battersby int k = -1; 22741da177e4SLinus Torvalds unsigned long iflags; 22751da177e4SLinus Torvalds 22767c07d613SJames Bottomley read_lock_irqsave(&sg_index_lock, iflags); 22777c07d613SJames Bottomley idr_for_each(&sg_index_idr, sg_idr_max_id, &k); 22787c07d613SJames Bottomley read_unlock_irqrestore(&sg_index_lock, iflags); 22791da177e4SLinus Torvalds return k + 1; /* origin 1 */ 22801da177e4SLinus Torvalds } 22811da177e4SLinus Torvalds #endif 22821da177e4SLinus Torvalds 2283c6517b79STony Battersby /* must be called with sg_index_lock held */ 2284c6517b79STony Battersby static Sg_device *sg_lookup_dev(int dev) 22851da177e4SLinus Torvalds { 2286c6517b79STony Battersby return idr_find(&sg_index_idr, dev); 2287c6517b79STony Battersby } 22881da177e4SLinus Torvalds 2289cc833acbSDouglas Gilbert static Sg_device * 2290cc833acbSDouglas Gilbert sg_get_dev(int dev) 2291c6517b79STony Battersby { 2292c6517b79STony Battersby struct sg_device *sdp; 2293c6517b79STony Battersby unsigned long flags; 2294c6517b79STony Battersby 2295c6517b79STony Battersby read_lock_irqsave(&sg_index_lock, flags); 2296c6517b79STony Battersby sdp = sg_lookup_dev(dev); 2297c6517b79STony Battersby if (!sdp) 2298c6517b79STony Battersby sdp = ERR_PTR(-ENXIO); 2299cc833acbSDouglas Gilbert else if (atomic_read(&sdp->detaching)) { 2300cc833acbSDouglas Gilbert /* If sdp->detaching, then the refcount may already be 0, in 2301c6517b79STony Battersby * which case it would be a bug to do kref_get(). 2302c6517b79STony Battersby */ 2303c6517b79STony Battersby sdp = ERR_PTR(-ENODEV); 2304c6517b79STony Battersby } else 2305c6517b79STony Battersby kref_get(&sdp->d_ref); 2306c6517b79STony Battersby read_unlock_irqrestore(&sg_index_lock, flags); 23077c07d613SJames Bottomley 23081da177e4SLinus Torvalds return sdp; 23091da177e4SLinus Torvalds } 23101da177e4SLinus Torvalds 23111da177e4SLinus Torvalds #ifdef CONFIG_SCSI_PROC_FS 23121da177e4SLinus Torvalds static int sg_proc_seq_show_int(struct seq_file *s, void *v); 23131da177e4SLinus Torvalds 23141da177e4SLinus Torvalds static int sg_proc_single_open_adio(struct inode *inode, struct file *file); 23151da177e4SLinus Torvalds static ssize_t sg_proc_write_adio(struct file *filp, const char __user *buffer, 23161da177e4SLinus Torvalds size_t count, loff_t *off); 231797a32539SAlexey Dobriyan static const struct proc_ops adio_proc_ops = { 231897a32539SAlexey Dobriyan .proc_open = sg_proc_single_open_adio, 231997a32539SAlexey Dobriyan .proc_read = seq_read, 232097a32539SAlexey Dobriyan .proc_lseek = seq_lseek, 232197a32539SAlexey Dobriyan .proc_write = sg_proc_write_adio, 232297a32539SAlexey Dobriyan .proc_release = single_release, 23231da177e4SLinus Torvalds }; 23241da177e4SLinus Torvalds 23251da177e4SLinus Torvalds static int sg_proc_single_open_dressz(struct inode *inode, struct file *file); 23261da177e4SLinus Torvalds static ssize_t sg_proc_write_dressz(struct file *filp, 23271da177e4SLinus Torvalds const char __user *buffer, size_t count, loff_t *off); 232897a32539SAlexey Dobriyan static const struct proc_ops dressz_proc_ops = { 232997a32539SAlexey Dobriyan .proc_open = sg_proc_single_open_dressz, 233097a32539SAlexey Dobriyan .proc_read = seq_read, 233197a32539SAlexey Dobriyan .proc_lseek = seq_lseek, 233297a32539SAlexey Dobriyan .proc_write = sg_proc_write_dressz, 233397a32539SAlexey Dobriyan .proc_release = single_release, 23341da177e4SLinus Torvalds }; 23351da177e4SLinus Torvalds 23361da177e4SLinus Torvalds static int sg_proc_seq_show_version(struct seq_file *s, void *v); 23371da177e4SLinus Torvalds static int sg_proc_seq_show_devhdr(struct seq_file *s, void *v); 23381da177e4SLinus Torvalds static int sg_proc_seq_show_dev(struct seq_file *s, void *v); 23391da177e4SLinus Torvalds static void * dev_seq_start(struct seq_file *s, loff_t *pos); 23401da177e4SLinus Torvalds static void * dev_seq_next(struct seq_file *s, void *v, loff_t *pos); 23411da177e4SLinus Torvalds static void dev_seq_stop(struct seq_file *s, void *v); 234288e9d34cSJames Morris static const struct seq_operations dev_seq_ops = { 23431da177e4SLinus Torvalds .start = dev_seq_start, 23441da177e4SLinus Torvalds .next = dev_seq_next, 23451da177e4SLinus Torvalds .stop = dev_seq_stop, 23461da177e4SLinus Torvalds .show = sg_proc_seq_show_dev, 23471da177e4SLinus Torvalds }; 23481da177e4SLinus Torvalds 23491da177e4SLinus Torvalds static int sg_proc_seq_show_devstrs(struct seq_file *s, void *v); 235088e9d34cSJames Morris static const struct seq_operations devstrs_seq_ops = { 23511da177e4SLinus Torvalds .start = dev_seq_start, 23521da177e4SLinus Torvalds .next = dev_seq_next, 23531da177e4SLinus Torvalds .stop = dev_seq_stop, 23541da177e4SLinus Torvalds .show = sg_proc_seq_show_devstrs, 23551da177e4SLinus Torvalds }; 23561da177e4SLinus Torvalds 23571da177e4SLinus Torvalds static int sg_proc_seq_show_debug(struct seq_file *s, void *v); 235888e9d34cSJames Morris static const struct seq_operations debug_seq_ops = { 23591da177e4SLinus Torvalds .start = dev_seq_start, 23601da177e4SLinus Torvalds .next = dev_seq_next, 23611da177e4SLinus Torvalds .stop = dev_seq_stop, 23621da177e4SLinus Torvalds .show = sg_proc_seq_show_debug, 23631da177e4SLinus Torvalds }; 23641da177e4SLinus Torvalds 23651da177e4SLinus Torvalds static int 23661da177e4SLinus Torvalds sg_proc_init(void) 23671da177e4SLinus Torvalds { 2368b8b1483dSChristoph Hellwig struct proc_dir_entry *p; 23691da177e4SLinus Torvalds 2370b8b1483dSChristoph Hellwig p = proc_mkdir("scsi/sg", NULL); 2371b8b1483dSChristoph Hellwig if (!p) 23721da177e4SLinus Torvalds return 1; 2373b8b1483dSChristoph Hellwig 237497a32539SAlexey Dobriyan proc_create("allow_dio", S_IRUGO | S_IWUSR, p, &adio_proc_ops); 2375b8b1483dSChristoph Hellwig proc_create_seq("debug", S_IRUGO, p, &debug_seq_ops); 237697a32539SAlexey Dobriyan proc_create("def_reserved_size", S_IRUGO | S_IWUSR, p, &dressz_proc_ops); 2377b8b1483dSChristoph Hellwig proc_create_single("device_hdr", S_IRUGO, p, sg_proc_seq_show_devhdr); 2378b8b1483dSChristoph Hellwig proc_create_seq("devices", S_IRUGO, p, &dev_seq_ops); 2379b8b1483dSChristoph Hellwig proc_create_seq("device_strs", S_IRUGO, p, &devstrs_seq_ops); 2380b8b1483dSChristoph Hellwig proc_create_single("version", S_IRUGO, p, sg_proc_seq_show_version); 23811da177e4SLinus Torvalds return 0; 23821da177e4SLinus Torvalds } 23831da177e4SLinus Torvalds 23841da177e4SLinus Torvalds 23851da177e4SLinus Torvalds static int sg_proc_seq_show_int(struct seq_file *s, void *v) 23861da177e4SLinus Torvalds { 23871da177e4SLinus Torvalds seq_printf(s, "%d\n", *((int *)s->private)); 23881da177e4SLinus Torvalds return 0; 23891da177e4SLinus Torvalds } 23901da177e4SLinus Torvalds 23911da177e4SLinus Torvalds static int sg_proc_single_open_adio(struct inode *inode, struct file *file) 23921da177e4SLinus Torvalds { 23931da177e4SLinus Torvalds return single_open(file, sg_proc_seq_show_int, &sg_allow_dio); 23941da177e4SLinus Torvalds } 23951da177e4SLinus Torvalds 23961da177e4SLinus Torvalds static ssize_t 23971da177e4SLinus Torvalds sg_proc_write_adio(struct file *filp, const char __user *buffer, 23981da177e4SLinus Torvalds size_t count, loff_t *off) 23991da177e4SLinus Torvalds { 24007e95fffeSStephen Boyd int err; 24017e95fffeSStephen Boyd unsigned long num; 24021da177e4SLinus Torvalds 24031da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) 24041da177e4SLinus Torvalds return -EACCES; 24057e95fffeSStephen Boyd err = kstrtoul_from_user(buffer, count, 0, &num); 24067e95fffeSStephen Boyd if (err) 24077e95fffeSStephen Boyd return err; 24087e95fffeSStephen Boyd sg_allow_dio = num ? 1 : 0; 24091da177e4SLinus Torvalds return count; 24101da177e4SLinus Torvalds } 24111da177e4SLinus Torvalds 24121da177e4SLinus Torvalds static int sg_proc_single_open_dressz(struct inode *inode, struct file *file) 24131da177e4SLinus Torvalds { 24141da177e4SLinus Torvalds return single_open(file, sg_proc_seq_show_int, &sg_big_buff); 24151da177e4SLinus Torvalds } 24161da177e4SLinus Torvalds 24171da177e4SLinus Torvalds static ssize_t 24181da177e4SLinus Torvalds sg_proc_write_dressz(struct file *filp, const char __user *buffer, 24191da177e4SLinus Torvalds size_t count, loff_t *off) 24201da177e4SLinus Torvalds { 24217e95fffeSStephen Boyd int err; 24221da177e4SLinus Torvalds unsigned long k = ULONG_MAX; 24231da177e4SLinus Torvalds 24241da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) 24251da177e4SLinus Torvalds return -EACCES; 24267e95fffeSStephen Boyd 24277e95fffeSStephen Boyd err = kstrtoul_from_user(buffer, count, 0, &k); 24287e95fffeSStephen Boyd if (err) 24297e95fffeSStephen Boyd return err; 24301da177e4SLinus Torvalds if (k <= 1048576) { /* limit "big buff" to 1 MB */ 24311da177e4SLinus Torvalds sg_big_buff = k; 24321da177e4SLinus Torvalds return count; 24331da177e4SLinus Torvalds } 24341da177e4SLinus Torvalds return -ERANGE; 24351da177e4SLinus Torvalds } 24361da177e4SLinus Torvalds 24371da177e4SLinus Torvalds static int sg_proc_seq_show_version(struct seq_file *s, void *v) 24381da177e4SLinus Torvalds { 24391da177e4SLinus Torvalds seq_printf(s, "%d\t%s [%s]\n", sg_version_num, SG_VERSION_STR, 24401da177e4SLinus Torvalds sg_version_date); 24411da177e4SLinus Torvalds return 0; 24421da177e4SLinus Torvalds } 24431da177e4SLinus Torvalds 24441da177e4SLinus Torvalds static int sg_proc_seq_show_devhdr(struct seq_file *s, void *v) 24451da177e4SLinus Torvalds { 2446cc833acbSDouglas Gilbert seq_puts(s, "host\tchan\tid\tlun\ttype\topens\tqdepth\tbusy\tonline\n"); 24471da177e4SLinus Torvalds return 0; 24481da177e4SLinus Torvalds } 24491da177e4SLinus Torvalds 24501da177e4SLinus Torvalds struct sg_proc_deviter { 24511da177e4SLinus Torvalds loff_t index; 24521da177e4SLinus Torvalds size_t max; 24531da177e4SLinus Torvalds }; 24541da177e4SLinus Torvalds 24551da177e4SLinus Torvalds static void * dev_seq_start(struct seq_file *s, loff_t *pos) 24561da177e4SLinus Torvalds { 24571da177e4SLinus Torvalds struct sg_proc_deviter * it = kmalloc(sizeof(*it), GFP_KERNEL); 24581da177e4SLinus Torvalds 2459729d70f5SJan Blunck s->private = it; 24601da177e4SLinus Torvalds if (! it) 24611da177e4SLinus Torvalds return NULL; 2462729d70f5SJan Blunck 24631da177e4SLinus Torvalds it->index = *pos; 24641da177e4SLinus Torvalds it->max = sg_last_dev(); 24651da177e4SLinus Torvalds if (it->index >= it->max) 24661da177e4SLinus Torvalds return NULL; 2467729d70f5SJan Blunck return it; 24681da177e4SLinus Torvalds } 24691da177e4SLinus Torvalds 24701da177e4SLinus Torvalds static void * dev_seq_next(struct seq_file *s, void *v, loff_t *pos) 24711da177e4SLinus Torvalds { 2472729d70f5SJan Blunck struct sg_proc_deviter * it = s->private; 24731da177e4SLinus Torvalds 24741da177e4SLinus Torvalds *pos = ++it->index; 24751da177e4SLinus Torvalds return (it->index < it->max) ? it : NULL; 24761da177e4SLinus Torvalds } 24771da177e4SLinus Torvalds 24781da177e4SLinus Torvalds static void dev_seq_stop(struct seq_file *s, void *v) 24791da177e4SLinus Torvalds { 2480729d70f5SJan Blunck kfree(s->private); 24811da177e4SLinus Torvalds } 24821da177e4SLinus Torvalds 24831da177e4SLinus Torvalds static int sg_proc_seq_show_dev(struct seq_file *s, void *v) 24841da177e4SLinus Torvalds { 24851da177e4SLinus Torvalds struct sg_proc_deviter * it = (struct sg_proc_deviter *) v; 24861da177e4SLinus Torvalds Sg_device *sdp; 24871da177e4SLinus Torvalds struct scsi_device *scsidp; 2488c6517b79STony Battersby unsigned long iflags; 24891da177e4SLinus Torvalds 2490c6517b79STony Battersby read_lock_irqsave(&sg_index_lock, iflags); 2491c6517b79STony Battersby sdp = it ? sg_lookup_dev(it->index) : NULL; 2492cc833acbSDouglas Gilbert if ((NULL == sdp) || (NULL == sdp->device) || 2493cc833acbSDouglas Gilbert (atomic_read(&sdp->detaching))) 2494cc833acbSDouglas Gilbert seq_puts(s, "-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\n"); 2495cc833acbSDouglas Gilbert else { 2496cc833acbSDouglas Gilbert scsidp = sdp->device; 24979cb78c16SHannes Reinecke seq_printf(s, "%d\t%d\t%d\t%llu\t%d\t%d\t%d\t%d\t%d\n", 24981da177e4SLinus Torvalds scsidp->host->host_no, scsidp->channel, 24991da177e4SLinus Torvalds scsidp->id, scsidp->lun, (int) scsidp->type, 25001da177e4SLinus Torvalds 1, 25011da177e4SLinus Torvalds (int) scsidp->queue_depth, 25028278807aSMing Lei (int) scsi_device_busy(scsidp), 25031da177e4SLinus Torvalds (int) scsi_device_online(scsidp)); 2504cc833acbSDouglas Gilbert } 2505c6517b79STony Battersby read_unlock_irqrestore(&sg_index_lock, iflags); 25061da177e4SLinus Torvalds return 0; 25071da177e4SLinus Torvalds } 25081da177e4SLinus Torvalds 25091da177e4SLinus Torvalds static int sg_proc_seq_show_devstrs(struct seq_file *s, void *v) 25101da177e4SLinus Torvalds { 25111da177e4SLinus Torvalds struct sg_proc_deviter * it = (struct sg_proc_deviter *) v; 25121da177e4SLinus Torvalds Sg_device *sdp; 25131da177e4SLinus Torvalds struct scsi_device *scsidp; 2514c6517b79STony Battersby unsigned long iflags; 25151da177e4SLinus Torvalds 2516c6517b79STony Battersby read_lock_irqsave(&sg_index_lock, iflags); 2517c6517b79STony Battersby sdp = it ? sg_lookup_dev(it->index) : NULL; 2518cc833acbSDouglas Gilbert scsidp = sdp ? sdp->device : NULL; 2519cc833acbSDouglas Gilbert if (sdp && scsidp && (!atomic_read(&sdp->detaching))) 25201da177e4SLinus Torvalds seq_printf(s, "%8.8s\t%16.16s\t%4.4s\n", 25211da177e4SLinus Torvalds scsidp->vendor, scsidp->model, scsidp->rev); 25221da177e4SLinus Torvalds else 2523cc833acbSDouglas Gilbert seq_puts(s, "<no active device>\n"); 2524c6517b79STony Battersby read_unlock_irqrestore(&sg_index_lock, iflags); 25251da177e4SLinus Torvalds return 0; 25261da177e4SLinus Torvalds } 25271da177e4SLinus Torvalds 2528c0d3b9c2SJames Bottomley /* must be called while holding sg_index_lock */ 25291da177e4SLinus Torvalds static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp) 25301da177e4SLinus Torvalds { 2531109bade9SHannes Reinecke int k, new_interface, blen, usg; 25321da177e4SLinus Torvalds Sg_request *srp; 25331da177e4SLinus Torvalds Sg_fd *fp; 25341da177e4SLinus Torvalds const sg_io_hdr_t *hp; 25351da177e4SLinus Torvalds const char * cp; 2536cb59e840S unsigned int ms; 25371da177e4SLinus Torvalds 25383442f802SFUJITA Tomonori k = 0; 25393442f802SFUJITA Tomonori list_for_each_entry(fp, &sdp->sfds, sfd_siblings) { 25403442f802SFUJITA Tomonori k++; 2541c6517b79STony Battersby read_lock(&fp->rq_list_lock); /* irqs already disabled */ 25421da177e4SLinus Torvalds seq_printf(s, " FD(%d): timeout=%dms bufflen=%d " 25433442f802SFUJITA Tomonori "(res)sgat=%d low_dma=%d\n", k, 25441da177e4SLinus Torvalds jiffies_to_msecs(fp->timeout), 25451da177e4SLinus Torvalds fp->reserve.bufflen, 2546aaff5ebaSChristoph Hellwig (int) fp->reserve.k_use_sg, 0); 2547ebaf466bSJörn Engel seq_printf(s, " cmd_q=%d f_packid=%d k_orphan=%d closed=0\n", 25481da177e4SLinus Torvalds (int) fp->cmd_q, (int) fp->force_packid, 2549ebaf466bSJörn Engel (int) fp->keep_orphan); 2550109bade9SHannes Reinecke list_for_each_entry(srp, &fp->rq_list, entry) { 25511da177e4SLinus Torvalds hp = &srp->header; 25521da177e4SLinus Torvalds new_interface = (hp->interface_id == '\0') ? 0 : 1; 25531da177e4SLinus Torvalds if (srp->res_used) { 25541da177e4SLinus Torvalds if (new_interface && 25551da177e4SLinus Torvalds (SG_FLAG_MMAP_IO & hp->flags)) 25561da177e4SLinus Torvalds cp = " mmap>> "; 25571da177e4SLinus Torvalds else 25581da177e4SLinus Torvalds cp = " rb>> "; 25591da177e4SLinus Torvalds } else { 25601da177e4SLinus Torvalds if (SG_INFO_DIRECT_IO_MASK & hp->info) 25611da177e4SLinus Torvalds cp = " dio>> "; 25621da177e4SLinus Torvalds else 25631da177e4SLinus Torvalds cp = " "; 25641da177e4SLinus Torvalds } 2565cc833acbSDouglas Gilbert seq_puts(s, cp); 2566d6b10348SMike Christie blen = srp->data.bufflen; 2567d6b10348SMike Christie usg = srp->data.k_use_sg; 2568cc833acbSDouglas Gilbert seq_puts(s, srp->done ? 25691da177e4SLinus Torvalds ((1 == srp->done) ? "rcv:" : "fin:") 2570d6b10348SMike Christie : "act:"); 25711da177e4SLinus Torvalds seq_printf(s, " id=%d blen=%d", 25721da177e4SLinus Torvalds srp->header.pack_id, blen); 25731da177e4SLinus Torvalds if (srp->done) 25741da177e4SLinus Torvalds seq_printf(s, " dur=%d", hp->duration); 2575cb59e840S else { 2576cb59e840S ms = jiffies_to_msecs(jiffies); 25771da177e4SLinus Torvalds seq_printf(s, " t_o/elap=%d/%d", 2578cb59e840S (new_interface ? hp->timeout : 2579cb59e840S jiffies_to_msecs(fp->timeout)), 2580cb59e840S (ms > hp->duration ? ms - hp->duration : 0)); 2581cb59e840S } 25821da177e4SLinus Torvalds seq_printf(s, "ms sgat=%d op=0x%02x\n", usg, 25831da177e4SLinus Torvalds (int) srp->data.cmd_opcode); 25841da177e4SLinus Torvalds } 2585109bade9SHannes Reinecke if (list_empty(&fp->rq_list)) 2586cc833acbSDouglas Gilbert seq_puts(s, " No requests active\n"); 2587c6517b79STony Battersby read_unlock(&fp->rq_list_lock); 25881da177e4SLinus Torvalds } 25891da177e4SLinus Torvalds } 25901da177e4SLinus Torvalds 25911da177e4SLinus Torvalds static int sg_proc_seq_show_debug(struct seq_file *s, void *v) 25921da177e4SLinus Torvalds { 25931da177e4SLinus Torvalds struct sg_proc_deviter * it = (struct sg_proc_deviter *) v; 25941da177e4SLinus Torvalds Sg_device *sdp; 2595c6517b79STony Battersby unsigned long iflags; 25961da177e4SLinus Torvalds 2597cc833acbSDouglas Gilbert if (it && (0 == it->index)) 2598cc833acbSDouglas Gilbert seq_printf(s, "max_active_device=%d def_reserved_size=%d\n", 2599cc833acbSDouglas Gilbert (int)it->max, sg_big_buff); 2600c6517b79STony Battersby 2601c6517b79STony Battersby read_lock_irqsave(&sg_index_lock, iflags); 2602c6517b79STony Battersby sdp = it ? sg_lookup_dev(it->index) : NULL; 2603cc833acbSDouglas Gilbert if (NULL == sdp) 2604cc833acbSDouglas Gilbert goto skip; 2605cc833acbSDouglas Gilbert read_lock(&sdp->sfd_lock); 2606cc833acbSDouglas Gilbert if (!list_empty(&sdp->sfds)) { 2607aebbb583SChristoph Hellwig seq_printf(s, " >>> device=%s ", sdp->name); 2608cc833acbSDouglas Gilbert if (atomic_read(&sdp->detaching)) 2609cc833acbSDouglas Gilbert seq_puts(s, "detaching pending close "); 2610cc833acbSDouglas Gilbert else if (sdp->device) { 26111da177e4SLinus Torvalds struct scsi_device *scsidp = sdp->device; 26121da177e4SLinus Torvalds 26139cb78c16SHannes Reinecke seq_printf(s, "%d:%d:%d:%llu em=%d", 26141da177e4SLinus Torvalds scsidp->host->host_no, 26151da177e4SLinus Torvalds scsidp->channel, scsidp->id, 26161da177e4SLinus Torvalds scsidp->lun, 26171da177e4SLinus Torvalds scsidp->host->hostt->emulated); 2618cc833acbSDouglas Gilbert } 2619cc833acbSDouglas Gilbert seq_printf(s, " sg_tablesize=%d excl=%d open_cnt=%d\n", 2620cc833acbSDouglas Gilbert sdp->sg_tablesize, sdp->exclude, sdp->open_cnt); 26211da177e4SLinus Torvalds sg_proc_debug_helper(s, sdp); 26221da177e4SLinus Torvalds } 2623cc833acbSDouglas Gilbert read_unlock(&sdp->sfd_lock); 2624cc833acbSDouglas Gilbert skip: 2625c6517b79STony Battersby read_unlock_irqrestore(&sg_index_lock, iflags); 26261da177e4SLinus Torvalds return 0; 26271da177e4SLinus Torvalds } 26281da177e4SLinus Torvalds 26291da177e4SLinus Torvalds #endif /* CONFIG_SCSI_PROC_FS */ 26301da177e4SLinus Torvalds 26311da177e4SLinus Torvalds module_init(init_sg); 26321da177e4SLinus Torvalds module_exit(exit_sg); 2633