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