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