|
|
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: #include "devtab.h"
9:
10: /* Intel 82077A (8272A compatible) floppy controller */
11:
12: /* This module expects the following functions to be defined
13: * elsewhere:
14: *
15: * inb()
16: * outb()
17: * floppyexec()
18: * floppyeject()
19: * floppysetup0()
20: * floppysetup1()
21: * dmasetup()
22: * dmaend()
23: *
24: * On DMA systems, floppyexec() should be an empty function;
25: * on non-DMA systems, dmaend() should be an empty function;
26: * dmasetup() may enforce maximum transfer sizes.
27: */
28:
29: enum {
30: /* file types */
31: Qdir= 0,
32: Qdata= (1<<2),
33: Qctl= (2<<2),
34: Qmask= (3<<2),
35:
36: DMAchan= 2, /* floppy dma channel */
37: };
38:
39: #define DPRINT if(floppydebug)kprint
40: int floppydebug;
41:
42: /*
43: * types of drive (from PC equipment byte)
44: */
45: enum
46: {
47: Tnone= 0,
48: T360kb= 1,
49: T1200kb= 2,
50: T720kb= 3,
51: T1440kb= 4,
52: };
53:
54: FType floppytype[] =
55: {
56: { "3½HD", T1440kb, 512, 18, 2, 1, 80, 0x1B, 0x54, 0, },
57: { "3½DD", T1440kb, 512, 9, 2, 1, 80, 0x1B, 0x54, 2, },
58: { "3½DD", T720kb, 512, 9, 2, 1, 80, 0x1B, 0x54, 2, },
59: { "5¼HD", T1200kb, 512, 15, 2, 1, 80, 0x2A, 0x50, 0, },
60: { "5¼DD", T1200kb, 512, 9, 2, 2, 40, 0x2A, 0x50, 1, },
61: { "ATT3B1", T1200kb, 512, 8, 2, 2, 48, 0x2A, 0x50, 1, },
62: { "5¼DD", T360kb, 512, 9, 2, 1, 40, 0x2A, 0x50, 2, },
63: };
64: #define NTYPES (sizeof(floppytype)/sizeof(FType))
65:
66: /*
67: * bytes per sector encoding for the controller.
68: * - index for b2c is is (bytes per sector/128).
69: * - index for c2b is code from b2c
70: */
71: static int b2c[] =
72: {
73: [1] 0,
74: [2] 1,
75: [4] 2,
76: [8] 3,
77: };
78: static int c2b[] =
79: {
80: 128,
81: 256,
82: 512,
83: 1024,
84: };
85:
86: FController fl;
87:
88: #define MOTORBIT(i) (1<<((i)+4))
89:
90: /*
91: * predeclared
92: */
93: static void floppykproc(void*);
94: static void floppypos(FDrive*,long);
95: static int floppyrecal(FDrive*);
96: static void floppyrevive(void);
97: static long floppyseek(FDrive*, long);
98: static int floppysense(void);
99: static void floppywait(void);
100: static long floppyxfer(FDrive*, int, void*, long, long);
101: static void floppyformat(FDrive*, char*);
102: static int cmddone(void*);
103: void Xdelay(int);
104:
105: Dirtab floppydir[]={
106: "fd0disk", {Qdata + 0}, 0, 0666,
107: "fd0ctl", {Qctl + 0}, 0, 0666,
108: "fd1disk", {Qdata + 1}, 0, 0666,
109: "fd1ctl", {Qctl + 1}, 0, 0666,
110: "fd2disk", {Qdata + 2}, 0, 0666,
111: "fd2ctl", {Qctl + 2}, 0, 0666,
112: "fd3disk", {Qdata + 3}, 0, 0666,
113: "fd3ctl", {Qctl + 3}, 0, 0666,
114: };
115: #define NFDIR 2 /* directory entries/drive */
116:
117: static void
118: fldump(void)
119: {
120: DPRINT("sra %ux srb %ux dor %ux msr %ux dir %ux\n", inb(Psra), inb(Psrb),
121: inb(Pdor), inb(Pmsr), inb(Pdir));
122: }
123:
124: /*
125: * set floppy drive to its default type
126: */
127: void
128: floppysetdef(FDrive *dp)
129: {
130: FType *t;
131:
132: for(t = floppytype; t < &floppytype[NTYPES]; t++)
133: if(dp->dt == t->dt){
134: dp->t = t;
135: floppydir[NFDIR*dp->dev].length = dp->t->cap;
136: break;
137: }
138: }
139:
140: void
141: floppyreset(void)
142: {
143: FDrive *dp;
144: FType *t;
145: ulong maxtsize;
146:
147: floppysetup0(&fl);
148:
149: /*
150: * init dependent parameters
151: */
152: maxtsize = 0;
153: for(t = floppytype; t < &floppytype[NTYPES]; t++){
154: t->cap = t->bytes * t->heads * t->sectors * t->tracks;
155: t->bcode = b2c[t->bytes/128];
156: t->tsize = t->bytes * t->sectors;
157: if(maxtsize < t->tsize)
158: maxtsize = t->tsize;
159: }
160:
161: /*
162: * allocate the drive storage
163: */
164: fl.d = xalloc(conf.nfloppy*sizeof(FDrive));
165: fl.selected = fl.d;
166:
167: /*
168: * stop the motors
169: */
170: fl.motor = 0;
171: delay(10);
172: outb(Pdor, fl.motor | Fintena | Fena);
173: delay(10);
174:
175: /*
176: * init drives
177: */
178: for(dp = fl.d; dp < &fl.d[conf.nfloppy]; dp++){
179: dp->dev = dp - fl.d;
180: dp->dt = T1440kb;
181: floppysetdef(dp);
182: dp->cyl = -1; /* because we don't know */
183: dp->cache = (uchar*)xspanalloc(maxtsize, BY2PG, 64*1024);
184: dp->ccyl = -1;
185: dp->vers = 1;
186: }
187:
188: /*
189: * first operation will recalibrate
190: */
191: fl.confused = 1;
192:
193: floppysetup1(&fl);
194: }
195:
196: void
197: floppyinit(void)
198: {
199: }
200:
201: Chan*
202: floppyattach(char *spec)
203: {
204: static int kstarted;
205:
206: if(kstarted == 0){
207: /*
208: * watchdog to turn off the motors
209: */
210: kstarted = 1;
211: kproc("floppy", floppykproc, 0);
212: }
213: return devattach('f', spec);
214: }
215:
216: Chan*
217: floppyclone(Chan *c, Chan *nc)
218: {
219: return devclone(c, nc);
220: }
221:
222: int
223: floppywalk(Chan *c, char *name)
224: {
225: return devwalk(c, name, floppydir, conf.nfloppy*NFDIR, devgen);
226: }
227:
228: void
229: floppystat(Chan *c, char *dp)
230: {
231: devstat(c, dp, floppydir, conf.nfloppy*NFDIR, devgen);
232: }
233:
234: Chan*
235: floppyopen(Chan *c, int omode)
236: {
237: return devopen(c, omode, floppydir, conf.nfloppy*NFDIR, devgen);
238: }
239:
240: void
241: floppycreate(Chan *c, char *name, int omode, ulong perm)
242: {
243: USED(c, name, omode, perm);
244: error(Eperm);
245: }
246:
247: void
248: floppyclose(Chan *c)
249: {
250: USED(c);
251: }
252:
253: void
254: floppyremove(Chan *c)
255: {
256: USED(c);
257: error(Eperm);
258: }
259:
260: void
261: floppywstat(Chan *c, char *dp)
262: {
263: USED(c, dp);
264: error(Eperm);
265: }
266:
267: static void
268: islegal(ulong offset, long n, FDrive *dp)
269: {
270: if(offset % dp->t->bytes)
271: error(Ebadarg);
272: if(n % dp->t->bytes)
273: error(Ebadarg);
274: }
275:
276: /*
277: * check if the floppy has been replaced under foot. cause
278: * an error if it has.
279: *
280: * a seek and a read clears the condition. this was determined
281: * experimentally, there has to be a better way.
282: *
283: * if the read fails, cycle through the possible floppy
284: * density till one works or we've cycled through all
285: * possibilities for this drive.
286: */
287: static void
288: changed(Chan *c, FDrive *dp)
289: {
290: ulong old;
291: FType *start;
292:
293: /*
294: * if floppy has changed or first time through
295: */
296: if((inb(Pdir)&Fchange) || dp->vers == 0){
297: DPRINT("changed\n");
298: fldump();
299: dp->vers++;
300: floppysetdef(dp);
301: start = dp->t;
302: dp->confused = 1; /* make floppyon recal */
303: floppyon(dp);
304: floppyseek(dp, dp->t->heads*dp->t->tsize);
305: while(waserror()){
306: while(++dp->t){
307: if(dp->t == &floppytype[NTYPES])
308: dp->t = floppytype;
309: if(dp->dt == dp->t->dt)
310: break;
311: }
312: floppydir[NFDIR*dp->dev].length = dp->t->cap;
313: floppyon(dp);
314: DPRINT("changed: trying %s\n", dp->t->name);
315: fldump();
316: if(dp->t == start)
317: nexterror();
318: }
319: floppyxfer(dp, Fread, dp->cache, 0, dp->t->tsize);
320: poperror();
321: }
322:
323: old = c->qid.vers;
324: c->qid.vers = dp->vers;
325: if(old && old != dp->vers)
326: error(Eio);
327: }
328:
329: static int
330: readtrack(FDrive *dp, int cyl, int head)
331: {
332: int i, nn, sofar;
333: ulong pos;
334:
335: nn = dp->t->tsize;
336: if(dp->ccyl==cyl && dp->chead==head)
337: return nn;
338: pos = (cyl*dp->t->heads+head) * nn;
339: for(sofar = 0; sofar < nn; sofar += i){
340: dp->ccyl = -1;
341: i = floppyxfer(dp, Fread, dp->cache + sofar, pos + sofar, nn - sofar);
342: if(i <= 0)
343: return -1;
344: }
345: dp->ccyl = cyl;
346: dp->chead = head;
347: return nn;
348: }
349:
350: long
351: floppyread(Chan *c, void *a, long n, ulong offset)
352: {
353: FDrive *dp;
354: long rv;
355: int sec, head, cyl;
356: long len;
357: uchar *aa;
358:
359: if(c->qid.path == CHDIR)
360: return devdirread(c, a, n, floppydir, conf.nfloppy*NFDIR, devgen);
361:
362: rv = 0;
363: dp = &fl.d[c->qid.path & ~Qmask];
364: switch ((int)(c->qid.path & Qmask)) {
365: case Qdata:
366: islegal(offset, n, dp);
367: aa = a;
368:
369: qlock(&fl);
370: if(waserror()){
371: qunlock(&fl);
372: nexterror();
373: }
374: floppyon(dp);
375: changed(c, dp);
376: for(rv = 0; rv < n; rv += len){
377: /*
378: * all xfers come out of the track cache
379: */
380: dp->len = n - rv;
381: floppypos(dp, offset+rv);
382: cyl = dp->tcyl;
383: head = dp->thead;
384: len = dp->len;
385: sec = dp->tsec;
386: if(readtrack(dp, cyl, head) < 0)
387: break;
388: memmove(aa+rv, dp->cache + (sec-1)*dp->t->bytes, len);
389: }
390: qunlock(&fl);
391: poperror();
392:
393: break;
394: case Qctl:
395: return readstr(offset, a, n, dp->t->name);
396: default:
397: panic("floppyread: bad qid");
398: }
399:
400: return rv;
401: }
402:
403: #define SNCMP(a, b) strncmp(a, b, sizeof(b)-1)
404: long
405: floppywrite(Chan *c, void *a, long n, ulong offset)
406: {
407: FDrive *dp;
408: long rv, i;
409: char *aa = a;
410: char ctlmsg[64];
411:
412: rv = 0;
413: dp = &fl.d[c->qid.path & ~Qmask];
414: switch ((int)(c->qid.path & Qmask)) {
415: case Qdata:
416: islegal(offset, n, dp);
417: qlock(&fl);
418: if(waserror()){
419: qunlock(&fl);
420: nexterror();
421: }
422: floppyon(dp);
423: changed(c, dp);
424: for(rv = 0; rv < n; rv += i){
425: floppypos(dp, offset+rv);
426: if(dp->tcyl == dp->ccyl)
427: dp->ccyl = -1;
428: i = floppyxfer(dp, Fwrite, aa+rv, offset+rv, n-rv);
429: if(i < 0)
430: break;
431: if(i == 0)
432: error(Eio);
433: }
434: qunlock(&fl);
435: poperror();
436: break;
437: case Qctl:
438: rv = n;
439: qlock(&fl);
440: if(waserror()){
441: qunlock(&fl);
442: nexterror();
443: }
444: if(n >= sizeof(ctlmsg))
445: n = sizeof(ctlmsg) - 1;
446: memmove(ctlmsg, aa, n);
447: ctlmsg[n] = 0;
448: if(SNCMP(ctlmsg, "eject") == 0){
449: floppyeject(dp);
450: } else if(SNCMP(ctlmsg, "reset") == 0){
451: fl.confused = 1;
452: floppyon(dp);
453: } else if(SNCMP(ctlmsg, "format") == 0){
454: floppyformat(dp, ctlmsg);
455: } else if(SNCMP(ctlmsg, "debug") == 0){
456: floppydebug = 1;
457: } else
458: error(Ebadctl);
459: poperror();
460: qunlock(&fl);
461: break;
462: default:
463: panic("floppywrite: bad qid");
464: }
465:
466: return rv;
467: }
468:
469: static void
470: floppykproc(void *a)
471: {
472: FDrive *dp;
473:
474: USED(a);
475: while(waserror())
476: ;
477: for(;;){
478: for(dp = fl.d; dp < &fl.d[conf.nfloppy]; dp++){
479: if((fl.motor&MOTORBIT(dp->dev))
480: && TK2SEC(m->ticks - dp->lasttouched) > 5
481: && canqlock(&fl)){
482: if(TK2SEC(m->ticks - dp->lasttouched) > 5)
483: floppyoff(dp);
484: qunlock(&fl);
485: }
486: }
487: tsleep(&fl.kr, return0, 0, 1000);
488: }
489: }
490:
491: /*
492: * start a floppy drive's motor.
493: */
494: void
495: floppyon(FDrive *dp)
496: {
497: int alreadyon;
498: int tries;
499:
500: if(fl.confused)
501: floppyrevive();
502:
503: /* start motor and select drive */
504: alreadyon = fl.motor & MOTORBIT(dp->dev);
505: fl.motor |= MOTORBIT(dp->dev);
506: outb(Pdor, fl.motor | Fintena | Fena | dp->dev);
507: if(!alreadyon){
508: /* wait for drive to spin up */
509: tsleep(&dp->r, return0, 0, 750);
510:
511: /* clear any pending interrupts */
512: floppysense();
513: }
514:
515: /* set transfer rate */
516: if(fl.rate != dp->t->rate){
517: fl.rate = dp->t->rate;
518: outb(Pdsr, fl.rate);
519: }
520:
521: /* get drive to a known cylinder */
522: if(dp->confused)
523: for(tries = 0; tries < 4; tries++)
524: if(floppyrecal(dp) >= 0)
525: break;
526: dp->lasttouched = m->ticks;
527: fl.selected = dp;
528: }
529:
530: /*
531: * stop the floppy if it hasn't been used in 5 seconds
532: */
533: void
534: floppyoff(FDrive *dp)
535: {
536: fl.motor &= ~MOTORBIT(dp->dev);
537: outb(Pdor, fl.motor | Fintena | Fena | dp->dev);
538: fl.selected = dp;
539: }
540:
541: /*
542: * send a command to the floppy
543: */
544: int
545: floppycmd(void)
546: {
547: int i;
548: int tries;
549:
550: fl.nstat = 0;
551: for(i = 0; i < fl.ncmd; i++){
552: for(tries = 0; ; tries++){
553: if(tries > 1000){
554: DPRINT("cmd %ux can't be sent (%d)\n", fl.cmd[0], i);
555: fldump();
556:
557: /* empty fifo, might have been a bad command */
558: floppyresult();
559: return -1;
560: }
561: if((inb(Pmsr)&(Ffrom|Fready)) == Fready)
562: break;
563: }
564: outb(Pfdata, fl.cmd[i]);
565: }
566: return 0;
567: }
568:
569: /*
570: * get a command result from the floppy
571: *
572: * when the controller goes ready waiting for a command
573: * (instead of sending results), we're done
574: *
575: */
576: int
577: floppyresult(void)
578: {
579: int i, s;
580: int tries;
581:
582: /* get the result of the operation */
583: for(i = 0; i < sizeof(fl.stat); i++){
584: /* wait for status byte */
585: for(tries = 0; ; tries++){
586: if(tries > 1000){
587: DPRINT("floppyresult: %d stats\n", i);
588: fldump();
589: fl.confused = 1;
590: return -1;
591: }
592: s = inb(Pmsr)&(Ffrom|Fready);
593: if(s == Fready){
594: fl.nstat = i;
595: return fl.nstat;
596: }
597: if(s == (Ffrom|Fready))
598: break;
599: }
600: fl.stat[i] = inb(Pfdata);
601: }
602: fl.nstat = sizeof(fl.stat);
603: return fl.nstat;
604: }
605:
606: /*
607: * calculate physical address of a logical byte offset into the disk
608: *
609: * truncate dp->length if it crosses a track boundary
610: */
611: static void
612: floppypos(FDrive *dp, long off)
613: {
614: int lsec;
615: int ltrack;
616: int end;
617:
618: lsec = off/dp->t->bytes;
619: ltrack = lsec/dp->t->sectors;
620: dp->tcyl = ltrack/dp->t->heads;
621: dp->tsec = (lsec % dp->t->sectors) + 1;
622: dp->thead = (lsec/dp->t->sectors) % dp->t->heads;
623:
624: /*
625: * can't read across track boundaries.
626: * if so, decrement the bytes to be read.
627: */
628: end = (ltrack+1)*dp->t->sectors*dp->t->bytes;
629: if(off+dp->len > end)
630: dp->len = end - off;
631: }
632:
633: /*
634: * get the interrupt cause from the floppy.
635: */
636: static int
637: floppysense(void)
638: {
639: fl.ncmd = 0;
640: fl.cmd[fl.ncmd++] = Fsense;
641: if(floppycmd() < 0)
642: return -1;
643: if(floppyresult() < 2){
644: DPRINT("can't read sense response\n");
645: fldump();
646: fl.confused = 1;
647: return -1;
648: }
649: return 0;
650: }
651:
652: static int
653: cmddone(void *a)
654: {
655: USED(a);
656: return fl.ncmd == 0;
657: }
658:
659: /*
660: * Wait for a floppy interrupt. If none occurs in 5 seconds, we
661: * may have missed one. This only happens on some portables which
662: * do power management behind our backs. Call the interrupt
663: * routine to try to clear any conditions.
664: */
665: static void
666: floppywait(void)
667: {
668: tsleep(&fl.r, cmddone, 0, 5000);
669: if(!cmddone(0)){
670: floppyintr(0);
671: fl.confused = 1;
672: }
673: }
674:
675: /*
676: * we've lost the floppy position, go to cylinder 0.
677: */
678: static int
679: floppyrecal(FDrive *dp)
680: {
681: dp->ccyl = -1;
682: dp->cyl = -1;
683:
684: fl.ncmd = 0;
685: fl.cmd[fl.ncmd++] = Frecal;
686: fl.cmd[fl.ncmd++] = dp->dev;
687: if(floppycmd() < 0)
688: return -1;
689: floppywait();
690: if(fl.nstat < 2){
691: DPRINT("recalibrate: confused %ux\n", inb(Pmsr));
692: fl.confused = 1;
693: return -1;
694: }
695: if((fl.stat[0] & (Codemask|Seekend)) != Seekend){
696: DPRINT("recalibrate: failed\n");
697: dp->confused = 1;
698: return -1;
699: }
700: dp->cyl = fl.stat[1];
701: if(dp->cyl != 0){
702: DPRINT("recalibrate: wrong cylinder %d\n", dp->cyl);
703: dp->cyl = -1;
704: dp->confused = 1;
705: return -1;
706: }
707:
708: dp->confused = 0;
709: return 0;
710: }
711:
712: /*
713: * if the controller or a specific drive is in a confused state,
714: * reset it and get back to a kown state
715: */
716: void
717: floppyrevive(void)
718: {
719: FDrive *dp;
720:
721: /*
722: * reset the controller if it's confused
723: */
724: if(fl.confused){
725: DPRINT("floppyrevive in\n");
726: fldump();
727:
728: /* reset controller and turn all motors off */
729: splhi();
730: fl.ncmd = 1;
731: fl.cmd[0] = 0;
732: outb(Pdor, 0);
733: delay(10);
734: outb(Pdor, Fintena|Fena);
735: delay(10);
736: spllo();
737: fl.motor = 0;
738: fl.confused = 0;
739: floppywait();
740:
741: /* mark all drives in an unknown state */
742: for(dp = fl.d; dp < &fl.d[conf.nfloppy]; dp++)
743: dp->confused = 1;
744:
745: /* set rate to a known value */
746: outb(Pdsr, 0);
747: fl.rate = 0;
748:
749: DPRINT("floppyrevive out\n");
750: fldump();
751: }
752: }
753:
754: /*
755: * seek to the target cylinder
756: *
757: * interrupt, no results
758: */
759: static long
760: floppyseek(FDrive *dp, long off)
761: {
762: floppypos(dp, off);
763: if(dp->cyl == dp->tcyl)
764: return dp->tcyl;
765: dp->cyl = -1;
766:
767: fl.ncmd = 0;
768: fl.cmd[fl.ncmd++] = Fseek;
769: fl.cmd[fl.ncmd++] = (dp->thead<<2) | dp->dev;
770: fl.cmd[fl.ncmd++] = dp->tcyl * dp->t->steps;
771: if(floppycmd() < 0)
772: return -1;
773: floppywait();
774: if(fl.nstat < 2){
775: DPRINT("seek: confused\n");
776: fl.confused = 1;
777: return -1;
778: }
779: if((fl.stat[0] & (Codemask|Seekend)) != Seekend){
780: DPRINT("seek: failed\n");
781: dp->confused = 1;
782: return -1;
783: }
784:
785: dp->cyl = dp->tcyl;
786: return dp->tcyl;
787: }
788:
789: /*
790: * read or write to floppy. try up to three times.
791: */
792: static long
793: floppyxfer(FDrive *dp, int cmd, void *a, long off, long n)
794: {
795: long offset;
796: int tries;
797:
798: if(off >= dp->t->cap)
799: return 0;
800: if(off + n > dp->t->cap)
801: n = dp->t->cap - off;
802:
803: /* retry on error 3 times */
804: tries = 0;
805: while(waserror()){
806: if(tries++ >= 3)
807: nexterror();
808: DPRINT("floppyxfer: retrying\n");
809: floppyon(dp);
810: }
811:
812: dp->len = n;
813: if(floppyseek(dp, off) < 0){
814: DPRINT("xfer: seek failed\n");
815: dp->confused = 1;
816: error(Eio);
817: }
818:
819: /*
820: * set up the dma (dp->len may be trimmed)
821: */
822: if(waserror()){
823: dmaend(DMAchan);
824: nexterror();
825: }
826: dp->len = dmasetup(DMAchan, a, dp->len, cmd==Fread);
827:
828: /*
829: * start operation
830: */
831: cmd = cmd | (dp->t->heads > 1 ? Fmulti : 0);
832: fl.ncmd = 0;
833: fl.cmd[fl.ncmd++] = cmd;
834: fl.cmd[fl.ncmd++] = (dp->thead<<2) | dp->dev;
835: fl.cmd[fl.ncmd++] = dp->tcyl;
836: fl.cmd[fl.ncmd++] = dp->thead;
837: fl.cmd[fl.ncmd++] = dp->tsec;
838: fl.cmd[fl.ncmd++] = dp->t->bcode;
839: fl.cmd[fl.ncmd++] = dp->t->sectors;
840: fl.cmd[fl.ncmd++] = dp->t->gpl;
841: fl.cmd[fl.ncmd++] = 0xFF;
842: if(floppycmd() < 0)
843: error(Eio);
844:
845: /* Poll ready bits and transfer data */
846: floppyexec((char*)a, dp->len, (cmd & ~Fmulti)==Fread);
847:
848: /*
849: * give bus to DMA, floppyintr() will read result
850: */
851: floppywait();
852: dmaend(DMAchan);
853: poperror();
854:
855: /*
856: * check for errors
857: */
858: if(fl.nstat < 7){
859: DPRINT("xfer: confused\n");
860: fl.confused = 1;
861: error(Eio);
862: }
863: if((fl.stat[0] & Codemask)!=0 || fl.stat[1] || fl.stat[2]){
864: DPRINT("xfer: failed %lux %lux %lux\n", fl.stat[0],
865: fl.stat[1], fl.stat[2]);
866: DPRINT("offset %lud len %d\n", off, dp->len);
867: dp->confused = 1;
868: error(Eio);
869: }
870:
871: /*
872: * check for correct cylinder
873: */
874: offset = fl.stat[3] * dp->t->heads + fl.stat[4];
875: offset = offset*dp->t->sectors + fl.stat[5] - 1;
876: offset = offset * c2b[fl.stat[6]];
877: if(offset != off+dp->len){
878: DPRINT("xfer: ends on wrong cyl\n");
879: dp->confused = 1;
880: error(Eio);
881: }
882: poperror();
883:
884: dp->lasttouched = m->ticks;
885: return dp->len;
886: }
887:
888: /*
889: * format a track
890: */
891: static void
892: floppyformat(FDrive *dp, char *params)
893: {
894: int cyl, h, sec;
895: ulong track;
896: uchar *buf, *bp;
897: FType *t;
898: char *f[3];
899:
900: /*
901: * set the type
902: */
903: if(getfields(params, f, 3, " ") > 1){
904: for(t = floppytype; t < &floppytype[NTYPES]; t++){
905: if(strcmp(f[1], t->name)==0 && t->dt==dp->dt){
906: dp->t = t;
907: floppydir[NFDIR*dp->dev].length = dp->t->cap;
908: break;
909: }
910: }
911: if(t >= &floppytype[NTYPES])
912: error(Ebadarg);
913: } else {
914: floppysetdef(dp);
915: t = dp->t;
916: }
917:
918: /*
919: * buffer for per track info
920: */
921: buf = smalloc(t->sectors*4);
922: if(waserror()){
923: free(buf);
924: nexterror();
925: }
926:
927: /* force a recalibrate to cylinder 0 */
928: dp->confused = 1;
929: if(!waserror()){
930: floppyon(dp);
931: poperror();
932: }
933:
934: /*
935: * format a track at time
936: */
937: for(track = 0; track < t->tracks*t->heads; track++){
938: cyl = track/t->heads;
939: h = track % t->heads;
940:
941: /*
942: * seek to track, ignore errors
943: */
944: floppyseek(dp, track*t->tsize);
945: dp->cyl = cyl;
946: dp->confused = 0;
947:
948: /*
949: * set up the dma (dp->len may be trimmed)
950: */
951: bp = buf;
952: for(sec = 1; sec <= t->sectors; sec++){
953: *bp++ = cyl;
954: *bp++ = h;
955: *bp++ = sec;
956: *bp++ = t->bcode;
957: }
958: if(waserror()){
959: dmaend(DMAchan);
960: nexterror();
961: }
962: dmasetup(DMAchan, buf, bp-buf, 0);
963:
964: /*
965: * start operation
966: */
967: fl.ncmd = 0;
968: fl.cmd[fl.ncmd++] = Fformat;
969: fl.cmd[fl.ncmd++] = (h<<2) | dp->dev;
970: fl.cmd[fl.ncmd++] = t->bcode;
971: fl.cmd[fl.ncmd++] = t->sectors;
972: fl.cmd[fl.ncmd++] = t->fgpl;
973: fl.cmd[fl.ncmd++] = 0x5a;
974: if(floppycmd() < 0)
975: error(Eio);
976:
977: /* Poll ready bits and transfer data */
978: floppyexec((char *)buf, bp-buf, 0);
979:
980: /*
981: * give bus to DMA, floppyintr() will read result
982: */
983: floppywait();
984: dmaend(DMAchan);
985: poperror();
986:
987: /*
988: * check for errors
989: */
990: if(fl.nstat < 7){
991: DPRINT("format: confused\n");
992: fl.confused = 1;
993: error(Eio);
994: }
995: if((fl.stat[0]&Codemask)!=0 || fl.stat[1]|| fl.stat[2]){
996: DPRINT("format: failed %lux %lux %lux\n",
997: fl.stat[0], fl.stat[1], fl.stat[2]);
998: dp->confused = 1;
999: error(Eio);
1000: }
1001: }
1002: free(buf);
1003: dp->confused = 1;
1004: poperror();
1005: }
1006:
1007: void
1008: floppyintr(Ureg *ur)
1009: {
1010: USED(ur);
1011: switch(fl.cmd[0]&~Fmulti){
1012: case Fread:
1013: case Fwrite:
1014: case Fformat:
1015: case Fdumpreg:
1016: floppyresult();
1017: break;
1018: case Fseek:
1019: case Frecal:
1020: default:
1021: floppysense(); /* to clear interrupt */
1022: break;
1023: }
1024: fl.ncmd = 0;
1025: wakeup(&fl.r);
1026: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.