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