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