2 e1dddc05 2004-06-17 devnull * Now thread-safe.
4 e1dddc05 2004-06-17 devnull * The codeqlock guarantees that once codes != nil, that pointer will never
5 e1dddc05 2004-06-17 devnull * change nor become invalid.
7 e1dddc05 2004-06-17 devnull * The QLock in the Scsi structure moderates access to the raw device.
8 e1dddc05 2004-06-17 devnull * We should probably export some of the already-locked routines, but
9 e1dddc05 2004-06-17 devnull * there hasn't been a need.
12 e1dddc05 2004-06-17 devnull #include <u.h>
13 e1dddc05 2004-06-17 devnull #include <libc.h>
14 e1dddc05 2004-06-17 devnull #include <disk.h>
16 e1dddc05 2004-06-17 devnull int scsiverbose;
18 e1dddc05 2004-06-17 devnull #define codefile "/sys/lib/scsicodes"
20 e1dddc05 2004-06-17 devnull static char *codes;
21 e1dddc05 2004-06-17 devnull static QLock codeqlock;
23 e1dddc05 2004-06-17 devnull static void
24 e1dddc05 2004-06-17 devnull getcodes(void)
27 e1dddc05 2004-06-17 devnull int n, fd;
29 e1dddc05 2004-06-17 devnull if(codes != nil)
32 e1dddc05 2004-06-17 devnull qlock(&codeqlock);
33 e1dddc05 2004-06-17 devnull if(codes != nil) {
34 e1dddc05 2004-06-17 devnull qunlock(&codeqlock);
38 e1dddc05 2004-06-17 devnull if((d = dirstat(codefile)) == nil || (fd = open(codefile, OREAD)) < 0) {
39 e1dddc05 2004-06-17 devnull qunlock(&codeqlock);
43 e1dddc05 2004-06-17 devnull codes = malloc(1+d->length+1);
44 e1dddc05 2004-06-17 devnull if(codes == nil) {
45 e1dddc05 2004-06-17 devnull close(fd);
46 e1dddc05 2004-06-17 devnull qunlock(&codeqlock);
51 e1dddc05 2004-06-17 devnull codes[0] = '\n'; /* for searches */
52 e1dddc05 2004-06-17 devnull n = readn(fd, codes+1, d->length);
53 e1dddc05 2004-06-17 devnull close(fd);
56 e1dddc05 2004-06-17 devnull if(n < 0) {
57 e1dddc05 2004-06-17 devnull free(codes);
58 e1dddc05 2004-06-17 devnull codes = nil;
59 e1dddc05 2004-06-17 devnull qunlock(&codeqlock);
62 e1dddc05 2004-06-17 devnull codes[n] = '\0';
63 e1dddc05 2004-06-17 devnull qunlock(&codeqlock);
67 e1dddc05 2004-06-17 devnull scsierror(int asc, int ascq)
69 e1dddc05 2004-06-17 devnull char *p, *q;
70 e1dddc05 2004-06-17 devnull static char search[32];
71 e1dddc05 2004-06-17 devnull static char buf[128];
73 e1dddc05 2004-06-17 devnull getcodes();
75 e1dddc05 2004-06-17 devnull if(codes) {
76 e1dddc05 2004-06-17 devnull sprint(search, "\n%.2ux%.2ux ", asc, ascq);
77 e1dddc05 2004-06-17 devnull if(p = strstr(codes, search)) {
79 e1dddc05 2004-06-17 devnull if((q = strchr(p, '\n')) == nil)
80 e1dddc05 2004-06-17 devnull q = p+strlen(p);
81 e1dddc05 2004-06-17 devnull snprint(buf, sizeof buf, "%.*s", (int)(q-p), p);
82 e1dddc05 2004-06-17 devnull return buf;
85 e1dddc05 2004-06-17 devnull sprint(search, "\n%.2ux00", asc);
86 e1dddc05 2004-06-17 devnull if(p = strstr(codes, search)) {
88 e1dddc05 2004-06-17 devnull if((q = strchr(p, '\n')) == nil)
89 e1dddc05 2004-06-17 devnull q = p+strlen(p);
90 e1dddc05 2004-06-17 devnull snprint(buf, sizeof buf, "(ascq #%.2ux) %.*s", ascq, (int)(q-p), p);
91 e1dddc05 2004-06-17 devnull return buf;
95 e1dddc05 2004-06-17 devnull sprint(buf, "scsi #%.2ux %.2ux", asc, ascq);
96 e1dddc05 2004-06-17 devnull return buf;
100 e1dddc05 2004-06-17 devnull static int
101 e1dddc05 2004-06-17 devnull _scsicmd(Scsi *s, uchar *cmd, int ccount, void *data, int dcount, int io, int dolock)
103 e1dddc05 2004-06-17 devnull uchar resp[16];
105 e1dddc05 2004-06-17 devnull long status;
107 e1dddc05 2004-06-17 devnull if(dolock)
108 e1dddc05 2004-06-17 devnull qlock(&s->lk);
109 e1dddc05 2004-06-17 devnull if(write(s->rawfd, cmd, ccount) != ccount) {
110 e1dddc05 2004-06-17 devnull werrstr("cmd write: %r");
111 e1dddc05 2004-06-17 devnull if(dolock)
112 e1dddc05 2004-06-17 devnull qunlock(&s->lk);
113 e1dddc05 2004-06-17 devnull return -1;
116 e1dddc05 2004-06-17 devnull switch(io){
117 e1dddc05 2004-06-17 devnull case Sread:
118 e1dddc05 2004-06-17 devnull n = read(s->rawfd, data, dcount);
119 e1dddc05 2004-06-17 devnull if(n < 0 && scsiverbose)
120 e1dddc05 2004-06-17 devnull fprint(2, "dat read: %r: cmd 0x%2.2uX\n", cmd[0]);
122 e1dddc05 2004-06-17 devnull case Swrite:
123 e1dddc05 2004-06-17 devnull n = write(s->rawfd, data, dcount);
124 e1dddc05 2004-06-17 devnull if(n != dcount && scsiverbose)
125 e1dddc05 2004-06-17 devnull fprint(2, "dat write: %r: cmd 0x%2.2uX\n", cmd[0]);
127 e1dddc05 2004-06-17 devnull default:
128 e1dddc05 2004-06-17 devnull case Snone:
129 e1dddc05 2004-06-17 devnull n = write(s->rawfd, resp, 0);
130 e1dddc05 2004-06-17 devnull if(n != 0 && scsiverbose)
131 e1dddc05 2004-06-17 devnull fprint(2, "none write: %r: cmd 0x%2.2uX\n", cmd[0]);
135 e1dddc05 2004-06-17 devnull memset(resp, 0, sizeof(resp));
136 e1dddc05 2004-06-17 devnull if(read(s->rawfd, resp, sizeof(resp)) < 0) {
137 e1dddc05 2004-06-17 devnull werrstr("resp read: %r\n");
138 e1dddc05 2004-06-17 devnull if(dolock)
139 e1dddc05 2004-06-17 devnull qunlock(&s->lk);
140 e1dddc05 2004-06-17 devnull return -1;
142 e1dddc05 2004-06-17 devnull if(dolock)
143 e1dddc05 2004-06-17 devnull qunlock(&s->lk);
145 e1dddc05 2004-06-17 devnull resp[sizeof(resp)-1] = '\0';
146 e1dddc05 2004-06-17 devnull status = atoi((char*)resp);
147 e1dddc05 2004-06-17 devnull if(status == 0)
148 e1dddc05 2004-06-17 devnull return n;
150 e1dddc05 2004-06-17 devnull werrstr("cmd %2.2uX: status %luX dcount %d n %d", cmd[0], status, dcount, n);
151 e1dddc05 2004-06-17 devnull return -1;
155 e1dddc05 2004-06-17 devnull scsicmd(Scsi *s, uchar *cmd, int ccount, void *data, int dcount, int io)
157 e1dddc05 2004-06-17 devnull return _scsicmd(s, cmd, ccount, data, dcount, io, 1);
160 e1dddc05 2004-06-17 devnull static int
161 e1dddc05 2004-06-17 devnull _scsiready(Scsi *s, int dolock)
163 e1dddc05 2004-06-17 devnull uchar cmd[6], resp[16];
164 e1dddc05 2004-06-17 devnull int status, i;
166 e1dddc05 2004-06-17 devnull if(dolock)
167 e1dddc05 2004-06-17 devnull qlock(&s->lk);
168 e1dddc05 2004-06-17 devnull for(i=0; i<3; i++) {
169 e1dddc05 2004-06-17 devnull memset(cmd, 0, sizeof(cmd));
170 e1dddc05 2004-06-17 devnull cmd[0] = 0x00; /* unit ready */
171 e1dddc05 2004-06-17 devnull if(write(s->rawfd, cmd, sizeof(cmd)) != sizeof(cmd)) {
172 e1dddc05 2004-06-17 devnull if(scsiverbose)
173 e1dddc05 2004-06-17 devnull fprint(2, "ur cmd write: %r\n");
174 e1dddc05 2004-06-17 devnull goto bad;
176 e1dddc05 2004-06-17 devnull write(s->rawfd, resp, 0);
177 e1dddc05 2004-06-17 devnull if(read(s->rawfd, resp, sizeof(resp)) < 0) {
178 e1dddc05 2004-06-17 devnull if(scsiverbose)
179 e1dddc05 2004-06-17 devnull fprint(2, "ur resp read: %r\n");
180 e1dddc05 2004-06-17 devnull goto bad;
182 e1dddc05 2004-06-17 devnull resp[sizeof(resp)-1] = '\0';
183 e1dddc05 2004-06-17 devnull status = atoi((char*)resp);
184 e1dddc05 2004-06-17 devnull if(status == 0 || status == 0x02) {
185 e1dddc05 2004-06-17 devnull if(dolock)
186 e1dddc05 2004-06-17 devnull qunlock(&s->lk);
187 e1dddc05 2004-06-17 devnull return 0;
189 e1dddc05 2004-06-17 devnull if(scsiverbose)
190 e1dddc05 2004-06-17 devnull fprint(2, "target: bad status: %x\n", status);
193 e1dddc05 2004-06-17 devnull if(dolock)
194 e1dddc05 2004-06-17 devnull qunlock(&s->lk);
195 e1dddc05 2004-06-17 devnull return -1;
199 e1dddc05 2004-06-17 devnull scsiready(Scsi *s)
201 e1dddc05 2004-06-17 devnull return _scsiready(s, 1);
205 e1dddc05 2004-06-17 devnull scsi(Scsi *s, uchar *cmd, int ccount, void *v, int dcount, int io)
207 e1dddc05 2004-06-17 devnull uchar req[6], sense[255], *data;
208 e1dddc05 2004-06-17 devnull int tries, code, key, n;
209 e1dddc05 2004-06-17 devnull char *p;
211 e1dddc05 2004-06-17 devnull data = v;
212 e1dddc05 2004-06-17 devnull SET(key); SET(code);
213 e1dddc05 2004-06-17 devnull qlock(&s->lk);
214 e1dddc05 2004-06-17 devnull for(tries=0; tries<2; tries++) {
215 e1dddc05 2004-06-17 devnull n = _scsicmd(s, cmd, ccount, data, dcount, io, 0);
216 e1dddc05 2004-06-17 devnull if(n >= 0) {
217 e1dddc05 2004-06-17 devnull qunlock(&s->lk);
218 e1dddc05 2004-06-17 devnull return n;
222 e1dddc05 2004-06-17 devnull * request sense
224 e1dddc05 2004-06-17 devnull memset(req, 0, sizeof(req));
225 e1dddc05 2004-06-17 devnull req[0] = 0x03;
226 e1dddc05 2004-06-17 devnull req[4] = sizeof(sense);
227 e1dddc05 2004-06-17 devnull memset(sense, 0xFF, sizeof(sense));
228 e1dddc05 2004-06-17 devnull if((n=_scsicmd(s, req, sizeof(req), sense, sizeof(sense), Sread, 0)) < 14)
229 e1dddc05 2004-06-17 devnull if(scsiverbose)
230 e1dddc05 2004-06-17 devnull fprint(2, "reqsense scsicmd %d: %r\n", n);
232 e1dddc05 2004-06-17 devnull if(_scsiready(s, 0) < 0)
233 e1dddc05 2004-06-17 devnull if(scsiverbose)
234 e1dddc05 2004-06-17 devnull fprint(2, "unit not ready\n");
236 e1dddc05 2004-06-17 devnull key = sense[2];
237 e1dddc05 2004-06-17 devnull code = sense[12];
238 e1dddc05 2004-06-17 devnull if(code == 0x17 || code == 0x18) { /* recovered errors */
239 e1dddc05 2004-06-17 devnull qunlock(&s->lk);
240 e1dddc05 2004-06-17 devnull return dcount;
242 e1dddc05 2004-06-17 devnull if(code == 0x28 && cmd[0] == 0x43) { /* get info and media changed */
243 e1dddc05 2004-06-17 devnull s->nchange++;
244 e1dddc05 2004-06-17 devnull s->changetime = time(0);
245 e1dddc05 2004-06-17 devnull continue;
249 e1dddc05 2004-06-17 devnull /* drive not ready, or medium not present */
250 e1dddc05 2004-06-17 devnull if(cmd[0] == 0x43 && key == 2 && (code == 0x3a || code == 0x04)) {
251 e1dddc05 2004-06-17 devnull s->changetime = 0;
252 e1dddc05 2004-06-17 devnull qunlock(&s->lk);
253 e1dddc05 2004-06-17 devnull return -1;
255 e1dddc05 2004-06-17 devnull qunlock(&s->lk);
257 e1dddc05 2004-06-17 devnull if(cmd[0] == 0x43 && key == 5 && code == 0x24) /* blank media */
258 e1dddc05 2004-06-17 devnull return -1;
260 e1dddc05 2004-06-17 devnull p = scsierror(code, sense[13]);
262 e1dddc05 2004-06-17 devnull werrstr("cmd #%.2ux: %s", cmd[0], p);
264 e1dddc05 2004-06-17 devnull if(scsiverbose)
265 e1dddc05 2004-06-17 devnull fprint(2, "scsi cmd #%.2ux: %.2ux %.2ux %.2ux: %s\n", cmd[0], key, code, sense[13], p);
267 cbeb0b26 2006-04-01 devnull /* if(key == 0) */
268 cbeb0b26 2006-04-01 devnull /* return dcount; */
269 e1dddc05 2004-06-17 devnull return -1;
273 e1dddc05 2004-06-17 devnull openscsi(char *dev)
275 e1dddc05 2004-06-17 devnull Scsi *s;
276 e1dddc05 2004-06-17 devnull int rawfd, ctlfd, l, n;
277 e1dddc05 2004-06-17 devnull char *name, *p, buf[512];
279 e1dddc05 2004-06-17 devnull l = strlen(dev)+1+3+1;
280 e1dddc05 2004-06-17 devnull name = malloc(l);
281 e1dddc05 2004-06-17 devnull if(name == nil)
282 e1dddc05 2004-06-17 devnull return nil;
284 e1dddc05 2004-06-17 devnull snprint(name, l, "%s/raw", dev);
285 e1dddc05 2004-06-17 devnull if((rawfd = open(name, ORDWR)) < 0) {
286 e1dddc05 2004-06-17 devnull free(name);
287 e1dddc05 2004-06-17 devnull return nil;
290 e1dddc05 2004-06-17 devnull snprint(name, l, "%s/ctl", dev);
291 e1dddc05 2004-06-17 devnull if((ctlfd = open(name, ORDWR)) < 0) {
292 e1dddc05 2004-06-17 devnull free(name);
294 e1dddc05 2004-06-17 devnull close(rawfd);
295 e1dddc05 2004-06-17 devnull return nil;
297 e1dddc05 2004-06-17 devnull free(name);
299 e1dddc05 2004-06-17 devnull n = readn(ctlfd, buf, sizeof buf);
300 e1dddc05 2004-06-17 devnull close(ctlfd);
301 e1dddc05 2004-06-17 devnull if(n <= 0)
302 e1dddc05 2004-06-17 devnull goto Error;
304 e1dddc05 2004-06-17 devnull if(strncmp(buf, "inquiry ", 8) != 0 || (p = strchr(buf, '\n')) == nil)
305 e1dddc05 2004-06-17 devnull goto Error;
306 e1dddc05 2004-06-17 devnull *p = '\0';
308 e1dddc05 2004-06-17 devnull if((p = strdup(buf+8)) == nil)
309 e1dddc05 2004-06-17 devnull goto Error;
311 e1dddc05 2004-06-17 devnull s = malloc(sizeof(*s));
312 e1dddc05 2004-06-17 devnull if(s == nil) {
314 e1dddc05 2004-06-17 devnull free(p);
315 e1dddc05 2004-06-17 devnull goto Error;
317 e1dddc05 2004-06-17 devnull memset(s, 0, sizeof(*s));
319 e1dddc05 2004-06-17 devnull s->rawfd = rawfd;
320 e1dddc05 2004-06-17 devnull s->inquire = p;
321 e1dddc05 2004-06-17 devnull s->changetime = time(0);
323 e1dddc05 2004-06-17 devnull if(scsiready(s) < 0)
324 e1dddc05 2004-06-17 devnull goto Error1;
326 e1dddc05 2004-06-17 devnull return s;