This source file includes following definitions.
- ioctl_probe
- scsi_ioctl_done
- ioctl_internal_command
- ioctl_command
- scsi_ioctl
- kernel_scsi_ioctl
1 #ifdef MODULE
2
3
4
5
6 #define _SCSI_SYMS_VER_
7 #include <linux/autoconf.h>
8 #include <linux/module.h>
9 #include <linux/version.h>
10 #else
11 #define MOD_INC_USE_COUNT
12 #define MOD_DEC_USE_COUNT
13 #endif
14
15 #include <asm/io.h>
16 #include <asm/segment.h>
17 #include <asm/system.h>
18
19 #include <linux/errno.h>
20 #include <linux/kernel.h>
21 #include <linux/sched.h>
22 #include <linux/mm.h>
23 #include <linux/string.h>
24
25 #include "../block/blk.h"
26 #include "scsi.h"
27 #include "hosts.h"
28 #include "scsi_ioctl.h"
29
30 #define MAX_RETRIES 5
31 #define MAX_TIMEOUT 900
32 #define MAX_BUF 4096
33
34 #define max(a,b) (((a) > (b)) ? (a) : (b))
35
36
37
38
39
40
41
42
43 static int ioctl_probe(struct Scsi_Host * host, void *buffer)
44 {
45 int temp, result;
46 unsigned int len,slen;
47 const char * string;
48
49 if ((temp = host->hostt->present) && buffer) {
50 result = verify_area(VERIFY_READ, buffer, sizeof(long));
51 if (result) return result;
52
53 len = get_user ((unsigned int *) buffer);
54 if(host->hostt->info)
55 string = host->hostt->info(host);
56 else
57 string = host->hostt->name;
58 if(string) {
59 slen = strlen(string);
60 if (len > slen)
61 len = slen + 1;
62 result = verify_area(VERIFY_WRITE, buffer, len);
63 if (result) return result;
64
65 memcpy_tofs (buffer, string, len);
66 }
67 }
68 return temp;
69 }
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98 static void scsi_ioctl_done (Scsi_Cmnd * SCpnt)
99 {
100 struct request * req;
101
102 req = &SCpnt->request;
103 req->dev = 0xfffe;
104
105 if (req->sem != NULL) {
106 up(req->sem);
107 }
108 }
109
110 static int ioctl_internal_command(Scsi_Device *dev, char * cmd)
111 {
112 int result;
113 Scsi_Cmnd * SCpnt;
114
115 SCpnt = allocate_device(NULL, dev, 1);
116 scsi_do_cmd(SCpnt, cmd, NULL, 0,
117 scsi_ioctl_done, MAX_TIMEOUT,
118 MAX_RETRIES);
119
120 if (SCpnt->request.dev != 0xfffe){
121 struct semaphore sem = MUTEX_LOCKED;
122 SCpnt->request.sem = &sem;
123 down(&sem);
124
125 while (SCpnt->request.dev != 0xfffe) schedule();
126 };
127
128 if(driver_byte(SCpnt->result) != 0)
129 switch(SCpnt->sense_buffer[2] & 0xf) {
130 case ILLEGAL_REQUEST:
131 if(cmd[0] == ALLOW_MEDIUM_REMOVAL) dev->lockable = 0;
132 else printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n");
133 break;
134 case NOT_READY:
135 if(dev->removable){
136 printk("Device not ready. Make sure there is a disc in the drive.\n");
137 break;
138 };
139 case UNIT_ATTENTION:
140 if (dev->removable){
141 dev->changed = 1;
142 SCpnt->result = 0;
143 printk("Disc change detected.\n");
144 break;
145 };
146 default:
147 printk("SCSI error: host %d id %d lun %d return code = %x\n",
148 dev->host->host_no,
149 dev->id,
150 dev->lun,
151 SCpnt->result);
152 printk("\tSense class %x, sense error %x, extended sense %x\n",
153 sense_class(SCpnt->sense_buffer[0]),
154 sense_error(SCpnt->sense_buffer[0]),
155 SCpnt->sense_buffer[2] & 0xf);
156
157 };
158
159 result = SCpnt->result;
160 SCpnt->request.dev = -1;
161 wake_up(&SCpnt->device->device_wait);
162 return result;
163 }
164
165
166
167
168
169
170 static int ioctl_command(Scsi_Device *dev, void *buffer)
171 {
172 char * buf;
173 char cmd[12];
174 char * cmd_in;
175 Scsi_Cmnd * SCpnt;
176 unsigned char opcode;
177 int inlen, outlen, cmdlen;
178 int needed, buf_needed;
179 int result;
180
181 if (!buffer)
182 return -EINVAL;
183
184
185
186
187
188 result = verify_area(VERIFY_READ, buffer, 2*sizeof(long) + 1);
189 if (result) return result;
190
191
192
193
194
195
196
197
198
199
200 inlen = get_user((unsigned int *) buffer);
201 outlen = get_user( ((unsigned int *) buffer) + 1);
202
203
204
205
206
207
208 if( inlen > MAX_BUF ) inlen = MAX_BUF;
209 if( outlen > MAX_BUF ) outlen = MAX_BUF;
210
211 cmd_in = (char *) ( ((int *)buffer) + 2);
212 opcode = get_user(cmd_in);
213
214 needed = buf_needed = (inlen > outlen ? inlen : outlen);
215 if(buf_needed){
216 buf_needed = (buf_needed + 511) & ~511;
217 if (buf_needed > MAX_BUF) buf_needed = MAX_BUF;
218 buf = (char *) scsi_malloc(buf_needed);
219 if (!buf) return -ENOMEM;
220 memset(buf, 0, buf_needed);
221 } else
222 buf = NULL;
223
224
225
226
227 cmdlen = COMMAND_SIZE(opcode);
228
229 result = verify_area(VERIFY_READ, cmd_in,
230 cmdlen + inlen > MAX_BUF ? MAX_BUF : inlen);
231 if (result) return result;
232
233 memcpy_fromfs ((void *) cmd, cmd_in, cmdlen);
234
235
236
237
238 memcpy_fromfs ((void *) buf,
239 (void *) (cmd_in + cmdlen),
240 inlen);
241
242
243
244
245 cmd[1] = ( cmd[1] & 0x1f ) | (dev->lun << 5);
246
247 #ifndef DEBUG_NO_CMD
248
249 SCpnt = allocate_device(NULL, dev, 1);
250
251 scsi_do_cmd(SCpnt, cmd, buf, needed, scsi_ioctl_done, MAX_TIMEOUT,
252 MAX_RETRIES);
253
254 if (SCpnt->request.dev != 0xfffe){
255 struct semaphore sem = MUTEX_LOCKED;
256 SCpnt->request.sem = &sem;
257 down(&sem);
258
259 while (SCpnt->request.dev != 0xfffe) schedule();
260 }
261
262
263
264
265
266 if(SCpnt->result) {
267 result = verify_area(VERIFY_WRITE,
268 cmd_in,
269 sizeof(SCpnt->sense_buffer));
270 if (result) return result;
271 memcpy_tofs((void *) cmd_in,
272 SCpnt->sense_buffer,
273 sizeof(SCpnt->sense_buffer));
274 } else {
275 result = verify_area(VERIFY_WRITE, cmd_in, outlen);
276 if (result) return result;
277 memcpy_tofs ((void *) cmd_in, buf, outlen);
278 }
279 result = SCpnt->result;
280 SCpnt->request.dev = -1;
281 if (buf) scsi_free(buf, buf_needed);
282
283 if(SCpnt->device->scsi_request_fn)
284 (*SCpnt->device->scsi_request_fn)();
285
286 wake_up(&SCpnt->device->device_wait);
287 return result;
288 #else
289 {
290 int i;
291 printk("scsi_ioctl : device %d. command = ", dev->id);
292 for (i = 0; i < 12; ++i)
293 printk("%02x ", cmd[i]);
294 printk("\nbuffer =");
295 for (i = 0; i < 20; ++i)
296 printk("%02x ", buf[i]);
297 printk("\n");
298 printk("inlen = %d, outlen = %d, cmdlen = %d\n",
299 inlen, outlen, cmdlen);
300 printk("buffer = %d, cmd_in = %d\n", buffer, cmd_in);
301 }
302 return 0;
303 #endif
304 }
305
306
307
308
309
310
311 int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
312 {
313 int result;
314 char scsi_cmd[12];
315
316
317 if (!dev) return -ENXIO;
318
319 switch (cmd) {
320 case SCSI_IOCTL_GET_IDLUN:
321 result = verify_area(VERIFY_WRITE, (void *) arg, 2*sizeof(long));
322 if (result) return result;
323
324 put_user(dev->id
325 + (dev->lun << 8)
326 + (dev->channel << 16)
327 + ((dev->host->hostt->low_ino & 0xff) << 24),
328 (unsigned long *) arg);
329 put_user( dev->host->unique_id, (unsigned long *) arg+1);
330 return 0;
331 case SCSI_IOCTL_TAGGED_ENABLE:
332 if(!suser()) return -EACCES;
333 if(!dev->tagged_supported) return -EINVAL;
334 dev->tagged_queue = 1;
335 dev->current_tag = 1;
336 break;
337 case SCSI_IOCTL_TAGGED_DISABLE:
338 if(!suser()) return -EACCES;
339 if(!dev->tagged_supported) return -EINVAL;
340 dev->tagged_queue = 0;
341 dev->current_tag = 0;
342 break;
343 case SCSI_IOCTL_PROBE_HOST:
344 return ioctl_probe(dev->host, arg);
345 case SCSI_IOCTL_SEND_COMMAND:
346 if(!suser()) return -EACCES;
347 return ioctl_command((Scsi_Device *) dev, arg);
348 case SCSI_IOCTL_DOORLOCK:
349 if (!dev->removable || !dev->lockable) return 0;
350 scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
351 scsi_cmd[1] = dev->lun << 5;
352 scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
353 scsi_cmd[4] = SCSI_REMOVAL_PREVENT;
354 return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd);
355 break;
356 case SCSI_IOCTL_DOORUNLOCK:
357 if (!dev->removable || !dev->lockable) return 0;
358 scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
359 scsi_cmd[1] = dev->lun << 5;
360 scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
361 scsi_cmd[4] = SCSI_REMOVAL_ALLOW;
362 return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd);
363 case SCSI_IOCTL_TEST_UNIT_READY:
364 scsi_cmd[0] = TEST_UNIT_READY;
365 scsi_cmd[1] = dev->lun << 5;
366 scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
367 scsi_cmd[4] = 0;
368 return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd);
369 break;
370 default :
371 return -EINVAL;
372 }
373 return -EINVAL;
374 }
375
376
377
378
379
380
381 int kernel_scsi_ioctl (Scsi_Device *dev, int cmd, void *arg) {
382 unsigned long oldfs;
383 int tmp;
384 oldfs = get_fs();
385 set_fs(get_ds());
386 tmp = scsi_ioctl (dev, cmd, arg);
387 set_fs(oldfs);
388 return tmp;
389 }
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408