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