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