1*48819Swilliam /*- 2*48819Swilliam * Copyright (c) 1990 The Regents of the University of California. 3*48819Swilliam * All rights reserved. 4*48819Swilliam * 5*48819Swilliam * This code is derived from software contributed to Berkeley by 6*48819Swilliam * Don Ahn. 7*48819Swilliam * 8*48819Swilliam * %sccs.include.redist.c% 9*48819Swilliam * 10*48819Swilliam * @(#)fd.c 7.1 (Berkeley) 04/28/91 11*48819Swilliam */ 12*48819Swilliam 13*48819Swilliam /****************************************************************************/ 14*48819Swilliam /* standalone fd driver */ 15*48819Swilliam /****************************************************************************/ 16*48819Swilliam #include "param.h" 17*48819Swilliam #include "dkbad.h" 18*48819Swilliam #include "i386/isa/disk.h" 19*48819Swilliam #include "i386/isa/fdreg.h" 20*48819Swilliam #include "i386/isa/isa.h" 21*48819Swilliam #include "saio.h" 22*48819Swilliam 23*48819Swilliam #define NUMRETRY 10 24*48819Swilliam /*#define FDDEBUG*/ 25*48819Swilliam 26*48819Swilliam #define NFD 2 27*48819Swilliam #define FDBLK 512 28*48819Swilliam #define NUMTYPES 4 29*48819Swilliam 30*48819Swilliam struct fd_type { 31*48819Swilliam int sectrac; /* sectors per track */ 32*48819Swilliam int secsize; /* size code for sectors */ 33*48819Swilliam int datalen; /* data len when secsize = 0 */ 34*48819Swilliam int gap; /* gap len between sectors */ 35*48819Swilliam int tracks; /* total num of tracks */ 36*48819Swilliam int size; /* size of disk in sectors */ 37*48819Swilliam int steptrac; /* steps per cylinder */ 38*48819Swilliam int trans; /* transfer speed code */ 39*48819Swilliam }; 40*48819Swilliam 41*48819Swilliam struct fd_type fd_types[NUMTYPES] = { 42*48819Swilliam { 18,2,0xFF,0x1B,80,2880,1,0 }, /* 1.44 meg HD 3.5in floppy */ 43*48819Swilliam { 15,2,0xFF,0x1B,80,2400,1,0 }, /* 1.2 meg HD floppy */ 44*48819Swilliam { 9,2,0xFF,0x23,40,720,2,1 }, /* 360k floppy in 1.2meg drive */ 45*48819Swilliam { 9,2,0xFF,0x2A,40,720,1,1 }, /* 360k floppy in DD drive */ 46*48819Swilliam }; 47*48819Swilliam 48*48819Swilliam 49*48819Swilliam /* state needed for current transfer */ 50*48819Swilliam static int fd_type; 51*48819Swilliam static int fd_motor; 52*48819Swilliam static int fd_retry; 53*48819Swilliam static int fd_drive; 54*48819Swilliam static int fd_status[7]; 55*48819Swilliam 56*48819Swilliam static int fdc = IO_FD1; /* floppy disk base */ 57*48819Swilliam 58*48819Swilliam /* Make sure DMA buffer doesn't cross 64k boundary */ 59*48819Swilliam char bounce[FDBLK]; 60*48819Swilliam 61*48819Swilliam 62*48819Swilliam /****************************************************************************/ 63*48819Swilliam /* fdstrategy */ 64*48819Swilliam /****************************************************************************/ 65*48819Swilliam int 66*48819Swilliam fdstrategy(io,func) 67*48819Swilliam register struct iob *io; 68*48819Swilliam int func; 69*48819Swilliam { 70*48819Swilliam char *address; 71*48819Swilliam long nblocks,blknum; 72*48819Swilliam int unit, iosize; 73*48819Swilliam 74*48819Swilliam #ifdef FDDEBUG 75*48819Swilliam printf("fdstrat "); 76*48819Swilliam #endif 77*48819Swilliam unit = io->i_unit; 78*48819Swilliam fd_type = io->i_part; 79*48819Swilliam 80*48819Swilliam /* 81*48819Swilliam * Set up block calculations. 82*48819Swilliam */ 83*48819Swilliam iosize = io->i_cc / FDBLK; 84*48819Swilliam blknum = (unsigned long) io->i_bn * DEV_BSIZE / FDBLK; 85*48819Swilliam nblocks = fd_types[fd_type].size; 86*48819Swilliam if ((blknum + iosize > nblocks) || blknum < 0) { 87*48819Swilliam #ifndef SMALL 88*48819Swilliam printf("bn = %d; sectors = %d; type = %d; fssize = %d ", 89*48819Swilliam blknum, iosize, fd_type, nblocks); 90*48819Swilliam printf("fdstrategy - I/O out of filesystem boundaries\n"); 91*48819Swilliam #endif 92*48819Swilliam return(-1); 93*48819Swilliam } 94*48819Swilliam 95*48819Swilliam address = io->i_ma; 96*48819Swilliam while (iosize > 0) { 97*48819Swilliam if (fdio(func, unit, blknum, address)) 98*48819Swilliam return(-1); 99*48819Swilliam iosize--; 100*48819Swilliam blknum++; 101*48819Swilliam address += FDBLK; 102*48819Swilliam } 103*48819Swilliam return(io->i_cc); 104*48819Swilliam } 105*48819Swilliam 106*48819Swilliam int 107*48819Swilliam fdio(func, unit, blknum, address) 108*48819Swilliam int func,unit,blknum; 109*48819Swilliam char *address; 110*48819Swilliam { 111*48819Swilliam int i,j,cyl,sectrac,sec,head,numretry; 112*48819Swilliam struct fd_type *ft; 113*48819Swilliam 114*48819Swilliam ft = &fd_types[fd_type]; 115*48819Swilliam #ifdef FDDEBUG 116*48819Swilliam printf("fdio "); 117*48819Swilliam #endif 118*48819Swilliam 119*48819Swilliam sectrac = ft->sectrac; 120*48819Swilliam cyl = blknum / (2 * sectrac); 121*48819Swilliam numretry = NUMRETRY; 122*48819Swilliam 123*48819Swilliam if (func == WRITE) bcopy(address,bounce,FDBLK); 124*48819Swilliam 125*48819Swilliam retry: 126*48819Swilliam out_fdc(15); /* Seek function */ 127*48819Swilliam out_fdc(unit); /* Drive number */ 128*48819Swilliam out_fdc(cyl); 129*48819Swilliam 130*48819Swilliam waitio(); 131*48819Swilliam 132*48819Swilliam out_fdc(0x8); 133*48819Swilliam i = in_fdc(); j = in_fdc(); 134*48819Swilliam if (!(i&0x20) || (cyl != j)) { 135*48819Swilliam numretry--; 136*48819Swilliam if (numretry) goto retry; 137*48819Swilliam #ifndef SMALL 138*48819Swilliam printf("Seek error %d, req = %d, at = %d\n",i,cyl,j); 139*48819Swilliam printf("unit %d, type %d, sectrac %d, blknum %d\n", 140*48819Swilliam unit,fd_type,sectrac,blknum); 141*48819Swilliam #endif 142*48819Swilliam return -1; 143*48819Swilliam } 144*48819Swilliam 145*48819Swilliam /* set up transfer */ 146*48819Swilliam fd_dma(func == READ,bounce,FDBLK); 147*48819Swilliam sec = blknum % (sectrac * 2); 148*48819Swilliam head = sec / sectrac; 149*48819Swilliam sec = sec % sectrac + 1; 150*48819Swilliam #ifdef FDDEBUG 151*48819Swilliam printf("sec %d hd %d cyl %d ", sec, head, cyl); 152*48819Swilliam #endif 153*48819Swilliam 154*48819Swilliam if (func == READ) out_fdc(0xE6);/* READ */ 155*48819Swilliam else out_fdc(0xC5); /* WRITE */ 156*48819Swilliam out_fdc(head << 2 | fd_drive); /* head & unit */ 157*48819Swilliam out_fdc(cyl); /* track */ 158*48819Swilliam out_fdc(head); 159*48819Swilliam out_fdc(sec); /* sector XXX +1? */ 160*48819Swilliam out_fdc(ft->secsize); /* sector size */ 161*48819Swilliam out_fdc(sectrac); /* sectors/track */ 162*48819Swilliam out_fdc(ft->gap); /* gap size */ 163*48819Swilliam out_fdc(ft->datalen); /* data length */ 164*48819Swilliam 165*48819Swilliam waitio(); 166*48819Swilliam 167*48819Swilliam for(i=0;i<7;i++) { 168*48819Swilliam fd_status[i] = in_fdc(); 169*48819Swilliam } 170*48819Swilliam if (fd_status[0]&0xF8) { 171*48819Swilliam numretry--; 172*48819Swilliam if (numretry) goto retry; 173*48819Swilliam #ifndef SMALL 174*48819Swilliam printf("FD err %X %X %X %X %X %X %X\n", 175*48819Swilliam fd_status[0], fd_status[1], fd_status[2], fd_status[3], 176*48819Swilliam fd_status[4], fd_status[5], fd_status[6] ); 177*48819Swilliam #endif 178*48819Swilliam return -1; 179*48819Swilliam } 180*48819Swilliam if (func == READ) bcopy(bounce,address,FDBLK); 181*48819Swilliam return 0; 182*48819Swilliam } 183*48819Swilliam 184*48819Swilliam /****************************************************************************/ 185*48819Swilliam /* fdc in/out */ 186*48819Swilliam /****************************************************************************/ 187*48819Swilliam int 188*48819Swilliam in_fdc() 189*48819Swilliam { 190*48819Swilliam int i; 191*48819Swilliam while ((i = inb(fdc+fdsts) & 192) != 192) if (i == 128) return -1; 192*48819Swilliam return inb(0x3f5); 193*48819Swilliam } 194*48819Swilliam 195*48819Swilliam dump_stat() 196*48819Swilliam { 197*48819Swilliam int i; 198*48819Swilliam for(i=0;i<7;i++) { 199*48819Swilliam fd_status[i] = in_fdc(); 200*48819Swilliam if (fd_status[i] < 0) break; 201*48819Swilliam } 202*48819Swilliam #ifdef FDDEBUGx 203*48819Swilliam printf("FD bad status :%X %X %X %X %X %X %X\n", 204*48819Swilliam fd_status[0], fd_status[1], fd_status[2], fd_status[3], 205*48819Swilliam fd_status[4], fd_status[5], fd_status[6] ); 206*48819Swilliam #endif 207*48819Swilliam } 208*48819Swilliam 209*48819Swilliam set_intr() 210*48819Swilliam { 211*48819Swilliam /* initialize 8259's */ 212*48819Swilliam outb(0x20,0x11); 213*48819Swilliam outb(0x21,32); 214*48819Swilliam outb(0x21,4); 215*48819Swilliam outb(0x21,1); 216*48819Swilliam outb(0x21,0x0f); /* turn on int 6 */ 217*48819Swilliam 218*48819Swilliam /* 219*48819Swilliam outb(0xa0,0x11); 220*48819Swilliam outb(0xa1,40); 221*48819Swilliam outb(0xa1,2); 222*48819Swilliam outb(0xa1,1); 223*48819Swilliam outb(0xa1,0xff); */ 224*48819Swilliam 225*48819Swilliam } 226*48819Swilliam 227*48819Swilliam 228*48819Swilliam 229*48819Swilliam waitio() 230*48819Swilliam { 231*48819Swilliam char c; 232*48819Swilliam int n; 233*48819Swilliam 234*48819Swilliam do 235*48819Swilliam outb(0x20,0xc); /* read polled interrupt */ 236*48819Swilliam while ((c=inb(0x20))&0x7f != 6); /* wait for int */ 237*48819Swilliam outb(0x20,0x20); 238*48819Swilliam } 239*48819Swilliam 240*48819Swilliam out_fdc(x) 241*48819Swilliam int x; 242*48819Swilliam { 243*48819Swilliam int r; 244*48819Swilliam do { 245*48819Swilliam r = (inb(fdc+fdsts) & 192); 246*48819Swilliam if (r==128) break; 247*48819Swilliam if (r==192) { 248*48819Swilliam dump_stat(); /* error: direction. eat up output */ 249*48819Swilliam } 250*48819Swilliam } while (1); 251*48819Swilliam outb(0x3f5,x&0xFF); 252*48819Swilliam } 253*48819Swilliam 254*48819Swilliam 255*48819Swilliam /****************************************************************************/ 256*48819Swilliam /* fdopen/fdclose */ 257*48819Swilliam /****************************************************************************/ 258*48819Swilliam fdopen(io) 259*48819Swilliam register struct iob *io; 260*48819Swilliam { 261*48819Swilliam int unit, type, i; 262*48819Swilliam struct fd_type *ft; 263*48819Swilliam 264*48819Swilliam unit = io->i_unit; 265*48819Swilliam type = io->i_part; 266*48819Swilliam io->i_boff = 0; /* no disklabels -- tar/dump wont work */ 267*48819Swilliam #ifdef FDDEBUG 268*48819Swilliam printf("fdopen %d %d ", unit, type); 269*48819Swilliam #endif 270*48819Swilliam ft = &fd_types[type]; 271*48819Swilliam fd_drive = unit; 272*48819Swilliam 273*48819Swilliam set_intr(); /* init intr cont */ 274*48819Swilliam 275*48819Swilliam /* Try a reset, keep motor on */ 276*48819Swilliam outb(0x3f2,0); 277*48819Swilliam for(i=0; i < 100000; i++); 278*48819Swilliam outb(0x3f2,unit | (unit ? 32 : 16) ); 279*48819Swilliam for(i=0; i < 100000; i++); 280*48819Swilliam outb(0x3f2,unit | 0xC | (unit ? 32 : 16) ); 281*48819Swilliam outb(0x3f7,ft->trans); 282*48819Swilliam fd_motor = 1; 283*48819Swilliam 284*48819Swilliam waitio(); 285*48819Swilliam 286*48819Swilliam out_fdc(3); /* specify command */ 287*48819Swilliam out_fdc(0xDF); 288*48819Swilliam out_fdc(2); 289*48819Swilliam 290*48819Swilliam out_fdc(7); /* Recalibrate Function */ 291*48819Swilliam out_fdc(unit); 292*48819Swilliam 293*48819Swilliam waitio(); 294*48819Swilliam return(0); 295*48819Swilliam } 296*48819Swilliam 297*48819Swilliam 298*48819Swilliam /****************************************************************************/ 299*48819Swilliam /* fd_dma */ 300*48819Swilliam /* set up DMA read/write operation and virtual address addr for nbytes */ 301*48819Swilliam /****************************************************************************/ 302*48819Swilliam fd_dma(read,addr,nbytes) 303*48819Swilliam int read; 304*48819Swilliam unsigned long addr; 305*48819Swilliam int nbytes; 306*48819Swilliam { 307*48819Swilliam /* Set read/write bytes */ 308*48819Swilliam if (read) { 309*48819Swilliam outb(0xC,0x46); outb(0xB,0x46); 310*48819Swilliam } else { 311*48819Swilliam outb(0xC,0x4A); outb(0xB,0x4A); 312*48819Swilliam } 313*48819Swilliam /* Send start address */ 314*48819Swilliam outb(0x4,addr & 0xFF); 315*48819Swilliam outb(0x4,(addr>>8) & 0xFF); 316*48819Swilliam outb(0x81,(addr>>16) & 0xFF); 317*48819Swilliam /* Send count */ 318*48819Swilliam nbytes--; 319*48819Swilliam outb(0x5,nbytes & 0xFF); 320*48819Swilliam outb(0x5,(nbytes>>8) & 0xFF); 321*48819Swilliam /* set channel 2 */ 322*48819Swilliam outb(0x0A,2); 323*48819Swilliam } 324*48819Swilliam 325