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