]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/port/devsd.c
fix fuckup
[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) && ((uintptr)a & (BY2PG-1))==0 && !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 >= 0xffffffff)
1076                         len = 0xffffffff;
1077                 else if(len > 0)
1078                         len--;
1079                 p = r->data;
1080                 *p++ = len>>24;
1081                 *p++ = len>>16;
1082                 *p++ = len>>8;
1083                 *p++ = len;
1084                 len = unit->secsize;
1085                 *p++ = len>>24;
1086                 *p++ = len>>16;
1087                 *p++ = len>>8;
1088                 *p++ = len;
1089                 r->rlen = p - (uchar*)r->data;
1090                 return sdsetsense(r, SDok, 0, 0, 0);
1091
1092         case 0x9E:      /* long read capacity */
1093                 if((cmd[1] & 0x01) || cmd[2] || cmd[3])
1094                         return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
1095                 if(r->data == nil || r->dlen < 8)
1096                         return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
1097                 /*
1098                  * Read capcity returns the LBA of the last sector.
1099                  */
1100                 len = unit->sectors;
1101                 if(len > 0)
1102                         len--;
1103                 p = r->data;
1104                 *p++ = len>>56;
1105                 *p++ = len>>48;
1106                 *p++ = len>>40;
1107                 *p++ = len>>32;
1108                 *p++ = len>>24;
1109                 *p++ = len>>16;
1110                 *p++ = len>>8;
1111                 *p++ = len;
1112                 len = unit->secsize;
1113                 *p++ = len>>24;
1114                 *p++ = len>>16;
1115                 *p++ = len>>8;
1116                 *p++ = len;
1117                 r->rlen = p - (uchar*)r->data;
1118                 return sdsetsense(r, SDok, 0, 0, 0);
1119         case 0x08:      /* read6 */
1120         case 0x0a:      /* write6 */
1121         case 0x28:      /* read10 */
1122         case 0x2a:      /* write10 */
1123         case 0xa8:      /* read12 */
1124         case 0xaa:      /* write12 */
1125         case 0x88:      /* read16 */
1126         case 0x8a:      /* write16 */
1127                 return SDnostatus;
1128         }
1129 }
1130
1131 int
1132 sdfakescsirw(SDreq *r, uvlong *llba, int *nsec, int *rwp)
1133 {
1134         uchar *c;
1135         int rw, count;
1136         uvlong lba;
1137
1138         c = r->cmd;
1139         rw = SDread;
1140         if((c[0] & 0xf) == 0xa)
1141                 rw = SDwrite;
1142         switch(c[0]){
1143         case 0x08:      /* read6 */
1144         case 0x0a:
1145                 lba = (c[1] & 0xf)<<16 | c[2]<<8 | c[3];
1146                 count = c[4];
1147                 break;
1148         case 0x28:      /* read10 */
1149         case 0x2a:
1150                 lba = c[2]<<24 | c[3]<<16 | c[4]<<8 | c[5];
1151                 count = c[7]<<8 | c[8];
1152                 break;
1153         case 0xa8:      /* read12 */
1154         case 0xaa:
1155                 lba = c[2]<<24 | c[3]<<16 | c[4]<<8 | c[5];
1156                 count = c[6]<<24 | c[7]<<16 | c[8]<<8 | c[9];
1157                 break;
1158         case 0x88:      /* read16 */
1159         case 0x8a:
1160                 /* ata commands only go to 48-bit lba */
1161                 if(c[2] || c[3])
1162                         return sdsetsense(r, SDcheck, 3, 0xc, 2);
1163                 lba = (uvlong)c[4]<<40 | (uvlong)c[5]<<32;
1164                 lba |= c[6]<<24 | c[7]<<16 | c[8]<<8 | c[9];
1165                 count = c[10]<<24 | c[11]<<16 | c[12]<<8 | c[13];
1166                 break;
1167         default:
1168                 print("%s: bad cmd 0x%.2ux\n", r->unit->name, c[0]);
1169                 r->status  = sdsetsense(r, SDcheck, 0x05, 0x20, 0);
1170                 return SDcheck;
1171         }
1172         if(r->data == nil)
1173                 return SDok;
1174         if(r->dlen < count * r->unit->secsize)
1175                 count = r->dlen/r->unit->secsize;
1176         if(rwp)
1177                 *rwp = rw;
1178         *llba = lba;
1179         *nsec = count;
1180         return SDnostatus;
1181 }
1182
1183 static long
1184 extrarw(int write, Chan *c, void *a, long n, vlong off)
1185 {
1186         int i;
1187         SDrw *f;
1188         SDev *sdev;
1189         SDunit *unit;
1190
1191         sdev = sdgetdev(DEV(c->qid));
1192         if(sdev == nil)
1193                 error(Enonexist);
1194         if(waserror()){
1195                 decref(&sdev->r);
1196                 nexterror();
1197         }
1198         unit = sdev->unit[UNIT(c->qid)];
1199         if(unit->vers != c->qid.vers)
1200                 error(Echange);
1201         unit = sdev->unit[UNIT(c->qid)];
1202         i = PART(c->qid);
1203         if(i >= unit->nefile)
1204                 error(Enonexist);
1205         f = unit->efile[i].r;
1206         if(write)
1207                 f = unit->efile[i].w;
1208         if(i >= unit->nefile || f == nil)
1209                 error(Eperm);
1210         n = f(unit, c, a, n, off);
1211         poperror();
1212         decref(&sdev->r);
1213         return n;
1214 }
1215
1216 static char*
1217 deftopctl(SDev *s, char *p, char *e)
1218 {
1219         return seprint(p, e, "sd%c %s %d units\n", s->idno, s->ifc->name, s->nunit);
1220 }
1221
1222 static long
1223 sdread(Chan *c, void *a, long n, vlong off)
1224 {
1225         char *p, *e, *buf;
1226         SDev *sdev;
1227         SDpart *pp;
1228         SDreq *r;
1229         SDunit *unit;
1230         ulong offset;
1231         int i, l, m, status;
1232
1233         offset = off;
1234         switch(TYPE(c->qid)){
1235         default:
1236                 error(Eperm);
1237         case Qtopctl:
1238                 m = 64*1024;    /* room for register dumps */
1239                 p = buf = smalloc(m);
1240                 e = p + m;
1241                 qlock(&devslock);
1242                 for(i = 0; i < nelem(devs); i++){
1243                         sdev = devs[i];
1244                         if(sdev && sdev->ifc->rtopctl)
1245                                 p = sdev->ifc->rtopctl(sdev, p, e);
1246                         else if(sdev)
1247                                 p = deftopctl(sdev, p, e);
1248                 }
1249                 qunlock(&devslock);
1250                 n = readstr(off, a, n, buf);
1251                 free(buf);
1252                 return n;
1253
1254         case Qtopdir:
1255         case Qunitdir:
1256                 return devdirread(c, a, n, 0, 0, sdgen);
1257
1258         case Qctl:
1259                 sdev = sdgetdev(DEV(c->qid));
1260                 if(sdev == nil)
1261                         error(Enonexist);
1262
1263                 unit = sdev->unit[UNIT(c->qid)];
1264                 m = 16*1024;    /* room for register dumps */
1265                 p = smalloc(m);
1266                 l = snprint(p, m, "inquiry %.48s\n",
1267                         (char*)unit->inquiry+8);
1268                 qlock(&unit->ctl);
1269                 /*
1270                  * If there's a device specific routine it must
1271                  * provide all information pertaining to night geometry
1272                  * and the garscadden trains.
1273                  */
1274                 if(unit->dev->ifc->rctl)
1275                         l += unit->dev->ifc->rctl(unit, p+l, m-l);
1276                 if(unit->sectors == 0)
1277                         sdinitpart(unit);
1278                 if(unit->sectors){
1279                         if(unit->dev->ifc->rctl == nil)
1280                                 l += snprint(p+l, m-l,
1281                                         "geometry %llud %lud\n",
1282                                         unit->sectors, unit->secsize);
1283                         pp = unit->part;
1284                         for(i = 0; i < unit->npart; i++){
1285                                 if(pp->valid)
1286                                         l += snprint(p+l, m-l,
1287                                                 "part %s %llud %llud\n",
1288                                                 pp->name, pp->start, pp->end);
1289                                 pp++;
1290                         }
1291                 }
1292                 qunlock(&unit->ctl);
1293                 decref(&sdev->r);
1294                 l = readstr(offset, a, n, p);
1295                 free(p);
1296                 return l;
1297
1298         case Qraw:
1299                 sdev = sdgetdev(DEV(c->qid));
1300                 if(sdev == nil)
1301                         error(Enonexist);
1302
1303                 unit = sdev->unit[UNIT(c->qid)];
1304                 qlock(&unit->raw);
1305                 if(waserror()){
1306                         qunlock(&unit->raw);
1307                         decref(&sdev->r);
1308                         nexterror();
1309                 }
1310                 if(unit->state == Rawdata){
1311                         unit->state = Rawstatus;
1312                         r = unit->req;
1313                         r->timeout = 0;
1314                         i = sdrio(r, a, n);
1315                 }
1316                 else if(unit->state == Rawstatus){
1317                         r = unit->req;
1318                         unit->req = nil;
1319                         unit->state = Rawcmd;
1320                         status = r->status;
1321                         if(r->proto == SData){
1322                                 p = a;
1323                                 i = 16 + Ahdrsz;
1324                                 if(n < i)
1325                                         i = n;
1326                                 if(i > 0)
1327                                         p[0] = status;
1328                                 if(i > Ahdrsz)
1329                                         memmove(p + Ahdrsz, r->cmd, i - Ahdrsz);
1330                         }else
1331                                 i = readnum(0, a, n, status, NUMSIZE);
1332                         free(r);
1333                 } else
1334                         i = 0;
1335                 poperror();
1336                 qunlock(&unit->raw);
1337                 decref(&sdev->r);
1338                 return i;
1339
1340         case Qpart:
1341                 return sdbio(c, 0, a, n, off);
1342         case Qextra:
1343                 return extrarw(0, c, a, n, off);
1344         }
1345 }
1346
1347 static void legacytopctl(Cmdbuf*);
1348
1349 static long
1350 sdwrite(Chan* c, void* a, long n, vlong off)
1351 {
1352         char *f0;
1353         int i, atacdb, proto, ataproto;
1354         uchar *u;
1355         uvlong end, start;
1356         Cmdbuf *cb;
1357         SDifc *ifc;
1358         SDreq *req;
1359         SDunit *unit;
1360         SDev *sdev;
1361
1362         switch(TYPE(c->qid)){
1363         default:
1364                 error(Eperm);
1365         case Qtopctl:
1366                 cb = parsecmd(a, n);
1367                 if(waserror()){
1368                         free(cb);
1369                         nexterror();
1370                 }
1371                 if(cb->nf == 0)
1372                         error("empty control message");
1373                 f0 = cb->f[0];
1374                 cb->f++;
1375                 cb->nf--;
1376                 if(strcmp(f0, "config") == 0){
1377                         /* wormhole into ugly legacy interface */
1378                         legacytopctl(cb);
1379                         poperror();
1380                         free(cb);
1381                         break;
1382                 }
1383                 /*
1384                  * "ata arg..." invokes sdifc[i]->wtopctl(nil, cb),
1385                  * where sdifc[i]->name=="ata" and cb contains the args.
1386                  */
1387                 ifc = nil;
1388                 sdev = nil;
1389                 for(i=0; sdifc[i]; i++){
1390                         if(strcmp(sdifc[i]->name, f0) == 0){
1391                                 ifc = sdifc[i];
1392                                 sdev = nil;
1393                                 goto subtopctl;
1394                         }
1395                 }
1396                 /*
1397                  * "sd1 arg..." invokes sdifc[i]->wtopctl(sdev, cb),
1398                  * where sdifc[i] and sdev match controller letter "1",
1399                  * and cb contains the args.
1400                  */
1401                 if(f0[0]=='s' && f0[1]=='d' && f0[2] && f0[3] == 0){
1402                         if((sdev = sdgetdev(f0[2])) != nil){
1403                                 ifc = sdev->ifc;
1404                                 goto subtopctl;
1405                         }
1406                 }
1407                 error("unknown interface");
1408
1409         subtopctl:
1410                 if(waserror()){
1411                         if(sdev)
1412                                 decref(&sdev->r);
1413                         nexterror();
1414                 }
1415                 if(ifc->wtopctl)
1416                         ifc->wtopctl(sdev, cb);
1417                 else
1418                         error(Ebadctl);
1419                 poperror();
1420                 poperror();
1421                 if(sdev)
1422                         decref(&sdev->r);
1423                 free(cb);
1424                 break;
1425
1426         case Qctl:
1427                 cb = parsecmd(a, n);
1428                 sdev = sdgetdev(DEV(c->qid));
1429                 if(sdev == nil)
1430                         error(Enonexist);
1431                 unit = sdev->unit[UNIT(c->qid)];
1432
1433                 qlock(&unit->ctl);
1434                 if(waserror()){
1435                         qunlock(&unit->ctl);
1436                         decref(&sdev->r);
1437                         free(cb);
1438                         nexterror();
1439                 }
1440                 if(unit->vers != c->qid.vers)
1441                         error(Echange);
1442
1443                 if(cb->nf < 1)
1444                         error(Ebadctl);
1445                 if(strcmp(cb->f[0], "part") == 0){
1446                         if(cb->nf != 4)
1447                                 error(Ebadctl);
1448                         if(unit->sectors == 0 && !sdinitpart(unit))
1449                                 error(Eio);
1450                         start = strtoull(cb->f[2], 0, 0);
1451                         end = strtoull(cb->f[3], 0, 0);
1452                         sdaddpart(unit, cb->f[1], start, end);
1453                 }
1454                 else if(strcmp(cb->f[0], "delpart") == 0){
1455                         if(cb->nf != 2 || unit->part == nil)
1456                                 error(Ebadctl);
1457                         sddelpart(unit, cb->f[1]);
1458                 }
1459                 else if(unit->dev->ifc->wctl)
1460                         unit->dev->ifc->wctl(unit, cb);
1461                 else
1462                         error(Ebadctl);
1463                 qunlock(&unit->ctl);
1464                 decref(&sdev->r);
1465                 poperror();
1466                 free(cb);
1467                 break;
1468
1469         case Qraw:
1470                 proto = SDcdb;
1471                 ataproto = 0;
1472                 atacdb = 0;
1473                 sdev = sdgetdev(DEV(c->qid));
1474                 if(sdev == nil)
1475                         error(Enonexist);
1476                 unit = sdev->unit[UNIT(c->qid)];
1477                 qlock(&unit->raw);
1478                 if(waserror()){
1479                         qunlock(&unit->raw);
1480                         decref(&sdev->r);
1481                         nexterror();
1482                 }
1483                 switch(unit->state){
1484                 case Rawcmd:
1485                         /* sneaky ata commands */
1486                         u = a;
1487                         if(n > 1 && *u == 0xff){
1488                                 proto = SData;
1489                                 ataproto = u[1];
1490                                 a = u + 2;
1491                                 atacdb = Ahdrsz;
1492                                 n -= Ahdrsz;
1493                         }               
1494                         if(n < 6 || n > sizeof(req->cmd))
1495                                 error(Ebadarg);
1496                         req = smalloc(sizeof(SDreq));
1497                         req->unit = unit;
1498                         if(waserror()){
1499                                 free(req);
1500                                 nexterror();
1501                         }
1502                         memmove(req->cmd, a, n);
1503                         poperror();
1504                         req->clen = n;
1505                 /*      req->flags = SDnosense; */
1506                         req->status = ~0;
1507                         req->proto = proto;
1508                         req->ataproto = ataproto;
1509                         unit->req = req;
1510                         unit->state = Rawdata;
1511                         n += atacdb;
1512                         break;
1513
1514                 case Rawstatus:
1515                         unit->state = Rawcmd;
1516                         free(unit->req);
1517                         unit->req = nil;
1518                         error(Ebadusefd);
1519
1520                 case Rawdata:
1521                         unit->state = Rawstatus;
1522                         req = unit->req;
1523                         req->write = 1;
1524                         n = sdrio(req, a, n);
1525                 }
1526                 poperror();
1527                 qunlock(&unit->raw);
1528                 decref(&sdev->r);
1529                 break;
1530         case Qpart:
1531                 return sdbio(c, 1, a, n, off);
1532         case Qextra:
1533                 return extrarw(1, c, a, n, off);
1534         }
1535
1536         return n;
1537 }
1538
1539 static int
1540 sdwstat(Chan* c, uchar* dp, int n)
1541 {
1542         Dir *d;
1543         SDpart *pp;
1544         SDperm *perm;
1545         SDunit *unit;
1546         SDev *sdev;
1547
1548         if(c->qid.type & QTDIR)
1549                 error(Eperm);
1550         if(TYPE(c->qid) == Qtopctl){
1551                 unit = &topctlunit;
1552                 sdev = nil;
1553         }else{
1554                 sdev = sdgetdev(DEV(c->qid));
1555                 if(sdev == nil)
1556                         error(Enonexist);
1557                 unit = sdev->unit[UNIT(c->qid)];
1558         }
1559         qlock(&unit->ctl);
1560
1561         d = nil;
1562         if(waserror()){
1563                 qunlock(&unit->ctl);
1564                 if(sdev != nil)
1565                         decref(&sdev->r);
1566                 free(d);
1567                 nexterror();
1568         }
1569
1570         switch(TYPE(c->qid)){
1571         default:
1572                 error(Eperm);
1573         case Qtopctl:
1574         case Qctl:
1575                 perm = &unit->ctlperm;
1576                 break;
1577         case Qraw:
1578                 perm = &unit->rawperm;
1579                 break;
1580         case Qpart:
1581                 pp = &unit->part[PART(c->qid)];
1582                 if(unit->vers+pp->vers != c->qid.vers)
1583                         error(Enonexist);
1584                 perm = &pp->SDperm;
1585                 break;
1586         }
1587
1588         if(strcmp(up->user, perm->user) && !iseve())
1589                 error(Eperm);
1590
1591         d = smalloc(sizeof(Dir)+n);
1592         n = convM2D(dp, n, &d[0], (char*)&d[1]);
1593         if(n == 0)
1594                 error(Eshortstat);
1595         if(d->atime != ~0 ||  d->mtime  != ~0 ||  d->length  != ~0)
1596                 error(Eperm);
1597         if(!emptystr(d[0].muid) || !emptystr(d[0].name))
1598                 error(Eperm);
1599         if(!emptystr(d[0].uid))
1600                 kstrdup(&perm->user, d[0].uid);
1601         if(!emptystr(d[0].gid) && strcmp(d[0].gid, eve) != 0)
1602                 error(Eperm);
1603         if(d[0].mode != ~0UL)
1604                 perm->perm = (perm->perm & ~0777) | (d[0].mode & 0777);
1605         poperror();
1606         qunlock(&unit->ctl);
1607         if(sdev != nil)
1608                 decref(&sdev->r);
1609         free(d);
1610         return n;
1611 }
1612
1613 static int
1614 configure(char* spec, DevConf* cf)
1615 {
1616         SDev *s, *sdev;
1617         char *p;
1618         int i;
1619
1620         if(sdindex(*spec) < 0)
1621                 error("bad sd spec");
1622
1623         if((p = strchr(cf->type, '/')) != nil)
1624                 *p++ = '\0';
1625
1626         for(i = 0; sdifc[i] != nil; i++)
1627                 if(strcmp(sdifc[i]->name, cf->type) == 0)
1628                         break;
1629         if(sdifc[i] == nil)
1630                 error("sd type not found");
1631         if(p)
1632                 *(p-1) = '/';
1633
1634         if(sdifc[i]->probe == nil)
1635                 error("sd type cannot probe");
1636
1637         sdev = sdifc[i]->probe(cf);
1638         for(s=sdev; s; s=s->next)
1639                 s->idno = *spec;
1640         sdadddevs(sdev);
1641         return 0;
1642 }
1643
1644 static int
1645 unconfigure(char* spec)
1646 {
1647         int i;
1648         SDev *sdev;
1649         SDunit *unit;
1650
1651         if((i = sdindex(*spec)) < 0)
1652                 error(Enonexist);
1653
1654         qlock(&devslock);
1655         if((sdev = devs[i]) == nil){
1656                 qunlock(&devslock);
1657                 error(Enonexist);
1658         }
1659         if(sdev->r.ref){
1660                 qunlock(&devslock);
1661                 error(Einuse);
1662         }
1663         devs[i] = nil;
1664         qunlock(&devslock);
1665
1666         /* make sure no interrupts arrive anymore before removing resources */
1667         if(sdev->enabled && sdev->ifc->disable)
1668                 sdev->ifc->disable(sdev);
1669
1670         for(i = 0; i != sdev->nunit; i++){
1671                 if(unit = sdev->unit[i]){
1672                         free(unit->name);
1673                         free(unit->user);
1674                         free(unit);
1675                 }
1676         }
1677
1678         if(sdev->ifc->clear)
1679                 sdev->ifc->clear(sdev);
1680         free(sdev);
1681         return 0;
1682 }
1683
1684 static int
1685 sdconfig(int on, char* spec, DevConf* cf)
1686 {
1687         if(on)
1688                 return configure(spec, cf);
1689         return unconfigure(spec);
1690 }
1691
1692 int
1693 sdaddfile(SDunit *unit, char *s, int perm, char *u, SDrw *r, SDrw *w)
1694 {
1695         int i;
1696         SDfile *e;
1697         static Lock lk;
1698
1699         if(unit == nil)
1700                 return -1;
1701         lock(&lk);
1702         for(i = 0; i < unit->nefile; i++)
1703                 if(strcmp(unit->efile[i].name, s) == 0)
1704                         break;
1705         if(i >= nelem(unit->efile)){
1706                 unlock(&lk);
1707                 return -1;
1708         }
1709         if(i >= unit->nefile)
1710                 unit->nefile = i + 1;
1711         e = unit->efile + i;
1712         if(e->name == nil)
1713                 kstrdup(&e->name, s);
1714         if(e->user == nil)
1715                  kstrdup(&e->user, u);
1716         e->perm = perm;
1717         e->r = r;
1718         e->w = w;
1719         unlock(&lk);
1720         return 0;
1721 }
1722
1723 static void
1724 sdshutdown(void)
1725 {
1726         int i;
1727         SDev *sd;
1728
1729         for(i = 0; i < nelem(devs); i++){
1730                 sd = devs[i];
1731                 if(sd == nil)
1732                         continue;
1733                 if(sd->ifc->disable == nil){
1734                         print("#S/sd%c: no disable function\n", devletters[i]);
1735                         continue;
1736                 }
1737                 sd->ifc->disable(sd);
1738         }
1739 }
1740
1741 Dev sddevtab = {
1742         'S',
1743         "sd",
1744
1745         sdreset,
1746         devinit,
1747         sdshutdown,
1748         sdattach,
1749         sdwalk,
1750         sdstat,
1751         sdopen,
1752         devcreate,
1753         sdclose,
1754         sdread,
1755         devbread,
1756         sdwrite,
1757         devbwrite,
1758         devremove,
1759         sdwstat,
1760         devpower,
1761         sdconfig,
1762 };
1763
1764 /*
1765  * This is wrong for so many reasons.  This code must go.
1766  */
1767 typedef struct Confdata Confdata;
1768 struct Confdata {
1769         int     on;
1770         char*   spec;
1771         DevConf cf;
1772 };
1773
1774 static void
1775 parseswitch(Confdata* cd, char* option)
1776 {
1777         if(!strcmp("on", option))
1778                 cd->on = 1;
1779         else if(!strcmp("off", option))
1780                 cd->on = 0;
1781         else
1782                 error(Ebadarg);
1783 }
1784
1785 static void
1786 parsespec(Confdata* cd, char* option)
1787 {
1788         if(strlen(option) > 1)
1789                 error(Ebadarg);
1790         cd->spec = option;
1791 }
1792
1793 static Devport*
1794 getnewport(DevConf* dc)
1795 {
1796         Devport *p;
1797
1798         p = malloc((dc->nports + 1) * sizeof(Devport));
1799         if(p == nil)
1800                 panic("sd: no memory for Devport");
1801         if(dc->nports > 0){
1802                 memmove(p, dc->ports, dc->nports * sizeof(Devport));
1803                 free(dc->ports);
1804         }
1805         dc->ports = p;
1806         p = &dc->ports[dc->nports++];
1807         p->size = -1;
1808         p->port = (ulong)-1;
1809         return p;
1810 }
1811
1812 static void
1813 parseport(Confdata* cd, char* option)
1814 {
1815         char *e;
1816         Devport *p;
1817
1818         if(cd->cf.nports == 0 || cd->cf.ports[cd->cf.nports-1].port != (ulong)-1)
1819                 p = getnewport(&cd->cf);
1820         else
1821                 p = &cd->cf.ports[cd->cf.nports-1];
1822         p->port = strtol(option, &e, 0);
1823         if(e == nil || *e != '\0')
1824                 error(Ebadarg);
1825 }
1826
1827 static void
1828 parsesize(Confdata* cd, char* option)
1829 {
1830         char *e;
1831         Devport *p;
1832
1833         if(cd->cf.nports == 0 || cd->cf.ports[cd->cf.nports-1].size != -1)
1834                 p = getnewport(&cd->cf);
1835         else
1836                 p = &cd->cf.ports[cd->cf.nports-1];
1837         p->size = (int)strtol(option, &e, 0);
1838         if(e == nil || *e != '\0')
1839                 error(Ebadarg);
1840 }
1841
1842 static void
1843 parseirq(Confdata* cd, char* option)
1844 {
1845         char *e;
1846
1847         cd->cf.intnum = strtoul(option, &e, 0);
1848         if(e == nil || *e != '\0')
1849                 error(Ebadarg);
1850 }
1851
1852 static void
1853 parsetype(Confdata* cd, char* option)
1854 {
1855         cd->cf.type = option;
1856 }
1857
1858 static struct {
1859         char    *name;
1860         void    (*parse)(Confdata*, char*);
1861 } options[] = {
1862         "switch",       parseswitch,
1863         "spec",         parsespec,
1864         "port",         parseport,
1865         "size",         parsesize,
1866         "irq",          parseirq,
1867         "type",         parsetype,
1868 };
1869
1870 static void
1871 legacytopctl(Cmdbuf *cb)
1872 {
1873         char *opt;
1874         int i, j;
1875         Confdata cd;
1876
1877         memset(&cd, 0, sizeof cd);
1878         cd.on = -1;
1879         for(i=0; i<cb->nf; i+=2){
1880                 if(i+2 > cb->nf)
1881                         error(Ebadarg);
1882                 opt = cb->f[i];
1883                 for(j=0; j<nelem(options); j++)
1884                         if(strcmp(opt, options[j].name) == 0){
1885                                 options[j].parse(&cd, cb->f[i+1]);
1886                                 break;
1887                         }
1888                 if(j == nelem(options))
1889                         error(Ebadarg);
1890         }
1891         if(cd.on < 0 || cd.spec == 0)
1892                 error(Ebadarg);
1893         if(cd.on && cd.cf.type == nil)
1894                 error(Ebadarg);
1895         sdconfig(cd.on, cd.spec, &cd.cf);
1896 }