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