|
|
1.1 root 1: #include "u.h"
2: #include "../port/lib.h"
3: #include "mem.h"
4: #include "dat.h"
5: #include "fns.h"
6: #include "io.h"
7: #include "../port/error.h"
8:
9: #include "devtab.h"
10:
11: #define DPRINT if(0)print
12:
13: typedef struct Drive Drive;
14: typedef struct Ident Ident;
15: typedef struct Controller Controller;
16: typedef struct Partition Partition;
17: typedef struct Repl Repl;
18:
19: enum
20: {
21: /* ports */
22: Pbase0= 0x1F0,
23: Pbase1= 0x170,
24: Pdata= 0, /* data port (16 bits) */
25: Perror= 1, /* error port (read) */
26: Pprecomp= 1, /* buffer mode port (write) */
27: Pcount= 2, /* sector count port */
28: Psector= 3, /* sector number port */
29: Pcyllsb= 4, /* least significant byte cylinder # */
30: Pcylmsb= 5, /* most significant byte cylinder # */
31: Pdh= 6, /* drive/head port */
32: Pstatus= 7, /* status port (read) */
33: Sbusy= (1<<7),
34: Sready= (1<<6),
35: Sdrq= (1<<3),
36: Serr= (1<<0),
37: Pcmd= 7, /* cmd port (write) */
38:
39: /* commands */
40: Crecal= 0x10,
41: Cread= 0x20,
42: Cwrite= 0x30,
43: Cident= 0xEC,
44: Cident2= 0xFF, /* pseudo command for post Cident interrupt */
45: Csetbuf= 0xEF,
46: Cinitparam= 0x91,
47:
48: /* conner specific commands */
49: Cstandby= 0xE2,
50: Cidle= 0xE1,
51: Cpowerdown= 0xE3,
52:
53: /* disk states */
54: Sspinning,
55: Sstandby,
56: Sidle,
57: Spowerdown,
58:
59: /* something we have to or into the drive/head reg */
60: DHmagic= 0xA0,
61:
62: /* file types */
63: Qdir= 0,
64:
65: Maxxfer= BY2PG, /* maximum transfer size/cmd */
66: Npart= 8+2, /* 8 sub partitions, disk, and partition */
67: Nrepl= 64, /* maximum replacement blocks */
68:
69: Hardtimeout= 4000, /* disk access timeout */
70: };
71: #define PART(x) ((x)&0xF)
72: #define DRIVE(x) (((x)>>4)&0x7)
73: #define MKQID(d,p) (((d)<<4) | (p))
74:
75: struct Partition
76: {
77: ulong start;
78: ulong end;
79: char name[NAMELEN+1];
80: };
81:
82: struct Repl
83: {
84: Partition *p;
85: int nrepl;
86: ulong blk[Nrepl];
87: };
88:
89: #define PARTMAGIC "plan9 partitions"
90: #define REPLMAGIC "block replacements"
91:
92: /*
93: * an ata drive
94: */
95: struct Drive
96: {
97: QLock;
98:
99: Controller *cp;
100: int drive;
101: int confused; /* needs to be recalibrated (or worse) */
102: int online;
103: int npart; /* number of real partitions */
104: Partition p[Npart];
105: Repl repl;
106: ulong usetime;
107: int state;
108: char vol[NAMELEN];
109:
110: ulong cap; /* total bytes */
111: int bytes; /* bytes/sector */
112: int sectors; /* sectors/track */
113: int heads; /* heads/cyl */
114: long cyl; /* cylinders/drive */
115:
116: char lba; /* true if drive has logical block addressing */
117: char multi; /* non-zero if drive does multiple block xfers */
118: };
119:
120: /*
121: * a controller for 2 drives
122: */
123: struct Controller
124: {
125: QLock; /* exclusive access to the controller */
126:
127: Lock reglock; /* exclusive access to the registers */
128:
129: int confused; /* needs to be recalibrated (or worse) */
130: int pbase; /* base port */
131:
132: /*
133: * current operation
134: */
135: int cmd; /* current command */
136: int lastcmd; /* debugging info */
137: Rendez r; /* wait here for command termination */
138: char *buf; /* xfer buffer */
139: int nsecs; /* length of transfer (sectors) */
140: int sofar; /* sectors transferred so far */
141: int status;
142: int error;
143: Drive *dp; /* drive being accessed */
144: };
145:
146: Controller *atac;
147: Drive *ata;
148: static int spindowntime;
149:
150: static void ataintr(Ureg*, void*);
151: static long ataxfer(Drive*, Partition*, int, long, long, char*);
152: static void ataident(Drive*);
153: static void atasetbuf(Drive*, int);
154: static void ataparams(Drive*);
155: static void atapart(Drive*);
156: static int ataprobe(Drive*, int, int, int);
157:
158: static int
159: atagen(Chan *c, Dirtab *tab, long ntab, long s, Dir *dirp)
160: {
161: Qid qid;
162: int drive;
163: char name[NAMELEN+4];
164: Drive *dp;
165: Partition *pp;
166: ulong l;
167:
168: USED(tab, ntab);
169: qid.vers = 0;
170: drive = s/Npart;
171: s = s % Npart;
172: if(drive >= conf.nhard)
173: return -1;
174: dp = &ata[drive];
175:
176: if(dp->online == 0 || s >= dp->npart)
177: return 0;
178:
179: pp = &dp->p[s];
180: sprint(name, "%s%s", dp->vol, pp->name);
181: name[NAMELEN] = 0;
182: qid.path = MKQID(drive, s);
183: l = (pp->end - pp->start) * dp->bytes;
184: devdir(c, qid, name, l, eve, 0660, dirp);
185: return 1;
186: }
187:
188: void
189: atareset(void)
190: {
191: Drive *dp;
192: Controller *cp;
193: uchar equip;
194: char *p;
195:
196: equip = nvramread(0x12);
197: if(equip == 0)
198: equip = 0x10; /* the Globalyst 250 lies */
199:
200: ata = xalloc(2 * sizeof(Drive));
201: atac = xalloc(sizeof(Controller));
202:
203: cp = atac;
204: cp->buf = 0;
205: cp->lastcmd = cp->cmd;
206: cp->cmd = 0;
207: cp->pbase = Pbase0;
208: setvec(ATAvec0, ataintr, 0);
209:
210: dp = ata;
211: if(equip & 0xf0){
212: dp->drive = 0;
213: dp->online = 0;
214: dp->cp = cp;
215: dp++;
216: }
217: if((equip & 0x0f)){
218: dp->drive = 1;
219: dp->online = 0;
220: dp->cp = cp;
221: dp++;
222: }
223: conf.nhard = dp - ata;
224:
225: if(conf.nhard && (p = getconf("spindowntime")))
226: spindowntime = atoi(p);
227: }
228:
229: void
230: atainit(void)
231: {
232: }
233:
234: /*
235: * Get the characteristics of each drive. Mark unresponsive ones
236: * off line.
237: */
238: Chan*
239: ataattach(char *spec)
240: {
241: Drive *dp;
242:
243: for(dp = ata; dp < &ata[conf.nhard]; dp++){
244: if(waserror()){
245: dp->online = 0;
246: qunlock(dp);
247: continue;
248: }
249: qlock(dp);
250: if(!dp->online){
251: /*
252: * Make sure ataclock() doesn't
253: * interfere.
254: */
255: dp->usetime = m->ticks;
256: ataparams(dp);
257: dp->online = 1;
258: atasetbuf(dp, 1);
259: }
260:
261: /*
262: * read Plan 9 partition table
263: */
264: atapart(dp);
265: qunlock(dp);
266: poperror();
267: }
268: return devattach('H', spec);
269: }
270:
271: Chan*
272: ataclone(Chan *c, Chan *nc)
273: {
274: return devclone(c, nc);
275: }
276:
277: int
278: atawalk(Chan *c, char *name)
279: {
280: return devwalk(c, name, 0, 0, atagen);
281: }
282:
283: void
284: atastat(Chan *c, char *dp)
285: {
286: devstat(c, dp, 0, 0, atagen);
287: }
288:
289: Chan*
290: ataopen(Chan *c, int omode)
291: {
292: return devopen(c, omode, 0, 0, atagen);
293: }
294:
295: void
296: atacreate(Chan *c, char *name, int omode, ulong perm)
297: {
298: USED(c, name, omode, perm);
299: error(Eperm);
300: }
301:
302: void
303: ataclose(Chan *c)
304: {
305: Drive *d;
306: Partition *p;
307:
308: if(c->mode != OWRITE && c->mode != ORDWR)
309: return;
310:
311: d = &ata[DRIVE(c->qid.path)];
312: p = &d->p[PART(c->qid.path)];
313: if(strcmp(p->name, "partition") != 0)
314: return;
315:
316: if(waserror()){
317: qunlock(d);
318: nexterror();
319: }
320: qlock(d);
321: atapart(d);
322: qunlock(d);
323: poperror();
324: }
325:
326: void
327: ataremove(Chan *c)
328: {
329: USED(c);
330: error(Eperm);
331: }
332:
333: void
334: atawstat(Chan *c, char *dp)
335: {
336: USED(c, dp);
337: error(Eperm);
338: }
339:
340: long
341: ataread(Chan *c, void *a, long n, ulong offset)
342: {
343: Drive *dp;
344: long rv, i;
345: int skip;
346: uchar *aa = a;
347: Partition *pp;
348: char *buf;
349:
350: if(c->qid.path == CHDIR)
351: return devdirread(c, a, n, 0, 0, atagen);
352:
353: buf = smalloc(Maxxfer);
354: if(waserror()){
355: free(buf);
356: nexterror();
357: }
358:
359: dp = &ata[DRIVE(c->qid.path)];
360: pp = &dp->p[PART(c->qid.path)];
361:
362: skip = offset % dp->bytes;
363: for(rv = 0; rv < n; rv += i){
364: i = ataxfer(dp, pp, Cread, offset+rv-skip, n-rv+skip, buf);
365: if(i == 0)
366: break;
367: i -= skip;
368: if(i > n - rv)
369: i = n - rv;
370: memmove(aa+rv, buf + skip, i);
371: skip = 0;
372: }
373:
374: free(buf);
375: poperror();
376:
377: return rv;
378: }
379:
380: long
381: atawrite(Chan *c, void *a, long n, ulong offset)
382: {
383: Drive *dp;
384: long rv, i, partial;
385: uchar *aa = a;
386: Partition *pp;
387: char *buf;
388:
389: if(c->qid.path == CHDIR)
390: error(Eisdir);
391:
392: dp = &ata[DRIVE(c->qid.path)];
393: pp = &dp->p[PART(c->qid.path)];
394: buf = smalloc(Maxxfer);
395: if(waserror()){
396: free(buf);
397: nexterror();
398: }
399:
400: /*
401: * if not starting on a sector boundary,
402: * read in the first sector before writing
403: * it out.
404: */
405: partial = offset % dp->bytes;
406: if(partial){
407: ataxfer(dp, pp, Cread, offset-partial, dp->bytes, buf);
408: if(partial+n > dp->bytes)
409: rv = dp->bytes - partial;
410: else
411: rv = n;
412: memmove(buf+partial, aa, rv);
413: ataxfer(dp, pp, Cwrite, offset-partial, dp->bytes, buf);
414: } else
415: rv = 0;
416:
417: /*
418: * write out the full sectors
419: */
420: partial = (n - rv) % dp->bytes;
421: n -= partial;
422: for(; rv < n; rv += i){
423: i = n - rv;
424: if(i > Maxxfer)
425: i = Maxxfer;
426: memmove(buf, aa+rv, i);
427: i = ataxfer(dp, pp, Cwrite, offset+rv, i, buf);
428: if(i == 0)
429: break;
430: }
431:
432: /*
433: * if not ending on a sector boundary,
434: * read in the last sector before writing
435: * it out.
436: */
437: if(partial){
438: ataxfer(dp, pp, Cread, offset+rv, dp->bytes, buf);
439: memmove(buf, aa+rv, partial);
440: ataxfer(dp, pp, Cwrite, offset+rv, dp->bytes, buf);
441: rv += partial;
442: }
443:
444: free(buf);
445: poperror();
446:
447: return rv;
448: }
449:
450: /*
451: * did an interrupt happen?
452: */
453: static int
454: cmddone(void *a)
455: {
456: Controller *cp = a;
457:
458: return cp->cmd == 0;
459: }
460:
461: /*
462: * Wait for the controller to be ready to accept a command.
463: * This is protected from intereference by ataclock() by
464: * setting dp->usetime before it is called.
465: */
466: static void
467: cmdreadywait(Drive *dp)
468: {
469: long start;
470: int period;
471: Controller *cp = dp->cp;
472:
473: /* give it 2 seconds to spin down and up */
474: if(dp->state == Sspinning)
475: period = 10;
476: else
477: period = 2000;
478:
479: start = m->ticks;
480: while((inb(cp->pbase+Pstatus) & (Sready|Sbusy)) != Sready)
481: if(TK2MS(m->ticks - start) > period){
482: DPRINT("cmdreadywait failed\n");
483: error(Eio);
484: }
485: }
486:
487: static void
488: atarepl(Drive *dp, long bblk)
489: {
490: int i;
491:
492: if(dp->repl.p == 0)
493: return;
494: for(i = 0; i < dp->repl.nrepl; i++){
495: if(dp->repl.blk[i] == bblk)
496: DPRINT("found bblk %ld at offset %ld\n", bblk, i);
497: }
498: }
499:
500: static void
501: atasleep(Controller *cp)
502: {
503: tsleep(&cp->r, cmddone, cp, Hardtimeout);
504: if(cp->cmd && cp->cmd != Cident2){
505: DPRINT("hard drive timeout\n");
506: error("ata drive timeout");
507: }
508: }
509:
510:
511: /*
512: * transfer a number of sectors. ataintr will perform all the iterative
513: * parts.
514: */
515: static long
516: ataxfer(Drive *dp, Partition *pp, int cmd, long start, long len, char *buf)
517: {
518: Controller *cp;
519: long lblk;
520: int cyl, sec, head;
521: int loop, stat;
522:
523: if(dp->online == 0)
524: error(Eio);
525:
526: /*
527: * cut transfer size down to disk buffer size
528: */
529: start = start / dp->bytes;
530: if(len > Maxxfer)
531: len = Maxxfer;
532: len = (len + dp->bytes - 1) / dp->bytes;
533: if(len == 0)
534: return 0;
535:
536: /*
537: * calculate physical address
538: */
539: lblk = start + pp->start;
540: if(lblk >= pp->end)
541: return 0;
542: if(lblk+len > pp->end)
543: len = pp->end - lblk;
544: if(dp->lba){
545: sec = lblk & 0xff;
546: cyl = (lblk>>8) & 0xffff;
547: head = (lblk>>24) & 0xf;
548: } else {
549: cyl = lblk/(dp->sectors*dp->heads);
550: sec = (lblk % dp->sectors) + 1;
551: head = ((lblk/dp->sectors) % dp->heads);
552: }
553:
554: cp = dp->cp;
555: qlock(cp);
556: if(waserror()){
557: cp->buf = 0;
558: qunlock(cp);
559: nexterror();
560: }
561:
562: /*
563: * Make sure hardclock() doesn't
564: * interfere.
565: */
566: dp->usetime = m->ticks;
567: cmdreadywait(dp);
568:
569: ilock(&cp->reglock);
570: cp->sofar = 0;
571: cp->buf = buf;
572: cp->nsecs = len;
573: cp->cmd = cmd;
574: cp->dp = dp;
575: cp->status = 0;
576:
577: outb(cp->pbase+Pcount, cp->nsecs);
578: outb(cp->pbase+Psector, sec);
579: outb(cp->pbase+Pdh, DHmagic | (dp->drive<<4) | (dp->lba<<6) | head);
580: outb(cp->pbase+Pcyllsb, cyl);
581: outb(cp->pbase+Pcylmsb, cyl>>8);
582: outb(cp->pbase+Pcmd, cmd);
583:
584: if(cmd == Cwrite){
585: loop = 0;
586: while((stat = inb(cp->pbase+Pstatus) & (Serr|Sdrq)) == 0)
587: if(++loop > 10000)
588: panic("ataxfer");
589: outss(cp->pbase+Pdata, cp->buf, dp->bytes/2);
590: } else
591: stat = 0;
592: iunlock(&cp->reglock);
593:
594: if(stat & Serr)
595: error(Eio);
596:
597: /*
598: * wait for command to complete. if we get a note,
599: * remember it but keep waiting to let the disk finish
600: * the current command.
601: */
602: loop = 0;
603: while(waserror()){
604: DPRINT("interrupted ataxfer\n");
605: if(loop++ > 10){
606: print("ata disk error\n");
607: nexterror();
608: }
609: }
610: atasleep(cp);
611: dp->state = Sspinning;
612: dp->usetime = m->ticks;
613: poperror();
614: if(loop)
615: nexterror();
616:
617: if(cp->status & Serr){
618: DPRINT("hd%d err: lblk %ld status %lux, err %lux\n",
619: dp-ata, lblk, cp->status, cp->error);
620: DPRINT("\tcyl %d, sec %d, head %d\n", cyl, sec, head);
621: DPRINT("\tnsecs %d, sofar %d\n", cp->nsecs, cp->sofar);
622: atarepl(dp, lblk+cp->sofar);
623: error(Eio);
624: }
625: cp->buf = 0;
626: len = cp->sofar*dp->bytes;
627: qunlock(cp);
628: poperror();
629:
630: return len;
631: }
632:
633: /*
634: * set read ahead mode
635: */
636: static void
637: atasetbuf(Drive *dp, int on)
638: {
639: Controller *cp = dp->cp;
640:
641: qlock(cp);
642: if(waserror()){
643: qunlock(cp);
644: nexterror();
645: }
646:
647: cmdreadywait(dp);
648:
649: ilock(&cp->reglock);
650: cp->cmd = Csetbuf;
651: outb(cp->pbase+Pprecomp, on ? 0xAA : 0x55); /* read look ahead */
652: outb(cp->pbase+Pdh, DHmagic | (dp->drive<<4));
653: outb(cp->pbase+Pcmd, Csetbuf);
654: iunlock(&cp->reglock);
655:
656: atasleep(cp);
657:
658: /* if(cp->status & Serr)
659: DPRINT("hd%d setbuf err: status %lux, err %lux\n",
660: dp-ata, cp->status, cp->error);/**/
661:
662: poperror();
663: qunlock(cp);
664: }
665:
666: /*
667: * ident sector from drive. this is from ANSI X3.221-1994
668: */
669: struct Ident
670: {
671: ushort config; /* general configuration info */
672: ushort cyls; /* # of cylinders (default) */
673: ushort reserved0;
674: ushort heads; /* # of heads (default) */
675: ushort b2t; /* unformatted bytes/track */
676: ushort b2s; /* unformated bytes/sector */
677: ushort s2t; /* sectors/track (default) */
678: ushort reserved1[3];
679: /* 10 */
680: ushort serial[10]; /* serial number */
681: ushort type; /* buffer type */
682: ushort bsize; /* buffer size/512 */
683: ushort ecc; /* ecc bytes returned by read long */
684: ushort firm[4]; /* firmware revision */
685: ushort model[20]; /* model number */
686: /* 47 */
687: ushort s2i; /* number of sectors/interrupt */
688: ushort dwtf; /* double word transfer flag */
689: ushort capabilities;
690: ushort reserved2;
691: ushort piomode;
692: ushort dmamode;
693: ushort cvalid; /* (cvald&1) if next 4 words are valid */
694: ushort ccyls; /* current # cylinders */
695: ushort cheads; /* current # heads */
696: ushort cs2t; /* current sectors/track */
697: ushort ccap[2]; /* current capacity in sectors */
698: ushort cs2i; /* current number of sectors/interrupt */
699: /* 60 */
700: ushort lbasecs[2]; /* # LBA user addressable sectors */
701: ushort dmasingle;
702: ushort dmadouble;
703: /* 64 */
704: ushort reserved3[64];
705: ushort vendor[32]; /* vendor specific */
706: ushort reserved4[96];
707: };
708:
709: /*
710: * get parameters from the drive
711: */
712: static void
713: ataident(Drive *dp)
714: {
715: Controller *cp;
716: char *buf;
717: Ident *ip;
718: char id[21];
719:
720: cp = dp->cp;
721: buf = smalloc(Maxxfer);
722: qlock(cp);
723: if(waserror()){
724: qunlock(cp);
725: nexterror();
726: }
727:
728: cmdreadywait(dp);
729:
730: ilock(&cp->reglock);
731: cp->nsecs = 1;
732: cp->sofar = 0;
733: cp->cmd = Cident;
734: cp->dp = dp;
735: cp->buf = buf;
736: outb(cp->pbase+Pdh, DHmagic | (dp->drive<<4));
737: outb(cp->pbase+Pcmd, Cident);
738: iunlock(&cp->reglock);
739:
740: atasleep(cp);
741:
742: if(cp->status & Serr){
743: DPRINT("bad disk ident status\n");
744: error(Eio);
745: }
746: ip = (Ident*)buf;
747:
748: /*
749: * this function appears to respond with an extra interrupt after
750: * the ident information is read, except on the safari. The following
751: * delay gives this extra interrupt a chance to happen while we are quiet.
752: * Otherwise, the interrupt may come during a subsequent read or write,
753: * causing a panic and much confusion.
754: */
755: if (cp->cmd == Cident2)
756: tsleep(&cp->r, return0, 0, Hardtimeout);
757:
758: memmove(id, ip->model, sizeof(id)-1);
759: id[sizeof(id)-1] = 0;
760:
761: if(ip->capabilities & (1<<9)){
762: dp->lba = 1;
763: dp->sectors = (ip->lbasecs[0]) | (ip->lbasecs[1]<<16);
764: dp->cap = dp->bytes * dp->sectors;
765: /*print("\nata%d model %s with %d lba sectors\n", dp->drive, id, dp->sectors);/**/
766: } else {
767: dp->lba = 0;
768:
769: /* use default (unformatted) settings */
770: dp->cyl = ip->cyls;
771: dp->heads = ip->heads;
772: dp->sectors = ip->s2t;
773: /*print("\nata%d model %s with default %d cyl %d head %d sec\n", dp->drive,
774: id, dp->cyl, dp->heads, dp->sectors);/**/
775:
776: if(ip->cvalid&(1<<0)){
777: /* use current settings */
778: dp->cyl = ip->ccyls;
779: dp->heads = ip->cheads;
780: dp->sectors = ip->cs2t;
781: /*print("\tchanged to %d cyl %d head %d sec\n", dp->cyl, dp->heads, dp->sectors);/**/
782: }
783: dp->cap = dp->bytes * dp->cyl * dp->heads * dp->sectors;
784: }
785: cp->lastcmd = cp->cmd;
786: cp->cmd = 0;
787: cp->buf = 0;
788: free(buf);
789: poperror();
790: qunlock(cp);
791: }
792:
793: /*
794: * probe the given sector to see if it exists
795: */
796: static int
797: ataprobe(Drive *dp, int cyl, int sec, int head)
798: {
799: Controller *cp;
800: char *buf;
801: int rv;
802:
803: cp = dp->cp;
804: buf = smalloc(Maxxfer);
805: qlock(cp);
806: if(waserror()){
807: free(buf);
808: qunlock(cp);
809: nexterror();
810: }
811:
812: cmdreadywait(dp);
813:
814: ilock(&cp->reglock);
815: cp->cmd = Cread;
816: cp->dp = dp;
817: cp->status = 0;
818: cp->nsecs = 1;
819: cp->sofar = 0;
820:
821: outb(cp->pbase+Pcount, 1);
822: outb(cp->pbase+Psector, sec+1);
823: outb(cp->pbase+Pdh, DHmagic | head | (dp->lba<<6) | (dp->drive<<4));
824: outb(cp->pbase+Pcyllsb, cyl);
825: outb(cp->pbase+Pcylmsb, cyl>>8);
826: outb(cp->pbase+Pcmd, Cread);
827: iunlock(&cp->reglock);
828:
829: atasleep(cp);
830:
831: if(cp->status & Serr)
832: rv = -1;
833: else
834: rv = 0;
835:
836: cp->buf = 0;
837: free(buf);
838: poperror();
839: qunlock(cp);
840: return rv;
841: }
842:
843: /*
844: * figure out the drive parameters
845: */
846: static void
847: ataparams(Drive *dp)
848: {
849: int i, hi, lo;
850:
851: /*
852: * first try the easy way, ask the drive and make sure it
853: * isn't lying.
854: */
855: dp->bytes = 512;
856: ataident(dp);
857: if(dp->lba){
858: i = dp->sectors - 1;
859: if(ataprobe(dp, (i>>8)&0xffff, (i&0xff)-1, (i>>24)&0xf) == 0)
860: return;
861: } else {
862: if(ataprobe(dp, dp->cyl-1, dp->sectors-1, dp->heads-1) == 0)
863: return;
864: }
865:
866: /*
867: * the drive lied, determine parameters by seeing which ones
868: * work to read sectors.
869: */
870: dp->lba = 0;
871: for(i = 0; i < 32; i++)
872: if(ataprobe(dp, 0, 0, i) < 0)
873: break;
874: dp->heads = i;
875: for(i = 0; i < 128; i++)
876: if(ataprobe(dp, 0, i, 0) < 0)
877: break;
878: dp->sectors = i;
879: for(i = 512; ; i += 512)
880: if(ataprobe(dp, i, dp->sectors-1, dp->heads-1) < 0)
881: break;
882: lo = i - 512;
883: hi = i;
884: for(; hi-lo > 1;){
885: i = lo + (hi - lo)/2;
886: if(ataprobe(dp, i, dp->sectors-1, dp->heads-1) < 0)
887: hi = i;
888: else
889: lo = i;
890: }
891: dp->cyl = lo + 1;
892: dp->cap = dp->bytes * dp->cyl * dp->heads * dp->sectors;
893: }
894:
895: /*
896: * Read block replacement table.
897: * The table is just ascii block numbers.
898: */
899: static void
900: atareplinit(Drive *dp)
901: {
902: char *line[Nrepl+1];
903: char *field[1];
904: ulong n;
905: int i;
906: char *buf;
907:
908: /*
909: * check the partition is big enough
910: */
911: if(dp->repl.p->end - dp->repl.p->start < Nrepl+1){
912: dp->repl.p = 0;
913: return;
914: }
915:
916: buf = smalloc(Maxxfer);
917: if(waserror()){
918: free(buf);
919: nexterror();
920: }
921:
922: /*
923: * read replacement table from disk, null terminate
924: */
925: ataxfer(dp, dp->repl.p, Cread, 0, dp->bytes, buf);
926: buf[dp->bytes-1] = 0;
927:
928: /*
929: * parse replacement table.
930: */
931: n = getfields(buf, line, Nrepl+1, "\n");
932: if(strncmp(line[0], REPLMAGIC, sizeof(REPLMAGIC)-1)){
933: dp->repl.p = 0;
934: } else {
935: for(dp->repl.nrepl = 0, i = 1; i < n; i++, dp->repl.nrepl++){
936: if(getfields(line[i], field, 1, " ") != 1)
937: break;
938: dp->repl.blk[dp->repl.nrepl] = strtoul(field[0], 0, 0);
939: if(dp->repl.blk[dp->repl.nrepl] <= 0)
940: break;
941: }
942: }
943: free(buf);
944: poperror();
945: }
946:
947: /*
948: * read partition table. The partition table is just ascii strings.
949: */
950: static void
951: atapart(Drive *dp)
952: {
953: Partition *pp;
954: char *line[Npart+1];
955: char *field[3];
956: ulong n;
957: int i;
958: char *buf;
959:
960: sprint(dp->vol, "hd%d", dp - ata);
961:
962: /*
963: * we always have a partition for the whole disk
964: * and one for the partition table
965: */
966: pp = &dp->p[0];
967: strcpy(pp->name, "disk");
968: pp->start = 0;
969: pp->end = dp->cap / dp->bytes;
970: pp++;
971: strcpy(pp->name, "partition");
972: pp->start = dp->p[0].end - 1;
973: pp->end = dp->p[0].end;
974: dp->npart = 2;
975:
976: /*
977: * initialise the bad-block replacement info
978: */
979: dp->repl.p = 0;
980:
981: buf = smalloc(Maxxfer);
982: if(waserror()){
983: free(buf);
984: nexterror();
985: }
986:
987: /*
988: * read last sector from disk, null terminate. This used
989: * to be the sector we used for the partition tables.
990: * However, this sector is special on some PC's so we've
991: * started to use the second last sector as the partition
992: * table instead. To avoid reconfiguring all our old systems
993: * we first look to see if there is a valid partition
994: * table in the last sector. If so, we use it. Otherwise
995: * we switch to the second last.
996: */
997: ataxfer(dp, pp, Cread, 0, dp->bytes, buf);
998: buf[dp->bytes-1] = 0;
999: n = getfields(buf, line, Npart+1, "\n");
1000: if(n == 0 || strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1)){
1001: dp->p[0].end--;
1002: dp->p[1].start--;
1003: dp->p[1].end--;
1004: ataxfer(dp, pp, Cread, 0, dp->bytes, buf);
1005: buf[dp->bytes-1] = 0;
1006: n = getfields(buf, line, Npart+1, "\n");
1007: }
1008:
1009: /*
1010: * parse partition table.
1011: */
1012: if(n && strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1) == 0){
1013: for(i = 1; i < n; i++){
1014: pp++;
1015: switch(getfields(line[i], field, 3, " ")) {
1016: case 2:
1017: if(strcmp(field[0], "unit") == 0)
1018: strncpy(dp->vol, field[1], NAMELEN);
1019: break;
1020: case 3:
1021: strncpy(pp->name, field[0], NAMELEN);
1022: if(strncmp(pp->name, "repl", NAMELEN) == 0)
1023: dp->repl.p = pp;
1024: pp->start = strtoul(field[1], 0, 0);
1025: pp->end = strtoul(field[2], 0, 0);
1026: if(pp->start > pp->end || pp->start >= dp->p[0].end)
1027: break;
1028: dp->npart++;
1029: }
1030: }
1031: }
1032: free(buf);
1033: poperror();
1034:
1035: if(dp->repl.p)
1036: atareplinit(dp);
1037: }
1038:
1039: enum
1040: {
1041: Maxloop= 10000,
1042: };
1043:
1044: /*
1045: * we get an interrupt for every sector transferred
1046: */
1047: static void
1048: ataintr(Ureg *ur, void *arg)
1049: {
1050: Controller *cp;
1051: Drive *dp;
1052: long loop;
1053: char *addr;
1054:
1055: USED(ur, arg);
1056:
1057: /*
1058: * BUG!! if there is ever more than one controller, we need a way to
1059: * distinguish which interrupted (use arg).
1060: */
1061: cp = &atac[0];
1062: dp = cp->dp;
1063:
1064: ilock(&cp->reglock);
1065:
1066: loop = 0;
1067: while((cp->status = inb(cp->pbase+Pstatus)) & Sbusy){
1068: if(++loop > Maxloop) {
1069: DPRINT("cmd=%lux status=%lux\n",
1070: cp->cmd, inb(cp->pbase+Pstatus));
1071: panic("ataintr: wait busy");
1072: }
1073: }
1074:
1075: switch(cp->cmd){
1076: case Cwrite:
1077: if(cp->status & Serr){
1078: cp->lastcmd = cp->cmd;
1079: cp->cmd = 0;
1080: cp->error = inb(cp->pbase+Perror);
1081: wakeup(&cp->r);
1082: break;
1083: }
1084: cp->sofar++;
1085: if(cp->sofar < cp->nsecs){
1086: loop = 0;
1087: while(((cp->status = inb(cp->pbase+Pstatus)) & Sdrq) == 0)
1088: if(++loop > Maxloop) {
1089: DPRINT("cmd=%lux status=%lux\n",
1090: cp->cmd, inb(cp->pbase+Pstatus));
1091: panic("ataintr: write");
1092: }
1093: addr = cp->buf;
1094: if(addr){
1095: addr += cp->sofar*dp->bytes;
1096: outss(cp->pbase+Pdata, addr, dp->bytes/2);
1097: }
1098: } else{
1099: cp->lastcmd = cp->cmd;
1100: cp->cmd = 0;
1101: wakeup(&cp->r);
1102: }
1103: break;
1104: case Cread:
1105: case Cident:
1106: loop = 0;
1107: while((cp->status & (Serr|Sdrq)) == 0){
1108: if(++loop > Maxloop) {
1109: DPRINT("cmd=%lux status=%lux\n",
1110: cp->cmd, inb(cp->pbase+Pstatus));
1111: panic("ataintr: read/ident");
1112: }
1113: cp->status = inb(cp->pbase+Pstatus);
1114: }
1115: if(cp->status & Serr){
1116: cp->lastcmd = cp->cmd;
1117: cp->cmd = 0;
1118: cp->error = inb(cp->pbase+Perror);
1119: wakeup(&cp->r);
1120: break;
1121: }
1122: addr = cp->buf;
1123: if(addr){
1124: addr += cp->sofar*dp->bytes;
1125: inss(cp->pbase+Pdata, addr, dp->bytes/2);
1126: }
1127: cp->sofar++;
1128: if(cp->sofar > cp->nsecs)
1129: print("ataintr %d %d\n", cp->sofar, cp->nsecs);
1130: if(cp->sofar >= cp->nsecs){
1131: cp->lastcmd = cp->cmd;
1132: if (cp->cmd == Cread)
1133: cp->cmd = 0;
1134: else
1135: cp->cmd = Cident2;
1136: wakeup(&cp->r);
1137: }
1138: break;
1139: case Cinitparam:
1140: case Csetbuf:
1141: case Cidle:
1142: case Cstandby:
1143: case Cpowerdown:
1144: cp->lastcmd = cp->cmd;
1145: cp->cmd = 0;
1146: wakeup(&cp->r);
1147: break;
1148: case Cident2:
1149: cp->lastcmd = cp->cmd;
1150: cp->cmd = 0;
1151: break;
1152: default:
1153: print("weird disk interrupt, cmd=%.2ux, lastcmd= %.2ux status=%.2ux\n",
1154: cp->cmd, cp->lastcmd, cp->status);
1155: break;
1156: }
1157:
1158: iunlock(&cp->reglock);
1159: }
1160:
1161: void
1162: hardclock(void)
1163: {
1164: int drive;
1165: Drive *dp;
1166: Controller *cp;
1167: int diff;
1168:
1169: if(spindowntime <= 0)
1170: return;
1171:
1172: for(drive = 0; drive < conf.nhard; drive++){
1173: dp = &ata[drive];
1174: cp = dp->cp;
1175:
1176: diff = TK2SEC(m->ticks - dp->usetime);
1177: if((dp->state == Sspinning) && (diff >= spindowntime)){
1178: ilock(&cp->reglock);
1179: cp->cmd = Cstandby;
1180: outb(cp->pbase+Pcount, 0);
1181: outb(cp->pbase+Pdh, DHmagic | (dp->drive<<4) | 0);
1182: outb(cp->pbase+Pcmd, cp->cmd);
1183: iunlock(&cp->reglock);
1184: dp->state = Sstandby;
1185: }
1186: }
1187: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.