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