]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/port/devsd.c
pc kernel: fix wrong simd exception mask (fixes go bootstrap)
[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    Enoata[]        = "raw ata commands not supported";
19 static  char    Enoscsi[]       = "raw scsi commands not supported";
20
21 static char devletters[] = "0123456789"
22         "abcdefghijklmnopqrstuvwxyz"
23         "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
24
25 static SDev *devs[sizeof devletters-1];
26 static QLock devslock;
27 static SDunit topctlunit;
28
29 enum {
30         Ahdrsz          = 2,
31 };
32
33 enum {
34         Rawcmd,
35         Rawdata,
36         Rawstatus,
37 };
38
39 enum {
40         Qtopdir         = 1,            /* top level directory */
41         Qtopbase,
42         Qtopctl          = Qtopbase,
43
44         Qunitdir,                       /* directory per unit */
45         Qunitbase,
46         Qctl            = Qunitbase,
47         Qraw,
48         Qpart,
49         Qextra,
50
51         TypeLOG         = 4,
52         NType           = (1<<TypeLOG),
53         TypeMASK        = (NType-1),
54         TypeSHIFT       = 0,
55
56         PartLOG         = 8,
57         NPart           = (1<<PartLOG),
58         PartMASK        = (NPart-1),
59         PartSHIFT       = TypeLOG,
60
61         UnitLOG         = 8,
62         NUnit           = (1<<UnitLOG),
63         UnitMASK        = (NUnit-1),
64         UnitSHIFT       = (PartLOG+TypeLOG),
65
66         DevLOG          = 8,
67         NDev            = (1 << DevLOG),
68         DevMASK         = (NDev-1),
69         DevSHIFT         = (UnitLOG+PartLOG+TypeLOG),
70
71         Ncmd = 20,
72 };
73
74 #define TYPE(q)         ((((ulong)(q).path)>>TypeSHIFT) & TypeMASK)
75 #define PART(q)         ((((ulong)(q).path)>>PartSHIFT) & PartMASK)
76 #define UNIT(q)         ((((ulong)(q).path)>>UnitSHIFT) & UnitMASK)
77 #define DEV(q)          ((((ulong)(q).path)>>DevSHIFT) & DevMASK)
78 #define QID(d,u, p, t)  (((d)<<DevSHIFT)|((u)<<UnitSHIFT)|\
79                                          ((p)<<PartSHIFT)|((t)<<TypeSHIFT))
80
81
82 static void
83 sdaddpart(SDunit* unit, char* name, uvlong start, uvlong end)
84 {
85         SDpart *pp;
86         int i, partno;
87
88         /*
89          * Check name not already used
90          * and look for a free slot.
91          */
92         if(unit->part != nil){
93                 partno = -1;
94                 for(i = 0; i < unit->npart; i++){
95                         pp = &unit->part[i];
96                         if(!pp->valid){
97                                 if(partno == -1)
98                                         partno = i;
99                                 break;
100                         }
101                         if(strcmp(name, pp->name) == 0){
102                                 if(pp->start == start && pp->end == end)
103                                         return;
104                                 error(Ebadctl);
105                         }
106                 }
107         }
108         else{
109                 if((unit->part = malloc(sizeof(SDpart)*SDnpart)) == nil)
110                         error(Enomem);
111                 unit->npart = SDnpart;
112                 partno = 0;
113         }
114
115         /*
116          * If no free slot found then increase the
117          * array size (can't get here with unit->part == nil).
118          */
119         if(partno == -1){
120                 if(unit->npart >= NPart)
121                         error(Enomem);
122                 if((pp = malloc(sizeof(SDpart)*(unit->npart+SDnpart))) == nil)
123                         error(Enomem);
124                 memmove(pp, unit->part, sizeof(SDpart)*unit->npart);
125                 free(unit->part);
126                 unit->part = pp;
127                 partno = unit->npart;
128                 unit->npart += SDnpart;
129         }
130
131         /*
132          * Check size and extent are valid.
133          */
134         if(start > end || end > unit->sectors)
135                 error(Eio);
136         pp = &unit->part[partno];
137         pp->start = start;
138         pp->end = end;
139         kstrdup(&pp->name, name);
140         kstrdup(&pp->user, eve);
141         pp->perm = 0640;
142         pp->valid = 1;
143 }
144
145 static void
146 sddelpart(SDunit* unit, char* name)
147 {
148         int i;
149         SDpart *pp;
150
151         /*
152          * Look for the partition to delete.
153          * Can't delete if someone still has it open.
154          */
155         pp = unit->part;
156         for(i = 0; i < unit->npart; i++){
157                 if(strcmp(name, pp->name) == 0)
158                         break;
159                 pp++;
160         }
161         if(i >= unit->npart)
162                 error(Ebadctl);
163         if(strcmp(up->user, pp->user) && !iseve())
164                 error(Eperm);
165         pp->valid = 0;
166         pp->vers++;
167 }
168
169 static void
170 sdincvers(SDunit *unit)
171 {
172         int i;
173
174         unit->vers++;
175         if(unit->part){
176                 for(i = 0; i < unit->npart; i++){
177                         unit->part[i].valid = 0;
178                         unit->part[i].vers++;
179                 }
180         }
181 }
182
183 static int
184 sdinitpart(SDunit* unit)
185 {
186         int nf;
187         uvlong start, end;
188         char *f[4], *p, *q, buf[10];
189
190         if(unit->sectors > 0){
191                 unit->sectors = unit->secsize = 0;
192                 sdincvers(unit);
193         }
194
195         if(unit->inquiry[0] & 0xC0)
196                 return 0;
197         switch(unit->inquiry[0] & 0x1F){
198         case 0x00:                      /* DA */
199         case 0x04:                      /* WORM */
200         case 0x05:                      /* CD-ROM */
201         case 0x07:                      /* MO */
202                 break;
203         default:
204                 return 0;
205         }
206
207         if(unit->dev->ifc->online)
208                 unit->dev->ifc->online(unit);
209         if(unit->sectors){
210                 sdincvers(unit);
211                 sdaddpart(unit, "data", 0, unit->sectors);
212
213                 /*
214                  * Use partitions passed from boot program,
215                  * e.g.
216                  *      sdC0part=dos 63 123123/plan9 123123 456456
217                  * This happens before /boot sets hostname so the
218                  * partitions will have the null-string for user.
219                  * The gen functions patch it up.
220                  */
221                 snprint(buf, sizeof buf, "%spart", unit->name);
222                 for(p = getconf(buf); p != nil; p = q){
223                         if(q = strchr(p, '/'))
224                                 *q++ = '\0';
225                         nf = tokenize(p, f, nelem(f));
226                         if(nf < 3)
227                                 continue;
228
229                         start = strtoull(f[1], 0, 0);
230                         end = strtoull(f[2], 0, 0);
231                         if(!waserror()){
232                                 sdaddpart(unit, f[0], start, end);
233                                 poperror();
234                         }
235                 }
236         }
237
238         return 1;
239 }
240
241 static int
242 sdindex(int idno)
243 {
244         char *p;
245
246         p = strchr(devletters, idno);
247         if(p == nil)
248                 return -1;
249         return p-devletters;
250 }
251
252 static SDev*
253 sdgetdev(int idno)
254 {
255         SDev *sdev;
256         int i;
257
258         if((i = sdindex(idno)) < 0)
259                 return nil;
260
261         qlock(&devslock);
262         if(sdev = devs[i])
263                 incref(&sdev->r);
264         qunlock(&devslock);
265         return sdev;
266 }
267
268 static SDunit*
269 sdgetunit(SDev* sdev, int subno)
270 {
271         SDunit *unit;
272         char buf[32];
273
274         /*
275          * Associate a unit with a given device and sub-unit
276          * number on that device.
277          * The device will be probed if it has not already been
278          * successfully accessed.
279          */
280         qlock(&sdev->unitlock);
281         if(subno > sdev->nunit){
282                 qunlock(&sdev->unitlock);
283                 return nil;
284         }
285
286         unit = sdev->unit[subno];
287         if(unit == nil){
288                 /*
289                  * Probe the unit only once. This decision
290                  * may be a little severe and reviewed later.
291                  */
292                 if(sdev->unitflg[subno]){
293                         qunlock(&sdev->unitlock);
294                         return nil;
295                 }
296
297                 if((unit = malloc(sizeof(SDunit))) == nil){
298                         qunlock(&sdev->unitlock);
299                         return nil;
300                 }
301                 sdev->unitflg[subno] = 1;
302                 snprint(buf, sizeof buf, "%s%x", sdev->name, subno);
303                 kstrdup(&unit->name, buf);
304                 kstrdup(&unit->user, eve);
305                 unit->perm = 0555;
306                 unit->subno = subno;
307                 unit->dev = sdev;
308         
309                 if(sdev->enabled == 0)
310                         sdev->enabled = sdev->ifc->enable == nil || sdev->ifc->enable(sdev);
311
312                 /*
313                  * No need to lock anything here as this is only
314                  * called before the unit is made available in the
315                  * sdunit[] array.
316                  */
317                 if(sdev->enabled == 0 || unit->dev->ifc->verify(unit) == 0){
318                         qunlock(&sdev->unitlock);
319                         free(unit->name);
320                         free(unit->user);
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, locked;
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         locked = (unit->inquiry[1] & 0x80) != 0;
837         if(!locked){
838                 qunlock(&unit->ctl);
839                 poperror();
840         }
841
842         offset = off%unit->secsize;
843         if(offset+len > nb*unit->secsize)
844                 len = nb*unit->secsize - offset;
845         hard = offset || write && len%unit->secsize;
846
847         if(iskaddr(a) && ((uintptr)a & (BY2PG-1))==0 && !hard) {
848                 b = (uchar*)a;
849                 allocd = 0;
850         }else{
851                 while((b = sdmalloc(nb*unit->secsize)) == nil){
852                         if(!waserror()){
853                                 resrcwait("no memory for sdbio");
854                                 poperror();
855                         }
856                 }
857                 allocd = 1;
858         }
859         if(waserror()){
860                 if(allocd)
861                         sdfree(b);
862                 if(!locked)
863                         decref(&sdev->r);               /* gadverdamme! */
864                 nexterror();
865         }
866
867         if(write){
868                 if(hard){
869                         l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno);
870                         if(l < 0)
871                                 error(Eio);
872                         if(l < (nb*unit->secsize)){
873                                 nb = l/unit->secsize;
874                                 l = nb*unit->secsize - offset;
875                                 if(len > l)
876                                         len = l;
877                         }
878                 }
879                 if(allocd)
880                         memmove(b+offset, a, len);
881                 l = unit->dev->ifc->bio(unit, 0, 1, b, nb, bno);
882                 if(l < 0)
883                         error(Eio);
884                 if(l < offset)
885                         len = 0;
886                 else if(len > l - offset)
887                         len = l - offset;
888         }
889         else{
890                 l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno);
891                 if(l < 0)
892                         error(Eio);
893                 if(l < offset)
894                         len = 0;
895                 else if(len > l - offset)
896                         len = l - offset;
897                 if(allocd)
898                         memmove(a, b+offset, len);
899         }
900         if(allocd)
901                 sdfree(b);
902         poperror();
903
904         if(locked){
905                 qunlock(&unit->ctl);
906                 poperror();
907         }
908
909         decref(&sdev->r);
910         return len;
911 }
912
913 static long
914 sdrio(SDreq* r, void* a, long n)
915 {
916         char *errstr;
917         int rv;
918         void *data;
919         SDunit *u;
920         int (*f)(SDreq*);
921
922         if(n >= SDmaxio || n < 0)
923                 error(Etoobig);
924         u = r->unit;
925         if(u->haversense && r->cmd[0] == 0x03){
926                 u->haversense = 0;
927                 r->rlen = sizeof u->rsense;
928                 if(r->rlen > n)
929                         r->rlen = n;
930                 memmove(a, u->rsense, r->rlen);
931                 r->status = SDok;
932                 return r->rlen;
933         }
934
935         data = nil;
936         while(n > 0 && (data = sdmalloc(n)) == nil){
937                 if(!waserror()){
938                         resrcwait("no memory for sdrio");
939                         poperror();
940                 }
941         }
942         if(waserror()){
943                 sdfree(data);
944                 r->data = nil;
945                 nexterror();
946         }
947         if(r->write && n > 0)
948                 memmove(data, a, n);
949         r->data = data;
950         r->dlen = n;
951
952         if(r->proto == SData){
953                 f = u->dev->ifc->ataio;
954                 errstr = Enoata;
955         }else{
956                 f = u->dev->ifc->rio;
957                 errstr = Enoscsi;
958         }
959         if(f == nil)
960                 error(errstr);
961         rv = f(r);
962         if(r->flags & SDvalidsense){
963                 memmove(u->rsense, r->sense, sizeof u->rsense);
964                 u->haversense = 1;
965         }
966         if(rv != SDok)
967                 error(Eio);
968
969         if(!r->write && r->rlen > 0)
970                 memmove(a, data, r->rlen);
971         poperror();
972         sdfree(data);
973         r->data = nil;
974
975         return r->rlen;
976 }
977
978 /*
979  * SCSI simulation for non-SCSI devices
980  *
981  * see /sys/src/cmd/scuzz/sense.c for information on key.
982  * see /sys/lib/scsicodes for asc:ascq codes
983  */
984 int
985 sdsetsense(SDreq *r, int status, int key, int asc, int ascq)
986 {
987         int len;
988         SDunit *unit;
989
990         unit = r->unit;
991         unit->sense[0] = 0x80 | 0x70;   /* valid; fixed-format */
992         unit->sense[2] = key;
993         unit->sense[12] = asc;
994         unit->sense[13] = ascq;
995
996         r->status = status;
997         if(status == SDcheck && !(r->flags & SDnosense)){
998                 /* request sense case from sdfakescsi */
999                 len = sizeof unit->sense;
1000                 if(len > sizeof r->sense-1)
1001                         len = sizeof r->sense-1;
1002                 memmove(r->sense, unit->sense, len);
1003                 unit->sense[2] = 0;
1004                 unit->sense[12] = 0;
1005                 unit->sense[13] = 0;
1006                 r->flags |= SDvalidsense;
1007                 return SDok;
1008         }
1009         return status;
1010 }
1011
1012 int
1013 sdfakescsi(SDreq *r)
1014 {
1015         uchar *cmd, *p;
1016         uvlong len;
1017         SDunit *unit;
1018
1019         cmd = r->cmd;
1020         r->rlen = 0;
1021         unit = r->unit;
1022
1023         /*
1024          * Map SCSI commands into ATA commands for discs.
1025          * Fail any command with a LUN except INQUIRY which
1026          * will return 'logical unit not supported'.
1027          */
1028         if((cmd[1]>>5) && cmd[0] != 0x12)
1029                 return sdsetsense(r, SDcheck, 0x05, 0x25, 0);
1030
1031         switch(cmd[0]){
1032         default:
1033                 return sdsetsense(r, SDcheck, 0x05, 0x20, 0);
1034
1035         case 0x00:      /* test unit ready */
1036                 return sdsetsense(r, SDok, 0, 0, 0);
1037
1038         case 0x03:      /* request sense */
1039                 if(cmd[4] < sizeof unit->sense)
1040                         len = cmd[4];
1041                 else
1042                         len = sizeof unit->sense;
1043                 if(r->data && r->dlen >= len){
1044                         memmove(r->data, unit->sense, len);
1045                         r->rlen = len;
1046                 }
1047                 return sdsetsense(r, SDok, 0, 0, 0);
1048
1049         case 0x12:      /* inquiry */
1050                 if(cmd[4] < sizeof unit->inquiry)
1051                         len = cmd[4];
1052                 else
1053                         len = sizeof unit->inquiry;
1054                 if(r->data && r->dlen >= len){
1055                         memmove(r->data, unit->inquiry, len);
1056                         r->rlen = len;
1057                 }
1058                 return sdsetsense(r, SDok, 0, 0, 0);
1059
1060         case 0x1B:      /* start/stop unit */
1061                 /*
1062                  * nop for now, can use power management later.
1063                  */
1064                 return sdsetsense(r, SDok, 0, 0, 0);
1065
1066         case 0x25:      /* read capacity */
1067                 if((cmd[1] & 0x01) || cmd[2] || cmd[3])
1068                         return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
1069                 if(r->data == nil || r->dlen < 8)
1070                         return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
1071
1072                 /*
1073                  * Read capacity returns the LBA of the last sector.
1074                  */
1075                 len = unit->sectors;
1076                 if(len >= 0xffffffff)
1077                         len = 0xffffffff;
1078                 else if(len > 0)
1079                         len--;
1080                 p = r->data;
1081                 *p++ = len>>24;
1082                 *p++ = len>>16;
1083                 *p++ = len>>8;
1084                 *p++ = len;
1085                 len = unit->secsize;
1086                 *p++ = len>>24;
1087                 *p++ = len>>16;
1088                 *p++ = len>>8;
1089                 *p++ = len;
1090                 r->rlen = p - (uchar*)r->data;
1091                 return sdsetsense(r, SDok, 0, 0, 0);
1092
1093         case 0x9E:      /* long read capacity */
1094                 if((cmd[1] & 0x01) || cmd[2] || cmd[3])
1095                         return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
1096                 if(r->data == nil || r->dlen < 8)
1097                         return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
1098                 /*
1099                  * Read capcity returns the LBA of the last sector.
1100                  */
1101                 len = unit->sectors;
1102                 if(len > 0)
1103                         len--;
1104                 p = r->data;
1105                 *p++ = len>>56;
1106                 *p++ = len>>48;
1107                 *p++ = len>>40;
1108                 *p++ = len>>32;
1109                 *p++ = len>>24;
1110                 *p++ = len>>16;
1111                 *p++ = len>>8;
1112                 *p++ = len;
1113                 len = unit->secsize;
1114                 *p++ = len>>24;
1115                 *p++ = len>>16;
1116                 *p++ = len>>8;
1117                 *p++ = len;
1118                 r->rlen = p - (uchar*)r->data;
1119                 return sdsetsense(r, SDok, 0, 0, 0);
1120
1121         case 0x35:      /* synchronize cache */
1122         case 0x91:
1123                 return sdsetsense(r, SDok, 0, 0, 0);
1124
1125         case 0x08:      /* read6 */
1126         case 0x0a:      /* write6 */
1127         case 0x28:      /* read10 */
1128         case 0x2a:      /* write10 */
1129         case 0xa8:      /* read12 */
1130         case 0xaa:      /* write12 */
1131         case 0x88:      /* read16 */
1132         case 0x8a:      /* write16 */
1133                 return SDnostatus;
1134         }
1135 }
1136
1137 int
1138 sdfakescsirw(SDreq *r, uvlong *llba, int *nsec, int *rwp)
1139 {
1140         uchar *c;
1141         int rw, count;
1142         uvlong lba;
1143
1144         c = r->cmd;
1145         rw = SDread;
1146         if((c[0] & 0xf) == 0xa)
1147                 rw = SDwrite;
1148         switch(c[0]){
1149         case 0x08:      /* read6 */
1150         case 0x0a:
1151                 lba = (c[1] & 0xf)<<16 | c[2]<<8 | c[3];
1152                 count = c[4];
1153                 break;
1154         case 0x28:      /* read10 */
1155         case 0x2a:
1156                 lba = c[2]<<24 | c[3]<<16 | c[4]<<8 | c[5];
1157                 count = c[7]<<8 | c[8];
1158                 break;
1159         case 0xa8:      /* read12 */
1160         case 0xaa:
1161                 lba = c[2]<<24 | c[3]<<16 | c[4]<<8 | c[5];
1162                 count = c[6]<<24 | c[7]<<16 | c[8]<<8 | c[9];
1163                 break;
1164         case 0x88:      /* read16 */
1165         case 0x8a:
1166                 /* ata commands only go to 48-bit lba */
1167                 if(c[2] || c[3])
1168                         return sdsetsense(r, SDcheck, 3, 0xc, 2);
1169                 lba = (uvlong)c[4]<<40 | (uvlong)c[5]<<32;
1170                 lba |= c[6]<<24 | c[7]<<16 | c[8]<<8 | c[9];
1171                 count = c[10]<<24 | c[11]<<16 | c[12]<<8 | c[13];
1172                 break;
1173         default:
1174                 print("%s: bad cmd 0x%.2ux\n", r->unit->name, c[0]);
1175                 r->status  = sdsetsense(r, SDcheck, 0x05, 0x20, 0);
1176                 return SDcheck;
1177         }
1178         if(r->data == nil)
1179                 return SDok;
1180         if(r->dlen < count * r->unit->secsize)
1181                 count = r->dlen/r->unit->secsize;
1182         if(rwp)
1183                 *rwp = rw;
1184         *llba = lba;
1185         *nsec = count;
1186         return SDnostatus;
1187 }
1188
1189 static long
1190 extrarw(int write, Chan *c, void *a, long n, vlong off)
1191 {
1192         int i;
1193         SDrw *f;
1194         SDev *sdev;
1195         SDunit *unit;
1196
1197         sdev = sdgetdev(DEV(c->qid));
1198         if(sdev == nil)
1199                 error(Enonexist);
1200         if(waserror()){
1201                 decref(&sdev->r);
1202                 nexterror();
1203         }
1204         unit = sdev->unit[UNIT(c->qid)];
1205         if(unit->vers != c->qid.vers)
1206                 error(Echange);
1207         unit = sdev->unit[UNIT(c->qid)];
1208         i = PART(c->qid);
1209         if(i >= unit->nefile)
1210                 error(Enonexist);
1211         f = unit->efile[i].r;
1212         if(write)
1213                 f = unit->efile[i].w;
1214         if(i >= unit->nefile || f == nil)
1215                 error(Eperm);
1216         n = f(unit, c, a, n, off);
1217         poperror();
1218         decref(&sdev->r);
1219         return n;
1220 }
1221
1222 static char*
1223 deftopctl(SDev *s, char *p, char *e)
1224 {
1225         return seprint(p, e, "sd%c %s %d units\n", s->idno, s->ifc->name, s->nunit);
1226 }
1227
1228 static long
1229 sdread(Chan *c, void *a, long n, vlong off)
1230 {
1231         char *p, *e, *buf;
1232         SDev *sdev;
1233         SDpart *pp;
1234         SDreq *r;
1235         SDunit *unit;
1236         ulong offset;
1237         int i, l, m, status;
1238
1239         offset = off;
1240         switch(TYPE(c->qid)){
1241         default:
1242                 error(Eperm);
1243         case Qtopctl:
1244                 m = 64*1024;    /* room for register dumps */
1245                 p = buf = smalloc(m);
1246                 e = p + m;
1247                 qlock(&devslock);
1248                 for(i = 0; i < nelem(devs); i++){
1249                         sdev = devs[i];
1250                         if(sdev && sdev->ifc->rtopctl)
1251                                 p = sdev->ifc->rtopctl(sdev, p, e);
1252                         else if(sdev)
1253                                 p = deftopctl(sdev, p, e);
1254                 }
1255                 qunlock(&devslock);
1256                 n = readstr(off, a, n, buf);
1257                 free(buf);
1258                 return n;
1259
1260         case Qtopdir:
1261         case Qunitdir:
1262                 return devdirread(c, a, n, 0, 0, sdgen);
1263
1264         case Qctl:
1265                 sdev = sdgetdev(DEV(c->qid));
1266                 if(sdev == nil)
1267                         error(Enonexist);
1268
1269                 unit = sdev->unit[UNIT(c->qid)];
1270                 m = 16*1024;    /* room for register dumps */
1271                 p = smalloc(m);
1272                 l = snprint(p, m, "inquiry %.48s\n",
1273                         (char*)unit->inquiry+8);
1274                 qlock(&unit->ctl);
1275                 /*
1276                  * If there's a device specific routine it must
1277                  * provide all information pertaining to night geometry
1278                  * and the garscadden trains.
1279                  */
1280                 if(unit->dev->ifc->rctl)
1281                         l += unit->dev->ifc->rctl(unit, p+l, m-l);
1282                 if(unit->sectors == 0)
1283                         sdinitpart(unit);
1284                 if(unit->sectors){
1285                         if(unit->dev->ifc->rctl == nil)
1286                                 l += snprint(p+l, m-l,
1287                                         "geometry %llud %lud\n",
1288                                         unit->sectors, unit->secsize);
1289                         pp = unit->part;
1290                         for(i = 0; i < unit->npart; i++){
1291                                 if(pp->valid)
1292                                         l += snprint(p+l, m-l,
1293                                                 "part %s %llud %llud\n",
1294                                                 pp->name, pp->start, pp->end);
1295                                 pp++;
1296                         }
1297                 }
1298                 qunlock(&unit->ctl);
1299                 decref(&sdev->r);
1300                 l = readstr(offset, a, n, p);
1301                 free(p);
1302                 return l;
1303
1304         case Qraw:
1305                 sdev = sdgetdev(DEV(c->qid));
1306                 if(sdev == nil)
1307                         error(Enonexist);
1308
1309                 unit = sdev->unit[UNIT(c->qid)];
1310                 qlock(&unit->raw);
1311                 if(waserror()){
1312                         qunlock(&unit->raw);
1313                         decref(&sdev->r);
1314                         nexterror();
1315                 }
1316                 if(unit->state == Rawdata){
1317                         unit->state = Rawstatus;
1318                         r = unit->req;
1319                         i = sdrio(r, a, n);
1320                 }
1321                 else if(unit->state == Rawstatus){
1322                         r = unit->req;
1323                         unit->req = nil;
1324                         unit->state = Rawcmd;
1325                         status = r->status;
1326                         if(r->proto == SData){
1327                                 p = a;
1328                                 i = 16 + Ahdrsz;
1329                                 if(n < i)
1330                                         i = n;
1331                                 if(i > 0)
1332                                         p[0] = status;
1333                                 if(i > Ahdrsz)
1334                                         memmove(p + Ahdrsz, r->cmd, i - Ahdrsz);
1335                         }else
1336                                 i = readnum(0, a, n, status, NUMSIZE);
1337                         free(r);
1338                 } else
1339                         i = 0;
1340                 poperror();
1341                 qunlock(&unit->raw);
1342                 decref(&sdev->r);
1343                 return i;
1344
1345         case Qpart:
1346                 return sdbio(c, 0, a, n, off);
1347         case Qextra:
1348                 return extrarw(0, c, a, n, off);
1349         }
1350 }
1351
1352 static void legacytopctl(Cmdbuf*);
1353
1354 static long
1355 sdwrite(Chan* c, void* a, long n, vlong off)
1356 {
1357         char *f0;
1358         int i, atacdb, proto, ataproto;
1359         uchar *u;
1360         uvlong end, start;
1361         Cmdbuf *cb;
1362         SDifc *ifc;
1363         SDreq *req;
1364         SDunit *unit;
1365         SDev *sdev;
1366
1367         switch(TYPE(c->qid)){
1368         default:
1369                 error(Eperm);
1370         case Qtopctl:
1371                 cb = parsecmd(a, n);
1372                 if(waserror()){
1373                         free(cb);
1374                         nexterror();
1375                 }
1376                 if(cb->nf == 0)
1377                         error("empty control message");
1378                 f0 = cb->f[0];
1379                 cb->f++;
1380                 cb->nf--;
1381                 if(strcmp(f0, "config") == 0){
1382                         /* wormhole into ugly legacy interface */
1383                         legacytopctl(cb);
1384                         poperror();
1385                         free(cb);
1386                         break;
1387                 }
1388                 /*
1389                  * "ata arg..." invokes sdifc[i]->wtopctl(nil, cb),
1390                  * where sdifc[i]->name=="ata" and cb contains the args.
1391                  */
1392                 ifc = nil;
1393                 sdev = nil;
1394                 for(i=0; sdifc[i]; i++){
1395                         if(strcmp(sdifc[i]->name, f0) == 0){
1396                                 ifc = sdifc[i];
1397                                 sdev = nil;
1398                                 goto subtopctl;
1399                         }
1400                 }
1401                 /*
1402                  * "sd1 arg..." invokes sdifc[i]->wtopctl(sdev, cb),
1403                  * where sdifc[i] and sdev match controller letter "1",
1404                  * and cb contains the args.
1405                  */
1406                 if(f0[0]=='s' && f0[1]=='d' && f0[2] && f0[3] == 0){
1407                         if((sdev = sdgetdev(f0[2])) != nil){
1408                                 ifc = sdev->ifc;
1409                                 goto subtopctl;
1410                         }
1411                 }
1412                 error("unknown interface");
1413
1414         subtopctl:
1415                 if(waserror()){
1416                         if(sdev)
1417                                 decref(&sdev->r);
1418                         nexterror();
1419                 }
1420                 if(ifc->wtopctl)
1421                         ifc->wtopctl(sdev, cb);
1422                 else
1423                         error(Ebadctl);
1424                 poperror();
1425                 poperror();
1426                 if(sdev)
1427                         decref(&sdev->r);
1428                 free(cb);
1429                 break;
1430
1431         case Qctl:
1432                 cb = parsecmd(a, n);
1433                 sdev = sdgetdev(DEV(c->qid));
1434                 if(sdev == nil)
1435                         error(Enonexist);
1436                 unit = sdev->unit[UNIT(c->qid)];
1437
1438                 qlock(&unit->ctl);
1439                 if(waserror()){
1440                         qunlock(&unit->ctl);
1441                         decref(&sdev->r);
1442                         free(cb);
1443                         nexterror();
1444                 }
1445                 if(unit->vers != c->qid.vers)
1446                         error(Echange);
1447
1448                 if(cb->nf < 1)
1449                         error(Ebadctl);
1450                 if(strcmp(cb->f[0], "part") == 0){
1451                         if(cb->nf != 4)
1452                                 error(Ebadctl);
1453                         if(unit->sectors == 0 && !sdinitpart(unit))
1454                                 error(Eio);
1455                         start = strtoull(cb->f[2], 0, 0);
1456                         end = strtoull(cb->f[3], 0, 0);
1457                         sdaddpart(unit, cb->f[1], start, end);
1458                 }
1459                 else if(strcmp(cb->f[0], "delpart") == 0){
1460                         if(cb->nf != 2 || unit->part == nil)
1461                                 error(Ebadctl);
1462                         sddelpart(unit, cb->f[1]);
1463                 }
1464                 else if(unit->dev->ifc->wctl)
1465                         unit->dev->ifc->wctl(unit, cb);
1466                 else
1467                         error(Ebadctl);
1468                 qunlock(&unit->ctl);
1469                 decref(&sdev->r);
1470                 poperror();
1471                 free(cb);
1472                 break;
1473
1474         case Qraw:
1475                 proto = SDcdb;
1476                 ataproto = 0;
1477                 atacdb = 0;
1478                 sdev = sdgetdev(DEV(c->qid));
1479                 if(sdev == nil)
1480                         error(Enonexist);
1481                 unit = sdev->unit[UNIT(c->qid)];
1482                 qlock(&unit->raw);
1483                 if(waserror()){
1484                         qunlock(&unit->raw);
1485                         decref(&sdev->r);
1486                         nexterror();
1487                 }
1488                 switch(unit->state){
1489                 case Rawcmd:
1490                         /* sneaky ata commands */
1491                         u = a;
1492                         if(n > 1 && *u == 0xff){
1493                                 proto = SData;
1494                                 ataproto = u[1];
1495                                 a = u + 2;
1496                                 atacdb = Ahdrsz;
1497                                 n -= Ahdrsz;
1498                         }               
1499                         if(n < 6 || n > sizeof(req->cmd))
1500                                 error(Ebadarg);
1501                         req = smalloc(sizeof(SDreq));
1502                         req->unit = unit;
1503                         if(waserror()){
1504                                 free(req);
1505                                 nexterror();
1506                         }
1507                         memmove(req->cmd, a, n);
1508                         poperror();
1509                         req->clen = n;
1510                 /*      req->flags = SDnosense; */
1511                         req->status = ~0;
1512                         req->proto = proto;
1513                         req->ataproto = ataproto;
1514                         unit->req = req;
1515                         unit->state = Rawdata;
1516                         n += atacdb;
1517                         break;
1518
1519                 case Rawstatus:
1520                         unit->state = Rawcmd;
1521                         free(unit->req);
1522                         unit->req = nil;
1523                         error(Ebadusefd);
1524
1525                 case Rawdata:
1526                         unit->state = Rawstatus;
1527                         req = unit->req;
1528                         req->write = 1;
1529                         n = sdrio(req, a, n);
1530                 }
1531                 poperror();
1532                 qunlock(&unit->raw);
1533                 decref(&sdev->r);
1534                 break;
1535         case Qpart:
1536                 return sdbio(c, 1, a, n, off);
1537         case Qextra:
1538                 return extrarw(1, c, a, n, off);
1539         }
1540
1541         return n;
1542 }
1543
1544 static int
1545 sdwstat(Chan* c, uchar* dp, int n)
1546 {
1547         Dir *d;
1548         SDpart *pp;
1549         SDperm *perm;
1550         SDunit *unit;
1551         SDev *sdev;
1552
1553         if(c->qid.type & QTDIR)
1554                 error(Eperm);
1555         if(TYPE(c->qid) == Qtopctl){
1556                 unit = &topctlunit;
1557                 sdev = nil;
1558         }else{
1559                 sdev = sdgetdev(DEV(c->qid));
1560                 if(sdev == nil)
1561                         error(Enonexist);
1562                 unit = sdev->unit[UNIT(c->qid)];
1563         }
1564         qlock(&unit->ctl);
1565
1566         d = nil;
1567         if(waserror()){
1568                 qunlock(&unit->ctl);
1569                 if(sdev != nil)
1570                         decref(&sdev->r);
1571                 free(d);
1572                 nexterror();
1573         }
1574
1575         switch(TYPE(c->qid)){
1576         default:
1577                 error(Eperm);
1578         case Qtopctl:
1579         case Qctl:
1580                 perm = &unit->ctlperm;
1581                 break;
1582         case Qraw:
1583                 perm = &unit->rawperm;
1584                 break;
1585         case Qpart:
1586                 pp = &unit->part[PART(c->qid)];
1587                 if(unit->vers+pp->vers != c->qid.vers)
1588                         error(Enonexist);
1589                 perm = &pp->SDperm;
1590                 break;
1591         }
1592
1593         if(strcmp(up->user, perm->user) && !iseve())
1594                 error(Eperm);
1595
1596         d = smalloc(sizeof(Dir)+n);
1597         n = convM2D(dp, n, &d[0], (char*)&d[1]);
1598         if(n == 0)
1599                 error(Eshortstat);
1600         if(d->atime != ~0 ||  d->mtime  != ~0 ||  d->length  != ~0)
1601                 error(Eperm);
1602         if(!emptystr(d[0].muid) || !emptystr(d[0].name))
1603                 error(Eperm);
1604         if(!emptystr(d[0].uid))
1605                 kstrdup(&perm->user, d[0].uid);
1606         if(!emptystr(d[0].gid) && strcmp(d[0].gid, eve) != 0)
1607                 error(Eperm);
1608         if(d[0].mode != ~0UL)
1609                 perm->perm = (perm->perm & ~0777) | (d[0].mode & 0777);
1610         poperror();
1611         qunlock(&unit->ctl);
1612         if(sdev != nil)
1613                 decref(&sdev->r);
1614         free(d);
1615         return n;
1616 }
1617
1618 static int
1619 configure(char* spec, DevConf* cf)
1620 {
1621         SDev *s, *sdev;
1622         char *p;
1623         int i;
1624
1625         if(sdindex(*spec) < 0)
1626                 error("bad sd spec");
1627
1628         if((p = strchr(cf->type, '/')) != nil)
1629                 *p++ = '\0';
1630
1631         for(i = 0; sdifc[i] != nil; i++)
1632                 if(strcmp(sdifc[i]->name, cf->type) == 0)
1633                         break;
1634         if(sdifc[i] == nil)
1635                 error("sd type not found");
1636         if(p)
1637                 *(p-1) = '/';
1638
1639         if(sdifc[i]->probe == nil)
1640                 error("sd type cannot probe");
1641
1642         sdev = sdifc[i]->probe(cf);
1643         for(s=sdev; s; s=s->next)
1644                 s->idno = *spec;
1645         sdadddevs(sdev);
1646         return 0;
1647 }
1648
1649 static int
1650 unconfigure(char* spec)
1651 {
1652         int i;
1653         SDev *sdev;
1654         SDunit *unit;
1655
1656         if((i = sdindex(*spec)) < 0)
1657                 error(Enonexist);
1658
1659         qlock(&devslock);
1660         if((sdev = devs[i]) == nil){
1661                 qunlock(&devslock);
1662                 error(Enonexist);
1663         }
1664         if(sdev->r.ref){
1665                 qunlock(&devslock);
1666                 error(Einuse);
1667         }
1668         devs[i] = nil;
1669         qunlock(&devslock);
1670
1671         /* make sure no interrupts arrive anymore before removing resources */
1672         if(sdev->enabled && sdev->ifc->disable)
1673                 sdev->ifc->disable(sdev);
1674
1675         for(i = 0; i != sdev->nunit; i++){
1676                 if(unit = sdev->unit[i]){
1677                         free(unit->name);
1678                         free(unit->user);
1679                         free(unit);
1680                 }
1681         }
1682
1683         if(sdev->ifc->clear)
1684                 sdev->ifc->clear(sdev);
1685         free(sdev);
1686         return 0;
1687 }
1688
1689 static int
1690 sdconfig(int on, char* spec, DevConf* cf)
1691 {
1692         if(on)
1693                 return configure(spec, cf);
1694         return unconfigure(spec);
1695 }
1696
1697 int
1698 sdaddfile(SDunit *unit, char *s, int perm, char *u, SDrw *r, SDrw *w)
1699 {
1700         int i;
1701         SDfile *e;
1702         static Lock lk;
1703
1704         if(unit == nil)
1705                 return -1;
1706         lock(&lk);
1707         for(i = 0; i < unit->nefile; i++)
1708                 if(strcmp(unit->efile[i].name, s) == 0)
1709                         break;
1710         if(i >= nelem(unit->efile)){
1711                 unlock(&lk);
1712                 return -1;
1713         }
1714         if(i >= unit->nefile)
1715                 unit->nefile = i + 1;
1716         e = unit->efile + i;
1717         if(e->name == nil)
1718                 kstrdup(&e->name, s);
1719         if(e->user == nil)
1720                  kstrdup(&e->user, u);
1721         e->perm = perm;
1722         e->r = r;
1723         e->w = w;
1724         unlock(&lk);
1725         return 0;
1726 }
1727
1728 static void
1729 sdshutdown(void)
1730 {
1731         int i;
1732         SDev *sd;
1733
1734         for(i = 0; i < nelem(devs); i++){
1735                 sd = devs[i];
1736                 if(sd == nil)
1737                         continue;
1738                 if(sd->ifc->disable == nil){
1739                         print("#S/sd%c: no disable function\n", devletters[i]);
1740                         continue;
1741                 }
1742                 sd->ifc->disable(sd);
1743         }
1744 }
1745
1746 Dev sddevtab = {
1747         'S',
1748         "sd",
1749
1750         sdreset,
1751         devinit,
1752         sdshutdown,
1753         sdattach,
1754         sdwalk,
1755         sdstat,
1756         sdopen,
1757         devcreate,
1758         sdclose,
1759         sdread,
1760         devbread,
1761         sdwrite,
1762         devbwrite,
1763         devremove,
1764         sdwstat,
1765         devpower,
1766         sdconfig,
1767 };
1768
1769 /*
1770  * This is wrong for so many reasons.  This code must go.
1771  */
1772 typedef struct Confdata Confdata;
1773 struct Confdata {
1774         int     on;
1775         char*   spec;
1776         DevConf cf;
1777 };
1778
1779 static void
1780 parseswitch(Confdata* cd, char* option)
1781 {
1782         if(!strcmp("on", option))
1783                 cd->on = 1;
1784         else if(!strcmp("off", option))
1785                 cd->on = 0;
1786         else
1787                 error(Ebadarg);
1788 }
1789
1790 static void
1791 parsespec(Confdata* cd, char* option)
1792 {
1793         if(strlen(option) > 1)
1794                 error(Ebadarg);
1795         cd->spec = option;
1796 }
1797
1798 static Devport*
1799 getnewport(DevConf* dc)
1800 {
1801         Devport *p;
1802
1803         p = malloc((dc->nports + 1) * sizeof(Devport));
1804         if(p == nil)
1805                 panic("sd: no memory for Devport");
1806         if(dc->nports > 0){
1807                 memmove(p, dc->ports, dc->nports * sizeof(Devport));
1808                 free(dc->ports);
1809         }
1810         dc->ports = p;
1811         p = &dc->ports[dc->nports++];
1812         p->size = -1;
1813         p->port = (ulong)-1;
1814         return p;
1815 }
1816
1817 static void
1818 parseport(Confdata* cd, char* option)
1819 {
1820         char *e;
1821         Devport *p;
1822
1823         if(cd->cf.nports == 0 || cd->cf.ports[cd->cf.nports-1].port != (ulong)-1)
1824                 p = getnewport(&cd->cf);
1825         else
1826                 p = &cd->cf.ports[cd->cf.nports-1];
1827         p->port = strtol(option, &e, 0);
1828         if(e == nil || *e != '\0')
1829                 error(Ebadarg);
1830 }
1831
1832 static void
1833 parsesize(Confdata* cd, char* option)
1834 {
1835         char *e;
1836         Devport *p;
1837
1838         if(cd->cf.nports == 0 || cd->cf.ports[cd->cf.nports-1].size != -1)
1839                 p = getnewport(&cd->cf);
1840         else
1841                 p = &cd->cf.ports[cd->cf.nports-1];
1842         p->size = (int)strtol(option, &e, 0);
1843         if(e == nil || *e != '\0')
1844                 error(Ebadarg);
1845 }
1846
1847 static void
1848 parseirq(Confdata* cd, char* option)
1849 {
1850         char *e;
1851
1852         cd->cf.intnum = strtoul(option, &e, 0);
1853         if(e == nil || *e != '\0')
1854                 error(Ebadarg);
1855 }
1856
1857 static void
1858 parsetype(Confdata* cd, char* option)
1859 {
1860         cd->cf.type = option;
1861 }
1862
1863 static struct {
1864         char    *name;
1865         void    (*parse)(Confdata*, char*);
1866 } options[] = {
1867         "switch",       parseswitch,
1868         "spec",         parsespec,
1869         "port",         parseport,
1870         "size",         parsesize,
1871         "irq",          parseirq,
1872         "type",         parsetype,
1873 };
1874
1875 static void
1876 legacytopctl(Cmdbuf *cb)
1877 {
1878         char *opt;
1879         int i, j;
1880         Confdata cd;
1881
1882         memset(&cd, 0, sizeof cd);
1883         cd.on = -1;
1884         for(i=0; i<cb->nf; i+=2){
1885                 if(i+2 > cb->nf)
1886                         error(Ebadarg);
1887                 opt = cb->f[i];
1888                 for(j=0; j<nelem(options); j++)
1889                         if(strcmp(opt, options[j].name) == 0){
1890                                 options[j].parse(&cd, cb->f[i+1]);
1891                                 break;
1892                         }
1893                 if(j == nelem(options))
1894                         error(Ebadarg);
1895         }
1896         if(cd.on < 0 || cd.spec == 0)
1897                 error(Ebadarg);
1898         if(cd.on && cd.cf.type == nil)
1899                 error(Ebadarg);
1900         sdconfig(cd.on, cd.spec, &cd.cf);
1901 }