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