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 devletters[] = "0123456789"
19 "abcdefghijklmnopqrstuvwxyz"
20 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
21
22 static SDev *devs[sizeof devletters-1];
23 static QLock devslock;
24
25 enum {
26 Rawcmd,
27 Rawdata,
28 Rawstatus,
29 };
30
31 enum {
32 Qtopdir = 1, /* top level directory */
33 Qtopbase,
34 Qtopctl = Qtopbase,
35
36 Qunitdir, /* directory per unit */
37 Qunitbase,
38 Qctl = Qunitbase,
39 Qraw,
40 Qpart,
41
42 TypeLOG = 4,
43 NType = (1<<TypeLOG),
44 TypeMASK = (NType-1),
45 TypeSHIFT = 0,
46
47 PartLOG = 8,
48 NPart = (1<<PartLOG),
49 PartMASK = (NPart-1),
50 PartSHIFT = TypeLOG,
51
52 UnitLOG = 8,
53 NUnit = (1<<UnitLOG),
54 UnitMASK = (NUnit-1),
55 UnitSHIFT = (PartLOG+TypeLOG),
56
57 DevLOG = 8,
58 NDev = (1 << DevLOG),
59 DevMASK = (NDev-1),
60 DevSHIFT = (UnitLOG+PartLOG+TypeLOG),
61
62 Ncmd = 20,
63 };
64
65 #define TYPE(q) ((((ulong)(q).path)>>TypeSHIFT) & TypeMASK)
66 #define PART(q) ((((ulong)(q).path)>>PartSHIFT) & PartMASK)
67 #define UNIT(q) ((((ulong)(q).path)>>UnitSHIFT) & UnitMASK)
68 #define DEV(q) ((((ulong)(q).path)>>DevSHIFT) & DevMASK)
69 #define QID(d,u, p, t) (((d)<<DevSHIFT)|((u)<<UnitSHIFT)|\
70 ((p)<<PartSHIFT)|((t)<<TypeSHIFT))
71
72
73 void
sdaddpart(SDunit * unit,char * name,uvlong start,uvlong end)74 sdaddpart(SDunit* unit, char* name, uvlong start, uvlong end)
75 {
76 SDpart *pp;
77 int i, partno;
78
79 /*
80 * Check name not already used
81 * and look for a free slot.
82 */
83 if(unit->part != nil){
84 partno = -1;
85 for(i = 0; i < unit->npart; i++){
86 pp = &unit->part[i];
87 if(!pp->valid){
88 if(partno == -1)
89 partno = i;
90 break;
91 }
92 if(strcmp(name, pp->name) == 0){
93 if(pp->start == start && pp->end == end)
94 return;
95 error(Ebadctl);
96 }
97 }
98 }
99 else{
100 if((unit->part = malloc(sizeof(SDpart)*SDnpart)) == nil)
101 error(Enomem);
102 unit->npart = SDnpart;
103 partno = 0;
104 }
105
106 /*
107 * If no free slot found then increase the
108 * array size (can't get here with unit->part == nil).
109 */
110 if(partno == -1){
111 if(unit->npart >= NPart)
112 error(Enomem);
113 if((pp = malloc(sizeof(SDpart)*(unit->npart+SDnpart))) == nil)
114 error(Enomem);
115 memmove(pp, unit->part, sizeof(SDpart)*unit->npart);
116 free(unit->part);
117 unit->part = pp;
118 partno = unit->npart;
119 unit->npart += SDnpart;
120 }
121
122 /*
123 * Check size and extent are valid.
124 */
125 if(start > end || end > unit->sectors)
126 error(Eio);
127 pp = &unit->part[partno];
128 pp->start = start;
129 pp->end = end;
130 kstrdup(&pp->name, name);
131 kstrdup(&pp->user, eve);
132 pp->perm = 0640;
133 pp->valid = 1;
134 }
135
136 static void
sddelpart(SDunit * unit,char * name)137 sddelpart(SDunit* unit, char* name)
138 {
139 int i;
140 SDpart *pp;
141
142 /*
143 * Look for the partition to delete.
144 * Can't delete if someone still has it open.
145 */
146 pp = unit->part;
147 for(i = 0; i < unit->npart; i++){
148 if(strcmp(name, pp->name) == 0)
149 break;
150 pp++;
151 }
152 if(i >= unit->npart)
153 error(Ebadctl);
154 if(strcmp(up->user, pp->user) && !iseve())
155 error(Eperm);
156 pp->valid = 0;
157 pp->vers++;
158 }
159
160 static void
sdincvers(SDunit * unit)161 sdincvers(SDunit *unit)
162 {
163 int i;
164
165 unit->vers++;
166 if(unit->part){
167 for(i = 0; i < unit->npart; i++){
168 unit->part[i].valid = 0;
169 unit->part[i].vers++;
170 }
171 }
172 }
173
174 static int
sdinitpart(SDunit * unit)175 sdinitpart(SDunit* unit)
176 {
177 int nf;
178 uvlong start, end;
179 char *f[4], *p, *q, buf[10];
180
181 if(unit->sectors > 0){
182 unit->sectors = unit->secsize = 0;
183 sdincvers(unit);
184 }
185
186 /* device must be connected or not; other values are trouble */
187 if(unit->inquiry[0] & 0xC0) /* see SDinq0periphqual */
188 return 0;
189 switch(unit->inquiry[0] & SDinq0periphtype){
190 case SDperdisk:
191 case SDperworm:
192 case SDpercd:
193 case SDpermo:
194 break;
195 default:
196 return 0;
197 }
198
199 if(unit->dev->ifc->online)
200 unit->dev->ifc->online(unit);
201 if(unit->sectors){
202 sdincvers(unit);
203 sdaddpart(unit, "data", 0, unit->sectors);
204
205 /*
206 * Use partitions passed from boot program,
207 * e.g.
208 * sdC0part=dos 63 123123/plan9 123123 456456
209 * This happens before /boot sets hostname so the
210 * partitions will have the null-string for user.
211 * The gen functions patch it up.
212 */
213 snprint(buf, sizeof buf, "%spart", unit->name);
214 for(p = getconf(buf); p != nil; p = q){
215 if(q = strchr(p, '/'))
216 *q++ = '\0';
217 nf = tokenize(p, f, nelem(f));
218 if(nf < 3)
219 continue;
220
221 start = strtoull(f[1], 0, 0);
222 end = strtoull(f[2], 0, 0);
223 if(!waserror()){
224 sdaddpart(unit, f[0], start, end);
225 poperror();
226 }
227 }
228 }
229
230 return 1;
231 }
232
233 static int
sdindex(int idno)234 sdindex(int idno)
235 {
236 char *p;
237
238 p = strchr(devletters, idno);
239 if(p == nil)
240 return -1;
241 return p-devletters;
242 }
243
244 static SDev*
sdgetdev(int idno)245 sdgetdev(int idno)
246 {
247 SDev *sdev;
248 int i;
249
250 if((i = sdindex(idno)) < 0)
251 return nil;
252
253 qlock(&devslock);
254 if(sdev = devs[i])
255 incref(&sdev->r);
256 qunlock(&devslock);
257 return sdev;
258 }
259
260 static SDunit*
sdgetunit(SDev * sdev,int subno)261 sdgetunit(SDev* sdev, int subno)
262 {
263 SDunit *unit;
264 char buf[32];
265
266 /*
267 * Associate a unit with a given device and sub-unit
268 * number on that device.
269 * The device will be probed if it has not already been
270 * successfully accessed.
271 */
272 qlock(&sdev->unitlock);
273 if(subno > sdev->nunit){
274 qunlock(&sdev->unitlock);
275 return nil;
276 }
277
278 unit = sdev->unit[subno];
279 if(unit == nil){
280 /*
281 * Probe the unit only once. This decision
282 * may be a little severe and reviewed later.
283 */
284 if(sdev->unitflg[subno]){
285 qunlock(&sdev->unitlock);
286 return nil;
287 }
288 if((unit = malloc(sizeof(SDunit))) == nil){
289 qunlock(&sdev->unitlock);
290 return nil;
291 }
292 sdev->unitflg[subno] = 1;
293
294 snprint(buf, sizeof(buf), "%s%d", sdev->name, subno);
295 kstrdup(&unit->name, buf);
296 kstrdup(&unit->user, eve);
297 unit->perm = 0555;
298 unit->subno = subno;
299 unit->dev = sdev;
300
301 if(sdev->enabled == 0 && sdev->ifc->enable)
302 sdev->ifc->enable(sdev);
303 sdev->enabled = 1;
304
305 /*
306 * No need to lock anything here as this is only
307 * called before the unit is made available in the
308 * sdunit[] array.
309 */
310 if(unit->dev->ifc->verify(unit) == 0){
311 qunlock(&sdev->unitlock);
312 free(unit);
313 return nil;
314 }
315 sdev->unit[subno] = unit;
316 }
317 qunlock(&sdev->unitlock);
318 return unit;
319 }
320
321 static void
sdreset(void)322 sdreset(void)
323 {
324 int i;
325 SDev *sdev;
326
327 /*
328 * Probe all known controller types and register any devices found.
329 */
330 for(i = 0; sdifc[i] != nil; i++){
331 if(sdifc[i]->pnp == nil || (sdev = sdifc[i]->pnp()) == nil)
332 continue;
333 sdadddevs(sdev);
334 }
335 }
336
337 void
sdadddevs(SDev * sdev)338 sdadddevs(SDev *sdev)
339 {
340 int i, j, id;
341 SDev *next;
342
343 for(; sdev; sdev=next){
344 next = sdev->next;
345
346 sdev->unit = (SDunit**)malloc(sdev->nunit * sizeof(SDunit*));
347 sdev->unitflg = (int*)malloc(sdev->nunit * sizeof(int));
348 if(sdev->unit == nil || sdev->unitflg == nil){
349 print("sdadddevs: out of memory\n");
350 giveup:
351 free(sdev->unit);
352 free(sdev->unitflg);
353 if(sdev->ifc->clear)
354 sdev->ifc->clear(sdev);
355 free(sdev);
356 continue;
357 }
358 id = sdindex(sdev->idno);
359 if(id == -1){
360 print("sdadddevs: bad id number %d (%C)\n", id, id);
361 goto giveup;
362 }
363 qlock(&devslock);
364 for(i=0; i<nelem(devs); i++){
365 if(devs[j = (id+i)%nelem(devs)] == nil){
366 sdev->idno = devletters[j];
367 devs[j] = sdev;
368 snprint(sdev->name, sizeof sdev->name, "sd%c", devletters[j]);
369 break;
370 }
371 }
372 qunlock(&devslock);
373 if(i == nelem(devs)){
374 print("sdadddevs: out of device letters\n");
375 goto giveup;
376 }
377 }
378 }
379
380 // void
381 // sdrmdevs(SDev *sdev)
382 // {
383 // char buf[2];
384 //
385 // snprint(buf, sizeof buf, "%c", sdev->idno);
386 // unconfigure(buf);
387 // }
388
389 void
sdaddallconfs(void (* addconf)(SDunit *))390 sdaddallconfs(void (*addconf)(SDunit *))
391 {
392 int i, u;
393 SDev *sdev;
394
395 for(i = 0; i < nelem(devs); i++) /* each controller */
396 for(sdev = devs[i]; sdev; sdev = sdev->next)
397 for(u = 0; u < sdev->nunit; u++) /* each drive */
398 (*addconf)(sdev->unit[u]);
399 }
400
401 static int
sd2gen(Chan * c,int i,Dir * dp)402 sd2gen(Chan* c, int i, Dir* dp)
403 {
404 Qid q;
405 uvlong l;
406 SDpart *pp;
407 SDperm *perm;
408 SDunit *unit;
409 SDev *sdev;
410 int rv;
411
412 sdev = sdgetdev(DEV(c->qid));
413 assert(sdev);
414 unit = sdev->unit[UNIT(c->qid)];
415
416 rv = -1;
417 switch(i){
418 case Qctl:
419 mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qctl),
420 unit->vers, QTFILE);
421 perm = &unit->ctlperm;
422 if(emptystr(perm->user)){
423 kstrdup(&perm->user, eve);
424 perm->perm = 0644; /* nothing secret in ctl */
425 }
426 devdir(c, q, "ctl", 0, perm->user, perm->perm, dp);
427 rv = 1;
428 break;
429
430 case Qraw:
431 mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qraw),
432 unit->vers, QTFILE);
433 perm = &unit->rawperm;
434 if(emptystr(perm->user)){
435 kstrdup(&perm->user, eve);
436 perm->perm = DMEXCL|0600;
437 }
438 devdir(c, q, "raw", 0, perm->user, perm->perm, dp);
439 rv = 1;
440 break;
441
442 case Qpart:
443 pp = &unit->part[PART(c->qid)];
444 l = (pp->end - pp->start) * unit->secsize;
445 mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qpart),
446 unit->vers+pp->vers, QTFILE);
447 if(emptystr(pp->user))
448 kstrdup(&pp->user, eve);
449 devdir(c, q, pp->name, l, pp->user, pp->perm, dp);
450 rv = 1;
451 break;
452 }
453
454 decref(&sdev->r);
455 return rv;
456 }
457
458 static int
sd1gen(Chan * c,int i,Dir * dp)459 sd1gen(Chan* c, int i, Dir* dp)
460 {
461 Qid q;
462
463 switch(i){
464 case Qtopctl:
465 mkqid(&q, QID(0, 0, 0, Qtopctl), 0, QTFILE);
466 devdir(c, q, "sdctl", 0, eve, 0644, dp); /* no secrets */
467 return 1;
468 }
469 return -1;
470 }
471
472 static int
sdgen(Chan * c,char *,Dirtab *,int,int s,Dir * dp)473 sdgen(Chan* c, char*, Dirtab*, int, int s, Dir* dp)
474 {
475 Qid q;
476 uvlong l;
477 int i, r;
478 SDpart *pp;
479 SDunit *unit;
480 SDev *sdev;
481
482 switch(TYPE(c->qid)){
483 case Qtopdir:
484 if(s == DEVDOTDOT){
485 mkqid(&q, QID(0, 0, 0, Qtopdir), 0, QTDIR);
486 snprint(up->genbuf, sizeof up->genbuf, "#%C",
487 sddevtab.dc);
488 devdir(c, q, up->genbuf, 0, eve, 0555, dp);
489 return 1;
490 }
491
492 if(s+Qtopbase < Qunitdir)
493 return sd1gen(c, s+Qtopbase, dp);
494 s -= (Qunitdir-Qtopbase);
495
496 qlock(&devslock);
497 for(i=0; i<nelem(devs); i++){
498 if(devs[i]){
499 if(s < devs[i]->nunit)
500 break;
501 s -= devs[i]->nunit;
502 }
503 }
504
505 if(i == nelem(devs)){
506 /* Run off the end of the list */
507 qunlock(&devslock);
508 return -1;
509 }
510
511 if((sdev = devs[i]) == nil){
512 qunlock(&devslock);
513 return 0;
514 }
515
516 incref(&sdev->r);
517 qunlock(&devslock);
518
519 if((unit = sdev->unit[s]) == nil)
520 if((unit = sdgetunit(sdev, s)) == nil){
521 decref(&sdev->r);
522 return 0;
523 }
524
525 mkqid(&q, QID(sdev->idno, s, 0, Qunitdir), 0, QTDIR);
526 if(emptystr(unit->user))
527 kstrdup(&unit->user, eve);
528 devdir(c, q, unit->name, 0, unit->user, unit->perm, dp);
529 decref(&sdev->r);
530 return 1;
531
532 case Qunitdir:
533 if(s == DEVDOTDOT){
534 mkqid(&q, QID(0, 0, 0, Qtopdir), 0, QTDIR);
535 snprint(up->genbuf, sizeof up->genbuf, "#%C",
536 sddevtab.dc);
537 devdir(c, q, up->genbuf, 0, eve, 0555, dp);
538 return 1;
539 }
540
541 if((sdev = sdgetdev(DEV(c->qid))) == nil){
542 devdir(c, c->qid, "unavailable", 0, eve, 0, dp);
543 return 1;
544 }
545
546 unit = sdev->unit[UNIT(c->qid)];
547 qlock(&unit->ctl);
548
549 /*
550 * Check for media change.
551 * If one has already been detected, sectors will be zero.
552 * If there is one waiting to be detected, online
553 * will return > 1.
554 * Online is a bit of a large hammer but does the job.
555 */
556 if(unit->sectors == 0
557 || (unit->dev->ifc->online && unit->dev->ifc->online(unit) > 1))
558 sdinitpart(unit);
559
560 i = s+Qunitbase;
561 if(i < Qpart){
562 r = sd2gen(c, i, dp);
563 qunlock(&unit->ctl);
564 decref(&sdev->r);
565 return r;
566 }
567 i -= Qpart;
568 if(unit->part == nil || i >= unit->npart){
569 qunlock(&unit->ctl);
570 decref(&sdev->r);
571 break;
572 }
573 pp = &unit->part[i];
574 if(!pp->valid){
575 qunlock(&unit->ctl);
576 decref(&sdev->r);
577 return 0;
578 }
579 l = (pp->end - pp->start) * unit->secsize;
580 mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), i, Qpart),
581 unit->vers+pp->vers, QTFILE);
582 if(emptystr(pp->user))
583 kstrdup(&pp->user, eve);
584 devdir(c, q, pp->name, l, pp->user, pp->perm, dp);
585 qunlock(&unit->ctl);
586 decref(&sdev->r);
587 return 1;
588 case Qraw:
589 case Qctl:
590 case Qpart:
591 if((sdev = sdgetdev(DEV(c->qid))) == nil){
592 devdir(c, q, "unavailable", 0, eve, 0, dp);
593 return 1;
594 }
595 unit = sdev->unit[UNIT(c->qid)];
596 qlock(&unit->ctl);
597 r = sd2gen(c, TYPE(c->qid), dp);
598 qunlock(&unit->ctl);
599 decref(&sdev->r);
600 return r;
601 case Qtopctl:
602 return sd1gen(c, TYPE(c->qid), dp);
603 default:
604 break;
605 }
606
607 return -1;
608 }
609
610 static Chan*
sdattach(char * spec)611 sdattach(char* spec)
612 {
613 Chan *c;
614 char *p;
615 SDev *sdev;
616 int idno, subno;
617
618 if(*spec == '\0'){
619 c = devattach(sddevtab.dc, spec);
620 mkqid(&c->qid, QID(0, 0, 0, Qtopdir), 0, QTDIR);
621 return c;
622 }
623
624 if(spec[0] != 's' || spec[1] != 'd')
625 error(Ebadspec);
626 idno = spec[2];
627 subno = strtol(&spec[3], &p, 0);
628 if(p == &spec[3])
629 error(Ebadspec);
630
631 if((sdev=sdgetdev(idno)) == nil)
632 error(Enonexist);
633 if(sdgetunit(sdev, subno) == nil){
634 decref(&sdev->r);
635 error(Enonexist);
636 }
637
638 c = devattach(sddevtab.dc, spec);
639 mkqid(&c->qid, QID(sdev->idno, subno, 0, Qunitdir), 0, QTDIR);
640 c->devno = (sdev->idno << UnitLOG) + subno;
641 decref(&sdev->r);
642 return c;
643 }
644
645 static Walkqid*
sdwalk(Chan * c,Chan * nc,char ** name,int nname)646 sdwalk(Chan* c, Chan* nc, char** name, int nname)
647 {
648 return devwalk(c, nc, name, nname, nil, 0, sdgen);
649 }
650
651 static long
sdstat(Chan * c,uchar * db,long n)652 sdstat(Chan* c, uchar* db, long n)
653 {
654 return devstat(c, db, n, nil, 0, sdgen);
655 }
656
657 static Chan*
sdopen(Chan * c,int omode)658 sdopen(Chan* c, int omode)
659 {
660 SDpart *pp;
661 SDunit *unit;
662 SDev *sdev;
663 uchar tp;
664
665 c = devopen(c, omode, 0, 0, sdgen);
666 if((tp = TYPE(c->qid)) != Qctl && tp != Qraw && tp != Qpart)
667 return c;
668
669 sdev = sdgetdev(DEV(c->qid));
670 if(sdev == nil)
671 error(Enonexist);
672
673 unit = sdev->unit[UNIT(c->qid)];
674
675 switch(TYPE(c->qid)){
676 case Qctl:
677 c->qid.vers = unit->vers;
678 break;
679 case Qraw:
680 c->qid.vers = unit->vers;
681 if(TAS(&unit->rawinuse) != 0){
682 c->flag &= ~COPEN;
683 decref(&sdev->r);
684 error(Einuse);
685 }
686 unit->state = Rawcmd;
687 break;
688 case Qpart:
689 qlock(&unit->ctl);
690 if(waserror()){
691 qunlock(&unit->ctl);
692 c->flag &= ~COPEN;
693 decref(&sdev->r);
694 nexterror();
695 }
696 pp = &unit->part[PART(c->qid)];
697 c->qid.vers = unit->vers+pp->vers;
698 qunlock(&unit->ctl);
699 poperror();
700 break;
701 }
702 decref(&sdev->r);
703 return c;
704 }
705
706 static void
sdclose(Chan * c)707 sdclose(Chan* c)
708 {
709 SDunit *unit;
710 SDev *sdev;
711
712 if(c->qid.type & QTDIR)
713 return;
714 if(!(c->flag & COPEN))
715 return;
716
717 switch(TYPE(c->qid)){
718 default:
719 break;
720 case Qraw:
721 sdev = sdgetdev(DEV(c->qid));
722 if(sdev){
723 unit = sdev->unit[UNIT(c->qid)];
724 unit->rawinuse = 0;
725 decref(&sdev->r);
726 }
727 break;
728 }
729 }
730
731 static long
sdbio(Chan * c,int write,char * a,long len,vlong off)732 sdbio(Chan* c, int write, char* a, long len, vlong off)
733 {
734 int nchange;
735 uchar *b;
736 SDpart *pp;
737 SDunit *unit;
738 SDev *sdev;
739 vlong bno;
740 long l, max, nb, offset;
741
742 sdev = sdgetdev(DEV(c->qid));
743 if(sdev == nil){
744 decref(&sdev->r);
745 error(Enonexist);
746 }
747 unit = sdev->unit[UNIT(c->qid)];
748 if(unit == nil)
749 error(Enonexist);
750
751 nchange = 0;
752 qlock(&unit->ctl);
753 while(waserror()){
754 /* notification of media change; go around again */
755 if(strcmp(up->errstr, Eio) == 0 && unit->sectors == 0 && nchange++ == 0){
756 sdinitpart(unit);
757 continue;
758 }
759
760 /* other errors; give up */
761 qunlock(&unit->ctl);
762 decref(&sdev->r);
763 nexterror();
764 }
765 pp = &unit->part[PART(c->qid)];
766 if(unit->vers+pp->vers != c->qid.vers)
767 error(Echange);
768
769 /*
770 * Check the request is within bounds.
771 * Removeable drives are locked throughout the I/O
772 * in case the media changes unexpectedly.
773 * Non-removeable drives are not locked during the I/O
774 * to allow the hardware to optimise if it can; this is
775 * a little fast and loose.
776 * It's assumed that non-removeable media parameters
777 * (sectors, secsize) can't change once the drive has
778 * been brought online.
779 */
780 bno = (off/unit->secsize) + pp->start;
781 nb = ((off+len+unit->secsize-1)/unit->secsize) + pp->start - bno;
782 max = SDmaxio/unit->secsize;
783 if(nb > max)
784 nb = max;
785 if(bno+nb > pp->end)
786 nb = pp->end - bno;
787 if(bno >= pp->end || nb == 0){
788 if(write)
789 error(Eio);
790 qunlock(&unit->ctl);
791 decref(&sdev->r);
792 poperror();
793 return 0;
794 }
795 if(!(unit->inquiry[1] & SDinq1removable)){
796 qunlock(&unit->ctl);
797 poperror();
798 }
799
800 b = sdmalloc(nb*unit->secsize);
801 if(b == nil)
802 error(Enomem);
803 if(waserror()){
804 sdfree(b);
805 if(!(unit->inquiry[1] & SDinq1removable))
806 decref(&sdev->r); /* gadverdamme! */
807 nexterror();
808 }
809
810 offset = off%unit->secsize;
811 if(offset+len > nb*unit->secsize)
812 len = nb*unit->secsize - offset;
813 if(write){
814 if(offset || (len%unit->secsize)){
815 l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno);
816 if(l < 0)
817 error(Eio);
818 if(l < (nb*unit->secsize)){
819 nb = l/unit->secsize;
820 l = nb*unit->secsize - offset;
821 if(len > l)
822 len = l;
823 }
824 }
825 memmove(b+offset, a, len);
826 l = unit->dev->ifc->bio(unit, 0, 1, b, nb, bno);
827 if(l < 0)
828 error(Eio);
829 if(l < offset)
830 len = 0;
831 else if(len > l - offset)
832 len = l - offset;
833 }
834 else{
835 l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno);
836 if(l < 0)
837 error(Eio);
838 if(l < offset)
839 len = 0;
840 else if(len > l - offset)
841 len = l - offset;
842 memmove(a, b+offset, len);
843 }
844 sdfree(b);
845 poperror();
846
847 if(unit->inquiry[1] & SDinq1removable){
848 qunlock(&unit->ctl);
849 poperror();
850 }
851
852 decref(&sdev->r);
853 return len;
854 }
855
856 static long
sdrio(SDreq * r,void * a,long n)857 sdrio(SDreq* r, void* a, long n)
858 {
859 void *data;
860
861 if(n >= SDmaxio || n < 0)
862 error(Etoobig);
863
864 data = nil;
865 if(n){
866 if((data = sdmalloc(n)) == nil)
867 error(Enomem);
868 if(r->write)
869 memmove(data, a, n);
870 }
871 r->data = data;
872 r->dlen = n;
873
874 if(waserror()){
875 sdfree(data);
876 r->data = nil;
877 nexterror();
878 }
879
880 if(r->unit->dev->ifc->rio(r) != SDok)
881 error(Eio);
882
883 if(!r->write && r->rlen > 0)
884 memmove(a, data, r->rlen);
885 sdfree(data);
886 r->data = nil;
887 poperror();
888
889 return r->rlen;
890 }
891
892 /*
893 * SCSI simulation for non-SCSI devices
894 */
895 int
sdsetsense(SDreq * r,int status,int key,int asc,int ascq)896 sdsetsense(SDreq *r, int status, int key, int asc, int ascq)
897 {
898 int len;
899 SDunit *unit;
900
901 unit = r->unit;
902 unit->sense[2] = key;
903 unit->sense[12] = asc;
904 unit->sense[13] = ascq;
905
906 r->status = status;
907 if(status == SDcheck && !(r->flags & SDnosense)){
908 /* request sense case from sdfakescsi */
909 len = sizeof unit->sense;
910 if(len > sizeof r->sense-1)
911 len = sizeof r->sense-1;
912 memmove(r->sense, unit->sense, len);
913 unit->sense[2] = 0;
914 unit->sense[12] = 0;
915 unit->sense[13] = 0;
916 r->flags |= SDvalidsense;
917 return SDok;
918 }
919 return status;
920 }
921
922 int
sdmodesense(SDreq * r,uchar * cmd,void * info,int ilen)923 sdmodesense(SDreq *r, uchar *cmd, void *info, int ilen)
924 {
925 int len;
926 uchar *data;
927
928 /*
929 * Fake a vendor-specific request with page code 0,
930 * return the drive info.
931 */
932 if((cmd[2] & 0x3F) != 0 && (cmd[2] & 0x3F) != 0x3F)
933 return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
934 len = (cmd[7]<<8)|cmd[8];
935 if(len == 0)
936 return SDok;
937 if(len < 8+ilen)
938 return sdsetsense(r, SDcheck, 0x05, 0x1A, 0);
939 if(r->data == nil || r->dlen < len)
940 return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
941 data = r->data;
942 memset(data, 0, 8);
943 data[0] = ilen>>8;
944 data[1] = ilen;
945 if(ilen)
946 memmove(data+8, info, ilen);
947 r->rlen = 8+ilen;
948 return sdsetsense(r, SDok, 0, 0, 0);
949 }
950
951 int
sdfakescsi(SDreq * r,void * info,int ilen)952 sdfakescsi(SDreq *r, void *info, int ilen)
953 {
954 uchar *cmd, *p;
955 uvlong len;
956 SDunit *unit;
957
958 cmd = r->cmd;
959 r->rlen = 0;
960 unit = r->unit;
961
962 /*
963 * Rewrite read(6)/write(6) into read(10)/write(10).
964 */
965 switch(cmd[0]){
966 case ScmdRead:
967 case ScmdWrite:
968 cmd[9] = 0;
969 cmd[8] = cmd[4];
970 cmd[7] = 0;
971 cmd[6] = 0;
972 cmd[5] = cmd[3];
973 cmd[4] = cmd[2];
974 cmd[3] = cmd[1] & 0x0F;
975 cmd[2] = 0;
976 cmd[1] &= 0xE0;
977 cmd[0] |= 0x20;
978 break;
979 }
980
981 /*
982 * Map SCSI commands into ATA commands for discs.
983 * Fail any command with a LUN except INQUIRY which
984 * will return 'logical unit not supported'.
985 */
986 if((cmd[1]>>5) && cmd[0] != ScmdInq)
987 return sdsetsense(r, SDcheck, 0x05, 0x25, 0);
988
989 switch(cmd[0]){
990 default:
991 return sdsetsense(r, SDcheck, 0x05, 0x20, 0);
992
993 case ScmdTur: /* test unit ready */
994 return sdsetsense(r, SDok, 0, 0, 0);
995
996 case ScmdRsense: /* request sense */
997 if(cmd[4] < sizeof unit->sense)
998 len = cmd[4];
999 else
1000 len = sizeof unit->sense;
1001 if(r->data && r->dlen >= len){
1002 memmove(r->data, unit->sense, len);
1003 r->rlen = len;
1004 }
1005 return sdsetsense(r, SDok, 0, 0, 0);
1006
1007 case ScmdInq: /* inquiry */
1008 if(cmd[4] < sizeof unit->inquiry)
1009 len = cmd[4];
1010 else
1011 len = sizeof unit->inquiry;
1012 if(r->data && r->dlen >= len){
1013 memmove(r->data, unit->inquiry, len);
1014 r->rlen = len;
1015 }
1016 return sdsetsense(r, SDok, 0, 0, 0);
1017
1018 case ScmdStart: /* start/stop unit */
1019 /*
1020 * nop for now, can use power management later.
1021 */
1022 return sdsetsense(r, SDok, 0, 0, 0);
1023
1024 case ScmdRcapacity: /* read capacity */
1025 if((cmd[1] & 0x01) || cmd[2] || cmd[3])
1026 return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
1027 if(r->data == nil || r->dlen < 8)
1028 return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
1029
1030 /*
1031 * Read capacity returns the LBA of the last sector.
1032 */
1033 len = unit->sectors - 1;
1034 p = r->data;
1035 *p++ = len>>24;
1036 *p++ = len>>16;
1037 *p++ = len>>8;
1038 *p++ = len;
1039 len = 512;
1040 *p++ = len>>24;
1041 *p++ = len>>16;
1042 *p++ = len>>8;
1043 *p++ = len;
1044 r->rlen = p - (uchar*)r->data;
1045 return sdsetsense(r, SDok, 0, 0, 0);
1046
1047 case ScmdRcapacity16: /* long read capacity */
1048 if((cmd[1] & 0x01) || cmd[2] || cmd[3])
1049 return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
1050 if(r->data == nil || r->dlen < 8)
1051 return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
1052 /*
1053 * Read capcity returns the LBA of the last sector.
1054 */
1055 len = unit->sectors - 1;
1056 p = r->data;
1057 *p++ = len>>56;
1058 *p++ = len>>48;
1059 *p++ = len>>40;
1060 *p++ = len>>32;
1061 *p++ = len>>24;
1062 *p++ = len>>16;
1063 *p++ = len>>8;
1064 *p++ = len;
1065 len = 512;
1066 *p++ = len>>24;
1067 *p++ = len>>16;
1068 *p++ = len>>8;
1069 *p++ = len;
1070 r->rlen = p - (uchar*)r->data;
1071 return sdsetsense(r, SDok, 0, 0, 0);
1072
1073 case ScmdMsense10: /* mode sense */
1074 return sdmodesense(r, cmd, info, ilen);
1075
1076 case ScmdExtread:
1077 case ScmdExtwrite:
1078 case ScmdRead16:
1079 case ScmdWrite16:
1080 return SDnostatus;
1081 }
1082 }
1083
1084 int
sdfakescsirw(SDreq * r,uvlong * llba,int * nsec,int * rwp)1085 sdfakescsirw(SDreq *r, uvlong *llba, int *nsec, int *rwp)
1086 {
1087 uchar *c;
1088 int rw, count;
1089 uvlong lba;
1090
1091 c = r->cmd;
1092 rw = 0;
1093 if((c[0] & 0xf) == 0xa)
1094 rw = 1;
1095 switch(c[0]){
1096 case 0x08: /* read6 */
1097 case 0x0a:
1098 lba = (c[1] & 0xf)<<16 | c[2]<<8 | c[3];
1099 count = c[4];
1100 break;
1101 case 0x28: /* read10 */
1102 case 0x2a:
1103 lba = c[2]<<24 | c[3]<<16 | c[4]<<8 | c[5];
1104 count = c[7]<<8 | c[8];
1105 break;
1106 case 0xa8: /* read12 */
1107 case 0xaa:
1108 lba = c[2]<<24 | c[3]<<16 | c[4]<<8 | c[5];
1109 count = c[6]<<24 | c[7]<<16 | c[8]<<8 | c[9];
1110 break;
1111 case 0x88: /* read16 */
1112 case 0x8a:
1113 /* ata commands only go to 48-bit lba */
1114 if(c[2] || c[3])
1115 return sdsetsense(r, SDcheck, 3, 0xc, 2);
1116 lba = (uvlong)c[4]<<40 | (uvlong)c[5]<<32;
1117 lba |= c[6]<<24 | c[7]<<16 | c[8]<<8 | c[9];
1118 count = c[10]<<24 | c[11]<<16 | c[12]<<8 | c[13];
1119 break;
1120 default:
1121 print("%s: bad cmd 0x%.2ux\n", r->unit->name, c[0]);
1122 r->status = sdsetsense(r, SDcheck, 0x05, 0x20, 0);
1123 return SDcheck;
1124 }
1125 if(r->data == nil)
1126 return SDok;
1127 if(r->dlen < count * r->unit->secsize)
1128 count = r->dlen/r->unit->secsize;
1129 if(rwp)
1130 *rwp = rw;
1131 *llba = lba;
1132 *nsec = count;
1133 return SDnostatus;
1134 }
1135
1136 static long
sdread(Chan * c,void * a,long n,vlong off)1137 sdread(Chan *c, void *a, long n, vlong off)
1138 {
1139 char *p, *e, *buf;
1140 SDpart *pp;
1141 SDunit *unit;
1142 SDev *sdev;
1143 long offset;
1144 int i, l, m, status;
1145
1146 offset = off;
1147 switch(TYPE(c->qid)){
1148 default:
1149 error(Eperm);
1150 case Qtopctl:
1151 m = 64*1024; /* room for register dumps */
1152 p = buf = malloc(m);
1153 if(p == nil)
1154 error(Enomem);
1155 e = p + m;
1156 qlock(&devslock);
1157 for(i = 0; i < nelem(devs); i++){
1158 sdev = devs[i];
1159 if(sdev && sdev->ifc->rtopctl)
1160 p = sdev->ifc->rtopctl(sdev, p, e);
1161 }
1162 qunlock(&devslock);
1163 n = readstr(offset, a, n, buf);
1164 free(buf);
1165 return n;
1166
1167 case Qtopdir:
1168 case Qunitdir:
1169 return devdirread(c, a, n, 0, 0, sdgen);
1170
1171 case Qctl:
1172 sdev = sdgetdev(DEV(c->qid));
1173 if(sdev == nil)
1174 error(Enonexist);
1175
1176 unit = sdev->unit[UNIT(c->qid)];
1177 m = 16*1024; /* room for register dumps */
1178 p = malloc(m);
1179 if(p == nil)
1180 error(Enomem);
1181 l = snprint(p, m, "inquiry %.48s\n",
1182 (char*)unit->inquiry+8);
1183 qlock(&unit->ctl);
1184 /*
1185 * If there's a device specific routine it must
1186 * provide all information pertaining to night geometry
1187 * and the garscadden trains.
1188 */
1189 if(unit->dev->ifc->rctl)
1190 l += unit->dev->ifc->rctl(unit, p+l, m-l);
1191 if(unit->sectors == 0)
1192 sdinitpart(unit);
1193 if(unit->sectors){
1194 if(unit->dev->ifc->rctl == nil)
1195 l += snprint(p+l, m-l,
1196 "geometry %llud %lud\n",
1197 unit->sectors, unit->secsize);
1198 pp = unit->part;
1199 for(i = 0; i < unit->npart; i++){
1200 if(pp->valid)
1201 l += snprint(p+l, m-l,
1202 "part %s %llud %llud\n",
1203 pp->name, pp->start, pp->end);
1204 pp++;
1205 }
1206 }
1207 qunlock(&unit->ctl);
1208 decref(&sdev->r);
1209 l = readstr(offset, a, n, p);
1210 free(p);
1211 return l;
1212
1213 case Qraw:
1214 sdev = sdgetdev(DEV(c->qid));
1215 if(sdev == nil)
1216 error(Enonexist);
1217
1218 unit = sdev->unit[UNIT(c->qid)];
1219 qlock(&unit->raw);
1220 if(waserror()){
1221 qunlock(&unit->raw);
1222 decref(&sdev->r);
1223 nexterror();
1224 }
1225 if(unit->state == Rawdata){
1226 unit->state = Rawstatus;
1227 i = sdrio(unit->req, a, n);
1228 }
1229 else if(unit->state == Rawstatus){
1230 status = unit->req->status;
1231 unit->state = Rawcmd;
1232 free(unit->req);
1233 unit->req = nil;
1234 i = readnum(0, a, n, status, NUMSIZE);
1235 } else
1236 i = 0;
1237 qunlock(&unit->raw);
1238 decref(&sdev->r);
1239 poperror();
1240 return i;
1241
1242 case Qpart:
1243 return sdbio(c, 0, a, n, off);
1244 }
1245 }
1246
1247 static void legacytopctl(Cmdbuf*);
1248
1249 static long
sdwrite(Chan * c,void * a,long n,vlong off)1250 sdwrite(Chan* c, void* a, long n, vlong off)
1251 {
1252 char *f0;
1253 int i;
1254 uvlong end, start;
1255 Cmdbuf *cb;
1256 SDifc *ifc;
1257 SDreq *req;
1258 SDunit *unit;
1259 SDev *sdev;
1260
1261 switch(TYPE(c->qid)){
1262 default:
1263 error(Eperm);
1264 case Qtopctl:
1265 cb = parsecmd(a, n);
1266 if(waserror()){
1267 free(cb);
1268 nexterror();
1269 }
1270 if(cb->nf == 0)
1271 error("empty control message");
1272 f0 = cb->f[0];
1273 cb->f++;
1274 cb->nf--;
1275 if(strcmp(f0, "config") == 0){
1276 /* wormhole into ugly legacy interface */
1277 legacytopctl(cb);
1278 poperror();
1279 free(cb);
1280 break;
1281 }
1282 /*
1283 * "ata arg..." invokes sdifc[i]->wtopctl(nil, cb),
1284 * where sdifc[i]->name=="ata" and cb contains the args.
1285 */
1286 ifc = nil;
1287 sdev = nil;
1288 for(i=0; sdifc[i]; i++){
1289 if(strcmp(sdifc[i]->name, f0) == 0){
1290 ifc = sdifc[i];
1291 sdev = nil;
1292 goto subtopctl;
1293 }
1294 }
1295 /*
1296 * "sd1 arg..." invokes sdifc[i]->wtopctl(sdev, cb),
1297 * where sdifc[i] and sdev match controller letter "1",
1298 * and cb contains the args.
1299 */
1300 if(f0[0]=='s' && f0[1]=='d' && f0[2] && f0[3] == 0){
1301 if((sdev = sdgetdev(f0[2])) != nil){
1302 ifc = sdev->ifc;
1303 goto subtopctl;
1304 }
1305 }
1306 error("unknown interface");
1307
1308 subtopctl:
1309 if(waserror()){
1310 if(sdev)
1311 decref(&sdev->r);
1312 nexterror();
1313 }
1314 if(ifc->wtopctl)
1315 ifc->wtopctl(sdev, cb);
1316 else
1317 error(Ebadctl);
1318 poperror();
1319 poperror();
1320 if(sdev)
1321 decref(&sdev->r);
1322 free(cb);
1323 break;
1324
1325 case Qctl:
1326 cb = parsecmd(a, n);
1327 sdev = sdgetdev(DEV(c->qid));
1328 if(sdev == nil)
1329 error(Enonexist);
1330 unit = sdev->unit[UNIT(c->qid)];
1331
1332 qlock(&unit->ctl);
1333 if(waserror()){
1334 qunlock(&unit->ctl);
1335 decref(&sdev->r);
1336 free(cb);
1337 nexterror();
1338 }
1339 if(unit->vers != c->qid.vers)
1340 error(Echange);
1341
1342 if(cb->nf < 1)
1343 error(Ebadctl);
1344 if(strcmp(cb->f[0], "part") == 0){
1345 if(cb->nf != 4)
1346 error(Ebadctl);
1347 if(unit->sectors == 0 && !sdinitpart(unit))
1348 error(Eio);
1349 start = strtoull(cb->f[2], 0, 0);
1350 end = strtoull(cb->f[3], 0, 0);
1351 sdaddpart(unit, cb->f[1], start, end);
1352 }
1353 else if(strcmp(cb->f[0], "delpart") == 0){
1354 if(cb->nf != 2 || unit->part == nil)
1355 error(Ebadctl);
1356 sddelpart(unit, cb->f[1]);
1357 }
1358 else if(unit->dev->ifc->wctl)
1359 unit->dev->ifc->wctl(unit, cb);
1360 else
1361 error(Ebadctl);
1362 qunlock(&unit->ctl);
1363 decref(&sdev->r);
1364 poperror();
1365 free(cb);
1366 break;
1367
1368 case Qraw:
1369 sdev = sdgetdev(DEV(c->qid));
1370 if(sdev == nil)
1371 error(Enonexist);
1372 unit = sdev->unit[UNIT(c->qid)];
1373 qlock(&unit->raw);
1374 if(waserror()){
1375 qunlock(&unit->raw);
1376 decref(&sdev->r);
1377 nexterror();
1378 }
1379 switch(unit->state){
1380 case Rawcmd:
1381 if(n < 6 || n > sizeof(req->cmd))
1382 error(Ebadarg);
1383 if((req = malloc(sizeof(SDreq))) == nil)
1384 error(Enomem);
1385 req->unit = unit;
1386 memmove(req->cmd, a, n);
1387 req->clen = n;
1388 req->flags = SDnosense;
1389 req->status = ~0;
1390
1391 unit->req = req;
1392 unit->state = Rawdata;
1393 break;
1394
1395 case Rawstatus:
1396 unit->state = Rawcmd;
1397 free(unit->req);
1398 unit->req = nil;
1399 error(Ebadusefd);
1400
1401 case Rawdata:
1402 unit->state = Rawstatus;
1403 unit->req->write = 1;
1404 n = sdrio(unit->req, a, n);
1405 }
1406 qunlock(&unit->raw);
1407 decref(&sdev->r);
1408 poperror();
1409 break;
1410 case Qpart:
1411 return sdbio(c, 1, a, n, off);
1412 }
1413
1414 return n;
1415 }
1416
1417 static long
sdwstat(Chan * c,uchar * dp,long n)1418 sdwstat(Chan* c, uchar* dp, long n)
1419 {
1420 Dir *d;
1421 SDpart *pp;
1422 SDperm *perm;
1423 SDunit *unit;
1424 SDev *sdev;
1425
1426 if(c->qid.type & QTDIR)
1427 error(Eperm);
1428
1429 sdev = sdgetdev(DEV(c->qid));
1430 if(sdev == nil)
1431 error(Enonexist);
1432 unit = sdev->unit[UNIT(c->qid)];
1433 qlock(&unit->ctl);
1434 d = nil;
1435 if(waserror()){
1436 free(d);
1437 qunlock(&unit->ctl);
1438 decref(&sdev->r);
1439 nexterror();
1440 }
1441
1442 switch(TYPE(c->qid)){
1443 default:
1444 error(Eperm);
1445 case Qctl:
1446 perm = &unit->ctlperm;
1447 break;
1448 case Qraw:
1449 perm = &unit->rawperm;
1450 break;
1451 case Qpart:
1452 pp = &unit->part[PART(c->qid)];
1453 if(unit->vers+pp->vers != c->qid.vers)
1454 error(Enonexist);
1455 perm = &pp->SDperm;
1456 break;
1457 }
1458
1459 if(strcmp(up->user, perm->user) && !iseve())
1460 error(Eperm);
1461
1462 d = smalloc(sizeof(Dir)+n);
1463 n = convM2D(dp, n, &d[0], (char*)&d[1]);
1464 if(n == 0)
1465 error(Eshortstat);
1466 if(!emptystr(d[0].uid))
1467 kstrdup(&perm->user, d[0].uid);
1468 if(d[0].mode != ~0UL)
1469 perm->perm = (perm->perm & ~0777) | (d[0].mode & 0777);
1470
1471 free(d);
1472 qunlock(&unit->ctl);
1473 decref(&sdev->r);
1474 poperror();
1475 return n;
1476 }
1477
1478 static int
configure(char * spec,DevConf * cf)1479 configure(char* spec, DevConf* cf)
1480 {
1481 SDev *s, *sdev;
1482 char *p;
1483 int i;
1484
1485 if(sdindex(*spec) < 0)
1486 error("bad sd spec");
1487
1488 if((p = strchr(cf->type, '/')) != nil)
1489 *p++ = '\0';
1490
1491 for(i = 0; sdifc[i] != nil; i++)
1492 if(strcmp(sdifc[i]->name, cf->type) == 0)
1493 break;
1494 if(sdifc[i] == nil)
1495 error("sd type not found");
1496 if(p)
1497 *(p-1) = '/';
1498
1499 if(sdifc[i]->probe == nil)
1500 error("sd type cannot probe");
1501
1502 sdev = sdifc[i]->probe(cf);
1503 for(s=sdev; s; s=s->next)
1504 s->idno = *spec;
1505 sdadddevs(sdev);
1506 return 0;
1507 }
1508
1509 static int
unconfigure(char * spec)1510 unconfigure(char* spec)
1511 {
1512 int i;
1513 SDev *sdev;
1514 SDunit *unit;
1515
1516 if((i = sdindex(*spec)) < 0)
1517 error(Enonexist);
1518
1519 qlock(&devslock);
1520 if((sdev = devs[i]) == nil){
1521 qunlock(&devslock);
1522 error(Enonexist);
1523 }
1524 if(sdev->r.ref){
1525 qunlock(&devslock);
1526 error(Einuse);
1527 }
1528 devs[i] = nil;
1529 qunlock(&devslock);
1530
1531 /* make sure no interrupts arrive anymore before removing resources */
1532 if(sdev->enabled && sdev->ifc->disable)
1533 sdev->ifc->disable(sdev);
1534
1535 for(i = 0; i != sdev->nunit; i++){
1536 if(unit = sdev->unit[i]){
1537 free(unit->name);
1538 free(unit->user);
1539 free(unit);
1540 }
1541 }
1542
1543 if(sdev->ifc->clear)
1544 sdev->ifc->clear(sdev);
1545 free(sdev);
1546 return 0;
1547 }
1548
1549 static int
sdconfig(int on,char * spec,DevConf * cf)1550 sdconfig(int on, char* spec, DevConf* cf)
1551 {
1552 if(on)
1553 return configure(spec, cf);
1554 return unconfigure(spec);
1555 }
1556
1557 Dev sddevtab = {
1558 'S',
1559 "sd",
1560
1561 sdreset,
1562 devinit,
1563 devshutdown,
1564 sdattach,
1565 sdwalk,
1566 sdstat,
1567 sdopen,
1568 devcreate,
1569 sdclose,
1570 sdread,
1571 devbread,
1572 sdwrite,
1573 devbwrite,
1574 devremove,
1575 sdwstat,
1576 devpower,
1577 sdconfig, /* probe; only called for pcmcia-like devices */
1578 };
1579
1580 /*
1581 * This is wrong for so many reasons. This code must go.
1582 */
1583 typedef struct Confdata Confdata;
1584 struct Confdata {
1585 int on;
1586 char* spec;
1587 DevConf cf;
1588 };
1589
1590 static void
parseswitch(Confdata * cd,char * option)1591 parseswitch(Confdata* cd, char* option)
1592 {
1593 if(!strcmp("on", option))
1594 cd->on = 1;
1595 else if(!strcmp("off", option))
1596 cd->on = 0;
1597 else
1598 error(Ebadarg);
1599 }
1600
1601 static void
parsespec(Confdata * cd,char * option)1602 parsespec(Confdata* cd, char* option)
1603 {
1604 if(strlen(option) > 1)
1605 error(Ebadarg);
1606 cd->spec = option;
1607 }
1608
1609 static Devport*
getnewport(DevConf * dc)1610 getnewport(DevConf* dc)
1611 {
1612 Devport *p;
1613
1614 p = (Devport *)malloc((dc->nports + 1) * sizeof(Devport));
1615 if(p == nil)
1616 error(Enomem);
1617 if(dc->nports > 0){
1618 memmove(p, dc->ports, dc->nports * sizeof(Devport));
1619 free(dc->ports);
1620 }
1621 dc->ports = p;
1622 p = &dc->ports[dc->nports++];
1623 p->size = -1;
1624 p->port = (ulong)-1;
1625 return p;
1626 }
1627
1628 static void
parseport(Confdata * cd,char * option)1629 parseport(Confdata* cd, char* option)
1630 {
1631 char *e;
1632 Devport *p;
1633
1634 if(cd->cf.nports == 0 || cd->cf.ports[cd->cf.nports-1].port != (ulong)-1)
1635 p = getnewport(&cd->cf);
1636 else
1637 p = &cd->cf.ports[cd->cf.nports-1];
1638 p->port = strtol(option, &e, 0);
1639 if(e == nil || *e != '\0')
1640 error(Ebadarg);
1641 }
1642
1643 static void
parsesize(Confdata * cd,char * option)1644 parsesize(Confdata* cd, char* option)
1645 {
1646 char *e;
1647 Devport *p;
1648
1649 if(cd->cf.nports == 0 || cd->cf.ports[cd->cf.nports-1].size != -1)
1650 p = getnewport(&cd->cf);
1651 else
1652 p = &cd->cf.ports[cd->cf.nports-1];
1653 p->size = (int)strtol(option, &e, 0);
1654 if(e == nil || *e != '\0')
1655 error(Ebadarg);
1656 }
1657
1658 static void
parseirq(Confdata * cd,char * option)1659 parseirq(Confdata* cd, char* option)
1660 {
1661 char *e;
1662
1663 cd->cf.intnum = strtoul(option, &e, 0);
1664 if(e == nil || *e != '\0')
1665 error(Ebadarg);
1666 }
1667
1668 static void
parsetype(Confdata * cd,char * option)1669 parsetype(Confdata* cd, char* option)
1670 {
1671 cd->cf.type = option;
1672 }
1673
1674 static struct {
1675 char *name;
1676 void (*parse)(Confdata*, char*);
1677 } options[] = {
1678 "switch", parseswitch,
1679 "spec", parsespec,
1680 "port", parseport,
1681 "size", parsesize,
1682 "irq", parseirq,
1683 "type", parsetype,
1684 };
1685
1686 static void
legacytopctl(Cmdbuf * cb)1687 legacytopctl(Cmdbuf *cb)
1688 {
1689 char *opt;
1690 int i, j;
1691 Confdata cd;
1692
1693 memset(&cd, 0, sizeof cd);
1694 cd.on = -1;
1695 for(i=0; i<cb->nf; i+=2){
1696 if(i+2 > cb->nf)
1697 error(Ebadarg);
1698 opt = cb->f[i];
1699 for(j=0; j<nelem(options); j++)
1700 if(strcmp(opt, options[j].name) == 0){
1701 options[j].parse(&cd, cb->f[i+1]);
1702 break;
1703 }
1704 if(j == nelem(options))
1705 error(Ebadarg);
1706 }
1707 /* this has been rewritten to accomodate sdaoe */
1708 if(cd.on < 0 || cd.spec == 0)
1709 error(Ebadarg);
1710 if(cd.on && cd.cf.type == nil)
1711 error(Ebadarg);
1712 sdconfig(cd.on, cd.spec, &cd.cf);
1713 }
1714