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