Blame


1 e1dddc05 2004-06-17 devnull /*
2 e1dddc05 2004-06-17 devnull * Now thread-safe.
3 e1dddc05 2004-06-17 devnull *
4 fa325e9b 2020-01-10 cross * The codeqlock guarantees that once codes != nil, that pointer will never
5 e1dddc05 2004-06-17 devnull * change nor become invalid.
6 e1dddc05 2004-06-17 devnull *
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.
10 e1dddc05 2004-06-17 devnull */
11 e1dddc05 2004-06-17 devnull
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>
15 e1dddc05 2004-06-17 devnull
16 e1dddc05 2004-06-17 devnull int scsiverbose;
17 e1dddc05 2004-06-17 devnull
18 e1dddc05 2004-06-17 devnull #define codefile "/sys/lib/scsicodes"
19 e1dddc05 2004-06-17 devnull
20 e1dddc05 2004-06-17 devnull static char *codes;
21 e1dddc05 2004-06-17 devnull static QLock codeqlock;
22 e1dddc05 2004-06-17 devnull
23 e1dddc05 2004-06-17 devnull static void
24 e1dddc05 2004-06-17 devnull getcodes(void)
25 e1dddc05 2004-06-17 devnull {
26 e1dddc05 2004-06-17 devnull Dir *d;
27 e1dddc05 2004-06-17 devnull int n, fd;
28 e1dddc05 2004-06-17 devnull
29 e1dddc05 2004-06-17 devnull if(codes != nil)
30 e1dddc05 2004-06-17 devnull return;
31 e1dddc05 2004-06-17 devnull
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);
35 e1dddc05 2004-06-17 devnull return;
36 e1dddc05 2004-06-17 devnull }
37 e1dddc05 2004-06-17 devnull
38 e1dddc05 2004-06-17 devnull if((d = dirstat(codefile)) == nil || (fd = open(codefile, OREAD)) < 0) {
39 e1dddc05 2004-06-17 devnull qunlock(&codeqlock);
40 e1dddc05 2004-06-17 devnull return;
41 e1dddc05 2004-06-17 devnull }
42 e1dddc05 2004-06-17 devnull
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);
47 e1dddc05 2004-06-17 devnull free(d);
48 e1dddc05 2004-06-17 devnull return;
49 e1dddc05 2004-06-17 devnull }
50 e1dddc05 2004-06-17 devnull
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);
54 e1dddc05 2004-06-17 devnull free(d);
55 e1dddc05 2004-06-17 devnull
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);
60 e1dddc05 2004-06-17 devnull return;
61 e1dddc05 2004-06-17 devnull }
62 e1dddc05 2004-06-17 devnull codes[n] = '\0';
63 e1dddc05 2004-06-17 devnull qunlock(&codeqlock);
64 e1dddc05 2004-06-17 devnull }
65 fa325e9b 2020-01-10 cross
66 e1dddc05 2004-06-17 devnull char*
67 e1dddc05 2004-06-17 devnull scsierror(int asc, int ascq)
68 e1dddc05 2004-06-17 devnull {
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];
72 e1dddc05 2004-06-17 devnull
73 e1dddc05 2004-06-17 devnull getcodes();
74 e1dddc05 2004-06-17 devnull
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)) {
78 e1dddc05 2004-06-17 devnull p += 6;
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;
83 e1dddc05 2004-06-17 devnull }
84 e1dddc05 2004-06-17 devnull
85 e1dddc05 2004-06-17 devnull sprint(search, "\n%.2ux00", asc);
86 e1dddc05 2004-06-17 devnull if(p = strstr(codes, search)) {
87 e1dddc05 2004-06-17 devnull p += 6;
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;
92 e1dddc05 2004-06-17 devnull }
93 e1dddc05 2004-06-17 devnull }
94 e1dddc05 2004-06-17 devnull
95 e1dddc05 2004-06-17 devnull sprint(buf, "scsi #%.2ux %.2ux", asc, ascq);
96 e1dddc05 2004-06-17 devnull return buf;
97 e1dddc05 2004-06-17 devnull }
98 e1dddc05 2004-06-17 devnull
99 e1dddc05 2004-06-17 devnull
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)
102 e1dddc05 2004-06-17 devnull {
103 e1dddc05 2004-06-17 devnull uchar resp[16];
104 e1dddc05 2004-06-17 devnull int n;
105 e1dddc05 2004-06-17 devnull long status;
106 e1dddc05 2004-06-17 devnull
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;
114 e1dddc05 2004-06-17 devnull }
115 e1dddc05 2004-06-17 devnull
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]);
121 e1dddc05 2004-06-17 devnull break;
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]);
126 e1dddc05 2004-06-17 devnull break;
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]);
132 e1dddc05 2004-06-17 devnull break;
133 e1dddc05 2004-06-17 devnull }
134 e1dddc05 2004-06-17 devnull
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;
141 e1dddc05 2004-06-17 devnull }
142 e1dddc05 2004-06-17 devnull if(dolock)
143 e1dddc05 2004-06-17 devnull qunlock(&s->lk);
144 e1dddc05 2004-06-17 devnull
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;
149 e1dddc05 2004-06-17 devnull
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;
152 e1dddc05 2004-06-17 devnull }
153 e1dddc05 2004-06-17 devnull
154 e1dddc05 2004-06-17 devnull int
155 e1dddc05 2004-06-17 devnull scsicmd(Scsi *s, uchar *cmd, int ccount, void *data, int dcount, int io)
156 e1dddc05 2004-06-17 devnull {
157 e1dddc05 2004-06-17 devnull return _scsicmd(s, cmd, ccount, data, dcount, io, 1);
158 e1dddc05 2004-06-17 devnull }
159 e1dddc05 2004-06-17 devnull
160 e1dddc05 2004-06-17 devnull static int
161 e1dddc05 2004-06-17 devnull _scsiready(Scsi *s, int dolock)
162 e1dddc05 2004-06-17 devnull {
163 e1dddc05 2004-06-17 devnull uchar cmd[6], resp[16];
164 e1dddc05 2004-06-17 devnull int status, i;
165 e1dddc05 2004-06-17 devnull
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;
175 e1dddc05 2004-06-17 devnull }
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;
181 e1dddc05 2004-06-17 devnull }
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;
188 e1dddc05 2004-06-17 devnull }
189 e1dddc05 2004-06-17 devnull if(scsiverbose)
190 e1dddc05 2004-06-17 devnull fprint(2, "target: bad status: %x\n", status);
191 e1dddc05 2004-06-17 devnull bad:;
192 e1dddc05 2004-06-17 devnull }
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;
196 e1dddc05 2004-06-17 devnull }
197 e1dddc05 2004-06-17 devnull
198 e1dddc05 2004-06-17 devnull int
199 e1dddc05 2004-06-17 devnull scsiready(Scsi *s)
200 e1dddc05 2004-06-17 devnull {
201 e1dddc05 2004-06-17 devnull return _scsiready(s, 1);
202 e1dddc05 2004-06-17 devnull }
203 e1dddc05 2004-06-17 devnull
204 e1dddc05 2004-06-17 devnull int
205 e1dddc05 2004-06-17 devnull scsi(Scsi *s, uchar *cmd, int ccount, void *v, int dcount, int io)
206 e1dddc05 2004-06-17 devnull {
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;
210 e1dddc05 2004-06-17 devnull
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;
219 e1dddc05 2004-06-17 devnull }
220 e1dddc05 2004-06-17 devnull
221 e1dddc05 2004-06-17 devnull /*
222 e1dddc05 2004-06-17 devnull * request sense
223 e1dddc05 2004-06-17 devnull */
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);
231 fa325e9b 2020-01-10 cross
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");
235 fa325e9b 2020-01-10 cross
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;
241 e1dddc05 2004-06-17 devnull }
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;
246 e1dddc05 2004-06-17 devnull }
247 e1dddc05 2004-06-17 devnull }
248 e1dddc05 2004-06-17 devnull
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;
254 e1dddc05 2004-06-17 devnull }
255 e1dddc05 2004-06-17 devnull qunlock(&s->lk);
256 e1dddc05 2004-06-17 devnull
257 e1dddc05 2004-06-17 devnull if(cmd[0] == 0x43 && key == 5 && code == 0x24) /* blank media */
258 e1dddc05 2004-06-17 devnull return -1;
259 e1dddc05 2004-06-17 devnull
260 e1dddc05 2004-06-17 devnull p = scsierror(code, sense[13]);
261 e1dddc05 2004-06-17 devnull
262 e1dddc05 2004-06-17 devnull werrstr("cmd #%.2ux: %s", cmd[0], p);
263 e1dddc05 2004-06-17 devnull
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);
266 e1dddc05 2004-06-17 devnull
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;
270 e1dddc05 2004-06-17 devnull }
271 e1dddc05 2004-06-17 devnull
272 e1dddc05 2004-06-17 devnull Scsi*
273 e1dddc05 2004-06-17 devnull openscsi(char *dev)
274 e1dddc05 2004-06-17 devnull {
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];
278 e1dddc05 2004-06-17 devnull
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;
283 e1dddc05 2004-06-17 devnull
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;
288 e1dddc05 2004-06-17 devnull }
289 e1dddc05 2004-06-17 devnull
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);
293 e1dddc05 2004-06-17 devnull Error:
294 e1dddc05 2004-06-17 devnull close(rawfd);
295 e1dddc05 2004-06-17 devnull return nil;
296 e1dddc05 2004-06-17 devnull }
297 e1dddc05 2004-06-17 devnull free(name);
298 e1dddc05 2004-06-17 devnull
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;
303 e1dddc05 2004-06-17 devnull
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';
307 e1dddc05 2004-06-17 devnull
308 e1dddc05 2004-06-17 devnull if((p = strdup(buf+8)) == nil)
309 e1dddc05 2004-06-17 devnull goto Error;
310 e1dddc05 2004-06-17 devnull
311 e1dddc05 2004-06-17 devnull s = malloc(sizeof(*s));
312 e1dddc05 2004-06-17 devnull if(s == nil) {
313 e1dddc05 2004-06-17 devnull Error1:
314 e1dddc05 2004-06-17 devnull free(p);
315 e1dddc05 2004-06-17 devnull goto Error;
316 e1dddc05 2004-06-17 devnull }
317 e1dddc05 2004-06-17 devnull memset(s, 0, sizeof(*s));
318 e1dddc05 2004-06-17 devnull
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);
322 fa325e9b 2020-01-10 cross
323 e1dddc05 2004-06-17 devnull if(scsiready(s) < 0)
324 e1dddc05 2004-06-17 devnull goto Error1;
325 e1dddc05 2004-06-17 devnull
326 e1dddc05 2004-06-17 devnull return s;
327 e1dddc05 2004-06-17 devnull }