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