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