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->dev = (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 int
sdstat(Chan * c,uchar * db,int n)652 sdstat(Chan* c, uchar* db, int 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,uvlong off)732 sdbio(Chan* c, int write, char* a, long len, uvlong off)
733 {
734 int nchange;
735 long l;
736 uchar *b;
737 SDpart *pp;
738 SDunit *unit;
739 SDev *sdev;
740 ulong max, nb, offset;
741 uvlong bno;
742
743 sdev = sdgetdev(DEV(c->qid));
744 if(sdev == nil){
745 decref(&sdev->r);
746 error(Enonexist);
747 }
748 unit = sdev->unit[UNIT(c->qid)];
749 if(unit == nil)
750 error(Enonexist);
751
752 nchange = 0;
753 qlock(&unit->ctl);
754 while(waserror()){
755 /* notification of media change; go around again */
756 if(strcmp(up->errstr, Eio) == 0 && unit->sectors == 0 && nchange++ == 0){
757 sdinitpart(unit);
758 continue;
759 }
760
761 /* other errors; give up */
762 qunlock(&unit->ctl);
763 decref(&sdev->r);
764 nexterror();
765 }
766 pp = &unit->part[PART(c->qid)];
767 if(unit->vers+pp->vers != c->qid.vers)
768 error(Echange);
769
770 /*
771 * Check the request is within bounds.
772 * Removeable drives are locked throughout the I/O
773 * in case the media changes unexpectedly.
774 * Non-removeable drives are not locked during the I/O
775 * to allow the hardware to optimise if it can; this is
776 * a little fast and loose.
777 * It's assumed that non-removeable media parameters
778 * (sectors, secsize) can't change once the drive has
779 * been brought online.
780 */
781 bno = (off/unit->secsize) + pp->start;
782 nb = ((off+len+unit->secsize-1)/unit->secsize) + pp->start - bno;
783 max = SDmaxio/unit->secsize;
784 if(nb > max)
785 nb = max;
786 if(bno+nb > pp->end)
787 nb = pp->end - bno;
788 if(bno >= pp->end || nb == 0){
789 if(write)
790 error(Eio);
791 qunlock(&unit->ctl);
792 decref(&sdev->r);
793 poperror();
794 return 0;
795 }
796 if(!(unit->inquiry[1] & SDinq1removable)){
797 qunlock(&unit->ctl);
798 poperror();
799 }
800
801 b = sdmalloc(nb*unit->secsize);
802 if(b == nil)
803 error(Enomem);
804 if(waserror()){
805 sdfree(b);
806 if(!(unit->inquiry[1] & SDinq1removable))
807 decref(&sdev->r); /* gadverdamme! */
808 nexterror();
809 }
810
811 offset = off%unit->secsize;
812 if(offset+len > nb*unit->secsize)
813 len = nb*unit->secsize - offset;
814 if(write){
815 if(offset || (len%unit->secsize)){
816 l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno);
817 if(l < 0)
818 error(Eio);
819 if(l < (nb*unit->secsize)){
820 nb = l/unit->secsize;
821 l = nb*unit->secsize - offset;
822 if(len > l)
823 len = l;
824 }
825 }
826 memmove(b+offset, a, len);
827 l = unit->dev->ifc->bio(unit, 0, 1, b, nb, bno);
828 if(l < 0)
829 error(Eio);
830 if(l < offset)
831 len = 0;
832 else if(len > l - offset)
833 len = l - offset;
834 }
835 else{
836 l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno);
837 if(l < 0)
838 error(Eio);
839 if(l < offset)
840 len = 0;
841 else if(len > l - offset)
842 len = l - offset;
843 memmove(a, b+offset, len);
844 }
845 sdfree(b);
846 poperror();
847
848 if(unit->inquiry[1] & SDinq1removable){
849 qunlock(&unit->ctl);
850 poperror();
851 }
852
853 decref(&sdev->r);
854 return len;
855 }
856
857 static long
sdrio(SDreq * r,void * a,long n)858 sdrio(SDreq* r, void* a, long n)
859 {
860 void *data;
861
862 if(n >= SDmaxio || n < 0)
863 error(Etoobig);
864
865 data = nil;
866 if(n){
867 if((data = sdmalloc(n)) == nil)
868 error(Enomem);
869 if(r->write)
870 memmove(data, a, n);
871 }
872 r->data = data;
873 r->dlen = n;
874
875 if(waserror()){
876 sdfree(data);
877 r->data = nil;
878 nexterror();
879 }
880
881 if(r->unit->dev->ifc->rio(r) != SDok)
882 error(Eio);
883
884 if(!r->write && r->rlen > 0)
885 memmove(a, data, r->rlen);
886 sdfree(data);
887 r->data = nil;
888 poperror();
889
890 return r->rlen;
891 }
892
893 /*
894 * SCSI simulation for non-SCSI devices
895 */
896 int
sdsetsense(SDreq * r,int status,int key,int asc,int ascq)897 sdsetsense(SDreq *r, int status, int key, int asc, int ascq)
898 {
899 int len;
900 SDunit *unit;
901
902 unit = r->unit;
903 unit->sense[2] = key;
904 unit->sense[12] = asc;
905 unit->sense[13] = ascq;
906
907 r->status = status;
908 if(status == SDcheck && !(r->flags & SDnosense)){
909 /* request sense case from sdfakescsi */
910 len = sizeof unit->sense;
911 if(len > sizeof r->sense-1)
912 len = sizeof r->sense-1;
913 memmove(r->sense, unit->sense, len);
914 unit->sense[2] = 0;
915 unit->sense[12] = 0;
916 unit->sense[13] = 0;
917 r->flags |= SDvalidsense;
918 return SDok;
919 }
920 return status;
921 }
922
923 int
sdmodesense(SDreq * r,uchar * cmd,void * info,int ilen)924 sdmodesense(SDreq *r, uchar *cmd, void *info, int ilen)
925 {
926 int len;
927 uchar *data;
928
929 /*
930 * Fake a vendor-specific request with page code 0,
931 * return the drive info.
932 */
933 if((cmd[2] & 0x3F) != 0 && (cmd[2] & 0x3F) != 0x3F)
934 return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
935 len = (cmd[7]<<8)|cmd[8];
936 if(len == 0)
937 return SDok;
938 if(len < 8+ilen)
939 return sdsetsense(r, SDcheck, 0x05, 0x1A, 0);
940 if(r->data == nil || r->dlen < len)
941 return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
942 data = r->data;
943 memset(data, 0, 8);
944 data[0] = ilen>>8;
945 data[1] = ilen;
946 if(ilen)
947 memmove(data+8, info, ilen);
948 r->rlen = 8+ilen;
949 return sdsetsense(r, SDok, 0, 0, 0);
950 }
951
952 int
sdfakescsi(SDreq * r,void * info,int ilen)953 sdfakescsi(SDreq *r, void *info, int ilen)
954 {
955 uchar *cmd, *p;
956 uvlong len;
957 SDunit *unit;
958
959 cmd = r->cmd;
960 r->rlen = 0;
961 unit = r->unit;
962
963 /*
964 * Rewrite read(6)/write(6) into read(10)/write(10).
965 */
966 switch(cmd[0]){
967 case 0x08: /* read */
968 case 0x0A: /* write */
969 cmd[9] = 0;
970 cmd[8] = cmd[4];
971 cmd[7] = 0;
972 cmd[6] = 0;
973 cmd[5] = cmd[3];
974 cmd[4] = cmd[2];
975 cmd[3] = cmd[1] & 0x0F;
976 cmd[2] = 0;
977 cmd[1] &= 0xE0;
978 cmd[0] |= 0x20;
979 break;
980 }
981
982 /*
983 * Map SCSI commands into ATA commands for discs.
984 * Fail any command with a LUN except INQUIRY which
985 * will return 'logical unit not supported'.
986 */
987 if((cmd[1]>>5) && cmd[0] != 0x12)
988 return sdsetsense(r, SDcheck, 0x05, 0x25, 0);
989
990 switch(cmd[0]){
991 default:
992 return sdsetsense(r, SDcheck, 0x05, 0x20, 0);
993
994 case 0x00: /* test unit ready */
995 return sdsetsense(r, SDok, 0, 0, 0);
996
997 case 0x03: /* request sense */
998 if(cmd[4] < sizeof unit->sense)
999 len = cmd[4];
1000 else
1001 len = sizeof unit->sense;
1002 if(r->data && r->dlen >= len){
1003 memmove(r->data, unit->sense, len);
1004 r->rlen = len;
1005 }
1006 return sdsetsense(r, SDok, 0, 0, 0);
1007
1008 case 0x12: /* inquiry */
1009 if(cmd[4] < sizeof unit->inquiry)
1010 len = cmd[4];
1011 else
1012 len = sizeof unit->inquiry;
1013 if(r->data && r->dlen >= len){
1014 memmove(r->data, unit->inquiry, len);
1015 r->rlen = len;
1016 }
1017 return sdsetsense(r, SDok, 0, 0, 0);
1018
1019 case 0x1B: /* start/stop unit */
1020 /*
1021 * nop for now, can use power management later.
1022 */
1023 return sdsetsense(r, SDok, 0, 0, 0);
1024
1025 case 0x25: /* read capacity */
1026 if((cmd[1] & 0x01) || cmd[2] || cmd[3])
1027 return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
1028 if(r->data == nil || r->dlen < 8)
1029 return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
1030
1031 /*
1032 * Read capacity returns the LBA of the last sector.
1033 */
1034 len = unit->sectors - 1;
1035 p = r->data;
1036 *p++ = len>>24;
1037 *p++ = len>>16;
1038 *p++ = len>>8;
1039 *p++ = len;
1040 len = 512;
1041 *p++ = len>>24;
1042 *p++ = len>>16;
1043 *p++ = len>>8;
1044 *p++ = len;
1045 r->rlen = p - (uchar*)r->data;
1046 return sdsetsense(r, SDok, 0, 0, 0);
1047
1048 case 0x9E: /* long read capacity */
1049 if((cmd[1] & 0x01) || cmd[2] || cmd[3])
1050 return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
1051 if(r->data == nil || r->dlen < 8)
1052 return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
1053 /*
1054 * Read capcity returns the LBA of the last sector.
1055 */
1056 len = unit->sectors - 1;
1057 p = r->data;
1058 *p++ = len>>56;
1059 *p++ = len>>48;
1060 *p++ = len>>40;
1061 *p++ = len>>32;
1062 *p++ = len>>24;
1063 *p++ = len>>16;
1064 *p++ = len>>8;
1065 *p++ = len;
1066 len = 512;
1067 *p++ = len>>24;
1068 *p++ = len>>16;
1069 *p++ = len>>8;
1070 *p++ = len;
1071 r->rlen = p - (uchar*)r->data;
1072 return sdsetsense(r, SDok, 0, 0, 0);
1073
1074 case 0x5A: /* mode sense */
1075 return sdmodesense(r, cmd, info, ilen);
1076
1077 case 0x28: /* read */
1078 case 0x2A: /* write */
1079 case 0x88: /* read16 */
1080 case 0x8a: /* write16 */
1081 return SDnostatus;
1082 }
1083 }
1084
1085 static long
sdread(Chan * c,void * a,long n,vlong off)1086 sdread(Chan *c, void *a, long n, vlong off)
1087 {
1088 char *p, *e, *buf;
1089 SDpart *pp;
1090 SDunit *unit;
1091 SDev *sdev;
1092 ulong offset;
1093 int i, l, m, status;
1094
1095 offset = off;
1096 switch(TYPE(c->qid)){
1097 default:
1098 error(Eperm);
1099 case Qtopctl:
1100 m = 64*1024; /* room for register dumps */
1101 p = buf = malloc(m);
1102 if(p == nil)
1103 error(Enomem);
1104 e = p + m;
1105 qlock(&devslock);
1106 for(i = 0; i < nelem(devs); i++){
1107 sdev = devs[i];
1108 if(sdev && sdev->ifc->rtopctl)
1109 p = sdev->ifc->rtopctl(sdev, p, e);
1110 }
1111 qunlock(&devslock);
1112 n = readstr(off, a, n, buf);
1113 free(buf);
1114 return n;
1115
1116 case Qtopdir:
1117 case Qunitdir:
1118 return devdirread(c, a, n, 0, 0, sdgen);
1119
1120 case Qctl:
1121 sdev = sdgetdev(DEV(c->qid));
1122 if(sdev == nil)
1123 error(Enonexist);
1124
1125 unit = sdev->unit[UNIT(c->qid)];
1126 m = 16*1024; /* room for register dumps */
1127 p = malloc(m);
1128 if(p == nil)
1129 error(Enomem);
1130 l = snprint(p, m, "inquiry %.48s\n",
1131 (char*)unit->inquiry+8);
1132 qlock(&unit->ctl);
1133 /*
1134 * If there's a device specific routine it must
1135 * provide all information pertaining to night geometry
1136 * and the garscadden trains.
1137 */
1138 if(unit->dev->ifc->rctl)
1139 l += unit->dev->ifc->rctl(unit, p+l, m-l);
1140 if(unit->sectors == 0)
1141 sdinitpart(unit);
1142 if(unit->sectors){
1143 if(unit->dev->ifc->rctl == nil)
1144 l += snprint(p+l, m-l,
1145 "geometry %llud %lud\n",
1146 unit->sectors, unit->secsize);
1147 pp = unit->part;
1148 for(i = 0; i < unit->npart; i++){
1149 if(pp->valid)
1150 l += snprint(p+l, m-l,
1151 "part %s %llud %llud\n",
1152 pp->name, pp->start, pp->end);
1153 pp++;
1154 }
1155 }
1156 qunlock(&unit->ctl);
1157 decref(&sdev->r);
1158 l = readstr(offset, a, n, p);
1159 free(p);
1160 return l;
1161
1162 case Qraw:
1163 sdev = sdgetdev(DEV(c->qid));
1164 if(sdev == nil)
1165 error(Enonexist);
1166
1167 unit = sdev->unit[UNIT(c->qid)];
1168 qlock(&unit->raw);
1169 if(waserror()){
1170 qunlock(&unit->raw);
1171 decref(&sdev->r);
1172 nexterror();
1173 }
1174 if(unit->state == Rawdata){
1175 unit->state = Rawstatus;
1176 i = sdrio(unit->req, a, n);
1177 }
1178 else if(unit->state == Rawstatus){
1179 status = unit->req->status;
1180 unit->state = Rawcmd;
1181 free(unit->req);
1182 unit->req = nil;
1183 i = readnum(0, a, n, status, NUMSIZE);
1184 } else
1185 i = 0;
1186 qunlock(&unit->raw);
1187 decref(&sdev->r);
1188 poperror();
1189 return i;
1190
1191 case Qpart:
1192 return sdbio(c, 0, a, n, off);
1193 }
1194 }
1195
1196 static void legacytopctl(Cmdbuf*);
1197
1198 static long
sdwrite(Chan * c,void * a,long n,vlong off)1199 sdwrite(Chan* c, void* a, long n, vlong off)
1200 {
1201 char *f0;
1202 int i;
1203 uvlong end, start;
1204 Cmdbuf *cb;
1205 SDifc *ifc;
1206 SDreq *req;
1207 SDunit *unit;
1208 SDev *sdev;
1209
1210 switch(TYPE(c->qid)){
1211 default:
1212 error(Eperm);
1213 case Qtopctl:
1214 cb = parsecmd(a, n);
1215 if(waserror()){
1216 free(cb);
1217 nexterror();
1218 }
1219 if(cb->nf == 0)
1220 error("empty control message");
1221 f0 = cb->f[0];
1222 cb->f++;
1223 cb->nf--;
1224 if(strcmp(f0, "config") == 0){
1225 /* wormhole into ugly legacy interface */
1226 legacytopctl(cb);
1227 poperror();
1228 free(cb);
1229 break;
1230 }
1231 /*
1232 * "ata arg..." invokes sdifc[i]->wtopctl(nil, cb),
1233 * where sdifc[i]->name=="ata" and cb contains the args.
1234 */
1235 ifc = nil;
1236 sdev = nil;
1237 for(i=0; sdifc[i]; i++){
1238 if(strcmp(sdifc[i]->name, f0) == 0){
1239 ifc = sdifc[i];
1240 sdev = nil;
1241 goto subtopctl;
1242 }
1243 }
1244 /*
1245 * "sd1 arg..." invokes sdifc[i]->wtopctl(sdev, cb),
1246 * where sdifc[i] and sdev match controller letter "1",
1247 * and cb contains the args.
1248 */
1249 if(f0[0]=='s' && f0[1]=='d' && f0[2] && f0[3] == 0){
1250 if((sdev = sdgetdev(f0[2])) != nil){
1251 ifc = sdev->ifc;
1252 goto subtopctl;
1253 }
1254 }
1255 error("unknown interface");
1256
1257 subtopctl:
1258 if(waserror()){
1259 if(sdev)
1260 decref(&sdev->r);
1261 nexterror();
1262 }
1263 if(ifc->wtopctl)
1264 ifc->wtopctl(sdev, cb);
1265 else
1266 error(Ebadctl);
1267 poperror();
1268 poperror();
1269 if (sdev)
1270 decref(&sdev->r);
1271 free(cb);
1272 break;
1273
1274 case Qctl:
1275 cb = parsecmd(a, n);
1276 sdev = sdgetdev(DEV(c->qid));
1277 if(sdev == nil)
1278 error(Enonexist);
1279 unit = sdev->unit[UNIT(c->qid)];
1280
1281 qlock(&unit->ctl);
1282 if(waserror()){
1283 qunlock(&unit->ctl);
1284 decref(&sdev->r);
1285 free(cb);
1286 nexterror();
1287 }
1288 if(unit->vers != c->qid.vers)
1289 error(Echange);
1290
1291 if(cb->nf < 1)
1292 error(Ebadctl);
1293 if(strcmp(cb->f[0], "part") == 0){
1294 if(cb->nf != 4)
1295 error(Ebadctl);
1296 if(unit->sectors == 0 && !sdinitpart(unit))
1297 error(Eio);
1298 start = strtoull(cb->f[2], 0, 0);
1299 end = strtoull(cb->f[3], 0, 0);
1300 sdaddpart(unit, cb->f[1], start, end);
1301 }
1302 else if(strcmp(cb->f[0], "delpart") == 0){
1303 if(cb->nf != 2 || unit->part == nil)
1304 error(Ebadctl);
1305 sddelpart(unit, cb->f[1]);
1306 }
1307 else if(unit->dev->ifc->wctl)
1308 unit->dev->ifc->wctl(unit, cb);
1309 else
1310 error(Ebadctl);
1311 qunlock(&unit->ctl);
1312 decref(&sdev->r);
1313 poperror();
1314 free(cb);
1315 break;
1316
1317 case Qraw:
1318 sdev = sdgetdev(DEV(c->qid));
1319 if(sdev == nil)
1320 error(Enonexist);
1321 unit = sdev->unit[UNIT(c->qid)];
1322 qlock(&unit->raw);
1323 if(waserror()){
1324 qunlock(&unit->raw);
1325 decref(&sdev->r);
1326 nexterror();
1327 }
1328 switch(unit->state){
1329 case Rawcmd:
1330 if(n < 6 || n > sizeof(req->cmd))
1331 error(Ebadarg);
1332 if((req = malloc(sizeof(SDreq))) == nil)
1333 error(Enomem);
1334 req->unit = unit;
1335 memmove(req->cmd, a, n);
1336 req->clen = n;
1337 req->flags = SDnosense;
1338 req->status = ~0;
1339
1340 unit->req = req;
1341 unit->state = Rawdata;
1342 break;
1343
1344 case Rawstatus:
1345 unit->state = Rawcmd;
1346 free(unit->req);
1347 unit->req = nil;
1348 error(Ebadusefd);
1349
1350 case Rawdata:
1351 unit->state = Rawstatus;
1352 unit->req->write = 1;
1353 n = sdrio(unit->req, a, n);
1354 }
1355 qunlock(&unit->raw);
1356 decref(&sdev->r);
1357 poperror();
1358 break;
1359 case Qpart:
1360 return sdbio(c, 1, a, n, off);
1361 }
1362
1363 return n;
1364 }
1365
1366 static int
sdwstat(Chan * c,uchar * dp,int n)1367 sdwstat(Chan* c, uchar* dp, int n)
1368 {
1369 Dir *d;
1370 SDpart *pp;
1371 SDperm *perm;
1372 SDunit *unit;
1373 SDev *sdev;
1374
1375 if(c->qid.type & QTDIR)
1376 error(Eperm);
1377
1378 sdev = sdgetdev(DEV(c->qid));
1379 if(sdev == nil)
1380 error(Enonexist);
1381 unit = sdev->unit[UNIT(c->qid)];
1382 qlock(&unit->ctl);
1383 d = nil;
1384 if(waserror()){
1385 free(d);
1386 qunlock(&unit->ctl);
1387 decref(&sdev->r);
1388 nexterror();
1389 }
1390
1391 switch(TYPE(c->qid)){
1392 default:
1393 error(Eperm);
1394 case Qctl:
1395 perm = &unit->ctlperm;
1396 break;
1397 case Qraw:
1398 perm = &unit->rawperm;
1399 break;
1400 case Qpart:
1401 pp = &unit->part[PART(c->qid)];
1402 if(unit->vers+pp->vers != c->qid.vers)
1403 error(Enonexist);
1404 perm = &pp->SDperm;
1405 break;
1406 }
1407
1408 if(strcmp(up->user, perm->user) && !iseve())
1409 error(Eperm);
1410
1411 d = smalloc(sizeof(Dir)+n);
1412 n = convM2D(dp, n, &d[0], (char*)&d[1]);
1413 if(n == 0)
1414 error(Eshortstat);
1415 if(!emptystr(d[0].uid))
1416 kstrdup(&perm->user, d[0].uid);
1417 if(d[0].mode != ~0UL)
1418 perm->perm = (perm->perm & ~0777) | (d[0].mode & 0777);
1419
1420 free(d);
1421 qunlock(&unit->ctl);
1422 decref(&sdev->r);
1423 poperror();
1424 return n;
1425 }
1426
1427 static int
configure(char * spec,DevConf * cf)1428 configure(char* spec, DevConf* cf)
1429 {
1430 SDev *s, *sdev;
1431 char *p;
1432 int i;
1433
1434 if(sdindex(*spec) < 0)
1435 error("bad sd spec");
1436
1437 if((p = strchr(cf->type, '/')) != nil)
1438 *p++ = '\0';
1439
1440 for(i = 0; sdifc[i] != nil; i++)
1441 if(strcmp(sdifc[i]->name, cf->type) == 0)
1442 break;
1443 if(sdifc[i] == nil)
1444 error("sd type not found");
1445 if(p)
1446 *(p-1) = '/';
1447
1448 if(sdifc[i]->probe == nil)
1449 error("sd type cannot probe");
1450
1451 sdev = sdifc[i]->probe(cf);
1452 for(s=sdev; s; s=s->next)
1453 s->idno = *spec;
1454 sdadddevs(sdev);
1455 return 0;
1456 }
1457
1458 static int
unconfigure(char * spec)1459 unconfigure(char* spec)
1460 {
1461 int i;
1462 SDev *sdev;
1463 SDunit *unit;
1464
1465 if((i = sdindex(*spec)) < 0)
1466 error(Enonexist);
1467
1468 qlock(&devslock);
1469 if((sdev = devs[i]) == nil){
1470 qunlock(&devslock);
1471 error(Enonexist);
1472 }
1473 if(sdev->r.ref){
1474 qunlock(&devslock);
1475 error(Einuse);
1476 }
1477 devs[i] = nil;
1478 qunlock(&devslock);
1479
1480 /* make sure no interrupts arrive anymore before removing resources */
1481 if(sdev->enabled && sdev->ifc->disable)
1482 sdev->ifc->disable(sdev);
1483
1484 for(i = 0; i != sdev->nunit; i++){
1485 if(unit = sdev->unit[i]){
1486 free(unit->name);
1487 free(unit->user);
1488 free(unit);
1489 }
1490 }
1491
1492 if(sdev->ifc->clear)
1493 sdev->ifc->clear(sdev);
1494 free(sdev);
1495 return 0;
1496 }
1497
1498 static int
sdconfig(int on,char * spec,DevConf * cf)1499 sdconfig(int on, char* spec, DevConf* cf)
1500 {
1501 if(on)
1502 return configure(spec, cf);
1503 return unconfigure(spec);
1504 }
1505
1506 Dev sddevtab = {
1507 'S',
1508 "sd",
1509
1510 sdreset,
1511 devinit,
1512 devshutdown,
1513 sdattach,
1514 sdwalk,
1515 sdstat,
1516 sdopen,
1517 devcreate,
1518 sdclose,
1519 sdread,
1520 devbread,
1521 sdwrite,
1522 devbwrite,
1523 devremove,
1524 sdwstat,
1525 devpower,
1526 sdconfig, /* probe; only called for pcmcia-like devices */
1527 };
1528
1529 /*
1530 * This is wrong for so many reasons. This code must go.
1531 */
1532 typedef struct Confdata Confdata;
1533 struct Confdata {
1534 int on;
1535 char* spec;
1536 DevConf cf;
1537 };
1538
1539 static void
parseswitch(Confdata * cd,char * option)1540 parseswitch(Confdata* cd, char* option)
1541 {
1542 if(!strcmp("on", option))
1543 cd->on = 1;
1544 else if(!strcmp("off", option))
1545 cd->on = 0;
1546 else
1547 error(Ebadarg);
1548 }
1549
1550 static void
parsespec(Confdata * cd,char * option)1551 parsespec(Confdata* cd, char* option)
1552 {
1553 if(strlen(option) > 1)
1554 error(Ebadarg);
1555 cd->spec = option;
1556 }
1557
1558 static Devport*
getnewport(DevConf * dc)1559 getnewport(DevConf* dc)
1560 {
1561 Devport *p;
1562
1563 p = (Devport *)malloc((dc->nports + 1) * sizeof(Devport));
1564 if(p == nil)
1565 error(Enomem);
1566 if(dc->nports > 0){
1567 memmove(p, dc->ports, dc->nports * sizeof(Devport));
1568 free(dc->ports);
1569 }
1570 dc->ports = p;
1571 p = &dc->ports[dc->nports++];
1572 p->size = -1;
1573 p->port = (ulong)-1;
1574 return p;
1575 }
1576
1577 static void
parseport(Confdata * cd,char * option)1578 parseport(Confdata* cd, char* option)
1579 {
1580 char *e;
1581 Devport *p;
1582
1583 if(cd->cf.nports == 0 || cd->cf.ports[cd->cf.nports-1].port != (ulong)-1)
1584 p = getnewport(&cd->cf);
1585 else
1586 p = &cd->cf.ports[cd->cf.nports-1];
1587 p->port = strtol(option, &e, 0);
1588 if(e == nil || *e != '\0')
1589 error(Ebadarg);
1590 }
1591
1592 static void
parsesize(Confdata * cd,char * option)1593 parsesize(Confdata* cd, char* option)
1594 {
1595 char *e;
1596 Devport *p;
1597
1598 if(cd->cf.nports == 0 || cd->cf.ports[cd->cf.nports-1].size != -1)
1599 p = getnewport(&cd->cf);
1600 else
1601 p = &cd->cf.ports[cd->cf.nports-1];
1602 p->size = (int)strtol(option, &e, 0);
1603 if(e == nil || *e != '\0')
1604 error(Ebadarg);
1605 }
1606
1607 static void
parseirq(Confdata * cd,char * option)1608 parseirq(Confdata* cd, char* option)
1609 {
1610 char *e;
1611
1612 cd->cf.intnum = strtoul(option, &e, 0);
1613 if(e == nil || *e != '\0')
1614 error(Ebadarg);
1615 }
1616
1617 static void
parsetype(Confdata * cd,char * option)1618 parsetype(Confdata* cd, char* option)
1619 {
1620 cd->cf.type = option;
1621 }
1622
1623 static struct {
1624 char *name;
1625 void (*parse)(Confdata*, char*);
1626 } options[] = {
1627 "switch", parseswitch,
1628 "spec", parsespec,
1629 "port", parseport,
1630 "size", parsesize,
1631 "irq", parseirq,
1632 "type", parsetype,
1633 };
1634
1635 static void
legacytopctl(Cmdbuf * cb)1636 legacytopctl(Cmdbuf *cb)
1637 {
1638 char *opt;
1639 int i, j;
1640 Confdata cd;
1641
1642 memset(&cd, 0, sizeof cd);
1643 cd.on = -1;
1644 for(i=0; i<cb->nf; i+=2){
1645 if(i+2 > cb->nf)
1646 error(Ebadarg);
1647 opt = cb->f[i];
1648 for(j=0; j<nelem(options); j++)
1649 if(strcmp(opt, options[j].name) == 0){
1650 options[j].parse(&cd, cb->f[i+1]);
1651 break;
1652 }
1653 if(j == nelem(options))
1654 error(Ebadarg);
1655 }
1656 /* this has been rewritten to accomodate sdaoe */
1657 if(cd.on < 0 || cd.spec == 0)
1658 error(Ebadarg);
1659 if(cd.on && cd.cf.type == nil)
1660 error(Ebadarg);
1661 sdconfig(cd.on, cd.spec, &cd.cf);
1662 }
1663