Blame view

drivers/scsi/sg.c 73.9 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
  /*
   *  History:
   *  Started: Aug 9 by Lawrence Foard (entropy@world.std.com),
   *           to allow user process control of SCSI devices.
   *  Development Sponsored by Killy Corp. NY NY
   *
   * Original driver (sg.c):
   *        Copyright (C) 1992 Lawrence Foard
   * Version 2 and 3 extensions to driver:
65c26a0f3   Douglas Gilbert   sg: relax 16 byte...
10
   *        Copyright (C) 1998 - 2014 Douglas Gilbert
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
12
13
14
15
16
17
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2, or (at your option)
   * any later version.
   *
   */
65c26a0f3   Douglas Gilbert   sg: relax 16 byte...
18
19
  static int sg_version_num = 30536;	/* 2 digits for each component */
  #define SG_VERSION_STR "3.5.36"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
21
  
  /*
65c26a0f3   Douglas Gilbert   sg: relax 16 byte...
22
   *  D. P. Gilbert (dgilbert@interlog.com), notes:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
25
26
27
   *      - scsi logging is available via SCSI_LOG_TIMEOUT macros. First
   *        the kernel/module needs to be built with CONFIG_SCSI_LOGGING
   *        (otherwise the macros compile to empty statements).
   *
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
29
30
31
32
33
34
35
36
37
  #include <linux/module.h>
  
  #include <linux/fs.h>
  #include <linux/kernel.h>
  #include <linux/sched.h>
  #include <linux/string.h>
  #include <linux/mm.h>
  #include <linux/errno.h>
  #include <linux/mtio.h>
  #include <linux/ioctl.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
38
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
41
  #include <linux/fcntl.h>
  #include <linux/init.h>
  #include <linux/poll.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
  #include <linux/moduleparam.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
  #include <linux/cdev.h>
7c07d613d   James Bottomley   [SCSI] sg: use id...
44
  #include <linux/idr.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
46
47
  #include <linux/seq_file.h>
  #include <linux/blkdev.h>
  #include <linux/delay.h>
6da127ad0   Christof Schmitt   blktrace: Add blk...
48
  #include <linux/blktrace_api.h>
c45d15d24   Arnd Bergmann   scsi: autoconvert...
49
  #include <linux/mutex.h>
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
50
  #include <linux/atomic.h>
2fe038e33   Christian Dietrich   scsi/sg: use prin...
51
  #include <linux/ratelimit.h>
e2e40f2c1   Christoph Hellwig   fs: move struct k...
52
  #include <linux/uio.h>
6e51bfa95   Jann Horn   scsi: sg: mitigat...
53
  #include <linux/cred.h> /* for sg_check_file_access() */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
55
  
  #include "scsi.h"
db9dff366   Christoph Hellwig   [PATCH] remove ou...
56
  #include <scsi/scsi_dbg.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
58
59
60
61
62
63
64
65
  #include <scsi/scsi_host.h>
  #include <scsi/scsi_driver.h>
  #include <scsi/scsi_ioctl.h>
  #include <scsi/sg.h>
  
  #include "scsi_logging.h"
  
  #ifdef CONFIG_SCSI_PROC_FS
  #include <linux/proc_fs.h>
65c26a0f3   Douglas Gilbert   sg: relax 16 byte...
66
  static char *sg_version_date = "20140603";
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
68
69
70
  
  static int sg_proc_init(void);
  static void sg_proc_cleanup(void);
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
  #define SG_ALLOW_DIO_DEF 0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
73
  
  #define SG_MAX_DEVS 32768
65c26a0f3   Douglas Gilbert   sg: relax 16 byte...
74
75
76
77
78
  /* SG_MAX_CDB_SIZE should be 260 (spc4r37 section 3.1.30) however the type
   * of sg_io_hdr::cmd_len can only represent 255. All SCSI commands greater
   * than 16 bytes are "variable length" whose length is a multiple of 4
   */
  #define SG_MAX_CDB_SIZE 252
f8630bd7e   Paul Burton   scsi: sg: Use mul...
79
  #define SG_DEFAULT_TIMEOUT mult_frac(SG_DEFAULT_TIMEOUT_USER, HZ, USER_HZ)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80
81
82
83
84
85
86
87
88
89
  
  int sg_big_buff = SG_DEF_RESERVED_SIZE;
  /* N.B. This variable is readable and writeable via
     /proc/scsi/sg/def_reserved_size . Each time sg_open() is called a buffer
     of this size (or less if there is not enough memory) will be reserved
     for use by this file descriptor. [Deprecated usage: this variable is also
     readable via /proc/sys/kernel/sg-big-buff if the sg driver is built into
     the kernel (i.e. it is not a module).] */
  static int def_reserved_size = -1;	/* picks up init parameter */
  static int sg_allow_dio = SG_ALLOW_DIO_DEF;
6460e75a1   Douglas Gilbert   [SCSI] sg: fixes ...
90
91
  static int scatter_elem_sz = SG_SCATTER_SZ;
  static int scatter_elem_sz_prev = SG_SCATTER_SZ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
  #define SG_SECTOR_SZ 512
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93

cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
94
95
  static int sg_add_device(struct device *, struct class_interface *);
  static void sg_remove_device(struct device *, struct class_interface *);
98481ff0b   James Bottomley   [SCSI] Revert "sg...
96

7c07d613d   James Bottomley   [SCSI] sg: use id...
97
  static DEFINE_IDR(sg_index_idr);
c0d3b9c29   James Bottomley   [SCSI] Revert "sg...
98
99
  static DEFINE_RWLOCK(sg_index_lock);	/* Also used to lock
  							   file descriptor list for device */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
101
  
  static struct class_interface sg_interface = {
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
102
103
  	.add_dev        = sg_add_device,
  	.remove_dev     = sg_remove_device,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
105
106
107
  };
  
  typedef struct sg_scatter_hold { /* holding area for scsi scatter gather info */
  	unsigned short k_use_sg; /* Count of kernel scatter-gather pieces */
ea312552e   FUJITA Tomonori   [SCSI] sg: increa...
108
  	unsigned sglist_len; /* size of malloc'd scatter-gather list ++ */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
  	unsigned bufflen;	/* Size of (aggregate) data buffer */
10db10d14   FUJITA Tomonori   sg: convert the i...
110
111
  	struct page **pages;
  	int page_order;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
113
114
115
116
117
118
119
  	char dio_in_use;	/* 0->indirect IO (or mmap), 1->dio */
  	unsigned char cmd_opcode; /* first byte of command */
  } Sg_scatter_hold;
  
  struct sg_device;		/* forward declarations */
  struct sg_fd;
  
  typedef struct sg_request {	/* SG_MAX_QUEUE requests outstanding per file */
109bade9c   Hannes Reinecke   scsi: sg: use sta...
120
  	struct list_head entry;	/* list entry */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
122
123
  	struct sg_fd *parentfp;	/* NULL -> not in use */
  	Sg_scatter_hold data;	/* hold buffer, perhaps scatter list */
  	sg_io_hdr_t header;	/* scsi command+info, see <scsi/sg.h> */
d6b10348f   Mike Christie   [SCSI] convert sg...
124
  	unsigned char sense_b[SCSI_SENSE_BUFFERSIZE];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125
126
127
  	char res_used;		/* 1 -> using reserve buffer, 0 -> not ... */
  	char orphan;		/* 1 -> drop on sight, 0 -> normal */
  	char sg_io_owned;	/* 1 -> packet belongs to SG_IO */
6acddc5e9   Jörn Engel   [SCSI] sg: preven...
128
129
  	/* done protected by rq_list_lock */
  	char done;		/* 0->before bh, 1->before read, 2->read */
10865dfa3   FUJITA Tomonori   sg: convert the n...
130
  	struct request *rq;
6e5a30cba   FUJITA Tomonori   sg: convert the d...
131
  	struct bio *bio;
c96952ed7   FUJITA Tomonori   [SCSI] sg: avoid ...
132
  	struct execute_work ew;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
133
134
135
  } Sg_request;
  
  typedef struct sg_fd {		/* holds the state of a file descriptor */
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
136
  	struct list_head sfd_siblings;  /* protected by device's sfd_lock */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
138
139
  	struct sg_device *parentdp;	/* owning device */
  	wait_queue_head_t read_wait;	/* queue read until command done */
  	rwlock_t rq_list_lock;	/* protect access to list in req_arr */
1bc0eb044   Hannes Reinecke   scsi: sg: protect...
140
  	struct mutex f_mutex;	/* protect against changes in this fd */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
142
143
  	int timeout;		/* defaults to SG_DEFAULT_TIMEOUT      */
  	int timeout_user;	/* defaults to SG_DEFAULT_TIMEOUT_USER */
  	Sg_scatter_hold reserve;	/* buffer held for this file descriptor */
109bade9c   Hannes Reinecke   scsi: sg: use sta...
144
  	struct list_head rq_list; /* head of request list */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
146
  	struct fasync_struct *async_qp;	/* used by asynchronous notification */
  	Sg_request req_arr[SG_MAX_QUEUE];	/* used as singly-linked list */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
  	char force_packid;	/* 1 -> pack_id input to read(), 0 -> ignored */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
  	char cmd_q;		/* 1 -> allow command queuing, 0 -> don't */
65c26a0f3   Douglas Gilbert   sg: relax 16 byte...
149
  	unsigned char next_cmd_len; /* 0: automatic, >0: use on next write() */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150
151
  	char keep_orphan;	/* 0 -> drop orphan (def), 1 -> keep for read() */
  	char mmap_called;	/* 0 -> mmap() never called on this fd */
1bc0eb044   Hannes Reinecke   scsi: sg: protect...
152
  	char res_in_use;	/* 1 -> 'reserve' array in use */
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
153
154
  	struct kref f_ref;
  	struct execute_work ew;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
156
157
158
  } Sg_fd;
  
  typedef struct sg_device { /* holds the state of each scsi generic device */
  	struct scsi_device *device;
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
159
160
  	wait_queue_head_t open_wait;    /* queue open() when O_EXCL present */
  	struct mutex open_rel_lock;     /* held when in open() or release() */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
  	int sg_tablesize;	/* adapter's max scatter-gather table size */
7c07d613d   James Bottomley   [SCSI] sg: use id...
162
  	u32 index;		/* device index number */
3442f802a   FUJITA Tomonori   [SCSI] sg: remove...
163
  	struct list_head sfds;
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
164
165
166
167
  	rwlock_t sfd_lock;      /* protect access to sfd list */
  	atomic_t detaching;     /* 0->device usable, 1->device detaching */
  	bool exclude;		/* 1->open(O_EXCL) succeeded and is active */
  	int open_cnt;		/* count of opens (perhaps < num(sfds) ) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
169
170
  	char sgdebug;		/* 0->off, 1->sense, 9->dump dev, 10-> all devs */
  	struct gendisk *disk;
  	struct cdev * cdev;	/* char_dev [sysfs: /sys/cdev/major/sg<n>] */
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
171
  	struct kref d_ref;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
172
  } Sg_device;
d6b10348f   Mike Christie   [SCSI] convert sg...
173
  /* tasklet or soft irq callback */
2a842acab   Christoph Hellwig   block: introduce ...
174
  static void sg_rq_end_io(struct request *rq, blk_status_t status);
10865dfa3   FUJITA Tomonori   sg: convert the n...
175
  static int sg_start_req(Sg_request *srp, unsigned char *cmd);
