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