1*45533Sbill #include "fd.h" 2*45533Sbill #if NFD > 0 343594Sdonahn /*- 443594Sdonahn * Copyright (c) 1990 The Regents of the University of California. 543594Sdonahn * All rights reserved. 643594Sdonahn * 743594Sdonahn * This code is derived from software contributed to Berkeley by 843594Sdonahn * Don Ahn. 943594Sdonahn * 1043594Sdonahn * %sccs.include.386.c% 1143594Sdonahn * 12*45533Sbill * @(#)fd.c 5.2 (Berkeley) 11/08/90 1343594Sdonahn */ 1443594Sdonahn 1543594Sdonahn /****************************************************************************/ 1643594Sdonahn /* fd driver */ 1743594Sdonahn /****************************************************************************/ 1843594Sdonahn #include "param.h" 1943594Sdonahn #include "dkbad.h" 2043594Sdonahn #include "systm.h" 2143594Sdonahn #include "conf.h" 2243594Sdonahn #include "file.h" 2343594Sdonahn #include "dir.h" 2443594Sdonahn #include "user.h" 2543594Sdonahn #include "ioctl.h" 2643594Sdonahn #include "disk.h" 2743594Sdonahn #include "buf.h" 2843594Sdonahn #include "vm.h" 2943594Sdonahn #include "uio.h" 3043594Sdonahn #include "machine/pte.h" 31*45533Sbill #include "machine/isa/device.h" 32*45533Sbill #include "machine/isa/fdreg.h" 3343594Sdonahn #include "icu.h" 3443594Sdonahn 3543594Sdonahn #define FDUNIT(s) ((s)&1) 3643594Sdonahn #define FDTYPE(s) (((s)>>1)&7) 37*45533Sbill 3843594Sdonahn #define b_cylin b_resid 39*45533Sbill #define b_step b_resid 4043594Sdonahn #define FDBLK 512 4143594Sdonahn #define NUMTYPES 4 4243594Sdonahn 4343594Sdonahn struct fd_type { 4443594Sdonahn int sectrac; /* sectors per track */ 4543594Sdonahn int secsize; /* size code for sectors */ 4643594Sdonahn int datalen; /* data len when secsize = 0 */ 4743594Sdonahn int gap; /* gap len between sectors */ 4843594Sdonahn int tracks; /* total num of tracks */ 4943594Sdonahn int size; /* size of disk in sectors */ 5043594Sdonahn int steptrac; /* steps per cylinder */ 5143594Sdonahn int trans; /* transfer speed code */ 5243594Sdonahn }; 5343594Sdonahn 5443594Sdonahn struct fd_type fd_types[NUMTYPES] = { 55*45533Sbill { 18,2,0xFF,0x1B,80,2880,1,0 }, /* 1.44 meg HD 3.5in floppy */ 5643594Sdonahn { 15,2,0xFF,0x1B,80,2400,1,0 }, /* 1.2 meg HD floppy */ 5743594Sdonahn { 9,2,0xFF,0x23,40,720,2,1 }, /* 360k floppy in 1.2meg drive */ 5843594Sdonahn { 9,2,0xFF,0x2A,40,720,1,1 }, /* 360k floppy in DD drive */ 5943594Sdonahn }; 6043594Sdonahn 6143594Sdonahn struct fd_u { 6243594Sdonahn int type; /* Drive type (HD, DD */ 6343594Sdonahn int active; /* Drive activity boolean */ 6443594Sdonahn int motor; /* Motor on flag */ 6543594Sdonahn struct buf head; /* Head of buf chain */ 6643594Sdonahn struct buf rhead; /* Raw head of buf chain */ 67*45533Sbill int reset; 6843594Sdonahn } fd_unit[NFD]; 6943594Sdonahn 70*45533Sbill 7143594Sdonahn extern int hz; 7243594Sdonahn 7343594Sdonahn /* state needed for current transfer */ 74*45533Sbill static fdc; /* floppy disk controller io base register */ 75*45533Sbill int fd_dmachan = 2; 7643594Sdonahn static int fd_skip; 7743594Sdonahn static int fd_state; 7843594Sdonahn static int fd_retry; 7943594Sdonahn static int fd_drive; 80*45533Sbill static int fd_track = -1; 8143594Sdonahn static int fd_status[7]; 8243594Sdonahn 83*45533Sbill /* 84*45533Sbill make sure bounce buffer for DMA is aligned since the DMA chip 85*45533Sbill doesn't roll over properly over a 64k boundary 86*45533Sbill */ 87*45533Sbill extern struct buf *dma_bounce[]; 8843594Sdonahn 8943594Sdonahn /****************************************************************************/ 9043594Sdonahn /* autoconfiguration stuff */ 9143594Sdonahn /****************************************************************************/ 9243594Sdonahn int fdprobe(), fdattach(), fd_turnoff(); 9343594Sdonahn 94*45533Sbill struct isa_driver fddriver = { 9543594Sdonahn fdprobe, fdattach, "fd", 9643594Sdonahn }; 9743594Sdonahn 9843594Sdonahn fdprobe(dev) 99*45533Sbill struct isa_device *dev; 10043594Sdonahn { 10143594Sdonahn return 1; 10243594Sdonahn } 10343594Sdonahn 10443594Sdonahn fdattach(dev) 105*45533Sbill struct isa_device *dev; 106*45533Sbill { int s; 107*45533Sbill 108*45533Sbill fdc = dev->id_iobase; 109*45533Sbill /* Set transfer to 500kbps */ 110*45533Sbill outb(fdc+fdctl,0); 111*45533Sbill fd_turnoff(0); 112*45533Sbill } 113*45533Sbill 114*45533Sbill int 115*45533Sbill fdsize(dev) 116*45533Sbill dev_t dev; 11743594Sdonahn { 118*45533Sbill return(2400); 11943594Sdonahn } 12043594Sdonahn 12143594Sdonahn /****************************************************************************/ 12243594Sdonahn /* fdstrategy */ 12343594Sdonahn /****************************************************************************/ 12443594Sdonahn fdstrategy(bp) 12543594Sdonahn register struct buf *bp; /* IO operation to perform */ 12643594Sdonahn { 12743594Sdonahn register struct buf *dp,*dp0,*dp1; 12843594Sdonahn long nblocks,blknum; 129*45533Sbill int unit, type, s; 13043594Sdonahn 131*45533Sbill unit = FDUNIT(minor(bp->b_dev)); 132*45533Sbill type = FDTYPE(minor(bp->b_dev)); 133*45533Sbill 134*45533Sbill #ifdef FDTEST 135*45533Sbill printf("fdstrat%d, blk = %d, bcount = %d, addr = %x|", 136*45533Sbill unit, bp->b_blkno, bp->b_bcount,bp->b_un.b_addr); 13743594Sdonahn #endif 13843594Sdonahn if ((unit >= NFD) || (bp->b_blkno < 0)) { 13943594Sdonahn printf("fdstrat: unit = %d, blkno = %d, bcount = %d\n", 14043594Sdonahn unit, bp->b_blkno, bp->b_bcount); 14143594Sdonahn pg("fd:error in fdstrategy"); 14243594Sdonahn bp->b_error = EINVAL; 143*45533Sbill bp->b_flags |= B_ERROR; 14443594Sdonahn goto bad; 14543594Sdonahn } 14643594Sdonahn /* 14743594Sdonahn * Set up block calculations. 14843594Sdonahn */ 14943594Sdonahn blknum = (unsigned long) bp->b_blkno * DEV_BSIZE/FDBLK; 150*45533Sbill nblocks = fd_types[type].size; 15143594Sdonahn if (blknum + (bp->b_bcount / FDBLK) > nblocks) { 152*45533Sbill if (blknum == nblocks) { 153*45533Sbill bp->b_resid = bp->b_bcount; 154*45533Sbill } else { 155*45533Sbill bp->b_error = ENOSPC; 156*45533Sbill bp->b_flags |= B_ERROR; 157*45533Sbill } 15843594Sdonahn goto bad; 15943594Sdonahn } 160*45533Sbill bp->b_cylin = blknum / (fd_types[type].sectrac * 2); 16143594Sdonahn dp = &fd_unit[unit].head; 16243594Sdonahn dp0 = &fd_unit[0].head; 16343594Sdonahn dp1 = &fd_unit[1].head; 164*45533Sbill dp->b_step = (fd_types[fd_unit[unit].type].steptrac); 16543594Sdonahn s = splbio(); 16643594Sdonahn disksort(dp, bp); 16743594Sdonahn if ((dp0->b_active == 0)&&(dp1->b_active == 0)) { 168*45533Sbill #ifdef FDDEBUG 169*45533Sbill printf("T|"); 170*45533Sbill #endif 17143594Sdonahn dp->b_active = 1; 17243594Sdonahn fd_drive = unit; 173*45533Sbill fd_track = -1; /* force seek on first xfer */ 17443594Sdonahn untimeout(fd_turnoff,unit); 17543594Sdonahn fdstart(unit); /* start drive if idle */ 17643594Sdonahn } 17743594Sdonahn splx(s); 17843594Sdonahn return; 17943594Sdonahn 18043594Sdonahn bad: 18143594Sdonahn biodone(bp); 18243594Sdonahn } 18343594Sdonahn 18443594Sdonahn /****************************************************************************/ 18543594Sdonahn /* motor control stuff */ 18643594Sdonahn /****************************************************************************/ 18743594Sdonahn set_motor(unit,reset) 18843594Sdonahn int unit,reset; 18943594Sdonahn { 19043594Sdonahn int m0,m1; 19143594Sdonahn m0 = fd_unit[0].motor; 19243594Sdonahn m1 = fd_unit[1].motor; 193*45533Sbill outb(fdc+fdout,unit | (reset ? 0 : 0xC) | (m0 ? 16 : 0) | (m1 ? 32 : 0)); 19443594Sdonahn } 19543594Sdonahn 19643594Sdonahn fd_turnoff(unit) 19743594Sdonahn int unit; 19843594Sdonahn { 19943594Sdonahn fd_unit[unit].motor = 0; 20043594Sdonahn if (unit) set_motor(0,0); 20143594Sdonahn else set_motor(1,0); 20243594Sdonahn } 20343594Sdonahn 20443594Sdonahn fd_turnon(unit) 20543594Sdonahn int unit; 20643594Sdonahn { 20743594Sdonahn fd_unit[unit].motor = 1; 20843594Sdonahn set_motor(unit,0); 20943594Sdonahn } 21043594Sdonahn 21143594Sdonahn /****************************************************************************/ 21243594Sdonahn /* fdc in/out */ 21343594Sdonahn /****************************************************************************/ 21443594Sdonahn int 21543594Sdonahn in_fdc() 21643594Sdonahn { 21743594Sdonahn int i; 218*45533Sbill while ((i = inb(fdc+fdsts) & (NE7_DIO|NE7_RQM)) != (NE7_DIO|NE7_RQM)) 219*45533Sbill if (i == NE7_RQM) return -1; 220*45533Sbill return inb(fdc+fddata); 22143594Sdonahn } 22243594Sdonahn 22343594Sdonahn dump_stat() 22443594Sdonahn { 22543594Sdonahn int i; 22643594Sdonahn for(i=0;i<7;i++) { 22743594Sdonahn fd_status[i] = in_fdc(); 22843594Sdonahn if (fd_status[i] < 0) break; 22943594Sdonahn } 230*45533Sbill printf("FD bad status :%X %X %X %X %X %X %X\n", 231*45533Sbill fd_status[0], fd_status[1], fd_status[2], fd_status[3], 232*45533Sbill fd_status[4], fd_status[5], fd_status[6] ); 23343594Sdonahn } 23443594Sdonahn 23543594Sdonahn out_fdc(x) 23643594Sdonahn int x; 23743594Sdonahn { 23843594Sdonahn int r,errcnt; 23943594Sdonahn static int maxcnt = 0; 24043594Sdonahn errcnt = 0; 24143594Sdonahn do { 242*45533Sbill r = (inb(fdc+fdsts) & (NE7_DIO|NE7_RQM)); 243*45533Sbill if (r== NE7_RQM) break; 244*45533Sbill if (r==(NE7_DIO|NE7_RQM)) { 24543594Sdonahn dump_stat(); /* error: direction. eat up output */ 24643594Sdonahn #ifdef FDOTHER 247*45533Sbill printf("%X\n",x); 24843594Sdonahn #endif 24943594Sdonahn } 25043594Sdonahn /* printf("Error r = %d:",r); */ 25143594Sdonahn errcnt++; 25243594Sdonahn } while (1); 25343594Sdonahn if (errcnt > maxcnt) { 25443594Sdonahn maxcnt = errcnt; 25543594Sdonahn #ifdef FDOTHER 256*45533Sbill printf("New MAX = %d\n",maxcnt); 25743594Sdonahn #endif 25843594Sdonahn } 259*45533Sbill outb(fdc+fddata,x); 26043594Sdonahn } 26143594Sdonahn 26243594Sdonahn /* see if fdc responding */ 26343594Sdonahn int 26443594Sdonahn check_fdc() 26543594Sdonahn { 26643594Sdonahn int i; 26743594Sdonahn for(i=0;i<100;i++) { 268*45533Sbill if (inb(fdc+fdsts)& NE7_RQM) return 0; 26943594Sdonahn } 27043594Sdonahn return 1; 27143594Sdonahn } 27243594Sdonahn 27343594Sdonahn /****************************************************************************/ 27443594Sdonahn /* fdopen/fdclose */ 27543594Sdonahn /****************************************************************************/ 27643594Sdonahn fdopen(dev, flags) 27743594Sdonahn dev_t dev; 27843594Sdonahn int flags; 27943594Sdonahn { 280*45533Sbill int unit = FDUNIT(minor(dev)); 281*45533Sbill int type = FDTYPE(minor(dev)); 28243594Sdonahn int s; 28343594Sdonahn 28443594Sdonahn /* check bounds */ 28543594Sdonahn if (unit >= NFD) return(ENXIO); 28643594Sdonahn if (type >= NUMTYPES) return(ENXIO); 287*45533Sbill /* 28843594Sdonahn if (check_fdc()) return(EBUSY); 289*45533Sbill */ 29043594Sdonahn 29143594Sdonahn /* Set proper disk type, only allow one type */ 29243594Sdonahn return 0; 29343594Sdonahn } 29443594Sdonahn 29543594Sdonahn fdclose(dev) 29643594Sdonahn dev_t dev; 29743594Sdonahn { 29843594Sdonahn } 29943594Sdonahn 30043594Sdonahn /****************************************************************************/ 30143594Sdonahn /* fdread/fdwrite */ 30243594Sdonahn /****************************************************************************/ 30343594Sdonahn /* 30443594Sdonahn * Routines to do raw IO for a unit. 30543594Sdonahn */ 30643594Sdonahn fdread(dev, uio) /* character read routine */ 30743594Sdonahn dev_t dev; 30843594Sdonahn struct uio *uio; 30943594Sdonahn { 310*45533Sbill int unit = FDUNIT(minor(dev)) ; 31143594Sdonahn if (unit >= NFD) return(ENXIO); 31243594Sdonahn return(physio(fdstrategy,&fd_unit[unit].rhead,dev,B_READ,minphys,uio)); 31343594Sdonahn } 31443594Sdonahn 31543594Sdonahn fdwrite(dev, uio) /* character write routine */ 31643594Sdonahn dev_t dev; 31743594Sdonahn struct uio *uio; 31843594Sdonahn { 319*45533Sbill int unit = FDUNIT(minor(dev)) ; 32043594Sdonahn if (unit >= NFD) return(ENXIO); 32143594Sdonahn return(physio(fdstrategy,&fd_unit[unit].rhead,dev,B_WRITE,minphys,uio)); 32243594Sdonahn } 32343594Sdonahn 32443594Sdonahn /****************************************************************************/ 32543594Sdonahn /* fdstart */ 32643594Sdonahn /****************************************************************************/ 32743594Sdonahn fdstart(unit) 32843594Sdonahn int unit; 32943594Sdonahn { 33043594Sdonahn register struct buf *dp,*bp; 33143594Sdonahn int s; 33243594Sdonahn 333*45533Sbill #ifdef FDTEST 334*45533Sbill printf("st%d|",unit); 335*45533Sbill #endif 336*45533Sbill s = splbio(); 33743594Sdonahn if (!fd_unit[unit].motor) { 33843594Sdonahn fd_turnon(unit); 33943594Sdonahn /* Wait for 1 sec */ 34043594Sdonahn timeout(fdstart,unit,hz); 341*45533Sbill /*DELAY(1000000);*/ 342*45533Sbill }else 343*45533Sbill { 344*45533Sbill /* make sure drive is selected as well as on */ 345*45533Sbill /*set_motor(unit,0);*/ 346*45533Sbill 34743594Sdonahn dp = &fd_unit[unit].head; 34843594Sdonahn bp = dp->b_actf; 34943594Sdonahn fd_retry = 0; 350*45533Sbill if (fd_unit[unit].reset) fd_state = 1; 351*45533Sbill else { 352*45533Sbill /* DO a RESET */ 353*45533Sbill fd_unit[unit].reset = 1; 354*45533Sbill fd_state = 5; 355*45533Sbill } 35643594Sdonahn fd_skip = 0; 357*45533Sbill #ifdef FDDEBUG 358*45533Sbill printf("Seek %d %d\n", bp->b_cylin, dp->b_step); 359*45533Sbill #endif 360*45533Sbill if (bp->b_cylin != fd_track) { 36143594Sdonahn /* Seek necessary, never quite sure where head is at! */ 36243594Sdonahn out_fdc(15); /* Seek function */ 36343594Sdonahn out_fdc(unit); /* Drive number */ 364*45533Sbill out_fdc(bp->b_cylin * dp->b_step); 365*45533Sbill } else fdintr(0); 36643594Sdonahn } 367*45533Sbill splx(s); 36843594Sdonahn } 36943594Sdonahn 37043594Sdonahn fd_timeout(x) 37143594Sdonahn int x; 37243594Sdonahn { 37343594Sdonahn int i,j; 37443594Sdonahn struct buf *dp,*bp; 37543594Sdonahn 37643594Sdonahn dp = &fd_unit[fd_drive].head; 37743594Sdonahn bp = dp->b_actf; 37843594Sdonahn 37943594Sdonahn out_fdc(0x4); 38043594Sdonahn out_fdc(fd_drive); 38143594Sdonahn i = in_fdc(); 38243594Sdonahn printf("Timeout drive status %X\n",i); 38343594Sdonahn 38443594Sdonahn out_fdc(0x8); 38543594Sdonahn i = in_fdc(); 38643594Sdonahn j = in_fdc(); 38743594Sdonahn printf("ST0 = %X, PCN = %X\n",i,j); 38843594Sdonahn 38943594Sdonahn if (bp) badtrans(dp,bp); 39043594Sdonahn } 39143594Sdonahn 39243594Sdonahn /****************************************************************************/ 39343594Sdonahn /* fdintr */ 39443594Sdonahn /****************************************************************************/ 39543594Sdonahn fdintr(vec) 39643594Sdonahn int vec; 39743594Sdonahn { 39843594Sdonahn register struct buf *dp,*bp; 39943594Sdonahn struct buf *dpother; 400*45533Sbill int read,head,trac,sec,i,s,sectrac,cyl; 40143594Sdonahn unsigned long blknum; 40243594Sdonahn struct fd_type *ft; 40343594Sdonahn 404*45533Sbill #ifdef FDTEST 405*45533Sbill printf("state %d, vec %d, dr %d|",fd_state,vec,fd_drive); 406*45533Sbill #endif 407*45533Sbill 40843594Sdonahn dp = &fd_unit[fd_drive].head; 40943594Sdonahn bp = dp->b_actf; 41043594Sdonahn read = bp->b_flags & B_READ; 411*45533Sbill ft = &fd_types[FDTYPE(bp->b_dev)]; 41243594Sdonahn 41343594Sdonahn switch (fd_state) { 41443594Sdonahn case 1 : /* SEEK DONE, START DMA */ 415*45533Sbill /* Make sure seek really happened*/ 416*45533Sbill if (vec) { 417*45533Sbill out_fdc(0x8); 418*45533Sbill i = in_fdc(); 419*45533Sbill cyl = in_fdc(); 420*45533Sbill if (!(i&0x20) || (cyl != bp->b_cylin*dp->b_step)) { 421*45533Sbill printf("Stray int ST0 = %X, PCN = %X:",i,cyl); 422*45533Sbill return; 423*45533Sbill } 424*45533Sbill } 425*45533Sbill 42643594Sdonahn fd_track = bp->b_cylin; 427*45533Sbill at_dma(read,bp->b_un.b_addr+fd_skip,FDBLK, fd_dmachan); 42843594Sdonahn blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK 42943594Sdonahn + fd_skip/FDBLK; 43043594Sdonahn sectrac = ft->sectrac; 43143594Sdonahn sec = blknum % (sectrac * 2); 43243594Sdonahn head = sec / sectrac; 43343594Sdonahn sec = sec % sectrac + 1; 43443594Sdonahn 43543594Sdonahn if (read) out_fdc(0xE6); /* READ */ 43643594Sdonahn else out_fdc(0xC5); /* WRITE */ 43743594Sdonahn out_fdc(head << 2 | fd_drive); /* head & unit */ 43843594Sdonahn out_fdc(fd_track); /* track */ 43943594Sdonahn out_fdc(head); 44043594Sdonahn out_fdc(sec); /* sector XXX +1? */ 44143594Sdonahn out_fdc(ft->secsize); /* sector size */ 44243594Sdonahn out_fdc(sectrac); /* sectors/track */ 44343594Sdonahn out_fdc(ft->gap); /* gap size */ 44443594Sdonahn out_fdc(ft->datalen); /* data length */ 44543594Sdonahn fd_state = 2; 44643594Sdonahn /* XXX PARANOIA */ 44743594Sdonahn untimeout(fd_timeout,2); 44843594Sdonahn timeout(fd_timeout,2,hz); 44943594Sdonahn break; 45043594Sdonahn case 2 : /* IO DONE, post-analyze */ 45143594Sdonahn untimeout(fd_timeout,2); 45243594Sdonahn for(i=0;i<7;i++) { 45343594Sdonahn fd_status[i] = in_fdc(); 45443594Sdonahn } 45543594Sdonahn if (fd_status[0]&0xF8) { 45643594Sdonahn #ifdef FDOTHER 457*45533Sbill printf("status0 err %d:",fd_status[0]); 45843594Sdonahn #endif 45943594Sdonahn goto retry; 46043594Sdonahn } 461*45533Sbill /* 46243594Sdonahn if (fd_status[1]){ 46343594Sdonahn printf("status1 err %d:",fd_status[0]); 46443594Sdonahn goto retry; 46543594Sdonahn } 46643594Sdonahn if (fd_status[2]){ 46743594Sdonahn printf("status2 err %d:",fd_status[0]); 46843594Sdonahn goto retry; 46943594Sdonahn } 470*45533Sbill */ 47143594Sdonahn /* All OK */ 47243594Sdonahn if (!kernel_space(bp->b_un.b_addr+fd_skip)) { 47343594Sdonahn /* RAW transfer */ 474*45533Sbill if (read) bcopy(dma_bounce[fd_dmachan]->b_un.b_addr, 475*45533Sbill bp->b_un.b_addr+fd_skip, FDBLK); 47643594Sdonahn } 47743594Sdonahn fd_skip += FDBLK; 47843594Sdonahn if (fd_skip >= bp->b_bcount) { 479*45533Sbill #ifdef FDTEST 480*45533Sbill printf("DONE %d|", bp->b_blkno); 481*45533Sbill #endif 48243594Sdonahn /* ALL DONE */ 48343594Sdonahn fd_skip = 0; 48443594Sdonahn bp->b_resid = 0; 48543594Sdonahn dp->b_actf = bp->av_forw; 48643594Sdonahn biodone(bp); 48743594Sdonahn nextstate(dp); 48843594Sdonahn 48943594Sdonahn } else { 490*45533Sbill #ifdef FDDEBUG 491*45533Sbill printf("next|"); 492*45533Sbill #endif 49343594Sdonahn /* set up next transfer */ 49443594Sdonahn blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK 49543594Sdonahn + fd_skip/FDBLK; 49643594Sdonahn fd_state = 1; 49743594Sdonahn bp->b_cylin = (blknum / (ft->sectrac * 2)); 49843594Sdonahn if (bp->b_cylin != fd_track) { 499*45533Sbill #ifdef FDTEST 500*45533Sbill printf("Seek|"); 501*45533Sbill #endif 50243594Sdonahn /* SEEK Necessary */ 50343594Sdonahn out_fdc(15); /* Seek function */ 50443594Sdonahn out_fdc(fd_drive);/* Drive number */ 505*45533Sbill out_fdc(bp->b_cylin * dp->b_step); 50643594Sdonahn break; 507*45533Sbill } else fdintr(0); 50843594Sdonahn } 50943594Sdonahn break; 51043594Sdonahn case 3: 511*45533Sbill #ifdef FDOTHER 512*45533Sbill printf("Seek %d %d\n", bp->b_cylin, dp->b_step); 513*45533Sbill #endif 51443594Sdonahn /* Seek necessary */ 51543594Sdonahn out_fdc(15); /* Seek function */ 51643594Sdonahn out_fdc(fd_drive);/* Drive number */ 517*45533Sbill out_fdc(bp->b_cylin * dp->b_step); 51843594Sdonahn fd_state = 1; 51943594Sdonahn break; 52043594Sdonahn case 4: 52143594Sdonahn out_fdc(3); /* specify command */ 52243594Sdonahn out_fdc(0xDF); 52343594Sdonahn out_fdc(2); 52443594Sdonahn out_fdc(7); /* Recalibrate Function */ 52543594Sdonahn out_fdc(fd_drive); 52643594Sdonahn fd_state = 3; 52743594Sdonahn break; 528*45533Sbill case 5: 529*45533Sbill #ifdef FDOTHER 530*45533Sbill printf("**RESET**\n"); 531*45533Sbill #endif 532*45533Sbill /* Try a reset, keep motor on */ 533*45533Sbill set_motor(fd_drive,1); 534*45533Sbill set_motor(fd_drive,0); 535*45533Sbill outb(fdc+fdctl,ft->trans); 536*45533Sbill fd_retry++; 537*45533Sbill fd_state = 4; 538*45533Sbill break; 53943594Sdonahn default: 54043594Sdonahn printf("Unexpected FD int->"); 54143594Sdonahn out_fdc(0x8); 54243594Sdonahn i = in_fdc(); 54343594Sdonahn sec = in_fdc(); 54443594Sdonahn printf("ST0 = %X, PCN = %X\n",i,sec); 54543594Sdonahn out_fdc(0x4A); 54643594Sdonahn out_fdc(fd_drive); 54743594Sdonahn for(i=0;i<7;i++) { 54843594Sdonahn fd_status[i] = in_fdc(); 54943594Sdonahn } 55043594Sdonahn printf("intr status :%X %X %X %X %X %X %X ", 55143594Sdonahn fd_status[0], fd_status[1], fd_status[2], fd_status[3], 55243594Sdonahn fd_status[4], fd_status[5], fd_status[6] ); 55343594Sdonahn break; 55443594Sdonahn } 55543594Sdonahn return; 55643594Sdonahn retry: 55743594Sdonahn switch(fd_retry) { 55843594Sdonahn case 0: case 1: 559*45533Sbill case 2: case 3: 56043594Sdonahn break; 561*45533Sbill case 4: 56243594Sdonahn fd_retry++; 563*45533Sbill fd_state = 5; 564*45533Sbill fdintr(0); 56543594Sdonahn return; 566*45533Sbill case 5: case 6: case 7: 56743594Sdonahn break; 56843594Sdonahn default: 56943594Sdonahn printf("FD err %X %X %X %X %X %X %X\n", 57043594Sdonahn fd_status[0], fd_status[1], fd_status[2], fd_status[3], 57143594Sdonahn fd_status[4], fd_status[5], fd_status[6] ); 57243594Sdonahn badtrans(dp,bp); 57343594Sdonahn return; 57443594Sdonahn } 57543594Sdonahn fd_state = 1; 57643594Sdonahn fd_retry++; 577*45533Sbill fdintr(0); 57843594Sdonahn } 57943594Sdonahn 58043594Sdonahn badtrans(dp,bp) 58143594Sdonahn struct buf *dp,*bp; 58243594Sdonahn { 58343594Sdonahn 58443594Sdonahn bp->b_flags |= B_ERROR; 58543594Sdonahn bp->b_error = EIO; 58643594Sdonahn bp->b_resid = bp->b_bcount - fd_skip; 58743594Sdonahn dp->b_actf = bp->av_forw; 58843594Sdonahn fd_skip = 0; 58943594Sdonahn biodone(bp); 59043594Sdonahn nextstate(dp); 59143594Sdonahn 59243594Sdonahn } 59343594Sdonahn 59443594Sdonahn /* 59543594Sdonahn nextstate : After a transfer is done, continue processing 59643594Sdonahn requests on the current drive queue. If empty, go to 59743594Sdonahn the other drives queue. If that is empty too, timeout 59843594Sdonahn to turn off the current drive in 5 seconds, and go 59943594Sdonahn to state 0 (not expecting any interrupts). 60043594Sdonahn */ 60143594Sdonahn 60243594Sdonahn nextstate(dp) 60343594Sdonahn struct buf *dp; 60443594Sdonahn { 60543594Sdonahn struct buf *dpother; 60643594Sdonahn 60743594Sdonahn dpother = &fd_unit[fd_drive ? 0 : 1].head; 60843594Sdonahn if (dp->b_actf) fdstart(fd_drive); 60943594Sdonahn else if (dpother->b_actf) { 610*45533Sbill #ifdef FDTEST 611*45533Sbill printf("switch|"); 612*45533Sbill #endif 613*45533Sbill untimeout(fd_turnoff,fd_drive); 614*45533Sbill timeout(fd_turnoff,fd_drive,5*hz); 615*45533Sbill fd_drive = 1 - fd_drive; 61643594Sdonahn dp->b_active = 0; 617*45533Sbill dpother->b_active = 1; 618*45533Sbill fdstart(fd_drive); 61943594Sdonahn } else { 620*45533Sbill #ifdef FDTEST 621*45533Sbill printf("off|"); 622*45533Sbill #endif 62343594Sdonahn untimeout(fd_turnoff,fd_drive); 62443594Sdonahn timeout(fd_turnoff,fd_drive,5*hz); 62543594Sdonahn fd_state = 0; 62643594Sdonahn dp->b_active = 0; 62743594Sdonahn } 62843594Sdonahn } 629*45533Sbill #endif 630