1 /* $NetBSD: hdfd.c,v 1.6 1997/01/01 21:12:56 leo Exp $ */ 2 3 /*- 4 * Copyright (c) 1996 Leo Weppelman 5 * Copyright (c) 1993, 1994, 1995, 1996 6 * Charles M. Hannum. All rights reserved. 7 * Copyright (c) 1990 The Regents of the University of California. 8 * All rights reserved. 9 * 10 * This code is derived from software contributed to Berkeley by 11 * Don Ahn. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. All advertising materials mentioning features or use of this software 22 * must display the following acknowledgement: 23 * This product includes software developed by the University of 24 * California, Berkeley and its contributors. 25 * 4. Neither the name of the University nor the names of its contributors 26 * may be used to endorse or promote products derived from this software 27 * without specific prior written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 39 * SUCH DAMAGE. 40 * 41 * @(#)fd.c 7.4 (Berkeley) 5/25/91 42 */ 43 44 /* 45 * Floppy formatting facilities merged from FreeBSD fd.c driver: 46 * Id: fd.c,v 1.53 1995/03/12 22:40:56 joerg Exp 47 * which carries the same copyright/redistribution notice as shown above with 48 * the addition of the following statement before the "Redistribution and 49 * use ..." clause: 50 * 51 * Copyright (c) 1993, 1994 by 52 * jc@irbs.UUCP (John Capo) 53 * vak@zebub.msk.su (Serge Vakulenko) 54 * ache@astral.msk.su (Andrew A. Chernov) 55 * 56 * Copyright (c) 1993, 1994, 1995 by 57 * joerg_wunsch@uriah.sax.de (Joerg Wunsch) 58 * dufault@hda.com (Peter Dufault) 59 */ 60 61 #include <sys/param.h> 62 #include <sys/systm.h> 63 #include <sys/kernel.h> 64 #include <sys/file.h> 65 #include <sys/ioctl.h> 66 #include <sys/device.h> 67 #include <sys/disklabel.h> 68 #include <sys/dkstat.h> 69 #include <sys/disk.h> 70 #include <sys/buf.h> 71 #include <sys/malloc.h> 72 #include <sys/uio.h> 73 #include <sys/syslog.h> 74 #include <sys/queue.h> 75 #include <sys/proc.h> 76 #include <sys/fdio.h> 77 #include <sys/conf.h> 78 #include <sys/device.h> 79 80 #include <machine/cpu.h> 81 #include <machine/bus.h> 82 #include <machine/iomap.h> 83 #include <machine/mfp.h> 84 85 #include <atari/dev/hdfdreg.h> 86 #include <atari/atari/intr.h> 87 #include <atari/atari/device.h> 88 89 /* 90 * {b,c}devsw[] function prototypes 91 */ 92 dev_type_open(fdopen); 93 dev_type_close(fdclose); 94 dev_type_read(fdread); 95 dev_type_write(fdwrite); 96 dev_type_ioctl(fdioctl); 97 dev_type_size(fdsize); 98 dev_type_dump(fddump); 99 100 volatile u_char *fdio_addr; 101 102 #define wrt_fdc_reg(reg, val) { fdio_addr[reg] = val; } 103 #define rd_fdc_reg(reg) ( fdio_addr[reg] ) 104 105 #define fdc_ienable() MFP2->mf_ierb |= IB_DCHG; 106 107 /* 108 * Interface to the pseudo-dma handler 109 */ 110 void fddma_intr(void); 111 caddr_t fddmaaddr = NULL; 112 int fddmalen = 0; 113 114 extern void mfp_hdfd_nf __P((void)), mfp_hdfd_fifo __P((void)); 115 116 /* 117 * Argument to fdcintr..... 118 */ 119 static void *intr_arg = NULL; /* XXX: arg. to intr_establish() */ 120 121 122 123 #define FDUNIT(dev) (minor(dev) / 8) 124 #define FDTYPE(dev) (minor(dev) % 8) 125 126 /* XXX misuse a flag to identify format operation */ 127 #define B_FORMAT B_XXX 128 129 #define b_cylin b_resid 130 131 enum fdc_state { 132 DEVIDLE = 0, 133 MOTORWAIT, 134 DOSEEK, 135 SEEKWAIT, 136 SEEKTIMEDOUT, 137 SEEKCOMPLETE, 138 DOIO, 139 IOCOMPLETE, 140 IOTIMEDOUT, 141 DORESET, 142 RESETCOMPLETE, 143 RESETTIMEDOUT, 144 DORECAL, 145 RECALWAIT, 146 RECALTIMEDOUT, 147 RECALCOMPLETE, 148 }; 149 150 /* software state, per controller */ 151 struct fdc_softc { 152 struct device sc_dev; /* boilerplate */ 153 struct fd_softc *sc_fd[4]; /* pointers to children */ 154 TAILQ_HEAD(drivehead, fd_softc) sc_drives; 155 enum fdc_state sc_state; 156 int sc_errors; /* number of retries so far */ 157 int sc_overruns; /* number of overruns so far */ 158 u_char sc_status[7]; /* copy of registers */ 159 }; 160 161 /* controller driver configuration */ 162 int fdcprobe __P((struct device *, struct cfdata *, void *)); 163 int fdprint __P((void *, const char *)); 164 void fdcattach __P((struct device *, struct device *, void *)); 165 166 struct cfattach fdc_ca = { 167 sizeof(struct fdc_softc), fdcprobe, fdcattach 168 }; 169 170 struct cfdriver fdc_cd = { 171 NULL, "fdc", DV_DULL 172 }; 173 174 /* 175 * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how 176 * we tell them apart. 177 */ 178 struct fd_type { 179 int sectrac; /* sectors per track */ 180 int heads; /* number of heads */ 181 int seccyl; /* sectors per cylinder */ 182 int secsize; /* size code for sectors */ 183 int datalen; /* data len when secsize = 0 */ 184 int steprate; /* step rate and head unload time */ 185 int gap1; /* gap len between sectors */ 186 int gap2; /* formatting gap */ 187 int tracks; /* total num of tracks */ 188 int size; /* size of disk in sectors */ 189 int step; /* steps per cylinder */ 190 int rate; /* transfer speed code */ 191 u_char fillbyte; /* format fill byte */ 192 u_char interleave; /* interleave factor (formatting) */ 193 char *name; 194 }; 195 196 /* 197 * The order of entries in the following table is important -- BEWARE! 198 * The order of the types is the same as for the TT/Falcon.... 199 */ 200 struct fd_type fd_types[] = { 201 /* 360kB in 720kB drive */ 202 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_125KBPS,0xf6,1,"360KB" }, 203 /* 3.5" 720kB diskette */ 204 { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_125KBPS,0xf6,1,"720KB" }, 205 /* 1.44MB diskette */ 206 { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_250KBPS,0xf6,1,"1.44MB" }, 207 }; 208 209 /* software state, per disk (with up to 4 disks per ctlr) */ 210 struct fd_softc { 211 struct device sc_dev; 212 struct disk sc_dk; 213 214 struct fd_type *sc_deftype; /* default type descriptor */ 215 struct fd_type *sc_type; /* current type descriptor */ 216 217 daddr_t sc_blkno; /* starting block number */ 218 int sc_bcount; /* byte count left */ 219 int sc_opts; /* user-set options */ 220 int sc_skip; /* bytes already transferred */ 221 int sc_nblks; /* #blocks currently tranferring */ 222 int sc_nbytes; /* #bytes currently tranferring */ 223 224 int sc_drive; /* physical unit number */ 225 int sc_flags; 226 #define FD_OPEN 0x01 /* it's open */ 227 #define FD_MOTOR 0x02 /* motor should be on */ 228 #define FD_MOTOR_WAIT 0x04 /* motor coming up */ 229 int sc_cylin; /* where we think the head is */ 230 231 void *sc_sdhook; /* saved shutdown hook for drive. */ 232 233 TAILQ_ENTRY(fd_softc) sc_drivechain; 234 int sc_ops; /* I/O ops since last switch */ 235 struct buf sc_q; /* head of buf chain */ 236 }; 237 238 /* floppy driver configuration */ 239 int fdprobe __P((struct device *, struct cfdata *, void *)); 240 void fdattach __P((struct device *, struct device *, void *)); 241 242 struct cfattach hdfd_ca = { 243 sizeof(struct fd_softc), fdprobe, fdattach 244 }; 245 246 struct cfdriver hdfd_cd = { 247 NULL, "hdfd", DV_DISK 248 }; 249 250 void fdstrategy __P((struct buf *)); 251 void fdstart __P((struct fd_softc *)); 252 253 struct dkdriver fddkdriver = { fdstrategy }; 254 255 void fd_set_motor __P((struct fdc_softc *fdc, int reset)); 256 void fd_motor_off __P((void *arg)); 257 void fd_motor_on __P((void *arg)); 258 int fdcresult __P((struct fdc_softc *fdc)); 259 int out_fdc __P((u_char x)); 260 void fdc_ctrl_intr __P((struct clockframe)); 261 void fdcstart __P((struct fdc_softc *fdc)); 262 void fdcstatus __P((struct device *dv, int n, char *s)); 263 void fdctimeout __P((void *arg)); 264 void fdcpseudointr __P((void *arg)); 265 int fdcintr __P((void *)); 266 void fdcretry __P((struct fdc_softc *fdc)); 267 void fdfinish __P((struct fd_softc *fd, struct buf *bp)); 268 int fdformat __P((dev_t, struct ne7_fd_formb *, struct proc *)); 269 270 __inline struct fd_type *fd_dev_to_type __P((struct fd_softc *, dev_t)); 271 272 int 273 fdcprobe(parent, cfp, aux) 274 struct device *parent; 275 struct cfdata *cfp; 276 void *aux; 277 { 278 int rv = 0; 279 280 if(strcmp("fdc", aux) || cfp->cf_unit != 0) 281 return(0); 282 283 if (!atari_realconfig) 284 return 0; 285 286 if (bus_space_map(NULL, 0xfff00000, NBPG, 0, (caddr_t*)&fdio_addr)) { 287 printf("fdcprobe: cannot map io-area\n"); 288 return (0); 289 } 290 291 #ifdef FD_DEBUG 292 printf("fdcprobe: I/O mapping done va: %p\n", fdio_addr); 293 #endif 294 295 /* reset */ 296 wrt_fdc_reg(fdout, 0); 297 delay(100); 298 wrt_fdc_reg(fdout, FDO_FRST); 299 300 /* see if it can handle a command */ 301 if (out_fdc(NE7CMD_SPECIFY) < 0) 302 goto out; 303 out_fdc(0xdf); 304 out_fdc(7); 305 306 rv = 1; 307 308 out: 309 if (rv == 0) 310 bus_space_unmap(NULL, (caddr_t)fdio_addr, NBPG); 311 312 return rv; 313 } 314 315 /* 316 * Arguments passed between fdcattach and fdprobe. 317 */ 318 struct fdc_attach_args { 319 int fa_drive; 320 struct fd_type *fa_deftype; 321 }; 322 323 /* 324 * Print the location of a disk drive (called just before attaching the 325 * the drive). If `fdc' is not NULL, the drive was found but was not 326 * in the system config file; print the drive name as well. 327 * Return QUIET (config_find ignores this if the device was configured) to 328 * avoid printing `fdN not configured' messages. 329 */ 330 int 331 fdprint(aux, fdc) 332 void *aux; 333 const char *fdc; 334 { 335 register struct fdc_attach_args *fa = aux; 336 337 if (!fdc) 338 printf(" drive %d", fa->fa_drive); 339 return QUIET; 340 } 341 342 void 343 fdcattach(parent, self, aux) 344 struct device *parent, *self; 345 void *aux; 346 { 347 struct fdc_softc *fdc = (void *)self; 348 struct fdc_attach_args fa; 349 int has_fifo; 350 351 has_fifo = 0; 352 353 fdc->sc_state = DEVIDLE; 354 TAILQ_INIT(&fdc->sc_drives); 355 356 out_fdc(NE7CMD_CONFIGURE); 357 if (out_fdc(0) == 0) { 358 out_fdc(0x1a); /* No polling, fifo depth = 10 */ 359 out_fdc(0); 360 361 /* Retain configuration across resets */ 362 out_fdc(NE7CMD_LOCK); 363 (void)fdcresult(fdc); 364 has_fifo = 1; 365 } 366 else { 367 (void)rd_fdc_reg(fddata); 368 printf(": no fifo"); 369 } 370 371 printf("\n"); 372 373 if (intr_establish(22, USER_VEC|FAST_VEC, 0, 374 (hw_ifun_t)(has_fifo ? mfp_hdfd_fifo : mfp_hdfd_nf), 375 NULL) == NULL) { 376 printf("fdcattach: Can't establish interrupt\n"); 377 return; 378 } 379 380 /* 381 * Setup the interrupt logic. 382 */ 383 MFP2->mf_iprb &= ~IB_DCHG; 384 MFP2->mf_imrb |= IB_DCHG; 385 MFP2->mf_aer |= 0x10; /* fdc int low->high */ 386 387 /* physical limit: four drives per controller. */ 388 for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) { 389 /* 390 * XXX: Choose something sensible as a default... 391 */ 392 fa.fa_deftype = &fd_types[2]; /* 1.44MB */ 393 (void)config_found(self, (void *)&fa, fdprint); 394 } 395 } 396 397 int 398 fdprobe(parent, cfp, aux) 399 struct device *parent; 400 struct cfdata *cfp; 401 void *aux; 402 { 403 struct fdc_softc *fdc = (void *)parent; 404 struct fdc_attach_args *fa = aux; 405 int drive = fa->fa_drive; 406 int n; 407 408 if (cfp->cf_loc[0] != -1 && cfp->cf_loc[0] != drive) 409 return 0; 410 /* 411 * XXX 412 * This is to work around some odd interactions between this driver 413 * and SMC Ethernet cards. 414 */ 415 if (cfp->cf_loc[0] == -1 && drive >= 2) 416 return 0; 417 418 /* select drive and turn on motor */ 419 wrt_fdc_reg(fdout, drive | FDO_FRST | FDO_MOEN(drive)); 420 421 /* wait for motor to spin up */ 422 delay(250000); 423 out_fdc(NE7CMD_RECAL); 424 out_fdc(drive); 425 426 /* wait for recalibrate */ 427 delay(2000000); 428 out_fdc(NE7CMD_SENSEI); 429 n = fdcresult(fdc); 430 431 #ifdef FD_DEBUG 432 { 433 int i; 434 printf("fdprobe: status"); 435 for (i = 0; i < n; i++) 436 printf(" %x", fdc->sc_status[i]); 437 printf("\n"); 438 } 439 #endif 440 intr_arg = (void*)fdc; 441 if (n != 2 || (fdc->sc_status[0] & 0xf8) != 0x20) 442 return 0; 443 /* turn off motor */ 444 wrt_fdc_reg(fdout, FDO_FRST); 445 446 return 1; 447 } 448 449 /* 450 * Controller is working, and drive responded. Attach it. 451 */ 452 void 453 fdattach(parent, self, aux) 454 struct device *parent, *self; 455 void *aux; 456 { 457 struct fdc_softc *fdc = (void *)parent; 458 struct fd_softc *fd = (void *)self; 459 struct fdc_attach_args *fa = aux; 460 struct fd_type *type = fa->fa_deftype; 461 int drive = fa->fa_drive; 462 463 /* XXX Allow `flags' to override device type? */ 464 465 if (type) 466 printf(": %s %d cyl, %d head, %d sec\n", type->name, 467 type->tracks, type->heads, type->sectrac); 468 else 469 printf(": density unknown\n"); 470 471 fd->sc_cylin = -1; 472 fd->sc_drive = drive; 473 fd->sc_deftype = type; 474 fdc->sc_fd[drive] = fd; 475 476 /* 477 * Initialize and attach the disk structure. 478 */ 479 fd->sc_dk.dk_name = fd->sc_dev.dv_xname; 480 fd->sc_dk.dk_driver = &fddkdriver; 481 disk_attach(&fd->sc_dk); 482 483 /* XXX Need to do some more fiddling with sc_dk. */ 484 dk_establish(&fd->sc_dk, &fd->sc_dev); 485 486 /* Needed to power off if the motor is on when we halt. */ 487 fd->sc_sdhook = shutdownhook_establish(fd_motor_off, fd); 488 } 489 490 /* 491 * This is called from the assembly part of the interrupt handler 492 * when it is clear that the interrupt was not related to shoving 493 * data. 494 */ 495 void 496 fdc_ctrl_intr(frame) 497 struct clockframe frame; 498 { 499 int s; 500 501 /* 502 * Disable further interrupts. The fdcintr() routine 503 * explicitely enables them when needed. 504 */ 505 MFP2->mf_ierb &= ~IB_DCHG; 506 507 /* 508 * Set fddmalen to zero so no pseudo-dma transfers will 509 * occur. 510 */ 511 fddmalen = 0; 512 513 if (!BASEPRI(frame.cf_sr)) { 514 /* 515 * We don't want to stay on ipl6..... 516 */ 517 add_sicallback((si_farg)fdcpseudointr, intr_arg, 0); 518 } 519 else { 520 s = splbio(); 521 (void) fdcintr(intr_arg); 522 splx(s); 523 } 524 } 525 526 __inline struct fd_type * 527 fd_dev_to_type(fd, dev) 528 struct fd_softc *fd; 529 dev_t dev; 530 { 531 int type = FDTYPE(dev); 532 533 if (type > (sizeof(fd_types) / sizeof(fd_types[0]))) 534 return NULL; 535 return type ? &fd_types[type - 1] : fd->sc_deftype; 536 } 537 538 void 539 fdstrategy(bp) 540 register struct buf *bp; /* IO operation to perform */ 541 { 542 struct fd_softc *fd = hdfd_cd.cd_devs[FDUNIT(bp->b_dev)]; 543 int sz; 544 int s; 545 546 /* Valid unit, controller, and request? */ 547 if (bp->b_blkno < 0 || 548 ((bp->b_bcount % FDC_BSIZE) != 0 && 549 (bp->b_flags & B_FORMAT) == 0)) { 550 bp->b_error = EINVAL; 551 goto bad; 552 } 553 554 /* If it's a null transfer, return immediately. */ 555 if (bp->b_bcount == 0) 556 goto done; 557 558 sz = howmany(bp->b_bcount, FDC_BSIZE); 559 560 if (bp->b_blkno + sz > fd->sc_type->size) { 561 sz = fd->sc_type->size - bp->b_blkno; 562 if (sz == 0) { 563 /* If exactly at end of disk, return EOF. */ 564 goto done; 565 } 566 if (sz < 0) { 567 /* If past end of disk, return EINVAL. */ 568 bp->b_error = EINVAL; 569 goto bad; 570 } 571 /* Otherwise, truncate request. */ 572 bp->b_bcount = sz << DEV_BSHIFT; 573 } 574 575 bp->b_cylin = bp->b_blkno / (FDC_BSIZE/DEV_BSIZE) / fd->sc_type->seccyl; 576 577 #ifdef FD_DEBUG 578 printf("fdstrategy: b_blkno %d b_bcount %ld blkno %ld cylin %ld sz" 579 " %d\n", bp->b_blkno, bp->b_bcount, (long)fd->sc_blkno, 580 bp->b_cylin, sz); 581 #endif 582 583 /* Queue transfer on drive, activate drive and controller if idle. */ 584 s = splbio(); 585 disksort(&fd->sc_q, bp); 586 untimeout(fd_motor_off, fd); /* a good idea */ 587 if (!fd->sc_q.b_active) 588 fdstart(fd); 589 #ifdef DIAGNOSTIC 590 else { 591 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; 592 if (fdc->sc_state == DEVIDLE) { 593 printf("fdstrategy: controller inactive\n"); 594 fdcstart(fdc); 595 } 596 } 597 #endif 598 splx(s); 599 return; 600 601 bad: 602 bp->b_flags |= B_ERROR; 603 done: 604 /* Toss transfer; we're done early. */ 605 bp->b_resid = bp->b_bcount; 606 biodone(bp); 607 } 608 609 void 610 fdstart(fd) 611 struct fd_softc *fd; 612 { 613 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; 614 int active = fdc->sc_drives.tqh_first != 0; 615 616 /* Link into controller queue. */ 617 fd->sc_q.b_active = 1; 618 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); 619 620 /* If controller not already active, start it. */ 621 if (!active) 622 fdcstart(fdc); 623 } 624 625 void 626 fdfinish(fd, bp) 627 struct fd_softc *fd; 628 struct buf *bp; 629 { 630 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; 631 632 /* 633 * Move this drive to the end of the queue to give others a `fair' 634 * chance. We only force a switch if N operations are completed while 635 * another drive is waiting to be serviced, since there is a long motor 636 * startup delay whenever we switch. 637 */ 638 if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) { 639 fd->sc_ops = 0; 640 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); 641 if (bp->b_actf) { 642 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); 643 } else 644 fd->sc_q.b_active = 0; 645 } 646 bp->b_resid = fd->sc_bcount; 647 fd->sc_skip = 0; 648 fd->sc_q.b_actf = bp->b_actf; 649 650 biodone(bp); 651 /* turn off motor 5s from now */ 652 timeout(fd_motor_off, fd, 5 * hz); 653 fdc->sc_state = DEVIDLE; 654 } 655 656 int 657 fdread(dev, uio, flags) 658 dev_t dev; 659 struct uio *uio; 660 int flags; 661 { 662 return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio)); 663 } 664 665 int 666 fdwrite(dev, uio, flags) 667 dev_t dev; 668 struct uio *uio; 669 int flags; 670 { 671 return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio)); 672 } 673 674 void 675 fd_set_motor(fdc, reset) 676 struct fdc_softc *fdc; 677 int reset; 678 { 679 struct fd_softc *fd; 680 u_char status; 681 int n; 682 683 if ((fd = fdc->sc_drives.tqh_first) != NULL) 684 status = fd->sc_drive; 685 else 686 status = 0; 687 if (!reset) 688 status |= FDO_FRST | FDO_FDMAEN; 689 for (n = 0; n < 4; n++) 690 if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR)) 691 status |= FDO_MOEN(n); 692 wrt_fdc_reg(fdout, status); 693 } 694 695 void 696 fd_motor_off(arg) 697 void *arg; 698 { 699 struct fd_softc *fd = arg; 700 int s; 701 702 s = splbio(); 703 fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); 704 fd_set_motor((struct fdc_softc *)fd->sc_dev.dv_parent, 0); 705 splx(s); 706 } 707 708 void 709 fd_motor_on(arg) 710 void *arg; 711 { 712 struct fd_softc *fd = arg; 713 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; 714 int s; 715 716 s = splbio(); 717 fd->sc_flags &= ~FD_MOTOR_WAIT; 718 if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT)) 719 (void) fdcintr(fdc); 720 splx(s); 721 } 722 723 int 724 fdcresult(fdc) 725 struct fdc_softc *fdc; 726 { 727 u_char i; 728 int j = 100000, 729 n = 0; 730 731 for (; j; j--) { 732 i = rd_fdc_reg(fdsts) & (NE7_DIO | NE7_RQM | NE7_CB); 733 if (i == NE7_RQM) 734 return n; 735 if (i == (NE7_DIO | NE7_RQM | NE7_CB)) { 736 if (n >= sizeof(fdc->sc_status)) { 737 log(LOG_ERR, "fdcresult: overrun\n"); 738 return -1; 739 } 740 fdc->sc_status[n++] = rd_fdc_reg(fddata); 741 } 742 else delay(10); 743 } 744 log(LOG_ERR, "fdcresult: timeout\n"); 745 return -1; 746 } 747 748 int 749 out_fdc(x) 750 u_char x; 751 { 752 int i = 100000; 753 754 while (((rd_fdc_reg(fdsts) & (NE7_DIO|NE7_RQM)) != NE7_RQM) && i-- > 0) 755 delay(1); 756 if (i <= 0) 757 return -1; 758 wrt_fdc_reg(fddata, x); 759 return 0; 760 } 761 762 int 763 fdopen(dev, flags, mode, p) 764 dev_t dev; 765 int flags; 766 int mode; 767 struct proc *p; 768 { 769 int unit; 770 struct fd_softc *fd; 771 struct fd_type *type; 772 773 unit = FDUNIT(dev); 774 if (unit >= hdfd_cd.cd_ndevs) 775 return ENXIO; 776 fd = hdfd_cd.cd_devs[unit]; 777 if (fd == 0) 778 return ENXIO; 779 type = fd_dev_to_type(fd, dev); 780 if (type == NULL) 781 return ENXIO; 782 783 if ((fd->sc_flags & FD_OPEN) != 0 && 784 fd->sc_type != type) 785 return EBUSY; 786 787 fd->sc_type = type; 788 fd->sc_cylin = -1; 789 fd->sc_flags |= FD_OPEN; 790 791 return 0; 792 } 793 794 int 795 fdclose(dev, flags, mode, p) 796 dev_t dev; 797 int flags; 798 int mode; 799 struct proc *p; 800 { 801 struct fd_softc *fd = hdfd_cd.cd_devs[FDUNIT(dev)]; 802 803 fd->sc_flags &= ~FD_OPEN; 804 fd->sc_opts &= ~(FDOPT_NORETRY|FDOPT_SILENT); 805 return 0; 806 } 807 808 void 809 fdcstart(fdc) 810 struct fdc_softc *fdc; 811 { 812 813 #ifdef DIAGNOSTIC 814 /* only got here if controller's drive queue was inactive; should 815 be in idle state */ 816 if (fdc->sc_state != DEVIDLE) { 817 printf("fdcstart: not idle\n"); 818 return; 819 } 820 #endif 821 (void) fdcintr(fdc); 822 } 823 824 void 825 fdcstatus(dv, n, s) 826 struct device *dv; 827 int n; 828 char *s; 829 { 830 struct fdc_softc *fdc = (void *)dv->dv_parent; 831 char bits[64]; 832 833 if (n == 0) { 834 out_fdc(NE7CMD_SENSEI); 835 (void) fdcresult(fdc); 836 n = 2; 837 } 838 839 printf("%s: %s", dv->dv_xname, s); 840 841 switch (n) { 842 case 0: 843 printf("\n"); 844 break; 845 case 2: 846 printf(" (st0 %s cyl %d)\n", 847 bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS, 848 bits, sizeof(bits)), fdc->sc_status[1]); 849 break; 850 case 7: 851 printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0], 852 NE7_ST0BITS, bits, sizeof(bits))); 853 printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1], 854 NE7_ST1BITS, bits, sizeof(bits))); 855 printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2], 856 NE7_ST2BITS, bits, sizeof(bits))); 857 printf(" cyl %d head %d sec %d)\n", 858 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]); 859 break; 860 #ifdef DIAGNOSTIC 861 default: 862 printf("\nfdcstatus: weird size"); 863 break; 864 #endif 865 } 866 } 867 868 void 869 fdctimeout(arg) 870 void *arg; 871 { 872 struct fdc_softc *fdc = arg; 873 struct fd_softc *fd = fdc->sc_drives.tqh_first; 874 int s; 875 876 s = splbio(); 877 fdcstatus(&fd->sc_dev, 0, "timeout"); 878 879 if (fd->sc_q.b_actf) 880 fdc->sc_state++; 881 else 882 fdc->sc_state = DEVIDLE; 883 884 (void) fdcintr(fdc); 885 splx(s); 886 } 887 888 void 889 fdcpseudointr(arg) 890 void *arg; 891 { 892 int s; 893 894 /* Just ensure it has the right spl. */ 895 s = splbio(); 896 (void) fdcintr(arg); 897 splx(s); 898 } 899 900 int 901 fdcintr(arg) 902 void *arg; 903 { 904 struct fdc_softc *fdc = arg; 905 #define st0 fdc->sc_status[0] 906 #define st1 fdc->sc_status[1] 907 #define cyl fdc->sc_status[1] 908 909 struct fd_softc *fd; 910 struct buf *bp; 911 int read, head, sec, i, nblks; 912 struct fd_type *type; 913 struct ne7_fd_formb *finfo = NULL; 914 915 loop: 916 /* Is there a drive for the controller to do a transfer with? */ 917 fd = fdc->sc_drives.tqh_first; 918 if (fd == NULL) { 919 fdc->sc_state = DEVIDLE; 920 return 1; 921 } 922 923 /* Is there a transfer to this drive? If not, deactivate drive. */ 924 bp = fd->sc_q.b_actf; 925 if (bp == NULL) { 926 fd->sc_ops = 0; 927 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); 928 fd->sc_q.b_active = 0; 929 goto loop; 930 } 931 932 if (bp->b_flags & B_FORMAT) 933 finfo = (struct ne7_fd_formb *)bp->b_data; 934 935 switch (fdc->sc_state) { 936 case DEVIDLE: 937 fdc->sc_errors = 0; 938 fdc->sc_overruns = 0; 939 fd->sc_skip = 0; 940 fd->sc_bcount = bp->b_bcount; 941 fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE); 942 untimeout(fd_motor_off, fd); 943 if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) { 944 fdc->sc_state = MOTORWAIT; 945 return 1; 946 } 947 if ((fd->sc_flags & FD_MOTOR) == 0) { 948 /* Turn on the motor, being careful about pairing. */ 949 struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1]; 950 if (ofd && ofd->sc_flags & FD_MOTOR) { 951 untimeout(fd_motor_off, ofd); 952 ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); 953 } 954 fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT; 955 fd_set_motor(fdc, 0); 956 fdc->sc_state = MOTORWAIT; 957 /* Allow .25s for motor to stabilize. */ 958 timeout(fd_motor_on, fd, hz / 4); 959 return 1; 960 } 961 /* Make sure the right drive is selected. */ 962 fd_set_motor(fdc, 0); 963 964 /* fall through */ 965 case DOSEEK: 966 doseek: 967 if (fd->sc_cylin == bp->b_cylin) 968 goto doio; 969 970 out_fdc(NE7CMD_SPECIFY);/* specify command */ 971 out_fdc(fd->sc_type->steprate); 972 out_fdc(0x7); /* XXX head load time == 6ms - non-dma */ 973 974 fdc_ienable(); 975 976 out_fdc(NE7CMD_SEEK); /* seek function */ 977 out_fdc(fd->sc_drive); /* drive number */ 978 out_fdc(bp->b_cylin * fd->sc_type->step); 979 980 fd->sc_cylin = -1; 981 fdc->sc_state = SEEKWAIT; 982 983 fd->sc_dk.dk_seek++; 984 disk_busy(&fd->sc_dk); 985 986 timeout(fdctimeout, fdc, 4 * hz); 987 return 1; 988 989 case DOIO: 990 doio: 991 if (finfo) 992 fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) - 993 (char *)finfo; 994 995 type = fd->sc_type; 996 sec = fd->sc_blkno % type->seccyl; 997 head = sec / type->sectrac; 998 sec -= head * type->sectrac; 999 nblks = type->sectrac - sec; 1000 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE); 1001 nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE); 1002 fd->sc_nblks = nblks; 1003 fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE; 1004 #ifdef DIAGNOSTIC 1005 { 1006 int block; 1007 1008 block = (fd->sc_cylin * type->heads + head) 1009 * type->sectrac + sec; 1010 if (block != fd->sc_blkno) { 1011 printf("fdcintr: block %d != blkno %d\n", 1012 block, fd->sc_blkno); 1013 #ifdef DDB 1014 Debugger(); 1015 #endif 1016 } 1017 } 1018 #endif 1019 read = bp->b_flags & B_READ ? 1 : 0; 1020 1021 /* 1022 * Setup pseudo-dma address & count 1023 */ 1024 fddmaaddr = bp->b_data + fd->sc_skip; 1025 fddmalen = fd->sc_nbytes; 1026 1027 wrt_fdc_reg(fdctl, type->rate); 1028 #ifdef FD_DEBUG 1029 printf("fdcintr: %s drive %d track %d head %d sec %d" 1030 " nblks %d\n", read ? "read" : "write", 1031 fd->sc_drive, fd->sc_cylin, head, sec, nblks); 1032 #endif 1033 fdc_ienable(); 1034 1035 if (finfo) { 1036 /* formatting */ 1037 if (out_fdc(NE7CMD_FORMAT) < 0) { 1038 fdc->sc_errors = 4; 1039 fdcretry(fdc); 1040 goto loop; 1041 } 1042 out_fdc((head << 2) | fd->sc_drive); 1043 out_fdc(finfo->fd_formb_secshift); 1044 out_fdc(finfo->fd_formb_nsecs); 1045 out_fdc(finfo->fd_formb_gaplen); 1046 out_fdc(finfo->fd_formb_fillbyte); 1047 } else { 1048 if (read) 1049 out_fdc(NE7CMD_READ); /* READ */ 1050 else 1051 out_fdc(NE7CMD_WRITE); /* WRITE */ 1052 out_fdc((head << 2) | fd->sc_drive); 1053 out_fdc(fd->sc_cylin); /* track */ 1054 out_fdc(head); /* head */ 1055 out_fdc(sec + 1); /* sector +1 */ 1056 out_fdc(type->secsize); /* sector size */ 1057 out_fdc(sec + nblks); /* last sectors */ 1058 out_fdc(type->gap1); /* gap1 size */ 1059 out_fdc(type->datalen); /* data length */ 1060 } 1061 fdc->sc_state = IOCOMPLETE; 1062 1063 disk_busy(&fd->sc_dk); 1064 1065 /* allow 2 seconds for operation */ 1066 timeout(fdctimeout, fdc, 2 * hz); 1067 return 1; /* will return later */ 1068 1069 case SEEKWAIT: 1070 untimeout(fdctimeout, fdc); 1071 fdc->sc_state = SEEKCOMPLETE; 1072 /* allow 1/50 second for heads to settle */ 1073 timeout(fdcpseudointr, fdc, hz / 50); 1074 return 1; 1075 1076 case SEEKCOMPLETE: 1077 disk_unbusy(&fd->sc_dk, 0); /* no data on seek */ 1078 1079 /* Make sure seek really happened. */ 1080 out_fdc(NE7CMD_SENSEI); 1081 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || 1082 cyl != bp->b_cylin * fd->sc_type->step) { 1083 #ifdef FD_DEBUG 1084 fdcstatus(&fd->sc_dev, 2, "seek failed"); 1085 #endif 1086 fdcretry(fdc); 1087 goto loop; 1088 } 1089 fd->sc_cylin = bp->b_cylin; 1090 goto doio; 1091 1092 case IOTIMEDOUT: 1093 case SEEKTIMEDOUT: 1094 case RECALTIMEDOUT: 1095 case RESETTIMEDOUT: 1096 fdcretry(fdc); 1097 goto loop; 1098 1099 case IOCOMPLETE: /* IO DONE, post-analyze */ 1100 untimeout(fdctimeout, fdc); 1101 1102 disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid)); 1103 1104 if (fdcresult(fdc) != 7 || (st1 & 0x37) != 0) { 1105 /* 1106 * As the damn chip doesn't seem to have a FIFO, 1107 * accept a few overruns as a fact of life *sigh* 1108 */ 1109 if ((st1 & 0x10) && (++fdc->sc_overruns < 4)) { 1110 fdc->sc_state = DOSEEK; 1111 goto loop; 1112 } 1113 #ifdef FD_DEBUG 1114 fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ? 1115 "read failed" : "write failed"); 1116 printf("blkno %d nblks %d\n", 1117 fd->sc_blkno, fd->sc_nblks); 1118 #endif 1119 fdcretry(fdc); 1120 goto loop; 1121 } 1122 if (fdc->sc_errors) { 1123 diskerr(bp, "fd", "soft error", LOG_PRINTF, 1124 fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL); 1125 printf("\n"); 1126 fdc->sc_errors = 0; 1127 } 1128 fdc->sc_overruns = 0; 1129 fd->sc_blkno += fd->sc_nblks; 1130 fd->sc_skip += fd->sc_nbytes; 1131 fd->sc_bcount -= fd->sc_nbytes; 1132 if (!finfo && fd->sc_bcount > 0) { 1133 bp->b_cylin = fd->sc_blkno / fd->sc_type->seccyl; 1134 goto doseek; 1135 } 1136 fdfinish(fd, bp); 1137 goto loop; 1138 1139 case DORESET: 1140 /* try a reset, keep motor on */ 1141 fd_set_motor(fdc, 1); 1142 delay(100); 1143 fd_set_motor(fdc, 0); 1144 fdc->sc_state = RESETCOMPLETE; 1145 timeout(fdctimeout, fdc, hz / 2); 1146 return 1; /* will return later */ 1147 1148 case RESETCOMPLETE: 1149 untimeout(fdctimeout, fdc); 1150 /* clear the controller output buffer */ 1151 for (i = 0; i < 4; i++) { 1152 out_fdc(NE7CMD_SENSEI); 1153 (void) fdcresult(fdc); 1154 } 1155 1156 /* fall through */ 1157 case DORECAL: 1158 fdc_ienable(); 1159 1160 out_fdc(NE7CMD_RECAL); /* recalibrate function */ 1161 out_fdc(fd->sc_drive); 1162 fdc->sc_state = RECALWAIT; 1163 timeout(fdctimeout, fdc, 5 * hz); 1164 return 1; /* will return later */ 1165 1166 case RECALWAIT: 1167 untimeout(fdctimeout, fdc); 1168 fdc->sc_state = RECALCOMPLETE; 1169 /* allow 1/30 second for heads to settle */ 1170 timeout(fdcpseudointr, fdc, hz / 30); 1171 return 1; /* will return later */ 1172 1173 case RECALCOMPLETE: 1174 out_fdc(NE7CMD_SENSEI); 1175 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) { 1176 #ifdef FD_DEBUG 1177 fdcstatus(&fd->sc_dev, 2, "recalibrate failed"); 1178 #endif 1179 fdcretry(fdc); 1180 goto loop; 1181 } 1182 fd->sc_cylin = 0; 1183 goto doseek; 1184 1185 case MOTORWAIT: 1186 if (fd->sc_flags & FD_MOTOR_WAIT) 1187 return 1; /* time's not up yet */ 1188 goto doseek; 1189 1190 default: 1191 fdcstatus(&fd->sc_dev, 0, "stray interrupt"); 1192 return 1; 1193 } 1194 #ifdef DIAGNOSTIC 1195 panic("fdcintr: impossible"); 1196 #endif 1197 #undef st0 1198 #undef st1 1199 #undef cyl 1200 } 1201 1202 void 1203 fdcretry(fdc) 1204 struct fdc_softc *fdc; 1205 { 1206 char bits[64]; 1207 struct fd_softc *fd; 1208 struct buf *bp; 1209 1210 fd = fdc->sc_drives.tqh_first; 1211 bp = fd->sc_q.b_actf; 1212 1213 if (fd->sc_opts & FDOPT_NORETRY) 1214 goto fail; 1215 1216 switch (fdc->sc_errors) { 1217 case 0: 1218 /* try again */ 1219 fdc->sc_state = DOSEEK; 1220 break; 1221 1222 case 1: case 2: case 3: 1223 /* didn't work; try recalibrating */ 1224 fdc->sc_state = DORECAL; 1225 break; 1226 1227 case 4: 1228 /* still no go; reset the bastard */ 1229 fdc->sc_state = DORESET; 1230 break; 1231 1232 default: 1233 fail: 1234 if ((fd->sc_opts & FDOPT_SILENT) == 0) { 1235 diskerr(bp, "fd", "hard error", LOG_PRINTF, 1236 fd->sc_skip / FDC_BSIZE, 1237 (struct disklabel *)NULL); 1238 1239 printf(" (st0 %s", 1240 bitmask_snprintf(fdc->sc_status[0], 1241 NE7_ST0BITS, bits, 1242 sizeof(bits))); 1243 printf(" st1 %s", 1244 bitmask_snprintf(fdc->sc_status[1], 1245 NE7_ST1BITS, bits, 1246 sizeof(bits))); 1247 printf(" st2 %s", 1248 bitmask_snprintf(fdc->sc_status[2], 1249 NE7_ST2BITS, bits, 1250 sizeof(bits))); 1251 printf(" cyl %d head %d sec %d)\n", 1252 fdc->sc_status[3], 1253 fdc->sc_status[4], 1254 fdc->sc_status[5]); 1255 } 1256 bp->b_flags |= B_ERROR; 1257 bp->b_error = EIO; 1258 fdfinish(fd, bp); 1259 } 1260 fdc->sc_errors++; 1261 } 1262 1263 int 1264 fdsize(dev) 1265 dev_t dev; 1266 { 1267 1268 /* Swapping to floppies would not make sense. */ 1269 return -1; 1270 } 1271 1272 int 1273 fddump(dev, blkno, va, size) 1274 dev_t dev; 1275 daddr_t blkno; 1276 caddr_t va; 1277 size_t size; 1278 { 1279 1280 /* Not implemented. */ 1281 return ENXIO; 1282 } 1283 1284 int 1285 fdioctl(dev, cmd, addr, flag, p) 1286 dev_t dev; 1287 u_long cmd; 1288 caddr_t addr; 1289 int flag; 1290 struct proc *p; 1291 { 1292 struct fd_softc *fd; 1293 struct disklabel buffer; 1294 struct cpu_disklabel cpulab; 1295 int error; 1296 struct fdformat_parms *form_parms; 1297 struct fdformat_cmd *form_cmd; 1298 struct ne7_fd_formb fd_formb; 1299 unsigned int scratch; 1300 int il[FD_MAX_NSEC + 1]; 1301 register int i, j; 1302 1303 fd = hdfd_cd.cd_devs[FDUNIT(dev)]; 1304 1305 switch (cmd) { 1306 case DIOCGDINFO: 1307 bzero(&buffer, sizeof(buffer)); 1308 bzero(&cpulab, sizeof(cpulab)); 1309 1310 buffer.d_secpercyl = fd->sc_type->seccyl; 1311 buffer.d_type = DTYPE_FLOPPY; 1312 buffer.d_secsize = FDC_BSIZE; 1313 buffer.d_secperunit = fd->sc_type->size; 1314 1315 if (readdisklabel(dev, fdstrategy, &buffer, &cpulab) != NULL) 1316 return EINVAL; 1317 *(struct disklabel *)addr = buffer; 1318 return 0; 1319 1320 case DIOCWLABEL: 1321 if ((flag & FWRITE) == 0) 1322 return EBADF; 1323 /* XXX do something */ 1324 return 0; 1325 1326 case DIOCWDINFO: 1327 if ((flag & FWRITE) == 0) 1328 return EBADF; 1329 1330 error = setdisklabel(&buffer, (struct disklabel *)addr, 0,NULL); 1331 if (error) 1332 return error; 1333 1334 error = writedisklabel(dev, fdstrategy, &buffer, NULL); 1335 return error; 1336 1337 case FDIOCGETFORMAT: 1338 form_parms = (struct fdformat_parms *)addr; 1339 form_parms->fdformat_version = FDFORMAT_VERSION; 1340 form_parms->nbps = 128 * (1 << fd->sc_type->secsize); 1341 form_parms->ncyl = fd->sc_type->tracks; 1342 form_parms->nspt = fd->sc_type->sectrac; 1343 form_parms->ntrk = fd->sc_type->heads; 1344 form_parms->stepspercyl = fd->sc_type->step; 1345 form_parms->gaplen = fd->sc_type->gap2; 1346 form_parms->fillbyte = fd->sc_type->fillbyte; 1347 form_parms->interleave = fd->sc_type->interleave; 1348 switch (fd->sc_type->rate) { 1349 case FDC_500KBPS: 1350 form_parms->xfer_rate = 500 * 1024; 1351 break; 1352 case FDC_300KBPS: 1353 form_parms->xfer_rate = 300 * 1024; 1354 break; 1355 case FDC_250KBPS: 1356 form_parms->xfer_rate = 250 * 1024; 1357 break; 1358 default: 1359 return EINVAL; 1360 } 1361 return 0; 1362 1363 case FDIOCSETFORMAT: 1364 if((flag & FWRITE) == 0) 1365 return EBADF; /* must be opened for writing */ 1366 form_parms = (struct fdformat_parms *)addr; 1367 if (form_parms->fdformat_version != FDFORMAT_VERSION) 1368 return EINVAL; /* wrong version of formatting prog */ 1369 1370 scratch = form_parms->nbps >> 7; 1371 if ((form_parms->nbps & 0x7f) || ffs(scratch) == 0 || 1372 scratch & ~(1 << (ffs(scratch)-1))) 1373 /* not a power-of-two multiple of 128 */ 1374 return EINVAL; 1375 1376 switch (form_parms->xfer_rate) { 1377 case 500 * 1024: 1378 fd->sc_type->rate = FDC_500KBPS; 1379 break; 1380 case 300 * 1024: 1381 fd->sc_type->rate = FDC_300KBPS; 1382 break; 1383 case 250 * 1024: 1384 fd->sc_type->rate = FDC_250KBPS; 1385 break; 1386 default: 1387 return EINVAL; 1388 } 1389 1390 if (form_parms->nspt > FD_MAX_NSEC || 1391 form_parms->fillbyte > 0xff || 1392 form_parms->interleave > 0xff) 1393 return EINVAL; 1394 fd->sc_type->sectrac = form_parms->nspt; 1395 if (form_parms->ntrk != 2 && form_parms->ntrk != 1) 1396 return EINVAL; 1397 fd->sc_type->heads = form_parms->ntrk; 1398 fd->sc_type->seccyl = form_parms->nspt * form_parms->ntrk; 1399 fd->sc_type->secsize = ffs(scratch)-1; 1400 fd->sc_type->gap2 = form_parms->gaplen; 1401 fd->sc_type->tracks = form_parms->ncyl; 1402 fd->sc_type->size = fd->sc_type->seccyl * form_parms->ncyl * 1403 form_parms->nbps / DEV_BSIZE; 1404 fd->sc_type->step = form_parms->stepspercyl; 1405 fd->sc_type->fillbyte = form_parms->fillbyte; 1406 fd->sc_type->interleave = form_parms->interleave; 1407 return 0; 1408 1409 case FDIOCFORMAT_TRACK: 1410 if((flag & FWRITE) == 0) 1411 return EBADF; /* must be opened for writing */ 1412 form_cmd = (struct fdformat_cmd *)addr; 1413 if (form_cmd->formatcmd_version != FDFORMAT_VERSION) 1414 return EINVAL; /* wrong version of formatting prog */ 1415 1416 if (form_cmd->head >= fd->sc_type->heads || 1417 form_cmd->cylinder >= fd->sc_type->tracks) { 1418 return EINVAL; 1419 } 1420 1421 fd_formb.head = form_cmd->head; 1422 fd_formb.cyl = form_cmd->cylinder; 1423 fd_formb.transfer_rate = fd->sc_type->rate; 1424 fd_formb.fd_formb_secshift = fd->sc_type->secsize; 1425 fd_formb.fd_formb_nsecs = fd->sc_type->sectrac; 1426 fd_formb.fd_formb_gaplen = fd->sc_type->gap2; 1427 fd_formb.fd_formb_fillbyte = fd->sc_type->fillbyte; 1428 1429 bzero(il,sizeof il); 1430 for (j = 0, i = 1; i <= fd_formb.fd_formb_nsecs; i++) { 1431 while (il[(j%fd_formb.fd_formb_nsecs)+1]) 1432 j++; 1433 il[(j%fd_formb.fd_formb_nsecs)+1] = i; 1434 j += fd->sc_type->interleave; 1435 } 1436 for (i = 0; i < fd_formb.fd_formb_nsecs; i++) { 1437 fd_formb.fd_formb_cylno(i) = form_cmd->cylinder; 1438 fd_formb.fd_formb_headno(i) = form_cmd->head; 1439 fd_formb.fd_formb_secno(i) = il[i+1]; 1440 fd_formb.fd_formb_secsize(i) = fd->sc_type->secsize; 1441 } 1442 case FDIOCGETOPTS: /* get drive options */ 1443 *(int *)addr = fd->sc_opts; 1444 return 0; 1445 1446 case FDIOCSETOPTS: /* set drive options */ 1447 fd->sc_opts = *(int *)addr; 1448 return 0; 1449 1450 1451 default: 1452 return ENOTTY; 1453 } 1454 1455 #ifdef DIAGNOSTIC 1456 panic("fdioctl: impossible"); 1457 #endif 1458 } 1459 1460 int 1461 fdformat(dev, finfo, p) 1462 dev_t dev; 1463 struct ne7_fd_formb *finfo; 1464 struct proc *p; 1465 { 1466 int rv = 0, s; 1467 struct fd_softc *fd = hdfd_cd.cd_devs[FDUNIT(dev)]; 1468 struct fd_type *type = fd->sc_type; 1469 struct buf *bp; 1470 1471 /* set up a buffer header for fdstrategy() */ 1472 bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT); 1473 if(bp == 0) 1474 return ENOBUFS; 1475 PHOLD(p); 1476 bzero((void *)bp, sizeof(struct buf)); 1477 bp->b_flags = B_BUSY | B_PHYS | B_FORMAT; 1478 bp->b_proc = p; 1479 bp->b_dev = dev; 1480 1481 /* 1482 * calculate a fake blkno, so fdstrategy() would initiate a 1483 * seek to the requested cylinder 1484 */ 1485 bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads) 1486 + finfo->head * type->sectrac) * FDC_BSIZE / DEV_BSIZE; 1487 1488 bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs; 1489 bp->b_data = (caddr_t)finfo; 1490 1491 #ifdef DEBUG 1492 printf("fdformat: blkno %x count %x\n", bp->b_blkno, bp->b_bcount); 1493 #endif 1494 1495 /* now do the format */ 1496 fdstrategy(bp); 1497 1498 /* ...and wait for it to complete */ 1499 s = splbio(); 1500 while(!(bp->b_flags & B_DONE)) { 1501 rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz); 1502 if (rv == EWOULDBLOCK) 1503 break; 1504 } 1505 splx(s); 1506 1507 if (rv == EWOULDBLOCK) { 1508 /* timed out */ 1509 rv = EIO; 1510 biodone(bp); 1511 } 1512 if(bp->b_flags & B_ERROR) { 1513 rv = bp->b_error; 1514 } 1515 PRELE(p); 1516 free(bp, M_TEMP); 1517 return rv; 1518 } 1519