e7ee4cc04   FUJITA Tomonori   [SCSI] sg: return...
176
  static int sg_finish_rem_req(Sg_request * srp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177
  static int sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178
179
  static ssize_t sg_new_read(Sg_fd * sfp, char __user *buf, size_t count,
  			   Sg_request * srp);
0b07de85a   Adel Gadllah   allow userspace t...
180
181
  static ssize_t sg_new_write(Sg_fd *sfp, struct file *file,
  			const char __user *buf, size_t count, int blocking,
a2dd3b4ce   Tony Battersby   [SCSI] sg: fix ra...
182
  			int read_only, int sg_io_owned, Sg_request **o_srp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
183
184
  static int sg_common_write(Sg_fd * sfp, Sg_request * srp,
  			   unsigned char *cmnd, int timeout, int blocking);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
  static int sg_read_oxfer(Sg_request * srp, char __user *outp, int num_read_xfer);
95e159d6d   Hannes Reinecke   scsi: Implement s...
186
  static void sg_remove_scat(Sg_fd * sfp, Sg_scatter_hold * schp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
187
188
189
  static void sg_build_reserve(Sg_fd * sfp, int req_size);
  static void sg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size);
  static void sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp);
95e159d6d   Hannes Reinecke   scsi: Implement s...
190
  static Sg_fd *sg_add_sfp(Sg_device * sdp);
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
191
  static void sg_remove_sfp(struct kref *);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
193
194
  static Sg_request *sg_get_rq_mark(Sg_fd * sfp, int pack_id);
  static Sg_request *sg_add_request(Sg_fd * sfp);
  static int sg_remove_request(Sg_fd * sfp, Sg_request * srp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195
  static Sg_device *sg_get_dev(int dev);
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
196
  static void sg_device_destroy(struct kref *kref);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
197

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
199
200
201
  #define SZ_SG_HEADER sizeof(struct sg_header)
  #define SZ_SG_IO_HDR sizeof(sg_io_hdr_t)
  #define SZ_SG_IOVEC sizeof(sg_iovec_t)
  #define SZ_SG_REQ_INFO sizeof(sg_req_info_t)
95e159d6d   Hannes Reinecke   scsi: Implement s...
202
  #define sg_printk(prefix, sdp, fmt, a...) \
22e0d9941   Hannes Reinecke   scsi: introduce s...
203
204
  	sdev_prefix_printk(prefix, (sdp)->device,		\
  			   (sdp)->disk->disk_name, fmt, ##a)
95e159d6d   Hannes Reinecke   scsi: Implement s...
205

6e51bfa95   Jann Horn   scsi: sg: mitigat...
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
  /*
   * The SCSI interfaces that use read() and write() as an asynchronous variant of
   * ioctl(..., SG_IO, ...) are fundamentally unsafe, since there are lots of ways
   * to trigger read() and write() calls from various contexts with elevated
   * privileges. This can lead to kernel memory corruption (e.g. if these
   * interfaces are called through splice()) and privilege escalation inside
   * userspace (e.g. if a process with access to such a device passes a file
   * descriptor to a SUID binary as stdin/stdout/stderr).
   *
   * This function provides protection for the legacy API by restricting the
   * calling context.
   */
  static int sg_check_file_access(struct file *filp, const char *caller)
  {
  	if (filp->f_cred != current_real_cred()) {
  		pr_err_once("%s: process %d (%s) changed security contexts after opening file descriptor, this is not allowed.
  ",
  			caller, task_tgid_vnr(current), current->comm);
  		return -EPERM;
  	}
  	if (uaccess_kernel()) {
  		pr_err_once("%s: process %d (%s) called from kernel context, this is not allowed.
  ",
  			caller, task_tgid_vnr(current), current->comm);
  		return -EACCES;
  	}
  	return 0;
  }
14e507b85   FUJITA Tomonori   sg: restore comma...
234
235
  static int sg_allow_access(struct file *filp, unsigned char *cmd)
  {
35df83970   Joe Perches   drivers/scsi: Rem...
236
  	struct sg_fd *sfp = filp->private_data;
14e507b85   FUJITA Tomonori   sg: restore comma...
237
238
239
  
  	if (sfp->parentdp->device->type == TYPE_SCANNER)
  		return 0;
018e04468   Jens Axboe   block: get rid of...
240
  	return blk_verify_command(cmd, filp->f_mode & FMODE_WRITE);
14e507b85   FUJITA Tomonori   sg: restore comma...
241
  }
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
242
243
  static int
  open_wait(Sg_device *sdp, int flags)
98481ff0b   James Bottomley   [SCSI] Revert "sg...
244
  {
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
245
  	int retval = 0;
98481ff0b   James Bottomley   [SCSI] Revert "sg...
246

cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
  	if (flags & O_EXCL) {
  		while (sdp->open_cnt > 0) {
  			mutex_unlock(&sdp->open_rel_lock);
  			retval = wait_event_interruptible(sdp->open_wait,
  					(atomic_read(&sdp->detaching) ||
  					 !sdp->open_cnt));
  			mutex_lock(&sdp->open_rel_lock);
  
  			if (retval) /* -ERESTARTSYS */
  				return retval;
  			if (atomic_read(&sdp->detaching))
  				return -ENODEV;
  		}
  	} else {
  		while (sdp->exclude) {
  			mutex_unlock(&sdp->open_rel_lock);
  			retval = wait_event_interruptible(sdp->open_wait,
  					(atomic_read(&sdp->detaching) ||
  					 !sdp->exclude));
  			mutex_lock(&sdp->open_rel_lock);
  
  			if (retval) /* -ERESTARTSYS */
  				return retval;
  			if (atomic_read(&sdp->detaching))
  				return -ENODEV;
  		}
  	}
035d12e65   Jörn Engel   [SCSI] sg: comple...
274

cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
275
  	return retval;
035d12e65   Jörn Engel   [SCSI] sg: comple...
276
  }
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
277
  /* Returns 0 on success, else a negated errno value */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
278
279
280
281
282
  static int
  sg_open(struct inode *inode, struct file *filp)
  {
  	int dev = iminor(inode);
  	int flags = filp->f_flags;
d6b10348f   Mike Christie   [SCSI] convert sg...
283
  	struct request_queue *q;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
284
285
  	Sg_device *sdp;
  	Sg_fd *sfp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286
287
288
  	int retval;
  
  	nonseekable_open(inode, filp);
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
289
290
  	if ((flags & O_EXCL) && (O_RDONLY == (flags & O_ACCMODE)))
  		return -EPERM; /* Can't lock it with read only access */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
  	sdp = sg_get_dev(dev);
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
292
293
  	if (IS_ERR(sdp))
  		return PTR_ERR(sdp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294

95e159d6d   Hannes Reinecke   scsi: Implement s...
295
296
297
  	SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp,
  				      "sg_open: flags=0x%x
  ", flags));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
298
299
300
  	/* This driver's module count bumped by fops_get in <linux/fs.h> */
  	/* Prevent the device driver from vanishing while we sleep */
  	retval = scsi_device_get(sdp->device);
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
301
302
  	if (retval)
  		goto sg_put;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
303

bc4f24014   Alan Stern   [SCSI] implement ...
304
305
306
  	retval = scsi_autopm_get_device(sdp->device);
  	if (retval)
  		goto sdp_put;
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
307
308
309
  	/* scsi_block_when_processing_errors() may block so bypass
  	 * check if O_NONBLOCK. Permits SCSI commands to be issued
  	 * during error recovery. Tread carefully. */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
311
312
313
314
315
  	if (!((flags & O_NONBLOCK) ||
  	      scsi_block_when_processing_errors(sdp->device))) {
  		retval = -ENXIO;
  		/* we are in error recovery for this device */
  		goto error_out;
  	}
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
316
317
318
319
320
321
322
323
324
325
326
327
  	mutex_lock(&sdp->open_rel_lock);
  	if (flags & O_NONBLOCK) {
  		if (flags & O_EXCL) {
  			if (sdp->open_cnt > 0) {
  				retval = -EBUSY;
  				goto error_mutex_locked;
  			}
  		} else {
  			if (sdp->exclude) {
  				retval = -EBUSY;
  				goto error_mutex_locked;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
328
  		}
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
329
330
331
332
  	} else {
  		retval = open_wait(sdp, flags);
  		if (retval) /* -ERESTARTSYS or -ENODEV */
  			goto error_mutex_locked;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
333
  	}
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
334
335
336
337
338
339
  
  	/* N.B. at this point we are holding the open_rel_lock */
  	if (flags & O_EXCL)
  		sdp->exclude = true;
  
  	if (sdp->open_cnt < 1) {  /* no existing opens */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340
  		sdp->sgdebug = 0;
d6b10348f   Mike Christie   [SCSI] convert sg...
341
  		q = sdp->device->request_queue;
8a78362c4   Martin K. Petersen   block: Consolidat...
342
  		sdp->sg_tablesize = queue_max_segments(q);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
343
  	}
95e159d6d   Hannes Reinecke   scsi: Implement s...
344
  	sfp = sg_add_sfp(sdp);
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
345
346
347
  	if (IS_ERR(sfp)) {
  		retval = PTR_ERR(sfp);
  		goto out_undo;
065b4a2f5   James Bottomley   [SCSI] Revert "sg...
348
  	}
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
349
350
351
352
  
  	filp->private_data = sfp;
  	sdp->open_cnt++;
  	mutex_unlock(&sdp->open_rel_lock);
065b4a2f5   James Bottomley   [SCSI] Revert "sg...
353
  	retval = 0;
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
354
  sg_put:
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
355
  	kref_put(&sdp->d_ref, sg_device_destroy);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
356
  	return retval;
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
357
358
359
360
361
362
363
364
365
366
367
368
369
  
  out_undo:
  	if (flags & O_EXCL) {
  		sdp->exclude = false;   /* undo if error */
  		wake_up_interruptible(&sdp->open_wait);
  	}
  error_mutex_locked:
  	mutex_unlock(&sdp->open_rel_lock);
  error_out:
  	scsi_autopm_put_device(sdp->device);
  sdp_put:
  	scsi_device_put(sdp->device);
  	goto sg_put;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
370
  }
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
371
372
  /* Release resources associated with a successful sg_open()
   * Returns 0 on success, else a negated errno value */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
373
374
375
376
377
378
379
380
  static int
  sg_release(struct inode *inode, struct file *filp)
  {
  	Sg_device *sdp;
  	Sg_fd *sfp;
  
  	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
  		return -ENXIO;
95e159d6d   Hannes Reinecke   scsi: Implement s...
381
382
  	SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp, "sg_release
  "));
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
383

cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
384
  	mutex_lock(&sdp->open_rel_lock);
bc4f24014   Alan Stern   [SCSI] implement ...
385
  	scsi_autopm_put_device(sdp->device);
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
386
  	kref_put(&sfp->f_ref, sg_remove_sfp);
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
387
388
389
390
391
392
393
394
395
396
397
  	sdp->open_cnt--;
  
  	/* possibly many open()s waiting on exlude clearing, start many;
  	 * only open(O_EXCL)s wait on 0==open_cnt so only start one */
  	if (sdp->exclude) {
  		sdp->exclude = false;
  		wake_up_interruptible_all(&sdp->open_wait);
  	} else if (0 == sdp->open_cnt) {
  		wake_up_interruptible(&sdp->open_wait);
  	}
  	mutex_unlock(&sdp->open_rel_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398
399
400
401
402
403
  	return 0;
  }
  
  static ssize_t
  sg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
404
405
406
407
  	Sg_device *sdp;
  	Sg_fd *sfp;
  	Sg_request *srp;
  	int req_pack_id = -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408
  	sg_io_hdr_t *hp;
cb59e8408   Douglas Gilbert   [PATCH] sg.c: update
409
410
  	struct sg_header *old_hdr = NULL;
  	int retval = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411

6e51bfa95   Jann Horn   scsi: sg: mitigat...
412
413
414
415
416
417
418
  	/*
  	 * This could cause a response to be stranded. Close the associated
  	 * file descriptor to free up any resources being held.
  	 */
  	retval = sg_check_file_access(filp, __func__);
  	if (retval)
  		return retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
419
420
  	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
  		return -ENXIO;
95e159d6d   Hannes Reinecke   scsi: Implement s...
421
422
423
  	SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp,
  				      "sg_read: count=%d
  ", (int) count));
d6b10348f   Mike Christie   [SCSI] convert sg...
424

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
425
426
427
  	if (!access_ok(VERIFY_WRITE, buf, count))
  		return -EFAULT;
  	if (sfp->force_packid && (count >= SZ_SG_HEADER)) {
cb59e8408   Douglas Gilbert   [PATCH] sg.c: update
428
429
430
431
432
433
434
435
  		old_hdr = kmalloc(SZ_SG_HEADER, GFP_KERNEL);
  		if (!old_hdr)
  			return -ENOMEM;
  		if (__copy_from_user(old_hdr, buf, SZ_SG_HEADER)) {
  			retval = -EFAULT;
  			goto free_old_hdr;
  		}
  		if (old_hdr->reply_len < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
436
  			if (count >= SZ_SG_IO_HDR) {
cb59e8408   Douglas Gilbert   [PATCH] sg.c: update
437
438
439
440
441
442
443
444
445
446
447
448
449
450
  				sg_io_hdr_t *new_hdr;
  				new_hdr = kmalloc(SZ_SG_IO_HDR, GFP_KERNEL);
  				if (!new_hdr) {
  					retval = -ENOMEM;
  					goto free_old_hdr;
  				}
  				retval =__copy_from_user
  				    (new_hdr, buf, SZ_SG_IO_HDR);
  				req_pack_id = new_hdr->pack_id;
  				kfree(new_hdr);
  				if (retval) {
  					retval = -EFAULT;
  					goto free_old_hdr;
  				}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
451
452
  			}
  		} else
cb59e8408   Douglas Gilbert   [PATCH] sg.c: update
453
  			req_pack_id = old_hdr->pack_id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
454
455
456
  	}
  	srp = sg_get_rq_mark(sfp, req_pack_id);
  	if (!srp) {		/* now wait on packet to arrive */
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
457
  		if (atomic_read(&sdp->detaching)) {
cb59e8408   Douglas Gilbert   [PATCH] sg.c: update
458
459
460
461
462
463
464
  			retval = -ENODEV;
  			goto free_old_hdr;
  		}
  		if (filp->f_flags & O_NONBLOCK) {
  			retval = -EAGAIN;
  			goto free_old_hdr;
  		}
3f0c6aba0   Jörn Engel   [SCSI] sg: use wa...
465
  		retval = wait_event_interruptible(sfp->read_wait,
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
466
  			(atomic_read(&sdp->detaching) ||
3f0c6aba0   Jörn Engel   [SCSI] sg: use wa...
467
  			(srp = sg_get_rq_mark(sfp, req_pack_id))));
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
468
  		if (atomic_read(&sdp->detaching)) {
794c10fa0   Jörn Engel   [SCSI] sg: remove...
469
470
471
472
  			retval = -ENODEV;
  			goto free_old_hdr;
  		}
  		if (retval) {
cb59e8408   Douglas Gilbert   [PATCH] sg.c: update
473
474
  			/* -ERESTARTSYS as signal hit process */
  			goto free_old_hdr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
475
476
  		}
  	}
cb59e8408   Douglas Gilbert   [PATCH] sg.c: update
477
478
479
480
  	if (srp->header.interface_id != '\0') {
  		retval = sg_new_read(sfp, buf, count, srp);
  		goto free_old_hdr;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
481
482
  
  	hp = &srp->header;
cb59e8408   Douglas Gilbert   [PATCH] sg.c: update
483
484
485
486
487
488
489
490
491
492
493
494
  	if (old_hdr == NULL) {
  		old_hdr = kmalloc(SZ_SG_HEADER, GFP_KERNEL);
  		if (! old_hdr) {
  			retval = -ENOMEM;
  			goto free_old_hdr;
  		}
  	}
  	memset(old_hdr, 0, SZ_SG_HEADER);
  	old_hdr->reply_len = (int) hp->timeout;
  	old_hdr->pack_len = old_hdr->reply_len; /* old, strange behaviour */
  	old_hdr->pack_id = hp->pack_id;
  	old_hdr->twelve_byte =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
495
  	    ((srp->data.cmd_opcode >= 0xc0) && (12 == hp->cmd_len)) ? 1 : 0;
cb59e8408   Douglas Gilbert   [PATCH] sg.c: update
496
497
498
  	old_hdr->target_status = hp->masked_status;
  	old_hdr->host_status = hp->host_status;
  	old_hdr->driver_status = hp->driver_status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
499
500
  	if ((CHECK_CONDITION & hp->masked_status) ||
  	    (DRIVER_SENSE & hp->driver_status))
cb59e8408   Douglas Gilbert   [PATCH] sg.c: update
501
502
  		memcpy(old_hdr->sense_buffer, srp->sense_b,
  		       sizeof (old_hdr->sense_buffer));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
503
504
505
506
507
508
  	switch (hp->host_status) {
  	/* This setup of 'result' is for backward compatibility and is best
  	   ignored by the user who should use target, host + driver status */
  	case DID_OK:
  	case DID_PASSTHROUGH:
  	case DID_SOFT_ERROR:
cb59e8408   Douglas Gilbert   [PATCH] sg.c: update
509
  		old_hdr->result = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
510
511
512
513
  		break;
  	case DID_NO_CONNECT:
  	case DID_BUS_BUSY:
  	case DID_TIME_OUT:
cb59e8408   Douglas Gilbert   [PATCH] sg.c: update
514
  		old_hdr->result = EBUSY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
515
516
517
518
519
520
  		break;
  	case DID_BAD_TARGET:
  	case DID_ABORT:
  	case DID_PARITY:
  	case DID_RESET:
  	case DID_BAD_INTR:
cb59e8408   Douglas Gilbert   [PATCH] sg.c: update
521
  		old_hdr->result = EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
522
523
  		break;
  	case DID_ERROR:
cb59e8408   Douglas Gilbert   [PATCH] sg.c: update
524
  		old_hdr->result = (srp->sense_b[0] == 0 && 
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
525
526
527
  				  hp->masked_status == GOOD) ? 0 : EIO;
  		break;
  	default:
cb59e8408   Douglas Gilbert   [PATCH] sg.c: update
528
  		old_hdr->result = EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
529
530
531
532
533
  		break;
  	}
  
  	/* Now copy the result back to the user buffer.  */
  	if (count >= SZ_SG_HEADER) {
cb59e8408   Douglas Gilbert   [PATCH] sg.c: update
534
535
536
537
  		if (__copy_to_user(buf, old_hdr, SZ_SG_HEADER)) {
  			retval = -EFAULT;
  			goto free_old_hdr;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
538
  		buf += SZ_SG_HEADER;
cb59e8408   Douglas Gilbert   [PATCH] sg.c: update
539
540
  		if (count > old_hdr->reply_len)
  			count = old_hdr->reply_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541
  		if (count > SZ_SG_HEADER) {
cb59e8408   Douglas Gilbert   [PATCH] sg.c: update
542
543
544
545
  			if (sg_read_oxfer(srp, buf, count - SZ_SG_HEADER)) {
  				retval = -EFAULT;
  				goto free_old_hdr;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
546
547
  		}
  	} else
cb59e8408   Douglas Gilbert   [PATCH] sg.c: update
548
  		count = (old_hdr->result == 0) ? 0 : -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
549
  	sg_finish_rem_req(srp);
97d27b0dd   Hannes Reinecke   scsi: sg: close r...
550
  	sg_remove_request(sfp, srp);
cb59e8408   Douglas Gilbert   [PATCH] sg.c: update
551
552
  	retval = count;
  free_old_hdr:
c9475cb0c   Jesper Juhl   [PATCH] kfree cle...
553
  	kfree(old_hdr);
cb59e8408   Douglas Gilbert   [PATCH] sg.c: update
554
  	return retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
555
556
557
558
559
560
  }
  
  static ssize_t
  sg_new_read(Sg_fd * sfp, char __user *buf, size_t count, Sg_request * srp)
  {
  	sg_io_hdr_t *hp = &srp->header;
3b524a683   Tony Battersby   sg: fix read() er...
561
  	int err = 0, err2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
562
563
564
565
566
567
568
569
570
571
  	int len;
  
  	if (count < SZ_SG_IO_HDR) {
  		err = -EINVAL;
  		goto err_out;
  	}
  	hp->sb_len_wr = 0;
  	if ((hp->mx_sb_len > 0) && hp->sbp) {
  		if ((CHECK_CONDITION & hp->masked_status) ||
  		    (DRIVER_SENSE & hp->driver_status)) {
d6b10348f   Mike Christie   [SCSI] convert sg...
572
  			int sb_len = SCSI_SENSE_BUFFERSIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
  			sb_len = (hp->mx_sb_len > sb_len) ? sb_len : hp->mx_sb_len;
  			len = 8 + (int) srp->sense_b[7];	/* Additional sense length field */
  			len = (len > sb_len) ? sb_len : len;
  			if (copy_to_user(hp->sbp, srp->sense_b, len)) {
  				err = -EFAULT;
  				goto err_out;
  			}
  			hp->sb_len_wr = len;
  		}
  	}
  	if (hp->masked_status || hp->host_status || hp->driver_status)
  		hp->info |= SG_INFO_CHECK;
  	if (copy_to_user(buf, hp, SZ_SG_IO_HDR)) {
  		err = -EFAULT;
  		goto err_out;
  	}
0b6cb26c6   FUJITA Tomonori   sg: remove sg_rea...
589
  err_out:
3b524a683   Tony Battersby   sg: fix read() er...
590
  	err2 = sg_finish_rem_req(srp);
97d27b0dd   Hannes Reinecke   scsi: sg: close r...
591
  	sg_remove_request(sfp, srp);
3b524a683   Tony Battersby   sg: fix read() er...
592
  	return err ? : err2 ? : count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
593
594
595
596
597
598
599
600
601
602
603
604
605
  }
  
  static ssize_t
  sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
  {
  	int mxsize, cmd_size, k;
  	int input_size, blocking;
  	unsigned char opcode;
  	Sg_device *sdp;
  	Sg_fd *sfp;
  	Sg_request *srp;
  	struct sg_header old_hdr;
  	sg_io_hdr_t *hp;
65c26a0f3   Douglas Gilbert   sg: relax 16 byte...
606
  	unsigned char cmnd[SG_MAX_CDB_SIZE];
6e51bfa95   Jann Horn   scsi: sg: mitigat...
607
  	int retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
608

6e51bfa95   Jann Horn   scsi: sg: mitigat...
609
610
611
  	retval = sg_check_file_access(filp, __func__);
  	if (retval)
  		return retval;
128394eff   Al Viro   sg_write()/bsg_wr...
612

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
613
614
  	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
  		return -ENXIO;
95e159d6d   Hannes Reinecke   scsi: Implement s...
615
616
617
  	SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp,
  				      "sg_write: count=%d
  ", (int) count));
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
618
  	if (atomic_read(&sdp->detaching))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
619
620
621
622
623
624
625
626
627
628
629
630
631
  		return -ENODEV;
  	if (!((filp->f_flags & O_NONBLOCK) ||
  	      scsi_block_when_processing_errors(sdp->device)))
  		return -ENXIO;
  
  	if (!access_ok(VERIFY_READ, buf, count))
  		return -EFAULT;	/* protects following copy_from_user()s + get_user()s */
  	if (count < SZ_SG_HEADER)
  		return -EIO;
  	if (__copy_from_user(&old_hdr, buf, SZ_SG_HEADER))
  		return -EFAULT;
  	blocking = !(filp->f_flags & O_NONBLOCK);
  	if (old_hdr.reply_len < 0)
a2dd3b4ce   Tony Battersby   [SCSI] sg: fix ra...
632
633
  		return sg_new_write(sfp, filp, buf, count,
  				    blocking, 0, 0, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
634
635
636
637
  	if (count < (SZ_SG_HEADER + 6))
  		return -EIO;	/* The minimum scsi command length is 6 bytes. */
  
  	if (!(srp = sg_add_request(sfp))) {
95e159d6d   Hannes Reinecke   scsi: Implement s...
638
639
640
  		SCSI_LOG_TIMEOUT(1, sg_printk(KERN_INFO, sdp,
  					      "sg_write: queue full
  "));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
641
642
643
644
  		return -EDOM;
  	}
  	buf += SZ_SG_HEADER;
  	__get_user(opcode, buf);
1bc0eb044   Hannes Reinecke   scsi: sg: protect...
645
  	mutex_lock(&sfp->f_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
646
  	if (sfp->next_cmd_len > 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
647
648
649
650
651
652
653
  		cmd_size = sfp->next_cmd_len;
  		sfp->next_cmd_len = 0;	/* reset so only this write() effected */
  	} else {
  		cmd_size = COMMAND_SIZE(opcode);	/* based on SCSI command group */
  		if ((opcode >= 0xc0) && old_hdr.twelve_byte)
  			cmd_size = 12;
  	}
1bc0eb044   Hannes Reinecke   scsi: sg: protect...
654
  	mutex_unlock(&sfp->f_mutex);
95e159d6d   Hannes Reinecke   scsi: Implement s...
655
  	SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sdp,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
  		"sg_write:   scsi opcode=0x%02x, cmd_size=%d
  ", (int) opcode, cmd_size));
  /* Determine buffer size.  */
  	input_size = count - cmd_size;
  	mxsize = (input_size > old_hdr.reply_len) ? input_size : old_hdr.reply_len;
  	mxsize -= SZ_SG_HEADER;
  	input_size -= SZ_SG_HEADER;
  	if (input_size < 0) {
  		sg_remove_request(sfp, srp);
  		return -EIO;	/* User did not pass enough bytes for this command. */
  	}
  	hp = &srp->header;
  	hp->interface_id = '\0';	/* indicator of old interface tunnelled */
  	hp->cmd_len = (unsigned char) cmd_size;
  	hp->iovec_count = 0;
  	hp->mx_sb_len = 0;
  	if (input_size > 0)
  		hp->dxfer_direction = (old_hdr.reply_len > SZ_SG_HEADER) ?
  		    SG_DXFER_TO_FROM_DEV : SG_DXFER_TO_DEV;
  	else
  		hp->dxfer_direction = (mxsize > 0) ? SG_DXFER_FROM_DEV : SG_DXFER_NONE;
  	hp->dxfer_len = mxsize;
5ecee0a3e   Douglas Gilbert   sg: fix dxferp in...
678
679
  	if ((hp->dxfer_direction == SG_DXFER_TO_DEV) ||
  	    (hp->dxfer_direction == SG_DXFER_TO_FROM_DEV))
fad7f01e6   FUJITA Tomonori   sg: set dxferp to...
680
681
682
  		hp->dxferp = (char __user *)buf + cmd_size;
  	else
  		hp->dxferp = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
683
684
685
686
687
688
689
690
691
692
693
694
  	hp->sbp = NULL;
  	hp->timeout = old_hdr.reply_len;	/* structure abuse ... */
  	hp->flags = input_size;	/* structure abuse ... */
  	hp->pack_id = old_hdr.pack_id;
  	hp->usr_ptr = NULL;
  	if (__copy_from_user(cmnd, buf, cmd_size))
  		return -EFAULT;
  	/*
  	 * SG_DXFER_TO_FROM_DEV is functionally equivalent to SG_DXFER_FROM_DEV,
  	 * but is is possible that the app intended SG_DXFER_TO_DEV, because there
  	 * is a non-zero input_size, so emit a warning.
  	 */
eaa3e22e8   Andi Kleen   [SCSI] sg: Only p...
695
  	if (hp->dxfer_direction == SG_DXFER_TO_FROM_DEV) {
28676d869   Johannes Thumshirn   scsi: sg: check f...
696
697
698
699
700
701
702
703
704
705
  		printk_ratelimited(KERN_WARNING
  				   "sg_write: data in/out %d/%d bytes "
  				   "for SCSI command 0x%x-- guessing "
  				   "data in;
     program %s not setting "
  				   "count and/or reply_len properly
  ",
  				   old_hdr.reply_len - (int)SZ_SG_HEADER,
  				   input_size, (unsigned int) cmnd[0],
  				   current->comm);
eaa3e22e8   Andi Kleen   [SCSI] sg: Only p...
706
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
707
708
709
710
711
  	k = sg_common_write(sfp, srp, cmnd, sfp->timeout, blocking);
  	return (k < 0) ? k : count;
  }
  
  static ssize_t
0b07de85a   Adel Gadllah   allow userspace t...
712
  sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf,
a2dd3b4ce   Tony Battersby   [SCSI] sg: fix ra...
713
  		 size_t count, int blocking, int read_only, int sg_io_owned,
0b07de85a   Adel Gadllah   allow userspace t...
714
  		 Sg_request **o_srp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
715
716
717
718
  {
  	int k;
  	Sg_request *srp;
  	sg_io_hdr_t *hp;
65c26a0f3   Douglas Gilbert   sg: relax 16 byte...
719
  	unsigned char cmnd[SG_MAX_CDB_SIZE];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
720
721
722
723
724
725
726
727
728
729
  	int timeout;
  	unsigned long ul_timeout;
  
  	if (count < SZ_SG_IO_HDR)
  		return -EINVAL;
  	if (!access_ok(VERIFY_READ, buf, count))
  		return -EFAULT; /* protects following copy_from_user()s + get_user()s */
  
  	sfp->cmd_q = 1;	/* when sg_io_hdr seen, set command queuing on */
  	if (!(srp = sg_add_request(sfp))) {
95e159d6d   Hannes Reinecke   scsi: Implement s...
730
731
732
  		SCSI_LOG_TIMEOUT(1, sg_printk(KERN_INFO, sfp->parentdp,
  					      "sg_new_write: queue full
  "));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
733
734
  		return -EDOM;
  	}
a2dd3b4ce   Tony Battersby   [SCSI] sg: fix ra...
735
  	srp->sg_io_owned = sg_io_owned;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
  	hp = &srp->header;
  	if (__copy_from_user(hp, buf, SZ_SG_IO_HDR)) {
  		sg_remove_request(sfp, srp);
  		return -EFAULT;
  	}
  	if (hp->interface_id != 'S') {
  		sg_remove_request(sfp, srp);
  		return -ENOSYS;
  	}
  	if (hp->flags & SG_FLAG_MMAP_IO) {
  		if (hp->dxfer_len > sfp->reserve.bufflen) {
  			sg_remove_request(sfp, srp);
  			return -ENOMEM;	/* MMAP_IO size must fit in reserve buffer */
  		}
  		if (hp->flags & SG_FLAG_DIRECT_IO) {
  			sg_remove_request(sfp, srp);
  			return -EINVAL;	/* either MMAP_IO or DIRECT_IO (not both) */
  		}
1bc0eb044   Hannes Reinecke   scsi: sg: protect...
754
  		if (sfp->res_in_use) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
  			sg_remove_request(sfp, srp);
  			return -EBUSY;	/* reserve buffer already being used */
  		}
  	}
  	ul_timeout = msecs_to_jiffies(srp->header.timeout);
  	timeout = (ul_timeout < INT_MAX) ? ul_timeout : INT_MAX;
  	if ((!hp->cmdp) || (hp->cmd_len < 6) || (hp->cmd_len > sizeof (cmnd))) {
  		sg_remove_request(sfp, srp);
  		return -EMSGSIZE;
  	}
  	if (!access_ok(VERIFY_READ, hp->cmdp, hp->cmd_len)) {
  		sg_remove_request(sfp, srp);
  		return -EFAULT;	/* protects following copy_from_user()s + get_user()s */
  	}
  	if (__copy_from_user(cmnd, hp->cmdp, hp->cmd_len)) {
  		sg_remove_request(sfp, srp);
  		return -EFAULT;
  	}
14e507b85   FUJITA Tomonori   sg: restore comma...
773
  	if (read_only && sg_allow_access(file, cmnd)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
  		sg_remove_request(sfp, srp);
  		return -EPERM;
  	}
  	k = sg_common_write(sfp, srp, cmnd, timeout, blocking);
  	if (k < 0)
  		return k;
  	if (o_srp)
  		*o_srp = srp;
  	return count;
  }
  
  static int
  sg_common_write(Sg_fd * sfp, Sg_request * srp,
  		unsigned char *cmnd, int timeout, int blocking)
  {
5af2e3824   Bart Van Assche   sg: remove an unu...
789
  	int k, at_head;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
790
791
  	Sg_device *sdp = sfp->parentdp;
  	sg_io_hdr_t *hp = &srp->header;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
792
793
794
795
796
797
798
799
800
  
  	srp->data.cmd_opcode = cmnd[0];	/* hold opcode of command */
  	hp->status = 0;
  	hp->masked_status = 0;
  	hp->msg_status = 0;
  	hp->info = 0;
  	hp->host_status = 0;
  	hp->driver_status = 0;
  	hp->resid = 0;
95e159d6d   Hannes Reinecke   scsi: Implement s...
801
802
803
804
  	SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sfp->parentdp,
  			"sg_common_write:  scsi opcode=0x%02x, cmd_size=%d
  ",
  			(int) cmnd[0], (int) hp->cmd_len));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
805

f930c7043   Johannes Thumshirn   scsi: sg: only ch...
806
  	if (hp->dxfer_len >= SZ_256M)
28676d869   Johannes Thumshirn   scsi: sg: check f...
807
  		return -EINVAL;
10865dfa3   FUJITA Tomonori   sg: convert the n...
808
809
  	k = sg_start_req(srp, cmnd);
  	if (k) {
95e159d6d   Hannes Reinecke   scsi: Implement s...
810
811
812
  		SCSI_LOG_TIMEOUT(1, sg_printk(KERN_INFO, sfp->parentdp,
  			"sg_common_write: start_req err=%d
  ", k));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
813
  		sg_finish_rem_req(srp);
97d27b0dd   Hannes Reinecke   scsi: sg: close r...
814
  		sg_remove_request(sfp, srp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
815
816
  		return k;	/* probably out of space --> ENOMEM */
  	}
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
817
  	if (atomic_read(&sdp->detaching)) {
f3951a370   Calvin Owens   sg: Fix double-fr...
818
  		if (srp->bio) {
82ed4db49   Christoph Hellwig   block: split scsi...
819
  			scsi_req_free_cmd(scsi_req(srp->rq));
2a842acab   Christoph Hellwig   block: introduce ...
820
  			blk_end_request_all(srp->rq, BLK_STS_IOERR);
f3951a370   Calvin Owens   sg: Fix double-fr...
821
822
  			srp->rq = NULL;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
823
  		sg_finish_rem_req(srp);
97d27b0dd   Hannes Reinecke   scsi: sg: close r...
824
  		sg_remove_request(sfp, srp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
825
826
  		return -ENODEV;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
827

cb59e8408   Douglas Gilbert   [PATCH] sg.c: update
828
  	hp->duration = jiffies_to_msecs(jiffies);
16070cc18   Douglas Gilbert   sg: add SG_FLAG_Q...
829
830
831
832
833
  	if (hp->interface_id != '\0' &&	/* v3 (or later) interface */
  	    (SG_FLAG_Q_AT_TAIL & hp->flags))
  		at_head = 0;
  	else
  		at_head = 1;
10db10d14   FUJITA Tomonori   sg: convert the i...
834
835
  
  	srp->rq->timeout = timeout;
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
836
  	kref_get(&sfp->f_ref); /* sg_rq_end_io() does kref_put(). */
10db10d14   FUJITA Tomonori   sg: convert the i...
837
  	blk_execute_rq_nowait(sdp->device->request_queue, sdp->disk,
16070cc18   Douglas Gilbert   sg: add SG_FLAG_Q...
838
  			      srp->rq, at_head, sg_rq_end_io);
10db10d14   FUJITA Tomonori   sg: convert the i...
839
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
840
  }
6acddc5e9   Jörn Engel   [SCSI] sg: preven...
841
842
843
844
845
846
847
848
849
850
  static int srp_done(Sg_fd *sfp, Sg_request *srp)
  {
  	unsigned long flags;
  	int ret;
  
  	read_lock_irqsave(&sfp->rq_list_lock, flags);
  	ret = srp->done;
  	read_unlock_irqrestore(&sfp->rq_list_lock, flags);
  	return ret;
  }
46f69e6a6   Akinobu Mita   sg: prevent integ...
851
852
853
854
855
856
857
858
  static int max_sectors_bytes(struct request_queue *q)
  {
  	unsigned int max_sectors = queue_max_sectors(q);
  
  	max_sectors = min_t(unsigned int, max_sectors, INT_MAX >> 9);
  
  	return max_sectors << 9;
  }
4759df905   Hannes Reinecke   scsi: sg: factor ...
859
860
861
862
863
864
865
866
867
  static void
  sg_fill_request_table(Sg_fd *sfp, sg_req_info_t *rinfo)
  {
  	Sg_request *srp;
  	int val;
  	unsigned int ms;
  
  	val = 0;
  	list_for_each_entry(srp, &sfp->rq_list, entry) {
587c3c9f2   Ben Hutchings   scsi: sg: Re-fix ...
868
  		if (val >= SG_MAX_QUEUE)
4759df905   Hannes Reinecke   scsi: sg: factor ...
869
  			break;
4759df905   Hannes Reinecke   scsi: sg: factor ...
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
  		rinfo[val].req_state = srp->done + 1;
  		rinfo[val].problem =
  			srp->header.masked_status &
  			srp->header.host_status &
  			srp->header.driver_status;
  		if (srp->done)
  			rinfo[val].duration =
  				srp->header.duration;
  		else {
  			ms = jiffies_to_msecs(jiffies);
  			rinfo[val].duration =
  				(ms > srp->header.duration) ?
  				(ms - srp->header.duration) : 0;
  		}
  		rinfo[val].orphan = srp->orphan;
  		rinfo[val].sg_io_owned = srp->sg_io_owned;
  		rinfo[val].pack_id = srp->header.pack_id;
  		rinfo[val].usr_ptr = srp->header.usr_ptr;
  		val++;
  	}
  }
37b9d1e00   Jörn Engel   [SCSI] sg: remove...
891
  static long
f4927c45b   Arnd Bergmann   scsi: Push down B...
892
  sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
893
894
895
  {
  	void __user *p = (void __user *)arg;
  	int __user *ip = p;
176aa9d6e   Christoph Hellwig   scsi: refactor sc...
896
  	int result, val, read_only;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
897
898
899
900
901
902
903
  	Sg_device *sdp;
  	Sg_fd *sfp;
  	Sg_request *srp;
  	unsigned long iflags;
  
  	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
  		return -ENXIO;
abf543937   FUJITA Tomonori   block: move cmdfi...
904

95e159d6d   Hannes Reinecke   scsi: Implement s...
905
906
907
  	SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp,
  				   "sg_ioctl: cmd=0x%x
  ", (int) cmd_in));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
908
909
910
911
  	read_only = (O_RDWR != (filp->f_flags & O_ACCMODE));
  
  	switch (cmd_in) {
  	case SG_IO:
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
912
  		if (atomic_read(&sdp->detaching))
dddbf8d90   Jörn Engel   [SCSI] sg: remove...
913
914
915
916
917
918
919
920
921
  			return -ENODEV;
  		if (!scsi_block_when_processing_errors(sdp->device))
  			return -ENXIO;
  		if (!access_ok(VERIFY_WRITE, p, SZ_SG_IO_HDR))
  			return -EFAULT;
  		result = sg_new_write(sfp, filp, p, SZ_SG_IO_HDR,
  				 1, read_only, 1, &srp);
  		if (result < 0)
  			return result;
3f0c6aba0   Jörn Engel   [SCSI] sg: use wa...
922
  		result = wait_event_interruptible(sfp->read_wait,
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
923
924
  			(srp_done(sfp, srp) || atomic_read(&sdp->detaching)));
  		if (atomic_read(&sdp->detaching))
794c10fa0   Jörn Engel   [SCSI] sg: remove...
925
926
927
928
  			return -ENODEV;
  		write_lock_irq(&sfp->rq_list_lock);
  		if (srp->done) {
  			srp->done = 2;
dddbf8d90   Jörn Engel   [SCSI] sg: remove...
929
  			write_unlock_irq(&sfp->rq_list_lock);
794c10fa0   Jörn Engel   [SCSI] sg: remove...
930
931
  			result = sg_new_read(sfp, p, SZ_SG_IO_HDR, srp);
  			return (result < 0) ? result : 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
932
  		}
794c10fa0   Jörn Engel   [SCSI] sg: remove...
933
934
935
  		srp->orphan = 1;
  		write_unlock_irq(&sfp->rq_list_lock);
  		return result;	/* -ERESTARTSYS because signal hit process */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
936
937
938
939
940
941
  	case SG_SET_TIMEOUT:
  		result = get_user(val, ip);
  		if (result)
  			return result;
  		if (val < 0)
  			return -EIO;
f8630bd7e   Paul Burton   scsi: sg: Use mul...
942
943
  		if (val >= mult_frac((s64)INT_MAX, USER_HZ, HZ))
  			val = min_t(s64, mult_frac((s64)INT_MAX, USER_HZ, HZ),
b9b6e80ad   Paul Burton   scsi: sg: Avoid o...
944
  				    INT_MAX);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
945
  		sfp->timeout_user = val;
f8630bd7e   Paul Burton   scsi: sg: Use mul...
946
  		sfp->timeout = mult_frac(val, HZ, USER_HZ);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
947
948
949
950
951
952
  
  		return 0;
  	case SG_GET_TIMEOUT:	/* N.B. User receives timeout as return value */
  				/* strange ..., for backward compatibility */
  		return sfp->timeout_user;
  	case SG_SET_FORCE_LOW_DMA:
745dfa0d8   Hannes Reinecke   scsi: sg: disable...
953
954
955
956
957
  		/*
  		 * N.B. This ioctl never worked properly, but failed to
  		 * return an error value. So returning '0' to keep compability
  		 * with legacy applications.
  		 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
958
959
  		return 0;
  	case SG_GET_LOW_DMA:
745dfa0d8   Hannes Reinecke   scsi: sg: disable...
960
  		return put_user((int) sdp->device->host->unchecked_isa_dma, ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
961
962
963
964
965
  	case SG_GET_SCSI_ID:
  		if (!access_ok(VERIFY_WRITE, p, sizeof (sg_scsi_id_t)))
  			return -EFAULT;
  		else {
  			sg_scsi_id_t __user *sg_idp = p;
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
966
  			if (atomic_read(&sdp->detaching))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
  				return -ENODEV;
  			__put_user((int) sdp->device->host->host_no,
  				   &sg_idp->host_no);
  			__put_user((int) sdp->device->channel,
  				   &sg_idp->channel);
  			__put_user((int) sdp->device->id, &sg_idp->scsi_id);
  			__put_user((int) sdp->device->lun, &sg_idp->lun);
  			__put_user((int) sdp->device->type, &sg_idp->scsi_type);
  			__put_user((short) sdp->device->host->cmd_per_lun,
  				   &sg_idp->h_cmd_per_lun);
  			__put_user((short) sdp->device->queue_depth,
  				   &sg_idp->d_queue_depth);
  			__put_user(0, &sg_idp->unused[0]);
  			__put_user(0, &sg_idp->unused[1]);
  			return 0;
  		}
  	case SG_SET_FORCE_PACK_ID:
  		result = get_user(val, ip);
  		if (result)
  			return result;
  		sfp->force_packid = val ? 1 : 0;
  		return 0;
  	case SG_GET_PACK_ID:
  		if (!access_ok(VERIFY_WRITE, ip, sizeof (int)))
  			return -EFAULT;
  		read_lock_irqsave(&sfp->rq_list_lock, iflags);
109bade9c   Hannes Reinecke   scsi: sg: use sta...
993
  		list_for_each_entry(srp, &sfp->rq_list, entry) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
  			if ((1 == srp->done) && (!srp->sg_io_owned)) {
  				read_unlock_irqrestore(&sfp->rq_list_lock,
  						       iflags);
  				__put_user(srp->header.pack_id, ip);
  				return 0;
  			}
  		}
  		read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
  		__put_user(-1, ip);
  		return 0;
  	case SG_GET_NUM_WAITING:
  		read_lock_irqsave(&sfp->rq_list_lock, iflags);
109bade9c   Hannes Reinecke   scsi: sg: use sta...
1006
1007
  		val = 0;
  		list_for_each_entry(srp, &sfp->rq_list, entry) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
  			if ((1 == srp->done) && (!srp->sg_io_owned))
  				++val;
  		}
  		read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
  		return put_user(val, ip);
  	case SG_GET_SG_TABLESIZE:
  		return put_user(sdp->sg_tablesize, ip);
  	case SG_SET_RESERVED_SIZE:
  		result = get_user(val, ip);
  		if (result)
  			return result;
                  if (val < 0)
                          return -EINVAL;
44ec95425   Alan Stern   [SCSI] sg: cap re...
1021
  		val = min_t(int, val,
46f69e6a6   Akinobu Mita   sg: prevent integ...
1022
  			    max_sectors_bytes(sdp->device->request_queue));
1bc0eb044   Hannes Reinecke   scsi: sg: protect...
1023
  		mutex_lock(&sfp->f_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1024
  		if (val != sfp->reserve.bufflen) {
1bc0eb044   Hannes Reinecke   scsi: sg: protect...
1025
1026
1027
  			if (sfp->mmap_called ||
  			    sfp->res_in_use) {
  				mutex_unlock(&sfp->f_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1028
  				return -EBUSY;
1bc0eb044   Hannes Reinecke   scsi: sg: protect...
1029
  			}
95e159d6d   Hannes Reinecke   scsi: Implement s...
1030
  			sg_remove_scat(sfp, &sfp->reserve);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1031
1032
  			sg_build_reserve(sfp, val);
  		}
1bc0eb044   Hannes Reinecke   scsi: sg: protect...
1033
  		mutex_unlock(&sfp->f_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1034
1035
  		return 0;
  	case SG_GET_RESERVED_SIZE:
44ec95425   Alan Stern   [SCSI] sg: cap re...
1036
  		val = min_t(int, sfp->reserve.bufflen,
46f69e6a6   Akinobu Mita   sg: prevent integ...
1037
  			    max_sectors_bytes(sdp->device->request_queue));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
  		return put_user(val, ip);
  	case SG_SET_COMMAND_Q:
  		result = get_user(val, ip);
  		if (result)
  			return result;
  		sfp->cmd_q = val ? 1 : 0;
  		return 0;
  	case SG_GET_COMMAND_Q:
  		return put_user((int) sfp->cmd_q, ip);
  	case SG_SET_KEEP_ORPHAN:
  		result = get_user(val, ip);
  		if (result)
  			return result;
  		sfp->keep_orphan = val;
  		return 0;
  	case SG_GET_KEEP_ORPHAN:
  		return put_user((int) sfp->keep_orphan, ip);
  	case SG_NEXT_CMD_LEN:
  		result = get_user(val, ip);
  		if (result)
  			return result;
bf33f87dd   peter chang   scsi: sg: check l...
1059
1060
  		if (val > SG_MAX_CDB_SIZE)
  			return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
  		sfp->next_cmd_len = (val > 0) ? val : 0;
  		return 0;
  	case SG_GET_VERSION_NUM:
  		return put_user(sg_version_num, ip);
  	case SG_GET_ACCESS_COUNT:
  		/* faked - we don't have a real access count anymore */
  		val = (sdp->device ? 1 : 0);
  		return put_user(val, ip);
  	case SG_GET_REQUEST_TABLE:
  		if (!access_ok(VERIFY_WRITE, p, SZ_SG_REQ_INFO * SG_MAX_QUEUE))
  			return -EFAULT;
  		else {
cb59e8408   Douglas Gilbert   [PATCH] sg.c: update
1073
  			sg_req_info_t *rinfo;
cb59e8408   Douglas Gilbert   [PATCH] sg.c: update
1074

3e0097499   Hannes Reinecke   scsi: sg: fixup i...
1075
1076
  			rinfo = kzalloc(SZ_SG_REQ_INFO * SG_MAX_QUEUE,
  					GFP_KERNEL);
cb59e8408   Douglas Gilbert   [PATCH] sg.c: update
1077
1078
  			if (!rinfo)
  				return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1079
  			read_lock_irqsave(&sfp->rq_list_lock, iflags);
4759df905   Hannes Reinecke   scsi: sg: factor ...
1080
  			sg_fill_request_table(sfp, rinfo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1081
  			read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
109bade9c   Hannes Reinecke   scsi: sg: use sta...
1082
  			result = __copy_to_user(p, rinfo,
cb59e8408   Douglas Gilbert   [PATCH] sg.c: update
1083
1084
1085
1086
  						SZ_SG_REQ_INFO * SG_MAX_QUEUE);
  			result = result ? -EFAULT : 0;
  			kfree(rinfo);
  			return result;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1087
1088
  		}
  	case SG_EMULATED_HOST:
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
1089
  		if (atomic_read(&sdp->detaching))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1090
1091
  			return -ENODEV;
  		return put_user(sdp->device->host->hostt->emulated, ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1092
  	case SCSI_IOCTL_SEND_COMMAND:
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
1093
  		if (atomic_read(&sdp->detaching))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1094
1095
1096
1097
1098
1099
1100
  			return -ENODEV;
  		if (read_only) {
  			unsigned char opcode = WRITE_6;
  			Scsi_Ioctl_Command __user *siocp = p;
  
  			if (copy_from_user(&opcode, siocp->data, 1))
  				return -EFAULT;
14e507b85   FUJITA Tomonori   sg: restore comma...
1101
  			if (sg_allow_access(filp, &opcode))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1102
1103
  				return -EPERM;
  		}
e915e872e   Al Viro   [PATCH] switch sg...
1104
  		return sg_scsi_ioctl(sdp->device->request_queue, NULL, filp->f_mode, p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1105
1106
1107
1108
1109
1110
  	case SG_SET_DEBUG:
  		result = get_user(val, ip);
  		if (result)
  			return result;
  		sdp->sgdebug = (char) val;
  		return 0;
44ec95425   Alan Stern   [SCSI] sg: cap re...
1111
  	case BLKSECTGET:
46f69e6a6   Akinobu Mita   sg: prevent integ...
1112
  		return put_user(max_sectors_bytes(sdp->device->request_queue),
44ec95425   Alan Stern   [SCSI] sg: cap re...
1113
  				ip);
6da127ad0   Christof Schmitt   blktrace: Add blk...
1114
1115
1116
  	case BLKTRACESETUP:
  		return blk_trace_setup(sdp->device->request_queue,
  				       sdp->disk->disk_name,
76e3a19d0   Martin Peschke   [SCSI] sg: fix de...
1117
  				       MKDEV(SCSI_GENERIC_MAJOR, sdp->index),
7475c8ae1   Bart Van Assche   scsi: sg: Fix typ...
1118
  				       NULL, p);
6da127ad0   Christof Schmitt   blktrace: Add blk...
1119
1120
1121
1122
1123
1124
  	case BLKTRACESTART:
  		return blk_trace_startstop(sdp->device->request_queue, 1);
  	case BLKTRACESTOP:
  		return blk_trace_startstop(sdp->device->request_queue, 0);
  	case BLKTRACETEARDOWN:
  		return blk_trace_remove(sdp->device->request_queue);
906d15fbd   Christoph Hellwig   scsi: split scsi_...
1125
1126
1127
1128
1129
1130
1131
1132
  	case SCSI_IOCTL_GET_IDLUN:
  	case SCSI_IOCTL_GET_BUS_NUMBER:
  	case SCSI_IOCTL_PROBE_HOST:
  	case SG_GET_TRANSFORM:
  	case SG_SCSI_RESET:
  		if (atomic_read(&sdp->detaching))
  			return -ENODEV;
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1133
1134
1135
  	default:
  		if (read_only)
  			return -EPERM;	/* don't know so take safe approach */
906d15fbd   Christoph Hellwig   scsi: split scsi_...
1136
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1137
  	}
906d15fbd   Christoph Hellwig   scsi: split scsi_...
1138
1139
1140
1141
1142
1143
  
  	result = scsi_ioctl_block_when_processing_errors(sdp->device,
  			cmd_in, filp->f_flags & O_NDELAY);
  	if (result)
  		return result;
  	return scsi_ioctl(sdp->device, cmd_in, p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
  }
  
  #ifdef CONFIG_COMPAT
  static long sg_compat_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
  {
  	Sg_device *sdp;
  	Sg_fd *sfp;
  	struct scsi_device *sdev;
  
  	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
  		return -ENXIO;
  
  	sdev = sdp->device;
  	if (sdev->host->hostt->compat_ioctl) { 
  		int ret;
  
  		ret = sdev->host->hostt->compat_ioctl(sdev, cmd_in, (void __user *)arg);
  
  		return ret;
  	}
  	
  	return -ENOIOCTLCMD;
  }
  #endif
  
  static unsigned int
  sg_poll(struct file *filp, poll_table * wait)
  {
  	unsigned int res = 0;
  	Sg_device *sdp;
  	Sg_fd *sfp;
  	Sg_request *srp;
  	int count = 0;
  	unsigned long iflags;
ebaf466be   Jörn Engel   [SCSI] sg: remove...
1178
1179
1180
1181
1182
  	sfp = filp->private_data;
  	if (!sfp)
  		return POLLERR;
  	sdp = sfp->parentdp;
  	if (!sdp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1183
1184
1185
  		return POLLERR;
  	poll_wait(filp, &sfp->read_wait, wait);
  	read_lock_irqsave(&sfp->rq_list_lock, iflags);
109bade9c   Hannes Reinecke   scsi: sg: use sta...
1186
  	list_for_each_entry(srp, &sfp->rq_list, entry) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1187
1188
1189
1190
1191
1192
  		/* if any read waiting, flag it */
  		if ((0 == res) && (1 == srp->done) && (!srp->sg_io_owned))
  			res = POLLIN | POLLRDNORM;
  		++count;
  	}
  	read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
1193
  	if (atomic_read(&sdp->detaching))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1194
1195
1196
1197
1198
1199
  		res |= POLLHUP;
  	else if (!sfp->cmd_q) {
  		if (0 == count)
  			res |= POLLOUT | POLLWRNORM;
  	} else if (count < SG_MAX_QUEUE)
  		res |= POLLOUT | POLLWRNORM;
95e159d6d   Hannes Reinecke   scsi: Implement s...
1200
1201
1202
  	SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp,
  				      "sg_poll: res=0x%x
  ", (int) res));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1203
1204
1205
1206
1207
1208
  	return res;
  }
  
  static int
  sg_fasync(int fd, struct file *filp, int mode)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1209
1210
1211
1212
1213
  	Sg_device *sdp;
  	Sg_fd *sfp;
  
  	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
  		return -ENXIO;
95e159d6d   Hannes Reinecke   scsi: Implement s...
1214
1215
1216
  	SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp,
  				      "sg_fasync: mode=%d
  ", mode));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1217

60aa49243   Jonathan Corbet   Rationalize fasyn...
1218
  	return fasync_helper(fd, filp, mode, &sfp->async_qp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1219
  }
a13ff0bb3   Nick Piggin   Convert SG from n...
1220
  static int
11bac8000   Dave Jiang   mm, fs: reduce fa...
1221
  sg_vma_fault(struct vm_fault *vmf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1222
  {
11bac8000   Dave Jiang   mm, fs: reduce fa...
1223
  	struct vm_area_struct *vma = vmf->vma;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1224
  	Sg_fd *sfp;
d6b10348f   Mike Christie   [SCSI] convert sg...
1225
  	unsigned long offset, len, sa;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1226
  	Sg_scatter_hold *rsv_schp;
10db10d14   FUJITA Tomonori   sg: convert the i...
1227
  	int k, length;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1228
1229
  
  	if ((NULL == vma) || (!(sfp = (Sg_fd *) vma->vm_private_data)))
a13ff0bb3   Nick Piggin   Convert SG from n...
1230
  		return VM_FAULT_SIGBUS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1231
  	rsv_schp = &sfp->reserve;
a13ff0bb3   Nick Piggin   Convert SG from n...
1232
  	offset = vmf->pgoff << PAGE_SHIFT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1233
  	if (offset >= rsv_schp->bufflen)
a13ff0bb3   Nick Piggin   Convert SG from n...
1234
  		return VM_FAULT_SIGBUS;
95e159d6d   Hannes Reinecke   scsi: Implement s...
1235
1236
1237
1238
  	SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sfp->parentdp,
  				      "sg_vma_fault: offset=%lu, scatg=%d
  ",
  				      offset, rsv_schp->k_use_sg));
d6b10348f   Mike Christie   [SCSI] convert sg...
1239
  	sa = vma->vm_start;
10db10d14   FUJITA Tomonori   sg: convert the i...
1240
1241
  	length = 1 << (PAGE_SHIFT + rsv_schp->page_order);
  	for (k = 0; k < rsv_schp->k_use_sg && sa < vma->vm_end; k++) {
d6b10348f   Mike Christie   [SCSI] convert sg...
1242
  		len = vma->vm_end - sa;
10db10d14   FUJITA Tomonori   sg: convert the i...
1243
  		len = (len < length) ? len : length;
d6b10348f   Mike Christie   [SCSI] convert sg...
1244
  		if (offset < len) {
10db10d14   FUJITA Tomonori   sg: convert the i...
1245
1246
  			struct page *page = nth_page(rsv_schp->pages[k],
  						     offset >> PAGE_SHIFT);
d6b10348f   Mike Christie   [SCSI] convert sg...
1247
  			get_page(page);	/* increment page count */
a13ff0bb3   Nick Piggin   Convert SG from n...
1248
1249
  			vmf->page = page;
  			return 0; /* success */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1250
  		}
d6b10348f   Mike Christie   [SCSI] convert sg...
1251
1252
  		sa += len;
  		offset -= len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1253
  	}
d6b10348f   Mike Christie   [SCSI] convert sg...
1254

a13ff0bb3   Nick Piggin   Convert SG from n...
1255
  	return VM_FAULT_SIGBUS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1256
  }
f0f37e2f7   Alexey Dobriyan   const: mark struc...
1257
  static const struct vm_operations_struct sg_mmap_vm_ops = {
a13ff0bb3   Nick Piggin   Convert SG from n...
1258
  	.fault = sg_vma_fault,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1259
1260
1261
1262
1263
1264
  };
  
  static int
  sg_mmap(struct file *filp, struct vm_area_struct *vma)
  {
  	Sg_fd *sfp;
d6b10348f   Mike Christie   [SCSI] convert sg...
1265
  	unsigned long req_sz, len, sa;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1266
  	Sg_scatter_hold *rsv_schp;
10db10d14   FUJITA Tomonori   sg: convert the i...
1267
  	int k, length;
6a8dadcca   Todd Poynor   scsi: sg: protect...
1268
  	int ret = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1269
1270
1271
  
  	if ((!filp) || (!vma) || (!(sfp = (Sg_fd *) filp->private_data)))
  		return -ENXIO;
cb59e8408   Douglas Gilbert   [PATCH] sg.c: update
1272
  	req_sz = vma->vm_end - vma->vm_start;
95e159d6d   Hannes Reinecke   scsi: Implement s...
1273
1274
1275
1276
  	SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sfp->parentdp,
  				      "sg_mmap starting, vm_start=%p, len=%d
  ",
  				      (void *) vma->vm_start, (int) req_sz));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1277
1278
1279
  	if (vma->vm_pgoff)
  		return -EINVAL;	/* want no offset */
  	rsv_schp = &sfp->reserve;
6a8dadcca   Todd Poynor   scsi: sg: protect...
1280
1281
1282
1283
1284
  	mutex_lock(&sfp->f_mutex);
  	if (req_sz > rsv_schp->bufflen) {
  		ret = -ENOMEM;	/* cannot map more than reserved buffer */
  		goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1285

d6b10348f   Mike Christie   [SCSI] convert sg...
1286
  	sa = vma->vm_start;
10db10d14   FUJITA Tomonori   sg: convert the i...
1287
1288
  	length = 1 << (PAGE_SHIFT + rsv_schp->page_order);
  	for (k = 0; k < rsv_schp->k_use_sg && sa < vma->vm_end; k++) {
d6b10348f   Mike Christie   [SCSI] convert sg...
1289
  		len = vma->vm_end - sa;
10db10d14   FUJITA Tomonori   sg: convert the i...
1290
  		len = (len < length) ? len : length;
d6b10348f   Mike Christie   [SCSI] convert sg...
1291
  		sa += len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1292
  	}
d6b10348f   Mike Christie   [SCSI] convert sg...
1293

f9aed0e25   Nick Piggin   [PATCH] sg: use c...
1294
  	sfp->mmap_called = 1;
461c7fa12   Kirill A. Shutemov   drivers/scsi/sg.c...
1295
  	vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1296
1297
  	vma->vm_private_data = sfp;
  	vma->vm_ops = &sg_mmap_vm_ops;
6a8dadcca   Todd Poynor   scsi: sg: protect...
1298
1299
1300
  out:
  	mutex_unlock(&sfp->f_mutex);
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1301
  }
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
1302
1303
  static void
  sg_rq_end_io_usercontext(struct work_struct *work)
c96952ed7   FUJITA Tomonori   [SCSI] sg: avoid ...
1304
1305
1306
1307
1308
  {
  	struct sg_request *srp = container_of(work, struct sg_request, ew.work);
  	struct sg_fd *sfp = srp->parentfp;
  
  	sg_finish_rem_req(srp);
97d27b0dd   Hannes Reinecke   scsi: sg: close r...
1309
  	sg_remove_request(sfp, srp);
c96952ed7   FUJITA Tomonori   [SCSI] sg: avoid ...
1310
1311
  	kref_put(&sfp->f_ref, sg_remove_sfp);
  }
a91a3a20e   FUJITA Tomonori   sg: rename sg_cmd...
1312
1313
1314
1315
  /*
   * This function is a "bottom half" handler that is called by the mid
   * level when a command is completed (or has failed).
   */
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
1316
  static void
2a842acab   Christoph Hellwig   block: introduce ...
1317
  sg_rq_end_io(struct request *rq, blk_status_t status)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1318
  {
a91a3a20e   FUJITA Tomonori   sg: rename sg_cmd...
1319
  	struct sg_request *srp = rq->end_io_data;
82ed4db49   Christoph Hellwig   block: split scsi...
1320
  	struct scsi_request *req = scsi_req(rq);
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
1321
  	Sg_device *sdp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1322
  	Sg_fd *sfp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1323
  	unsigned long iflags;
cb59e8408   Douglas Gilbert   [PATCH] sg.c: update
1324
  	unsigned int ms;
a91a3a20e   FUJITA Tomonori   sg: rename sg_cmd...
1325
  	char *sense;
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
1326
  	int result, resid, done = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1327

c6517b794   Tony Battersby   [SCSI] sg: fix ra...
1328
  	if (WARN_ON(srp->done != 0))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1329
  		return;
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
1330

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1331
  	sfp = srp->parentfp;
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
1332
  	if (WARN_ON(sfp == NULL))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1333
  		return;
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
1334
1335
  
  	sdp = sfp->parentdp;
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
1336
1337
1338
  	if (unlikely(atomic_read(&sdp->detaching)))
  		pr_info("%s: device detaching
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1339

82ed4db49   Christoph Hellwig   block: split scsi...
1340
  	sense = req->sense;
17d5363b8   Christoph Hellwig   scsi: introduce a...
1341
  	result = req->result;
82ed4db49   Christoph Hellwig   block: split scsi...
1342
  	resid = req->resid_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1343

95e159d6d   Hannes Reinecke   scsi: Implement s...
1344
1345
1346
1347
  	SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sdp,
  				      "sg_cmd_done: pack_id=%d, res=0x%x
  ",
  				      srp->header.pack_id, result));
d6b10348f   Mike Christie   [SCSI] convert sg...
1348
  	srp->header.resid = resid;
cb59e8408   Douglas Gilbert   [PATCH] sg.c: update
1349
1350
1351
  	ms = jiffies_to_msecs(jiffies);
  	srp->header.duration = (ms > srp->header.duration) ?
  				(ms - srp->header.duration) : 0;
d6b10348f   Mike Christie   [SCSI] convert sg...
1352
  	if (0 != result) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1353
  		struct scsi_sense_hdr sshdr;
d6b10348f   Mike Christie   [SCSI] convert sg...
1354
1355
1356
1357
1358
  		srp->header.status = 0xff & result;
  		srp->header.masked_status = status_byte(result);
  		srp->header.msg_status = msg_byte(result);
  		srp->header.host_status = host_byte(result);
  		srp->header.driver_status = driver_byte(result);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1359
1360
1361
  		if ((sdp->sgdebug > 0) &&
  		    ((CHECK_CONDITION == srp->header.masked_status) ||
  		     (COMMAND_TERMINATED == srp->header.masked_status)))
d811b848e   Hannes Reinecke   scsi: use sdev as...
1362
  			__scsi_print_sense(sdp->device, __func__, sense,
d6b10348f   Mike Christie   [SCSI] convert sg...
1363
  					   SCSI_SENSE_BUFFERSIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1364
1365
  
  		/* Following if statement is a patch supplied by Eric Youngdale */
d6b10348f   Mike Christie   [SCSI] convert sg...
1366
1367
  		if (driver_byte(result) != 0
  		    && scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1368
1369
1370
1371
1372
1373
1374
1375
  		    && !scsi_sense_is_deferred(&sshdr)
  		    && sshdr.sense_key == UNIT_ATTENTION
  		    && sdp->device->removable) {
  			/* Detected possible disc change. Set the bit - this */
  			/* may be used if there are filesystems using this device */
  			sdp->device->changed = 1;
  		}
  	}
82ed4db49   Christoph Hellwig   block: split scsi...
1376
1377
1378
  
  	if (req->sense_len)
  		memcpy(srp->sense_b, req->sense, SCSI_SENSE_BUFFERSIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1379
  	/* Rely on write phase to clean out srp status values, so no "else" */
7568615c1   Tony Battersby   sg: fix unkillabl...
1380
1381
1382
1383
1384
1385
1386
  	/*
  	 * Free the request as soon as it is complete so that its resources
  	 * can be reused without waiting for userspace to read() the
  	 * result.  But keep the associated bio (if any) around until
  	 * blk_rq_unmap_user() can be called from user context.
  	 */
  	srp->rq = NULL;
82ed4db49   Christoph Hellwig   block: split scsi...
1387
  	scsi_req_free_cmd(scsi_req(rq));
7568615c1   Tony Battersby   sg: fix unkillabl...
1388
  	__blk_put_request(rq->q, rq);
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
1389
1390
  	write_lock_irqsave(&sfp->rq_list_lock, iflags);
  	if (unlikely(srp->orphan)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1391
1392
  		if (sfp->keep_orphan)
  			srp->sg_io_owned = 0;
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
1393
1394
  		else
  			done = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1395
  	}
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
1396
1397
1398
1399
1400
1401
1402
  	srp->done = done;
  	write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
  
  	if (likely(done)) {
  		/* Now wake up any sg_read() that is waiting for this
  		 * packet.
  		 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1403
  		wake_up_interruptible(&sfp->read_wait);
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
1404
  		kill_fasync(&sfp->async_qp, SIGPOLL, POLL_IN);
c96952ed7   FUJITA Tomonori   [SCSI] sg: avoid ...
1405
  		kref_put(&sfp->f_ref, sg_remove_sfp);
015640edb   FUJITA Tomonori   [SCSI] sg: fix q-...
1406
1407
1408
1409
  	} else {
  		INIT_WORK(&srp->ew.work, sg_rq_end_io_usercontext);
  		schedule_work(&srp->ew.work);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1410
  }
828c09509   Alexey Dobriyan   const: constify r...
1411
  static const struct file_operations sg_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1412
1413
1414
1415
  	.owner = THIS_MODULE,
  	.read = sg_read,
  	.write = sg_write,
  	.poll = sg_poll,
37b9d1e00   Jörn Engel   [SCSI] sg: remove...
1416
  	.unlocked_ioctl = sg_ioctl,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1417
1418
1419
1420
1421
1422
1423
  #ifdef CONFIG_COMPAT
  	.compat_ioctl = sg_compat_ioctl,
  #endif
  	.open = sg_open,
  	.mmap = sg_mmap,
  	.release = sg_release,
  	.fasync = sg_fasync,
6038f373a   Arnd Bergmann   llseek: automatic...
1424
  	.llseek = no_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1425
  };
d253878b3   Greg Kroah-Hartman   [PATCH] class: co...
1426
  static struct class *sg_sysfs_class;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1427
1428
  
  static int sg_sysfs_valid = 0;
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
1429
1430
  static Sg_device *
  sg_alloc(struct gendisk *disk, struct scsi_device *scsidp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1431
  {
d6b10348f   Mike Christie   [SCSI] convert sg...
1432
  	struct request_queue *q = scsidp->request_queue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1433
1434
  	Sg_device *sdp;
  	unsigned long iflags;
7c07d613d   James Bottomley   [SCSI] sg: use id...
1435
1436
  	int error;
  	u32 k;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1437

24669f75a   Jes Sorensen   [SCSI] SCSI core ...
1438
  	sdp = kzalloc(sizeof(Sg_device), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1439
  	if (!sdp) {
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
1440
1441
1442
  		sdev_printk(KERN_WARNING, scsidp, "%s: kmalloc Sg_device "
  			    "failure
  ", __func__);
7c07d613d   James Bottomley   [SCSI] sg: use id...
1443
1444
  		return ERR_PTR(-ENOMEM);
  	}
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
1445

b98c52b57   Tejun Heo   scsi: convert to ...
1446
  	idr_preload(GFP_KERNEL);
7c07d613d   James Bottomley   [SCSI] sg: use id...
1447
  	write_lock_irqsave(&sg_index_lock, iflags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1448

b98c52b57   Tejun Heo   scsi: convert to ...
1449
1450
1451
1452
1453
1454
1455
1456
1457
  	error = idr_alloc(&sg_index_idr, sdp, 0, SG_MAX_DEVS, GFP_NOWAIT);
  	if (error < 0) {
  		if (error == -ENOSPC) {
  			sdev_printk(KERN_WARNING, scsidp,
  				    "Unable to attach sg device type=%d, minor number exceeds %d
  ",
  				    scsidp->type, SG_MAX_DEVS - 1);
  			error = -ENODEV;
  		} else {
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
1458
1459
1460
1461
  			sdev_printk(KERN_WARNING, scsidp, "%s: idr "
  				    "allocation Sg_device failure: %d
  ",
  				    __func__, error);
b98c52b57   Tejun Heo   scsi: convert to ...
1462
1463
  		}
  		goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1464
  	}
b98c52b57   Tejun Heo   scsi: convert to ...
1465
  	k = error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1466

95e159d6d   Hannes Reinecke   scsi: Implement s...
1467
1468
1469
  	SCSI_LOG_TIMEOUT(3, sdev_printk(KERN_INFO, scsidp,
  					"sg_alloc: dev=%d 
  ", k));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1470
1471
1472
1473
  	sprintf(disk->disk_name, "sg%d", k);
  	disk->first_minor = k;
  	sdp->disk = disk;
  	sdp->device = scsidp;
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
1474
  	mutex_init(&sdp->open_rel_lock);
3442f802a   FUJITA Tomonori   [SCSI] sg: remove...
1475
  	INIT_LIST_HEAD(&sdp->sfds);
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
1476
1477
1478
  	init_waitqueue_head(&sdp->open_wait);
  	atomic_set(&sdp->detaching, 0);
  	rwlock_init(&sdp->sfd_lock);
8a78362c4   Martin K. Petersen   block: Consolidat...
1479
  	sdp->sg_tablesize = queue_max_segments(q);
7c07d613d   James Bottomley   [SCSI] sg: use id...
1480
  	sdp->index = k;
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
1481
  	kref_init(&sdp->d_ref);
b98c52b57   Tejun Heo   scsi: convert to ...
1482
  	error = 0;
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
1483

b98c52b57   Tejun Heo   scsi: convert to ...
1484
  out_unlock:
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
1485
  	write_unlock_irqrestore(&sg_index_lock, iflags);
b98c52b57   Tejun Heo   scsi: convert to ...
1486
  	idr_preload_end();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1487

7c07d613d   James Bottomley   [SCSI] sg: use id...
1488
  	if (error) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1489
  		kfree(sdp);
7c07d613d   James Bottomley   [SCSI] sg: use id...
1490
1491
1492
  		return ERR_PTR(error);
  	}
  	return sdp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1493
1494
1495
  }
  
  static int
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
1496
  sg_add_device(struct device *cl_dev, struct class_interface *cl_intf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1497
  {
ee959b00c   Tony Jones   SCSI: convert str...
1498
  	struct scsi_device *scsidp = to_scsi_device(cl_dev->parent);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1499
1500
1501
  	struct gendisk *disk;
  	Sg_device *sdp = NULL;
  	struct cdev * cdev = NULL;
7c07d613d   James Bottomley   [SCSI] sg: use id...
1502
  	int error;
454e8957e   Ishai Rabinovitz   [SCSI] sg.c: Fix ...
1503
  	unsigned long iflags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1504
1505
1506
  
  	disk = alloc_disk(1);
  	if (!disk) {
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
1507
1508
  		pr_warn("%s: alloc_disk failed
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1509
1510
1511
1512
1513
1514
1515
  		return -ENOMEM;
  	}
  	disk->major = SCSI_GENERIC_MAJOR;
  
  	error = -ENOMEM;
  	cdev = cdev_alloc();
  	if (!cdev) {
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
1516
1517
  		pr_warn("%s: cdev_alloc failed
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1518
1519
1520
1521
  		goto out;
  	}
  	cdev->owner = THIS_MODULE;
  	cdev->ops = &sg_fops;
7c07d613d   James Bottomley   [SCSI] sg: use id...
1522
1523
  	sdp = sg_alloc(disk, scsidp);
  	if (IS_ERR(sdp)) {
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
1524
1525
  		pr_warn("%s: sg_alloc failed
  ", __func__);
7c07d613d   James Bottomley   [SCSI] sg: use id...
1526
  		error = PTR_ERR(sdp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1527
1528
  		goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1529

7c07d613d   James Bottomley   [SCSI] sg: use id...
1530
  	error = cdev_add(cdev, MKDEV(SCSI_GENERIC_MAJOR, sdp->index), 1);
5e3c34c1e   Greg Kroah-Hartman   [SCSI] Remove dev...
1531
  	if (error)
454e8957e   Ishai Rabinovitz   [SCSI] sg.c: Fix ...
1532
  		goto cdev_add_err;
5e3c34c1e   Greg Kroah-Hartman   [SCSI] Remove dev...
1533

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1534
1535
  	sdp->cdev = cdev;
  	if (sg_sysfs_valid) {
ee959b00c   Tony Jones   SCSI: convert str...
1536
  		struct device *sg_class_member;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1537

d73a1a674   Greg Kroah-Hartman   device create: sc...
1538
1539
1540
1541
  		sg_class_member = device_create(sg_sysfs_class, cl_dev->parent,
  						MKDEV(SCSI_GENERIC_MAJOR,
  						      sdp->index),
  						sdp, "%s", disk->disk_name);
d07e03610   FUJITA Tomonori   [SCSI] sg: handle...
1542
  		if (IS_ERR(sg_class_member)) {
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
1543
1544
  			pr_err("%s: device_create failed
  ", __func__);
d07e03610   FUJITA Tomonori   [SCSI] sg: handle...
1545
1546
1547
  			error = PTR_ERR(sg_class_member);
  			goto cdev_add_err;
  		}
d07e03610   FUJITA Tomonori   [SCSI] sg: handle...
1548
  		error = sysfs_create_link(&scsidp->sdev_gendev.kobj,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1549
1550
  					  &sg_class_member->kobj, "generic");
  		if (error)
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
1551
1552
1553
  			pr_err("%s: unable to make symlink 'generic' back "
  			       "to sg%d
  ", __func__, sdp->index);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1554
  	} else
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
1555
1556
  		pr_warn("%s: sg_sys Invalid
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1557

cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
1558
1559
1560
  	sdev_printk(KERN_NOTICE, scsidp, "Attached scsi generic sg%d "
  		    "type %d
  ", sdp->index, scsidp->type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1561

ee959b00c   Tony Jones   SCSI: convert str...
1562
  	dev_set_drvdata(cl_dev, sdp);
a24484f28   FUJITA Tomonori   [SCSI] sg: set cl...
1563

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1564
  	return 0;
454e8957e   Ishai Rabinovitz   [SCSI] sg.c: Fix ...
1565
  cdev_add_err:
7c07d613d   James Bottomley   [SCSI] sg: use id...
1566
1567
1568
1569
  	write_lock_irqsave(&sg_index_lock, iflags);
  	idr_remove(&sg_index_idr, sdp->index);
  	write_unlock_irqrestore(&sg_index_lock, iflags);
  	kfree(sdp);
454e8957e   Ishai Rabinovitz   [SCSI] sg.c: Fix ...
1570

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1571
1572
1573
1574
1575
1576
  out:
  	put_disk(disk);
  	if (cdev)
  		cdev_del(cdev);
  	return error;
  }
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
1577
1578
  static void
  sg_device_destroy(struct kref *kref)
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
  {
  	struct sg_device *sdp = container_of(kref, struct sg_device, d_ref);
  	unsigned long flags;
  
  	/* CAUTION!  Note that the device can still be found via idr_find()
  	 * even though the refcount is 0.  Therefore, do idr_remove() BEFORE
  	 * any other cleanup.
  	 */
  
  	write_lock_irqsave(&sg_index_lock, flags);
  	idr_remove(&sg_index_idr, sdp->index);
  	write_unlock_irqrestore(&sg_index_lock, flags);
  
  	SCSI_LOG_TIMEOUT(3,
95e159d6d   Hannes Reinecke   scsi: Implement s...
1593
1594
  		sg_printk(KERN_INFO, sdp, "sg_device_destroy
  "));
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
1595
1596
1597
1598
  
  	put_disk(sdp->disk);
  	kfree(sdp);
  }
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
1599
1600
  static void
  sg_remove_device(struct device *cl_dev, struct class_interface *cl_intf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1601
  {
ee959b00c   Tony Jones   SCSI: convert str...
1602
1603
  	struct scsi_device *scsidp = to_scsi_device(cl_dev->parent);
  	Sg_device *sdp = dev_get_drvdata(cl_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1604
1605
  	unsigned long iflags;
  	Sg_fd *sfp;
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
1606
  	int val;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1607

cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
1608
  	if (!sdp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1609
  		return;
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
1610
1611
1612
1613
  	/* want sdp->detaching non-zero as soon as possible */
  	val = atomic_inc_return(&sdp->detaching);
  	if (val > 1)
  		return; /* only want to do following once per device */
7c07d613d   James Bottomley   [SCSI] sg: use id...
1614

95e159d6d   Hannes Reinecke   scsi: Implement s...
1615
1616
1617
  	SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp,
  				      "%s
  ", __func__));
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
1618

cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
1619
  	read_lock_irqsave(&sdp->sfd_lock, iflags);
3442f802a   FUJITA Tomonori   [SCSI] sg: remove...
1620
  	list_for_each_entry(sfp, &sdp->sfds, sfd_siblings) {
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
1621
  		wake_up_interruptible_all(&sfp->read_wait);
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
1622
  		kill_fasync(&sfp->async_qp, SIGPOLL, POLL_HUP);
7c07d613d   James Bottomley   [SCSI] sg: use id...
1623
  	}
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
1624
1625
  	wake_up_interruptible_all(&sdp->open_wait);
  	read_unlock_irqrestore(&sdp->sfd_lock, iflags);
7c07d613d   James Bottomley   [SCSI] sg: use id...
1626
1627
  
  	sysfs_remove_link(&scsidp->sdev_gendev.kobj, "generic");
ee959b00c   Tony Jones   SCSI: convert str...
1628
  	device_destroy(sg_sysfs_class, MKDEV(SCSI_GENERIC_MAJOR, sdp->index));
7c07d613d   James Bottomley   [SCSI] sg: use id...
1629
1630
  	cdev_del(sdp->cdev);
  	sdp->cdev = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1631

cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
1632
  	kref_put(&sdp->d_ref, sg_device_destroy);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1633
  }
6460e75a1   Douglas Gilbert   [SCSI] sg: fixes ...
1634
1635
1636
  module_param_named(scatter_elem_sz, scatter_elem_sz, int, S_IRUGO | S_IWUSR);
  module_param_named(def_reserved_size, def_reserved_size, int,
  		   S_IRUGO | S_IWUSR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1637
1638
1639
1640
1641
1642
  module_param_named(allow_dio, sg_allow_dio, int, S_IRUGO | S_IWUSR);
  
  MODULE_AUTHOR("Douglas Gilbert");
  MODULE_DESCRIPTION("SCSI generic (sg) driver");
  MODULE_LICENSE("GPL");
  MODULE_VERSION(SG_VERSION_STR);
f018fa552   Rene Herman   [SCSI] MODULE_ALI...
1643
  MODULE_ALIAS_CHARDEV_MAJOR(SCSI_GENERIC_MAJOR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1644

6460e75a1   Douglas Gilbert   [SCSI] sg: fixes ...
1645
1646
  MODULE_PARM_DESC(scatter_elem_sz, "scatter gather element "
                  "size (default: max(SG_SCATTER_SZ, PAGE_SIZE))");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1647
1648
1649
1650
1651
1652
1653
  MODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd");
  MODULE_PARM_DESC(allow_dio, "allow direct I/O (default: 0 (disallow))");
  
  static int __init
  init_sg(void)
  {
  	int rc;
6460e75a1   Douglas Gilbert   [SCSI] sg: fixes ...
1654
1655
1656
1657
  	if (scatter_elem_sz < PAGE_SIZE) {
  		scatter_elem_sz = PAGE_SIZE;
  		scatter_elem_sz_prev = scatter_elem_sz;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1658
1659
  	if (def_reserved_size >= 0)
  		sg_big_buff = def_reserved_size;
6460e75a1   Douglas Gilbert   [SCSI] sg: fixes ...
1660
1661
  	else
  		def_reserved_size = sg_big_buff;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1662
1663
1664
1665
1666
  
  	rc = register_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0), 
  				    SG_MAX_DEVS, "sg");
  	if (rc)
  		return rc;
d253878b3   Greg Kroah-Hartman   [PATCH] class: co...
1667
          sg_sysfs_class = class_create(THIS_MODULE, "scsi_generic");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
          if ( IS_ERR(sg_sysfs_class) ) {
  		rc = PTR_ERR(sg_sysfs_class);
  		goto err_out;
          }
  	sg_sysfs_valid = 1;
  	rc = scsi_register_interface(&sg_interface);
  	if (0 == rc) {
  #ifdef CONFIG_SCSI_PROC_FS
  		sg_proc_init();
  #endif				/* CONFIG_SCSI_PROC_FS */
  		return 0;
  	}
d253878b3   Greg Kroah-Hartman   [PATCH] class: co...
1680
  	class_destroy(sg_sysfs_class);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
  err_out:
  	unregister_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0), SG_MAX_DEVS);
  	return rc;
  }
  
  static void __exit
  exit_sg(void)
  {
  #ifdef CONFIG_SCSI_PROC_FS
  	sg_proc_cleanup();
  #endif				/* CONFIG_SCSI_PROC_FS */
  	scsi_unregister_interface(&sg_interface);
d253878b3   Greg Kroah-Hartman   [PATCH] class: co...
1693
  	class_destroy(sg_sysfs_class);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1694
1695
1696
  	sg_sysfs_valid = 0;
  	unregister_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0),
  				 SG_MAX_DEVS);
7c07d613d   James Bottomley   [SCSI] sg: use id...
1697
  	idr_destroy(&sg_index_idr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1698
  }
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
1699
1700
  static int
  sg_start_req(Sg_request *srp, unsigned char *cmd)
10865dfa3   FUJITA Tomonori   sg: convert the n...
1701
  {
626710c9d   FUJITA Tomonori   sg: incorporate s...
1702
  	int res;
10865dfa3   FUJITA Tomonori   sg: convert the n...
1703
  	struct request *rq;
82ed4db49   Christoph Hellwig   block: split scsi...
1704
  	struct scsi_request *req;
44c7b0eaa   FUJITA Tomonori   sg: remove __sg_s...
1705
1706
1707
1708
  	Sg_fd *sfp = srp->parentfp;
  	sg_io_hdr_t *hp = &srp->header;
  	int dxfer_len = (int) hp->dxfer_len;
  	int dxfer_dir = hp->dxfer_direction;
626710c9d   FUJITA Tomonori   sg: incorporate s...
1709
  	unsigned int iov_count = hp->iovec_count;
44c7b0eaa   FUJITA Tomonori   sg: remove __sg_s...
1710
1711
1712
  	Sg_scatter_hold *req_schp = &srp->data;
  	Sg_scatter_hold *rsv_schp = &sfp->reserve;
  	struct request_queue *q = sfp->parentdp->device->request_queue;
626710c9d   FUJITA Tomonori   sg: incorporate s...
1713
  	struct rq_map_data *md, map_data;
10865dfa3   FUJITA Tomonori   sg: convert the n...
1714
  	int rw = hp->dxfer_direction == SG_DXFER_TO_DEV ? WRITE : READ;
65c26a0f3   Douglas Gilbert   sg: relax 16 byte...
1715
  	unsigned char *long_cmdp = NULL;
10865dfa3   FUJITA Tomonori   sg: convert the n...
1716

95e159d6d   Hannes Reinecke   scsi: Implement s...
1717
1718
1719
1720
  	SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sfp->parentdp,
  				      "sg_start_req: dxfer_len=%d
  ",
  				      dxfer_len));
44c7b0eaa   FUJITA Tomonori   sg: remove __sg_s...
1721

65c26a0f3   Douglas Gilbert   sg: relax 16 byte...
1722
1723
1724
1725
1726
  	if (hp->cmd_len > BLK_MAX_CDB) {
  		long_cmdp = kzalloc(hp->cmd_len, GFP_KERNEL);
  		if (!long_cmdp)
  			return -ENOMEM;
  	}
7772855a9   Tony Battersby   sg: fix EWOULDBLO...
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
  	/*
  	 * NOTE
  	 *
  	 * With scsi-mq enabled, there are a fixed number of preallocated
  	 * requests equal in number to shost->can_queue.  If all of the
  	 * preallocated requests are already in use, then using GFP_ATOMIC with
  	 * blk_get_request() will return -EWOULDBLOCK, whereas using GFP_KERNEL
  	 * will cause blk_get_request() to sleep until an active command
  	 * completes, freeing up a request.  Neither option is ideal, but
  	 * GFP_KERNEL is the better choice to prevent userspace from getting an
  	 * unexpected EWOULDBLOCK.
  	 *
  	 * With scsi-mq disabled, blk_get_request() with GFP_KERNEL usually
  	 * does not sleep except under memory pressure.
  	 */
aebf526b5   Christoph Hellwig   block: fold cmd_t...
1742
1743
  	rq = blk_get_request(q, hp->dxfer_direction == SG_DXFER_TO_DEV ?
  			REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, GFP_KERNEL);
a492f0754   Joe Lawrence   block,scsi: fixup...
1744
  	if (IS_ERR(rq)) {
65c26a0f3   Douglas Gilbert   sg: relax 16 byte...
1745
  		kfree(long_cmdp);
a492f0754   Joe Lawrence   block,scsi: fixup...
1746
  		return PTR_ERR(rq);
65c26a0f3   Douglas Gilbert   sg: relax 16 byte...
1747
  	}
82ed4db49   Christoph Hellwig   block: split scsi...
1748
  	req = scsi_req(rq);
10865dfa3   FUJITA Tomonori   sg: convert the n...
1749

65c26a0f3   Douglas Gilbert   sg: relax 16 byte...
1750
  	if (hp->cmd_len > BLK_MAX_CDB)
82ed4db49   Christoph Hellwig   block: split scsi...
1751
1752
1753
  		req->cmd = long_cmdp;
  	memcpy(req->cmd, cmd, hp->cmd_len);
  	req->cmd_len = hp->cmd_len;
10865dfa3   FUJITA Tomonori   sg: convert the n...
1754
1755
1756
  
  	srp->rq = rq;
  	rq->end_io_data = srp;
64c7f1d15   Christoph Hellwig   block, scsi: move...
1757
  	req->retries = SG_DEFAULT_RETRIES;
10865dfa3   FUJITA Tomonori   sg: convert the n...
1758

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1759
  	if ((dxfer_len <= 0) || (dxfer_dir == SG_DXFER_NONE))
10db10d14   FUJITA Tomonori   sg: convert the i...
1760
  		return 0;
10865dfa3   FUJITA Tomonori   sg: convert the n...
1761

626710c9d   FUJITA Tomonori   sg: incorporate s...
1762
1763
1764
  	if (sg_allow_dio && hp->flags & SG_FLAG_DIRECT_IO &&
  	    dxfer_dir != SG_DXFER_UNKNOWN && !iov_count &&
  	    !sfp->parentdp->device->host->unchecked_isa_dma &&
2610a2540   Namhyung Kim   sg: fix a warning...
1765
  	    blk_rq_aligned(q, (unsigned long)hp->dxferp, dxfer_len))
626710c9d   FUJITA Tomonori   sg: incorporate s...
1766
1767
1768
1769
1770
  		md = NULL;
  	else
  		md = &map_data;
  
  	if (md) {
1bc0eb044   Hannes Reinecke   scsi: sg: protect...
1771
1772
1773
1774
  		mutex_lock(&sfp->f_mutex);
  		if (dxfer_len <= rsv_schp->bufflen &&
  		    !sfp->res_in_use) {
  			sfp->res_in_use = 1;
626710c9d   FUJITA Tomonori   sg: incorporate s...
1775
  			sg_link_reserve(sfp, srp, dxfer_len);
8d26f4911   Todd Poynor   scsi: sg: recheck...
1776
1777
1778
1779
  		} else if (hp->flags & SG_FLAG_MMAP_IO) {
  			res = -EBUSY; /* sfp->res_in_use == 1 */
  			if (dxfer_len > rsv_schp->bufflen)
  				res = -ENOMEM;
1bc0eb044   Hannes Reinecke   scsi: sg: protect...
1780
  			mutex_unlock(&sfp->f_mutex);
8d26f4911   Todd Poynor   scsi: sg: recheck...
1781
  			return res;
1bc0eb044   Hannes Reinecke   scsi: sg: protect...
1782
  		} else {
626710c9d   FUJITA Tomonori   sg: incorporate s...
1783
  			res = sg_build_indirect(req_schp, sfp, dxfer_len);
1bc0eb044   Hannes Reinecke   scsi: sg: protect...
1784
1785
  			if (res) {
  				mutex_unlock(&sfp->f_mutex);
626710c9d   FUJITA Tomonori   sg: incorporate s...
1786
  				return res;
1bc0eb044   Hannes Reinecke   scsi: sg: protect...
1787
  			}
626710c9d   FUJITA Tomonori   sg: incorporate s...
1788
  		}
1bc0eb044   Hannes Reinecke   scsi: sg: protect...
1789
  		mutex_unlock(&sfp->f_mutex);
7e56cb0f7   FUJITA Tomonori   sg: remove SG_ALL...
1790

626710c9d   FUJITA Tomonori   sg: incorporate s...
1791
1792
1793
  		md->pages = req_schp->pages;
  		md->page_order = req_schp->page_order;
  		md->nr_entries = req_schp->k_use_sg;
56c451f4b   FUJITA Tomonori   [SCSI] block: fix...
1794
  		md->offset = 0;
97ae77a1c   FUJITA Tomonori   [SCSI] block: mak...
1795
  		md->null_mapped = hp->dxferp ? 0 : 1;
ecb554a84   FUJITA Tomonori   block: fix sg SG_...
1796
1797
1798
1799
  		if (dxfer_dir == SG_DXFER_TO_FROM_DEV)
  			md->from_user = 1;
  		else
  			md->from_user = 0;
626710c9d   FUJITA Tomonori   sg: incorporate s...
1800
  	}
0fdf96b67   FUJITA Tomonori   [SCSI] sg: fix io...
1801
  	if (iov_count) {
fdc81f45e   Al Viro   sg_start_req(): u...
1802
  		struct iovec *iov = NULL;
26e49cfc7   Kent Overstreet   block: pass iov_i...
1803
  		struct iov_iter i;
0fdf96b67   FUJITA Tomonori   [SCSI] sg: fix io...
1804

fdc81f45e   Al Viro   sg_start_req(): u...
1805
1806
1807
  		res = import_iovec(rw, hp->dxferp, iov_count, 0, &iov, &i);
  		if (res < 0)
  			return res;
0fdf96b67   FUJITA Tomonori   [SCSI] sg: fix io...
1808

fdc81f45e   Al Viro   sg_start_req(): u...
1809
  		iov_iter_truncate(&i, hp->dxfer_len);
137d01df5   Al Viro   Fix missing sanit...
1810
1811
1812
1813
  		if (!iov_iter_count(&i)) {
  			kfree(iov);
  			return -EINVAL;
  		}
0fdf96b67   FUJITA Tomonori   [SCSI] sg: fix io...
1814

26e49cfc7   Kent Overstreet   block: pass iov_i...
1815
  		res = blk_rq_map_user_iov(q, rq, md, &i, GFP_ATOMIC);
0fdf96b67   FUJITA Tomonori   [SCSI] sg: fix io...
1816
1817
  		kfree(iov);
  	} else
626710c9d   FUJITA Tomonori   sg: incorporate s...
1818
1819
  		res = blk_rq_map_user(q, rq, md, hp->dxferp,
  				      hp->dxfer_len, GFP_ATOMIC);
10db10d14   FUJITA Tomonori   sg: convert the i...
1820
1821
  
  	if (!res) {
626710c9d   FUJITA Tomonori   sg: incorporate s...
1822
  		srp->bio = rq->bio;
10db10d14   FUJITA Tomonori   sg: convert the i...
1823

626710c9d   FUJITA Tomonori   sg: incorporate s...
1824
1825
1826
1827
1828
  		if (!md) {
  			req_schp->dio_in_use = 1;
  			hp->info |= SG_INFO_DIRECT_IO;
  		}
  	}
10db10d14   FUJITA Tomonori   sg: convert the i...
1829
  	return res;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1830
  }
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
1831
1832
  static int
  sg_finish_rem_req(Sg_request *srp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1833
  {
e7ee4cc04   FUJITA Tomonori   [SCSI] sg: return...
1834
  	int ret = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1835
1836
  	Sg_fd *sfp = srp->parentfp;
  	Sg_scatter_hold *req_schp = &srp->data;
95e159d6d   Hannes Reinecke   scsi: Implement s...
1837
1838
1839
1840
  	SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sfp->parentdp,
  				      "sg_finish_rem_req: res_used=%d
  ",
  				      (int) srp->res_used));
7568615c1   Tony Battersby   sg: fix unkillabl...
1841
1842
  	if (srp->bio)
  		ret = blk_rq_unmap_user(srp->bio);
10db10d14   FUJITA Tomonori   sg: convert the i...
1843

7568615c1   Tony Battersby   sg: fix unkillabl...
1844
  	if (srp->rq) {
82ed4db49   Christoph Hellwig   block: split scsi...
1845
  		scsi_req_free_cmd(scsi_req(srp->rq));
10865dfa3   FUJITA Tomonori   sg: convert the n...
1846
  		blk_put_request(srp->rq);
6e5a30cba   FUJITA Tomonori   sg: convert the d...
1847
  	}
10865dfa3   FUJITA Tomonori   sg: convert the n...
1848

e27168f8c   Christof Schmitt   [SCSI] sg: Free d...
1849
1850
1851
  	if (srp->res_used)
  		sg_unlink_reserve(sfp, srp);
  	else
95e159d6d   Hannes Reinecke   scsi: Implement s...
1852
  		sg_remove_scat(sfp, req_schp);
e27168f8c   Christof Schmitt   [SCSI] sg: Free d...
1853

e7ee4cc04   FUJITA Tomonori   [SCSI] sg: return...
1854
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1855
1856
1857
1858
1859
  }
  
  static int
  sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp, int tablesize)
  {
10db10d14   FUJITA Tomonori   sg: convert the i...
1860
  	int sg_bufflen = tablesize * sizeof(struct page *);
2d20eaf94   Al Viro   [PATCH] sg gfp_t ...
1861
  	gfp_t gfp_flags = GFP_ATOMIC | __GFP_NOWARN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1862

10db10d14   FUJITA Tomonori   sg: convert the i...
1863
1864
  	schp->pages = kzalloc(sg_bufflen, gfp_flags);
  	if (!schp->pages)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1865
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1866
  	schp->sglist_len = sg_bufflen;
d6b10348f   Mike Christie   [SCSI] convert sg...
1867
  	return tablesize;	/* number of scat_gath elements allocated */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1868
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1869
1870
1871
  static int
  sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size)
  {
10db10d14   FUJITA Tomonori   sg: convert the i...
1872
  	int ret_sz = 0, i, k, rem_sz, num, mx_sc_elems;
d6b10348f   Mike Christie   [SCSI] convert sg...
1873
  	int sg_tablesize = sfp->parentdp->sg_tablesize;
10db10d14   FUJITA Tomonori   sg: convert the i...
1874
1875
  	int blk_size = buff_size, order;
  	gfp_t gfp_mask = GFP_ATOMIC | __GFP_COMP | __GFP_NOWARN;
745dfa0d8   Hannes Reinecke   scsi: sg: disable...
1876
  	struct sg_device *sdp = sfp->parentdp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1877

fb119935e   Eric Sesterhenn   [SCSI] sg: remove...
1878
  	if (blk_size < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1879
1880
1881
  		return -EFAULT;
  	if (0 == blk_size)
  		++blk_size;	/* don't know why */
b2ed6c69a   FUJITA Tomonori   [SCSI] sg: use AL...
1882
1883
  	/* round request up to next highest SG_SECTOR_SZ byte boundary */
  	blk_size = ALIGN(blk_size, SG_SECTOR_SZ);
95e159d6d   Hannes Reinecke   scsi: Implement s...
1884
1885
1886
1887
  	SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sfp->parentdp,
  		"sg_build_indirect: buff_size=%d, blk_size=%d
  ",
  		buff_size, blk_size));
d6b10348f   Mike Christie   [SCSI] convert sg...
1888
1889
1890
1891
1892
  
  	/* N.B. ret_sz carried into this block ... */
  	mx_sc_elems = sg_build_sgat(schp, sfp, sg_tablesize);
  	if (mx_sc_elems < 0)
  		return mx_sc_elems;	/* most likely -ENOMEM */
6460e75a1   Douglas Gilbert   [SCSI] sg: fixes ...
1893
1894
1895
1896
1897
1898
1899
1900
  	num = scatter_elem_sz;
  	if (unlikely(num != scatter_elem_sz_prev)) {
  		if (num < PAGE_SIZE) {
  			scatter_elem_sz = PAGE_SIZE;
  			scatter_elem_sz_prev = PAGE_SIZE;
  		} else
  			scatter_elem_sz_prev = num;
  	}
10db10d14   FUJITA Tomonori   sg: convert the i...
1901

745dfa0d8   Hannes Reinecke   scsi: sg: disable...
1902
  	if (sdp->device->host->unchecked_isa_dma)
10db10d14   FUJITA Tomonori   sg: convert the i...
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
  		gfp_mask |= GFP_DMA;
  
  	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
  		gfp_mask |= __GFP_ZERO;
  
  	order = get_order(num);
  retry:
  	ret_sz = 1 << (PAGE_SHIFT + order);
  
  	for (k = 0, rem_sz = blk_size; rem_sz > 0 && k < mx_sc_elems;
  	     k++, rem_sz -= ret_sz) {
6460e75a1   Douglas Gilbert   [SCSI] sg: fixes ...
1914
  		num = (rem_sz > scatter_elem_sz_prev) ?
10db10d14   FUJITA Tomonori   sg: convert the i...
1915
  			scatter_elem_sz_prev : rem_sz;
d827bea2d   Alexander Potapenko   scsi: sg: allocat...
1916
  		schp->pages[k] = alloc_pages(gfp_mask | __GFP_ZERO, order);
10db10d14   FUJITA Tomonori   sg: convert the i...
1917
1918
  		if (!schp->pages[k])
  			goto out;
d6b10348f   Mike Christie   [SCSI] convert sg...
1919

6460e75a1   Douglas Gilbert   [SCSI] sg: fixes ...
1920
1921
1922
1923
1924
1925
  		if (num == scatter_elem_sz_prev) {
  			if (unlikely(ret_sz > scatter_elem_sz_prev)) {
  				scatter_elem_sz = ret_sz;
  				scatter_elem_sz_prev = ret_sz;
  			}
  		}
d6b10348f   Mike Christie   [SCSI] convert sg...
1926

95e159d6d   Hannes Reinecke   scsi: Implement s...
1927
1928
1929
1930
  		SCSI_LOG_TIMEOUT(5, sg_printk(KERN_INFO, sfp->parentdp,
  				 "sg_build_indirect: k=%d, num=%d, ret_sz=%d
  ",
  				 k, num, ret_sz));
d6b10348f   Mike Christie   [SCSI] convert sg...
1931
  	}		/* end of for loop */
10db10d14   FUJITA Tomonori   sg: convert the i...
1932
  	schp->page_order = order;
d6b10348f   Mike Christie   [SCSI] convert sg...
1933
  	schp->k_use_sg = k;
95e159d6d   Hannes Reinecke   scsi: Implement s...
1934
1935
1936
1937
  	SCSI_LOG_TIMEOUT(5, sg_printk(KERN_INFO, sfp->parentdp,
  			 "sg_build_indirect: k_use_sg=%d, rem_sz=%d
  ",
  			 k, rem_sz));
d6b10348f   Mike Christie   [SCSI] convert sg...
1938
1939
1940
1941
  
  	schp->bufflen = blk_size;
  	if (rem_sz > 0)	/* must have failed */
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1942
  	return 0;
10db10d14   FUJITA Tomonori   sg: convert the i...
1943
1944
  out:
  	for (i = 0; i < k; i++)
e71044ee2   Michal Schmidt   [SCSI] sg: fix oo...
1945
  		__free_pages(schp->pages[i], order);
10db10d14   FUJITA Tomonori   sg: convert the i...
1946
1947
1948
1949
1950
  
  	if (--order >= 0)
  		goto retry;
  
  	return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1951
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1952
  static void
95e159d6d   Hannes Reinecke   scsi: Implement s...
1953
  sg_remove_scat(Sg_fd * sfp, Sg_scatter_hold * schp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1954
  {
95e159d6d   Hannes Reinecke   scsi: Implement s...
1955
1956
1957
  	SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sfp->parentdp,
  			 "sg_remove_scat: k_use_sg=%d
  ", schp->k_use_sg));
10db10d14   FUJITA Tomonori   sg: convert the i...
1958
  	if (schp->pages && schp->sglist_len > 0) {
6e5a30cba   FUJITA Tomonori   sg: convert the d...
1959
  		if (!schp->dio_in_use) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1960
  			int k;
10db10d14   FUJITA Tomonori   sg: convert the i...
1961
  			for (k = 0; k < schp->k_use_sg && schp->pages[k]; k++) {
95e159d6d   Hannes Reinecke   scsi: Implement s...
1962
1963
1964
1965
1966
  				SCSI_LOG_TIMEOUT(5,
  					sg_printk(KERN_INFO, sfp->parentdp,
  					"sg_remove_scat: k=%d, pg=0x%p
  ",
  					k, schp->pages[k]));
10db10d14   FUJITA Tomonori   sg: convert the i...
1967
  				__free_pages(schp->pages[k], schp->page_order);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1968
  			}
6e5a30cba   FUJITA Tomonori   sg: convert the d...
1969

10db10d14   FUJITA Tomonori   sg: convert the i...
1970
  			kfree(schp->pages);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1971
  		}
d6b10348f   Mike Christie   [SCSI] convert sg...
1972
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1973
1974
1975
1976
  	memset(schp, 0, sizeof (*schp));
  }
  
  static int
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1977
1978
1979
  sg_read_oxfer(Sg_request * srp, char __user *outp, int num_read_xfer)
  {
  	Sg_scatter_hold *schp = &srp->data;
d6b10348f   Mike Christie   [SCSI] convert sg...
1980
  	int k, num;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1981

95e159d6d   Hannes Reinecke   scsi: Implement s...
1982
1983
1984
1985
  	SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, srp->parentfp->parentdp,
  			 "sg_read_oxfer: num_read_xfer=%d
  ",
  			 num_read_xfer));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1986
1987
  	if ((!outp) || (num_read_xfer <= 0))
  		return 0;
d6b10348f   Mike Christie   [SCSI] convert sg...
1988

10db10d14   FUJITA Tomonori   sg: convert the i...
1989
1990
  	num = 1 << (PAGE_SHIFT + schp->page_order);
  	for (k = 0; k < schp->k_use_sg && schp->pages[k]; k++) {
d6b10348f   Mike Christie   [SCSI] convert sg...
1991
  		if (num > num_read_xfer) {
10db10d14   FUJITA Tomonori   sg: convert the i...
1992
  			if (__copy_to_user(outp, page_address(schp->pages[k]),
d6b10348f   Mike Christie   [SCSI] convert sg...
1993
1994
1995
1996
  					   num_read_xfer))
  				return -EFAULT;
  			break;
  		} else {
10db10d14   FUJITA Tomonori   sg: convert the i...
1997
  			if (__copy_to_user(outp, page_address(schp->pages[k]),
d6b10348f   Mike Christie   [SCSI] convert sg...
1998
1999
2000
2001
  					   num))
  				return -EFAULT;
  			num_read_xfer -= num;
  			if (num_read_xfer <= 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2002
  				break;
d6b10348f   Mike Christie   [SCSI] convert sg...
2003
  			outp += num;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2004
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2005
  	}
d6b10348f   Mike Christie   [SCSI] convert sg...
2006

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2007
2008
2009
2010
2011
2012
2013
  	return 0;
  }
  
  static void
  sg_build_reserve(Sg_fd * sfp, int req_size)
  {
  	Sg_scatter_hold *schp = &sfp->reserve;
95e159d6d   Hannes Reinecke   scsi: Implement s...
2014
2015
2016
  	SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sfp->parentdp,
  			 "sg_build_reserve: req_size=%d
  ", req_size));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2017
2018
2019
2020
2021
2022
  	do {
  		if (req_size < PAGE_SIZE)
  			req_size = PAGE_SIZE;
  		if (0 == sg_build_indirect(schp, sfp, req_size))
  			return;
  		else
95e159d6d   Hannes Reinecke   scsi: Implement s...
2023
  			sg_remove_scat(sfp, schp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2024
2025
2026
2027
2028
2029
2030
2031
2032
  		req_size >>= 1;	/* divide by 2 */
  	} while (req_size > (PAGE_SIZE / 2));
  }
  
  static void
  sg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size)
  {
  	Sg_scatter_hold *req_schp = &srp->data;
  	Sg_scatter_hold *rsv_schp = &sfp->reserve;
d6b10348f   Mike Christie   [SCSI] convert sg...
2033
  	int k, num, rem;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2034
2035
  
  	srp->res_used = 1;
95e159d6d   Hannes Reinecke   scsi: Implement s...
2036
2037
2038
  	SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sfp->parentdp,
  			 "sg_link_reserve: size=%d
  ", size));
eca7be5e1   Brian King   [SCSI] sg: Remove...
2039
  	rem = size;
d6b10348f   Mike Christie   [SCSI] convert sg...
2040

10db10d14   FUJITA Tomonori   sg: convert the i...
2041
2042
  	num = 1 << (PAGE_SHIFT + rsv_schp->page_order);
  	for (k = 0; k < rsv_schp->k_use_sg; k++) {
d6b10348f   Mike Christie   [SCSI] convert sg...
2043
  		if (rem <= num) {
d6b10348f   Mike Christie   [SCSI] convert sg...
2044
2045
  			req_schp->k_use_sg = k + 1;
  			req_schp->sglist_len = rsv_schp->sglist_len;
10db10d14   FUJITA Tomonori   sg: convert the i...
2046
  			req_schp->pages = rsv_schp->pages;
d6b10348f   Mike Christie   [SCSI] convert sg...
2047
2048
  
  			req_schp->bufflen = size;
10db10d14   FUJITA Tomonori   sg: convert the i...
2049
  			req_schp->page_order = rsv_schp->page_order;
d6b10348f   Mike Christie   [SCSI] convert sg...
2050
2051
2052
  			break;
  		} else
  			rem -= num;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2053
  	}
d6b10348f   Mike Christie   [SCSI] convert sg...
2054
2055
  
  	if (k >= rsv_schp->k_use_sg)
95e159d6d   Hannes Reinecke   scsi: Implement s...
2056
2057
2058
  		SCSI_LOG_TIMEOUT(1, sg_printk(KERN_INFO, sfp->parentdp,
  				 "sg_link_reserve: BAD size
  "));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2059
2060
2061
2062
2063
2064
  }
  
  static void
  sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp)
  {
  	Sg_scatter_hold *req_schp = &srp->data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2065

95e159d6d   Hannes Reinecke   scsi: Implement s...
2066
2067
2068
2069
  	SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, srp->parentfp->parentdp,
  				      "sg_unlink_reserve: req->k_use_sg=%d
  ",
  				      (int) req_schp->k_use_sg));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2070
2071
  	req_schp->k_use_sg = 0;
  	req_schp->bufflen = 0;
10db10d14   FUJITA Tomonori   sg: convert the i...
2072
2073
  	req_schp->pages = NULL;
  	req_schp->page_order = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2074
  	req_schp->sglist_len = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2075
  	srp->res_used = 0;
e791ce27c   Hannes Reinecke   scsi: sg: reset '...
2076
2077
  	/* Called without mutex lock to avoid deadlock */
  	sfp->res_in_use = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2078
2079
2080
2081
2082
2083
2084
2085
2086
  }
  
  static Sg_request *
  sg_get_rq_mark(Sg_fd * sfp, int pack_id)
  {
  	Sg_request *resp;
  	unsigned long iflags;
  
  	write_lock_irqsave(&sfp->rq_list_lock, iflags);
109bade9c   Hannes Reinecke   scsi: sg: use sta...
2087
  	list_for_each_entry(resp, &sfp->rq_list, entry) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2088
2089
2090
2091
  		/* look for requests that are ready + not SG_IO owned */
  		if ((1 == resp->done) && (!resp->sg_io_owned) &&
  		    ((-1 == pack_id) || (resp->header.pack_id == pack_id))) {
  			resp->done = 2;	/* guard against other readers */
48ae8484e   Johannes Thumshirn   scsi: sg: don't r...
2092
2093
  			write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
  			return resp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2094
2095
2096
  		}
  	}
  	write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
48ae8484e   Johannes Thumshirn   scsi: sg: don't r...
2097
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2098
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2099
2100
2101
2102
2103
2104
  /* always adds to end of list */
  static Sg_request *
  sg_add_request(Sg_fd * sfp)
  {
  	int k;
  	unsigned long iflags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2105
2106
2107
  	Sg_request *rp = sfp->req_arr;
  
  	write_lock_irqsave(&sfp->rq_list_lock, iflags);
109bade9c   Hannes Reinecke   scsi: sg: use sta...
2108
2109
2110
2111
2112
2113
2114
  	if (!list_empty(&sfp->rq_list)) {
  		if (!sfp->cmd_q)
  			goto out_unlock;
  
  		for (k = 0; k < SG_MAX_QUEUE; ++k, ++rp) {
  			if (!rp->parentfp)
  				break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2115
  		}
109bade9c   Hannes Reinecke   scsi: sg: use sta...
2116
2117
  		if (k >= SG_MAX_QUEUE)
  			goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2118
  	}
109bade9c   Hannes Reinecke   scsi: sg: use sta...
2119
2120
2121
2122
  	memset(rp, 0, sizeof (Sg_request));
  	rp->parentfp = sfp;
  	rp->header.duration = jiffies_to_msecs(jiffies);
  	list_add_tail(&rp->entry, &sfp->rq_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2123
  	write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
109bade9c   Hannes Reinecke   scsi: sg: use sta...
2124
2125
2126
2127
  	return rp;
  out_unlock:
  	write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2128
2129
2130
2131
2132
2133
  }
  
  /* Return of 1 for found; 0 for not found */
  static int
  sg_remove_request(Sg_fd * sfp, Sg_request * srp)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2134
2135
  	unsigned long iflags;
  	int res = 0;
109bade9c   Hannes Reinecke   scsi: sg: use sta...
2136
  	if (!sfp || !srp || list_empty(&sfp->rq_list))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2137
2138
  		return res;
  	write_lock_irqsave(&sfp->rq_list_lock, iflags);
109bade9c   Hannes Reinecke   scsi: sg: use sta...
2139
2140
2141
  	if (!list_empty(&srp->entry)) {
  		list_del(&srp->entry);
  		srp->parentfp = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2142
  		res = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2143
2144
2145
2146
  	}
  	write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
  	return res;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2147
  static Sg_fd *
95e159d6d   Hannes Reinecke   scsi: Implement s...
2148
  sg_add_sfp(Sg_device * sdp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2149
2150
2151
  {
  	Sg_fd *sfp;
  	unsigned long iflags;
44ec95425   Alan Stern   [SCSI] sg: cap re...
2152
  	int bufflen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2153

d6b10348f   Mike Christie   [SCSI] convert sg...
2154
  	sfp = kzalloc(sizeof(*sfp), GFP_ATOMIC | __GFP_NOWARN);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2155
  	if (!sfp)
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
2156
  		return ERR_PTR(-ENOMEM);
d6b10348f   Mike Christie   [SCSI] convert sg...
2157

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2158
2159
  	init_waitqueue_head(&sfp->read_wait);
  	rwlock_init(&sfp->rq_list_lock);
109bade9c   Hannes Reinecke   scsi: sg: use sta...
2160
  	INIT_LIST_HEAD(&sfp->rq_list);
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
2161
  	kref_init(&sfp->f_ref);
1bc0eb044   Hannes Reinecke   scsi: sg: protect...
2162
  	mutex_init(&sfp->f_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2163
2164
2165
  	sfp->timeout = SG_DEFAULT_TIMEOUT;
  	sfp->timeout_user = SG_DEFAULT_TIMEOUT_USER;
  	sfp->force_packid = SG_DEF_FORCE_PACK_ID;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2166
2167
2168
  	sfp->cmd_q = SG_DEF_COMMAND_Q;
  	sfp->keep_orphan = SG_DEF_KEEP_ORPHAN;
  	sfp->parentdp = sdp;
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
2169
2170
2171
  	write_lock_irqsave(&sdp->sfd_lock, iflags);
  	if (atomic_read(&sdp->detaching)) {
  		write_unlock_irqrestore(&sdp->sfd_lock, iflags);
b4653a3ea   Tony Battersby   scsi: sg: fix min...
2172
  		kfree(sfp);
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
2173
2174
  		return ERR_PTR(-ENODEV);
  	}
3442f802a   FUJITA Tomonori   [SCSI] sg: remove...
2175
  	list_add_tail(&sfp->sfd_siblings, &sdp->sfds);
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
2176
  	write_unlock_irqrestore(&sdp->sfd_lock, iflags);
95e159d6d   Hannes Reinecke   scsi: Implement s...
2177
2178
2179
  	SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp,
  				      "sg_add_sfp: sfp=0x%p
  ", sfp));
6460e75a1   Douglas Gilbert   [SCSI] sg: fixes ...
2180
2181
  	if (unlikely(sg_big_buff != def_reserved_size))
  		sg_big_buff = def_reserved_size;
44ec95425   Alan Stern   [SCSI] sg: cap re...
2182
  	bufflen = min_t(int, sg_big_buff,
46f69e6a6   Akinobu Mita   sg: prevent integ...
2183
  			max_sectors_bytes(sdp->device->request_queue));
44ec95425   Alan Stern   [SCSI] sg: cap re...
2184
  	sg_build_reserve(sfp, bufflen);
95e159d6d   Hannes Reinecke   scsi: Implement s...
2185
2186
2187
2188
2189
  	SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp,
  				      "sg_add_sfp: bufflen=%d, k_use_sg=%d
  ",
  				      sfp->reserve.bufflen,
  				      sfp->reserve.k_use_sg));
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
2190
2191
2192
  
  	kref_get(&sdp->d_ref);
  	__module_get(THIS_MODULE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2193
2194
  	return sfp;
  }
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
2195
2196
  static void
  sg_remove_sfp_usercontext(struct work_struct *work)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2197
  {
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
2198
2199
  	struct sg_fd *sfp = container_of(work, struct sg_fd, ew.work);
  	struct sg_device *sdp = sfp->parentdp;
109bade9c   Hannes Reinecke   scsi: sg: use sta...
2200
  	Sg_request *srp;
97d27b0dd   Hannes Reinecke   scsi: sg: close r...
2201
  	unsigned long iflags;
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
2202
2203
  
  	/* Cleanup any responses which were never read(). */
97d27b0dd   Hannes Reinecke   scsi: sg: close r...
2204
  	write_lock_irqsave(&sfp->rq_list_lock, iflags);
109bade9c   Hannes Reinecke   scsi: sg: use sta...
2205
2206
2207
  	while (!list_empty(&sfp->rq_list)) {
  		srp = list_first_entry(&sfp->rq_list, Sg_request, entry);
  		sg_finish_rem_req(srp);
97d27b0dd   Hannes Reinecke   scsi: sg: close r...
2208
2209
  		list_del(&srp->entry);
  		srp->parentfp = NULL;
109bade9c   Hannes Reinecke   scsi: sg: use sta...
2210
  	}
97d27b0dd   Hannes Reinecke   scsi: sg: close r...
2211
  	write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2212

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2213
  	if (sfp->reserve.bufflen > 0) {
95e159d6d   Hannes Reinecke   scsi: Implement s...
2214
2215
2216
  		SCSI_LOG_TIMEOUT(6, sg_printk(KERN_INFO, sdp,
  				"sg_remove_sfp:    bufflen=%d, k_use_sg=%d
  ",
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
2217
2218
  				(int) sfp->reserve.bufflen,
  				(int) sfp->reserve.k_use_sg));
95e159d6d   Hannes Reinecke   scsi: Implement s...
2219
  		sg_remove_scat(sfp, &sfp->reserve);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2220
  	}
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
2221

95e159d6d   Hannes Reinecke   scsi: Implement s...
2222
2223
2224
  	SCSI_LOG_TIMEOUT(6, sg_printk(KERN_INFO, sdp,
  			"sg_remove_sfp: sfp=0x%p
  ", sfp));
d6b10348f   Mike Christie   [SCSI] convert sg...
2225
  	kfree(sfp);
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
2226
2227
  
  	scsi_device_put(sdp->device);
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
2228
  	kref_put(&sdp->d_ref, sg_device_destroy);
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
2229
  	module_put(THIS_MODULE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2230
  }
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
2231
2232
  static void
  sg_remove_sfp(struct kref *kref)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2233
  {
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
2234
  	struct sg_fd *sfp = container_of(kref, struct sg_fd, f_ref);
065b4a2f5   James Bottomley   [SCSI] Revert "sg...
2235
  	struct sg_device *sdp = sfp->parentdp;
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
2236
  	unsigned long iflags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2237

cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
2238
  	write_lock_irqsave(&sdp->sfd_lock, iflags);
3442f802a   FUJITA Tomonori   [SCSI] sg: remove...
2239
  	list_del(&sfp->sfd_siblings);
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
2240
  	write_unlock_irqrestore(&sdp->sfd_lock, iflags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2241

015640edb   FUJITA Tomonori   [SCSI] sg: fix q-...
2242
2243
  	INIT_WORK(&sfp->ew.work, sg_remove_sfp_usercontext);
  	schedule_work(&sfp->ew.work);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2244
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2245
2246
  #ifdef CONFIG_SCSI_PROC_FS
  static int
7c07d613d   James Bottomley   [SCSI] sg: use id...
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
  sg_idr_max_id(int id, void *p, void *data)
  {
  	int *k = data;
  
  	if (*k < id)
  		*k = id;
  
  	return 0;
  }
  
  static int
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2258
2259
  sg_last_dev(void)
  {
53474c042   Tony Battersby   [SCSI] sg: fix /p...
2260
  	int k = -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2261
  	unsigned long iflags;
7c07d613d   James Bottomley   [SCSI] sg: use id...
2262
2263
2264
  	read_lock_irqsave(&sg_index_lock, iflags);
  	idr_for_each(&sg_index_idr, sg_idr_max_id, &k);
  	read_unlock_irqrestore(&sg_index_lock, iflags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2265
2266
2267
  	return k + 1;		/* origin 1 */
  }
  #endif
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
2268
2269
  /* must be called with sg_index_lock held */
  static Sg_device *sg_lookup_dev(int dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2270
  {
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
2271
2272
  	return idr_find(&sg_index_idr, dev);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2273

cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
2274
2275
  static Sg_device *
  sg_get_dev(int dev)
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
2276
2277
2278
2279
2280
2281
2282
2283
  {
  	struct sg_device *sdp;
  	unsigned long flags;
  
  	read_lock_irqsave(&sg_index_lock, flags);
  	sdp = sg_lookup_dev(dev);
  	if (!sdp)
  		sdp = ERR_PTR(-ENXIO);
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
2284
2285
  	else if (atomic_read(&sdp->detaching)) {
  		/* If sdp->detaching, then the refcount may already be 0, in
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
2286
2287
2288
2289
2290
2291
  		 * which case it would be a bug to do kref_get().
  		 */
  		sdp = ERR_PTR(-ENODEV);
  	} else
  		kref_get(&sdp->d_ref);
  	read_unlock_irqrestore(&sg_index_lock, flags);
7c07d613d   James Bottomley   [SCSI] sg: use id...
2292

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
  	return sdp;
  }
  
  #ifdef CONFIG_SCSI_PROC_FS
  
  static struct proc_dir_entry *sg_proc_sgp = NULL;
  
  static char sg_proc_sg_dirname[] = "scsi/sg";
  
  static int sg_proc_seq_show_int(struct seq_file *s, void *v);
  
  static int sg_proc_single_open_adio(struct inode *inode, struct file *file);
  static ssize_t sg_proc_write_adio(struct file *filp, const char __user *buffer,
  			          size_t count, loff_t *off);
828c09509   Alexey Dobriyan   const: constify r...
2307
2308
  static const struct file_operations adio_fops = {
  	.owner = THIS_MODULE,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2309
  	.open = sg_proc_single_open_adio,
828c09509   Alexey Dobriyan   const: constify r...
2310
2311
  	.read = seq_read,
  	.llseek = seq_lseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2312
2313
2314
2315
2316
2317
2318
  	.write = sg_proc_write_adio,
  	.release = single_release,
  };
  
  static int sg_proc_single_open_dressz(struct inode *inode, struct file *file);
  static ssize_t sg_proc_write_dressz(struct file *filp, 
  		const char __user *buffer, size_t count, loff_t *off);
828c09509   Alexey Dobriyan   const: constify r...
2319
2320
  static const struct file_operations dressz_fops = {
  	.owner = THIS_MODULE,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2321
  	.open = sg_proc_single_open_dressz,
828c09509   Alexey Dobriyan   const: constify r...
2322
2323
  	.read = seq_read,
  	.llseek = seq_lseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2324
2325
2326
2327
2328
2329
  	.write = sg_proc_write_dressz,
  	.release = single_release,
  };
  
  static int sg_proc_seq_show_version(struct seq_file *s, void *v);
  static int sg_proc_single_open_version(struct inode *inode, struct file *file);
828c09509   Alexey Dobriyan   const: constify r...
2330
2331
  static const struct file_operations version_fops = {
  	.owner = THIS_MODULE,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2332
  	.open = sg_proc_single_open_version,
828c09509   Alexey Dobriyan   const: constify r...
2333
2334
  	.read = seq_read,
  	.llseek = seq_lseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2335
2336
2337
2338
2339
  	.release = single_release,
  };
  
  static int sg_proc_seq_show_devhdr(struct seq_file *s, void *v);
  static int sg_proc_single_open_devhdr(struct inode *inode, struct file *file);
828c09509   Alexey Dobriyan   const: constify r...
2340
2341
  static const struct file_operations devhdr_fops = {
  	.owner = THIS_MODULE,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2342
  	.open = sg_proc_single_open_devhdr,
828c09509   Alexey Dobriyan   const: constify r...
2343
2344
  	.read = seq_read,
  	.llseek = seq_lseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2345
2346
2347
2348
2349
2350
2351
2352
  	.release = single_release,
  };
  
  static int sg_proc_seq_show_dev(struct seq_file *s, void *v);
  static int sg_proc_open_dev(struct inode *inode, struct file *file);
  static void * dev_seq_start(struct seq_file *s, loff_t *pos);
  static void * dev_seq_next(struct seq_file *s, void *v, loff_t *pos);
  static void dev_seq_stop(struct seq_file *s, void *v);
828c09509   Alexey Dobriyan   const: constify r...
2353
2354
  static const struct file_operations dev_fops = {
  	.owner = THIS_MODULE,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2355
  	.open = sg_proc_open_dev,
828c09509   Alexey Dobriyan   const: constify r...
2356
2357
  	.read = seq_read,
  	.llseek = seq_lseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2358
2359
  	.release = seq_release,
  };
88e9d34c7   James Morris   seq_file: constif...
2360
  static const struct seq_operations dev_seq_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2361
2362
2363
2364
2365
2366
2367
2368
  	.start = dev_seq_start,
  	.next  = dev_seq_next,
  	.stop  = dev_seq_stop,
  	.show  = sg_proc_seq_show_dev,
  };
  
  static int sg_proc_seq_show_devstrs(struct seq_file *s, void *v);
  static int sg_proc_open_devstrs(struct inode *inode, struct file *file);
828c09509   Alexey Dobriyan   const: constify r...
2369
2370
  static const struct file_operations devstrs_fops = {
  	.owner = THIS_MODULE,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2371
  	.open = sg_proc_open_devstrs,
828c09509   Alexey Dobriyan   const: constify r...
2372
2373
  	.read = seq_read,
  	.llseek = seq_lseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2374
2375
  	.release = seq_release,
  };
88e9d34c7   James Morris   seq_file: constif...
2376
  static const struct seq_operations devstrs_seq_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2377
2378
2379
2380
2381
2382
2383
2384
  	.start = dev_seq_start,
  	.next  = dev_seq_next,
  	.stop  = dev_seq_stop,
  	.show  = sg_proc_seq_show_devstrs,
  };
  
  static int sg_proc_seq_show_debug(struct seq_file *s, void *v);
  static int sg_proc_open_debug(struct inode *inode, struct file *file);
828c09509   Alexey Dobriyan   const: constify r...
2385
2386
  static const struct file_operations debug_fops = {
  	.owner = THIS_MODULE,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2387
  	.open = sg_proc_open_debug,
828c09509   Alexey Dobriyan   const: constify r...
2388
2389
  	.read = seq_read,
  	.llseek = seq_lseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2390
2391
  	.release = seq_release,
  };
88e9d34c7   James Morris   seq_file: constif...
2392
  static const struct seq_operations debug_seq_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2393
2394
2395
2396
2397
2398
2399
2400
2401
  	.start = dev_seq_start,
  	.next  = dev_seq_next,
  	.stop  = dev_seq_stop,
  	.show  = sg_proc_seq_show_debug,
  };
  
  
  struct sg_proc_leaf {
  	const char * name;
828c09509   Alexey Dobriyan   const: constify r...
2402
  	const struct file_operations * fops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2403
  };
18b8ba6cf   Jörn Engel   [SCSI] sg: consti...
2404
  static const struct sg_proc_leaf sg_proc_leaf_arr[] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
  	{"allow_dio", &adio_fops},
  	{"debug", &debug_fops},
  	{"def_reserved_size", &dressz_fops},
  	{"device_hdr", &devhdr_fops},
  	{"devices", &dev_fops},
  	{"device_strs", &devstrs_fops},
  	{"version", &version_fops}
  };
  
  static int
  sg_proc_init(void)
  {
6391a1137   Tobias Klauser   [SCSI] drivers/sc...
2417
  	int num_leaves = ARRAY_SIZE(sg_proc_leaf_arr);
d161a13f9   Al Viro   switch procfs to ...
2418
  	int k;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2419

666002218   Al Viro   [PATCH] proc_mkdi...
2420
  	sg_proc_sgp = proc_mkdir(sg_proc_sg_dirname, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2421
2422
2423
  	if (!sg_proc_sgp)
  		return 1;
  	for (k = 0; k < num_leaves; ++k) {
18b8ba6cf   Jörn Engel   [SCSI] sg: consti...
2424
  		const struct sg_proc_leaf *leaf = &sg_proc_leaf_arr[k];
d161a13f9   Al Viro   switch procfs to ...
2425
  		umode_t mask = leaf->fops->write ? S_IRUGO | S_IWUSR : S_IRUGO;
a973909fc   Denis V. Lunev   scsi: use non-rac...
2426
  		proc_create(leaf->name, mask, sg_proc_sgp, leaf->fops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2427
2428
2429
2430
2431
2432
2433
2434
  	}
  	return 0;
  }
  
  static void
  sg_proc_cleanup(void)
  {
  	int k;
6391a1137   Tobias Klauser   [SCSI] drivers/sc...
2435
  	int num_leaves = ARRAY_SIZE(sg_proc_leaf_arr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
  
  	if (!sg_proc_sgp)
  		return;
  	for (k = 0; k < num_leaves; ++k)
  		remove_proc_entry(sg_proc_leaf_arr[k].name, sg_proc_sgp);
  	remove_proc_entry(sg_proc_sg_dirname, NULL);
  }
  
  
  static int sg_proc_seq_show_int(struct seq_file *s, void *v)
  {
  	seq_printf(s, "%d
  ", *((int *)s->private));
  	return 0;
  }
  
  static int sg_proc_single_open_adio(struct inode *inode, struct file *file)
  {
  	return single_open(file, sg_proc_seq_show_int, &sg_allow_dio);
  }
  
  static ssize_t 
  sg_proc_write_adio(struct file *filp, const char __user *buffer,
  		   size_t count, loff_t *off)
  {
7e95fffe0   Stephen Boyd   [SCSI] sg: conver...
2461
2462
  	int err;
  	unsigned long num;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2463
2464
2465
  
  	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
  		return -EACCES;
7e95fffe0   Stephen Boyd   [SCSI] sg: conver...
2466
2467
2468
2469
  	err = kstrtoul_from_user(buffer, count, 0, &num);
  	if (err)
  		return err;
  	sg_allow_dio = num ? 1 : 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
  	return count;
  }
  
  static int sg_proc_single_open_dressz(struct inode *inode, struct file *file)
  {
  	return single_open(file, sg_proc_seq_show_int, &sg_big_buff);
  }
  
  static ssize_t 
  sg_proc_write_dressz(struct file *filp, const char __user *buffer,
  		     size_t count, loff_t *off)
  {
7e95fffe0   Stephen Boyd   [SCSI] sg: conver...
2482
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2483
  	unsigned long k = ULONG_MAX;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2484
2485
2486
  
  	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
  		return -EACCES;
7e95fffe0   Stephen Boyd   [SCSI] sg: conver...
2487
2488
2489
2490
  
  	err = kstrtoul_from_user(buffer, count, 0, &k);
  	if (err)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
  	if (k <= 1048576) {	/* limit "big buff" to 1 MB */
  		sg_big_buff = k;
  		return count;
  	}
  	return -ERANGE;
  }
  
  static int sg_proc_seq_show_version(struct seq_file *s, void *v)
  {
  	seq_printf(s, "%d\t%s [%s]
  ", sg_version_num, SG_VERSION_STR,
  		   sg_version_date);
  	return 0;
  }
  
  static int sg_proc_single_open_version(struct inode *inode, struct file *file)
  {
  	return single_open(file, sg_proc_seq_show_version, NULL);
  }
  
  static int sg_proc_seq_show_devhdr(struct seq_file *s, void *v)
  {
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
2513
2514
  	seq_puts(s, "host\tchan\tid\tlun\ttype\topens\tqdepth\tbusy\tonline
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
  	return 0;
  }
  
  static int sg_proc_single_open_devhdr(struct inode *inode, struct file *file)
  {
  	return single_open(file, sg_proc_seq_show_devhdr, NULL);
  }
  
  struct sg_proc_deviter {
  	loff_t	index;
  	size_t	max;
  };
  
  static void * dev_seq_start(struct seq_file *s, loff_t *pos)
  {
  	struct sg_proc_deviter * it = kmalloc(sizeof(*it), GFP_KERNEL);
729d70f5d   Jan Blunck   [PATCH] sg.c: fix...
2531
  	s->private = it;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2532
2533
  	if (! it)
  		return NULL;
729d70f5d   Jan Blunck   [PATCH] sg.c: fix...
2534

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2535
2536
2537
  	it->index = *pos;
  	it->max = sg_last_dev();
  	if (it->index >= it->max)
729d70f5d   Jan Blunck   [PATCH] sg.c: fix...
2538
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2539
  	return it;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2540
2541
2542
2543
  }
  
  static void * dev_seq_next(struct seq_file *s, void *v, loff_t *pos)
  {
729d70f5d   Jan Blunck   [PATCH] sg.c: fix...
2544
  	struct sg_proc_deviter * it = s->private;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2545
2546
2547
2548
2549
2550
2551
  
  	*pos = ++it->index;
  	return (it->index < it->max) ? it : NULL;
  }
  
  static void dev_seq_stop(struct seq_file *s, void *v)
  {
729d70f5d   Jan Blunck   [PATCH] sg.c: fix...
2552
  	kfree(s->private);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
  }
  
  static int sg_proc_open_dev(struct inode *inode, struct file *file)
  {
          return seq_open(file, &dev_seq_ops);
  }
  
  static int sg_proc_seq_show_dev(struct seq_file *s, void *v)
  {
  	struct sg_proc_deviter * it = (struct sg_proc_deviter *) v;
  	Sg_device *sdp;
  	struct scsi_device *scsidp;
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
2565
  	unsigned long iflags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2566

c6517b794   Tony Battersby   [SCSI] sg: fix ra...
2567
2568
  	read_lock_irqsave(&sg_index_lock, iflags);
  	sdp = it ? sg_lookup_dev(it->index) : NULL;
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
2569
2570
2571
2572
2573
2574
  	if ((NULL == sdp) || (NULL == sdp->device) ||
  	    (atomic_read(&sdp->detaching)))
  		seq_puts(s, "-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1
  ");
  	else {
  		scsidp = sdp->device;
9cb78c16f   Hannes Reinecke   scsi: use 64-bit ...
2575
2576
  		seq_printf(s, "%d\t%d\t%d\t%llu\t%d\t%d\t%d\t%d\t%d
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2577
2578
2579
2580
  			      scsidp->host->host_no, scsidp->channel,
  			      scsidp->id, scsidp->lun, (int) scsidp->type,
  			      1,
  			      (int) scsidp->queue_depth,
71e75c97f   Christoph Hellwig   scsi: convert dev...
2581
  			      (int) atomic_read(&scsidp->device_busy),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2582
  			      (int) scsi_device_online(scsidp));
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
2583
  	}
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
2584
  	read_unlock_irqrestore(&sg_index_lock, iflags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
  	return 0;
  }
  
  static int sg_proc_open_devstrs(struct inode *inode, struct file *file)
  {
          return seq_open(file, &devstrs_seq_ops);
  }
  
  static int sg_proc_seq_show_devstrs(struct seq_file *s, void *v)
  {
  	struct sg_proc_deviter * it = (struct sg_proc_deviter *) v;
  	Sg_device *sdp;
  	struct scsi_device *scsidp;
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
2598
  	unsigned long iflags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2599

c6517b794   Tony Battersby   [SCSI] sg: fix ra...
2600
2601
  	read_lock_irqsave(&sg_index_lock, iflags);
  	sdp = it ? sg_lookup_dev(it->index) : NULL;
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
2602
2603
  	scsidp = sdp ? sdp->device : NULL;
  	if (sdp && scsidp && (!atomic_read(&sdp->detaching)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2604
2605
2606
2607
  		seq_printf(s, "%8.8s\t%16.16s\t%4.4s
  ",
  			   scsidp->vendor, scsidp->model, scsidp->rev);
  	else
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
2608
2609
  		seq_puts(s, "<no active device>
  ");
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
2610
  	read_unlock_irqrestore(&sg_index_lock, iflags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2611
2612
  	return 0;
  }
c0d3b9c29   James Bottomley   [SCSI] Revert "sg...
2613
  /* must be called while holding sg_index_lock */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2614
2615
  static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp)
  {
109bade9c   Hannes Reinecke   scsi: sg: use sta...
2616
  	int k, new_interface, blen, usg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2617
2618
2619
2620
  	Sg_request *srp;
  	Sg_fd *fp;
  	const sg_io_hdr_t *hp;
  	const char * cp;
cb59e8408   Douglas Gilbert   [PATCH] sg.c: update
2621
  	unsigned int ms;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2622

3442f802a   FUJITA Tomonori   [SCSI] sg: remove...
2623
2624
2625
  	k = 0;
  	list_for_each_entry(fp, &sdp->sfds, sfd_siblings) {
  		k++;
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
2626
  		read_lock(&fp->rq_list_lock); /* irqs already disabled */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2627
  		seq_printf(s, "   FD(%d): timeout=%dms bufflen=%d "
3442f802a   FUJITA Tomonori   [SCSI] sg: remove...
2628
2629
  			   "(res)sgat=%d low_dma=%d
  ", k,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2630
2631
2632
  			   jiffies_to_msecs(fp->timeout),
  			   fp->reserve.bufflen,
  			   (int) fp->reserve.k_use_sg,
745dfa0d8   Hannes Reinecke   scsi: sg: disable...
2633
  			   (int) sdp->device->host->unchecked_isa_dma);
ebaf466be   Jörn Engel   [SCSI] sg: remove...
2634
2635
  		seq_printf(s, "   cmd_q=%d f_packid=%d k_orphan=%d closed=0
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2636
  			   (int) fp->cmd_q, (int) fp->force_packid,
ebaf466be   Jörn Engel   [SCSI] sg: remove...
2637
  			   (int) fp->keep_orphan);
109bade9c   Hannes Reinecke   scsi: sg: use sta...
2638
  		list_for_each_entry(srp, &fp->rq_list, entry) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2639
2640
2641
  			hp = &srp->header;
  			new_interface = (hp->interface_id == '\0') ? 0 : 1;
  			if (srp->res_used) {
109bade9c   Hannes Reinecke   scsi: sg: use sta...
2642
  				if (new_interface &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
  				    (SG_FLAG_MMAP_IO & hp->flags))
  					cp = "     mmap>> ";
  				else
  					cp = "     rb>> ";
  			} else {
  				if (SG_INFO_DIRECT_IO_MASK & hp->info)
  					cp = "     dio>> ";
  				else
  					cp = "     ";
  			}
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
2653
  			seq_puts(s, cp);
d6b10348f   Mike Christie   [SCSI] convert sg...
2654
2655
  			blen = srp->data.bufflen;
  			usg = srp->data.k_use_sg;
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
2656
2657
2658
  			seq_puts(s, srp->done ?
  				 ((1 == srp->done) ?  "rcv:" : "fin:")
  				  : "act:");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2659
2660
2661
2662
  			seq_printf(s, " id=%d blen=%d",
  				   srp->header.pack_id, blen);
  			if (srp->done)
  				seq_printf(s, " dur=%d", hp->duration);
cb59e8408   Douglas Gilbert   [PATCH] sg.c: update
2663
2664
  			else {
  				ms = jiffies_to_msecs(jiffies);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2665
  				seq_printf(s, " t_o/elap=%d/%d",
cb59e8408   Douglas Gilbert   [PATCH] sg.c: update
2666
2667
2668
2669
  					(new_interface ? hp->timeout :
  						  jiffies_to_msecs(fp->timeout)),
  					(ms > hp->duration ? ms - hp->duration : 0));
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2670
2671
2672
2673
  			seq_printf(s, "ms sgat=%d op=0x%02x
  ", usg,
  				   (int) srp->data.cmd_opcode);
  		}
109bade9c   Hannes Reinecke   scsi: sg: use sta...
2674
  		if (list_empty(&fp->rq_list))
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
2675
2676
  			seq_puts(s, "     No requests active
  ");
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
2677
  		read_unlock(&fp->rq_list_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
  	}
  }
  
  static int sg_proc_open_debug(struct inode *inode, struct file *file)
  {
          return seq_open(file, &debug_seq_ops);
  }
  
  static int sg_proc_seq_show_debug(struct seq_file *s, void *v)
  {
  	struct sg_proc_deviter * it = (struct sg_proc_deviter *) v;
  	Sg_device *sdp;
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
2690
  	unsigned long iflags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2691

cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
2692
2693
2694
2695
  	if (it && (0 == it->index))
  		seq_printf(s, "max_active_device=%d  def_reserved_size=%d
  ",
  			   (int)it->max, sg_big_buff);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2696

c6517b794   Tony Battersby   [SCSI] sg: fix ra...
2697
2698
  	read_lock_irqsave(&sg_index_lock, iflags);
  	sdp = it ? sg_lookup_dev(it->index) : NULL;
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
2699
2700
2701
2702
  	if (NULL == sdp)
  		goto skip;
  	read_lock(&sdp->sfd_lock);
  	if (!list_empty(&sdp->sfds)) {
c0d3b9c29   James Bottomley   [SCSI] Revert "sg...
2703
  		seq_printf(s, " >>> device=%s ", sdp->disk->disk_name);
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
2704
2705
2706
2707
  		if (atomic_read(&sdp->detaching))
  			seq_puts(s, "detaching pending close ");
  		else if (sdp->device) {
  			struct scsi_device *scsidp = sdp->device;
9cb78c16f   Hannes Reinecke   scsi: use 64-bit ...
2708
  			seq_printf(s, "%d:%d:%d:%llu   em=%d",
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
2709
2710
2711
2712
2713
2714
2715
2716
  				   scsidp->host->host_no,
  				   scsidp->channel, scsidp->id,
  				   scsidp->lun,
  				   scsidp->host->hostt->emulated);
  		}
  		seq_printf(s, " sg_tablesize=%d excl=%d open_cnt=%d
  ",
  			   sdp->sg_tablesize, sdp->exclude, sdp->open_cnt);
c0d3b9c29   James Bottomley   [SCSI] Revert "sg...
2717
  		sg_proc_debug_helper(s, sdp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2718
  	}
cc833acbe   Douglas Gilbert   sg: O_EXCL and ot...
2719
2720
  	read_unlock(&sdp->sfd_lock);
  skip:
c6517b794   Tony Battersby   [SCSI] sg: fix ra...
2721
  	read_unlock_irqrestore(&sg_index_lock, iflags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2722
2723
2724
2725
2726
2727
2728
  	return 0;
  }
  
  #endif				/* CONFIG_SCSI_PROC_FS */
  
  module_init(init_sg);
  module_exit(exit_sg);