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