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