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