This source file includes following definitions.
- ioctl_probe
- scsi_ioctl_done
- ioctl_internal_command
- ioctl_command
- 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 "../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(int dev, void *buffer)
29 {
30 int temp;
31 unsigned int len,slen;
32 const char * string;
33
34 if ((temp = scsi_hosts[dev].present) && buffer) {
35 len = get_fs_long ((int *) buffer);
36 string = scsi_hosts[dev].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 struct task_struct * p;
77
78 req = &SCpnt->request;
79 req->dev = 0xfffe;
80
81 if ((p = req->waiting) != NULL) {
82 req->waiting = NULL;
83 p->state = TASK_RUNNING;
84 if (p->counter > current->counter)
85 need_resched = 1;
86 }
87 }
88
89 static int ioctl_internal_command(Scsi_Device *dev, char * cmd)
90 {
91 int host, result;
92 Scsi_Cmnd * SCpnt;
93
94 host = dev->host_no;
95
96 SCpnt = allocate_device(NULL, dev->index, 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 SCpnt->request.waiting = current;
103 current->state = TASK_UNINTERRUPTIBLE;
104 while (SCpnt->request.dev != 0xfffe) schedule();
105 };
106
107 if(driver_byte(SCpnt->result) != 0)
108 switch(SCpnt->sense_buffer[2] & 0xf) {
109 case ILLEGAL_REQUEST:
110 if(cmd[0] == ALLOW_MEDIUM_REMOVAL) dev->lockable = 0;
111 else printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n");
112 break;
113 case NOT_READY:
114 if(dev->removable){
115 printk("Device not ready. Make sure there is a disc in the drive.\n");
116 break;
117 };
118 case UNIT_ATTENTION:
119 if (dev->removable){
120 dev->changed = 1;
121 SCpnt->result = 0;
122 printk("Disc change detected.\n");
123 break;
124 };
125 default:
126 printk("SCSI CD error: host %d id %d lun %d return code = %x\n",
127 dev->host_no,
128 dev->id,
129 dev->lun,
130 SCpnt->result);
131 printk("\tSense class %x, sense error %x, extended sense %x\n",
132 sense_class(SCpnt->sense_buffer[0]),
133 sense_error(SCpnt->sense_buffer[0]),
134 SCpnt->sense_buffer[2] & 0xf);
135
136 };
137
138 result = SCpnt->result;
139 SCpnt->request.dev = -1;
140 wake_up(&scsi_devices[SCpnt->index].device_wait);
141 return result;
142 }
143
144 static int ioctl_command(Scsi_Device *dev, void *buffer)
145 {
146 char * buf;
147 char cmd[12];
148 char * cmd_in;
149 Scsi_Cmnd * SCpnt;
150 unsigned char opcode;
151 int inlen, outlen, cmdlen, host;
152 int needed;
153 int result;
154
155 if (!buffer)
156 return -EINVAL;
157
158 inlen = get_fs_long((int *) buffer);
159 outlen = get_fs_long( ((int *) buffer) + 1);
160
161 cmd_in = (char *) ( ((int *)buffer) + 2);
162 opcode = get_fs_byte(cmd_in);
163
164 needed = (inlen > outlen ? inlen : outlen);
165 if(needed){
166 needed = (needed + 511) & ~511;
167 if (needed > MAX_BUF) needed = MAX_BUF;
168 buf = scsi_malloc(needed);
169 if (!buf) return -ENOMEM;
170 } else
171 buf = NULL;
172
173 memcpy_fromfs ((void *) cmd, cmd_in, cmdlen = COMMAND_SIZE (opcode));
174 memcpy_fromfs ((void *) buf, (void *) (cmd_in + cmdlen), inlen > MAX_BUF ? MAX_BUF : inlen);
175 host = dev->host_no;
176 cmd[1] = ( cmd[1] & 0x1f ) | (dev->lun << 5);
177
178 #ifndef DEBUG_NO_CMD
179
180 SCpnt = allocate_device(NULL, dev->index, 1);
181
182 scsi_do_cmd(SCpnt, cmd, buf, ((outlen > MAX_BUF) ?
183 MAX_BUF : outlen), scsi_ioctl_done, MAX_TIMEOUT,
184 MAX_RETRIES);
185
186 if (SCpnt->request.dev != 0xfffe){
187 SCpnt->request.waiting = current;
188 current->state = TASK_UNINTERRUPTIBLE;
189 while (SCpnt->request.dev != 0xfffe) schedule();
190 };
191
192 result = verify_area(VERIFY_WRITE, cmd_in, (outlen > MAX_BUF) ? MAX_BUF : outlen);
193 if (result)
194 return result;
195 memcpy_tofs ((void *) cmd_in, buf, (outlen > MAX_BUF) ? MAX_BUF : outlen);
196 result = SCpnt->result;
197 SCpnt->request.dev = -1;
198 if (buf) scsi_free(buf, needed);
199 wake_up(&scsi_devices[SCpnt->index].device_wait);
200 return result;
201 #else
202 {
203 int i;
204 printk("scsi_ioctl : device %d. command = ", dev->id);
205 for (i = 0; i < 10; ++i)
206 printk("%02x ", cmd[i]);
207 printk("\nbuffer =");
208 for (i = 0; i < 20; ++i)
209 printk("%02x ", buf[i]);
210 printk("\n");
211 printk("inlen = %d, outlen = %d, cmdlen = %d\n",
212 inlen, outlen, cmdlen);
213 printk("buffer = %d, cmd_in = %d\n", buffer, cmd_in);
214 }
215 return 0;
216 #endif
217 }
218
219
220
221
222
223
224
225 int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
226 {
227 char scsi_cmd[10];
228
229 if ((cmd != 0 && dev->index > NR_SCSI_DEVICES))
230 return -ENODEV;
231 if ((cmd == 0 && dev->host_no > max_scsi_hosts))
232 return -ENODEV;
233
234 switch (cmd) {
235 case SCSI_IOCTL_GET_IDLUN:
236 verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
237 put_fs_long(dev->id + (dev->lun << 8) +
238 (dev->host_no << 16), (long *) arg);
239 return 0;
240 case SCSI_IOCTL_PROBE_HOST:
241 return ioctl_probe(dev->host_no, arg);
242 case SCSI_IOCTL_SEND_COMMAND:
243 return ioctl_command((Scsi_Device *) dev, arg);
244 case SCSI_IOCTL_DOORLOCK:
245 if (!dev->removable || !dev->lockable) return 0;
246 scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
247 scsi_cmd[1] = dev->lun << 5;
248 scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
249 scsi_cmd[4] = SCSI_REMOVAL_PREVENT;
250 return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd);
251 break;
252 case SCSI_IOCTL_DOORUNLOCK:
253 if (!dev->removable || !dev->lockable) return 0;
254 scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
255 scsi_cmd[1] = dev->lun << 5;
256 scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
257 scsi_cmd[4] = SCSI_REMOVAL_ALLOW;
258 return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd);
259 case SCSI_IOCTL_TEST_UNIT_READY:
260 scsi_cmd[0] = TEST_UNIT_READY;
261 scsi_cmd[1] = dev->lun << 5;
262 scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
263 scsi_cmd[4] = 0;
264 return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd);
265 break;
266 default :
267 return -EINVAL;
268 }
269 }