| ---
sdscsi.c (7937B)
---
1 #include "u.h"
2 #include "lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "io.h"
7 #include "ureg.h"
8 #include "error.h"
9
10 #include "sd.h"
11
12 static int
13 scsitest(SDreq* r)
14 {
15 r->write = 0;
16 memset(r->cmd, 0, sizeof(r->cmd));
17 r->cmd[1] = r->lun<<5;
18 r->clen = 6;
19 r->data = nil;
20 r->dlen = 0;
21 r->flags = 0;
22
23 r->status = ~0;
24
25 return r->unit->dev->ifc->rio(r);
26 }
27
28 int
29 scsiverify(SDunit* unit)
30 {
31 SDreq *r;
32 int i, status;
33 uchar *inquiry;
34
35 if((r = malloc(sizeof(SDreq))) == nil)
36 return 0;
37 if((inquiry = sdmalloc(sizeof(unit->inquiry))) == nil){
38 free(r);
39 return 0;
40 }
41 r->unit = unit;
42 r->lun = 0; /* ??? */
43
44 memset(unit->inquiry, 0, sizeof(unit->inquiry));
45 r->write = 0;
46 r->cmd[0] = 0x12;
47 r->cmd[1] = r->lun<<5;
48 r->cmd[4] = sizeof(unit->inquiry)-1;
49 r->clen = 6;
50 r->data = inquiry;
51 r->dlen = sizeof(unit->inquiry)-1;
52 r->flags = 0;
53
54 r->status = ~0;
55 if(unit->dev->ifc->rio(r) != SDok){
56 free(r);
57 return 0;
58 }
59 memmove(unit->inquiry, inquiry, r->dlen);
60 free(inquiry);
61
62 status = 0;
63 for(i = 0; i < 3; i++){
64 while((status = scsitest(r)) == SDbusy)
65 ;
66 if(status == SDok || status != SDcheck)
67 break;
68 if(!(r->flags & SDvalidsense))
69 break;
70 if((r->sense[2] & 0x0F) != 0x02)
71 continue;
72
73 /*
74 * Unit is 'not ready'.
75 * If it is in the process of becoming ready or needs
76 * an initialising command, set status so it will be spun-up
77 * below.
78 * If there's no medium, that's OK too, but don't
79 * try to spin it up.
80 */
81 if(r->sense[12] == 0x04){
82 if(r->sense[13] == 0x02 || r->sense[13] == 0x01){
83 status = SDok;
84 break;
85 }
86 }
87 if(r->sense[12] == 0x3A)
88 break;
89 }
90
91 if(status == SDok){
92 /*
93 * Try to ensure a direct-access device is spinning.
94 * Don't wait for completion, ignore the result.
95 */
96 if((unit->inquiry[0] & 0x1F) == 0){
97 memset(r->cmd, 0, sizeof(r->cmd));
98 r->write = 0;
99 r->cmd[0] = 0x1B;
100 r->cmd[1] = (r->lun<<5)|0x01;
101 r->cmd[4] = 1;
102 r->clen = 6;
103 r->data = nil;
104 r->dlen = 0;
105 r->flags = 0;
106
107 r->status = ~0;
108 unit->dev->ifc->rio(r);
109 }
110 }
111 free(r);
112
113 if(status == SDok || status == SDcheck)
114 return 1;
115 return 0;
116 }
117
118 static int
119 scsirio(SDreq* r)
120 {
121 /*
122 * Perform an I/O request, returning
123 * -1 failure
124 * 0 ok
125 * 1 no medium present
126 * 2 retry
127 * The contents of r may be altered so the
128 * caller should re-initialise if necesary.
129 */
130 r->status = ~0;
131 switch(r->unit->dev->ifc->rio(r)){
132 default:
133 break;
134 case SDcheck:
135 if(!(r->flags & SDvalidsense))
136 break;
137 switch(r->sense[2] & 0x0F){
138 case 0x00: /* no sense */
139 case 0x01: /* recovered error */
140 return 2;
141 case 0x06: /* check condition */
142 /*
143 * 0x28 - not ready to ready transition,
144 * medium may have changed.
145 * 0x29 - power on or some type of reset.
146 */
147 if(r->sense[12] == 0x28 && r->sense[13] == 0)
148 return 2;
149 if(r->sense[12] == 0x29)
150 return 2;
151 break;
152 case 0x02: /* not ready */
153 /*
154 * If no medium present, bail out.
155 * If unit is becoming ready, rather than not
156 * not ready, wait a little then poke it again. */
157 if(r->sense[12] == 0x3A)
158 break;
159 if(r->sense[12] != 0x04 || r->sense[13] != 0x01)
160 break;
161
162 while(waserror())
163 ;
164 tsleep(&up->sleep, return0, 0, 500);
165 poperror();
166 scsitest(r);
167 return 2;
168 default:
169 break;
170 }
171 break;
172 case SDok:
173 return 0;
174 }
175 return -1;
176 }
177
178 int
179 scsionline(SDunit* unit)
180 {
181 SDreq *r;
182 uchar *p;
183 int ok, retries;
184
185 if((r = malloc(sizeof(SDreq))) == nil)
186 return 0;
187 if((p = sdmalloc(8)) == nil){
188 free(r);
189 return 0;
190 }
191
192 ok = 0;
193
194 r->unit = unit;
195 r->lun = 0; /* ??? */
196 for(retries = 0; retries < 10; retries++){
197 /*
198 * Read-capacity is mandatory for DA, WORM, CD-ROM and
199 * MO. It may return 'not ready' if type DA is not
200 * spun up, type MO or type CD-ROM are not loaded or just
201 * plain slow getting their act together after a reset.
202 */
203 r->write = 0;
204 memset(r->cmd, 0, sizeof(r->cmd));
205 r->cmd[0] = 0x25;
206 r->cmd[1] = r->lun<<5;
207 r->clen = 10;
208 r->data = p;
209 r->dlen = 8;
210 r->flags = 0;
211
212 r->status = ~0;
213 switch(scsirio(r)){
214 default:
215 break;
216 case 0:
217 unit->sectors = (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3];
218 unit->secsize = (p[4]<<24)|(p[5]<<16)|(p[6]<<8)|p[7];
219
220 /*
221 * Some ATAPI CD readers lie about the block size.
222 * Since we don't read audio via this interface
223 * it's okay to always fudge this.
224 */
225 if(unit->secsize == 2352)
226 unit->secsize = 2048;
227 /*
228 * Devices with removable media may return 0 sectors
229 * when they have empty media (e.g. sata dvd writers);
230 * if so, keep the count zero.
231 *
232 * Read-capacity returns the LBA of the last sector,
233 * therefore the number of sectors must be incremented.
234 */
235 if(unit->sectors != 0)
236 unit->sectors++;
237 ok = 1;
238 break;
239 case 1:
240 ok = 1;
241 break;
242 case 2:
243 continue;
244 }
245 break;
246 }
247 free(p);
248 free(r);
249
250 if(ok)
251 return ok+retries;
252 else
253 return 0;
254 }
255
256 int
257 scsiexec(SDunit* unit, int write, uchar* cmd, int clen, void* data, int* dlen)
258 {
259 SDreq *r;
260 int status;
261
262 if((r = malloc(sizeof(SDreq))) == nil)
263 return SDmalloc;
264 r->unit = unit;
265 r->lun = cmd[1]>>5; /* ??? */
266 r->write = write;
267 memmove(r->cmd, cmd, clen);
268 r->clen = clen;
269 r->data = data;
270 if(dlen)
271 r->dlen = *dlen;
272 r->flags = 0;
273
274 r->status = ~0;
275
276 /*
277 * Call the device-specific I/O routine.
278 * There should be no calls to 'error()' below this
279 * which percolate back up.
280 */
281 switch(status = unit->dev->ifc->rio(r)){
282 case SDok:
283 if(dlen)
284 *dlen = r->rlen;
285 /*FALLTHROUGH*/
286 case SDcheck:
287 /*FALLTHROUGH*/
288 default:
289 /*
290 * It's more complicated than this. There are conditions
291 * which are 'ok' but for which the returned status code
292 * is not 'SDok'.
293 * Also, not all conditions require a reqsense, might
294 * need to do a reqsense here and make it available to the
295 * caller somehow.
296 *
297 * MaƱana.
298 */
299 break;
300 }
301 sdfree(r);
302
303 return status;
304 }
305
306 static void
307 scsifmt10(SDreq *r, int write, int lun, ulong nb, uvlong bno)
308 {
309 uchar *c;
310
311 c = r->cmd;
312 if(write == 0)
313 c[0] = 0x28;
314 else
315 c[0] = 0x2A;
316 c[1] = lun<<5;
317 c[2] = bno>>24;
318 c[3] = bno>>16;
319 c[4] = bno>>8;
320 c[5] = bno;
321 c[6] = 0;
322 c[7] = nb>>8;
323 c[8] = nb;
324 c[9] = 0;
325
326 r->clen = 10;
327 }
328
329 static void
330 scsifmt16(SDreq *r, int write, int lun, ulong nb, uvlong bno)
331 {
332 uchar *c;
333
334 c = r->cmd;
335 if(write == 0)
336 c[0] = 0x88;
337 else
338 c[0] = 0x8A;
339 c[1] = lun<<5; /* so wrong */
340 c[2] = bno>>56;
341 c[3] = bno>>48;
342 c[4] = bno>>40;
343 c[5] = bno>>32;
344 c[6] = bno>>24;
345 c[7] = bno>>16;
346 c[8] = bno>>8;
347 c[9] = bno;
348 c[10] = nb>>24;
349 c[11] = nb>>16;
350 c[12] = nb>>8;
351 c[13] = nb;
352 c[14] = 0;
353 c[15] = 0;
354
355 r->clen = 16;
356 }
357
358 long
359 scsibio(SDunit* unit, int lun, int write, void* data, long nb, uvlong bno)
360 {
361 SDreq *r;
362 long rlen;
363
364 if((r = malloc(sizeof(SDreq))) == nil)
365 error(Enomem);
366 r->unit = unit;
367 r->lun = lun;
368 again:
369 r->write = write;
370 if(bno >= (1ULL<<32))
371 scsifmt16(r, write, lun, nb, bno);
372 else
373 scsifmt10(r, write, lun, nb, bno);
374 r->data = data;
375 r->dlen = nb*unit->secsize;
376 r->flags = 0;
377
378 r->status = ~0;
379 switch(scsirio(r)){
380 default:
381 rlen = -1;
382 break;
383 case 0:
384 rlen = r->rlen;
385 break;
386 case 2:
387 rlen = -1;
388 if(!(r->flags & SDvalidsense))
389 break;
390 switch(r->sense[2] & 0x0F){
391 default:
392 break;
393 case 0x01: /* recovered error */
394 print("%s: recovered error at sector %llud\n",
395 unit->perm.name, bno);
396 rlen = r->rlen;
397 break;
398 case 0x06: /* check condition */
399 /*
400 * Check for a removeable media change.
401 * If so, mark it by zapping the geometry info
402 * to force an online request.
403 */
404 if(r->sense[12] != 0x28 || r->sense[13] != 0)
405 break;
406 if(unit->inquiry[1] & 0x80)
407 unit->sectors = 0;
408 break;
409 case 0x02: /* not ready */
410 /*
411 * If unit is becoming ready,
412 * rather than not not ready, try again.
413 */
414 if(r->sense[12] == 0x04 && r->sense[13] == 0x01)
415 goto again;
416 break;
417 }
418 break;
419 }
420 free(r);
421
422 return rlen;
423 }
424 |