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