148819Swilliam /*- 248819Swilliam * Copyright (c) 1990 The Regents of the University of California. 348819Swilliam * All rights reserved. 448819Swilliam * 548819Swilliam * This code is derived from software contributed to Berkeley by 648819Swilliam * Don Ahn. 748819Swilliam * 848819Swilliam * %sccs.include.redist.c% 948819Swilliam * 10*49078Sbostic * @(#)fd.c 7.2 (Berkeley) 05/04/91 1148819Swilliam */ 1248819Swilliam 1348819Swilliam /****************************************************************************/ 1448819Swilliam /* standalone fd driver */ 1548819Swilliam /****************************************************************************/ 1648819Swilliam #include "param.h" 1748819Swilliam #include "dkbad.h" 1848819Swilliam #include "i386/isa/disk.h" 1948819Swilliam #include "i386/isa/fdreg.h" 2048819Swilliam #include "i386/isa/isa.h" 2148819Swilliam #include "saio.h" 2248819Swilliam 2348819Swilliam #define NUMRETRY 10 2448819Swilliam /*#define FDDEBUG*/ 2548819Swilliam 2648819Swilliam #define NFD 2 2748819Swilliam #define FDBLK 512 2848819Swilliam #define NUMTYPES 4 2948819Swilliam 3048819Swilliam struct fd_type { 3148819Swilliam int sectrac; /* sectors per track */ 3248819Swilliam int secsize; /* size code for sectors */ 3348819Swilliam int datalen; /* data len when secsize = 0 */ 3448819Swilliam int gap; /* gap len between sectors */ 3548819Swilliam int tracks; /* total num of tracks */ 3648819Swilliam int size; /* size of disk in sectors */ 3748819Swilliam int steptrac; /* steps per cylinder */ 3848819Swilliam int trans; /* transfer speed code */ 3948819Swilliam }; 4048819Swilliam 4148819Swilliam struct fd_type fd_types[NUMTYPES] = { 4248819Swilliam { 18,2,0xFF,0x1B,80,2880,1,0 }, /* 1.44 meg HD 3.5in floppy */ 4348819Swilliam { 15,2,0xFF,0x1B,80,2400,1,0 }, /* 1.2 meg HD floppy */ 4448819Swilliam { 9,2,0xFF,0x23,40,720,2,1 }, /* 360k floppy in 1.2meg drive */ 4548819Swilliam { 9,2,0xFF,0x2A,40,720,1,1 }, /* 360k floppy in DD drive */ 4648819Swilliam }; 4748819Swilliam 4848819Swilliam 4948819Swilliam /* state needed for current transfer */ 5048819Swilliam static int fd_type; 5148819Swilliam static int fd_motor; 5248819Swilliam static int fd_retry; 5348819Swilliam static int fd_drive; 5448819Swilliam static int fd_status[7]; 5548819Swilliam 5648819Swilliam static int fdc = IO_FD1; /* floppy disk base */ 5748819Swilliam 5848819Swilliam /* Make sure DMA buffer doesn't cross 64k boundary */ 5948819Swilliam char bounce[FDBLK]; 6048819Swilliam 6148819Swilliam 6248819Swilliam /****************************************************************************/ 6348819Swilliam /* fdstrategy */ 6448819Swilliam /****************************************************************************/ 6548819Swilliam int 6648819Swilliam fdstrategy(io,func) 6748819Swilliam register struct iob *io; 6848819Swilliam int func; 6948819Swilliam { 7048819Swilliam char *address; 7148819Swilliam long nblocks,blknum; 7248819Swilliam int unit, iosize; 7348819Swilliam 7448819Swilliam #ifdef FDDEBUG 7548819Swilliam printf("fdstrat "); 7648819Swilliam #endif 7748819Swilliam unit = io->i_unit; 7848819Swilliam fd_type = io->i_part; 7948819Swilliam 8048819Swilliam /* 8148819Swilliam * Set up block calculations. 8248819Swilliam */ 8348819Swilliam iosize = io->i_cc / FDBLK; 8448819Swilliam blknum = (unsigned long) io->i_bn * DEV_BSIZE / FDBLK; 8548819Swilliam nblocks = fd_types[fd_type].size; 8648819Swilliam if ((blknum + iosize > nblocks) || blknum < 0) { 8748819Swilliam #ifndef SMALL 8848819Swilliam printf("bn = %d; sectors = %d; type = %d; fssize = %d ", 8948819Swilliam blknum, iosize, fd_type, nblocks); 9048819Swilliam printf("fdstrategy - I/O out of filesystem boundaries\n"); 9148819Swilliam #endif 9248819Swilliam return(-1); 9348819Swilliam } 9448819Swilliam 9548819Swilliam address = io->i_ma; 9648819Swilliam while (iosize > 0) { 9748819Swilliam if (fdio(func, unit, blknum, address)) 9848819Swilliam return(-1); 9948819Swilliam iosize--; 10048819Swilliam blknum++; 10148819Swilliam address += FDBLK; 10248819Swilliam } 10348819Swilliam return(io->i_cc); 10448819Swilliam } 10548819Swilliam 10648819Swilliam int 10748819Swilliam fdio(func, unit, blknum, address) 10848819Swilliam int func,unit,blknum; 10948819Swilliam char *address; 11048819Swilliam { 11148819Swilliam int i,j,cyl,sectrac,sec,head,numretry; 11248819Swilliam struct fd_type *ft; 11348819Swilliam 11448819Swilliam ft = &fd_types[fd_type]; 11548819Swilliam #ifdef FDDEBUG 11648819Swilliam printf("fdio "); 11748819Swilliam #endif 11848819Swilliam 11948819Swilliam sectrac = ft->sectrac; 12048819Swilliam cyl = blknum / (2 * sectrac); 12148819Swilliam numretry = NUMRETRY; 12248819Swilliam 123*49078Sbostic if (func == F_WRITE) bcopy(address,bounce,FDBLK); 12448819Swilliam 12548819Swilliam retry: 12648819Swilliam out_fdc(15); /* Seek function */ 12748819Swilliam out_fdc(unit); /* Drive number */ 12848819Swilliam out_fdc(cyl); 12948819Swilliam 13048819Swilliam waitio(); 13148819Swilliam 13248819Swilliam out_fdc(0x8); 13348819Swilliam i = in_fdc(); j = in_fdc(); 13448819Swilliam if (!(i&0x20) || (cyl != j)) { 13548819Swilliam numretry--; 13648819Swilliam if (numretry) goto retry; 13748819Swilliam #ifndef SMALL 13848819Swilliam printf("Seek error %d, req = %d, at = %d\n",i,cyl,j); 13948819Swilliam printf("unit %d, type %d, sectrac %d, blknum %d\n", 14048819Swilliam unit,fd_type,sectrac,blknum); 14148819Swilliam #endif 14248819Swilliam return -1; 14348819Swilliam } 14448819Swilliam 14548819Swilliam /* set up transfer */ 146*49078Sbostic fd_dma(func == F_READ, bounce, FDBLK); 14748819Swilliam sec = blknum % (sectrac * 2); 14848819Swilliam head = sec / sectrac; 14948819Swilliam sec = sec % sectrac + 1; 15048819Swilliam #ifdef FDDEBUG 15148819Swilliam printf("sec %d hd %d cyl %d ", sec, head, cyl); 15248819Swilliam #endif 15348819Swilliam 154*49078Sbostic if (func == F_READ) out_fdc(0xE6);/* READ */ 15548819Swilliam else out_fdc(0xC5); /* WRITE */ 15648819Swilliam out_fdc(head << 2 | fd_drive); /* head & unit */ 15748819Swilliam out_fdc(cyl); /* track */ 15848819Swilliam out_fdc(head); 15948819Swilliam out_fdc(sec); /* sector XXX +1? */ 16048819Swilliam out_fdc(ft->secsize); /* sector size */ 16148819Swilliam out_fdc(sectrac); /* sectors/track */ 16248819Swilliam out_fdc(ft->gap); /* gap size */ 16348819Swilliam out_fdc(ft->datalen); /* data length */ 16448819Swilliam 16548819Swilliam waitio(); 16648819Swilliam 16748819Swilliam for(i=0;i<7;i++) { 16848819Swilliam fd_status[i] = in_fdc(); 16948819Swilliam } 17048819Swilliam if (fd_status[0]&0xF8) { 17148819Swilliam numretry--; 17248819Swilliam if (numretry) goto retry; 17348819Swilliam #ifndef SMALL 17448819Swilliam printf("FD err %X %X %X %X %X %X %X\n", 17548819Swilliam fd_status[0], fd_status[1], fd_status[2], fd_status[3], 17648819Swilliam fd_status[4], fd_status[5], fd_status[6] ); 17748819Swilliam #endif 17848819Swilliam return -1; 17948819Swilliam } 180*49078Sbostic if (func == F_READ) bcopy(bounce,address,FDBLK); 18148819Swilliam return 0; 18248819Swilliam } 18348819Swilliam 18448819Swilliam /****************************************************************************/ 18548819Swilliam /* fdc in/out */ 18648819Swilliam /****************************************************************************/ 18748819Swilliam int 18848819Swilliam in_fdc() 18948819Swilliam { 19048819Swilliam int i; 19148819Swilliam while ((i = inb(fdc+fdsts) & 192) != 192) if (i == 128) return -1; 19248819Swilliam return inb(0x3f5); 19348819Swilliam } 19448819Swilliam 19548819Swilliam dump_stat() 19648819Swilliam { 19748819Swilliam int i; 19848819Swilliam for(i=0;i<7;i++) { 19948819Swilliam fd_status[i] = in_fdc(); 20048819Swilliam if (fd_status[i] < 0) break; 20148819Swilliam } 20248819Swilliam #ifdef FDDEBUGx 20348819Swilliam printf("FD bad status :%X %X %X %X %X %X %X\n", 20448819Swilliam fd_status[0], fd_status[1], fd_status[2], fd_status[3], 20548819Swilliam fd_status[4], fd_status[5], fd_status[6] ); 20648819Swilliam #endif 20748819Swilliam } 20848819Swilliam 20948819Swilliam set_intr() 21048819Swilliam { 21148819Swilliam /* initialize 8259's */ 21248819Swilliam outb(0x20,0x11); 21348819Swilliam outb(0x21,32); 21448819Swilliam outb(0x21,4); 21548819Swilliam outb(0x21,1); 21648819Swilliam outb(0x21,0x0f); /* turn on int 6 */ 21748819Swilliam 21848819Swilliam /* 21948819Swilliam outb(0xa0,0x11); 22048819Swilliam outb(0xa1,40); 22148819Swilliam outb(0xa1,2); 22248819Swilliam outb(0xa1,1); 22348819Swilliam outb(0xa1,0xff); */ 22448819Swilliam 22548819Swilliam } 22648819Swilliam 22748819Swilliam 22848819Swilliam 22948819Swilliam waitio() 23048819Swilliam { 23148819Swilliam char c; 23248819Swilliam int n; 23348819Swilliam 23448819Swilliam do 23548819Swilliam outb(0x20,0xc); /* read polled interrupt */ 23648819Swilliam while ((c=inb(0x20))&0x7f != 6); /* wait for int */ 23748819Swilliam outb(0x20,0x20); 23848819Swilliam } 23948819Swilliam 24048819Swilliam out_fdc(x) 24148819Swilliam int x; 24248819Swilliam { 24348819Swilliam int r; 24448819Swilliam do { 24548819Swilliam r = (inb(fdc+fdsts) & 192); 24648819Swilliam if (r==128) break; 24748819Swilliam if (r==192) { 24848819Swilliam dump_stat(); /* error: direction. eat up output */ 24948819Swilliam } 25048819Swilliam } while (1); 25148819Swilliam outb(0x3f5,x&0xFF); 25248819Swilliam } 25348819Swilliam 25448819Swilliam 25548819Swilliam /****************************************************************************/ 25648819Swilliam /* fdopen/fdclose */ 25748819Swilliam /****************************************************************************/ 25848819Swilliam fdopen(io) 25948819Swilliam register struct iob *io; 26048819Swilliam { 26148819Swilliam int unit, type, i; 26248819Swilliam struct fd_type *ft; 26348819Swilliam 26448819Swilliam unit = io->i_unit; 26548819Swilliam type = io->i_part; 26648819Swilliam io->i_boff = 0; /* no disklabels -- tar/dump wont work */ 26748819Swilliam #ifdef FDDEBUG 26848819Swilliam printf("fdopen %d %d ", unit, type); 26948819Swilliam #endif 27048819Swilliam ft = &fd_types[type]; 27148819Swilliam fd_drive = unit; 27248819Swilliam 27348819Swilliam set_intr(); /* init intr cont */ 27448819Swilliam 27548819Swilliam /* Try a reset, keep motor on */ 27648819Swilliam outb(0x3f2,0); 27748819Swilliam for(i=0; i < 100000; i++); 27848819Swilliam outb(0x3f2,unit | (unit ? 32 : 16) ); 27948819Swilliam for(i=0; i < 100000; i++); 28048819Swilliam outb(0x3f2,unit | 0xC | (unit ? 32 : 16) ); 28148819Swilliam outb(0x3f7,ft->trans); 28248819Swilliam fd_motor = 1; 28348819Swilliam 28448819Swilliam waitio(); 28548819Swilliam 28648819Swilliam out_fdc(3); /* specify command */ 28748819Swilliam out_fdc(0xDF); 28848819Swilliam out_fdc(2); 28948819Swilliam 29048819Swilliam out_fdc(7); /* Recalibrate Function */ 29148819Swilliam out_fdc(unit); 29248819Swilliam 29348819Swilliam waitio(); 29448819Swilliam return(0); 29548819Swilliam } 29648819Swilliam 29748819Swilliam 29848819Swilliam /****************************************************************************/ 29948819Swilliam /* fd_dma */ 30048819Swilliam /* set up DMA read/write operation and virtual address addr for nbytes */ 30148819Swilliam /****************************************************************************/ 30248819Swilliam fd_dma(read,addr,nbytes) 30348819Swilliam int read; 30448819Swilliam unsigned long addr; 30548819Swilliam int nbytes; 30648819Swilliam { 30748819Swilliam /* Set read/write bytes */ 30848819Swilliam if (read) { 30948819Swilliam outb(0xC,0x46); outb(0xB,0x46); 31048819Swilliam } else { 31148819Swilliam outb(0xC,0x4A); outb(0xB,0x4A); 31248819Swilliam } 31348819Swilliam /* Send start address */ 31448819Swilliam outb(0x4,addr & 0xFF); 31548819Swilliam outb(0x4,(addr>>8) & 0xFF); 31648819Swilliam outb(0x81,(addr>>16) & 0xFF); 31748819Swilliam /* Send count */ 31848819Swilliam nbytes--; 31948819Swilliam outb(0x5,nbytes & 0xFF); 32048819Swilliam outb(0x5,(nbytes>>8) & 0xFF); 32148819Swilliam /* set channel 2 */ 32248819Swilliam outb(0x0A,2); 32348819Swilliam } 32448819Swilliam 325