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->rq_status = RQ_SCSI_DONE;
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.rq_status != RQ_SCSI_DONE){
121 struct semaphore sem = MUTEX_LOCKED;
122 SCpnt->request.sem = &sem;
123 down(&sem);
124
125 while (SCpnt->request.rq_status != RQ_SCSI_DONE)
126 schedule();
127 };
128
129 if(driver_byte(SCpnt->result) != 0)
130 switch(SCpnt->sense_buffer[2] & 0xf) {
131 case ILLEGAL_REQUEST:
132 if(cmd[0] == ALLOW_MEDIUM_REMOVAL) dev->lockable = 0;
133 else printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n");
134 break;
135 case NOT_READY:
136 if(dev->removable){
137 printk("Device not ready. Make sure there is a disc in the drive.\n");
138 break;
139 };
140 case UNIT_ATTENTION:
141 if (dev->removable){
142 dev->changed = 1;
143 SCpnt->result = 0;
144 printk("Disc change detected.\n");
145 break;
146 };
147 default:
148 printk("SCSI error: host %d id %d lun %d return code = %x\n",
149 dev->host->host_no,
150 dev->id,
151 dev->lun,
152 SCpnt->result);
153 printk("\tSense class %x, sense error %x, extended sense %x\n",
154 sense_class(SCpnt->sense_buffer[0]),
155 sense_error(SCpnt->sense_buffer[0]),
156 SCpnt->sense_buffer[2] & 0xf);
157
158 };
159
160 result = SCpnt->result;
161 SCpnt->request.rq_status = RQ_INACTIVE;
162 wake_up(&SCpnt->device->device_wait);
163 return result;
164 }
165
166
167
168
169
170
171 static int ioctl_command(Scsi_Device *dev, void *buffer)
172 {
173 char * buf;
174 char cmd[12];
175 char * cmd_in;
176 Scsi_Cmnd * SCpnt;
177 unsigned char opcode;
178 int inlen, outlen, cmdlen;
179 int needed, buf_needed;
180 int result;
181
182 if (!buffer)
183 return -EINVAL;
184
185
186
187
188
189 result = verify_area(VERIFY_READ, buffer, 2*sizeof(long) + 1);
190 if (result) return result;
191
192
193
194
195
196
197
198
199
200
201 inlen = get_user((unsigned int *) buffer);
202 outlen = get_user( ((unsigned int *) buffer) + 1);
203
204
205
206
207
208
209 if( inlen > MAX_BUF ) inlen = MAX_BUF;
210 if( outlen > MAX_BUF ) outlen = MAX_BUF;
211
212 cmd_in = (char *) ( ((int *)buffer) + 2);
213 opcode = get_user(cmd_in);
214
215 needed = buf_needed = (inlen > outlen ? inlen : outlen);
216 if(buf_needed){
217 buf_needed = (buf_needed + 511) & ~511;
218 if (buf_needed > MAX_BUF) buf_needed = MAX_BUF;
219 buf = (char *) scsi_malloc(buf_needed);
220 if (!buf) return -ENOMEM;
221 memset(buf, 0, buf_needed);
222 } else
223 buf = NULL;
224
225
226
227
228 cmdlen = COMMAND_SIZE(opcode);
229
230 result = verify_area(VERIFY_READ, cmd_in,
231 cmdlen + inlen > MAX_BUF ? MAX_BUF : inlen);
232 if (result) return result;
233
234 memcpy_fromfs ((void *) cmd, cmd_in, cmdlen);
235
236
237
238
239 memcpy_fromfs ((void *) buf,
240 (void *) (cmd_in + cmdlen),
241 inlen);
242
243
244
245
246 cmd[1] = ( cmd[1] & 0x1f ) | (dev->lun << 5);
247
248 #ifndef DEBUG_NO_CMD
249
250 SCpnt = allocate_device(NULL, dev, 1);
251
252 scsi_do_cmd(SCpnt, cmd, buf, needed, scsi_ioctl_done, MAX_TIMEOUT,
253 MAX_RETRIES);
254
255 if (SCpnt->request.rq_status != RQ_SCSI_DONE){
256 struct semaphore sem = MUTEX_LOCKED;
257 SCpnt->request.sem = &sem;
258 down(&sem);
259
260 while (SCpnt->request.rq_status != RQ_SCSI_DONE)
261 schedule();
262 }
263
264
265
266
267
268 if(SCpnt->result) {
269 result = verify_area(VERIFY_WRITE,
270 cmd_in,
271 sizeof(SCpnt->sense_buffer));
272 if (result) return result;
273 memcpy_tofs((void *) cmd_in,
274 SCpnt->sense_buffer,
275 sizeof(SCpnt->sense_buffer));
276 } else {
277 result = verify_area(VERIFY_WRITE, cmd_in, outlen);
278 if (result) return result;
279 memcpy_tofs ((void *) cmd_in, buf, outlen);
280 }
281 result = SCpnt->result;
282
283 SCpnt->request.rq_status = RQ_INACTIVE;
284
285 if (buf) scsi_free(buf, buf_needed);
286
287 if(SCpnt->device->scsi_request_fn)
288 (*SCpnt->device->scsi_request_fn)();
289
290 wake_up(&SCpnt->device->device_wait);
291 return result;
292 #else
293 {
294 int i;
295 printk("scsi_ioctl : device %d. command = ", dev->id);
296 for (i = 0; i < 12; ++i)
297 printk("%02x ", cmd[i]);
298 printk("\nbuffer =");
299 for (i = 0; i < 20; ++i)
300 printk("%02x ", buf[i]);
301 printk("\n");
302 printk("inlen = %d, outlen = %d, cmdlen = %d\n",
303 inlen, outlen, cmdlen);
304 printk("buffer = %d, cmd_in = %d\n", buffer, cmd_in);
305 }
306 return 0;
307 #endif
308 }
309
310
311
312
313
314
315 int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
316 {
317 int result;
318 char scsi_cmd[12];
319
320
321 if (!dev) return -ENXIO;
322
323 switch (cmd) {
324 case SCSI_IOCTL_GET_IDLUN:
325 result = verify_area(VERIFY_WRITE, (void *) arg, 2*sizeof(long));
326 if (result) return result;
327
328 put_user(dev->id
329 + (dev->lun << 8)
330 + (dev->channel << 16)
331 + ((dev->host->hostt->proc_dir->low_ino & 0xff) << 24),
332 (unsigned long *) arg);
333 put_user( dev->host->unique_id, (unsigned long *) arg+1);
334 return 0;
335 case SCSI_IOCTL_TAGGED_ENABLE:
336 if(!suser()) return -EACCES;
337 if(!dev->tagged_supported) return -EINVAL;
338 dev->tagged_queue = 1;
339 dev->current_tag = 1;
340 break;
341 case SCSI_IOCTL_TAGGED_DISABLE:
342 if(!suser()) return -EACCES;
343 if(!dev->tagged_supported) return -EINVAL;
344 dev->tagged_queue = 0;
345 dev->current_tag = 0;
346 break;
347 case SCSI_IOCTL_PROBE_HOST:
348 return ioctl_probe(dev->host, arg);
349 case SCSI_IOCTL_SEND_COMMAND:
350 if(!suser()) return -EACCES;
351 return ioctl_command((Scsi_Device *) dev, arg);
352 case SCSI_IOCTL_DOORLOCK:
353 if (!dev->removable || !dev->lockable) return 0;
354 scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
355 scsi_cmd[1] = dev->lun << 5;
356 scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
357 scsi_cmd[4] = SCSI_REMOVAL_PREVENT;
358 return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd);
359 break;
360 case SCSI_IOCTL_DOORUNLOCK:
361 if (!dev->removable || !dev->lockable) return 0;
362 scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
363 scsi_cmd[1] = dev->lun << 5;
364 scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
365 scsi_cmd[4] = SCSI_REMOVAL_ALLOW;
366 return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd);
367 case SCSI_IOCTL_TEST_UNIT_READY:
368 scsi_cmd[0] = TEST_UNIT_READY;
369 scsi_cmd[1] = dev->lun << 5;
370 scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
371 scsi_cmd[4] = 0;
372 return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd);
373 break;
374 default :
375 return -EINVAL;
376 }
377 return -EINVAL;
378 }
379
380
381
382
383
384
385 int kernel_scsi_ioctl (Scsi_Device *dev, int cmd, void *arg) {
386 unsigned long oldfs;
387 int tmp;
388 oldfs = get_fs();
389 set_fs(get_ds());
390 tmp = scsi_ioctl (dev, cmd, arg);
391 set_fs(oldfs);
392 return tmp;
393 }
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412