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