143594Sdonahn /*- 243594Sdonahn * Copyright (c) 1990 The Regents of the University of California. 343594Sdonahn * All rights reserved. 443594Sdonahn * 543594Sdonahn * This code is derived from software contributed to Berkeley by 643594Sdonahn * Don Ahn. 743594Sdonahn * 849609Swilliam * %sccs.include.redist.c% 943594Sdonahn * 10*52360Sbostic * @(#)fd.c 7.6 (Berkeley) 02/05/92 1143594Sdonahn */ 1243594Sdonahn 1349825Sbostic #include "fd.h" 1449825Sbostic #if NFD > 0 15*52360Sbostic /* 16*52360Sbostic * This driver assumed that NFD == 2. Now it works for NFD == 1 or NFD == 2 17*52360Sbostic * It will probably not work for NFD > 2. 18*52360Sbostic */ 1943594Sdonahn #include "param.h" 2043594Sdonahn #include "dkbad.h" 2143594Sdonahn #include "systm.h" 2243594Sdonahn #include "conf.h" 2343594Sdonahn #include "file.h" 2443594Sdonahn #include "ioctl.h" 2543594Sdonahn #include "buf.h" 2643594Sdonahn #include "uio.h" 27*52360Sbostic 2849573Swilliam #include "i386/isa/isa_device.h" 2949573Swilliam #include "i386/isa/fdreg.h" 3049573Swilliam #include "i386/isa/icu.h" 3143594Sdonahn 3243594Sdonahn #define FDUNIT(s) ((s)&1) 3343594Sdonahn #define FDTYPE(s) (((s)>>1)&7) 34*52360Sbostic #define FDMOTOR(u) (fd_unit[(u)].motor ? (1 << (4 + (u))) : 0) 3545533Sbill 3643594Sdonahn #define b_cylin b_resid 3745533Sbill #define b_step b_resid 3843594Sdonahn #define FDBLK 512 3943594Sdonahn #define NUMTYPES 4 4043594Sdonahn 4143594Sdonahn struct fd_type { 4243594Sdonahn int sectrac; /* sectors per track */ 4343594Sdonahn int secsize; /* size code for sectors */ 4443594Sdonahn int datalen; /* data len when secsize = 0 */ 4543594Sdonahn int gap; /* gap len between sectors */ 4643594Sdonahn int tracks; /* total num of tracks */ 4743594Sdonahn int size; /* size of disk in sectors */ 4843594Sdonahn int steptrac; /* steps per cylinder */ 4943594Sdonahn int trans; /* transfer speed code */ 5043594Sdonahn }; 5143594Sdonahn 5243594Sdonahn struct fd_type fd_types[NUMTYPES] = { 5345533Sbill { 18,2,0xFF,0x1B,80,2880,1,0 }, /* 1.44 meg HD 3.5in floppy */ 5443594Sdonahn { 15,2,0xFF,0x1B,80,2400,1,0 }, /* 1.2 meg HD floppy */ 5543594Sdonahn { 9,2,0xFF,0x23,40,720,2,1 }, /* 360k floppy in 1.2meg drive */ 5643594Sdonahn { 9,2,0xFF,0x2A,40,720,1,1 }, /* 360k floppy in DD drive */ 5743594Sdonahn }; 5843594Sdonahn 5943594Sdonahn struct fd_u { 6043594Sdonahn int type; /* Drive type (HD, DD */ 6143594Sdonahn int active; /* Drive activity boolean */ 6243594Sdonahn int motor; /* Motor on flag */ 6343594Sdonahn struct buf head; /* Head of buf chain */ 6443594Sdonahn struct buf rhead; /* Raw head of buf chain */ 6545533Sbill int reset; 6643594Sdonahn } fd_unit[NFD]; 6743594Sdonahn 6845533Sbill 6943594Sdonahn extern int hz; 7043594Sdonahn 7143594Sdonahn /* state needed for current transfer */ 7245533Sbill static fdc; /* floppy disk controller io base register */ 7345533Sbill int fd_dmachan = 2; 7443594Sdonahn static int fd_skip; 7543594Sdonahn static int fd_state; 7643594Sdonahn static int fd_retry; 7743594Sdonahn static int fd_drive; 7845533Sbill static int fd_track = -1; 7943594Sdonahn static int fd_status[7]; 8043594Sdonahn 8145533Sbill /* 8245533Sbill make sure bounce buffer for DMA is aligned since the DMA chip 8345533Sbill doesn't roll over properly over a 64k boundary 8445533Sbill */ 8545533Sbill extern struct buf *dma_bounce[]; 8643594Sdonahn 8743594Sdonahn /****************************************************************************/ 8843594Sdonahn /* autoconfiguration stuff */ 8943594Sdonahn /****************************************************************************/ 9043594Sdonahn int fdprobe(), fdattach(), fd_turnoff(); 9143594Sdonahn 9245533Sbill struct isa_driver fddriver = { 9343594Sdonahn fdprobe, fdattach, "fd", 9443594Sdonahn }; 9543594Sdonahn 9643594Sdonahn fdprobe(dev) 9745533Sbill struct isa_device *dev; 9843594Sdonahn { 9943594Sdonahn return 1; 10043594Sdonahn } 10143594Sdonahn 10243594Sdonahn fdattach(dev) 10345533Sbill struct isa_device *dev; 10445533Sbill { int s; 10545533Sbill 10645533Sbill fdc = dev->id_iobase; 10745533Sbill /* Set transfer to 500kbps */ 10845533Sbill outb(fdc+fdctl,0); 10945533Sbill fd_turnoff(0); 11045533Sbill } 11145533Sbill 11245533Sbill int 11351729Swilliam Fdsize(dev) 11445533Sbill dev_t dev; 11543594Sdonahn { 11645533Sbill return(2400); 11743594Sdonahn } 11843594Sdonahn 11943594Sdonahn /****************************************************************************/ 12043594Sdonahn /* fdstrategy */ 12143594Sdonahn /****************************************************************************/ 12251729Swilliam Fdstrategy(bp) 12343594Sdonahn register struct buf *bp; /* IO operation to perform */ 12443594Sdonahn { 125*52360Sbostic register struct buf *dp; 12643594Sdonahn long nblocks,blknum; 12745533Sbill int unit, type, s; 12843594Sdonahn 12945533Sbill unit = FDUNIT(minor(bp->b_dev)); 13045533Sbill type = FDTYPE(minor(bp->b_dev)); 13145533Sbill 13245533Sbill #ifdef FDTEST 13345533Sbill printf("fdstrat%d, blk = %d, bcount = %d, addr = %x|", 13445533Sbill unit, bp->b_blkno, bp->b_bcount,bp->b_un.b_addr); 13543594Sdonahn #endif 13643594Sdonahn if ((unit >= NFD) || (bp->b_blkno < 0)) { 13743594Sdonahn printf("fdstrat: unit = %d, blkno = %d, bcount = %d\n", 13843594Sdonahn unit, bp->b_blkno, bp->b_bcount); 13943594Sdonahn pg("fd:error in fdstrategy"); 14043594Sdonahn bp->b_error = EINVAL; 14145533Sbill bp->b_flags |= B_ERROR; 14243594Sdonahn goto bad; 14343594Sdonahn } 14443594Sdonahn /* 14543594Sdonahn * Set up block calculations. 14643594Sdonahn */ 14743594Sdonahn blknum = (unsigned long) bp->b_blkno * DEV_BSIZE/FDBLK; 14845533Sbill nblocks = fd_types[type].size; 14943594Sdonahn if (blknum + (bp->b_bcount / FDBLK) > nblocks) { 15045533Sbill if (blknum == nblocks) { 15145533Sbill bp->b_resid = bp->b_bcount; 15245533Sbill } else { 15345533Sbill bp->b_error = ENOSPC; 15445533Sbill bp->b_flags |= B_ERROR; 15545533Sbill } 156*52360Sbostic #ifdef FDTEST 157*52360Sbostic printf("fdstrat%d, too big\n"); 158*52360Sbostic #endif 15943594Sdonahn goto bad; 16043594Sdonahn } 16145533Sbill bp->b_cylin = blknum / (fd_types[type].sectrac * 2); 16243594Sdonahn dp = &fd_unit[unit].head; 16345533Sbill dp->b_step = (fd_types[fd_unit[unit].type].steptrac); 16443594Sdonahn s = splbio(); 16543594Sdonahn disksort(dp, bp); 166*52360Sbostic if ((fd_unit[0].head.b_active == 0) 167*52360Sbostic #if NFD > 1 168*52360Sbostic && (fd_unit[1].head.b_active == 0) 169*52360Sbostic #endif 170*52360Sbostic ) { 17145533Sbill #ifdef FDDEBUG 17245533Sbill printf("T|"); 17345533Sbill #endif 17443594Sdonahn dp->b_active = 1; 17543594Sdonahn fd_drive = unit; 17645533Sbill fd_track = -1; /* force seek on first xfer */ 17743594Sdonahn untimeout(fd_turnoff,unit); 17843594Sdonahn fdstart(unit); /* start drive if idle */ 17943594Sdonahn } 18043594Sdonahn splx(s); 18143594Sdonahn return; 18243594Sdonahn 18343594Sdonahn bad: 18443594Sdonahn biodone(bp); 18543594Sdonahn } 18643594Sdonahn 18743594Sdonahn /****************************************************************************/ 18843594Sdonahn /* motor control stuff */ 18943594Sdonahn /****************************************************************************/ 19043594Sdonahn set_motor(unit,reset) 19143594Sdonahn int unit,reset; 19243594Sdonahn { 193*52360Sbostic outb(fdc+fdout,unit | (reset ? 0 : 0xC) | FDMOTOR(0) 194*52360Sbostic #if NFD > 1 195*52360Sbostic | FDMOTOR(1) 196*52360Sbostic #endif 197*52360Sbostic ); 19843594Sdonahn } 19943594Sdonahn 20043594Sdonahn fd_turnoff(unit) 20143594Sdonahn int unit; 20243594Sdonahn { 20343594Sdonahn fd_unit[unit].motor = 0; 20443594Sdonahn if (unit) set_motor(0,0); 20543594Sdonahn else set_motor(1,0); 20643594Sdonahn } 20743594Sdonahn 20843594Sdonahn fd_turnon(unit) 20943594Sdonahn int unit; 21043594Sdonahn { 21143594Sdonahn fd_unit[unit].motor = 1; 21243594Sdonahn set_motor(unit,0); 21343594Sdonahn } 21443594Sdonahn 21543594Sdonahn /****************************************************************************/ 21643594Sdonahn /* fdc in/out */ 21743594Sdonahn /****************************************************************************/ 21843594Sdonahn int 21943594Sdonahn in_fdc() 22043594Sdonahn { 22143594Sdonahn int i; 22245533Sbill while ((i = inb(fdc+fdsts) & (NE7_DIO|NE7_RQM)) != (NE7_DIO|NE7_RQM)) 22345533Sbill if (i == NE7_RQM) return -1; 22445533Sbill return inb(fdc+fddata); 22543594Sdonahn } 22643594Sdonahn 22743594Sdonahn dump_stat() 22843594Sdonahn { 22943594Sdonahn int i; 23043594Sdonahn for(i=0;i<7;i++) { 23143594Sdonahn fd_status[i] = in_fdc(); 23243594Sdonahn if (fd_status[i] < 0) break; 23343594Sdonahn } 23449878Sbostic printf("FD bad status :%lx %lx %lx %lx %lx %lx %lx\n", 23545533Sbill fd_status[0], fd_status[1], fd_status[2], fd_status[3], 23645533Sbill fd_status[4], fd_status[5], fd_status[6] ); 23743594Sdonahn } 23843594Sdonahn 23943594Sdonahn out_fdc(x) 24043594Sdonahn int x; 24143594Sdonahn { 24243594Sdonahn int r,errcnt; 24343594Sdonahn static int maxcnt = 0; 24443594Sdonahn errcnt = 0; 24543594Sdonahn do { 24645533Sbill r = (inb(fdc+fdsts) & (NE7_DIO|NE7_RQM)); 24745533Sbill if (r== NE7_RQM) break; 24845533Sbill if (r==(NE7_DIO|NE7_RQM)) { 24943594Sdonahn dump_stat(); /* error: direction. eat up output */ 25043594Sdonahn #ifdef FDOTHER 25149878Sbostic printf("%lx\n",x); 25243594Sdonahn #endif 25343594Sdonahn } 25443594Sdonahn /* printf("Error r = %d:",r); */ 25543594Sdonahn errcnt++; 25643594Sdonahn } while (1); 25743594Sdonahn if (errcnt > maxcnt) { 25843594Sdonahn maxcnt = errcnt; 25943594Sdonahn #ifdef FDOTHER 26045533Sbill printf("New MAX = %d\n",maxcnt); 26143594Sdonahn #endif 26243594Sdonahn } 26345533Sbill outb(fdc+fddata,x); 26443594Sdonahn } 26543594Sdonahn 26643594Sdonahn /* see if fdc responding */ 26743594Sdonahn int 26843594Sdonahn check_fdc() 26943594Sdonahn { 27043594Sdonahn int i; 27143594Sdonahn for(i=0;i<100;i++) { 27245533Sbill if (inb(fdc+fdsts)& NE7_RQM) return 0; 27343594Sdonahn } 27443594Sdonahn return 1; 27543594Sdonahn } 27643594Sdonahn 27743594Sdonahn /****************************************************************************/ 27843594Sdonahn /* fdopen/fdclose */ 27943594Sdonahn /****************************************************************************/ 28049573Swilliam Fdopen(dev, flags) 28143594Sdonahn dev_t dev; 28243594Sdonahn int flags; 28343594Sdonahn { 28445533Sbill int unit = FDUNIT(minor(dev)); 28545533Sbill int type = FDTYPE(minor(dev)); 28643594Sdonahn int s; 28743594Sdonahn 288*52360Sbostic printf("fdopen %x %d %d\n", minor(dev), unit, type); 28943594Sdonahn /* check bounds */ 29043594Sdonahn if (unit >= NFD) return(ENXIO); 29143594Sdonahn if (type >= NUMTYPES) return(ENXIO); 29245533Sbill /* 29343594Sdonahn if (check_fdc()) return(EBUSY); 29445533Sbill */ 29543594Sdonahn 29643594Sdonahn /* Set proper disk type, only allow one type */ 29743594Sdonahn return 0; 29843594Sdonahn } 29943594Sdonahn 30051729Swilliam Fdclose(dev, flags) 30143594Sdonahn dev_t dev; 30243594Sdonahn { 30343594Sdonahn } 30443594Sdonahn 30543594Sdonahn /****************************************************************************/ 30643594Sdonahn /* fdread/fdwrite */ 30743594Sdonahn /****************************************************************************/ 30843594Sdonahn /* 30943594Sdonahn * Routines to do raw IO for a unit. 31043594Sdonahn */ 31151729Swilliam Fdread(dev, uio) /* character read routine */ 31243594Sdonahn dev_t dev; 31343594Sdonahn struct uio *uio; 31443594Sdonahn { 31545533Sbill int unit = FDUNIT(minor(dev)) ; 31643594Sdonahn if (unit >= NFD) return(ENXIO); 31751729Swilliam return(physio(Fdstrategy,&fd_unit[unit].rhead,dev,B_READ,minphys,uio)); 31843594Sdonahn } 31943594Sdonahn 32051729Swilliam Fdwrite(dev, uio) /* character write routine */ 32143594Sdonahn dev_t dev; 32243594Sdonahn struct uio *uio; 32343594Sdonahn { 32445533Sbill int unit = FDUNIT(minor(dev)) ; 32543594Sdonahn if (unit >= NFD) return(ENXIO); 32651729Swilliam return(physio(Fdstrategy,&fd_unit[unit].rhead,dev,B_WRITE,minphys,uio)); 32743594Sdonahn } 32843594Sdonahn 32943594Sdonahn /****************************************************************************/ 33043594Sdonahn /* fdstart */ 33143594Sdonahn /****************************************************************************/ 33243594Sdonahn fdstart(unit) 33343594Sdonahn int unit; 33443594Sdonahn { 33543594Sdonahn register struct buf *dp,*bp; 33643594Sdonahn int s; 33743594Sdonahn 33845533Sbill #ifdef FDTEST 339*52360Sbostic printf("fd%d|",unit); 34045533Sbill #endif 34145533Sbill s = splbio(); 34243594Sdonahn if (!fd_unit[unit].motor) { 34343594Sdonahn fd_turnon(unit); 34443594Sdonahn /* Wait for 1 sec */ 34543594Sdonahn timeout(fdstart,unit,hz); 34645533Sbill /*DELAY(1000000);*/ 34745533Sbill }else 34845533Sbill { 34945533Sbill /* make sure drive is selected as well as on */ 35045533Sbill /*set_motor(unit,0);*/ 35145533Sbill 35243594Sdonahn dp = &fd_unit[unit].head; 35343594Sdonahn bp = dp->b_actf; 35443594Sdonahn fd_retry = 0; 35545533Sbill if (fd_unit[unit].reset) fd_state = 1; 35645533Sbill else { 35745533Sbill /* DO a RESET */ 35845533Sbill fd_unit[unit].reset = 1; 35945533Sbill fd_state = 5; 36045533Sbill } 36143594Sdonahn fd_skip = 0; 36245533Sbill #ifdef FDDEBUG 36345533Sbill printf("Seek %d %d\n", bp->b_cylin, dp->b_step); 36445533Sbill #endif 36545533Sbill if (bp->b_cylin != fd_track) { 36643594Sdonahn /* Seek necessary, never quite sure where head is at! */ 36743594Sdonahn out_fdc(15); /* Seek function */ 36843594Sdonahn out_fdc(unit); /* Drive number */ 36945533Sbill out_fdc(bp->b_cylin * dp->b_step); 37049573Swilliam } else fdintr(0xff); 37143594Sdonahn } 37245533Sbill splx(s); 37343594Sdonahn } 37443594Sdonahn 37543594Sdonahn fd_timeout(x) 37643594Sdonahn int x; 37743594Sdonahn { 37843594Sdonahn int i,j; 37943594Sdonahn struct buf *dp,*bp; 38043594Sdonahn 38143594Sdonahn dp = &fd_unit[fd_drive].head; 38243594Sdonahn bp = dp->b_actf; 38343594Sdonahn 38443594Sdonahn out_fdc(0x4); 38543594Sdonahn out_fdc(fd_drive); 38643594Sdonahn i = in_fdc(); 38749878Sbostic printf("Timeout drive status %lx\n",i); 38843594Sdonahn 38943594Sdonahn out_fdc(0x8); 39043594Sdonahn i = in_fdc(); 39143594Sdonahn j = in_fdc(); 39249878Sbostic printf("ST0 = %lx, PCN = %lx\n",i,j); 39343594Sdonahn 39443594Sdonahn if (bp) badtrans(dp,bp); 39543594Sdonahn } 39643594Sdonahn 39743594Sdonahn /****************************************************************************/ 39843594Sdonahn /* fdintr */ 39943594Sdonahn /****************************************************************************/ 40049573Swilliam fdintr(unit) 40143594Sdonahn { 40243594Sdonahn register struct buf *dp,*bp; 40343594Sdonahn struct buf *dpother; 40445533Sbill int read,head,trac,sec,i,s,sectrac,cyl; 40543594Sdonahn unsigned long blknum; 40643594Sdonahn struct fd_type *ft; 40743594Sdonahn 40845533Sbill #ifdef FDTEST 40949573Swilliam printf("state %d, unit %d, dr %d|",fd_state,unit,fd_drive); 41045533Sbill #endif 41145533Sbill 41243594Sdonahn dp = &fd_unit[fd_drive].head; 41343594Sdonahn bp = dp->b_actf; 41443594Sdonahn read = bp->b_flags & B_READ; 41545533Sbill ft = &fd_types[FDTYPE(bp->b_dev)]; 41643594Sdonahn 41743594Sdonahn switch (fd_state) { 41843594Sdonahn case 1 : /* SEEK DONE, START DMA */ 41945533Sbill /* Make sure seek really happened*/ 42049573Swilliam if (unit != 0xff) { 42145533Sbill out_fdc(0x8); 42245533Sbill i = in_fdc(); 42345533Sbill cyl = in_fdc(); 42445533Sbill if (!(i&0x20) || (cyl != bp->b_cylin*dp->b_step)) { 42549878Sbostic printf("Stray int ST0 = %lx, PCN = %lx:",i,cyl); 42645533Sbill return; 42745533Sbill } 42845533Sbill } 42945533Sbill 43043594Sdonahn fd_track = bp->b_cylin; 43145533Sbill at_dma(read,bp->b_un.b_addr+fd_skip,FDBLK, fd_dmachan); 43243594Sdonahn blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK 43343594Sdonahn + fd_skip/FDBLK; 43443594Sdonahn sectrac = ft->sectrac; 43543594Sdonahn sec = blknum % (sectrac * 2); 43643594Sdonahn head = sec / sectrac; 43743594Sdonahn sec = sec % sectrac + 1; 43843594Sdonahn 43943594Sdonahn if (read) out_fdc(0xE6); /* READ */ 44043594Sdonahn else out_fdc(0xC5); /* WRITE */ 44143594Sdonahn out_fdc(head << 2 | fd_drive); /* head & unit */ 44243594Sdonahn out_fdc(fd_track); /* track */ 44343594Sdonahn out_fdc(head); 44443594Sdonahn out_fdc(sec); /* sector XXX +1? */ 44543594Sdonahn out_fdc(ft->secsize); /* sector size */ 44643594Sdonahn out_fdc(sectrac); /* sectors/track */ 44743594Sdonahn out_fdc(ft->gap); /* gap size */ 44843594Sdonahn out_fdc(ft->datalen); /* data length */ 44943594Sdonahn fd_state = 2; 45043594Sdonahn /* XXX PARANOIA */ 45143594Sdonahn untimeout(fd_timeout,2); 45243594Sdonahn timeout(fd_timeout,2,hz); 45343594Sdonahn break; 45443594Sdonahn case 2 : /* IO DONE, post-analyze */ 45543594Sdonahn untimeout(fd_timeout,2); 45643594Sdonahn for(i=0;i<7;i++) { 45743594Sdonahn fd_status[i] = in_fdc(); 45843594Sdonahn } 45943594Sdonahn if (fd_status[0]&0xF8) { 46043594Sdonahn #ifdef FDOTHER 46145533Sbill printf("status0 err %d:",fd_status[0]); 46243594Sdonahn #endif 46343594Sdonahn goto retry; 46443594Sdonahn } 46545533Sbill /* 46643594Sdonahn if (fd_status[1]){ 46743594Sdonahn printf("status1 err %d:",fd_status[0]); 46843594Sdonahn goto retry; 46943594Sdonahn } 47043594Sdonahn if (fd_status[2]){ 47143594Sdonahn printf("status2 err %d:",fd_status[0]); 47243594Sdonahn goto retry; 47343594Sdonahn } 47445533Sbill */ 47543594Sdonahn /* All OK */ 47643594Sdonahn if (!kernel_space(bp->b_un.b_addr+fd_skip)) { 47743594Sdonahn /* RAW transfer */ 47845533Sbill if (read) bcopy(dma_bounce[fd_dmachan]->b_un.b_addr, 47945533Sbill bp->b_un.b_addr+fd_skip, FDBLK); 48043594Sdonahn } 48143594Sdonahn fd_skip += FDBLK; 48243594Sdonahn if (fd_skip >= bp->b_bcount) { 48345533Sbill #ifdef FDTEST 48445533Sbill printf("DONE %d|", bp->b_blkno); 48545533Sbill #endif 48643594Sdonahn /* ALL DONE */ 48743594Sdonahn fd_skip = 0; 48843594Sdonahn bp->b_resid = 0; 48943594Sdonahn dp->b_actf = bp->av_forw; 49043594Sdonahn biodone(bp); 49143594Sdonahn nextstate(dp); 49243594Sdonahn 49343594Sdonahn } else { 49445533Sbill #ifdef FDDEBUG 49545533Sbill printf("next|"); 49645533Sbill #endif 49743594Sdonahn /* set up next transfer */ 49843594Sdonahn blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK 49943594Sdonahn + fd_skip/FDBLK; 50043594Sdonahn fd_state = 1; 50143594Sdonahn bp->b_cylin = (blknum / (ft->sectrac * 2)); 50243594Sdonahn if (bp->b_cylin != fd_track) { 50345533Sbill #ifdef FDTEST 50445533Sbill printf("Seek|"); 50545533Sbill #endif 50643594Sdonahn /* SEEK Necessary */ 50743594Sdonahn out_fdc(15); /* Seek function */ 50843594Sdonahn out_fdc(fd_drive);/* Drive number */ 50945533Sbill out_fdc(bp->b_cylin * dp->b_step); 51043594Sdonahn break; 51149573Swilliam } else fdintr(0xff); 51243594Sdonahn } 51343594Sdonahn break; 51443594Sdonahn case 3: 51545533Sbill #ifdef FDOTHER 51645533Sbill printf("Seek %d %d\n", bp->b_cylin, dp->b_step); 51745533Sbill #endif 51843594Sdonahn /* Seek necessary */ 51943594Sdonahn out_fdc(15); /* Seek function */ 52043594Sdonahn out_fdc(fd_drive);/* Drive number */ 52145533Sbill out_fdc(bp->b_cylin * dp->b_step); 52243594Sdonahn fd_state = 1; 52343594Sdonahn break; 52443594Sdonahn case 4: 52543594Sdonahn out_fdc(3); /* specify command */ 52643594Sdonahn out_fdc(0xDF); 52743594Sdonahn out_fdc(2); 52843594Sdonahn out_fdc(7); /* Recalibrate Function */ 52943594Sdonahn out_fdc(fd_drive); 53043594Sdonahn fd_state = 3; 53143594Sdonahn break; 53245533Sbill case 5: 53345533Sbill #ifdef FDOTHER 53445533Sbill printf("**RESET**\n"); 53545533Sbill #endif 53645533Sbill /* Try a reset, keep motor on */ 53745533Sbill set_motor(fd_drive,1); 53845533Sbill set_motor(fd_drive,0); 53945533Sbill outb(fdc+fdctl,ft->trans); 54045533Sbill fd_retry++; 54145533Sbill fd_state = 4; 54245533Sbill break; 54343594Sdonahn default: 54443594Sdonahn printf("Unexpected FD int->"); 54543594Sdonahn out_fdc(0x8); 54643594Sdonahn i = in_fdc(); 54743594Sdonahn sec = in_fdc(); 54849878Sbostic printf("ST0 = %lx, PCN = %lx\n",i,sec); 54943594Sdonahn out_fdc(0x4A); 55043594Sdonahn out_fdc(fd_drive); 55143594Sdonahn for(i=0;i<7;i++) { 55243594Sdonahn fd_status[i] = in_fdc(); 55343594Sdonahn } 55449878Sbostic printf("intr status :%lx %lx %lx %lx %lx %lx %lx ", 55543594Sdonahn fd_status[0], fd_status[1], fd_status[2], fd_status[3], 55643594Sdonahn fd_status[4], fd_status[5], fd_status[6] ); 55743594Sdonahn break; 55843594Sdonahn } 55943594Sdonahn return; 56043594Sdonahn retry: 56143594Sdonahn switch(fd_retry) { 56243594Sdonahn case 0: case 1: 56345533Sbill case 2: case 3: 56443594Sdonahn break; 56545533Sbill case 4: 56643594Sdonahn fd_retry++; 56745533Sbill fd_state = 5; 56849573Swilliam fdintr(0xff); 56943594Sdonahn return; 57045533Sbill case 5: case 6: case 7: 57143594Sdonahn break; 57243594Sdonahn default: 57349878Sbostic printf("FD err %lx %lx %lx %lx %lx %lx %lx\n", 57443594Sdonahn fd_status[0], fd_status[1], fd_status[2], fd_status[3], 57543594Sdonahn fd_status[4], fd_status[5], fd_status[6] ); 57643594Sdonahn badtrans(dp,bp); 57743594Sdonahn return; 57843594Sdonahn } 57943594Sdonahn fd_state = 1; 58043594Sdonahn fd_retry++; 58149573Swilliam fdintr(0xff); 58243594Sdonahn } 58343594Sdonahn 58443594Sdonahn badtrans(dp,bp) 58543594Sdonahn struct buf *dp,*bp; 58643594Sdonahn { 58743594Sdonahn 58843594Sdonahn bp->b_flags |= B_ERROR; 58943594Sdonahn bp->b_error = EIO; 59043594Sdonahn bp->b_resid = bp->b_bcount - fd_skip; 59143594Sdonahn dp->b_actf = bp->av_forw; 59243594Sdonahn fd_skip = 0; 59343594Sdonahn biodone(bp); 59443594Sdonahn nextstate(dp); 59543594Sdonahn 59643594Sdonahn } 59743594Sdonahn 59843594Sdonahn /* 59943594Sdonahn nextstate : After a transfer is done, continue processing 60043594Sdonahn requests on the current drive queue. If empty, go to 60143594Sdonahn the other drives queue. If that is empty too, timeout 60243594Sdonahn to turn off the current drive in 5 seconds, and go 60343594Sdonahn to state 0 (not expecting any interrupts). 60443594Sdonahn */ 60543594Sdonahn 60643594Sdonahn nextstate(dp) 60743594Sdonahn struct buf *dp; 60843594Sdonahn { 60943594Sdonahn 610*52360Sbostic if (dp->b_actf) 611*52360Sbostic fdstart(fd_drive); 612*52360Sbostic else { 613*52360Sbostic #if NFD > 1 614*52360Sbostic struct buf *dpother; 615*52360Sbostic 616*52360Sbostic dpother = &fd_unit[fd_drive ? 0 : 1].head; 617*52360Sbostic 618*52360Sbostic if (dpother->b_actf) { 61945533Sbill #ifdef FDTEST 62045533Sbill printf("switch|"); 62145533Sbill #endif 622*52360Sbostic untimeout(fd_turnoff,fd_drive); 623*52360Sbostic timeout(fd_turnoff,fd_drive,5*hz); 624*52360Sbostic fd_drive = 1 - fd_drive; 625*52360Sbostic dp->b_active = 0; 626*52360Sbostic dpother->b_active = 1; 627*52360Sbostic fdstart(fd_drive); 628*52360Sbostic } else 629*52360Sbostic #endif 630*52360Sbostic { 63145533Sbill #ifdef FDTEST 63245533Sbill printf("off|"); 63345533Sbill #endif 634*52360Sbostic untimeout(fd_turnoff,fd_drive); 635*52360Sbostic timeout(fd_turnoff,fd_drive,5*hz); 636*52360Sbostic fd_state = 0; 637*52360Sbostic dp->b_active = 0; 638*52360Sbostic } 63943594Sdonahn } 64043594Sdonahn } 64151729Swilliam 64251729Swilliam Fdioctl() {} 64351729Swilliam Fddump() {} 64445533Sbill #endif 645