]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/port/devsd.c
merge
[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, locked;
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         locked = (unit->inquiry[1] & 0x80) != 0;
836         if(!locked){
837                 qunlock(&unit->ctl);
838                 poperror();
839         }
840
841         offset = off%unit->secsize;
842         if(offset+len > nb*unit->secsize)
843                 len = nb*unit->secsize - offset;
844         hard = offset || write && len%unit->secsize;
845
846         if(iskaddr(a) && !hard) {
847                 b = (uchar*)a;
848                 allocd = 0;
849         }else{
850                 while((b = sdmalloc(nb*unit->secsize)) == nil){
851                         if(!waserror()){
852                                 resrcwait("no memory for sdbio");
853                                 poperror();
854                         }
855                 }
856                 allocd = 1;
857         }
858         if(waserror()){
859                 if(allocd)
860                         sdfree(b);
861                 if(!locked)
862                         decref(&sdev->r);               /* gadverdamme! */
863                 nexterror();
864         }
865
866         if(write){
867                 if(hard){
868                         l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno);
869                         if(l < 0)
870                                 error(Eio);
871                         if(l < (nb*unit->secsize)){
872                                 nb = l/unit->secsize;
873                                 l = nb*unit->secsize - offset;
874                                 if(len > l)
875                                         len = l;
876                         }
877                 }
878                 if(allocd)
879                         memmove(b+offset, a, len);
880                 l = unit->dev->ifc->bio(unit, 0, 1, b, nb, bno);
881                 if(l < 0)
882                         error(Eio);
883                 if(l < offset)
884                         len = 0;
885                 else if(len > l - offset)
886                         len = l - offset;
887         }
888         else{
889                 l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno);
890                 if(l < 0)
891                         error(Eio);
892                 if(l < offset)
893                         len = 0;
894                 else if(len > l - offset)
895                         len = l - offset;
896                 if(allocd)
897                         memmove(a, b+offset, len);
898         }
899         if(allocd)
900                 sdfree(b);
901         poperror();
902
903         if(locked){
904                 qunlock(&unit->ctl);
905                 poperror();
906         }
907
908         decref(&sdev->r);
909         return len;
910 }
911
912 static long
913 sdrio(SDreq* r, void* a, long n)
914 {
915         char *errstr;
916         int rv;
917         void *data;
918         SDunit *u;
919         int (*f)(SDreq*);
920
921         if(n >= SDmaxio || n < 0)
922                 error(Etoobig);
923         u = r->unit;
924         if(u->haversense && r->cmd[0] == 0x03){
925                 u->haversense = 0;
926                 r->rlen = sizeof u->rsense;
927                 if(r->rlen > n)
928                         r->rlen = n;
929                 memmove(a, u->rsense, r->rlen);
930                 r->status = SDok;
931                 return r->rlen;
932         }
933
934         data = nil;
935         while(n > 0 && (data = sdmalloc(n)) == nil){
936                 if(!waserror()){
937                         resrcwait("no memory for sdrio");
938                         poperror();
939                 }
940         }
941         if(waserror()){
942                 sdfree(data);
943                 r->data = nil;
944                 nexterror();
945         }
946         if(r->write && n > 0)
947                 memmove(data, a, n);
948         r->data = data;
949         r->dlen = n;
950
951         if(r->proto == SData){
952                 f = u->dev->ifc->ataio;
953                 errstr = Enoata;
954         }else{
955                 f = u->dev->ifc->rio;
956                 errstr = Enoscsi;
957         }
958         if(f == nil)
959                 error(errstr);
960         rv = f(r);
961         if(r->flags & SDvalidsense){
962                 memmove(u->rsense, r->sense, sizeof u->rsense);
963                 u->haversense = 1;
964         }
965         if(rv != SDok)
966                 error(Eio);
967
968         if(!r->write && r->rlen > 0)
969                 memmove(a, data, r->rlen);
970         poperror();
971         sdfree(data);
972         r->data = nil;
973
974         return r->rlen;
975 }
976
977 /*
978  * SCSI simulation for non-SCSI devices
979  *
980  * see /sys/src/cmd/scuzz/sense.c for information on key.
981  * see /sys/lib/scsicodes for asc:ascq codes
982  */
983 int
984 sdsetsense(SDreq *r, int status, int key, int asc, int ascq)
985 {
986         int len;
987         SDunit *unit;
988
989         unit = r->unit;
990         unit->sense[0] = 0x80 | 0x70;   /* valid; fixed-format */
991         unit->sense[2] = key;
992         unit->sense[12] = asc;
993         unit->sense[13] = ascq;
994
995         r->status = status;
996         if(status == SDcheck && !(r->flags & SDnosense)){
997                 /* request sense case from sdfakescsi */
998                 len = sizeof unit->sense;
999                 if(len > sizeof r->sense-1)
1000                         len = sizeof r->sense-1;
1001                 memmove(r->sense, unit->sense, len);
1002                 unit->sense[2] = 0;
1003                 unit->sense[12] = 0;
1004                 unit->sense[13] = 0;
1005                 r->flags |= SDvalidsense;
1006                 return SDok;
1007         }
1008         return status;
1009 }
1010
1011 int
1012 sdfakescsi(SDreq *r)
1013 {
1014         uchar *cmd, *p;
1015         uvlong len;
1016         SDunit *unit;
1017
1018         cmd = r->cmd;
1019         r->rlen = 0;
1020         unit = r->unit;
1021
1022         /*
1023          * Map SCSI commands into ATA commands for discs.
1024          * Fail any command with a LUN except INQUIRY which
1025          * will return 'logical unit not supported'.
1026          */
1027         if((cmd[1]>>5) && cmd[0] != 0x12)
1028                 return sdsetsense(r, SDcheck, 0x05, 0x25, 0);
1029
1030         switch(cmd[0]){
1031         default:
1032                 return sdsetsense(r, SDcheck, 0x05, 0x20, 0);
1033
1034         case 0x00:      /* test unit ready */
1035                 return sdsetsense(r, SDok, 0, 0, 0);
1036
1037         case 0x03:      /* request sense */
1038                 if(cmd[4] < sizeof unit->sense)
1039                         len = cmd[4];
1040                 else
1041                         len = sizeof unit->sense;
1042                 if(r->data && r->dlen >= len){
1043                         memmove(r->data, unit->sense, len);
1044                         r->rlen = len;
1045                 }
1046                 return sdsetsense(r, SDok, 0, 0, 0);
1047
1048         case 0x12:      /* inquiry */
1049                 if(cmd[4] < sizeof unit->inquiry)
1050                         len = cmd[4];
1051                 else
1052                         len = sizeof unit->inquiry;
1053                 if(r->data && r->dlen >= len){
1054                         memmove(r->data, unit->inquiry, len);
1055                         r->rlen = len;
1056                 }
1057                 return sdsetsense(r, SDok, 0, 0, 0);
1058
1059         case 0x1B:      /* start/stop unit */
1060                 /*
1061                  * nop for now, can use power management later.
1062                  */
1063                 return sdsetsense(r, SDok, 0, 0, 0);
1064
1065         case 0x25:      /* read capacity */
1066                 if((cmd[1] & 0x01) || cmd[2] || cmd[3])
1067                         return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
1068                 if(r->data == nil || r->dlen < 8)
1069                         return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
1070
1071                 /*
1072                  * Read capacity returns the LBA of the last sector.
1073                  */
1074                 len = unit->sectors;
1075                 if(len > 0)
1076                         len--;
1077                 p = r->data;
1078                 *p++ = len>>24;
1079                 *p++ = len>>16;
1080                 *p++ = len>>8;
1081                 *p++ = len;
1082                 len = unit->secsize;
1083                 *p++ = len>>24;
1084                 *p++ = len>>16;
1085                 *p++ = len>>8;
1086                 *p++ = len;
1087                 r->rlen = p - (uchar*)r->data;
1088                 return sdsetsense(r, SDok, 0, 0, 0);
1089
1090         case 0x9E:      /* long read capacity */
1091                 if((cmd[1] & 0x01) || cmd[2] || cmd[3])
1092                         return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
1093                 if(r->data == nil || r->dlen < 8)
1094                         return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
1095                 /*
1096                  * Read capcity returns the LBA of the last sector.
1097                  */
1098                 len = unit->sectors;
1099                 if(len > 0)
1100                         len--;
1101                 p = r->data;
1102                 *p++ = len>>56;
1103                 *p++ = len>>48;
1104                 *p++ = len>>40;
1105                 *p++ = len>>32;
1106                 *p++ = len>>24;
1107                 *p++ = len>>16;
1108                 *p++ = len>>8;
1109                 *p++ = len;
1110                 len = unit->secsize;
1111                 *p++ = len>>24;
1112                 *p++ = len>>16;
1113                 *p++ = len>>8;
1114                 *p++ = len;
1115                 r->rlen = p - (uchar*)r->data;
1116                 return sdsetsense(r, SDok, 0, 0, 0);
1117         case 0x08:      /* read6 */
1118         case 0x0a:      /* write6 */
1119         case 0x28:      /* read10 */
1120         case 0x2a:      /* write10 */
1121         case 0xa8:      /* read12 */
1122         case 0xaa:      /* write12 */
1123         case 0x88:      /* read16 */
1124         case 0x8a:      /* write16 */
1125                 return SDnostatus;
1126         }
1127 }
1128
1129 int
1130 sdfakescsirw(SDreq *r, uvlong *llba, int *nsec, int *rwp)
1131 {
1132         uchar *c;
1133         int rw, count;
1134         uvlong lba;
1135
1136         c = r->cmd;
1137         rw = SDread;
1138         if((c[0] & 0xf) == 0xa)
1139                 rw = SDwrite;
1140         switch(c[0]){
1141         case 0x08:      /* read6 */
1142         case 0x0a:
1143                 lba = (c[1] & 0xf)<<16 | c[2]<<8 | c[3];
1144                 count = c[4];
1145                 break;
1146         case 0x28:      /* read10 */
1147         case 0x2a:
1148                 lba = c[2]<<24 | c[3]<<16 | c[4]<<8 | c[5];
1149                 count = c[7]<<8 | c[8];
1150                 break;
1151         case 0xa8:      /* read12 */
1152         case 0xaa:
1153                 lba = c[2]<<24 | c[3]<<16 | c[4]<<8 | c[5];
1154                 count = c[6]<<24 | c[7]<<16 | c[8]<<8 | c[9];
1155                 break;
1156         case 0x88:      /* read16 */
1157         case 0x8a:
1158                 /* ata commands only go to 48-bit lba */
1159                 if(c[2] || c[3])
1160                         return sdsetsense(r, SDcheck, 3, 0xc, 2);
1161                 lba = (uvlong)c[4]<<40 | (uvlong)c[5]<<32;
1162                 lba |= c[6]<<24 | c[7]<<16 | c[8]<<8 | c[9];
1163                 count = c[10]<<24 | c[11]<<16 | c[12]<<8 | c[13];
1164                 break;
1165         default:
1166                 print("%s: bad cmd 0x%.2ux\n", r->unit->name, c[0]);
1167                 r->status  = sdsetsense(r, SDcheck, 0x05, 0x20, 0);
1168                 return SDcheck;
1169         }
1170         if(r->data == nil)
1171                 return SDok;
1172         if(r->dlen < count * r->unit->secsize)
1173                 count = r->dlen/r->unit->secsize;
1174         if(rwp)
1175                 *rwp = rw;
1176         *llba = lba;
1177         *nsec = count;
1178         return SDnostatus;
1179 }
1180
1181 static long
1182 extrarw(int write, Chan *c, void *a, long n, vlong off)
1183 {
1184         int i;
1185         SDrw *f;
1186         SDev *sdev;
1187         SDunit *unit;
1188
1189         sdev = sdgetdev(DEV(c->qid));
1190         if(sdev == nil)
1191                 error(Enonexist);
1192         if(waserror()){
1193                 decref(&sdev->r);
1194                 nexterror();
1195         }
1196         unit = sdev->unit[UNIT(c->qid)];
1197         if(unit->vers != c->qid.vers)
1198                 error(Echange);
1199         unit = sdev->unit[UNIT(c->qid)];
1200         i = PART(c->qid);
1201         if(i >= unit->nefile)
1202                 error(Enonexist);
1203         f = unit->efile[i].r;
1204         if(write)
1205                 f = unit->efile[i].w;
1206         if(i >= unit->nefile || f == nil)
1207                 error(Eperm);
1208         n = f(unit, c, a, n, off);
1209         poperror();
1210         decref(&sdev->r);
1211         return n;
1212 }
1213
1214 static char*
1215 deftopctl(SDev *s, char *p, char *e)
1216 {
1217         return seprint(p, e, "sd%c %s %d units\n", s->idno, s->ifc->name, s->nunit);
1218 }
1219
1220 static long
1221 sdread(Chan *c, void *a, long n, vlong off)
1222 {
1223         char *p, *e, *buf;
1224         SDev *sdev;
1225         SDpart *pp;
1226         SDreq *r;
1227         SDunit *unit;
1228         ulong offset;
1229         int i, l, m, status;
1230
1231         offset = off;
1232         switch(TYPE(c->qid)){
1233         default:
1234                 error(Eperm);
1235         case Qtopctl:
1236                 m = 64*1024;    /* room for register dumps */
1237                 p = buf = smalloc(m);
1238                 e = p + m;
1239                 qlock(&devslock);
1240                 for(i = 0; i < nelem(devs); i++){
1241                         sdev = devs[i];
1242                         if(sdev && sdev->ifc->rtopctl)
1243                                 p = sdev->ifc->rtopctl(sdev, p, e);
1244                         else if(sdev)
1245                                 p = deftopctl(sdev, p, e);
1246                 }
1247                 qunlock(&devslock);
1248                 n = readstr(off, a, n, buf);
1249                 free(buf);
1250                 return n;
1251
1252         case Qtopdir:
1253         case Qunitdir:
1254                 return devdirread(c, a, n, 0, 0, sdgen);
1255
1256         case Qctl:
1257                 sdev = sdgetdev(DEV(c->qid));
1258                 if(sdev == nil)
1259                         error(Enonexist);
1260
1261                 unit = sdev->unit[UNIT(c->qid)];
1262                 m = 16*1024;    /* room for register dumps */
1263                 p = smalloc(m);
1264                 l = snprint(p, m, "inquiry %.48s\n",
1265                         (char*)unit->inquiry+8);
1266                 qlock(&unit->ctl);
1267                 /*
1268                  * If there's a device specific routine it must
1269                  * provide all information pertaining to night geometry
1270                  * and the garscadden trains.
1271                  */
1272                 if(unit->dev->ifc->rctl)
1273                         l += unit->dev->ifc->rctl(unit, p+l, m-l);
1274                 if(unit->sectors == 0)
1275                         sdinitpart(unit);
1276                 if(unit->sectors){
1277                         if(unit->dev->ifc->rctl == nil)
1278                                 l += snprint(p+l, m-l,
1279                                         "geometry %llud %lud\n",
1280                                         unit->sectors, unit->secsize);
1281                         pp = unit->part;
1282                         for(i = 0; i < unit->npart; i++){
1283                                 if(pp->valid)
1284                                         l += snprint(p+l, m-l,
1285                                                 "part %s %llud %llud\n",
1286                                                 pp->name, pp->start, pp->end);
1287                                 pp++;
1288                         }
1289                 }
1290                 qunlock(&unit->ctl);
1291                 decref(&sdev->r);
1292                 l = readstr(offset, a, n, p);
1293                 free(p);
1294                 return l;
1295
1296         case Qraw:
1297                 sdev = sdgetdev(DEV(c->qid));
1298                 if(sdev == nil)
1299                         error(Enonexist);
1300
1301                 unit = sdev->unit[UNIT(c->qid)];
1302                 qlock(&unit->raw);
1303                 if(waserror()){
1304                         qunlock(&unit->raw);
1305                         decref(&sdev->r);
1306                         nexterror();
1307                 }
1308                 if(unit->state == Rawdata){
1309                         unit->state = Rawstatus;
1310                         r = unit->req;
1311                         r->timeout = 0;
1312                         i = sdrio(r, a, n);
1313                 }
1314                 else if(unit->state == Rawstatus){
1315                         r = unit->req;
1316                         unit->req = nil;
1317                         unit->state = Rawcmd;
1318                         status = r->status;
1319                         if(r->proto == SData){
1320                                 p = a;
1321                                 i = 16 + Ahdrsz;
1322                                 if(n < i)
1323                                         i = n;
1324                                 if(i > 0)
1325                                         p[0] = status;
1326                                 if(i > Ahdrsz)
1327                                         memmove(p + Ahdrsz, r->cmd, i - Ahdrsz);
1328                         }else
1329                                 i = readnum(0, a, n, status, NUMSIZE);
1330                         free(r);
1331                 } else
1332                         i = 0;
1333                 poperror();
1334                 qunlock(&unit->raw);
1335                 decref(&sdev->r);
1336                 return i;
1337
1338         case Qpart:
1339                 return sdbio(c, 0, a, n, off);
1340         case Qextra:
1341                 return extrarw(0, c, a, n, off);
1342         }
1343 }
1344
1345 static void legacytopctl(Cmdbuf*);
1346
1347 static long
1348 sdwrite(Chan* c, void* a, long n, vlong off)
1349 {
1350         char *f0;
1351         int i, atacdb, proto, ataproto;
1352         uchar *u;
1353         uvlong end, start;
1354         Cmdbuf *cb;
1355         SDifc *ifc;
1356         SDreq *req;
1357         SDunit *unit;
1358         SDev *sdev;
1359
1360         switch(TYPE(c->qid)){
1361         default:
1362                 error(Eperm);
1363         case Qtopctl:
1364                 cb = parsecmd(a, n);
1365                 if(waserror()){
1366                         free(cb);
1367                         nexterror();
1368                 }
1369                 if(cb->nf == 0)
1370                         error("empty control message");
1371                 f0 = cb->f[0];
1372                 cb->f++;
1373                 cb->nf--;
1374                 if(strcmp(f0, "config") == 0){
1375                         /* wormhole into ugly legacy interface */
1376                         legacytopctl(cb);
1377                         poperror();
1378                         free(cb);
1379                         break;
1380                 }
1381                 /*
1382                  * "ata arg..." invokes sdifc[i]->wtopctl(nil, cb),
1383                  * where sdifc[i]->name=="ata" and cb contains the args.
1384                  */
1385                 ifc = nil;
1386                 sdev = nil;
1387                 for(i=0; sdifc[i]; i++){
1388                         if(strcmp(sdifc[i]->name, f0) == 0){
1389                                 ifc = sdifc[i];
1390                                 sdev = nil;
1391                                 goto subtopctl;
1392                         }
1393                 }
1394                 /*
1395                  * "sd1 arg..." invokes sdifc[i]->wtopctl(sdev, cb),
1396                  * where sdifc[i] and sdev match controller letter "1",
1397                  * and cb contains the args.
1398                  */
1399                 if(f0[0]=='s' && f0[1]=='d' && f0[2] && f0[3] == 0){
1400                         if((sdev = sdgetdev(f0[2])) != nil){
1401                                 ifc = sdev->ifc;
1402                                 goto subtopctl;
1403                         }
1404                 }
1405                 error("unknown interface");
1406
1407         subtopctl:
1408                 if(waserror()){
1409                         if(sdev)
1410                                 decref(&sdev->r);
1411                         nexterror();
1412                 }
1413                 if(ifc->wtopctl)
1414                         ifc->wtopctl(sdev, cb);
1415                 else
1416                         error(Ebadctl);
1417                 poperror();
1418                 poperror();
1419                 if(sdev)
1420                         decref(&sdev->r);
1421                 free(cb);
1422                 break;
1423
1424         case Qctl:
1425                 cb = parsecmd(a, n);
1426                 sdev = sdgetdev(DEV(c->qid));
1427                 if(sdev == nil)
1428                         error(Enonexist);
1429                 unit = sdev->unit[UNIT(c->qid)];
1430
1431                 qlock(&unit->ctl);
1432                 if(waserror()){
1433                         qunlock(&unit->ctl);
1434                         decref(&sdev->r);
1435                         free(cb);
1436                         nexterror();
1437                 }
1438                 if(unit->vers != c->qid.vers)
1439                         error(Echange);
1440
1441                 if(cb->nf < 1)
1442                         error(Ebadctl);
1443                 if(strcmp(cb->f[0], "part") == 0){
1444                         if(cb->nf != 4)
1445                                 error(Ebadctl);
1446                         if(unit->sectors == 0 && !sdinitpart(unit))
1447                                 error(Eio);
1448                         start = strtoull(cb->f[2], 0, 0);
1449                         end = strtoull(cb->f[3], 0, 0);
1450                         sdaddpart(unit, cb->f[1], start, end);
1451                 }
1452                 else if(strcmp(cb->f[0], "delpart") == 0){
1453                         if(cb->nf != 2 || unit->part == nil)
1454                                 error(Ebadctl);
1455                         sddelpart(unit, cb->f[1]);
1456                 }
1457                 else if(unit->dev->ifc->wctl)
1458                         unit->dev->ifc->wctl(unit, cb);
1459                 else
1460                         error(Ebadctl);
1461                 qunlock(&unit->ctl);
1462                 decref(&sdev->r);
1463                 poperror();
1464                 free(cb);
1465                 break;
1466
1467         case Qraw:
1468                 proto = SDcdb;
1469                 ataproto = 0;
1470                 atacdb = 0;
1471                 sdev = sdgetdev(DEV(c->qid));
1472                 if(sdev == nil)
1473                         error(Enonexist);
1474                 unit = sdev->unit[UNIT(c->qid)];
1475                 qlock(&unit->raw);
1476                 if(waserror()){
1477                         qunlock(&unit->raw);
1478                         decref(&sdev->r);
1479                         nexterror();
1480                 }
1481                 switch(unit->state){
1482                 case Rawcmd:
1483                         /* sneaky ata commands */
1484                         u = a;
1485                         if(n > 1 && *u == 0xff){
1486                                 proto = SData;
1487                                 ataproto = u[1];
1488                                 a = u + 2;
1489                                 atacdb = Ahdrsz;
1490                                 n -= Ahdrsz;
1491                         }               
1492                         if(n < 6 || n > sizeof(req->cmd))
1493                                 error(Ebadarg);
1494                         req = smalloc(sizeof(SDreq));
1495                         req->unit = unit;
1496                         if(waserror()){
1497                                 free(req);
1498                                 nexterror();
1499                         }
1500                         memmove(req->cmd, a, n);
1501                         poperror();
1502                         req->clen = n;
1503                 /*      req->flags = SDnosense; */
1504                         req->status = ~0;
1505                         req->proto = proto;
1506                         req->ataproto = ataproto;
1507                         unit->req = req;
1508                         unit->state = Rawdata;
1509                         n += atacdb;
1510                         break;
1511
1512                 case Rawstatus:
1513                         unit->state = Rawcmd;
1514                         free(unit->req);
1515                         unit->req = nil;
1516                         error(Ebadusefd);
1517
1518                 case Rawdata:
1519                         unit->state = Rawstatus;
1520                         req = unit->req;
1521                         req->write = 1;
1522                         n = sdrio(req, a, n);
1523                 }
1524                 poperror();
1525                 qunlock(&unit->raw);
1526                 decref(&sdev->r);
1527                 break;
1528         case Qpart:
1529                 return sdbio(c, 1, a, n, off);
1530         case Qextra:
1531                 return extrarw(1, c, a, n, off);
1532         }
1533
1534         return n;
1535 }
1536
1537 static int
1538 sdwstat(Chan* c, uchar* dp, int n)
1539 {
1540         Dir *d;
1541         SDpart *pp;
1542         SDperm *perm;
1543         SDunit *unit;
1544         SDev *sdev;
1545
1546         if(c->qid.type & QTDIR)
1547                 error(Eperm);
1548         if(TYPE(c->qid) == Qtopctl){
1549                 unit = &topctlunit;
1550                 sdev = nil;
1551         }else{
1552                 sdev = sdgetdev(DEV(c->qid));
1553                 if(sdev == nil)
1554                         error(Enonexist);
1555                 unit = sdev->unit[UNIT(c->qid)];
1556         }
1557         qlock(&unit->ctl);
1558
1559         d = nil;
1560         if(waserror()){
1561                 qunlock(&unit->ctl);
1562                 if(sdev != nil)
1563                         decref(&sdev->r);
1564                 free(d);
1565                 nexterror();
1566         }
1567
1568         switch(TYPE(c->qid)){
1569         default:
1570                 error(Eperm);
1571         case Qtopctl:
1572         case Qctl:
1573                 perm = &unit->ctlperm;
1574                 break;
1575         case Qraw:
1576                 perm = &unit->rawperm;
1577                 break;
1578         case Qpart:
1579                 pp = &unit->part[PART(c->qid)];
1580                 if(unit->vers+pp->vers != c->qid.vers)
1581                         error(Enonexist);
1582                 perm = &pp->SDperm;
1583                 break;
1584         }
1585
1586         if(strcmp(up->user, perm->user) && !iseve())
1587                 error(Eperm);
1588
1589         d = smalloc(sizeof(Dir)+n);
1590         n = convM2D(dp, n, &d[0], (char*)&d[1]);
1591         if(n == 0)
1592                 error(Eshortstat);
1593         if(d->atime != ~0 ||  d->mtime  != ~0 ||  d->length  != ~0)
1594                 error(Eperm);
1595         if(!emptystr(d[0].muid) || !emptystr(d[0].name))
1596                 error(Eperm);
1597         if(!emptystr(d[0].uid))
1598                 kstrdup(&perm->user, d[0].uid);
1599         if(!emptystr(d[0].gid) && strcmp(d[0].gid, eve) != 0)
1600                 error(Eperm);
1601         if(d[0].mode != ~0UL)
1602                 perm->perm = (perm->perm & ~0777) | (d[0].mode & 0777);
1603         poperror();
1604         qunlock(&unit->ctl);
1605         if(sdev != nil)
1606                 decref(&sdev->r);
1607         free(d);
1608         return n;
1609 }
1610
1611 static int
1612 configure(char* spec, DevConf* cf)
1613 {
1614         SDev *s, *sdev;
1615         char *p;
1616         int i;
1617
1618         if(sdindex(*spec) < 0)
1619                 error("bad sd spec");
1620
1621         if((p = strchr(cf->type, '/')) != nil)
1622                 *p++ = '\0';
1623
1624         for(i = 0; sdifc[i] != nil; i++)
1625                 if(strcmp(sdifc[i]->name, cf->type) == 0)
1626                         break;
1627         if(sdifc[i] == nil)
1628                 error("sd type not found");
1629         if(p)
1630                 *(p-1) = '/';
1631
1632         if(sdifc[i]->probe == nil)
1633                 error("sd type cannot probe");
1634
1635         sdev = sdifc[i]->probe(cf);
1636         for(s=sdev; s; s=s->next)
1637                 s->idno = *spec;
1638         sdadddevs(sdev);
1639         return 0;
1640 }
1641
1642 static int
1643 unconfigure(char* spec)
1644 {
1645         int i;
1646         SDev *sdev;
1647         SDunit *unit;
1648
1649         if((i = sdindex(*spec)) < 0)
1650                 error(Enonexist);
1651
1652         qlock(&devslock);
1653         if((sdev = devs[i]) == nil){
1654                 qunlock(&devslock);
1655                 error(Enonexist);
1656         }
1657         if(sdev->r.ref){
1658                 qunlock(&devslock);
1659                 error(Einuse);
1660         }
1661         devs[i] = nil;
1662         qunlock(&devslock);
1663
1664         /* make sure no interrupts arrive anymore before removing resources */
1665         if(sdev->enabled && sdev->ifc->disable)
1666                 sdev->ifc->disable(sdev);
1667
1668         for(i = 0; i != sdev->nunit; i++){
1669                 if(unit = sdev->unit[i]){
1670                         free(unit->name);
1671                         free(unit->user);
1672                         free(unit);
1673                 }
1674         }
1675
1676         if(sdev->ifc->clear)
1677                 sdev->ifc->clear(sdev);
1678         free(sdev);
1679         return 0;
1680 }
1681
1682 static int
1683 sdconfig(int on, char* spec, DevConf* cf)
1684 {
1685         if(on)
1686                 return configure(spec, cf);
1687         return unconfigure(spec);
1688 }
1689
1690 int
1691 sdaddfile(SDunit *unit, char *s, int perm, char *u, SDrw *r, SDrw *w)
1692 {
1693         int i;
1694         SDfile *e;
1695         static Lock lk;
1696
1697         if(unit == nil)
1698                 return -1;
1699         lock(&lk);
1700         for(i = 0; i < unit->nefile; i++)
1701                 if(strcmp(unit->efile[i].name, s) == 0)
1702                         break;
1703         if(i >= nelem(unit->efile)){
1704                 unlock(&lk);
1705                 return -1;
1706         }
1707         if(i >= unit->nefile)
1708                 unit->nefile = i + 1;
1709         e = unit->efile + i;
1710         if(e->name == nil)
1711                 kstrdup(&e->name, s);
1712         if(e->user == nil)
1713                  kstrdup(&e->user, u);
1714         e->perm = perm;
1715         e->r = r;
1716         e->w = w;
1717         unlock(&lk);
1718         return 0;
1719 }
1720
1721 static void
1722 sdshutdown(void)
1723 {
1724         int i;
1725         SDev *sd;
1726
1727         for(i = 0; i < nelem(devs); i++){
1728                 sd = devs[i];
1729                 if(sd == nil)
1730                         continue;
1731                 if(sd->ifc->disable == nil){
1732                         print("#S/sd%c: no disable function\n", devletters[i]);
1733                         continue;
1734                 }
1735                 sd->ifc->disable(sd);
1736         }
1737 }
1738
1739 Dev sddevtab = {
1740         'S',
1741         "sd",
1742
1743         sdreset,
1744         devinit,
1745         sdshutdown,
1746         sdattach,
1747         sdwalk,
1748         sdstat,
1749         sdopen,
1750         devcreate,
1751         sdclose,
1752         sdread,
1753         devbread,
1754         sdwrite,
1755         devbwrite,
1756         devremove,
1757         sdwstat,
1758         devpower,
1759         sdconfig,
1760 };
1761
1762 /*
1763  * This is wrong for so many reasons.  This code must go.
1764  */
1765 typedef struct Confdata Confdata;
1766 struct Confdata {
1767         int     on;
1768         char*   spec;
1769         DevConf cf;
1770 };
1771
1772 static void
1773 parseswitch(Confdata* cd, char* option)
1774 {
1775         if(!strcmp("on", option))
1776                 cd->on = 1;
1777         else if(!strcmp("off", option))
1778                 cd->on = 0;
1779         else
1780                 error(Ebadarg);
1781 }
1782
1783 static void
1784 parsespec(Confdata* cd, char* option)
1785 {
1786         if(strlen(option) > 1)
1787                 error(Ebadarg);
1788         cd->spec = option;
1789 }
1790
1791 static Devport*
1792 getnewport(DevConf* dc)
1793 {
1794         Devport *p;
1795
1796         p = malloc((dc->nports + 1) * sizeof(Devport));
1797         if(p == nil)
1798                 panic("sd: no memory for Devport");
1799         if(dc->nports > 0){
1800                 memmove(p, dc->ports, dc->nports * sizeof(Devport));
1801                 free(dc->ports);
1802         }
1803         dc->ports = p;
1804         p = &dc->ports[dc->nports++];
1805         p->size = -1;
1806         p->port = (ulong)-1;
1807         return p;
1808 }
1809
1810 static void
1811 parseport(Confdata* cd, char* option)
1812 {
1813         char *e;
1814         Devport *p;
1815
1816         if(cd->cf.nports == 0 || cd->cf.ports[cd->cf.nports-1].port != (ulong)-1)
1817                 p = getnewport(&cd->cf);
1818         else
1819                 p = &cd->cf.ports[cd->cf.nports-1];
1820         p->port = strtol(option, &e, 0);
1821         if(e == nil || *e != '\0')
1822                 error(Ebadarg);
1823 }
1824
1825 static void
1826 parsesize(Confdata* cd, char* option)
1827 {
1828         char *e;
1829         Devport *p;
1830
1831         if(cd->cf.nports == 0 || cd->cf.ports[cd->cf.nports-1].size != -1)
1832                 p = getnewport(&cd->cf);
1833         else
1834                 p = &cd->cf.ports[cd->cf.nports-1];
1835         p->size = (int)strtol(option, &e, 0);
1836         if(e == nil || *e != '\0')
1837                 error(Ebadarg);
1838 }
1839
1840 static void
1841 parseirq(Confdata* cd, char* option)
1842 {
1843         char *e;
1844
1845         cd->cf.intnum = strtoul(option, &e, 0);
1846         if(e == nil || *e != '\0')
1847                 error(Ebadarg);
1848 }
1849
1850 static void
1851 parsetype(Confdata* cd, char* option)
1852 {
1853         cd->cf.type = option;
1854 }
1855
1856 static struct {
1857         char    *name;
1858         void    (*parse)(Confdata*, char*);
1859 } options[] = {
1860         "switch",       parseswitch,
1861         "spec",         parsespec,
1862         "port",         parseport,
1863         "size",         parsesize,
1864         "irq",          parseirq,
1865         "type",         parsetype,
1866 };
1867
1868 static void
1869 legacytopctl(Cmdbuf *cb)
1870 {
1871         char *opt;
1872         int i, j;
1873         Confdata cd;
1874
1875         memset(&cd, 0, sizeof cd);
1876         cd.on = -1;
1877         for(i=0; i<cb->nf; i+=2){
1878                 if(i+2 > cb->nf)
1879                         error(Ebadarg);
1880                 opt = cb->f[i];
1881                 for(j=0; j<nelem(options); j++)
1882                         if(strcmp(opt, options[j].name) == 0){
1883                                 options[j].parse(&cd, cb->f[i+1]);
1884                                 break;
1885                         }
1886                 if(j == nelem(options))
1887                         error(Ebadarg);
1888         }
1889         if(cd.on < 0 || cd.spec == 0)
1890                 error(Ebadarg);
1891         if(cd.on && cd.cf.type == nil)
1892                 error(Ebadarg);
1893         sdconfig(cd.on, cd.spec, &cd.cf);
1894 }