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