Export CONFIG_ options via #version/kconfig
[akaros.git] / kern / drivers / dev / sd.c
index 412bc78..6022cc9 100644 (file)
 /*
  * Storage Device.
  */
-#include "../port/error.h"
-#include "../port/lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "io.h"
-#include "mem.h"
-#include "u.h"
-#include "ureg.h"
 
-#include "../port/sd.h"
+#include <vfs.h>
+
+#include <assert.h>
+#include <cpio.h>
+#include <error.h>
+#include <ip.h>
+#include <kfs.h>
+#include <kmalloc.h>
+#include <kref.h>
+#include <pmap.h>
+#include <slab.h>
+#include <smp.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <sd.h>
 
 extern struct dev sddevtab;
-extern struct sdifc *sdifc[];
+struct sdifc sdiahciifc;
+
+/* In Plan 9, this array is auto-generated. That's almost certainly not
+ * necessary;
+ * we can use linker sets at some point, as we do elsewhere in Akaros. */
+struct sdifc *sdifc[] = {
+    &sdiahciifc, NULL,
+};
+
+static const char Echange[] = "media or partition has changed";
 
-static char Echange[] = "media or partition has changed";
+static const char devletters[] =
+    "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
 
-static char devletters[] = "0123456789"
-                           "abcdefghijklmnopqrstuvwxyz"
-                           "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+static struct sdev *devs[sizeof(devletters) - 1];
 
-static struct sdev *devs[sizeof devletters - 1];
-static qlock_t devslock;
+static qlock_t devslock = QLOCK_INITIALIZER(devslock);
 
 enum {
        Rawcmd,
@@ -90,7 +104,7 @@ void sdaddpart(struct sdunit *unit, char *name, uint64_t start, uint64_t end)
         * Check name not already used
         * and look for a free slot.
         */
-       if (unit->part != nil) {
+       if (unit->part != NULL) {
                partno = -1;
                for (i = 0; i < unit->npart; i++) {
                        pp = &unit->part[i];
@@ -99,31 +113,34 @@ void sdaddpart(struct sdunit *unit, char *name, uint64_t start, uint64_t end)
                                        partno = i;
                                break;
                        }
-                       if (strcmp(name, pp->SDperm.name) == 0) {
+                       if (strcmp(name, pp->sdperm.name) == 0) {
                                if (pp->start == start && pp->end == end)
                                        return;
-                               error(Ebadctl);
+                               error(EINVAL, "%s: '%s' is not valid", __func__, name);
                        }
                }
        } else {
-               if ((unit->part = malloc(sizeof(struct sdpart) * SDnpart)) == nil)
-                       error(Enomem);
+               unit->part = kzmalloc(sizeof(struct sdpart) * SDnpart, 0);
+               if (unit->part == NULL)
+                       error(ENOMEM, "%s: can't allocate %d bytes", __func__,
+                             sizeof(struct sdpart) * SDnpart);
                unit->npart = SDnpart;
                partno = 0;
        }
 
        /*
         * If no free slot found then increase the
-        * array size (can't get here with unit->part == nil).
+        * array size (can't get here with unit->part == NULL).
         */
        if (partno == -1) {
                if (unit->npart >= NPart)
-                       error(Enomem);
-               if ((pp = malloc(sizeof(struct sdpart) * (unit->npart + SDnpart))) ==
-                   nil)
-                       error(Enomem);
+                       error(ENOMEM, "%s: no memory", __func__);
+               pp = kzmalloc(sizeof(struct sdpart) * (unit->npart + SDnpart), 0);
+               if (pp == NULL)
+                       error(ENOMEM, "%s: Can't allocate space for %d partitions",
+                             unit->npart + SDnpart);
                memmove(pp, unit->part, sizeof(struct sdpart) * unit->npart);
-               free(unit->part);
+               kfree(unit->part);
                unit->part = pp;
                partno = unit->npart;
                unit->npart += SDnpart;
@@ -132,20 +149,22 @@ void sdaddpart(struct sdunit *unit, char *name, uint64_t start, uint64_t end)
        /*
         * Check size and extent are valid.
         */
-       if (start > end || end > unit->sectors)
-               error(Eio);
+       if (start > end)
+               error(EINVAL, "%s: start %d > end %d", __func__, start, end);
+       if (end > unit->sectors)
+               error(EINVAL, "%s: end %d > number of sectors %d", __func__, end,
+                     unit->sectors);
        pp = &unit->part[partno];
        pp->start = start;
        pp->end = end;
-       kstrdup(&pp->SDperm.name, name);
-       kstrdup(&pp->SDperm.user, eve);
-       pp->SDperm.perm = 0640;
+       kstrdup(&pp->sdperm.name, name);
+       kstrdup(&pp->sdperm.user, eve.name);
+       pp->sdperm.perm = 0640;
        pp->valid = 1;
 }
 
 static void sddelpart(struct sdunit *unit, char *name)
 {
-       struct proc *up = externup();
        int i;
        struct sdpart *pp;
        /*
@@ -154,14 +173,17 @@ static void sddelpart(struct sdunit *unit, char *name)
         */
        pp = unit->part;
        for (i = 0; i < unit->npart; i++) {
-               if (strcmp(name, pp->SDperm.name) == 0)
+               if (strcmp(name, pp->sdperm.name) == 0)
                        break;
                pp++;
        }
        if (i >= unit->npart)
-               error(Ebadctl);
-       if (strcmp(up->user, pp->SDperm.user) && !iseve())
-               error(Eperm);
+               error(EINVAL, "%s: %d > npart %d", __func__, i, unit->npart);
+
+       /* TODO: Implement permission checking and raise errors as appropriate. */
+       // if (strcmp(current->user.name, pp->SDperm.user) && !iseve())
+               // error(Eperm);
+
        pp->valid = 0;
        pp->vers++;
 }
@@ -222,20 +244,20 @@ static int sdinitpart(struct sdunit *unit)
  * The gen functions patch it up.
  */
 #if 0
-               snprint(buf, sizeof buf, "%spart", unit->SDperm.name);
-               for(p = getconf(buf); p != nil; p = q){
-                       if(q = strchr(p, '/'))
+               snprintf(buf, sizeof(buf), "%spart", unit->sdperm.name);
+               for (p = getconf(buf); p != NULL; p = q) {
+                       q = strchr(p, '/');
+                       if (q)
                                *q++ = '\0';
-                       nf = tokenize(p, f, nelem(f));
-                       if(nf < 3)
+                       nf = tokenize(p, f, ARRAY_SIZE(f));
+                       if (nf < 3)
                                continue;
 
                        start = strtoull(f[1], 0, 0);
                        end = strtoull(f[2], 0, 0);
-                       if(!waserror()){
+                       if (!waserror())
                                sdaddpart(unit, f[0], start, end);
-                               poperror();
-                       }
+                       poperror();
                }
 #endif
        }
@@ -248,7 +270,7 @@ static int sdindex(int idno)
        char *p;
 
        p = strchr(devletters, idno);
-       if (p == nil)
+       if (p == NULL)
                return -1;
        return p - devletters;
 }
@@ -259,11 +281,12 @@ static struct sdev *sdgetdev(int idno)
        int i;
 
        if ((i = sdindex(idno)) < 0)
-               return nil;
+               return NULL;
 
        qlock(&devslock);
-       if (sdev = devs[i])
-               incref(&sdev->r);
+       sdev = devs[i];
+       if (sdev)
+               kref_get(&sdev->r, 1);
        qunlock(&devslock);
        return sdev;
 }
