Blame view

drivers/scsi/scsi_ioctl.c 9.14 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  /*
   * Changes:
   * Arnaldo Carvalho de Melo <acme@conectiva.com.br> 08/23/2000
   * - get rid of some verify_areas and use __copy*user and __get/put_user
   *   for the ones that remain
   */
  #include <linux/module.h>
  #include <linux/blkdev.h>
  #include <linux/interrupt.h>
  #include <linux/errno.h>
  #include <linux/kernel.h>
  #include <linux/sched.h>
  #include <linux/mm.h>
  #include <linux/string.h>
  #include <asm/uaccess.h>
  
  #include <scsi/scsi.h>
beb404875   Christoph Hellwig   [SCSI] remove scs...
18
  #include <scsi/scsi_cmnd.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
20
21
22
  #include <scsi/scsi_device.h>
  #include <scsi/scsi_eh.h>
  #include <scsi/scsi_host.h>
  #include <scsi/scsi_ioctl.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
25
26
27
28
29
  #include <scsi/sg.h>
  #include <scsi/scsi_dbg.h>
  
  #include "scsi_logging.h"
  
  #define NORMAL_RETRIES			5
  #define IOCTL_NORMAL_TIMEOUT			(10 * HZ)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
31
  
  #define MAX_BUF PAGE_SIZE
32993523d   Christoph Hellwig   [SCSI] fix SCSI_I...
32
33
34
35
36
37
38
  /**
   * ioctl_probe  --  return host identification
   * @host:	host to identify
   * @buffer:	userspace buffer for identification
   *
   * Return an identifying string at @buffer, if @buffer is non-NULL, filling
   * to the length stored at * (int *) @buffer.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
41
42
43
  static int ioctl_probe(struct Scsi_Host *host, void __user *buffer)
  {
  	unsigned int len, slen;
  	const char *string;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44

32993523d   Christoph Hellwig   [SCSI] fix SCSI_I...
45
  	if (buffer) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
  		if (get_user(len, (unsigned int __user *) buffer))
  			return -EFAULT;
  
  		if (host->hostt->info)
  			string = host->hostt->info(host);
  		else
  			string = host->hostt->name;
  		if (string) {
  			slen = strlen(string);
  			if (len > slen)
  				len = slen + 1;
  			if (copy_to_user(buffer, string, len))
  				return -EFAULT;
  		}
  	}
32993523d   Christoph Hellwig   [SCSI] fix SCSI_I...
61
  	return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
  }
  
  /*
  
   * The SCSI_IOCTL_SEND_COMMAND ioctl sends a command out to the SCSI host.
   * The IOCTL_NORMAL_TIMEOUT and NORMAL_RETRIES  variables are used.  
   * 
   * dev is the SCSI device struct ptr, *(int *) arg is the length of the
   * input data, if any, not including the command string & counts, 
   * *((int *)arg + 1) is the output buffer size in bytes.
   * 
   * *(char *) ((int *) arg)[2] the actual command byte.   
   * 
   * Note that if more than MAX_BUF bytes are requested to be transferred,
   * the ioctl will fail with error EINVAL.
   * 
   * This size *does not* include the initial lengths that were passed.
   * 
   * The SCSI command is read from the memory location immediately after the
   * length words, and the input data is right after the command.  The SCSI
   * routines know the command size based on the opcode decode.  
   * 
   * The output area is then filled in starting from the command byte. 
   */
  
  static int ioctl_internal_command(struct scsi_device *sdev, char *cmd,
  				  int timeout, int retries)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90
