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