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