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 ScmdRead:
968 case ScmdWrite:
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] != ScmdInq)
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 ScmdTur: /* test unit ready */
995 return sdsetsense(r, SDok, 0, 0, 0);
996
997 case ScmdRsense: /* 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 ScmdInq: /* 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 ScmdStart: /* 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 ScmdRcapacity: /* 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 ScmdRcapacity16: /* 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 ScmdMsense10: /* mode sense */
1075 return sdmodesense(r, cmd, info, ilen);
1076
1077 case ScmdExtread:
1078 case ScmdExtwrite:
1079 case ScmdRead16:
1080 case ScmdWrite16:
1081 return SDnostatus;
1082 }
1083 }
1084
1085 int
sdfakescsirw(SDreq * r,uvlong * llba,int * nsec,int * rwp)1086 sdfakescsirw(SDreq *r, uvlong *llba, int *nsec, int *rwp)
1087 {
1088 uchar *c;
1089 int rw, count;
1090 uvlong lba;
1091
1092 c = r->cmd;
1093 rw = 0;
1094 if((c[0] & 0xf) == 0xa)
1095 rw = 1;
1096 switch(c[0]){
1097 case 0x08: /* read6 */
1098 case 0x0a:
1099 lba = (c[1] & 0xf)<<16 | c[2]<<8 | c[3];
1100 count = c[4];
1101 break;
1102 case 0x28: /* read10 */
1103 case 0x2a:
1104 lba = c[2]<<24 | c[3]<<16 | c[4]<<8 | c[5];
1105 count = c[7]<<8 | c[8];
1106 break;
1107 case 0xa8: /* read12 */
1108 case 0xaa:
1109 lba = c[2]<<24 | c[3]<<16 | c[4]<<8 | c[5];
1110 count = c[6]<<24 | c[7]<<16 | c[8]<<8 | c[9];
1111 break;
1112 case 0x88: /* read16 */
1113 case 0x8a:
1114 /* ata commands only go to 48-bit lba */
1115 if(c[2] || c[3])
1116 return sdsetsense(r, SDcheck, 3, 0xc, 2);
1117 lba = (uvlong)c[4]<<40 | (uvlong)c[5]<<32;
1118 lba |= c[6]<<24 | c[7]<<16 | c[8]<<8 | c[9];
1119 count = c[10]<<24 | c[11]<<16 | c[12]<<8 | c[13];
1120 break;
1121 default:
1122 print("%s: bad cmd 0x%.2ux\n", r->unit->name, c[0]);
1123 r->status = sdsetsense(r, SDcheck, 0x05, 0x20, 0);
1124 return SDcheck;
1125 }
1126 if(r->data == nil)
1127 return SDok;
1128 if(r->dlen < count * r->unit->secsize)
1129 count = r->dlen/r->unit->secsize;
1130 if(rwp)
1131 *rwp = rw;
1132 *llba = lba;
1133 *nsec = count;
1134 return SDnostatus;
1135 }
1136
1137 static long
sdread(Chan * c,void * a,long n,vlong off)1138 sdread(Chan *c, void *a, long n, vlong off)
1139 {
1140 char *p, *e, *buf;
1141 SDpart *pp;
1142 SDunit *unit;
1143 SDev *sdev;
1144 ulong offset;
1145 int i, l, m, status;
1146
1147 offset = off;
1148 switch(TYPE(c->qid)){
1149 default:
1150 error(Eperm);
1151 case Qtopctl:
1152 m = 64*1024; /* room for register dumps */
1153 p = buf = malloc(m);
1154 if(p == nil)
1155 error(Enomem);
1156 e = p + m;
1157 qlock(&devslock);
1158 for(i = 0; i < nelem(devs); i++){
1159 sdev = devs[i];
1160 if(sdev && sdev->ifc->rtopctl)
1161 p = sdev->ifc->rtopctl(sdev, p, e);
1162 }
1163 qunlock(&devslock);
1164 n = readstr(off, a, n, buf);
1165 free(buf);
1166 return n;
1167
1168 case Qtopdir:
1169 case Qunitdir:
1170 return devdirread(c, a, n, 0, 0, sdgen);
1171
1172 case Qctl:
1173 sdev = sdgetdev(DEV(c->qid));
1174 if(sdev == nil)
1175 error(Enonexist);
1176
1177 unit = sdev->unit[UNIT(c->qid)];
1178 m = 16*1024; /* room for register dumps */
1179 p = malloc(m);
1180 if(p == nil)
1181 error(Enomem);
1182 l = snprint(p, m, "inquiry %.48s\n",
1183 (char*)unit->inquiry+8);
1184 qlock(&unit->ctl);
1185 /*
1186 * If there's a device specific routine it must
1187 * provide all information pertaining to night geometry
1188 * and the garscadden trains.
1189 */
1190 if(unit->dev->ifc->rctl)
1191 l += unit->dev->ifc->rctl(unit, p+l, m-l);
1192 if(unit->sectors == 0)
1193 sdinitpart(unit);
1194 if(unit->sectors){
1195 if(unit->dev->ifc->rctl == nil)
1196 l += snprint(p+l, m-l,
1197 "geometry %llud %lud\n",
1198 unit->sectors, unit->secsize);
1199 pp = unit->part;
1200 for(i = 0; i < unit->npart; i++){
1201 if(pp->valid)
1202 l += snprint(p+l, m-l,
1203 "part %s %llud %llud\n",
1204 pp->name, pp->start, pp->end);
1205 pp++;
1206 }
1207 }
1208 qunlock(&unit->ctl);
1209 decref(&sdev->r);
1210 l = readstr(offset, a, n, p);
1211 free(p);
1212 return l;
1213
1214 case Qraw:
1215 sdev = sdgetdev(DEV(c->qid));
1216 if(sdev == nil)
1217 error(Enonexist);
1218
1219 unit = sdev->unit[UNIT(c->qid)];
1220 qlock(&unit->raw);
1221 if(waserror()){
1222 qunlock(&unit->raw);
1223 decref(&sdev->r);
1224 nexterror();
1225 }
1226 if(unit->state == Rawdata){
1227 unit->state = Rawstatus;
1228 i = sdrio(unit->req, a, n);
1229 }
1230 else if(unit->state == Rawstatus){
1231 status = unit->req->status;
1232 unit->state = Rawcmd;
1233 free(unit->req);
1234 unit->req = nil;
1235 i = readnum(0, a, n, status, NUMSIZE);
1236 } else
1237 i = 0;
1238 qunlock(&unit->raw);
1239 decref(&sdev->r);
1240 poperror();
1241 return i;
1242
1243 case Qpart:
1244 return sdbio(c, 0, a, n, off);
1245 }
1246 }
1247
1248 static void legacytopctl(Cmdbuf*);
1249
1250 static long
sdwrite(Chan * c,void * a,long n,vlong off)1251 sdwrite(Chan* c, void* a, long n, vlong off)
1252 {
1253 char *f0;
1254 int i;
1255 uvlong end, start;
1256 Cmdbuf *cb;
1257 SDifc *ifc;
1258 SDreq *req;
1259 SDunit *unit;
1260 SDev *sdev;
1261
1262 switch(TYPE(c->qid)){
1263 default:
1264 error(Eperm);
1265 case Qtopctl:
1266 cb = parsecmd(a, n);
1267 if(waserror()){
1268 free(cb);
1269 nexterror();
1270 }
1271 if(cb->nf == 0)
1272 error("empty control message");
1273 f0 = cb->f[0];
1274 cb->f++;
1275 cb->nf--;
1276 if(strcmp(f0, "config") == 0){
1277 /* wormhole into ugly legacy interface */
1278 legacytopctl(cb);
1279 poperror();
1280 free(cb);
1281 break;
1282 }
1283 /*
1284 * "ata arg..." invokes sdifc[i]->wtopctl(nil, cb),
1285 * where sdifc[i]->name=="ata" and cb contains the args.
1286 */
1287 ifc = nil;
1288 sdev = nil;
1289 for(i=0; sdifc[i]; i++){
1290 if(strcmp(sdifc[i]->name, f0) == 0){
1291 ifc = sdifc[i];
1292 sdev = nil;
1293 goto subtopctl;
1294 }
1295 }
1296 /*
1297 * "sd1 arg..." invokes sdifc[i]->wtopctl(sdev, cb),
1298 * where sdifc[i] and sdev match controller letter "1",
1299 * and cb contains the args.
1300 */
1301 if(f0[0]=='s' && f0[1]=='d' && f0[2] && f0[3] == 0){
1302 if((sdev = sdgetdev(f0[2])) != nil){
1303 ifc = sdev->ifc;
1304 goto subtopctl;
1305 }
1306 }
1307 error("unknown interface");
1308
1309 subtopctl:
1310 if(waserror()){
1311 if(sdev)
1312 decref(&sdev->r);
1313 nexterror();
1314 }
1315 if(ifc->wtopctl)
1316 ifc->wtopctl(sdev, cb);
1317 else
1318 error(Ebadctl);
1319 poperror();
1320 poperror();
1321 if (sdev)
1322 decref(&sdev->r);
1323 free(cb);
1324 break;
1325
1326 case Qctl:
1327 cb = parsecmd(a, n);
1328 sdev = sdgetdev(DEV(c->qid));
1329 if(sdev == nil)
1330 error(Enonexist);
1331 unit = sdev->unit[UNIT(c->qid)];
1332
1333 qlock(&unit->ctl);
1334 if(waserror()){
1335 qunlock(&unit->ctl);
1336 decref(&sdev->r);
1337 free(cb);
1338 nexterror();
1339 }
1340 if(unit->vers != c->qid.vers)
1341 error(Echange);
1342
1343 if(cb->nf < 1)
1344 error(Ebadctl);
1345 if(strcmp(cb->f[0], "part") == 0){
1346 if(cb->nf != 4)
1347 error(Ebadctl);
1348 if(unit->sectors == 0 && !sdinitpart(unit))
1349 error(Eio);
1350 start = strtoull(cb->f[2], 0, 0);
1351 end = strtoull(cb->f[3], 0, 0);
1352 sdaddpart(unit, cb->f[1], start, end);
1353 }
1354 else if(strcmp(cb->f[0], "delpart") == 0){
1355 if(cb->nf != 2 || unit->part == nil)
1356 error(Ebadctl);
1357 sddelpart(unit, cb->f[1]);
1358 }
1359 else if(unit->dev->ifc->wctl)
1360 unit->dev->ifc->wctl(unit, cb);
1361 else
1362 error(Ebadctl);
1363 qunlock(&unit->ctl);
1364 decref(&sdev->r);
1365 poperror();
1366 free(cb);
1367 break;
1368
1369 case Qraw:
1370 sdev = sdgetdev(DEV(c->qid));
1371 if(sdev == nil)
1372 error(Enonexist);
1373 unit = sdev->unit[UNIT(c->qid)];
1374 qlock(&unit->raw);
1375 if(waserror()){
1376 qunlock(&unit->raw);
1377 decref(&sdev->r);
1378 nexterror();
1379 }
1380 switch(unit->state){
1381 case Rawcmd:
1382 if(n < 6 || n > sizeof(req->cmd))
1383 error(Ebadarg);
1384 if((req = malloc(sizeof(SDreq))) == nil)
1385 error(Enomem);
1386 req->unit = unit;
1387 memmove(req->cmd, a, n);
1388 req->clen = n;
1389 req->flags = SDnosense;
1390 req->status = ~0;
1391
1392 unit->req = req;
1393 unit->state = Rawdata;
1394 break;
1395
1396 case Rawstatus:
1397 unit->state = Rawcmd;
1398 free(unit->req);
1399 unit->req = nil;
1400 error(Ebadusefd);
1401
1402 case Rawdata:
1403 unit->state = Rawstatus;
1404 unit->req->write = 1;
1405 n = sdrio(unit->req, a, n);
1406 }
1407 qunlock(&unit->raw);
1408 decref(&sdev->r);
1409 poperror();
1410 break;
1411 case Qpart:
1412 return sdbio(c, 1, a, n, off);
1413 }
1414
1415 return n;
1416 }
1417
1418 static int
sdwstat(Chan * c,uchar * dp,int n)1419 sdwstat(Chan* c, uchar* dp, int n)
1420 {
1421 Dir *d;
1422 SDpart *pp;
1423 SDperm *perm;
1424 SDunit *unit;
1425 SDev *sdev;
1426
1427 if(c->qid.type & QTDIR)
1428 error(Eperm);
1429
1430 sdev = sdgetdev(DEV(c->qid));
1431 if(sdev == nil)
1432 error(Enonexist);
1433 unit = sdev->unit[UNIT(c->qid)];
1434 qlock(&unit->ctl);
1435 d = nil;
1436 if(waserror()){
1437 free(d);
1438 qunlock(&unit->ctl);
1439 decref(&sdev->r);
1440 nexterror();
1441 }
1442
1443 switch(TYPE(c->qid)){
1444 default:
1445 error(Eperm);
1446 case Qctl:
1447 perm = &unit->ctlperm;
1448 break;
1449 case Qraw:
1450 perm = &unit->rawperm;
1451 break;
1452 case Qpart:
1453 pp = &unit->part[PART(c->qid)];
1454 if(unit->vers+pp->vers != c->qid.vers)
1455 error(Enonexist);
1456 perm = &pp->SDperm;
1457 break;
1458 }
1459
1460 if(strcmp(up->user, perm->user) && !iseve())
1461 error(Eperm);
1462
1463 d = smalloc(sizeof(Dir)+n);
1464 n = convM2D(dp, n, &d[0], (char*)&d[1]);
1465 if(n == 0)
1466 error(Eshortstat);
1467 if(!emptystr(d[0].uid))
1468 kstrdup(&perm->user, d[0].uid);
1469 if(d[0].mode != ~0UL)
1470 perm->perm = (perm->perm & ~0777) | (d[0].mode & 0777);
1471
1472 free(d);
1473 qunlock(&unit->ctl);
1474 decref(&sdev->r);
1475 poperror();
1476 return n;
1477 }
1478
1479 static int
configure(char * spec,DevConf * cf)1480 configure(char* spec, DevConf* cf)
1481 {
1482 SDev *s, *sdev;
1483 char *p;
1484 int i;
1485
1486 if(sdindex(*spec) < 0)
1487 error("bad sd spec");
1488
1489 if((p = strchr(cf->type, '/')) != nil)
1490 *p++ = '\0';
1491
1492 for(i = 0; sdifc[i] != nil; i++)
1493 if(strcmp(sdifc[i]->name, cf->type) == 0)
1494 break;
1495 if(sdifc[i] == nil)
1496 error("sd type not found");
1497 if(p)
1498 *(p-1) = '/';
1499
1500 if(sdifc[i]->probe == nil)
1501 error("sd type cannot probe");
1502
1503 sdev = sdifc[i]->probe(cf);
1504 for(s=sdev; s; s=s->next)
1505 s->idno = *spec;
1506 sdadddevs(sdev);
1507 return 0;
1508 }
1509
1510 static int
unconfigure(char * spec)1511 unconfigure(char* spec)
1512 {
1513 int i;
1514 SDev *sdev;
1515 SDunit *unit;
1516
1517 if((i = sdindex(*spec)) < 0)
1518 error(Enonexist);
1519
1520 qlock(&devslock);
1521 if((sdev = devs[i]) == nil){
1522 qunlock(&devslock);
1523 error(Enonexist);
1524 }
1525 if(sdev->r.ref){
1526 qunlock(&devslock);
1527 error(Einuse);
1528 }
1529 devs[i] = nil;
1530 qunlock(&devslock);
1531
1532 /* make sure no interrupts arrive anymore before removing resources */
1533 if(sdev->enabled && sdev->ifc->disable)
1534 sdev->ifc->disable(sdev);
1535
1536 for(i = 0; i != sdev->nunit; i++){
1537 if(unit = sdev->unit[i]){
1538 free(unit->name);
1539 free(unit->user);
1540 free(unit);
1541 }
1542 }
1543
1544 if(sdev->ifc->clear)
1545 sdev->ifc->clear(sdev);
1546 free(sdev);
1547 return 0;
1548 }
1549
1550 static int
sdconfig(int on,char * spec,DevConf * cf)1551 sdconfig(int on, char* spec, DevConf* cf)
1552 {
1553 if(on)
1554 return configure(spec, cf);
1555 return unconfigure(spec);
1556 }
1557
1558 Dev sddevtab = {
1559 'S',
1560 "sd",
1561
1562 sdreset,
1563 devinit,
1564 devshutdown,
1565 sdattach,
1566 sdwalk,
1567 sdstat,
1568 sdopen,
1569 devcreate,
1570 sdclose,
1571 sdread,
1572 devbread,
1573 sdwrite,
1574 devbwrite,
1575 devremove,
1576 sdwstat,
1577 devpower,
1578 sdconfig, /* probe; only called for pcmcia-like devices */
1579 };
1580
1581 /*
1582 * This is wrong for so many reasons. This code must go.
1583 */
1584 typedef struct Confdata Confdata;
1585 struct Confdata {
1586 int on;
1587 char* spec;
1588 DevConf cf;
1589 };
1590
1591 static void
parseswitch(Confdata * cd,char * option)1592 parseswitch(Confdata* cd, char* option)
1593 {
1594 if(!strcmp("on", option))
1595 cd->on = 1;
1596 else if(!strcmp("off", option))
1597 cd->on = 0;
1598 else
1599 error(Ebadarg);
1600 }
1601
1602 static void
parsespec(Confdata * cd,char * option)1603 parsespec(Confdata* cd, char* option)
1604 {
1605 if(strlen(option) > 1)
1606 error(Ebadarg);
1607 cd->spec = option;
1608 }
1609
1610 static Devport*
getnewport(DevConf * dc)1611 getnewport(DevConf* dc)
1612 {
1613 Devport *p;
1614
1615 p = (Devport *)malloc((dc->nports + 1) * sizeof(Devport));
1616 if(p == nil)
1617 error(Enomem);
1618 if(dc->nports > 0){
1619 memmove(p, dc->ports, dc->nports * sizeof(Devport));
1620 free(dc->ports);
1621 }
1622 dc->ports = p;
1623 p = &dc->ports[dc->nports++];
1624 p->size = -1;
1625 p->port = (ulong)-1;
1626 return p;
1627 }
1628
1629 static void
parseport(Confdata * cd,char * option)1630 parseport(Confdata* cd, char* option)
1631 {
1632 char *e;
1633 Devport *p;
1634
1635 if(cd->cf.nports == 0 || cd->cf.ports[cd->cf.nports-1].port != (ulong)-1)
1636 p = getnewport(&cd->cf);
1637 else
1638 p = &cd->cf.ports[cd->cf.nports-1];
1639 p->port = strtol(option, &e, 0);
1640 if(e == nil || *e != '\0')
1641 error(Ebadarg);
1642 }
1643
1644 static void
parsesize(Confdata * cd,char * option)1645 parsesize(Confdata* cd, char* option)
1646 {
1647 char *e;
1648 Devport *p;
1649
1650 if(cd->cf.nports == 0 || cd->cf.ports[cd->cf.nports-1].size != -1)
1651 p = getnewport(&cd->cf);
1652 else
1653 p = &cd->cf.ports[cd->cf.nports-1];
1654 p->size = (int)strtol(option, &e, 0);
1655 if(e == nil || *e != '\0')
1656 error(Ebadarg);
1657 }
1658
1659 static void
parseirq(Confdata * cd,char * option)1660 parseirq(Confdata* cd, char* option)
1661 {
1662 char *e;
1663
1664 cd->cf.intnum = strtoul(option, &e, 0);
1665 if(e == nil || *e != '\0')
1666 error(Ebadarg);
1667 }
1668
1669 static void
parsetype(Confdata * cd,char * option)1670 parsetype(Confdata* cd, char* option)
1671 {
1672 cd->cf.type = option;
1673 }
1674
1675 static struct {
1676 char *name;
1677 void (*parse)(Confdata*, char*);
1678 } options[] = {
1679 "switch", parseswitch,
1680 "spec", parsespec,
1681 "port", parseport,
1682 "size", parsesize,
1683 "irq", parseirq,
1684 "type", parsetype,
1685 };
1686
1687 static void
legacytopctl(Cmdbuf * cb)1688 legacytopctl(Cmdbuf *cb)
1689 {
1690 char *opt;
1691 int i, j;
1692 Confdata cd;
1693
1694 memset(&cd, 0, sizeof cd);
1695 cd.on = -1;
1696 for(i=0; i<cb->nf; i+=2){
1697 if(i+2 > cb->nf)
1698 error(Ebadarg);
1699 opt = cb->f[i];
1700 for(j=0; j<nelem(options); j++)
1701 if(strcmp(opt, options[j].name) == 0){
1702 options[j].parse(&cd, cb->f[i+1]);
1703 break;
1704 }
1705 if(j == nelem(options))
1706 error(Ebadarg);
1707 }
1708 /* this has been rewritten to accomodate sdaoe */
1709 if(cd.on < 0 || cd.spec == 0)
1710 error(Ebadarg);
1711 if(cd.on && cd.cf.type == nil)
1712 error(Ebadarg);
1713 sdconfig(cd.on, cd.spec, &cd.cf);
1714 }
1715