blob: 3f351053a369d74a85114140d68a959b905961f2 [file] [log] [blame]
wkje1dddc02004-06-17 01:46:29 +00001/*
2 * Now thread-safe.
3 *
4 * The codeqlock guarantees that once codes != nil, that pointer will never
5 * change nor become invalid.
6 *
7 * The QLock in the Scsi structure moderates access to the raw device.
8 * We should probably export some of the already-locked routines, but
9 * there hasn't been a need.
10 */
11
12#include <u.h>
13#include <libc.h>
14#include <disk.h>
15
16int scsiverbose;
17
18#define codefile "/sys/lib/scsicodes"
19
20static char *codes;
21static QLock codeqlock;
22
23static void
24getcodes(void)
25{
26 Dir *d;
27 int n, fd;
28
29 if(codes != nil)
30 return;
31
32 qlock(&codeqlock);
33 if(codes != nil) {
34 qunlock(&codeqlock);
35 return;
36 }
37
38 if((d = dirstat(codefile)) == nil || (fd = open(codefile, OREAD)) < 0) {
39 qunlock(&codeqlock);
40 return;
41 }
42
43 codes = malloc(1+d->length+1);
44 if(codes == nil) {
45 close(fd);
46 qunlock(&codeqlock);
47 free(d);
48 return;
49 }
50
51 codes[0] = '\n'; /* for searches */
52 n = readn(fd, codes+1, d->length);
53 close(fd);
54 free(d);
55
56 if(n < 0) {
57 free(codes);
58 codes = nil;
59 qunlock(&codeqlock);
60 return;
61 }
62 codes[n] = '\0';
63 qunlock(&codeqlock);
64}
65
66char*
67scsierror(int asc, int ascq)
68{
69 char *p, *q;
70 static char search[32];
71 static char buf[128];
72
73 getcodes();
74
75 if(codes) {
76 sprint(search, "\n%.2ux%.2ux ", asc, ascq);
77 if(p = strstr(codes, search)) {
78 p += 6;
79 if((q = strchr(p, '\n')) == nil)
80 q = p+strlen(p);
81 snprint(buf, sizeof buf, "%.*s", (int)(q-p), p);
82 return buf;
83 }
84
85 sprint(search, "\n%.2ux00", asc);
86 if(p = strstr(codes, search)) {
87 p += 6;
88 if((q = strchr(p, '\n')) == nil)
89 q = p+strlen(p);
90 snprint(buf, sizeof buf, "(ascq #%.2ux) %.*s", ascq, (int)(q-p), p);
91 return buf;
92 }
93 }
94
95 sprint(buf, "scsi #%.2ux %.2ux", asc, ascq);
96 return buf;
97}
98
99
100static int
101_scsicmd(Scsi *s, uchar *cmd, int ccount, void *data, int dcount, int io, int dolock)
102{
103 uchar resp[16];
104 int n;
105 long status;
106
107 if(dolock)
108 qlock(&s->lk);
109 if(write(s->rawfd, cmd, ccount) != ccount) {
110 werrstr("cmd write: %r");
111 if(dolock)
112 qunlock(&s->lk);
113 return -1;
114 }
115
116 switch(io){
117 case Sread:
118 n = read(s->rawfd, data, dcount);
119 if(n < 0 && scsiverbose)
120 fprint(2, "dat read: %r: cmd 0x%2.2uX\n", cmd[0]);
121 break;
122 case Swrite:
123 n = write(s->rawfd, data, dcount);
124 if(n != dcount && scsiverbose)
125 fprint(2, "dat write: %r: cmd 0x%2.2uX\n", cmd[0]);
126 break;
127 default:
128 case Snone:
129 n = write(s->rawfd, resp, 0);
130 if(n != 0 && scsiverbose)
131 fprint(2, "none write: %r: cmd 0x%2.2uX\n", cmd[0]);
132 break;
133 }
134
135 memset(resp, 0, sizeof(resp));
136 if(read(s->rawfd, resp, sizeof(resp)) < 0) {
137 werrstr("resp read: %r\n");
138 if(dolock)
139 qunlock(&s->lk);
140 return -1;
141 }
142 if(dolock)
143 qunlock(&s->lk);
144
145 resp[sizeof(resp)-1] = '\0';
146 status = atoi((char*)resp);
147 if(status == 0)
148 return n;
149
150 werrstr("cmd %2.2uX: status %luX dcount %d n %d", cmd[0], status, dcount, n);
151 return -1;
152}
153
154int
155scsicmd(Scsi *s, uchar *cmd, int ccount, void *data, int dcount, int io)
156{
157 return _scsicmd(s, cmd, ccount, data, dcount, io, 1);
158}
159
160static int
161_scsiready(Scsi *s, int dolock)
162{
163 uchar cmd[6], resp[16];
164 int status, i;
165
166 if(dolock)
167 qlock(&s->lk);
168 for(i=0; i<3; i++) {
169 memset(cmd, 0, sizeof(cmd));
170 cmd[0] = 0x00; /* unit ready */
171 if(write(s->rawfd, cmd, sizeof(cmd)) != sizeof(cmd)) {
172 if(scsiverbose)
173 fprint(2, "ur cmd write: %r\n");
174 goto bad;
175 }
176 write(s->rawfd, resp, 0);
177 if(read(s->rawfd, resp, sizeof(resp)) < 0) {
178 if(scsiverbose)
179 fprint(2, "ur resp read: %r\n");
180 goto bad;
181 }
182 resp[sizeof(resp)-1] = '\0';
183 status = atoi((char*)resp);
184 if(status == 0 || status == 0x02) {
185 if(dolock)
186 qunlock(&s->lk);
187 return 0;
188 }
189 if(scsiverbose)
190 fprint(2, "target: bad status: %x\n", status);
191 bad:;
192 }
193 if(dolock)
194 qunlock(&s->lk);
195 return -1;
196}
197
198int
199scsiready(Scsi *s)
200{
201 return _scsiready(s, 1);
202}
203
204int
205scsi(Scsi *s, uchar *cmd, int ccount, void *v, int dcount, int io)
206{
207 uchar req[6], sense[255], *data;
208 int tries, code, key, n;
209 char *p;
210
211 data = v;
212 SET(key); SET(code);
213 qlock(&s->lk);
214 for(tries=0; tries<2; tries++) {
215 n = _scsicmd(s, cmd, ccount, data, dcount, io, 0);
216 if(n >= 0) {
217 qunlock(&s->lk);
218 return n;
219 }
220
221 /*
222 * request sense
223 */
224 memset(req, 0, sizeof(req));
225 req[0] = 0x03;
226 req[4] = sizeof(sense);
227 memset(sense, 0xFF, sizeof(sense));
228 if((n=_scsicmd(s, req, sizeof(req), sense, sizeof(sense), Sread, 0)) < 14)
229 if(scsiverbose)
230 fprint(2, "reqsense scsicmd %d: %r\n", n);
231
232 if(_scsiready(s, 0) < 0)
233 if(scsiverbose)
234 fprint(2, "unit not ready\n");
235
236 key = sense[2];
237 code = sense[12];
238 if(code == 0x17 || code == 0x18) { /* recovered errors */
239 qunlock(&s->lk);
240 return dcount;
241 }
242 if(code == 0x28 && cmd[0] == 0x43) { /* get info and media changed */
243 s->nchange++;
244 s->changetime = time(0);
245 continue;
246 }
247 }
248
249 /* drive not ready, or medium not present */
250 if(cmd[0] == 0x43 && key == 2 && (code == 0x3a || code == 0x04)) {
251 s->changetime = 0;
252 qunlock(&s->lk);
253 return -1;
254 }
255 qunlock(&s->lk);
256
257 if(cmd[0] == 0x43 && key == 5 && code == 0x24) /* blank media */
258 return -1;
259
260 p = scsierror(code, sense[13]);
261
262 werrstr("cmd #%.2ux: %s", cmd[0], p);
263
264 if(scsiverbose)
265 fprint(2, "scsi cmd #%.2ux: %.2ux %.2ux %.2ux: %s\n", cmd[0], key, code, sense[13], p);
266
rsccbeb0b22006-04-01 19:24:03 +0000267/* if(key == 0) */
268/* return dcount; */
wkje1dddc02004-06-17 01:46:29 +0000269 return -1;
270}
271
272Scsi*
273openscsi(char *dev)
274{
275 Scsi *s;
276 int rawfd, ctlfd, l, n;
277 char *name, *p, buf[512];
278
279 l = strlen(dev)+1+3+1;
280 name = malloc(l);
281 if(name == nil)
282 return nil;
283
284 snprint(name, l, "%s/raw", dev);
285 if((rawfd = open(name, ORDWR)) < 0) {
286 free(name);
287 return nil;
288 }
289
290 snprint(name, l, "%s/ctl", dev);
291 if((ctlfd = open(name, ORDWR)) < 0) {
292 free(name);
293 Error:
294 close(rawfd);
295 return nil;
296 }
297 free(name);
298
299 n = readn(ctlfd, buf, sizeof buf);
300 close(ctlfd);
301 if(n <= 0)
302 goto Error;
303
304 if(strncmp(buf, "inquiry ", 8) != 0 || (p = strchr(buf, '\n')) == nil)
305 goto Error;
306 *p = '\0';
307
308 if((p = strdup(buf+8)) == nil)
309 goto Error;
310
311 s = malloc(sizeof(*s));
312 if(s == nil) {
313 Error1:
314 free(p);
315 goto Error;
316 }
317 memset(s, 0, sizeof(*s));
318
319 s->rawfd = rawfd;
320 s->inquire = p;
321 s->changetime = time(0);
322
323 if(scsiready(s) < 0)
324 goto Error1;
325
326 return s;
327}