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