1*43594Sdonahn /*- 2*43594Sdonahn * Copyright (c) 1990 The Regents of the University of California. 3*43594Sdonahn * All rights reserved. 4*43594Sdonahn * 5*43594Sdonahn * This code is derived from software contributed to Berkeley by 6*43594Sdonahn * Don Ahn. 7*43594Sdonahn * 8*43594Sdonahn * %sccs.include.386.c% 9*43594Sdonahn * 10*43594Sdonahn * @(#)fd.c 5.1 (Berkeley) 06/23/90 11*43594Sdonahn */ 12*43594Sdonahn 13*43594Sdonahn /****************************************************************************/ 14*43594Sdonahn /* fd driver */ 15*43594Sdonahn /****************************************************************************/ 16*43594Sdonahn #include "param.h" 17*43594Sdonahn #include "dkbad.h" 18*43594Sdonahn #include "systm.h" 19*43594Sdonahn #include "conf.h" 20*43594Sdonahn #include "file.h" 21*43594Sdonahn #include "dir.h" 22*43594Sdonahn #include "user.h" 23*43594Sdonahn #include "ioctl.h" 24*43594Sdonahn #include "disk.h" 25*43594Sdonahn #include "buf.h" 26*43594Sdonahn #include "vm.h" 27*43594Sdonahn #include "uio.h" 28*43594Sdonahn #include "machine/pte.h" 29*43594Sdonahn #include "machine/device.h" 30*43594Sdonahn #include "icu.h" 31*43594Sdonahn 32*43594Sdonahn #define NFD 2 33*43594Sdonahn #define FDUNIT(s) ((s)&1) 34*43594Sdonahn #define FDTYPE(s) (((s)>>1)&7) 35*43594Sdonahn #define b_cylin b_resid 36*43594Sdonahn #define FDBLK 512 37*43594Sdonahn #define NUMTYPES 4 38*43594Sdonahn 39*43594Sdonahn struct fd_type { 40*43594Sdonahn int sectrac; /* sectors per track */ 41*43594Sdonahn int secsize; /* size code for sectors */ 42*43594Sdonahn int datalen; /* data len when secsize = 0 */ 43*43594Sdonahn int gap; /* gap len between sectors */ 44*43594Sdonahn int tracks; /* total num of tracks */ 45*43594Sdonahn int size; /* size of disk in sectors */ 46*43594Sdonahn int steptrac; /* steps per cylinder */ 47*43594Sdonahn int trans; /* transfer speed code */ 48*43594Sdonahn }; 49*43594Sdonahn 50*43594Sdonahn struct fd_type fd_types[NUMTYPES] = { 51*43594Sdonahn { 18,2,0xFF,0x1B,80,2880,1,0 }, /* 1.44 meg HD 3.5in floppy */ 52*43594Sdonahn { 15,2,0xFF,0x1B,80,2400,1,0 }, /* 1.2 meg HD floppy */ 53*43594Sdonahn { 9,2,0xFF,0x23,40,720,2,1 }, /* 360k floppy in 1.2meg drive */ 54*43594Sdonahn { 9,2,0xFF,0x2A,40,720,1,1 }, /* 360k floppy in DD drive */ 55*43594Sdonahn }; 56*43594Sdonahn 57*43594Sdonahn struct fd_u { 58*43594Sdonahn int type; /* Drive type (HD, DD */ 59*43594Sdonahn int active; /* Drive activity boolean */ 60*43594Sdonahn int motor; /* Motor on flag */ 61*43594Sdonahn int opencnt; /* Num times open */ 62*43594Sdonahn struct buf head; /* Head of buf chain */ 63*43594Sdonahn struct buf rhead; /* Raw head of buf chain */ 64*43594Sdonahn } fd_unit[NFD]; 65*43594Sdonahn 66*43594Sdonahn extern int hz; 67*43594Sdonahn 68*43594Sdonahn /* state needed for current transfer */ 69*43594Sdonahn static int fd_skip; 70*43594Sdonahn static int fd_state; 71*43594Sdonahn static int fd_retry; 72*43594Sdonahn static int fd_drive; 73*43594Sdonahn static int fd_status[7]; 74*43594Sdonahn static char fdrawbuf[FDBLK]; 75*43594Sdonahn 76*43594Sdonahn /* stuff needed for virtual to physical calculations */ 77*43594Sdonahn extern char Sysbase; 78*43594Sdonahn static unsigned long sbase = (unsigned long) &Sysbase; 79*43594Sdonahn 80*43594Sdonahn /****************************************************************************/ 81*43594Sdonahn /* autoconfiguration stuff */ 82*43594Sdonahn /****************************************************************************/ 83*43594Sdonahn int fdprobe(), fdattach(), fd_turnoff(); 84*43594Sdonahn 85*43594Sdonahn struct driver fddriver = { 86*43594Sdonahn fdprobe, fdattach, "fd", 87*43594Sdonahn }; 88*43594Sdonahn 89*43594Sdonahn fdprobe(dev) 90*43594Sdonahn struct device *dev; 91*43594Sdonahn { 92*43594Sdonahn return 1; 93*43594Sdonahn } 94*43594Sdonahn 95*43594Sdonahn fdattach(dev) 96*43594Sdonahn struct device *dev; 97*43594Sdonahn { 98*43594Sdonahn INTREN(IRQ6); 99*43594Sdonahn } 100*43594Sdonahn 101*43594Sdonahn /****************************************************************************/ 102*43594Sdonahn /* fdstrategy */ 103*43594Sdonahn /****************************************************************************/ 104*43594Sdonahn fdstrategy(bp) 105*43594Sdonahn register struct buf *bp; /* IO operation to perform */ 106*43594Sdonahn { 107*43594Sdonahn register struct buf *dp,*dp0,*dp1; 108*43594Sdonahn long nblocks,blknum; 109*43594Sdonahn int unit, type, s; 110*43594Sdonahn 111*43594Sdonahn unit = FDUNIT(minor(bp->b_dev)); 112*43594Sdonahn type = FDTYPE(minor(bp->b_dev)); 113*43594Sdonahn #ifdef FDOTHER 114*43594Sdonahn printf("fdstrat: unit = %d, blkno = %d, bcount = %d\n", 115*43594Sdonahn unit, bp->b_blkno, bp->b_bcount); 116*43594Sdonahn #endif 117*43594Sdonahn if ((unit >= NFD) || (bp->b_blkno < 0)) { 118*43594Sdonahn printf("fdstrat: unit = %d, blkno = %d, bcount = %d\n", 119*43594Sdonahn unit, bp->b_blkno, bp->b_bcount); 120*43594Sdonahn pg("fd:error in fdstrategy"); 121*43594Sdonahn bp->b_error = EINVAL; 122*43594Sdonahn goto bad; 123*43594Sdonahn } 124*43594Sdonahn /* 125*43594Sdonahn * Set up block calculations. 126*43594Sdonahn */ 127*43594Sdonahn blknum = (unsigned long) bp->b_blkno * DEV_BSIZE/FDBLK; 128*43594Sdonahn nblocks = fd_types[type].size; 129*43594Sdonahn if (blknum + (bp->b_bcount / FDBLK) > nblocks) { 130*43594Sdonahn if (blknum == nblocks) bp->b_resid = bp->b_bcount; 131*43594Sdonahn else bp->b_error = ENOSPC; 132*43594Sdonahn goto bad; 133*43594Sdonahn } 134*43594Sdonahn bp->b_cylin = blknum / (fd_types[type].sectrac * 2); 135*43594Sdonahn bp->b_cylin *= (fd_types[type].steptrac); 136*43594Sdonahn dp = &fd_unit[unit].head; 137*43594Sdonahn dp0 = &fd_unit[0].head; 138*43594Sdonahn dp1 = &fd_unit[1].head; 139*43594Sdonahn s = splbio(); 140*43594Sdonahn disksort(dp, bp); 141*43594Sdonahn if ((dp0->b_active == 0)&&(dp1->b_active == 0)) { 142*43594Sdonahn dp->b_active = 1; 143*43594Sdonahn fd_drive = unit; 144*43594Sdonahn untimeout(fd_turnoff,unit); 145*43594Sdonahn fdstart(unit); /* start drive if idle */ 146*43594Sdonahn } 147*43594Sdonahn splx(s); 148*43594Sdonahn return; 149*43594Sdonahn 150*43594Sdonahn bad: 151*43594Sdonahn bp->b_flags |= B_ERROR; 152*43594Sdonahn biodone(bp); 153*43594Sdonahn } 154*43594Sdonahn 155*43594Sdonahn /****************************************************************************/ 156*43594Sdonahn /* motor control stuff */ 157*43594Sdonahn /****************************************************************************/ 158*43594Sdonahn set_motor(unit,reset) 159*43594Sdonahn int unit,reset; 160*43594Sdonahn { 161*43594Sdonahn int m0,m1; 162*43594Sdonahn m0 = fd_unit[0].motor; 163*43594Sdonahn m1 = fd_unit[1].motor; 164*43594Sdonahn outb(0x3f2,unit | (reset ? 0 : 0xC) | (m0 ? 16 : 0) | (m1 ? 32 : 0)); 165*43594Sdonahn } 166*43594Sdonahn 167*43594Sdonahn fd_turnoff(unit) 168*43594Sdonahn int unit; 169*43594Sdonahn { 170*43594Sdonahn fd_unit[unit].motor = 0; 171*43594Sdonahn if (unit) set_motor(0,0); 172*43594Sdonahn else set_motor(1,0); 173*43594Sdonahn } 174*43594Sdonahn 175*43594Sdonahn fd_turnon(unit) 176*43594Sdonahn int unit; 177*43594Sdonahn { 178*43594Sdonahn fd_unit[unit].motor = 1; 179*43594Sdonahn set_motor(unit,0); 180*43594Sdonahn } 181*43594Sdonahn 182*43594Sdonahn /****************************************************************************/ 183*43594Sdonahn /* fdc in/out */ 184*43594Sdonahn /****************************************************************************/ 185*43594Sdonahn int 186*43594Sdonahn in_fdc() 187*43594Sdonahn { 188*43594Sdonahn int i; 189*43594Sdonahn while ((i = inb(0x3f4) & 192) != 192) if (i == 128) return -1; 190*43594Sdonahn return inb(0x3f5); 191*43594Sdonahn } 192*43594Sdonahn 193*43594Sdonahn dump_stat() 194*43594Sdonahn { 195*43594Sdonahn int i; 196*43594Sdonahn for(i=0;i<7;i++) { 197*43594Sdonahn fd_status[i] = in_fdc(); 198*43594Sdonahn if (fd_status[i] < 0) break; 199*43594Sdonahn } 200*43594Sdonahn printf("FD bad status :%X %X %X %X %X %X %X\n", 201*43594Sdonahn fd_status[0], fd_status[1], fd_status[2], fd_status[3], 202*43594Sdonahn fd_status[4], fd_status[5], fd_status[6] ); 203*43594Sdonahn } 204*43594Sdonahn 205*43594Sdonahn out_fdc(x) 206*43594Sdonahn int x; 207*43594Sdonahn { 208*43594Sdonahn int r,errcnt; 209*43594Sdonahn static int maxcnt = 0; 210*43594Sdonahn errcnt = 0; 211*43594Sdonahn do { 212*43594Sdonahn r = (inb(0x3f4) & 192); 213*43594Sdonahn if (r==128) break; 214*43594Sdonahn if (r==192) { 215*43594Sdonahn dump_stat(); /* error: direction. eat up output */ 216*43594Sdonahn #ifdef FDOTHER 217*43594Sdonahn printf("%X\n",x); 218*43594Sdonahn #endif 219*43594Sdonahn } 220*43594Sdonahn /* printf("Error r = %d:",r); */ 221*43594Sdonahn errcnt++; 222*43594Sdonahn } while (1); 223*43594Sdonahn if (errcnt > maxcnt) { 224*43594Sdonahn maxcnt = errcnt; 225*43594Sdonahn #ifdef FDOTHER 226*43594Sdonahn printf("New MAX = %d\n",maxcnt); 227*43594Sdonahn #endif 228*43594Sdonahn } 229*43594Sdonahn outb(0x3f5,x&0xFF); 230*43594Sdonahn } 231*43594Sdonahn 232*43594Sdonahn /* see if fdc responding */ 233*43594Sdonahn int 234*43594Sdonahn check_fdc() 235*43594Sdonahn { 236*43594Sdonahn int i; 237*43594Sdonahn for(i=0;i<100;i++) { 238*43594Sdonahn if (inb(0x3f4)&128) return 0; 239*43594Sdonahn } 240*43594Sdonahn return 1; 241*43594Sdonahn } 242*43594Sdonahn 243*43594Sdonahn /****************************************************************************/ 244*43594Sdonahn /* fdopen/fdclose */ 245*43594Sdonahn /****************************************************************************/ 246*43594Sdonahn fdopen(dev, flags) 247*43594Sdonahn dev_t dev; 248*43594Sdonahn int flags; 249*43594Sdonahn { 250*43594Sdonahn int unit = FDUNIT(minor(dev)); 251*43594Sdonahn int type = FDTYPE(minor(dev)); 252*43594Sdonahn int s; 253*43594Sdonahn 254*43594Sdonahn /* check bounds */ 255*43594Sdonahn if (unit >= NFD) return(ENXIO); 256*43594Sdonahn if (type >= NUMTYPES) return(ENXIO); 257*43594Sdonahn if (check_fdc()) return(EBUSY); 258*43594Sdonahn 259*43594Sdonahn /* Set proper disk type, only allow one type */ 260*43594Sdonahn s = splbio(); 261*43594Sdonahn splx(s); 262*43594Sdonahn 263*43594Sdonahn return 0; 264*43594Sdonahn } 265*43594Sdonahn 266*43594Sdonahn fdclose(dev) 267*43594Sdonahn dev_t dev; 268*43594Sdonahn { 269*43594Sdonahn } 270*43594Sdonahn 271*43594Sdonahn /****************************************************************************/ 272*43594Sdonahn /* fdread/fdwrite */ 273*43594Sdonahn /****************************************************************************/ 274*43594Sdonahn /* 275*43594Sdonahn * Routines to do raw IO for a unit. 276*43594Sdonahn */ 277*43594Sdonahn fdread(dev, uio) /* character read routine */ 278*43594Sdonahn dev_t dev; 279*43594Sdonahn struct uio *uio; 280*43594Sdonahn { 281*43594Sdonahn int unit = FDUNIT(minor(dev)) ; 282*43594Sdonahn if (unit >= NFD) return(ENXIO); 283*43594Sdonahn return(physio(fdstrategy,&fd_unit[unit].rhead,dev,B_READ,minphys,uio)); 284*43594Sdonahn } 285*43594Sdonahn 286*43594Sdonahn fdwrite(dev, uio) /* character write routine */ 287*43594Sdonahn dev_t dev; 288*43594Sdonahn struct uio *uio; 289*43594Sdonahn { 290*43594Sdonahn int unit = FDUNIT(minor(dev)); 291*43594Sdonahn if (unit >= NFD) return(ENXIO); 292*43594Sdonahn return(physio(fdstrategy,&fd_unit[unit].rhead,dev,B_WRITE,minphys,uio)); 293*43594Sdonahn } 294*43594Sdonahn 295*43594Sdonahn /****************************************************************************/ 296*43594Sdonahn /* fdstart */ 297*43594Sdonahn /****************************************************************************/ 298*43594Sdonahn fdstart(unit) 299*43594Sdonahn int unit; 300*43594Sdonahn { 301*43594Sdonahn register struct buf *dp,*bp; 302*43594Sdonahn int s; 303*43594Sdonahn 304*43594Sdonahn if (!fd_unit[unit].motor) { 305*43594Sdonahn fd_turnon(unit); 306*43594Sdonahn /* Wait for 1 sec */ 307*43594Sdonahn timeout(fdstart,unit,hz); 308*43594Sdonahn } else { 309*43594Sdonahn s = splbio(); 310*43594Sdonahn dp = &fd_unit[unit].head; 311*43594Sdonahn bp = dp->b_actf; 312*43594Sdonahn fd_retry = 0; 313*43594Sdonahn fd_state = 1; 314*43594Sdonahn fd_skip = 0; 315*43594Sdonahn /* Seek necessary, never quite sure where head is at! */ 316*43594Sdonahn out_fdc(15); /* Seek function */ 317*43594Sdonahn out_fdc(unit); /* Drive number */ 318*43594Sdonahn out_fdc(bp->b_cylin); 319*43594Sdonahn splx(s); 320*43594Sdonahn } 321*43594Sdonahn } 322*43594Sdonahn 323*43594Sdonahn /* XXX temporary */ 324*43594Sdonahn kernel_space(x) 325*43594Sdonahn unsigned long x; 326*43594Sdonahn { 327*43594Sdonahn if ((x >= sbase) & (x < sbase + 0x800000)) return 1; 328*43594Sdonahn else return 0; 329*43594Sdonahn } 330*43594Sdonahn 331*43594Sdonahn 332*43594Sdonahn /****************************************************************************/ 333*43594Sdonahn /* fd_dma */ 334*43594Sdonahn /* set up DMA read/write operation and virtual address addr for nbytes */ 335*43594Sdonahn /****************************************************************************/ 336*43594Sdonahn fd_dma(read,addr,nbytes) 337*43594Sdonahn int read; 338*43594Sdonahn unsigned long addr; 339*43594Sdonahn int nbytes; 340*43594Sdonahn { 341*43594Sdonahn unsigned long phys; 342*43594Sdonahn int s,raw; 343*43594Sdonahn 344*43594Sdonahn if (kernel_space(addr)) raw = 0; 345*43594Sdonahn else raw = 1; 346*43594Sdonahn 347*43594Sdonahn /* copy bounce buffer on write */ 348*43594Sdonahn if (raw && !read) bcopy(addr,fdrawbuf,FDBLK); 349*43594Sdonahn 350*43594Sdonahn /* Set read/write bytes */ 351*43594Sdonahn if (read) { 352*43594Sdonahn outb(0xC,0x46); outb(0xB,0x46); 353*43594Sdonahn } else { 354*43594Sdonahn outb(0xC,0x4A); outb(0xB,0x4A); 355*43594Sdonahn } 356*43594Sdonahn /* Send start address */ 357*43594Sdonahn if (raw) phys = (unsigned long) &fdrawbuf[0]; 358*43594Sdonahn else phys = addr; 359*43594Sdonahn /* translate to physical */ 360*43594Sdonahn phys = phys - sbase; 361*43594Sdonahn outb(0x4,phys & 0xFF); 362*43594Sdonahn outb(0x4,(phys>>8) & 0xFF); 363*43594Sdonahn outb(0x81,(phys>>16) & 0xFF); 364*43594Sdonahn /* Send count */ 365*43594Sdonahn nbytes--; 366*43594Sdonahn outb(0x5,nbytes & 0xFF); 367*43594Sdonahn outb(0x5,(nbytes>>8) & 0xFF); 368*43594Sdonahn /* set channel 2 */ 369*43594Sdonahn outb(0x0A,2); 370*43594Sdonahn } 371*43594Sdonahn 372*43594Sdonahn fd_timeout(x) 373*43594Sdonahn int x; 374*43594Sdonahn { 375*43594Sdonahn int i,j; 376*43594Sdonahn struct buf *dp,*bp; 377*43594Sdonahn 378*43594Sdonahn dp = &fd_unit[fd_drive].head; 379*43594Sdonahn bp = dp->b_actf; 380*43594Sdonahn 381*43594Sdonahn out_fdc(0x4); 382*43594Sdonahn out_fdc(fd_drive); 383*43594Sdonahn i = in_fdc(); 384*43594Sdonahn printf("Timeout drive status %X\n",i); 385*43594Sdonahn 386*43594Sdonahn out_fdc(0x8); 387*43594Sdonahn i = in_fdc(); 388*43594Sdonahn j = in_fdc(); 389*43594Sdonahn printf("ST0 = %X, PCN = %X\n",i,j); 390*43594Sdonahn 391*43594Sdonahn if (bp) badtrans(dp,bp); 392*43594Sdonahn } 393*43594Sdonahn 394*43594Sdonahn /****************************************************************************/ 395*43594Sdonahn /* fdintr */ 396*43594Sdonahn /****************************************************************************/ 397*43594Sdonahn fdintr(vec) 398*43594Sdonahn int vec; 399*43594Sdonahn { 400*43594Sdonahn register struct buf *dp,*bp; 401*43594Sdonahn struct buf *dpother; 402*43594Sdonahn int read,head,trac,sec,i,s,sectrac; 403*43594Sdonahn unsigned long blknum; 404*43594Sdonahn struct fd_type *ft; 405*43594Sdonahn static int fd_track; 406*43594Sdonahn 407*43594Sdonahn dp = &fd_unit[fd_drive].head; 408*43594Sdonahn bp = dp->b_actf; 409*43594Sdonahn read = bp->b_flags & B_READ; 410*43594Sdonahn ft = &fd_types[FDTYPE(bp->b_dev)]; 411*43594Sdonahn 412*43594Sdonahn switch (fd_state) { 413*43594Sdonahn case 1 : /* SEEK DONE, START DMA */ 414*43594Sdonahn #ifdef FDOTHER 415*43594Sdonahn out_fdc(0x8); 416*43594Sdonahn i = in_fdc(); 417*43594Sdonahn sec = in_fdc(); 418*43594Sdonahn printf("ST0 = %X, PCN = %X:",i,sec); 419*43594Sdonahn #endif 420*43594Sdonahn fd_track = bp->b_cylin; 421*43594Sdonahn fd_dma(read,bp->b_un.b_addr+fd_skip,FDBLK); 422*43594Sdonahn blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK 423*43594Sdonahn + fd_skip/FDBLK; 424*43594Sdonahn sectrac = ft->sectrac; 425*43594Sdonahn sec = blknum % (sectrac * 2); 426*43594Sdonahn head = sec / sectrac; 427*43594Sdonahn sec = sec % sectrac + 1; 428*43594Sdonahn 429*43594Sdonahn if (read) out_fdc(0xE6); /* READ */ 430*43594Sdonahn else out_fdc(0xC5); /* WRITE */ 431*43594Sdonahn out_fdc(head << 2 | fd_drive); /* head & unit */ 432*43594Sdonahn out_fdc(fd_track); /* track */ 433*43594Sdonahn out_fdc(head); 434*43594Sdonahn out_fdc(sec); /* sector XXX +1? */ 435*43594Sdonahn out_fdc(ft->secsize); /* sector size */ 436*43594Sdonahn out_fdc(sectrac); /* sectors/track */ 437*43594Sdonahn out_fdc(ft->gap); /* gap size */ 438*43594Sdonahn out_fdc(ft->datalen); /* data length */ 439*43594Sdonahn fd_state = 2; 440*43594Sdonahn /* XXX PARANOIA */ 441*43594Sdonahn untimeout(fd_timeout,2); 442*43594Sdonahn timeout(fd_timeout,2,hz); 443*43594Sdonahn break; 444*43594Sdonahn case 2 : /* IO DONE, post-analyze */ 445*43594Sdonahn untimeout(fd_timeout,2); 446*43594Sdonahn for(i=0;i<7;i++) { 447*43594Sdonahn fd_status[i] = in_fdc(); 448*43594Sdonahn } 449*43594Sdonahn if (fd_status[0]&0xF8) { 450*43594Sdonahn #ifdef FDOTHER 451*43594Sdonahn printf("status0 err %d:",fd_status[0]); 452*43594Sdonahn #endif 453*43594Sdonahn goto retry; 454*43594Sdonahn } 455*43594Sdonahn if (fd_status[1]){ 456*43594Sdonahn printf("status1 err %d:",fd_status[0]); 457*43594Sdonahn goto retry; 458*43594Sdonahn } 459*43594Sdonahn if (fd_status[2]){ 460*43594Sdonahn printf("status2 err %d:",fd_status[0]); 461*43594Sdonahn goto retry; 462*43594Sdonahn } 463*43594Sdonahn /* All OK */ 464*43594Sdonahn if (!kernel_space(bp->b_un.b_addr+fd_skip)) { 465*43594Sdonahn /* RAW transfer */ 466*43594Sdonahn if (read) bcopy(fdrawbuf,bp->b_un.b_addr+fd_skip, 467*43594Sdonahn DEV_BSIZE); 468*43594Sdonahn } 469*43594Sdonahn fd_skip += FDBLK; 470*43594Sdonahn if (fd_skip >= bp->b_bcount) { 471*43594Sdonahn /* ALL DONE */ 472*43594Sdonahn fd_skip = 0; 473*43594Sdonahn bp->b_resid = 0; 474*43594Sdonahn dp->b_actf = bp->av_forw; 475*43594Sdonahn biodone(bp); 476*43594Sdonahn nextstate(dp); 477*43594Sdonahn 478*43594Sdonahn } else { 479*43594Sdonahn /* set up next transfer */ 480*43594Sdonahn blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK 481*43594Sdonahn + fd_skip/FDBLK; 482*43594Sdonahn fd_state = 1; 483*43594Sdonahn bp->b_cylin = (blknum / (ft->sectrac * 2)); 484*43594Sdonahn bp->b_cylin *= ft->steptrac; 485*43594Sdonahn if (bp->b_cylin != fd_track) { 486*43594Sdonahn /* SEEK Necessary */ 487*43594Sdonahn out_fdc(15); /* Seek function */ 488*43594Sdonahn out_fdc(fd_drive);/* Drive number */ 489*43594Sdonahn out_fdc(bp->b_cylin); 490*43594Sdonahn break; 491*43594Sdonahn } else fdintr(); 492*43594Sdonahn } 493*43594Sdonahn break; 494*43594Sdonahn case 3: 495*43594Sdonahn /* Seek necessary */ 496*43594Sdonahn out_fdc(15); /* Seek function */ 497*43594Sdonahn out_fdc(fd_drive);/* Drive number */ 498*43594Sdonahn out_fdc(bp->b_cylin); 499*43594Sdonahn fd_state = 1; 500*43594Sdonahn break; 501*43594Sdonahn case 4: 502*43594Sdonahn out_fdc(3); /* specify command */ 503*43594Sdonahn out_fdc(0xDF); 504*43594Sdonahn out_fdc(2); 505*43594Sdonahn out_fdc(7); /* Recalibrate Function */ 506*43594Sdonahn out_fdc(fd_drive); 507*43594Sdonahn fd_state = 3; 508*43594Sdonahn break; 509*43594Sdonahn default: 510*43594Sdonahn #ifdef FDDEBUG 511*43594Sdonahn printf("Unexpected FD int->"); 512*43594Sdonahn out_fdc(0x8); 513*43594Sdonahn i = in_fdc(); 514*43594Sdonahn sec = in_fdc(); 515*43594Sdonahn printf("ST0 = %X, PCN = %X\n",i,sec); 516*43594Sdonahn out_fdc(0x4A); 517*43594Sdonahn out_fdc(fd_drive); 518*43594Sdonahn for(i=0;i<7;i++) { 519*43594Sdonahn fd_status[i] = in_fdc(); 520*43594Sdonahn } 521*43594Sdonahn printf("intr status :%X %X %X %X %X %X %X ", 522*43594Sdonahn fd_status[0], fd_status[1], fd_status[2], fd_status[3], 523*43594Sdonahn fd_status[4], fd_status[5], fd_status[6] ); 524*43594Sdonahn #endif 525*43594Sdonahn break; 526*43594Sdonahn } 527*43594Sdonahn return; 528*43594Sdonahn retry: 529*43594Sdonahn switch(fd_retry) { 530*43594Sdonahn case 0: case 1: 531*43594Sdonahn break; 532*43594Sdonahn case 2: 533*43594Sdonahn #ifdef FDDEBUG 534*43594Sdonahn printf("**RESET**\n"); 535*43594Sdonahn #endif 536*43594Sdonahn /* Try a reset, keep motor on */ 537*43594Sdonahn set_motor(fd_drive,1); 538*43594Sdonahn set_motor(fd_drive,0); 539*43594Sdonahn outb(0x3f7,ft->trans); 540*43594Sdonahn fd_retry++; 541*43594Sdonahn fd_state = 4; 542*43594Sdonahn return; 543*43594Sdonahn case 3: case 4: 544*43594Sdonahn case 5: case 6: 545*43594Sdonahn break; 546*43594Sdonahn default: 547*43594Sdonahn printf("FD err %X %X %X %X %X %X %X\n", 548*43594Sdonahn fd_status[0], fd_status[1], fd_status[2], fd_status[3], 549*43594Sdonahn fd_status[4], fd_status[5], fd_status[6] ); 550*43594Sdonahn badtrans(dp,bp); 551*43594Sdonahn return; 552*43594Sdonahn } 553*43594Sdonahn fd_state = 1; 554*43594Sdonahn fd_retry++; 555*43594Sdonahn fdintr(); 556*43594Sdonahn } 557*43594Sdonahn 558*43594Sdonahn badtrans(dp,bp) 559*43594Sdonahn struct buf *dp,*bp; 560*43594Sdonahn { 561*43594Sdonahn 562*43594Sdonahn bp->b_flags |= B_ERROR; 563*43594Sdonahn bp->b_error = EIO; 564*43594Sdonahn bp->b_resid = bp->b_bcount - fd_skip; 565*43594Sdonahn dp->b_actf = bp->av_forw; 566*43594Sdonahn fd_skip = 0; 567*43594Sdonahn biodone(bp); 568*43594Sdonahn nextstate(dp); 569*43594Sdonahn 570*43594Sdonahn } 571*43594Sdonahn 572*43594Sdonahn /* 573*43594Sdonahn nextstate : After a transfer is done, continue processing 574*43594Sdonahn requests on the current drive queue. If empty, go to 575*43594Sdonahn the other drives queue. If that is empty too, timeout 576*43594Sdonahn to turn off the current drive in 5 seconds, and go 577*43594Sdonahn to state 0 (not expecting any interrupts). 578*43594Sdonahn */ 579*43594Sdonahn 580*43594Sdonahn nextstate(dp) 581*43594Sdonahn struct buf *dp; 582*43594Sdonahn { 583*43594Sdonahn struct buf *dpother; 584*43594Sdonahn 585*43594Sdonahn dpother = &fd_unit[fd_drive ? 0 : 1].head; 586*43594Sdonahn if (dp->b_actf) fdstart(fd_drive); 587*43594Sdonahn else if (dpother->b_actf) { 588*43594Sdonahn dp->b_active = 0; 589*43594Sdonahn fdstart(fd_drive ? 0 : 1); 590*43594Sdonahn } else { 591*43594Sdonahn untimeout(fd_turnoff,fd_drive); 592*43594Sdonahn timeout(fd_turnoff,fd_drive,5*hz); 593*43594Sdonahn fd_state = 0; 594*43594Sdonahn dp->b_active = 0; 595*43594Sdonahn } 596*43594Sdonahn } 597