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