91
92
93
94
  	int result;
  	struct scsi_sense_hdr sshdr;
  
  	SCSI_LOG_IOCTL(1, printk("Trying ioctl with scsi command %d
  ", *cmd));
1cf72699c   James Bottomley   [SCSI] convert th...
95
  	result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0,
f4f4e47e4   FUJITA Tomonori   [SCSI] add residu...
96
  				  &sshdr, timeout, retries, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97

1cf72699c   James Bottomley   [SCSI] convert th...
98
99
  	SCSI_LOG_IOCTL(2, printk("Ioctl returned  0x%x
  ", result));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100

1cf72699c   James Bottomley   [SCSI] convert th...
101
  	if ((driver_byte(result) & DRIVER_SENSE) &&
ea73a9f23   James Bottomley   [SCSI] convert sd...
102
  	    (scsi_sense_valid(&sshdr))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
104
105
106
107
108
109
110
111
112
113
  		switch (sshdr.sense_key) {
  		case ILLEGAL_REQUEST:
  			if (cmd[0] == ALLOW_MEDIUM_REMOVAL)
  				sdev->lockable = 0;
  			else
  				printk(KERN_INFO "ioctl_internal_command: "
  				       "ILLEGAL REQUEST asc=0x%x ascq=0x%x
  ",
  				       sshdr.asc, sshdr.ascq);
  			break;
  		case NOT_READY:	/* This happens if there is no disc in drive */
a75ad3c27   Jens Axboe   [PATCH] scsi: kil...
114
  			if (sdev->removable)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
  				break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
117
118
  		case UNIT_ATTENTION:
  			if (sdev->removable) {
  				sdev->changed = 1;
1cf72699c   James Bottomley   [SCSI] convert th...
119
  				result = 0;	/* This is no longer considered an error */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120
121
122
  				break;
  			}
  		default:	/* Fall through for non-removable media */
9ccfc756a   James Bottomley   [SCSI] move the m...
123
124
125
126
  			sdev_printk(KERN_INFO, sdev,
  				    "ioctl_internal_command return code = %x
  ",
  				    result);
ea73a9f23   James Bottomley   [SCSI] convert sd...
127
  			scsi_print_sense_hdr("   ", &sshdr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128
129
130
  			break;
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
132
  	SCSI_LOG_IOCTL(2, printk("IOCTL Releasing command
  "));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
  	return result;
  }
  
  int scsi_set_medium_removal(struct scsi_device *sdev, char state)
  {
  	char scsi_cmd[MAX_COMMAND_SIZE];
  	int ret;
  
  	if (!sdev->removable || !sdev->lockable)
  	       return 0;
  
  	scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
  	scsi_cmd[1] = 0;
  	scsi_cmd[2] = 0;
  	scsi_cmd[3] = 0;
  	scsi_cmd[4] = state;
  	scsi_cmd[5] = 0;
  
  	ret = ioctl_internal_command(sdev, scsi_cmd,
  			IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES);
  	if (ret == 0)
  		sdev->locked = (state == SCSI_REMOVAL_PREVENT);
  	return ret;
  }
  EXPORT_SYMBOL(scsi_set_medium_removal);
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
161
162
163
164
165
166
167
168
169
170
171
   * The scsi_ioctl_get_pci() function places into arg the value
   * pci_dev::slot_name (8 characters) for the PCI device (if any).
   * Returns: 0 on success
   *          -ENXIO if there isn't a PCI device pointer
   *                 (could be because the SCSI driver hasn't been
   *                  updated yet, or because it isn't a SCSI
   *                  device)
   *          any copy_to_user() error on failure there
   */
  static int scsi_ioctl_get_pci(struct scsi_device *sdev, void __user *arg)
  {
  	struct device *dev = scsi_get_device(sdev->host);
71610f55f   Kay Sievers   [SCSI] struct dev...
172
  	const char *name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
174
175
  
          if (!dev)
  		return -ENXIO;
71610f55f   Kay Sievers   [SCSI] struct dev...
176
177
178
179
180
181
182
  
  	name = dev_name(dev);
  
  	/* compatibility with old ioctl which only returned
  	 * 20 characters */
          return copy_to_user(arg, name, min(strlen(name), (size_t)20))
  		? -EFAULT: 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
183
  }
eb44820c2   Rob Landley   [SCSI] Add Docume...
184
185
186
187
188
189
190
191
192
  /**
   * scsi_ioctl - Dispatch ioctl to scsi device
   * @sdev: scsi device receiving ioctl
   * @cmd: which ioctl is it
   * @arg: data associated with ioctl
   *
   * Description: The scsi_ioctl() function differs from most ioctls in that it
   * does not take a major/minor number as the dev field.  Rather, it takes
   * a pointer to a &struct scsi_device.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193
194
195
196
197
198
199
200
201
202
203
204
205
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
234
235
236
237
238
239
240
241
242
243
244
245
246
247
   */
  int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
  {
  	char scsi_cmd[MAX_COMMAND_SIZE];
  
  	/* No idea how this happens.... */
  	if (!sdev)
  		return -ENXIO;
  
  	/*
  	 * If we are in the middle of error recovery, don't let anyone
  	 * else try and use this device.  Also, if error recovery fails, it
  	 * may try and take the device offline, in which case all further
  	 * access to the device is prohibited.
  	 */
  	if (!scsi_block_when_processing_errors(sdev))
  		return -ENODEV;
  
  	/* Check for deprecated ioctls ... all the ioctls which don't
  	 * follow the new unique numbering scheme are deprecated */
  	switch (cmd) {
  	case SCSI_IOCTL_SEND_COMMAND:
  	case SCSI_IOCTL_TEST_UNIT_READY:
  	case SCSI_IOCTL_BENCHMARK_COMMAND:
  	case SCSI_IOCTL_SYNC:
  	case SCSI_IOCTL_START_UNIT:
  	case SCSI_IOCTL_STOP_UNIT:
  		printk(KERN_WARNING "program %s is using a deprecated SCSI "
  		       "ioctl, please convert it to SG_IO
  ", current->comm);
  		break;
  	default:
  		break;
  	}
  
  	switch (cmd) {
  	case SCSI_IOCTL_GET_IDLUN:
  		if (!access_ok(VERIFY_WRITE, arg, sizeof(struct scsi_idlun)))
  			return -EFAULT;
  
  		__put_user((sdev->id & 0xff)
  			 + ((sdev->lun & 0xff) << 8)
  			 + ((sdev->channel & 0xff) << 16)
  			 + ((sdev->host->host_no & 0xff) << 24),
  			 &((struct scsi_idlun __user *)arg)->dev_id);
  		__put_user(sdev->host->unique_id,
  			 &((struct scsi_idlun __user *)arg)->host_unique_id);
  		return 0;
  	case SCSI_IOCTL_GET_BUS_NUMBER:
  		return put_user(sdev->host->host_no, (int __user *)arg);
  	case SCSI_IOCTL_PROBE_HOST:
  		return ioctl_probe(sdev->host, arg);
  	case SCSI_IOCTL_SEND_COMMAND:
  		if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
  			return -EACCES;
e915e872e   Al Viro   [PATCH] switch sg...
248
  		return sg_scsi_ioctl(sdev->request_queue, NULL, 0, arg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
250
251
252
253
254
  	case SCSI_IOCTL_DOORLOCK:
  		return scsi_set_medium_removal(sdev, SCSI_REMOVAL_PREVENT);
  	case SCSI_IOCTL_DOORUNLOCK:
  		return scsi_set_medium_removal(sdev, SCSI_REMOVAL_ALLOW);
  	case SCSI_IOCTL_TEST_UNIT_READY:
  		return scsi_test_unit_ready(sdev, IOCTL_NORMAL_TIMEOUT,
001aac257   James Bottomley   [SCSI] sd,sr: add...
255
  					    NORMAL_RETRIES, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
  	case SCSI_IOCTL_START_UNIT:
  		scsi_cmd[0] = START_STOP;
  		scsi_cmd[1] = 0;
  		scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
  		scsi_cmd[4] = 1;
  		return ioctl_internal_command(sdev, scsi_cmd,
  				     START_STOP_TIMEOUT, NORMAL_RETRIES);
  	case SCSI_IOCTL_STOP_UNIT:
  		scsi_cmd[0] = START_STOP;
  		scsi_cmd[1] = 0;
  		scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
  		scsi_cmd[4] = 0;
  		return ioctl_internal_command(sdev, scsi_cmd,
  				     START_STOP_TIMEOUT, NORMAL_RETRIES);
          case SCSI_IOCTL_GET_PCI:
                  return scsi_ioctl_get_pci(sdev, arg);
  	default:
  		if (sdev->host->hostt->ioctl)
  			return sdev->host->hostt->ioctl(sdev, cmd, arg);
  	}
  	return -EINVAL;
  }
  EXPORT_SYMBOL(scsi_ioctl);
eb44820c2   Rob Landley   [SCSI] Add Docume...
279
  /**
decf67e31   Randy Dunlap   [SCSI] scsi ioctl...
280
   * scsi_nonblockable_ioctl() - Handle SG_SCSI_RESET
eb44820c2   Rob Landley   [SCSI] Add Docume...
281
282
283
   * @sdev: scsi device receiving ioctl
   * @cmd: Must be SC_SCSI_RESET
   * @arg: pointer to int containing SG_SCSI_RESET_{DEVICE,BUS,HOST}
decf67e31   Randy Dunlap   [SCSI] scsi ioctl...
284
   * @ndelay: file mode O_NDELAY flag
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
286
   */
  int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd,
83ff6fe85   Al Viro   [PATCH] don't mes...
287
  			    void __user *arg, int ndelay)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288
289
290
291
292
293
  {
  	int val, result;
  
  	/* The first set of iocts may be executed even if we're doing
  	 * error processing, as long as the device was opened
  	 * non-blocking */
83ff6fe85   Al Viro   [PATCH] don't mes...
294
  	if (ndelay) {
939647ee3   James Bottomley   [SCSI] fix oops o...
295
  		if (scsi_host_in_recovery(sdev->host))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
  			return -ENODEV;
  	} else if (!scsi_block_when_processing_errors(sdev))
  		return -ENODEV;
  
  	switch (cmd) {
  	case SG_SCSI_RESET:
  		result = get_user(val, (int __user *)arg);
  		if (result)
  			return result;
  		if (val == SG_SCSI_RESET_NOTHING)
  			return 0;
  		switch (val) {
  		case SG_SCSI_RESET_DEVICE:
  			val = SCSI_TRY_RESET_DEVICE;
  			break;
3f9daedfc   Mike Christie   [SCSI] add scsi t...
311
312
313
  		case SG_SCSI_RESET_TARGET:
  			val = SCSI_TRY_RESET_TARGET;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
  		case SG_SCSI_RESET_BUS:
  			val = SCSI_TRY_RESET_BUS;
  			break;
  		case SG_SCSI_RESET_HOST:
  			val = SCSI_TRY_RESET_HOST;
  			break;
  		default:
  			return -EINVAL;
  		}
  		if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
  			return -EACCES;
  		return (scsi_reset_provider(sdev, val) ==
  			SUCCESS) ? 0 : -EIO;
  	}
  	return -ENODEV;
  }
  EXPORT_SYMBOL(scsi_nonblockable_ioctl);