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