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