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