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