@@ -282,31 +305,33 @@ static struct sdunit *sdgetunit(struct sdev *sdev, int subno)
        qlock(&sdev->unitlock);
        if (subno > sdev->nunit) {
                qunlock(&sdev->unitlock);
-               return nil;
+               return NULL;
        }
 
        unit = sdev->unit[subno];
-       if (unit == nil) {
+       if (unit == NULL) {
                /*
                 * Probe the unit only once. This decision
                 * may be a little severe and reviewed later.
                 */
                if (sdev->unitflg[subno]) {
                        qunlock(&sdev->unitlock);
-                       return nil;
+                       return NULL;
                }
-               if ((unit = malloc(sizeof(struct sdunit))) == nil) {
+               unit = kzmalloc(sizeof(struct sdunit), 0);
+               if (unit == NULL) {
                        qunlock(&sdev->unitlock);
-                       return nil;
+                       return NULL;
                }
                sdev->unitflg[subno] = 1;
 
-               snprint(buf, sizeof(buf), "%s%d", sdev->name, subno);
-               kstrdup(&unit->SDperm.name, buf);
-               kstrdup(&unit->SDperm.user, eve);
-               unit->SDperm.perm = 0555;
+               snprintf(buf, sizeof(buf), "%s%d", sdev->name, subno);
+               kstrdup(&unit->sdperm.name, buf);
+               kstrdup(&unit->sdperm.user, eve.name);
+               unit->sdperm.perm = 0555;
                unit->subno = subno;
                unit->dev = sdev;
+               qlock_init(&unit->ctl);
 
                if (sdev->enabled == 0 && sdev->ifc->enable)
                        sdev->ifc->enable(sdev);
@@ -319,8 +344,8 @@ static struct sdunit *sdgetunit(struct sdev *sdev, int subno)
                 */
                if (unit->dev->ifc->verify(unit) == 0) {
                        qunlock(&sdev->unitlock);
-                       free(unit);
-                       return nil;
+                       kfree(unit);
+                       return NULL;
                }
                sdev->unit[subno] = unit;
        }
@@ -336,8 +361,11 @@ static void sdreset(void)
        /*
         * Probe all known controller types and register any devices found.
         */
-       for (i = 0; sdifc[i] != nil; i++) {
-               if (sdifc[i]->pnp == nil || (sdev = sdifc[i]->pnp()) == nil)
+       for (i = 0; sdifc[i] != NULL; i++) {
+               if (sdifc[i]->pnp == NULL)
+                       continue;
+               sdev = sdifc[i]->pnp();
+               if (sdev == NULL)
                        continue;
                sdadddevs(sdev);
        }
@@ -351,56 +379,48 @@ void sdadddevs(struct sdev *sdev)
        for (; sdev; sdev = next) {
                next = sdev->next;
 
-               sdev->unit =
-                   (struct sdunit **)malloc(sdev->nunit * sizeof(struct sdunit *));
-               sdev->unitflg = (int *)malloc(sdev->nunit * sizeof(int));
-               if (sdev->unit == nil || sdev->unitflg == nil) {
-                       print("sdadddevs: out of memory\n");
+               sdev->unit = (struct sdunit **)kzmalloc(
+                   sdev->nunit * sizeof(struct sdunit *), 0);
+               sdev->unitflg = (int *)kzmalloc(sdev->nunit * sizeof(int), 0);
+               if (sdev->unit == NULL || sdev->unitflg == NULL) {
+                       printd("sdadddevs: out of memory\n");
                giveup:
-                       free(sdev->unit);
-                       free(sdev->unitflg);
+                       kfree(sdev->unit);
+                       kfree(sdev->unitflg);
                        if (sdev->ifc->clear)
                                sdev->ifc->clear(sdev);
-                       free(sdev);
+                       kfree(sdev);
                        continue;
                }
                id = sdindex(sdev->idno);
                if (id == -1) {
-                       print("sdadddevs: bad id number %d (%C)\n", id, id);
+                       printd("sdadddevs: bad id number %d (%C)\n", id, id);
                        goto giveup;
                }
                qlock(&devslock);
-               for (i = 0; i < nelem(devs); i++) {
-                       if (devs[j = (id + i) % nelem(devs)] == nil) {
+               for (i = 0; i < ARRAY_SIZE(devs); i++) {
+                       j = (id + i) % ARRAY_SIZE(devs);
+                       if (devs[j] == NULL) {
                                sdev->idno = devletters[j];
                                devs[j] = sdev;
-                               snprint(sdev->name, sizeof sdev->name, "sd%c", devletters[j]);
+                               snprintf(sdev->name, sizeof(sdev->name), "sd%c", devletters[j]);
                                break;
                        }
                }
                qunlock(&devslock);
-               if (i == nelem(devs)) {
-                       print("sdadddevs: out of device letters\n");
+               if (i == ARRAY_SIZE(devs)) {
+                       printd("sdadddevs: out of device letters\n");
                        goto giveup;
                }
        }
 }
 
-// void
-// sdrmdevs(SDev *sdev)
-// {
-//     char buf[2];
-//
-//     snprint(buf, sizeof buf, "%c", sdev->idno);
-//     unconfigure(buf);
-// }
-
 void sdaddallconfs(void (*addconf)(struct sdunit *))
 {
        int i, u;
        struct sdev *sdev;
 
-       for (i = 0; i < nelem(devs); i++) /* each controller */
+       for (i = 0; i < ARRAY_SIZE(devs); i++) /* each controller */
                for (sdev = devs[i]; sdev; sdev = sdev->next)
                        for (u = 0; u < sdev->nunit; u++) /* each drive */
                                (*addconf)(sdev->unit[u]);
@@ -427,7 +447,7 @@ static int sd2gen(struct chan *c, int i, struct dir *dp)
                      unit->vers, QTFILE);
                perm = &unit->ctlperm;
                if (emptystr(perm->user)) {
-                       kstrdup(&perm->user, eve);
+                       kstrdup(&perm->user, eve.name);
                        perm->perm = 0644; /* nothing secret in ctl */
                }
                devdir(c, q, "ctl", 0, perm->user, perm->perm, dp);
@@ -439,7 +459,7 @@ static int sd2gen(struct chan *c, int i, struct dir *dp)
                      unit->vers, QTFILE);
                perm = &unit->rawperm;
                if (emptystr(perm->user)) {
-                       kstrdup(&perm->user, eve);
+                       kstrdup(&perm->user, eve.name);
                        perm->perm = DMEXCL | 0600;
                }
                devdir(c, q, "raw", 0, perm->user, perm->perm, dp);
@@ -451,14 +471,14 @@ static int sd2gen(struct chan *c, int i, struct dir *dp)
                l = (pp->end - pp->start) * unit->secsize;
                mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qpart),
                      unit->vers + pp->vers, QTFILE);
-               if (emptystr(pp->SDperm.user))
-                       kstrdup(&pp->SDperm.user, eve);
-               devdir(c, q, pp->SDperm.name, l, pp->SDperm.user, pp->SDperm.perm, dp);
+               if (emptystr(pp->sdperm.user))
+                       kstrdup(&pp->sdperm.user, eve.name);
+               devdir(c, q, pp->sdperm.name, l, pp->sdperm.user, pp->sdperm.perm, dp);
                rv = 1;
                break;
        }
 
-       decref(&sdev->r);
+       kref_put(&sdev->r);
        return rv;
 }
 
@@ -469,7 +489,7 @@ static int sd1gen(struct chan *c, int i, struct dir *dp)
        switch (i) {
        case Qtopctl:
                mkqid(&q, QID(0, 0, 0, Qtopctl), 0, QTFILE);
-               devdir(c, q, "sdctl", 0, eve, 0644, dp); /* no secrets */
+               devdir(c, q, "sdctl", 0, eve.name, 0644, dp); /* no secrets */
                return 1;
        }
        return -1;
@@ -478,7 +498,6 @@ static int sd1gen(struct chan *c, int i, struct dir *dp)
 static int sdgen(struct chan *c, char *d, struct dirtab *dir, int j, int s,
                  struct dir *dp)
 {
-       struct proc *up = externup();
        struct qid q = {};
        int64_t l;
        int i, r;
@@ -490,8 +509,8 @@ static int sdgen(struct chan *c, char *d, struct dirtab *dir, int j, int s,
        case Qtopdir:
                if (s == DEVDOTDOT) {
                        mkqid(&q, QID(0, 0, 0, Qtopdir), 0, QTDIR);
-                       sprint(up->genbuf, "#%C", sddevtab.dc);
-                       devdir(c, q, up->genbuf, 0, eve, 0555, dp);
+                       snprintf(get_cur_genbuf(), GENBUF_SZ, "#%s", sddevtab.name);
+                       devdir(c, q, get_cur_genbuf(), 0, eve.name, 0555, dp);
                        return 1;
                }
 
@@ -500,7 +519,7 @@ static int sdgen(struct chan *c, char *d, struct dirtab *dir, int j, int s,
                s -= (Qunitdir - Qtopbase);
 
                qlock(&devslock);
-               for (i = 0; i < nelem(devs); i++) {
+               for (i = 0; i < ARRAY_SIZE(devs); i++) {
                        if (devs[i]) {
                                if (s < devs[i]->nunit)
                                        break;
@@ -508,44 +527,48 @@ static int sdgen(struct chan *c, char *d, struct dirtab *dir, int j, int s,
                        }
                }
 
-               if (i == nelem(devs)) {
+               if (i == ARRAY_SIZE(devs)) {
                        /* Run off the end of the list */
                        qunlock(&devslock);
                        return -1;
                }
 
-               if ((sdev = devs[i]) == nil) {
+               sdev = devs[i];
+               if (sdev == NULL) {
                        qunlock(&devslock);
                        return 0;
                }
 
-               incref(&sdev->r);
+               kref_get(&sdev->r, 1);
                qunlock(&devslock);
 
-               if ((unit = sdev->unit[s]) == nil)
-                       if ((unit = sdgetunit(sdev, s)) == nil) {
-                               decref(&sdev->r);
-                               return 0;
-                       }
+               unit = sdev->unit[s];
+               if (unit == NULL)
+                       unit = sdgetunit(sdev, s);
+               if (unit == NULL) {
+                       kref_put(&sdev->r);
+                       return 0;
+               }
 
                mkqid(&q, QID(sdev->idno, s, 0, Qunitdir), 0, QTDIR);
-               if (emptystr(unit->SDperm.user))
-                       kstrdup(&unit->SDperm.user, eve);
-               devdir(c, q, unit->SDperm.name, 0, unit->SDperm.user, unit->SDperm.perm,
+               if (emptystr(unit->sdperm.user))
+                       kstrdup(&unit->sdperm.user, eve.name);
+               devdir(c, q, unit->sdperm.name, 0, unit->sdperm.user, unit->sdperm.perm,
                       dp);
-               decref(&sdev->r);
+               kref_put(&sdev->r);
                return 1;
 
        case Qunitdir:
                if (s == DEVDOTDOT) {
                        mkqid(&q, QID(0, 0, 0, Qtopdir), 0, QTDIR);
-                       sprint(up->genbuf, "#%C", sddevtab.dc);
-                       devdir(c, q, up->genbuf, 0, eve, 0555, dp);
+                       snprintf(get_cur_genbuf(), GENBUF_SZ, "#%s", sddevtab.name);
+                       devdir(c, q, get_cur_genbuf(), 0, eve.name, 0555, dp);
                        return 1;
                }
 
-               if ((sdev = sdgetdev(DEV(c->qid))) == nil) {
-                       devdir(c, c->qid, "unavailable", 0, eve, 0, dp);
+               sdev = sdgetdev(DEV(c->qid));
+               if (sdev == NULL) {
+                       devdir(c, c->qid, "unavailable", 0, eve.name, 0, dp);
                        return 1;
                }
 
@@ -567,42 +590,43 @@ static int sdgen(struct chan *c, char *d, struct dirtab *dir, int j, int s,
                if (i < Qpart) {
                        r = sd2gen(c, i, dp);
                        qunlock(&unit->ctl);
-                       decref(&sdev->r);
+                       kref_put(&sdev->r);
                        return r;
                }
                i -= Qpart;
-               if (unit->part == nil || i >= unit->npart) {
+               if (unit->part == NULL || i >= unit->npart) {
                        qunlock(&unit->ctl);
-                       decref(&sdev->r);
+                       kref_put(&sdev->r);
                        break;
                }
                pp = &unit->part[i];
                if (!pp->valid) {
                        qunlock(&unit->ctl);
-                       decref(&sdev->r);
+                       kref_put(&sdev->r);
                        return 0;
                }
                l = (pp->end - pp->start) * (int64_t)unit->secsize;
                mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), i, Qpart),
                      unit->vers + pp->vers, QTFILE);
-               if (emptystr(pp->SDperm.user))
-                       kstrdup(&pp->SDperm.user, eve);
-               devdir(c, q, pp->SDperm.name, l, pp->SDperm.user, pp->SDperm.perm, dp);
+               if (emptystr(pp->sdperm.user))
+                       kstrdup(&pp->sdperm.user, eve.name);
+               devdir(c, q, pp->sdperm.name, l, pp->sdperm.user, pp->sdperm.perm, dp);
                qunlock(&unit->ctl);
-               decref(&sdev->r);
+               kref_put(&sdev->r);
                return 1;
        case Qraw:
        case Qctl:
        case Qpart:
-               if ((sdev = sdgetdev(DEV(c->qid))) == nil) {
-                       devdir(c, q, "unavailable", 0, eve, 0, dp);
+               sdev = sdgetdev(DEV(c->qid));
+               if (sdev == NULL) {
+                       devdir(c, q, "unavailable", 0, eve.name, 0, dp);
                        return 1;
                }
                unit = sdev->unit[UNIT(c->qid)];
                qlock(&unit->ctl);
                r = sd2gen(c, TYPE(c->qid), dp);
                qunlock(&unit->ctl);
-               decref(&sdev->r);
+               kref_put(&sdev->r);
                return r;
        case Qtopctl:
                return sd1gen(c, TYPE(c->qid), dp);
@@ -621,46 +645,48 @@ static struct chan *sdattach(char *spec)
        int idno, subno;
 
        if (*spec == '\0') {
-               c = devattach(sddevtab.dc, spec);
+               c = devattach(sddevtab.name, spec);
                mkqid(&c->qid, QID(0, 0, 0, Qtopdir), 0, QTDIR);
                return c;
        }
 
        if (spec[0] != 's' || spec[1] != 'd')
-               error(Ebadspec);
+               error(EINVAL, "First two characters of spec must be 'sd', not %c%c",
+                     spec[0], spec[1]);
        idno = spec[2];
        subno = strtol(&spec[3], &p, 0);
        if (p == &spec[3])
-               error(Ebadspec);
-
-       if ((sdev = sdgetdev(idno)) == nil)
-               error(Enonexist);
-       if (sdgetunit(sdev, subno) == nil) {
-               decref(&sdev->r);
-               error(Enonexist);
+               error(EINVAL, "subno '%s' is not a number", &spec[3]);
+
+       sdev = sdgetdev(idno);
+       if (sdev == NULL)
+               error(ENOENT, "No such unit %d", idno);
+       if (sdgetunit(sdev, subno) == NULL) {
+               kref_put(&sdev->r);
+               error(ENOENT, "No such subno %d", subno);
        }
 
-       c = devattach(sddevtab.dc, spec);
+       c = devattach(sddevtab.name, spec);
        mkqid(&c->qid, QID(sdev->idno, subno, 0, Qunitdir), 0, QTDIR);
-       c->devno = (sdev->idno << UnitLOG) + subno;
-       decref(&sdev->r);
+       c->dev = (sdev->idno << UnitLOG) + subno;
+       kref_put(&sdev->r);
        return c;
 }
 
 static struct walkqid *sdwalk(struct chan *c, struct chan *nc, char **name,
                               int nname)
 {
-       return devwalk(c, nc, name, nname, nil, 0, sdgen);
+       return devwalk(c, nc, name, nname, NULL, 0, sdgen);
 }
 
 static int32_t sdstat(struct chan *c, uint8_t *db, int32_t n)
 {
-       return devstat(c, db, n, nil, 0, sdgen);
+       return devstat(c, db, n, NULL, 0, sdgen);
 }
 
 static struct chan *sdopen(struct chan *c, int omode)
 {
-       struct proc *up = externup();
+       ERRSTACK(1);
        struct sdpart *pp;
        struct sdunit *unit;
        struct sdev *sdev;
@@ -671,8 +697,8 @@ static struct chan *sdopen(struct chan *c, int omode)
                return c;
 
        sdev = sdgetdev(DEV(c->qid));
-       if (sdev == nil)
-               error(Enonexist);
+       if (sdev == NULL)
+               error(ENOENT, "No such device");
 
        unit = sdev->unit[UNIT(c->qid)];
 
@@ -682,10 +708,11 @@ static struct chan *sdopen(struct chan *c, int omode)
                break;
        case Qraw:
                c->qid.vers = unit->vers;
-               if (TAS(&unit->rawinuse) != 0) {
+               if (test_and_set_bit(0, (unsigned long *)&unit->rawinuse) !=
+                   0) {
                        c->flag &= ~COPEN;
-                       decref(&sdev->r);
-                       error(Einuse);
+                       kref_put(&sdev->r);
+                       error(EBUSY, "In use");
                }
                unit->state = Rawcmd;
                break;
@@ -694,7 +721,7 @@ static struct chan *sdopen(struct chan *c, int omode)
                if (waserror()) {
                        qunlock(&unit->ctl);
                        c->flag &= ~COPEN;
-                       decref(&sdev->r);
+                       kref_put(&sdev->r);
                        nexterror();
                }
                pp = &unit->part[PART(c->qid)];
@@ -703,7 +730,7 @@ static struct chan *sdopen(struct chan *c, int omode)
                poperror();
                break;
        }
-       decref(&sdev->r);
+       kref_put(&sdev->r);
        return c;
 }
 
@@ -725,7 +752,7 @@ static void sdclose(struct chan *c)
                if (sdev) {
                        unit = sdev->unit[UNIT(c->qid)];
                        unit->rawinuse = 0;
-                       decref(&sdev->r);
+                       kref_put(&sdev->r);
                }
                break;
        }
@@ -734,7 +761,7 @@ static void sdclose(struct chan *c)
 static int32_t sdbio(struct chan *c, int write, char *a, int32_t len,
                      int64_t off)
 {
-       struct proc *up = externup();
+       ERRSTACK(2);
        int nchange;
        uint8_t *b;
        struct sdpart *pp;
@@ -744,32 +771,39 @@ static int32_t sdbio(struct chan *c, int write, char *a, int32_t len,
        int32_t l, max, nb, offset;
 
        sdev = sdgetdev(DEV(c->qid));
-       if (sdev == nil) {
-               decref(&sdev->r);
-               error(Enonexist);
+       if (sdev == NULL) {
+               kref_put(&sdev->r);
+               error(ENOENT, "No such file or directory");
        }
        unit = sdev->unit[UNIT(c->qid)];
-       if (unit == nil)
-               error(Enonexist);
+       if (unit == NULL)
+               error(ENOENT, "No such file or directory");
 
        nchange = 0;
        qlock(&unit->ctl);
        while (waserror()) {
                /* notification of media change; go around again */
-               if (strcmp(up->errstr, Eio) == 0 && unit->sectors == 0 &&
-                   nchange++ == 0) {
+               /* Meta-comment: I'm leaving commented-out code in place,
+                * which originally contained a strcmp of the error string to
+                * a value, to remind us: plan 9 is a distributed system. It's
+                * possible in principle to have the storage device on this
+                * machine use an sdi{ata,ahci} on another machine, and it all
+                * works. Nobody is going to do that, now, so get_errno() it is.
+                * if (strcmp(up->errstr, Eio) == 0 ... */
+               if ((get_errno() == EIO) && (unit->sectors == 0) && (nchange++ == 0)) {
                        sdinitpart(unit);
+                       poperror();
                        continue;
                }
 
                /* other errors; give up */
                qunlock(&unit->ctl);
-               decref(&sdev->r);
+               kref_put(&sdev->r);
                nexterror();
        }
        pp = &unit->part[PART(c->qid)];
        if (unit->vers + pp->vers != c->qid.vers)
-               error(Echange);
+               error(EIO, "disk changed");
 
        /*
         * Check the request is within bounds.
@@ -791,9 +825,10 @@ static int32_t sdbio(struct chan *c, int write, char *a, int32_t len,
                nb = pp->end - bno;
        if (bno >= pp->end || nb == 0) {
                if (write)
-                       error(Eio);
+                       error(EIO, "bno(%d) >= pp->end(%d) or nb(%d) == 0", bno, pp->end,
+                             nb);
                qunlock(&unit->ctl);
-               decref(&sdev->r);
+               kref_put(&sdev->r);
                poperror();
                return 0;
        }
@@ -802,13 +837,13 @@ static int32_t sdbio(struct chan *c, int write, char *a, int32_t len,
                poperror();
        }
 
-       b = sdmalloc(nb * unit->secsize);
-       if (b == nil)
-               error(Enomem);
+       b = kzmalloc(nb * unit->secsize, MEM_WAIT);
+       if (b == NULL)
+               error(ENOMEM, "%s: could not allocate %d bytes", nb * unit->secsize);
        if (waserror()) {
-               sdfree(b);
+               kfree(b);
                if (!(unit->inquiry[1] & SDinq1removable))
-                       decref(&sdev->r); /* gadverdamme! */
+                       kref_put(&sdev->r); /* gadverdamme! */
                nexterror();
        }
 
@@ -819,7 +854,7 @@ static int32_t sdbio(struct chan *c, int write, char *a, int32_t len,
                if (offset || (len % unit->secsize)) {
                        l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno);
                        if (l < 0)
-                               error(Eio);
+                               error(EIO, "IO Error");
                        if (l < (nb * unit->secsize)) {
                                nb = l / unit->secsize;
                                l = nb * unit->secsize - offset;
@@ -830,7 +865,7 @@ static int32_t sdbio(struct chan *c, int write, char *a, int32_t len,
                memmove(b + offset, a, len);
                l = unit->dev->ifc->bio(unit, 0, 1, b, nb, bno);
                if (l < 0)
-                       error(Eio);
+                       error(EIO, "IO Error");
                if (l < offset)
                        len = 0;
                else if (len > l - offset)
@@ -838,14 +873,14 @@ static int32_t sdbio(struct chan *c, int write, char *a, int32_t len,
        } else {
                l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno);
                if (l < 0)
-                       error(Eio);
+                       error(EIO, "IO Error");
                if (l < offset)
                        len = 0;
                else if (len > l - offset)
                        len = l - offset;
                memmove(a, b + offset, len);
        }
-       sdfree(b);
+       kfree(b);
        poperror();
 
        if (unit->inquiry[1] & SDinq1removable) {
@@ -853,22 +888,23 @@ static int32_t sdbio(struct chan *c, int write, char *a, int32_t len,
                poperror();
        }
 
-       decref(&sdev->r);
+       kref_put(&sdev->r);
        return len;
 }
 
 static int32_t sdrio(struct sdreq *r, void *a, int32_t n)
 {
-       struct proc *up = externup();
+       ERRSTACK(1);
        void *data;
 
        if (n >= SDmaxio || n < 0)
-               error(Etoobig);
+               error(EINVAL, "%d is < 0 or > SDmaxio", n);
 
-       data = nil;
+       data = NULL;
        if (n) {
-               if ((data = sdmalloc(n)) == nil)
-                       error(Enomem);
+               data = kzmalloc(n, MEM_WAIT);
+               if (data == NULL)
+                       error(ENOMEM, "Alloc of %d bytes failed", n);
                if (r->write)
                        memmove(data, a, n);
        }
@@ -876,18 +912,18 @@ static int32_t sdrio(struct sdreq *r, void *a, int32_t n)
        r->dlen = n;
 
        if (waserror()) {
-               sdfree(data);
-               r->data = nil;
+               kfree(data);
+               r->data = NULL;
                nexterror();
        }
 
        if (r->unit->dev->ifc->rio(r) != SDok)
-               error(Eio);
+               error(EIO, "IO Error");
 
        if (!r->write && r->rlen > 0)
                memmove(a, data, r->rlen);
-       sdfree(data);
-       r->data = nil;
+       kfree(data);
+       r->data = NULL;
        poperror();
 
        return r->rlen;
@@ -910,8 +946,8 @@ int sdsetsense(struct sdreq *r, int status, int key, int asc, int ascq)
        if (status == SDcheck && !(r->flags & SDnosense)) {
                /* request sense case from sdfakescsi */
                len = sizeof unit->sense;
-               if (len > sizeof r->sense - 1)
-                       len = sizeof r->sense - 1;
+               if (len > sizeof(r->sense) - 1)
+                       len = sizeof(r->sense) - 1;
                memmove(r->sense, unit->sense, len);
                unit->sense[2] = 0;
                unit->sense[12] = 0;
@@ -938,7 +974,7 @@ int sdmodesense(struct sdreq *r, uint8_t *cmd, void *info, int ilen)
                return SDok;
        if (len < 8 + ilen)
                return sdsetsense(r, SDcheck, 0x05, 0x1A, 0);
-       if (r->data == nil || r->dlen < len)
+       if (r->data == NULL || r->dlen < len)
                return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
        data = r->data;
        memset(data, 0, 8);
@@ -1018,14 +1054,14 @@ int sdfakescsi(struct sdreq *r, void *info, int ilen)
 
        case 0x1B: /* start/stop unit */
                /*
-               * nop for now, can use power management later.
-                                  */
+                * nop for now, can use power management later.
+                */
                return sdsetsense(r, SDok, 0, 0, 0);
 
        case 0x25: /* read capacity */
                if ((cmd[1] & 0x01) || cmd[2] || cmd[3])
                        return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
-               if (r->data == nil || r->dlen < 8)
+               if (r->data == NULL || r->dlen < 8)
                        return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
 
                /*
@@ -1048,7 +1084,7 @@ int sdfakescsi(struct sdreq *r, void *info, int ilen)
        case 0x9E: /* long read capacity */
                if ((cmd[1] & 0x01) || cmd[2] || cmd[3])
                        return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
-               if (r->data == nil || r->dlen < 8)
+               if (r->data == NULL || r->dlen < 8)
                        return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
                /*
                 * Read capcity returns the LBA of the last sector.
@@ -1082,9 +1118,9 @@ int sdfakescsi(struct sdreq *r, void *info, int ilen)
        }
 }
 
-static int32_t sdread(struct chan *c, void *a, int32_t n, int64_t off)
+static long sdread(struct chan *c, void *a, long n, int64_t off)
 {
-       struct proc *up = externup();
+       ERRSTACK(1);
        char *p, *e, *buf;
        struct sdpart *pp;
        struct sdunit *unit;
@@ -1095,22 +1131,22 @@ static int32_t sdread(struct chan *c, void *a, int32_t n, int64_t off)
        offset = off;
        switch (TYPE(c->qid)) {
        default:
-               error(Eperm);
+               error(EPERM, "Permission denied");
        case Qtopctl:
                mm = 64 * 1024; /* room for register dumps */
-               p = buf = malloc(mm);
-               if (p == nil)
-                       error(Enomem);
+               p = buf = kzmalloc(mm, 0);
+               if (p == NULL)
+                       error(ENOMEM, "Alloc of %d bytes failed", mm);
                e = p + mm;
                qlock(&devslock);
-               for (i = 0; i < nelem(devs); i++) {
+               for (i = 0; i < ARRAY_SIZE(devs); i++) {
                        sdev = devs[i];
                        if (sdev && sdev->ifc->rtopctl)
                                p = sdev->ifc->rtopctl(sdev, p, e);
                }
                qunlock(&devslock);
                n = readstr(offset, a, n, buf);
-               free(buf);
+               kfree(buf);
                return n;
 
        case Qtopdir:
@@ -1119,15 +1155,15 @@ static int32_t sdread(struct chan *c, void *a, int32_t n, int64_t off)
 
        case Qctl:
                sdev = sdgetdev(DEV(c->qid));
-               if (sdev == nil)
-                       error(Enonexist);
+               if (sdev == NULL)
+                       error(ENOENT, "No such device");
 
                unit = sdev->unit[UNIT(c->qid)];
                mm = 16 * 1024; /* room for register dumps */
-               p = malloc(mm);
-               if (p == nil)
-                       error(Enomem);
-               l = snprint(p, mm, "inquiry %.48s\n", (char *)unit->inquiry + 8);
+               p = kzmalloc(mm, 0);
+               if (p == NULL)
+                       error(ENOMEM, "Alloc of %d bytes failed", mm);
+               l = snprintf(p, mm, "inquiry %.48s\n", (char *)unit->inquiry + 8);
                qlock(&unit->ctl);
                /*
                 * If there's a device specific routine it must
@@ -1139,33 +1175,33 @@ static int32_t sdread(struct chan *c, void *a, int32_t n, int64_t off)
                if (unit->sectors == 0)
                        sdinitpart(unit);
                if (unit->sectors) {
-                       if (unit->dev->ifc->rctl == nil)
-                               l += snprint(p + l, mm - l, "geometry %llu %lu\n",
-                                            unit->sectors, unit->secsize);
+                       if (unit->dev->ifc->rctl == NULL)
+                               l += snprintf(p + l, mm - l, "geometry %llu %lu\n",
+                                             unit->sectors, unit->secsize);
                        pp = unit->part;
                        for (i = 0; i < unit->npart; i++) {
                                if (pp->valid)
-                                       l += snprint(p + l, mm - l, "part %s %llu %llu\n",
-                                                    pp->SDperm.name, pp->start, pp->end);
+                                       l += snprintf(p + l, mm - l, "part %s %llu %llu\n",
+                                                     pp->sdperm.name, pp->start, pp->end);
                                pp++;
                        }
                }
                qunlock(&unit->ctl);
-               decref(&sdev->r);
+               kref_put(&sdev->r);
                l = readstr(offset, a, n, p);
-               free(p);
+               kfree(p);
                return l;
 
        case Qraw:
                sdev = sdgetdev(DEV(c->qid));
-               if (sdev == nil)
-                       error(Enonexist);
+               if (sdev == NULL)
+                       error(ENOENT, "No such file or directory");
 
                unit = sdev->unit[UNIT(c->qid)];
                qlock(&unit->raw);
                if (waserror()) {
                        qunlock(&unit->raw);
-                       decref(&sdev->r);
+                       kref_put(&sdev->r);
                        nexterror();
                }
                if (unit->state == Rawdata) {
@@ -1174,13 +1210,13 @@ static int32_t sdread(struct chan *c, void *a, int32_t n, int64_t off)
                } else if (unit->state == Rawstatus) {
                        status = unit->req->status;
                        unit->state = Rawcmd;
-                       free(unit->req);
-                       unit->req = nil;
+                       kfree(unit->req);
+                       unit->req = NULL;
                        i = readnum(0, a, n, status, NUMSIZE);
                } else
                        i = 0;
                qunlock(&unit->raw);
-               decref(&sdev->r);
+               kref_put(&sdev->r);
                poperror();
                return i;
 
@@ -1191,9 +1227,9 @@ static int32_t sdread(struct chan *c, void *a, int32_t n, int64_t off)
 
 static void legacytopctl(struct cmdbuf *);
 
-static int32_t sdwrite(struct chan *c, void *a, int32_t n, int64_t off)
+static long sdwrite(struct chan *c, void *a, long n, int64_t off)
 {
-       struct proc *up = externup();
+       ERRSTACK(2);
        char *f0;
        int i;
        uint64_t end, start;
@@ -1205,15 +1241,15 @@ static int32_t sdwrite(struct chan *c, void *a, int32_t n, int64_t off)
 
        switch (TYPE(c->qid)) {
        default:
-               error(Eperm);
+               error(EPERM, "Permission denied");
        case Qtopctl:
                cb = parsecmd(a, n);
                if (waserror()) {
-                       free(cb);
+                       kfree(cb);
                        nexterror();
                }
                if (cb->nf == 0)
-                       error("empty control message");
+                       error(EINVAL, "empty control message");
                f0 = cb->f[0];
                cb->f++;
                cb->nf--;
@@ -1221,19 +1257,19 @@ static int32_t sdwrite(struct chan *c, void *a, int32_t n, int64_t off)
                        /* wormhole into ugly legacy interface */
                        legacytopctl(cb);
                        poperror();
-                       free(cb);
+                       kfree(cb);
                        break;
                }
                /*
-                * "ata arg..." invokes sdifc[i]->wtopctl(nil, cb),
-                * where sdifc[i]->SDperm.name=="ata" and cb contains the args.
+                * "ata arg..." invokes sdifc[i]->wtopctl(NULL, cb),
+                * where sdifc[i]->sdperm.name=="ata" and cb contains the args.
                 */
-               ifc = nil;
-               sdev = nil;
+               ifc = NULL;
+               sdev = NULL;
                for (i = 0; sdifc[i]; i++) {
                        if (strcmp(sdifc[i]->name, f0) == 0) {
                                ifc = sdifc[i];
-                               sdev = nil;
+                               sdev = NULL;
                                goto subtopctl;
                        }
                }
@@ -1243,88 +1279,94 @@ static int32_t sdwrite(struct chan *c, void *a, int32_t n, int64_t off)
                 * and cb contains the args.
                 */
                if (f0[0] == 's' && f0[1] == 'd' && f0[2] && f0[3] == 0) {
-                       if ((sdev = sdgetdev(f0[2])) != nil) {
+                       sdev = sdgetdev(f0[2]);
+                       if (sdev != NULL) {
                                ifc = sdev->ifc;
                                goto subtopctl;
                        }
                }
-               error("unknown interface");
+               error(EINVAL, "unknown interface");
 
        subtopctl:
                if (waserror()) {
                        if (sdev)
-                               decref(&sdev->r);
+                               kref_put(&sdev->r);
                        nexterror();
                }
                if (ifc->wtopctl)
                        ifc->wtopctl(sdev, cb);
                else
-                       error(Ebadctl);
+                       error(EINVAL, "Bad control");
                poperror();
                poperror();
                if (sdev)
-                       decref(&sdev->r);
-               free(cb);
+                       kref_put(&sdev->r);
+               kfree(cb);
                break;
 
        case Qctl:
                cb = parsecmd(a, n);
                sdev = sdgetdev(DEV(c->qid));
-               if (sdev == nil)
-                       error(Enonexist);
+               if (sdev == NULL)
+                       error(ENOENT, "No such file or directory");
                unit = sdev->unit[UNIT(c->qid)];
 
                qlock(&unit->ctl);
                if (waserror()) {
                        qunlock(&unit->ctl);
-                       decref(&sdev->r);
-                       free(cb);
+                       kref_put(&sdev->r);
+                       kfree(cb);
                        nexterror();
                }
                if (unit->vers != c->qid.vers)
-                       error(Echange);
+                       error(EIO, "Unit changed");
 
                if (cb->nf < 1)
-                       error(Ebadctl);
+                       error(EINVAL, "%s requires at least one argument", cb->f[0]);
                if (strcmp(cb->f[0], "part") == 0) {
                        if (cb->nf != 4)
-                               error(Ebadctl);
-                       if (unit->sectors == 0 && !sdinitpart(unit))
-                               error(Eio);
-                       start = strtoull(cb->f[2], 0, 0);
-                       end = strtoull(cb->f[3], 0, 0);
+                               error(EINVAL, "Part got %d arguments, requires 4", cb->nf);
+                       if (unit->sectors == 0)
+                               error(EINVAL, "unit->sectors was 0");
+                       if (!sdinitpart(unit))
+                               error(EIO, "sdinitpart failed");
+                       start = strtoul(cb->f[2], 0, 0);
+                       end = strtoul(cb->f[3], 0, 0);
                        sdaddpart(unit, cb->f[1], start, end);
                } else if (strcmp(cb->f[0], "delpart") == 0) {
-                       if (cb->nf != 2 || unit->part == nil)
-                               error(Ebadctl);
+                       if (cb->nf != 2)
+                               error(EINVAL, "delpart got %d args, 2 required");
+                       if (unit->part == NULL)
+                               error(EIO, "partition was NULL");
                        sddelpart(unit, cb->f[1]);
                } else if (unit->dev->ifc->wctl)
                        unit->dev->ifc->wctl(unit, cb);
                else
-                       error(Ebadctl);
+                       error(EINVAL, "Bad control %s", cb->f[0]);
                qunlock(&unit->ctl);
-               decref(&sdev->r);
+               kref_put(&sdev->r);
                poperror();
-               free(cb);
+               kfree(cb);
                break;
 
        case Qraw:
                sdev = sdgetdev(DEV(c->qid));
-               if (sdev == nil)
-                       error(Enonexist);
+               if (sdev == NULL)
+                       error(ENOENT, "No such file or directory");
                unit = sdev->unit[UNIT(c->qid)];
                qlock(&unit->raw);
                if (waserror()) {
                        qunlock(&unit->raw);
-                       decref(&sdev->r);
+                       kref_put(&sdev->r);
                        nexterror();
                }
                switch (unit->state) {
                case Rawcmd:
                        if (n < 6 || n > sizeof(req->cmd))
-                               error(Ebadarg);
-                       if ((req = malloc(sizeof(struct sdreq))) == nil)
-                               error(Enomem);
+                               error(EINVAL, "%d is < 6 or > %d", n, sizeof(req->cmd));
+                       req = kzmalloc(sizeof(struct sdreq), 0);
+                       if (req == NULL)
+                               error(ENOMEM, "Can't allocate an sdreq");
                        req->unit = unit;
                        memmove(req->cmd, a, n);
                        req->clen = n;
@@ -1337,9 +1379,9 @@ static int32_t sdwrite(struct chan *c, void *a, int32_t n, int64_t off)
 
                case Rawstatus:
                        unit->state = Rawcmd;
-                       free(unit->req);
-                       unit->req = nil;
-                       error(Ebadusefd);
+                       kfree(unit->req);
+                       unit->req = NULL;
+                       error(EINVAL, "Bad use of rawstatus");
 
                case Rawdata:
                        unit->state = Rawstatus;
@@ -1347,7 +1389,7 @@ static int32_t sdwrite(struct chan *c, void *a, int32_t n, int64_t off)
                        n = sdrio(unit->req, a, n);
                }
                qunlock(&unit->raw);
-               decref(&sdev->r);
+               kref_put(&sdev->r);
                poperror();
                break;
        case Qpart:
@@ -1359,7 +1401,7 @@ static int32_t sdwrite(struct chan *c, void *a, int32_t n, int64_t off)
 
 static int32_t sdwstat(struct chan *c, uint8_t *dp, int32_t n)
 {
-       struct proc *up = externup();
+       ERRSTACK(2);
        struct dir *d;
        struct sdpart *pp;
        struct sdperm *perm;
@@ -1367,24 +1409,24 @@ static int32_t sdwstat(struct chan *c, uint8_t *dp, int32_t n)
        struct sdev *sdev;
 
        if (c->qid.type & QTDIR)
-               error(Eperm);
+               error(EPERM, "Not a directory");
 
        sdev = sdgetdev(DEV(c->qid));
-       if (sdev == nil)
-               error(Enonexist);
+       if (sdev == NULL)
+               error(ENOENT, "No such file or device");
        unit = sdev->unit[UNIT(c->qid)];
        qlock(&unit->ctl);
-       d = nil;
+       d = NULL;
        if (waserror()) {
-               free(d);
+               kfree(d);
                qunlock(&unit->ctl);
-               decref(&sdev->r);
+               kref_put(&sdev->r);
                nexterror();
        }
 
        switch (TYPE(c->qid)) {
        default:
-               error(Eperm);
+               error(EPERM, "Permission denied");
        case Qctl:
                perm = &unit->ctlperm;
                break;
@@ -1394,52 +1436,54 @@ static int32_t sdwstat(struct chan *c, uint8_t *dp, int32_t n)
        case Qpart:
                pp = &unit->part[PART(c->qid)];
                if (unit->vers + pp->vers != c->qid.vers)
-                       error(Enonexist);
-               perm = &pp->SDperm;
+                       error(ENOENT, "No such file or directory");
+               perm = &pp->sdperm;
                break;
        }
 
-       if (strcmp(up->user, perm->user) && !iseve())
-               error(Eperm);
+       /* TODO: Implement permissions checking and raise errors as appropriate. */
+       // if (strcmp(current->user.name, perm->user) && !iseve())
+               // error(Eperm);
 
-       d = smalloc(sizeof(struct dir) + n);
+       d = kzmalloc(sizeof(struct dir) + n, 0);
        n = convM2D(dp, n, &d[0], (char *)&d[1]);
        if (n == 0)
-               error(Eshortstat);
+               error(EIO, "Short status");
        if (!emptystr(d[0].uid))
                kstrdup(&perm->user, d[0].uid);
        if (d[0].mode != (uint32_t)~0UL)
                perm->perm = (perm->perm & ~0777) | (d[0].mode & 0777);
 
-       free(d);
+       kfree(d);
        qunlock(&unit->ctl);
-       decref(&sdev->r);
+       kref_put(&sdev->r);
        poperror();
        return n;
 }
 
-static int configure(char *spec, DevConf *cf)
+static int configure(char *spec, struct devconf *cf)
 {
        struct sdev *s, *sdev;
        char *p;
        int i;
 
        if (sdindex(*spec) < 0)
-               error("bad sd spec");
+               error(EINVAL, "bad sd spec '%s'", spec);
 
-       if ((p = strchr(cf->type, '/')) != nil)
+       p = strchr(cf->type, '/');
+       if (p != NULL)
                *p++ = '\0';
 
-       for (i = 0; sdifc[i] != nil; i++)
+       for (i = 0; sdifc[i] != NULL; i++)
                if (strcmp(sdifc[i]->name, cf->type) == 0)
                        break;
-       if (sdifc[i] == nil)
-               error("sd type not found");
+       if (sdifc[i] == NULL)
+               error(ENOENT, "sd type not found");
        if (p)
                *(p - 1) = '/';
 
-       if (sdifc[i]->probe == nil)
-               error("sd type cannot probe");
+       if (sdifc[i]->probe == NULL)
+               error(EIO, "sd type cannot probe");
 
        sdev = sdifc[i]->probe(cf);
        for (s = sdev; s; s = s->next)
@@ -1455,18 +1499,19 @@ static int unconfigure(char *spec)
        struct sdunit *unit;
 
        if ((i = sdindex(*spec)) < 0)
-               error(Enonexist);
+               error(ENOENT, "No such file or directory '%s'", spec);
 
        qlock(&devslock);
-       if ((sdev = devs[i]) == nil) {
+       sdev = devs[i];
+       if (sdev == NULL) {
                qunlock(&devslock);
-               error(Enonexist);
+               error(ENOENT, "No such file or directory at index %d", i);
        }
-       if (sdev->r.ref) {
+       if (kref_refcnt(&sdev->r)) {
                qunlock(&devslock);
-               error(Einuse);
+               error(EBUSY, "%s is busy", spec);
        }
-       devs[i] = nil;
+       devs[i] = NULL;
        qunlock(&devslock);
 
        /* make sure no interrupts arrive anymore before removing resources */
@@ -1474,28 +1519,28 @@ static int unconfigure(char *spec)
                sdev->ifc->disable(sdev);
 
        for (i = 0; i != sdev->nunit; i++) {
-               if (unit = sdev->unit[i]) {
-                       free(unit->SDperm.name);
-                       free(unit->SDperm.user);
-                       free(unit);
+               unit = sdev->unit[i];
+               if (unit) {
+                       kfree(unit->sdperm.name);
+                       kfree(unit->sdperm.user);
+                       kfree(unit);
                }
        }
 
        if (sdev->ifc->clear)
                sdev->ifc->clear(sdev);
-       free(sdev);
+       kfree(sdev);
        return 0;
 }
 
-static int sdconfig(int on, char *spec, DevConf *cf)
+static int sdconfig(int on, char *spec, struct devconf *cf)
 {
        if (on)
                return configure(spec, cf);
        return unconfigure(spec);
 }
 
-struct dev sddevtab = {
-    .dc = 'S',
+struct dev sddevtab __devtab = {
     .name = "sd",
 
     .reset = sdreset,
@@ -1514,46 +1559,46 @@ struct dev sddevtab = {
     .remove = devremove,
     .wstat = sdwstat,
     .power = devpower,
-    .config = sdconfig, /* probe; only called for pcmcia-like devices */
 };
 
 /*
  * This is wrong for so many reasons.  This code must go.
  */
-typedef struct Confdata Confdata;
-struct Confdata {
+struct confdata {
        int on;
        char *spec;
-       DevConf cf;
+       struct devconf cf;
 };
 
-static void parseswitch(Confdata *cd, char *option)
+static void parseswitch(struct confdata *cd, char *option)
 {
        if (!strcmp("on", option))
                cd->on = 1;
        else if (!strcmp("off", option))
                cd->on = 0;
        else
-               error(Ebadarg);
+               error(EINVAL, "Got %s, must be on or off", option);
 }
 
-static void parsespec(Confdata *cd, char *option)
+static void parsespec(struct confdata *cd, char *option)
 {
        if (strlen(option) > 1)
-               error(Ebadarg);
+               error(EINVAL, "spec is %d bytes, must be 1", strlen(option));
        cd->spec = option;
 }
 
-static struct devport *getnewport(DevConf *dc)
+static struct devport *getnewport(struct devconf *dc)
 {
        struct devport *p;
 
-       p = (struct devport *)malloc((dc->nports + 1) * sizeof(struct devport));
-       if (p == nil)
-               error(Enomem);
+       p = (struct devport *)kzmalloc((dc->nports + 1) * sizeof(struct devport),
+                                      0);
+       if (p == NULL)
+               error(ENOMEM, "Can't allocate %d bytes for %d ports", dc->nports,
+                     (dc->nports + 1) * sizeof(struct devport));
        if (dc->nports > 0) {
                memmove(p, dc->ports, dc->nports * sizeof(struct devport));
-               free(dc->ports);
+               kfree(dc->ports);
        }
        dc->ports = p;
        p = &dc->ports[dc->nports++];
@@ -1562,22 +1607,22 @@ static struct devport *getnewport(DevConf *dc)
        return p;
 }
 
-static void parseport(Confdata *cd, char *option)
+static void parseport(struct confdata *cd, char *option)
 {
        char *e;
        struct devport *p;
 
-       if (cd->cf.nports == 0 ||
-           cd->cf.ports[cd->cf.nports - 1].port != (uint32_t)-1)
+       if ((cd->cf.nports == 0) ||
+           (cd->cf.ports[cd->cf.nports - 1].port != (uint32_t)-1))
                p = getnewport(&cd->cf);
        else
                p = &cd->cf.ports[cd->cf.nports - 1];
        p->port = strtol(option, &e, 0);
-       if (e == nil || *e != '\0')
-               error(Ebadarg);
+       if (e == NULL || *e != '\0')
+               error(EINVAL, "option %s is not a number", option);
 }
 
-static void parsesize(Confdata *cd, char *option)
+static void parsesize(struct confdata *cd, char *option)
 {
        char *e;
        struct devport *p;
@@ -1587,53 +1632,60 @@ static void parsesize(Confdata *cd, char *option)
        else
                p = &cd->cf.ports[cd->cf.nports - 1];
        p->size = (int)strtol(option, &e, 0);
-       if (e == nil || *e != '\0')
-               error(Ebadarg);
+       if (e == NULL || *e != '\0')
+               error(EINVAL, "%s is not a number", option);
 }
 
-static void parseirq(Confdata *cd, char *option)
+static void parseirq(struct confdata *cd, char *option)
 {
        char *e;
 
        cd->cf.intnum = strtoul(option, &e, 0);
-       if (e == nil || *e != '\0')
-               error(Ebadarg);
+       if (e == NULL || *e != '\0')
+               error(EINVAL, "%s is not a number", option);
 }
 
-static void parsetype(Confdata *cd, char *option) { cd->cf.type = option; }
+static void parsetype(struct confdata *cd, char *option)
+{
+       cd->cf.type = option;
+}
 
 static struct {
        char *name;
-       void (*parse)(Confdata *, char *);
+       void (*parse)(struct confdata *, char *unused_char_p_t);
 } options[] = {
-    "switch", parseswitch, "spec", parsespec, "port", parseport,
-    "size",   parsesize,   "irq",  parseirq,  "type", parsetype,
+    {"switch", parseswitch},
+    {"spec", parsespec},
+    {"port", parseport},
+    {"size", parsesize},
+    {"irq", parseirq},
+    {"type", parsetype},
 };
 
 static void legacytopctl(struct cmdbuf *cb)
 {
        char *opt;
        int i, j;
-       Confdata cd;
+       struct confdata cd;
 
-       memset(&cd, 0, sizeof cd);
+       memset(&cd, 0, sizeof(cd));
        cd.on = -1;
        for (i = 0; i < cb->nf; i += 2) {
                if (i + 2 > cb->nf)
-                       error(Ebadarg);
+                       error(EINVAL, "FIX ME. I don't know what this means");
                opt = cb->f[i];
-               for (j = 0; j < nelem(options); j++)
+               for (j = 0; j < ARRAY_SIZE(options); j++)
                        if (strcmp(opt, options[j].name) == 0) {
                                options[j].parse(&cd, cb->f[i + 1]);
                                break;
                        }
-               if (j == nelem(options))
-                       error(Ebadarg);
+               if (j == ARRAY_SIZE(options))
+                       error(EINVAL, "FIX ME");
        }
-       /* this has been rewritten to accomodate sdaoe */
+       /* this has been rewritten to accommodate sdaoe */
        if (cd.on < 0 || cd.spec == 0)
-               error(Ebadarg);
-       if (cd.on && cd.cf.type == nil)
-               error(Ebadarg);
+               error(EINVAL, "cd.on(%d) < 0 or cd.spec == 0", cd.on);
+       if (cd.on && cd.cf.type == NULL)
+               error(EINVAL, "cd.on non-zero and cd.cf.type == NULL");
        sdconfig(cd.on, cd.spec, &cd.cf);
 }