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