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