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