The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/port/devsd.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 19273d9e5ea2de63ca9698d80488b5c4


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.