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