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*51729Swilliam * @(#)fd.c 7.5 (Berkeley) 11/16/91 1143594Sdonahn */ 1243594Sdonahn 1349825Sbostic #include "fd.h" 1449825Sbostic #if NFD > 0 1549825Sbostic 1643594Sdonahn #include "param.h" 1743594Sdonahn #include "dkbad.h" 1843594Sdonahn #include "systm.h" 1943594Sdonahn #include "conf.h" 2043594Sdonahn #include "file.h" 2143594Sdonahn #include "ioctl.h" 2243594Sdonahn #include "buf.h" 2343594Sdonahn #include "uio.h" 2449573Swilliam #include "i386/isa/isa_device.h" 2549573Swilliam #include "i386/isa/fdreg.h" 2649573Swilliam #include "i386/isa/icu.h" 2743594Sdonahn 2843594Sdonahn #define FDUNIT(s) ((s)&1) 2943594Sdonahn #define FDTYPE(s) (((s)>>1)&7) 3045533Sbill 3143594Sdonahn #define b_cylin b_resid 3245533Sbill #define b_step b_resid 3343594Sdonahn #define FDBLK 512 3443594Sdonahn #define NUMTYPES 4 3543594Sdonahn 3643594Sdonahn struct fd_type { 3743594Sdonahn int sectrac; /* sectors per track */ 3843594Sdonahn int secsize; /* size code for sectors */ 3943594Sdonahn int datalen; /* data len when secsize = 0 */ 4043594Sdonahn int gap; /* gap len between sectors */ 4143594Sdonahn int tracks; /* total num of tracks */ 4243594Sdonahn int size; /* size of disk in sectors */ 4343594Sdonahn int steptrac; /* steps per cylinder */ 4443594Sdonahn int trans; /* transfer speed code */ 4543594Sdonahn }; 4643594Sdonahn 4743594Sdonahn struct fd_type fd_types[NUMTYPES] = { 4845533Sbill { 18,2,0xFF,0x1B,80,2880,1,0 }, /* 1.44 meg HD 3.5in floppy */ 4943594Sdonahn { 15,2,0xFF,0x1B,80,2400,1,0 }, /* 1.2 meg HD floppy */ 5043594Sdonahn { 9,2,0xFF,0x23,40,720,2,1 }, /* 360k floppy in 1.2meg drive */ 5143594Sdonahn { 9,2,0xFF,0x2A,40,720,1,1 }, /* 360k floppy in DD drive */ 5243594Sdonahn }; 5343594Sdonahn 5443594Sdonahn struct fd_u { 5543594Sdonahn int type; /* Drive type (HD, DD */ 5643594Sdonahn int active; /* Drive activity boolean */ 5743594Sdonahn int motor; /* Motor on flag */ 5843594Sdonahn struct buf head; /* Head of buf chain */ 5943594Sdonahn struct buf rhead; /* Raw head of buf chain */ 6045533Sbill int reset; 6143594Sdonahn } fd_unit[NFD]; 6243594Sdonahn 6345533Sbill 6443594Sdonahn extern int hz; 6543594Sdonahn 6643594Sdonahn /* state needed for current transfer */ 6745533Sbill static fdc; /* floppy disk controller io base register */ 6845533Sbill int fd_dmachan = 2; 6943594Sdonahn static int fd_skip; 7043594Sdonahn static int fd_state; 7143594Sdonahn static int fd_retry; 7243594Sdonahn static int fd_drive; 7345533Sbill static int fd_track = -1; 7443594Sdonahn static int fd_status[7]; 7543594Sdonahn 7645533Sbill /* 7745533Sbill make sure bounce buffer for DMA is aligned since the DMA chip 7845533Sbill doesn't roll over properly over a 64k boundary 7945533Sbill */ 8045533Sbill extern struct buf *dma_bounce[]; 8143594Sdonahn 8243594Sdonahn /****************************************************************************/ 8343594Sdonahn /* autoconfiguration stuff */ 8443594Sdonahn /****************************************************************************/ 8543594Sdonahn int fdprobe(), fdattach(), fd_turnoff(); 8643594Sdonahn 8745533Sbill struct isa_driver fddriver = { 8843594Sdonahn fdprobe, fdattach, "fd", 8943594Sdonahn }; 9043594Sdonahn 9143594Sdonahn fdprobe(dev) 9245533Sbill struct isa_device *dev; 9343594Sdonahn { 9443594Sdonahn return 1; 9543594Sdonahn } 9643594Sdonahn 9743594Sdonahn fdattach(dev) 9845533Sbill struct isa_device *dev; 9945533Sbill { int s; 10045533Sbill 10145533Sbill fdc = dev->id_iobase; 10245533Sbill /* Set transfer to 500kbps */ 10345533Sbill outb(fdc+fdctl,0); 10445533Sbill fd_turnoff(0); 10545533Sbill } 10645533Sbill 10745533Sbill int 108*51729Swilliam Fdsize(dev) 10945533Sbill dev_t dev; 11043594Sdonahn { 11145533Sbill return(2400); 11243594Sdonahn } 11343594Sdonahn 11443594Sdonahn /****************************************************************************/ 11543594Sdonahn /* fdstrategy */ 11643594Sdonahn /****************************************************************************/ 117*51729Swilliam Fdstrategy(bp) 11843594Sdonahn register struct buf *bp; /* IO operation to perform */ 11943594Sdonahn { 12043594Sdonahn register struct buf *dp,*dp0,*dp1; 12143594Sdonahn long nblocks,blknum; 12245533Sbill int unit, type, s; 12343594Sdonahn 12445533Sbill unit = FDUNIT(minor(bp->b_dev)); 12545533Sbill type = FDTYPE(minor(bp->b_dev)); 12645533Sbill 12745533Sbill #ifdef FDTEST 12845533Sbill printf("fdstrat%d, blk = %d, bcount = %d, addr = %x|", 12945533Sbill unit, bp->b_blkno, bp->b_bcount,bp->b_un.b_addr); 13043594Sdonahn #endif 13143594Sdonahn if ((unit >= NFD) || (bp->b_blkno < 0)) { 13243594Sdonahn printf("fdstrat: unit = %d, blkno = %d, bcount = %d\n", 13343594Sdonahn unit, bp->b_blkno, bp->b_bcount); 13443594Sdonahn pg("fd:error in fdstrategy"); 13543594Sdonahn bp->b_error = EINVAL; 13645533Sbill bp->b_flags |= B_ERROR; 13743594Sdonahn goto bad; 13843594Sdonahn } 13943594Sdonahn /* 14043594Sdonahn * Set up block calculations. 14143594Sdonahn */ 14243594Sdonahn blknum = (unsigned long) bp->b_blkno * DEV_BSIZE/FDBLK; 14345533Sbill nblocks = fd_types[type].size; 14443594Sdonahn if (blknum + (bp->b_bcount / FDBLK) > nblocks) { 14545533Sbill if (blknum == nblocks) { 14645533Sbill bp->b_resid = bp->b_bcount; 14745533Sbill } else { 14845533Sbill bp->b_error = ENOSPC; 14945533Sbill bp->b_flags |= B_ERROR; 15045533Sbill } 15143594Sdonahn goto bad; 15243594Sdonahn } 15345533Sbill bp->b_cylin = blknum / (fd_types[type].sectrac * 2); 15443594Sdonahn dp = &fd_unit[unit].head; 15543594Sdonahn dp0 = &fd_unit[0].head; 15643594Sdonahn dp1 = &fd_unit[1].head; 15745533Sbill dp->b_step = (fd_types[fd_unit[unit].type].steptrac); 15843594Sdonahn s = splbio(); 15943594Sdonahn disksort(dp, bp); 16043594Sdonahn if ((dp0->b_active == 0)&&(dp1->b_active == 0)) { 16145533Sbill #ifdef FDDEBUG 16245533Sbill printf("T|"); 16345533Sbill #endif 16443594Sdonahn dp->b_active = 1; 16543594Sdonahn fd_drive = unit; 16645533Sbill fd_track = -1; /* force seek on first xfer */ 16743594Sdonahn untimeout(fd_turnoff,unit); 16843594Sdonahn fdstart(unit); /* start drive if idle */ 16943594Sdonahn } 17043594Sdonahn splx(s); 17143594Sdonahn return; 17243594Sdonahn 17343594Sdonahn bad: 17443594Sdonahn biodone(bp); 17543594Sdonahn } 17643594Sdonahn 17743594Sdonahn /****************************************************************************/ 17843594Sdonahn /* motor control stuff */ 17943594Sdonahn /****************************************************************************/ 18043594Sdonahn set_motor(unit,reset) 18143594Sdonahn int unit,reset; 18243594Sdonahn { 18343594Sdonahn int m0,m1; 18443594Sdonahn m0 = fd_unit[0].motor; 18543594Sdonahn m1 = fd_unit[1].motor; 18645533Sbill outb(fdc+fdout,unit | (reset ? 0 : 0xC) | (m0 ? 16 : 0) | (m1 ? 32 : 0)); 18743594Sdonahn } 18843594Sdonahn 18943594Sdonahn fd_turnoff(unit) 19043594Sdonahn int unit; 19143594Sdonahn { 19243594Sdonahn fd_unit[unit].motor = 0; 19343594Sdonahn if (unit) set_motor(0,0); 19443594Sdonahn else set_motor(1,0); 19543594Sdonahn } 19643594Sdonahn 19743594Sdonahn fd_turnon(unit) 19843594Sdonahn int unit; 19943594Sdonahn { 20043594Sdonahn fd_unit[unit].motor = 1; 20143594Sdonahn set_motor(unit,0); 20243594Sdonahn } 20343594Sdonahn 20443594Sdonahn /****************************************************************************/ 20543594Sdonahn /* fdc in/out */ 20643594Sdonahn /****************************************************************************/ 20743594Sdonahn int 20843594Sdonahn in_fdc() 20943594Sdonahn { 21043594Sdonahn int i; 21145533Sbill while ((i = inb(fdc+fdsts) & (NE7_DIO|NE7_RQM)) != (NE7_DIO|NE7_RQM)) 21245533Sbill if (i == NE7_RQM) return -1; 21345533Sbill return inb(fdc+fddata); 21443594Sdonahn } 21543594Sdonahn 21643594Sdonahn dump_stat() 21743594Sdonahn { 21843594Sdonahn int i; 21943594Sdonahn for(i=0;i<7;i++) { 22043594Sdonahn fd_status[i] = in_fdc(); 22143594Sdonahn if (fd_status[i] < 0) break; 22243594Sdonahn } 22349878Sbostic printf("FD bad status :%lx %lx %lx %lx %lx %lx %lx\n", 22445533Sbill fd_status[0], fd_status[1], fd_status[2], fd_status[3], 22545533Sbill fd_status[4], fd_status[5], fd_status[6] ); 22643594Sdonahn } 22743594Sdonahn 22843594Sdonahn out_fdc(x) 22943594Sdonahn int x; 23043594Sdonahn { 23143594Sdonahn int r,errcnt; 23243594Sdonahn static int maxcnt = 0; 23343594Sdonahn errcnt = 0; 23443594Sdonahn do { 23545533Sbill r = (inb(fdc+fdsts) & (NE7_DIO|NE7_RQM)); 23645533Sbill if (r== NE7_RQM) break; 23745533Sbill if (r==(NE7_DIO|NE7_RQM)) { 23843594Sdonahn dump_stat(); /* error: direction. eat up output */ 23943594Sdonahn #ifdef FDOTHER 24049878Sbostic printf("%lx\n",x); 24143594Sdonahn #endif 24243594Sdonahn } 24343594Sdonahn /* printf("Error r = %d:",r); */ 24443594Sdonahn errcnt++; 24543594Sdonahn } while (1); 24643594Sdonahn if (errcnt > maxcnt) { 24743594Sdonahn maxcnt = errcnt; 24843594Sdonahn #ifdef FDOTHER 24945533Sbill printf("New MAX = %d\n",maxcnt); 25043594Sdonahn #endif 25143594Sdonahn } 25245533Sbill outb(fdc+fddata,x); 25343594Sdonahn } 25443594Sdonahn 25543594Sdonahn /* see if fdc responding */ 25643594Sdonahn int 25743594Sdonahn check_fdc() 25843594Sdonahn { 25943594Sdonahn int i; 26043594Sdonahn for(i=0;i<100;i++) { 26145533Sbill if (inb(fdc+fdsts)& NE7_RQM) return 0; 26243594Sdonahn } 26343594Sdonahn return 1; 26443594Sdonahn } 26543594Sdonahn 26643594Sdonahn /****************************************************************************/ 26743594Sdonahn /* fdopen/fdclose */ 26843594Sdonahn /****************************************************************************/ 26949573Swilliam Fdopen(dev, flags) 27043594Sdonahn dev_t dev; 27143594Sdonahn int flags; 27243594Sdonahn { 27345533Sbill int unit = FDUNIT(minor(dev)); 27445533Sbill int type = FDTYPE(minor(dev)); 27543594Sdonahn int s; 27643594Sdonahn 27743594Sdonahn /* check bounds */ 27843594Sdonahn if (unit >= NFD) return(ENXIO); 27943594Sdonahn if (type >= NUMTYPES) return(ENXIO); 28045533Sbill /* 28143594Sdonahn if (check_fdc()) return(EBUSY); 28245533Sbill */ 28343594Sdonahn 28443594Sdonahn /* Set proper disk type, only allow one type */ 28543594Sdonahn return 0; 28643594Sdonahn } 28743594Sdonahn 288*51729Swilliam Fdclose(dev, flags) 28943594Sdonahn dev_t dev; 29043594Sdonahn { 29143594Sdonahn } 29243594Sdonahn 29343594Sdonahn /****************************************************************************/ 29443594Sdonahn /* fdread/fdwrite */ 29543594Sdonahn /****************************************************************************/ 29643594Sdonahn /* 29743594Sdonahn * Routines to do raw IO for a unit. 29843594Sdonahn */ 299*51729Swilliam Fdread(dev, uio) /* character read routine */ 30043594Sdonahn dev_t dev; 30143594Sdonahn struct uio *uio; 30243594Sdonahn { 30345533Sbill int unit = FDUNIT(minor(dev)) ; 30443594Sdonahn if (unit >= NFD) return(ENXIO); 305*51729Swilliam return(physio(Fdstrategy,&fd_unit[unit].rhead,dev,B_READ,minphys,uio)); 30643594Sdonahn } 30743594Sdonahn 308*51729Swilliam Fdwrite(dev, uio) /* character write routine */ 30943594Sdonahn dev_t dev; 31043594Sdonahn struct uio *uio; 31143594Sdonahn { 31245533Sbill int unit = FDUNIT(minor(dev)) ; 31343594Sdonahn if (unit >= NFD) return(ENXIO); 314*51729Swilliam return(physio(Fdstrategy,&fd_unit[unit].rhead,dev,B_WRITE,minphys,uio)); 31543594Sdonahn } 31643594Sdonahn 31743594Sdonahn /****************************************************************************/ 31843594Sdonahn /* fdstart */ 31943594Sdonahn /****************************************************************************/ 32043594Sdonahn fdstart(unit) 32143594Sdonahn int unit; 32243594Sdonahn { 32343594Sdonahn register struct buf *dp,*bp; 32443594Sdonahn int s; 32543594Sdonahn 32645533Sbill #ifdef FDTEST 32745533Sbill printf("st%d|",unit); 32845533Sbill #endif 32945533Sbill s = splbio(); 33043594Sdonahn if (!fd_unit[unit].motor) { 33143594Sdonahn fd_turnon(unit); 33243594Sdonahn /* Wait for 1 sec */ 33343594Sdonahn timeout(fdstart,unit,hz); 33445533Sbill /*DELAY(1000000);*/ 33545533Sbill }else 33645533Sbill { 33745533Sbill /* make sure drive is selected as well as on */ 33845533Sbill /*set_motor(unit,0);*/ 33945533Sbill 34043594Sdonahn dp = &fd_unit[unit].head; 34143594Sdonahn bp = dp->b_actf; 34243594Sdonahn fd_retry = 0; 34345533Sbill if (fd_unit[unit].reset) fd_state = 1; 34445533Sbill else { 34545533Sbill /* DO a RESET */ 34645533Sbill fd_unit[unit].reset = 1; 34745533Sbill fd_state = 5; 34845533Sbill } 34943594Sdonahn fd_skip = 0; 35045533Sbill #ifdef FDDEBUG 35145533Sbill printf("Seek %d %d\n", bp->b_cylin, dp->b_step); 35245533Sbill #endif 35345533Sbill if (bp->b_cylin != fd_track) { 35443594Sdonahn /* Seek necessary, never quite sure where head is at! */ 35543594Sdonahn out_fdc(15); /* Seek function */ 35643594Sdonahn out_fdc(unit); /* Drive number */ 35745533Sbill out_fdc(bp->b_cylin * dp->b_step); 35849573Swilliam } else fdintr(0xff); 35943594Sdonahn } 36045533Sbill splx(s); 36143594Sdonahn } 36243594Sdonahn 36343594Sdonahn fd_timeout(x) 36443594Sdonahn int x; 36543594Sdonahn { 36643594Sdonahn int i,j; 36743594Sdonahn struct buf *dp,*bp; 36843594Sdonahn 36943594Sdonahn dp = &fd_unit[fd_drive].head; 37043594Sdonahn bp = dp->b_actf; 37143594Sdonahn 37243594Sdonahn out_fdc(0x4); 37343594Sdonahn out_fdc(fd_drive); 37443594Sdonahn i = in_fdc(); 37549878Sbostic printf("Timeout drive status %lx\n",i); 37643594Sdonahn 37743594Sdonahn out_fdc(0x8); 37843594Sdonahn i = in_fdc(); 37943594Sdonahn j = in_fdc(); 38049878Sbostic printf("ST0 = %lx, PCN = %lx\n",i,j); 38143594Sdonahn 38243594Sdonahn if (bp) badtrans(dp,bp); 38343594Sdonahn } 38443594Sdonahn 38543594Sdonahn /****************************************************************************/ 38643594Sdonahn /* fdintr */ 38743594Sdonahn /****************************************************************************/ 38849573Swilliam fdintr(unit) 38943594Sdonahn { 39043594Sdonahn register struct buf *dp,*bp; 39143594Sdonahn struct buf *dpother; 39245533Sbill int read,head,trac,sec,i,s,sectrac,cyl; 39343594Sdonahn unsigned long blknum; 39443594Sdonahn struct fd_type *ft; 39543594Sdonahn 39645533Sbill #ifdef FDTEST 39749573Swilliam printf("state %d, unit %d, dr %d|",fd_state,unit,fd_drive); 39845533Sbill #endif 39945533Sbill 40043594Sdonahn dp = &fd_unit[fd_drive].head; 40143594Sdonahn bp = dp->b_actf; 40243594Sdonahn read = bp->b_flags & B_READ; 40345533Sbill ft = &fd_types[FDTYPE(bp->b_dev)]; 40443594Sdonahn 40543594Sdonahn switch (fd_state) { 40643594Sdonahn case 1 : /* SEEK DONE, START DMA */ 40745533Sbill /* Make sure seek really happened*/ 40849573Swilliam if (unit != 0xff) { 40945533Sbill out_fdc(0x8); 41045533Sbill i = in_fdc(); 41145533Sbill cyl = in_fdc(); 41245533Sbill if (!(i&0x20) || (cyl != bp->b_cylin*dp->b_step)) { 41349878Sbostic printf("Stray int ST0 = %lx, PCN = %lx:",i,cyl); 41445533Sbill return; 41545533Sbill } 41645533Sbill } 41745533Sbill 41843594Sdonahn fd_track = bp->b_cylin; 41945533Sbill at_dma(read,bp->b_un.b_addr+fd_skip,FDBLK, fd_dmachan); 42043594Sdonahn blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK 42143594Sdonahn + fd_skip/FDBLK; 42243594Sdonahn sectrac = ft->sectrac; 42343594Sdonahn sec = blknum % (sectrac * 2); 42443594Sdonahn head = sec / sectrac; 42543594Sdonahn sec = sec % sectrac + 1; 42643594Sdonahn 42743594Sdonahn if (read) out_fdc(0xE6); /* READ */ 42843594Sdonahn else out_fdc(0xC5); /* WRITE */ 42943594Sdonahn out_fdc(head << 2 | fd_drive); /* head & unit */ 43043594Sdonahn out_fdc(fd_track); /* track */ 43143594Sdonahn out_fdc(head); 43243594Sdonahn out_fdc(sec); /* sector XXX +1? */ 43343594Sdonahn out_fdc(ft->secsize); /* sector size */ 43443594Sdonahn out_fdc(sectrac); /* sectors/track */ 43543594Sdonahn out_fdc(ft->gap); /* gap size */ 43643594Sdonahn out_fdc(ft->datalen); /* data length */ 43743594Sdonahn fd_state = 2; 43843594Sdonahn /* XXX PARANOIA */ 43943594Sdonahn untimeout(fd_timeout,2); 44043594Sdonahn timeout(fd_timeout,2,hz); 44143594Sdonahn break; 44243594Sdonahn case 2 : /* IO DONE, post-analyze */ 44343594Sdonahn untimeout(fd_timeout,2); 44443594Sdonahn for(i=0;i<7;i++) { 44543594Sdonahn fd_status[i] = in_fdc(); 44643594Sdonahn } 44743594Sdonahn if (fd_status[0]&0xF8) { 44843594Sdonahn #ifdef FDOTHER 44945533Sbill printf("status0 err %d:",fd_status[0]); 45043594Sdonahn #endif 45143594Sdonahn goto retry; 45243594Sdonahn } 45345533Sbill /* 45443594Sdonahn if (fd_status[1]){ 45543594Sdonahn printf("status1 err %d:",fd_status[0]); 45643594Sdonahn goto retry; 45743594Sdonahn } 45843594Sdonahn if (fd_status[2]){ 45943594Sdonahn printf("status2 err %d:",fd_status[0]); 46043594Sdonahn goto retry; 46143594Sdonahn } 46245533Sbill */ 46343594Sdonahn /* All OK */ 46443594Sdonahn if (!kernel_space(bp->b_un.b_addr+fd_skip)) { 46543594Sdonahn /* RAW transfer */ 46645533Sbill if (read) bcopy(dma_bounce[fd_dmachan]->b_un.b_addr, 46745533Sbill bp->b_un.b_addr+fd_skip, FDBLK); 46843594Sdonahn } 46943594Sdonahn fd_skip += FDBLK; 47043594Sdonahn if (fd_skip >= bp->b_bcount) { 47145533Sbill #ifdef FDTEST 47245533Sbill printf("DONE %d|", bp->b_blkno); 47345533Sbill #endif 47443594Sdonahn /* ALL DONE */ 47543594Sdonahn fd_skip = 0; 47643594Sdonahn bp->b_resid = 0; 47743594Sdonahn dp->b_actf = bp->av_forw; 47843594Sdonahn biodone(bp); 47943594Sdonahn nextstate(dp); 48043594Sdonahn 48143594Sdonahn } else { 48245533Sbill #ifdef FDDEBUG 48345533Sbill printf("next|"); 48445533Sbill #endif 48543594Sdonahn /* set up next transfer */ 48643594Sdonahn blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK 48743594Sdonahn + fd_skip/FDBLK; 48843594Sdonahn fd_state = 1; 48943594Sdonahn bp->b_cylin = (blknum / (ft->sectrac * 2)); 49043594Sdonahn if (bp->b_cylin != fd_track) { 49145533Sbill #ifdef FDTEST 49245533Sbill printf("Seek|"); 49345533Sbill #endif 49443594Sdonahn /* SEEK Necessary */ 49543594Sdonahn out_fdc(15); /* Seek function */ 49643594Sdonahn out_fdc(fd_drive);/* Drive number */ 49745533Sbill out_fdc(bp->b_cylin * dp->b_step); 49843594Sdonahn break; 49949573Swilliam } else fdintr(0xff); 50043594Sdonahn } 50143594Sdonahn break; 50243594Sdonahn case 3: 50345533Sbill #ifdef FDOTHER 50445533Sbill printf("Seek %d %d\n", bp->b_cylin, dp->b_step); 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 fd_state = 1; 51143594Sdonahn break; 51243594Sdonahn case 4: 51343594Sdonahn out_fdc(3); /* specify command */ 51443594Sdonahn out_fdc(0xDF); 51543594Sdonahn out_fdc(2); 51643594Sdonahn out_fdc(7); /* Recalibrate Function */ 51743594Sdonahn out_fdc(fd_drive); 51843594Sdonahn fd_state = 3; 51943594Sdonahn break; 52045533Sbill case 5: 52145533Sbill #ifdef FDOTHER 52245533Sbill printf("**RESET**\n"); 52345533Sbill #endif 52445533Sbill /* Try a reset, keep motor on */ 52545533Sbill set_motor(fd_drive,1); 52645533Sbill set_motor(fd_drive,0); 52745533Sbill outb(fdc+fdctl,ft->trans); 52845533Sbill fd_retry++; 52945533Sbill fd_state = 4; 53045533Sbill break; 53143594Sdonahn default: 53243594Sdonahn printf("Unexpected FD int->"); 53343594Sdonahn out_fdc(0x8); 53443594Sdonahn i = in_fdc(); 53543594Sdonahn sec = in_fdc(); 53649878Sbostic printf("ST0 = %lx, PCN = %lx\n",i,sec); 53743594Sdonahn out_fdc(0x4A); 53843594Sdonahn out_fdc(fd_drive); 53943594Sdonahn for(i=0;i<7;i++) { 54043594Sdonahn fd_status[i] = in_fdc(); 54143594Sdonahn } 54249878Sbostic printf("intr status :%lx %lx %lx %lx %lx %lx %lx ", 54343594Sdonahn fd_status[0], fd_status[1], fd_status[2], fd_status[3], 54443594Sdonahn fd_status[4], fd_status[5], fd_status[6] ); 54543594Sdonahn break; 54643594Sdonahn } 54743594Sdonahn return; 54843594Sdonahn retry: 54943594Sdonahn switch(fd_retry) { 55043594Sdonahn case 0: case 1: 55145533Sbill case 2: case 3: 55243594Sdonahn break; 55345533Sbill case 4: 55443594Sdonahn fd_retry++; 55545533Sbill fd_state = 5; 55649573Swilliam fdintr(0xff); 55743594Sdonahn return; 55845533Sbill case 5: case 6: case 7: 55943594Sdonahn break; 56043594Sdonahn default: 56149878Sbostic printf("FD err %lx %lx %lx %lx %lx %lx %lx\n", 56243594Sdonahn fd_status[0], fd_status[1], fd_status[2], fd_status[3], 56343594Sdonahn fd_status[4], fd_status[5], fd_status[6] ); 56443594Sdonahn badtrans(dp,bp); 56543594Sdonahn return; 56643594Sdonahn } 56743594Sdonahn fd_state = 1; 56843594Sdonahn fd_retry++; 56949573Swilliam fdintr(0xff); 57043594Sdonahn } 57143594Sdonahn 57243594Sdonahn badtrans(dp,bp) 57343594Sdonahn struct buf *dp,*bp; 57443594Sdonahn { 57543594Sdonahn 57643594Sdonahn bp->b_flags |= B_ERROR; 57743594Sdonahn bp->b_error = EIO; 57843594Sdonahn bp->b_resid = bp->b_bcount - fd_skip; 57943594Sdonahn dp->b_actf = bp->av_forw; 58043594Sdonahn fd_skip = 0; 58143594Sdonahn biodone(bp); 58243594Sdonahn nextstate(dp); 58343594Sdonahn 58443594Sdonahn } 58543594Sdonahn 58643594Sdonahn /* 58743594Sdonahn nextstate : After a transfer is done, continue processing 58843594Sdonahn requests on the current drive queue. If empty, go to 58943594Sdonahn the other drives queue. If that is empty too, timeout 59043594Sdonahn to turn off the current drive in 5 seconds, and go 59143594Sdonahn to state 0 (not expecting any interrupts). 59243594Sdonahn */ 59343594Sdonahn 59443594Sdonahn nextstate(dp) 59543594Sdonahn struct buf *dp; 59643594Sdonahn { 59743594Sdonahn struct buf *dpother; 59843594Sdonahn 59943594Sdonahn dpother = &fd_unit[fd_drive ? 0 : 1].head; 60043594Sdonahn if (dp->b_actf) fdstart(fd_drive); 60143594Sdonahn else if (dpother->b_actf) { 60245533Sbill #ifdef FDTEST 60345533Sbill printf("switch|"); 60445533Sbill #endif 60545533Sbill untimeout(fd_turnoff,fd_drive); 60645533Sbill timeout(fd_turnoff,fd_drive,5*hz); 60745533Sbill fd_drive = 1 - fd_drive; 60843594Sdonahn dp->b_active = 0; 60945533Sbill dpother->b_active = 1; 61045533Sbill fdstart(fd_drive); 61143594Sdonahn } else { 61245533Sbill #ifdef FDTEST 61345533Sbill printf("off|"); 61445533Sbill #endif 61543594Sdonahn untimeout(fd_turnoff,fd_drive); 61643594Sdonahn timeout(fd_turnoff,fd_drive,5*hz); 61743594Sdonahn fd_state = 0; 61843594Sdonahn dp->b_active = 0; 61943594Sdonahn } 62043594Sdonahn } 621*51729Swilliam 622*51729Swilliam Fdioctl() {} 623*51729Swilliam Fddump() {} 62445533Sbill #endif 625