AHCI: reformat with clang-format, fix with spatch.
[akaros.git] / kern / drivers / dev / sd.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  * Storage Device.
12  */
13 #include "../port/error.h"
14 #include "../port/lib.h"
15 #include "dat.h"
16 #include "fns.h"
17 #include "io.h"
18 #include "mem.h"
19 #include "u.h"
20 #include "ureg.h"
21
22 #include "../port/sd.h"
23
24 extern struct dev sddevtab;
25 extern struct sdifc *sdifc[];
26
27 static char Echange[] = "media or partition has changed";
28
29 static char devletters[] = "0123456789"
30                            "abcdefghijklmnopqrstuvwxyz"
31                            "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
32
33 static struct sdev *devs[sizeof devletters - 1];
34 static qlock_t devslock;
35
36 enum {
37         Rawcmd,
38         Rawdata,
39         Rawstatus,
40 };
41
42 enum {
43         Qtopdir = 1, /* top level directory */
44         Qtopbase,
45         Qtopctl = Qtopbase,
46
47         Qunitdir, /* directory per unit */
48         Qunitbase,
49         Qctl = Qunitbase,
50         Qraw,
51         Qpart,
52
53         TypeLOG = 4,
54         NType = (1 << TypeLOG),
55         TypeMASK = (NType - 1),
56         TypeSHIFT = 0,
57
58         PartLOG = 8,
59         NPart = (1 << PartLOG),
60         PartMASK = (NPart - 1),
61         PartSHIFT = TypeLOG,
62
63         UnitLOG = 8,
64         NUnit = (1 << UnitLOG),
65         UnitMASK = (NUnit - 1),
66         UnitSHIFT = (PartLOG + TypeLOG),
67
68         DevLOG = 8,
69         NDev = (1 << DevLOG),
70         DevMASK = (NDev - 1),
71         DevSHIFT = (UnitLOG + PartLOG + TypeLOG),
72
73         Ncmd = 20,
74 };
75
76 #define TYPE(q) ((((uint32_t)(q).path) >> TypeSHIFT) & TypeMASK)
77 #define PART(q) ((((uint32_t)(q).path) >> PartSHIFT) & PartMASK)
78 #define UNIT(q) ((((uint32_t)(q).path) >> UnitSHIFT) & UnitMASK)
79 #define DEV(q) ((((uint32_t)(q).path) >> DevSHIFT) & DevMASK)
80 #define QID(d, u, p, t)                                                        \
81         (((d) << DevSHIFT) | ((u) << UnitSHIFT) | ((p) << PartSHIFT) |             \
82          ((t) << TypeSHIFT))
83
84 void sdaddpart(struct sdunit *unit, char *name, uint64_t start, uint64_t end)
85 {
86         struct sdpart *pp;
87         int i, partno;
88
89         /*
90          * Check name not already used
91          * and look for a free slot.
92          */
93         if (unit->part != nil) {
94                 partno = -1;
95                 for (i = 0; i < unit->npart; i++) {
96                         pp = &unit->part[i];
97                         if (!pp->valid) {
98                                 if (partno == -1)
99                                         partno = i;
100                                 break;
101                         }
102                         if (strcmp(name, pp->SDperm.name) == 0) {
103                                 if (pp->start == start && pp->end == end)
104                                         return;
105                                 error(Ebadctl);
106                         }
107                 }
108         } else {
109                 if ((unit->part = malloc(sizeof(struct sdpart) * SDnpart)) == nil)
110                         error(Enomem);
111                 unit->npart = SDnpart;
112                 partno = 0;
113         }
114
115         /*
116          * If no free slot found then increase the
117          * array size (can't get here with unit->part == nil).
118          */
119         if (partno == -1) {
120                 if (unit->npart >= NPart)
121                         error(Enomem);
122                 if ((pp = malloc(sizeof(struct sdpart) * (unit->npart + SDnpart))) ==
123                     nil)
124                         error(Enomem);
125                 memmove(pp, unit->part, sizeof(struct sdpart) * unit->npart);
126                 free(unit->part);
127                 unit->part = pp;
128                 partno = unit->npart;
129                 unit->npart += SDnpart;
130         }
131
132         /*
133          * Check size and extent are valid.
134          */
135         if (start > end || end > unit->sectors)
136                 error(Eio);
137         pp = &unit->part[partno];
138         pp->start = start;
139         pp->end = end;
140         kstrdup(&pp->SDperm.name, name);
141         kstrdup(&pp->SDperm.user, eve);
142         pp->SDperm.perm = 0640;
143         pp->valid = 1;
144 }
145
146 static void sddelpart(struct sdunit *unit, char *name)
147 {
148         struct proc *up = externup();
149         int i;
150         struct sdpart *pp;
151         /*
152          * Look for the partition to delete.
153          * Can't delete if someone still has it open.
154          */
155         pp = unit->part;
156         for (i = 0; i < unit->npart; i++) {
157                 if (strcmp(name, pp->SDperm.name) == 0)
158                         break;
159                 pp++;
160         }
161         if (i >= unit->npart)
162                 error(Ebadctl);
163         if (strcmp(up->user, pp->SDperm.user) && !iseve())
164                 error(Eperm);
165         pp->valid = 0;
166         pp->vers++;
167 }
168
169 static void sdincvers(struct sdunit *unit)
170 {
171         int i;
172
173         unit->vers++;
174         if (unit->part) {
175                 for (i = 0; i < unit->npart; i++) {
176                         unit->part[i].valid = 0;
177                         unit->part[i].vers++;
178                 }
179         }
180 }
181
182 static int sdinitpart(struct sdunit *unit)
183 {
184 #if 0
185         Mach *m;
186         int nf;
187         uint64_t start, end;
188         char *f[4], *p, *q, buf[10];
189
190         m = machp();
191 #endif
192         if (unit->sectors > 0) {
193                 unit->sectors = unit->secsize = 0;
194                 sdincvers(unit);
195         }
196
197         /* device must be connected or not; other values are trouble */
198         if (unit->inquiry[0] & 0xC0) /* see SDinq0periphqual */
199                 return 0;
200         switch (unit->inquiry[0] & SDinq0periphtype) {
201         case SDperdisk:
202         case SDperworm:
203         case SDpercd:
204         case SDpermo:
205                 break;
206         default:
207                 return 0;
208         }
209
210         if (unit->dev->ifc->online)
211                 unit->dev->ifc->online(unit);
212         if (unit->sectors) {
213                 sdincvers(unit);
214                 sdaddpart(unit, "data", 0, unit->sectors);
215
216 /*
217  * Use partitions passed from boot program,
218  * e.g.
219  *      sdC0part=dos 63 123123/plan9 123123 456456
220  * This happens before /boot sets hostname so the
221  * partitions will have the null-string for user.
222  * The gen functions patch it up.
223  */
224 #if 0
225                 snprint(buf, sizeof buf, "%spart", unit->SDperm.name);
226                 for(p = getconf(buf); p != nil; p = q){
227                         if(q = strchr(p, '/'))
228                                 *q++ = '\0';
229                         nf = tokenize(p, f, nelem(f));
230                         if(nf < 3)
231                                 continue;
232
233                         start = strtoull(f[1], 0, 0);
234                         end = strtoull(f[2], 0, 0);
235                         if(!waserror()){
236                                 sdaddpart(unit, f[0], start, end);
237                                 poperror();
238                         }
239                 }
240 #endif
241         }
242
243         return 1;
244 }
245
246 static int sdindex(int idno)
247 {
248         char *p;
249
250         p = strchr(devletters, idno);
251         if (p == nil)
252                 return -1;
253         return p - devletters;
254 }
255
256 static struct sdev *sdgetdev(int idno)
257 {
258         struct sdev *sdev;
259         int i;
260
261         if ((i = sdindex(idno)) < 0)
262                 return nil;
263
264         qlock(&devslock);
265         if (sdev = devs[i])
266                 incref(&sdev->r);
267         qunlock(&devslock);
268         return sdev;
269 }
270
271 static struct sdunit *sdgetunit(struct sdev *sdev, int subno)
272 {
273         struct sdunit *unit;
274         char buf[32];
275
276         /*
277          * Associate a unit with a given device and sub-unit
278          * number on that device.
279          * The device will be probed if it has not already been
280          * successfully accessed.
281          */
282         qlock(&sdev->unitlock);
283         if (subno > sdev->nunit) {
284                 qunlock(&sdev->unitlock);
285                 return nil;
286         }
287
288         unit = sdev->unit[subno];
289         if (unit == nil) {
290                 /*
291                  * Probe the unit only once. This decision
292                  * may be a little severe and reviewed later.
293                  */
294                 if (sdev->unitflg[subno]) {
295                         qunlock(&sdev->unitlock);
296                         return nil;
297                 }
298                 if ((unit = malloc(sizeof(struct sdunit))) == nil) {
299                         qunlock(&sdev->unitlock);
300                         return nil;
301                 }
302                 sdev->unitflg[subno] = 1;
303
304                 snprint(buf, sizeof(buf), "%s%d", sdev->name, subno);
305                 kstrdup(&unit->SDperm.name, buf);
306                 kstrdup(&unit->SDperm.user, eve);
307                 unit->SDperm.perm = 0555;
308                 unit->subno = subno;
309                 unit->dev = sdev;
310
311                 if (sdev->enabled == 0 && sdev->ifc->enable)
312                         sdev->ifc->enable(sdev);
313                 sdev->enabled = 1;
314
315                 /*
316                  * No need to lock anything here as this is only
317                  * called before the unit is made available in the
318                  * sdunit[] array.
319                  */
320                 if (unit->dev->ifc->verify(unit) == 0) {
321                         qunlock(&sdev->unitlock);
322                         free(unit);
323                         return nil;
324                 }
325                 sdev->unit[subno] = unit;
326         }
327         qunlock(&sdev->unitlock);
328         return unit;
329 }
330
331 static void sdreset(void)
332 {
333         int i;
334         struct sdev *sdev;
335
336         /*
337          * Probe all known controller types and register any devices found.
338          */
339         for (i = 0; sdifc[i] != nil; i++) {
340                 if (sdifc[i]->pnp == nil || (sdev = sdifc[i]->pnp()) == nil)
341                         continue;
342                 sdadddevs(sdev);
343         }
344 }
345
346 void sdadddevs(struct sdev *sdev)
347 {
348         int i, j, id;
349         struct sdev *next;
350
351         for (; sdev; sdev = next) {
352                 next = sdev->next;
353
354                 sdev->unit =
355                     (struct sdunit **)malloc(sdev->nunit * sizeof(struct sdunit *));
356                 sdev->unitflg = (int *)malloc(sdev->nunit * sizeof(int));
357                 if (sdev->unit == nil || sdev->unitflg == nil) {
358                         print("sdadddevs: out of memory\n");
359                 giveup:
360                         free(sdev->unit);
361                         free(sdev->unitflg);
362                         if (sdev->ifc->clear)
363                                 sdev->ifc->clear(sdev);
364                         free(sdev);
365                         continue;
366                 }
367                 id = sdindex(sdev->idno);
368                 if (id == -1) {
369                         print("sdadddevs: bad id number %d (%C)\n", id, id);
370                         goto giveup;
371                 }
372                 qlock(&devslock);
373                 for (i = 0; i < nelem(devs); i++) {
374                         if (devs[j = (id + i) % nelem(devs)] == nil) {
375                                 sdev->idno = devletters[j];
376                                 devs[j] = sdev;
377                                 snprint(sdev->name, sizeof sdev->name, "sd%c", devletters[j]);
378                                 break;
379                         }
380                 }
381                 qunlock(&devslock);
382                 if (i == nelem(devs)) {
383                         print("sdadddevs: out of device letters\n");
384                         goto giveup;
385                 }
386         }
387 }
388
389 // void
390 // sdrmdevs(SDev *sdev)
391 // {
392 //      char buf[2];
393 //
394 //      snprint(buf, sizeof buf, "%c", sdev->idno);
395 //      unconfigure(buf);
396 // }
397
398 void sdaddallconfs(void (*addconf)(struct sdunit *))
399 {
400         int i, u;
401         struct sdev *sdev;
402
403         for (i = 0; i < nelem(devs); i++) /* each controller */
404                 for (sdev = devs[i]; sdev; sdev = sdev->next)
405                         for (u = 0; u < sdev->nunit; u++) /* each drive */
406                                 (*addconf)(sdev->unit[u]);
407 }
408
409 static int sd2gen(struct chan *c, int i, struct dir *dp)
410 {
411         struct qid q;
412         uint64_t l;
413         struct sdpart *pp;
414         struct sdperm *perm;
415         struct sdunit *unit;
416         struct sdev *sdev;
417         int rv;
418
419         sdev = sdgetdev(DEV(c->qid));
420         assert(sdev);
421         unit = sdev->unit[UNIT(c->qid)];
422
423         rv = -1;
424         switch (i) {
425         case Qctl:
426                 mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qctl),
427                       unit->vers, QTFILE);
428                 perm = &unit->ctlperm;
429                 if (emptystr(perm->user)) {
430                         kstrdup(&perm->user, eve);
431                         perm->perm = 0644; /* nothing secret in ctl */
432                 }
433                 devdir(c, q, "ctl", 0, perm->user, perm->perm, dp);
434                 rv = 1;
435                 break;
436
437         case Qraw:
438                 mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qraw),
439                       unit->vers, QTFILE);
440                 perm = &unit->rawperm;
441                 if (emptystr(perm->user)) {
442                         kstrdup(&perm->user, eve);
443                         perm->perm = DMEXCL | 0600;
444                 }
445                 devdir(c, q, "raw", 0, perm->user, perm->perm, dp);
446                 rv = 1;
447                 break;
448
449         case Qpart:
450                 pp = &unit->part[PART(c->qid)];
451                 l = (pp->end - pp->start) * unit->secsize;
452                 mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qpart),
453                       unit->vers + pp->vers, QTFILE);
454                 if (emptystr(pp->SDperm.user))
455                         kstrdup(&pp->SDperm.user, eve);
456                 devdir(c, q, pp->SDperm.name, l, pp->SDperm.user, pp->SDperm.perm, dp);
457                 rv = 1;
458                 break;
459         }
460
461         decref(&sdev->r);
462         return rv;
463 }
464
465 static int sd1gen(struct chan *c, int i, struct dir *dp)
466 {
467         struct qid q;
468
469         switch (i) {
470         case Qtopctl:
471                 mkqid(&q, QID(0, 0, 0, Qtopctl), 0, QTFILE);
472                 devdir(c, q, "sdctl", 0, eve, 0644, dp); /* no secrets */
473                 return 1;
474         }
475         return -1;
476 }
477
478 static int sdgen(struct chan *c, char *d, struct dirtab *dir, int j, int s,
479                  struct dir *dp)
480 {
481         struct proc *up = externup();
482         struct qid q = {};
483         int64_t l;
484         int i, r;
485         struct sdpart *pp;
486         struct sdunit *unit;
487         struct sdev *sdev;
488
489         switch (TYPE(c->qid)) {
490         case Qtopdir:
491                 if (s == DEVDOTDOT) {
492                         mkqid(&q, QID(0, 0, 0, Qtopdir), 0, QTDIR);
493                         sprint(up->genbuf, "#%C", sddevtab.dc);
494                         devdir(c, q, up->genbuf, 0, eve, 0555, dp);
495                         return 1;
496                 }
497
498                 if (s + Qtopbase < Qunitdir)
499                         return sd1gen(c, s + Qtopbase, dp);
500                 s -= (Qunitdir - Qtopbase);
501
502                 qlock(&devslock);
503                 for (i = 0; i < nelem(devs); i++) {
504                         if (devs[i]) {
505                                 if (s < devs[i]->nunit)
506                                         break;
507                                 s -= devs[i]->nunit;
508                         }
509                 }
510
511                 if (i == nelem(devs)) {
512                         /* Run off the end of the list */
513                         qunlock(&devslock);
514                         return -1;
515                 }
516
517                 if ((sdev = devs[i]) == nil) {
518                         qunlock(&devslock);
519                         return 0;
520                 }
521
522                 incref(&sdev->r);
523                 qunlock(&devslock);
524
525                 if ((unit = sdev->unit[s]) == nil)
526                         if ((unit = sdgetunit(sdev, s)) == nil) {
527                                 decref(&sdev->r);
528                                 return 0;
529                         }
530
531                 mkqid(&q, QID(sdev->idno, s, 0, Qunitdir), 0, QTDIR);
532                 if (emptystr(unit->SDperm.user))
533                         kstrdup(&unit->SDperm.user, eve);
534                 devdir(c, q, unit->SDperm.name, 0, unit->SDperm.user, unit->SDperm.perm,
535                        dp);
536                 decref(&sdev->r);
537                 return 1;
538
539         case Qunitdir:
540                 if (s == DEVDOTDOT) {
541                         mkqid(&q, QID(0, 0, 0, Qtopdir), 0, QTDIR);
542                         sprint(up->genbuf, "#%C", sddevtab.dc);
543                         devdir(c, q, up->genbuf, 0, eve, 0555, dp);
544                         return 1;
545                 }
546
547                 if ((sdev = sdgetdev(DEV(c->qid))) == nil) {
548                         devdir(c, c->qid, "unavailable", 0, eve, 0, dp);
549                         return 1;
550                 }
551
552                 unit = sdev->unit[UNIT(c->qid)];
553                 qlock(&unit->ctl);
554
555                 /*
556                  * Check for media change.
557                  * If one has already been detected, sectors will be zero.
558                  * If there is one waiting to be detected, online
559                  * will return > 1.
560                  * Online is a bit of a large hammer but does the job.
561                  */
562                 if (unit->sectors == 0 ||
563                     (unit->dev->ifc->online && unit->dev->ifc->online(unit) > 1))
564                         sdinitpart(unit);
565
566                 i = s + Qunitbase;
567                 if (i < Qpart) {
568                         r = sd2gen(c, i, dp);
569                         qunlock(&unit->ctl);
570                         decref(&sdev->r);
571                         return r;
572                 }
573                 i -= Qpart;
574                 if (unit->part == nil || i >= unit->npart) {
575                         qunlock(&unit->ctl);
576                         decref(&sdev->r);
577                         break;
578                 }
579                 pp = &unit->part[i];
580                 if (!pp->valid) {
581                         qunlock(&unit->ctl);
582                         decref(&sdev->r);
583                         return 0;
584                 }
585                 l = (pp->end - pp->start) * (int64_t)unit->secsize;
586                 mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), i, Qpart),
587                       unit->vers + pp->vers, QTFILE);
588                 if (emptystr(pp->SDperm.user))
589                         kstrdup(&pp->SDperm.user, eve);
590                 devdir(c, q, pp->SDperm.name, l, pp->SDperm.user, pp->SDperm.perm, dp);
591                 qunlock(&unit->ctl);
592                 decref(&sdev->r);
593                 return 1;
594         case Qraw:
595         case Qctl:
596         case Qpart:
597                 if ((sdev = sdgetdev(DEV(c->qid))) == nil) {
598                         devdir(c, q, "unavailable", 0, eve, 0, dp);
599                         return 1;
600                 }
601                 unit = sdev->unit[UNIT(c->qid)];
602                 qlock(&unit->ctl);
603                 r = sd2gen(c, TYPE(c->qid), dp);
604                 qunlock(&unit->ctl);
605                 decref(&sdev->r);
606                 return r;
607         case Qtopctl:
608                 return sd1gen(c, TYPE(c->qid), dp);
609         default:
610                 break;
611         }
612
613         return -1;
614 }
615
616 static struct chan *sdattach(char *spec)
617 {
618         struct chan *c;
619         char *p;
620         struct sdev *sdev;
621         int idno, subno;
622
623         if (*spec == '\0') {
624                 c = devattach(sddevtab.dc, spec);
625                 mkqid(&c->qid, QID(0, 0, 0, Qtopdir), 0, QTDIR);
626                 return c;
627         }
628
629         if (spec[0] != 's' || spec[1] != 'd')
630                 error(Ebadspec);
631         idno = spec[2];
632         subno = strtol(&spec[3], &p, 0);
633         if (p == &spec[3])
634                 error(Ebadspec);
635
636         if ((sdev = sdgetdev(idno)) == nil)
637                 error(Enonexist);
638         if (sdgetunit(sdev, subno) == nil) {
639                 decref(&sdev->r);
640                 error(Enonexist);
641         }
642
643         c = devattach(sddevtab.dc, spec);
644         mkqid(&c->qid, QID(sdev->idno, subno, 0, Qunitdir), 0, QTDIR);
645         c->devno = (sdev->idno << UnitLOG) + subno;
646         decref(&sdev->r);
647         return c;
648 }
649
650 static struct walkqid *sdwalk(struct chan *c, struct chan *nc, char **name,
651                               int nname)
652 {
653         return devwalk(c, nc, name, nname, nil, 0, sdgen);
654 }
655
656 static int32_t sdstat(struct chan *c, uint8_t *db, int32_t n)
657 {
658         return devstat(c, db, n, nil, 0, sdgen);
659 }
660
661 static struct chan *sdopen(struct chan *c, int omode)
662 {
663         struct proc *up = externup();
664         struct sdpart *pp;
665         struct sdunit *unit;
666         struct sdev *sdev;
667         uint8_t tp;
668
669         c = devopen(c, omode, 0, 0, sdgen);
670         if ((tp = TYPE(c->qid)) != Qctl && tp != Qraw && tp != Qpart)
671                 return c;
672
673         sdev = sdgetdev(DEV(c->qid));
674         if (sdev == nil)
675                 error(Enonexist);
676
677         unit = sdev->unit[UNIT(c->qid)];
678
679         switch (TYPE(c->qid)) {
680         case Qctl:
681                 c->qid.vers = unit->vers;
682                 break;
683         case Qraw:
684                 c->qid.vers = unit->vers;
685                 if (TAS(&unit->rawinuse) != 0) {
686                         c->flag &= ~COPEN;
687                         decref(&sdev->r);
688                         error(Einuse);
689                 }
690                 unit->state = Rawcmd;
691                 break;
692         case Qpart:
693                 qlock(&unit->ctl);
694                 if (waserror()) {
695                         qunlock(&unit->ctl);
696                         c->flag &= ~COPEN;
697                         decref(&sdev->r);
698                         nexterror();
699                 }
700                 pp = &unit->part[PART(c->qid)];
701                 c->qid.vers = unit->vers + pp->vers;
702                 qunlock(&unit->ctl);
703                 poperror();
704                 break;
705         }
706         decref(&sdev->r);
707         return c;
708 }
709
710 static void sdclose(struct chan *c)
711 {
712         struct sdunit *unit;
713         struct sdev *sdev;
714
715         if (c->qid.type & QTDIR)
716                 return;
717         if (!(c->flag & COPEN))
718                 return;
719
720         switch (TYPE(c->qid)) {
721         default:
722                 break;
723         case Qraw:
724                 sdev = sdgetdev(DEV(c->qid));
725                 if (sdev) {
726                         unit = sdev->unit[UNIT(c->qid)];
727                         unit->rawinuse = 0;
728                         decref(&sdev->r);
729                 }
730                 break;
731         }
732 }
733
734 static int32_t sdbio(struct chan *c, int write, char *a, int32_t len,
735                      int64_t off)
736 {
737         struct proc *up = externup();
738         int nchange;
739         uint8_t *b;
740         struct sdpart *pp;
741         struct sdunit *unit;
742         struct sdev *sdev;
743         int64_t bno;
744         int32_t l, max, nb, offset;
745
746         sdev = sdgetdev(DEV(c->qid));
747         if (sdev == nil) {
748                 decref(&sdev->r);
749                 error(Enonexist);
750         }
751         unit = sdev->unit[UNIT(c->qid)];
752         if (unit == nil)
753                 error(Enonexist);
754
755         nchange = 0;
756         qlock(&unit->ctl);
757         while (waserror()) {
758                 /* notification of media change; go around again */
759                 if (strcmp(up->errstr, Eio) == 0 && unit->sectors == 0 &&
760                     nchange++ == 0) {
761                         sdinitpart(unit);
762                         continue;
763                 }
764
765                 /* other errors; give up */
766                 qunlock(&unit->ctl);
767                 decref(&sdev->r);
768                 nexterror();
769         }
770         pp = &unit->part[PART(c->qid)];
771         if (unit->vers + pp->vers != c->qid.vers)
772                 error(Echange);
773
774         /*
775          * Check the request is within bounds.
776          * Removeable drives are locked throughout the I/O
777          * in case the media changes unexpectedly.
778          * Non-removeable drives are not locked during the I/O
779          * to allow the hardware to optimise if it can; this is
780          * a little fast and loose.
781          * It's assumed that non-removeable media parameters
782          * (sectors, secsize) can't change once the drive has
783          * been brought online.
784          */
785         bno = (off / unit->secsize) + pp->start;
786         nb = ((off + len + unit->secsize - 1) / unit->secsize) + pp->start - bno;
787         max = SDmaxio / unit->secsize;
788         if (nb > max)
789                 nb = max;
790         if (bno + nb > pp->end)
791                 nb = pp->end - bno;
792         if (bno >= pp->end || nb == 0) {
793                 if (write)
794                         error(Eio);
795                 qunlock(&unit->ctl);
796                 decref(&sdev->r);
797                 poperror();
798                 return 0;
799         }
800         if (!(unit->inquiry[1] & SDinq1removable)) {
801                 qunlock(&unit->ctl);
802                 poperror();
803         }
804
805         b = sdmalloc(nb * unit->secsize);
806         if (b == nil)
807                 error(Enomem);
808         if (waserror()) {
809                 sdfree(b);
810                 if (!(unit->inquiry[1] & SDinq1removable))
811                         decref(&sdev->r); /* gadverdamme! */
812                 nexterror();
813         }
814
815         offset = off % unit->secsize;
816         if (offset + len > nb * unit->secsize)
817                 len = nb * unit->secsize - offset;
818         if (write) {
819                 if (offset || (len % unit->secsize)) {
820                         l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno);
821                         if (l < 0)
822                                 error(Eio);
823                         if (l < (nb * unit->secsize)) {
824                                 nb = l / unit->secsize;
825                                 l = nb * unit->secsize - offset;
826                                 if (len > l)
827                                         len = l;
828                         }
829                 }
830                 memmove(b + offset, a, len);
831                 l = unit->dev->ifc->bio(unit, 0, 1, b, nb, bno);
832                 if (l < 0)
833                         error(Eio);
834                 if (l < offset)
835                         len = 0;
836                 else if (len > l - offset)
837                         len = l - offset;
838         } else {
839                 l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno);
840                 if (l < 0)
841                         error(Eio);
842                 if (l < offset)
843                         len = 0;
844                 else if (len > l - offset)
845                         len = l - offset;
846                 memmove(a, b + offset, len);
847         }
848         sdfree(b);
849         poperror();
850
851         if (unit->inquiry[1] & SDinq1removable) {
852                 qunlock(&unit->ctl);
853                 poperror();
854         }
855
856         decref(&sdev->r);
857         return len;
858 }
859
860 static int32_t sdrio(struct sdreq *r, void *a, int32_t n)
861 {
862         struct proc *up = externup();
863         void *data;
864
865         if (n >= SDmaxio || n < 0)
866                 error(Etoobig);
867
868         data = nil;
869         if (n) {
870                 if ((data = sdmalloc(n)) == nil)
871                         error(Enomem);
872                 if (r->write)
873                         memmove(data, a, n);
874         }
875         r->data = data;
876         r->dlen = n;
877
878         if (waserror()) {
879                 sdfree(data);
880                 r->data = nil;
881                 nexterror();
882         }
883
884         if (r->unit->dev->ifc->rio(r) != SDok)
885                 error(Eio);
886
887         if (!r->write && r->rlen > 0)
888                 memmove(a, data, r->rlen);
889         sdfree(data);
890         r->data = nil;
891         poperror();
892
893         return r->rlen;
894 }
895
896 /*
897  * SCSI simulation for non-SCSI devices
898  */
899 int sdsetsense(struct sdreq *r, int status, int key, int asc, int ascq)
900 {
901         int len;
902         struct sdunit *unit;
903
904         unit = r->unit;
905         unit->sense[2] = key;
906         unit->sense[12] = asc;
907         unit->sense[13] = ascq;
908
909         r->status = status;
910         if (status == SDcheck && !(r->flags & SDnosense)) {
911                 /* request sense case from sdfakescsi */
912                 len = sizeof unit->sense;
913                 if (len > sizeof r->sense - 1)
914                         len = sizeof r->sense - 1;
915                 memmove(r->sense, unit->sense, len);
916                 unit->sense[2] = 0;
917                 unit->sense[12] = 0;
918                 unit->sense[13] = 0;
919                 r->flags |= SDvalidsense;
920                 return SDok;
921         }
922         return status;
923 }
924
925 int sdmodesense(struct sdreq *r, uint8_t *cmd, void *info, int ilen)
926 {
927         int len;
928         uint8_t *data;
929
930         /*
931          * Fake a vendor-specific request with page code 0,
932          * return the drive info.
933          */
934         if ((cmd[2] & 0x3F) != 0 && (cmd[2] & 0x3F) != 0x3F)
935                 return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
936         len = (cmd[7] << 8) | cmd[8];
937         if (len == 0)
938                 return SDok;
939         if (len < 8 + ilen)
940                 return sdsetsense(r, SDcheck, 0x05, 0x1A, 0);
941         if (r->data == nil || r->dlen < len)
942                 return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
943         data = r->data;
944         memset(data, 0, 8);
945         data[0] = ilen >> 8;
946         data[1] = ilen;
947         if (ilen)
948                 memmove(data + 8, info, ilen);
949         r->rlen = 8 + ilen;
950         return sdsetsense(r, SDok, 0, 0, 0);
951 }
952
953 int sdfakescsi(struct sdreq *r, void *info, int ilen)
954 {
955         uint8_t *cmd, *p;
956         uint64_t len;
957         struct sdunit *unit;
958
959         cmd = r->cmd;
960         r->rlen = 0;
961         unit = r->unit;
962
963         /*
964          * Rewrite read(6)/write(6) into read(10)/write(10).
965          */
966         switch (cmd[0]) {
967         case 0x08: /* read */
968         case 0x0A: /* write */
969                 cmd[9] = 0;
970                 cmd[8] = cmd[4];
971                 cmd[7] = 0;
972                 cmd[6] = 0;
973                 cmd[5] = cmd[3];
974                 cmd[4] = cmd[2];
975                 cmd[3] = cmd[1] & 0x0F;
976                 cmd[2] = 0;
977                 cmd[1] &= 0xE0;
978                 cmd[0] |= 0x20;
979                 break;
980         }
981
982         /*
983          * Map SCSI commands into ATA commands for discs.
984          * Fail any command with a LUN except INQUIRY which
985          * will return 'logical unit not supported'.
986          */
987         if ((cmd[1] >> 5) && cmd[0] != 0x12)
988                 return sdsetsense(r, SDcheck, 0x05, 0x25, 0);
989
990         switch (cmd[0]) {
991         default:
992                 return sdsetsense(r, SDcheck, 0x05, 0x20, 0);
993
994         case 0x00: /* test unit ready */
995                 return sdsetsense(r, SDok, 0, 0, 0);
996
997         case 0x03: /* request sense */
998                 if (cmd[4] < sizeof unit->sense)
999                         len = cmd[4];
1000                 else
1001                         len = sizeof unit->sense;
1002                 if (r->data && r->dlen >= len) {
1003                         memmove(r->data, unit->sense, len);
1004                         r->rlen = len;
1005                 }
1006                 return sdsetsense(r, SDok, 0, 0, 0);
1007
1008         case 0x12: /* inquiry */
1009                 if (cmd[4] < sizeof unit->inquiry)
1010                         len = cmd[4];
1011                 else
1012                         len = sizeof unit->inquiry;
1013                 if (r->data && r->dlen >= len) {
1014                         memmove(r->data, unit->inquiry, len);
1015                         r->rlen = len;
1016                 }
1017                 return sdsetsense(r, SDok, 0, 0, 0);
1018
1019         case 0x1B: /* start/stop unit */
1020                 /*
1021                 * nop for now, can use power management later.
1022                                    */
1023                 return sdsetsense(r, SDok, 0, 0, 0);
1024
1025         case 0x25: /* read capacity */
1026                 if ((cmd[1] & 0x01) || cmd[2] || cmd[3])
1027                         return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
1028                 if (r->data == nil || r->dlen < 8)
1029                         return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
1030
1031                 /*
1032                  * Read capacity returns the LBA of the last sector.
1033                  */
1034                 len = unit->sectors - 1;
1035                 p = r->data;
1036                 *p++ = len >> 24;
1037                 *p++ = len >> 16;
1038                 *p++ = len >> 8;
1039                 *p++ = len;
1040                 len = 512;
1041                 *p++ = len >> 24;
1042                 *p++ = len >> 16;
1043                 *p++ = len >> 8;
1044                 *p++ = len;
1045                 r->rlen = p - (uint8_t *)r->data;
1046                 return sdsetsense(r, SDok, 0, 0, 0);
1047
1048         case 0x9E: /* long read capacity */
1049                 if ((cmd[1] & 0x01) || cmd[2] || cmd[3])
1050                         return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
1051                 if (r->data == nil || r->dlen < 8)
1052                         return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
1053                 /*
1054                  * Read capcity returns the LBA of the last sector.
1055                  */
1056                 len = unit->sectors - 1;
1057                 p = r->data;
1058                 *p++ = len >> 56;
1059                 *p++ = len >> 48;
1060                 *p++ = len >> 40;
1061                 *p++ = len >> 32;
1062                 *p++ = len >> 24;
1063                 *p++ = len >> 16;
1064                 *p++ = len >> 8;
1065                 *p++ = len;
1066                 len = 512;
1067                 *p++ = len >> 24;
1068                 *p++ = len >> 16;
1069                 *p++ = len >> 8;
1070                 *p++ = len;
1071                 r->rlen = p - (uint8_t *)r->data;
1072                 return sdsetsense(r, SDok, 0, 0, 0);
1073
1074         case 0x5A: /* mode sense */
1075                 return sdmodesense(r, cmd, info, ilen);
1076
1077         case 0x28: /* read */
1078         case 0x2A: /* write */
1079         case 0x88: /* read16 */
1080         case 0x8a: /* write16 */
1081                 return SDnostatus;
1082         }
1083 }
1084
1085 static int32_t sdread(struct chan *c, void *a, int32_t n, int64_t off)
1086 {
1087         struct proc *up = externup();
1088         char *p, *e, *buf;
1089         struct sdpart *pp;
1090         struct sdunit *unit;
1091         struct sdev *sdev;
1092         int32_t offset;
1093         int i, l, mm, status;
1094
1095         offset = off;
1096         switch (TYPE(c->qid)) {
1097         default:
1098                 error(Eperm);
1099         case Qtopctl:
1100                 mm = 64 * 1024; /* room for register dumps */
1101                 p = buf = malloc(mm);
1102                 if (p == nil)
1103                         error(Enomem);
1104                 e = p + mm;
1105                 qlock(&devslock);
1106                 for (i = 0; i < nelem(devs); i++) {
1107                         sdev = devs[i];
1108                         if (sdev && sdev->ifc->rtopctl)
1109                                 p = sdev->ifc->rtopctl(sdev, p, e);
1110                 }
1111                 qunlock(&devslock);
1112                 n = readstr(offset, a, n, buf);
1113                 free(buf);
1114                 return n;
1115
1116         case Qtopdir:
1117         case Qunitdir:
1118                 return devdirread(c, a, n, 0, 0, sdgen);
1119
1120         case Qctl:
1121                 sdev = sdgetdev(DEV(c->qid));
1122                 if (sdev == nil)
1123                         error(Enonexist);
1124
1125                 unit = sdev->unit[UNIT(c->qid)];
1126                 mm = 16 * 1024; /* room for register dumps */
1127                 p = malloc(mm);
1128                 if (p == nil)
1129                         error(Enomem);
1130                 l = snprint(p, mm, "inquiry %.48s\n", (char *)unit->inquiry + 8);
1131                 qlock(&unit->ctl);
1132                 /*
1133                  * If there's a device specific routine it must
1134                  * provide all information pertaining to night geometry
1135                  * and the garscadden trains.
1136                  */
1137                 if (unit->dev->ifc->rctl)
1138                         l += unit->dev->ifc->rctl(unit, p + l, mm - l);
1139                 if (unit->sectors == 0)
1140                         sdinitpart(unit);
1141                 if (unit->sectors) {
1142                         if (unit->dev->ifc->rctl == nil)
1143                                 l += snprint(p + l, mm - l, "geometry %llu %lu\n",
1144                                              unit->sectors, unit->secsize);
1145                         pp = unit->part;
1146                         for (i = 0; i < unit->npart; i++) {
1147                                 if (pp->valid)
1148                                         l += snprint(p + l, mm - l, "part %s %llu %llu\n",
1149                                                      pp->SDperm.name, pp->start, pp->end);
1150                                 pp++;
1151                         }
1152                 }
1153                 qunlock(&unit->ctl);
1154                 decref(&sdev->r);
1155                 l = readstr(offset, a, n, p);
1156                 free(p);
1157                 return l;
1158
1159         case Qraw:
1160                 sdev = sdgetdev(DEV(c->qid));
1161                 if (sdev == nil)
1162                         error(Enonexist);
1163
1164                 unit = sdev->unit[UNIT(c->qid)];
1165                 qlock(&unit->raw);
1166                 if (waserror()) {
1167                         qunlock(&unit->raw);
1168                         decref(&sdev->r);
1169                         nexterror();
1170                 }
1171                 if (unit->state == Rawdata) {
1172                         unit->state = Rawstatus;
1173                         i = sdrio(unit->req, a, n);
1174                 } else if (unit->state == Rawstatus) {
1175                         status = unit->req->status;
1176                         unit->state = Rawcmd;
1177                         free(unit->req);
1178                         unit->req = nil;
1179                         i = readnum(0, a, n, status, NUMSIZE);
1180                 } else
1181                         i = 0;
1182                 qunlock(&unit->raw);
1183                 decref(&sdev->r);
1184                 poperror();
1185                 return i;
1186
1187         case Qpart:
1188                 return sdbio(c, 0, a, n, off);
1189         }
1190 }
1191
1192 static void legacytopctl(struct cmdbuf *);
1193
1194 static int32_t sdwrite(struct chan *c, void *a, int32_t n, int64_t off)
1195 {
1196         struct proc *up = externup();
1197         char *f0;
1198         int i;
1199         uint64_t end, start;
1200         struct cmdbuf *cb;
1201         struct sdifc *ifc;
1202         struct sdreq *req;
1203         struct sdunit *unit;
1204         struct sdev *sdev;
1205
1206         switch (TYPE(c->qid)) {
1207         default:
1208                 error(Eperm);
1209         case Qtopctl:
1210                 cb = parsecmd(a, n);
1211                 if (waserror()) {
1212                         free(cb);
1213                         nexterror();
1214                 }
1215                 if (cb->nf == 0)
1216                         error("empty control message");
1217                 f0 = cb->f[0];
1218                 cb->f++;
1219                 cb->nf--;
1220                 if (strcmp(f0, "config") == 0) {
1221                         /* wormhole into ugly legacy interface */
1222                         legacytopctl(cb);
1223                         poperror();
1224                         free(cb);
1225                         break;
1226                 }
1227                 /*
1228                  * "ata arg..." invokes sdifc[i]->wtopctl(nil, cb),
1229                  * where sdifc[i]->SDperm.name=="ata" and cb contains the args.
1230                  */
1231                 ifc = nil;
1232                 sdev = nil;
1233                 for (i = 0; sdifc[i]; i++) {
1234                         if (strcmp(sdifc[i]->name, f0) == 0) {
1235                                 ifc = sdifc[i];
1236                                 sdev = nil;
1237                                 goto subtopctl;
1238                         }
1239                 }
1240                 /*
1241                  * "sd1 arg..." invokes sdifc[i]->wtopctl(sdev, cb),
1242                  * where sdifc[i] and sdev match controller letter "1",
1243                  * and cb contains the args.
1244                  */
1245                 if (f0[0] == 's' && f0[1] == 'd' && f0[2] && f0[3] == 0) {
1246                         if ((sdev = sdgetdev(f0[2])) != nil) {
1247                                 ifc = sdev->ifc;
1248                                 goto subtopctl;
1249                         }
1250                 }
1251                 error("unknown interface");
1252
1253         subtopctl:
1254                 if (waserror()) {
1255                         if (sdev)
1256                                 decref(&sdev->r);
1257                         nexterror();
1258                 }
1259                 if (ifc->wtopctl)
1260                         ifc->wtopctl(sdev, cb);
1261                 else
1262                         error(Ebadctl);
1263                 poperror();
1264                 poperror();
1265                 if (sdev)
1266                         decref(&sdev->r);
1267                 free(cb);
1268                 break;
1269
1270         case Qctl:
1271                 cb = parsecmd(a, n);
1272                 sdev = sdgetdev(DEV(c->qid));
1273                 if (sdev == nil)
1274                         error(Enonexist);
1275                 unit = sdev->unit[UNIT(c->qid)];
1276
1277                 qlock(&unit->ctl);
1278                 if (waserror()) {
1279                         qunlock(&unit->ctl);
1280                         decref(&sdev->r);
1281                         free(cb);
1282                         nexterror();
1283                 }
1284                 if (unit->vers != c->qid.vers)
1285                         error(Echange);
1286
1287                 if (cb->nf < 1)
1288                         error(Ebadctl);
1289                 if (strcmp(cb->f[0], "part") == 0) {
1290                         if (cb->nf != 4)
1291                                 error(Ebadctl);
1292                         if (unit->sectors == 0 && !sdinitpart(unit))
1293                                 error(Eio);
1294                         start = strtoull(cb->f[2], 0, 0);
1295                         end = strtoull(cb->f[3], 0, 0);
1296                         sdaddpart(unit, cb->f[1], start, end);
1297                 } else if (strcmp(cb->f[0], "delpart") == 0) {
1298                         if (cb->nf != 2 || unit->part == nil)
1299                                 error(Ebadctl);
1300                         sddelpart(unit, cb->f[1]);
1301                 } else if (unit->dev->ifc->wctl)
1302                         unit->dev->ifc->wctl(unit, cb);
1303                 else
1304                         error(Ebadctl);
1305                 qunlock(&unit->ctl);
1306                 decref(&sdev->r);
1307                 poperror();
1308                 free(cb);
1309                 break;
1310
1311         case Qraw:
1312                 sdev = sdgetdev(DEV(c->qid));
1313                 if (sdev == nil)
1314                         error(Enonexist);
1315                 unit = sdev->unit[UNIT(c->qid)];
1316                 qlock(&unit->raw);
1317                 if (waserror()) {
1318                         qunlock(&unit->raw);
1319                         decref(&sdev->r);
1320                         nexterror();
1321                 }
1322                 switch (unit->state) {
1323                 case Rawcmd:
1324                         if (n < 6 || n > sizeof(req->cmd))
1325                                 error(Ebadarg);
1326                         if ((req = malloc(sizeof(struct sdreq))) == nil)
1327                                 error(Enomem);
1328                         req->unit = unit;
1329                         memmove(req->cmd, a, n);
1330                         req->clen = n;
1331                         req->flags = SDnosense;
1332                         req->status = ~0;
1333
1334                         unit->req = req;
1335                         unit->state = Rawdata;
1336                         break;
1337
1338                 case Rawstatus:
1339                         unit->state = Rawcmd;
1340                         free(unit->req);
1341                         unit->req = nil;
1342                         error(Ebadusefd);
1343
1344                 case Rawdata:
1345                         unit->state = Rawstatus;
1346                         unit->req->write = 1;
1347                         n = sdrio(unit->req, a, n);
1348                 }
1349                 qunlock(&unit->raw);
1350                 decref(&sdev->r);
1351                 poperror();
1352                 break;
1353         case Qpart:
1354                 return sdbio(c, 1, a, n, off);
1355         }
1356
1357         return n;
1358 }
1359
1360 static int32_t sdwstat(struct chan *c, uint8_t *dp, int32_t n)
1361 {
1362         struct proc *up = externup();
1363         struct dir *d;
1364         struct sdpart *pp;
1365         struct sdperm *perm;
1366         struct sdunit *unit;
1367         struct sdev *sdev;
1368
1369         if (c->qid.type & QTDIR)
1370                 error(Eperm);
1371
1372         sdev = sdgetdev(DEV(c->qid));
1373         if (sdev == nil)
1374                 error(Enonexist);
1375         unit = sdev->unit[UNIT(c->qid)];
1376         qlock(&unit->ctl);
1377         d = nil;
1378         if (waserror()) {
1379                 free(d);
1380                 qunlock(&unit->ctl);
1381                 decref(&sdev->r);
1382                 nexterror();
1383         }
1384
1385         switch (TYPE(c->qid)) {
1386         default:
1387                 error(Eperm);
1388         case Qctl:
1389                 perm = &unit->ctlperm;
1390                 break;
1391         case Qraw:
1392                 perm = &unit->rawperm;
1393                 break;
1394         case Qpart:
1395                 pp = &unit->part[PART(c->qid)];
1396                 if (unit->vers + pp->vers != c->qid.vers)
1397                         error(Enonexist);
1398                 perm = &pp->SDperm;
1399                 break;
1400         }
1401
1402         if (strcmp(up->user, perm->user) && !iseve())
1403                 error(Eperm);
1404
1405         d = smalloc(sizeof(struct dir) + n);
1406         n = convM2D(dp, n, &d[0], (char *)&d[1]);
1407         if (n == 0)
1408                 error(Eshortstat);
1409         if (!emptystr(d[0].uid))
1410                 kstrdup(&perm->user, d[0].uid);
1411         if (d[0].mode != (uint32_t)~0UL)
1412                 perm->perm = (perm->perm & ~0777) | (d[0].mode & 0777);
1413
1414         free(d);
1415         qunlock(&unit->ctl);
1416         decref(&sdev->r);
1417         poperror();
1418         return n;
1419 }
1420
1421 static int configure(char *spec, DevConf *cf)
1422 {
1423         struct sdev *s, *sdev;
1424         char *p;
1425         int i;
1426
1427         if (sdindex(*spec) < 0)
1428                 error("bad sd spec");
1429
1430         if ((p = strchr(cf->type, '/')) != nil)
1431                 *p++ = '\0';
1432
1433         for (i = 0; sdifc[i] != nil; i++)
1434                 if (strcmp(sdifc[i]->name, cf->type) == 0)
1435                         break;
1436         if (sdifc[i] == nil)
1437                 error("sd type not found");
1438         if (p)
1439                 *(p - 1) = '/';
1440
1441         if (sdifc[i]->probe == nil)
1442                 error("sd type cannot probe");
1443
1444         sdev = sdifc[i]->probe(cf);
1445         for (s = sdev; s; s = s->next)
1446                 s->idno = *spec;
1447         sdadddevs(sdev);
1448         return 0;
1449 }
1450
1451 static int unconfigure(char *spec)
1452 {
1453         int i;
1454         struct sdev *sdev;
1455         struct sdunit *unit;
1456
1457         if ((i = sdindex(*spec)) < 0)
1458                 error(Enonexist);
1459
1460         qlock(&devslock);
1461         if ((sdev = devs[i]) == nil) {
1462                 qunlock(&devslock);
1463                 error(Enonexist);
1464         }
1465         if (sdev->r.ref) {
1466                 qunlock(&devslock);
1467                 error(Einuse);
1468         }
1469         devs[i] = nil;
1470         qunlock(&devslock);
1471
1472         /* make sure no interrupts arrive anymore before removing resources */
1473         if (sdev->enabled && sdev->ifc->disable)
1474                 sdev->ifc->disable(sdev);
1475
1476         for (i = 0; i != sdev->nunit; i++) {
1477                 if (unit = sdev->unit[i]) {
1478                         free(unit->SDperm.name);
1479                         free(unit->SDperm.user);
1480                         free(unit);
1481                 }
1482         }
1483
1484         if (sdev->ifc->clear)
1485                 sdev->ifc->clear(sdev);
1486         free(sdev);
1487         return 0;
1488 }
1489
1490 static int sdconfig(int on, char *spec, DevConf *cf)
1491 {
1492         if (on)
1493                 return configure(spec, cf);
1494         return unconfigure(spec);
1495 }
1496
1497 struct dev sddevtab = {
1498     .dc = 'S',
1499     .name = "sd",
1500
1501     .reset = sdreset,
1502     .init = devinit,
1503     .shutdown = devshutdown,
1504     .attach = sdattach,
1505     .walk = sdwalk,
1506     .stat = sdstat,
1507     .open = sdopen,
1508     .create = devcreate,
1509     .close = sdclose,
1510     .read = sdread,
1511     .bread = devbread,
1512     .write = sdwrite,
1513     .bwrite = devbwrite,
1514     .remove = devremove,
1515     .wstat = sdwstat,
1516     .power = devpower,
1517     .config = sdconfig, /* probe; only called for pcmcia-like devices */
1518 };
1519
1520 /*
1521  * This is wrong for so many reasons.  This code must go.
1522  */
1523 typedef struct Confdata Confdata;
1524 struct Confdata {
1525         int on;
1526         char *spec;
1527         DevConf cf;
1528 };
1529
1530 static void parseswitch(Confdata *cd, char *option)
1531 {
1532         if (!strcmp("on", option))
1533                 cd->on = 1;
1534         else if (!strcmp("off", option))
1535                 cd->on = 0;
1536         else
1537                 error(Ebadarg);
1538 }
1539
1540 static void parsespec(Confdata *cd, char *option)
1541 {
1542         if (strlen(option) > 1)
1543                 error(Ebadarg);
1544         cd->spec = option;
1545 }
1546
1547 static struct devport *getnewport(DevConf *dc)
1548 {
1549         struct devport *p;
1550
1551         p = (struct devport *)malloc((dc->nports + 1) * sizeof(struct devport));
1552         if (p == nil)
1553                 error(Enomem);
1554         if (dc->nports > 0) {
1555                 memmove(p, dc->ports, dc->nports * sizeof(struct devport));
1556                 free(dc->ports);
1557         }
1558         dc->ports = p;
1559         p = &dc->ports[dc->nports++];
1560         p->size = -1;
1561         p->port = (uint32_t)-1;
1562         return p;
1563 }
1564
1565 static void parseport(Confdata *cd, char *option)
1566 {
1567         char *e;
1568         struct devport *p;
1569
1570         if (cd->cf.nports == 0 ||
1571             cd->cf.ports[cd->cf.nports - 1].port != (uint32_t)-1)
1572                 p = getnewport(&cd->cf);
1573         else
1574                 p = &cd->cf.ports[cd->cf.nports - 1];
1575         p->port = strtol(option, &e, 0);
1576         if (e == nil || *e != '\0')
1577                 error(Ebadarg);
1578 }
1579
1580 static void parsesize(Confdata *cd, char *option)
1581 {
1582         char *e;
1583         struct devport *p;
1584
1585         if (cd->cf.nports == 0 || cd->cf.ports[cd->cf.nports - 1].size != -1)
1586                 p = getnewport(&cd->cf);
1587         else
1588                 p = &cd->cf.ports[cd->cf.nports - 1];
1589         p->size = (int)strtol(option, &e, 0);
1590         if (e == nil || *e != '\0')
1591                 error(Ebadarg);
1592 }
1593
1594 static void parseirq(Confdata *cd, char *option)
1595 {
1596         char *e;
1597
1598         cd->cf.intnum = strtoul(option, &e, 0);
1599         if (e == nil || *e != '\0')
1600                 error(Ebadarg);
1601 }
1602
1603 static void parsetype(Confdata *cd, char *option) { cd->cf.type = option; }
1604
1605 static struct {
1606         char *name;
1607         void (*parse)(Confdata *, char *);
1608 } options[] = {
1609     "switch", parseswitch, "spec", parsespec, "port", parseport,
1610     "size",   parsesize,   "irq",  parseirq,  "type", parsetype,
1611 };
1612
1613 static void legacytopctl(struct cmdbuf *cb)
1614 {
1615         char *opt;
1616         int i, j;
1617         Confdata cd;
1618
1619         memset(&cd, 0, sizeof cd);
1620         cd.on = -1;
1621         for (i = 0; i < cb->nf; i += 2) {
1622                 if (i + 2 > cb->nf)
1623                         error(Ebadarg);
1624                 opt = cb->f[i];
1625                 for (j = 0; j < nelem(options); j++)
1626                         if (strcmp(opt, options[j].name) == 0) {
1627                                 options[j].parse(&cd, cb->f[i + 1]);
1628                                 break;
1629                         }
1630                 if (j == nelem(options))
1631                         error(Ebadarg);
1632         }
1633         /* this has been rewritten to accomodate sdaoe */
1634         if (cd.on < 0 || cd.spec == 0)
1635                 error(Ebadarg);
1636         if (cd.on && cd.cf.type == nil)
1637                 error(Ebadarg);
1638         sdconfig(cd.on, cd.spec, &cd.cf);
1639 }