1 /* $NetBSD: hdfd.c,v 1.64 2008/12/18 10:58:17 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.64 2008/12/18 10:58:17 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 117 #include <uvm/uvm_extern.h> 118 119 #include <machine/cpu.h> 120 #include <machine/bus.h> 121 #include <machine/iomap.h> 122 #include <machine/mfp.h> 123 124 #include <atari/dev/hdfdreg.h> 125 #include <atari/atari/intr.h> 126 #include <atari/atari/device.h> 127 128 #include "locators.h" 129 130 /* 131 * {b,c}devsw[] function prototypes 132 */ 133 dev_type_open(fdopen); 134 dev_type_close(fdclose); 135 dev_type_read(fdread); 136 dev_type_write(fdwrite); 137 dev_type_ioctl(fdioctl); 138 dev_type_strategy(fdstrategy); 139 140 volatile u_char *fdio_addr; 141 142 #define wrt_fdc_reg(reg, val) { fdio_addr[reg] = val; } 143 #define rd_fdc_reg(reg) ( fdio_addr[reg] ) 144 145 #define fdc_ienable() MFP2->mf_ierb |= IB_DCHG; 146 147 /* 148 * Interface to the pseudo-DMA handler 149 */ 150 void fddma_intr(void); 151 void * fddmaaddr = NULL; 152 int fddmalen = 0; 153 154 extern void mfp_hdfd_nf __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 /* (mis)use device use flag to identify format operation */ 167 #define B_FORMAT B_DEVPRIVATE 168 169 enum fdc_state { 170 DEVIDLE = 0, 171 MOTORWAIT, 172 DOSEEK, 173 SEEKWAIT, 174 SEEKTIMEDOUT, 175 SEEKCOMPLETE, 176 DOIO, 177 IOCOMPLETE, 178 IOTIMEDOUT, 179 DORESET, 180 RESETCOMPLETE, 181 RESETTIMEDOUT, 182 DORECAL, 183 RECALWAIT, 184 RECALTIMEDOUT, 185 RECALCOMPLETE, 186 }; 187 188 /* software state, per controller */ 189 struct fdc_softc { 190 struct device sc_dev; /* boilerplate */ 191 192 struct callout sc_timo_ch; /* timeout callout */ 193 struct callout sc_intr_ch; /* pseudo-intr callout */ 194 195 struct fd_softc *sc_fd[4]; /* pointers to children */ 196 TAILQ_HEAD(drivehead, fd_softc) sc_drives; 197 enum fdc_state sc_state; 198 int sc_errors; /* number of retries so far */ 199 int sc_overruns; /* number of overruns so far */ 200 u_char sc_status[7]; /* copy of registers */ 201 }; 202 203 /* controller driver configuration */ 204 int fdcprobe __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 const char *name; 231 }; 232 233 /* 234 * The order of entries in the following table is important -- BEWARE! 235 * The order of the types is the same as for the TT/Falcon.... 236 */ 237 struct fd_type fd_types[] = { 238 /* 360kB in 720kB drive */ 239 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_125KBPS,0xf6,1,"360KB" }, 240 /* 3.5" 720kB diskette */ 241 { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_125KBPS,0xf6,1,"720KB" }, 242 /* 1.44MB diskette */ 243 { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_250KBPS,0xf6,1,"1.44MB" }, 244 }; 245 246 /* software state, per disk (with up to 4 disks per ctlr) */ 247 struct fd_softc { 248 struct device sc_dev; 249 struct disk sc_dk; 250 251 struct fd_type *sc_deftype; /* default type descriptor */ 252 struct fd_type *sc_type; /* current type descriptor */ 253 254 struct callout sc_motoron_ch; 255 struct callout sc_motoroff_ch; 256 257 daddr_t sc_blkno; /* starting block number */ 258 int sc_bcount; /* byte count left */ 259 int sc_opts; /* user-set options */ 260 int sc_skip; /* bytes already transferred */ 261 int sc_nblks; /* #blocks currently transferring */ 262 int sc_nbytes; /* #bytes currently transferring */ 263 264 int sc_drive; /* physical unit number */ 265 int sc_flags; 266 #define FD_OPEN 0x01 /* it's open */ 267 #define FD_MOTOR 0x02 /* motor should be on */ 268 #define FD_MOTOR_WAIT 0x04 /* motor coming up */ 269 #define FD_HAVELAB 0x08 /* got a disklabel */ 270 int sc_cylin; /* where we think the head is */ 271 272 void *sc_sdhook; /* saved shutdown hook for drive. */ 273 274 TAILQ_ENTRY(fd_softc) sc_drivechain; 275 int sc_ops; /* I/O ops since last switch */ 276 struct bufq_state *sc_q; /* pending I/O requests */ 277 int sc_active; /* number of active I/O operations */ 278 }; 279 280 /* floppy driver configuration */ 281 int fdprobe __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, const 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 bus_space_handle_t handle; 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, &handle)) { 344 printf("fdcprobe: cannot map io-area\n"); 345 mb_free_bus_space_tag(mb_tag); 346 return (0); 347 } 348 fdio_addr = bus_space_vaddr(mb_tag, handle); /* XXX */ 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, handle, 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, 0); 435 callout_init(&fdc->sc_intr_ch, 0); 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, 0); 529 callout_init(&fd->sc_motoroff_ch, 0); 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, "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 disk_init(&fd->sc_dk, fd->sc_dev.dv_xname, &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(struct fd_softc *fd, dev_t dev) 593 { 594 int type = FDTYPE(dev); 595 596 if (type > (sizeof(fd_types) / sizeof(fd_types[0]))) 597 return NULL; 598 return type ? &fd_types[type - 1] : fd->sc_deftype; 599 } 600 601 void 602 fdstrategy(struct buf *bp) 603 { 604 struct fd_softc *fd = device_lookup_private(&hdfd_cd, FDUNIT(bp->b_dev)); 605 int sz; 606 int s; 607 608 /* Valid unit, controller, and request? */ 609 if (bp->b_blkno < 0 || 610 ((bp->b_bcount % FDC_BSIZE) != 0 && 611 (bp->b_flags & B_FORMAT) == 0)) { 612 bp->b_error = EINVAL; 613 goto done; 614 } 615 616 /* If it's a null transfer, return immediately. */ 617 if (bp->b_bcount == 0) 618 goto done; 619 620 sz = howmany(bp->b_bcount, FDC_BSIZE); 621 622 if (bp->b_blkno + sz > fd->sc_type->size) { 623 sz = fd->sc_type->size - bp->b_blkno; 624 if (sz == 0) { 625 /* If exactly at end of disk, return EOF. */ 626 goto done; 627 } 628 if (sz < 0) { 629 /* If past end of disk, return EINVAL. */ 630 bp->b_error = EINVAL; 631 goto done; 632 } 633 /* Otherwise, truncate request. */ 634 bp->b_bcount = sz << DEV_BSHIFT; 635 } 636 637 bp->b_rawblkno = bp->b_blkno; 638 bp->b_cylinder = bp->b_blkno / (FDC_BSIZE/DEV_BSIZE) / fd->sc_type->seccyl; 639 640 #ifdef FD_DEBUG 641 printf("fdstrategy: b_blkno %d b_bcount %ld blkno %qd cylin %ld sz" 642 " %d\n", bp->b_blkno, bp->b_bcount, (long)fd->sc_blkno, 643 bp->b_cylinder, sz); 644 #endif 645 646 /* Queue transfer on drive, activate drive and controller if idle. */ 647 s = splbio(); 648 BUFQ_PUT(fd->sc_q, bp); 649 callout_stop(&fd->sc_motoroff_ch); /* a good idea */ 650 if (fd->sc_active == 0) 651 fdstart(fd); 652 #ifdef DIAGNOSTIC 653 else { 654 struct fdc_softc *fdc = (void *) device_parent(&fd->sc_dev); 655 if (fdc->sc_state == DEVIDLE) { 656 printf("fdstrategy: controller inactive\n"); 657 fdcstart(fdc); 658 } 659 } 660 #endif 661 splx(s); 662 return; 663 664 done: 665 /* Toss transfer; we're done early. */ 666 bp->b_resid = bp->b_bcount; 667 biodone(bp); 668 } 669 670 void 671 fdstart(fd) 672 struct fd_softc *fd; 673 { 674 struct fdc_softc *fdc = (void *) device_parent(&fd->sc_dev); 675 int active = fdc->sc_drives.tqh_first != 0; 676 677 /* Link into controller queue. */ 678 fd->sc_active = 1; 679 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); 680 681 /* If controller not already active, start it. */ 682 if (!active) 683 fdcstart(fdc); 684 } 685 686 void 687 fdfinish(fd, bp) 688 struct fd_softc *fd; 689 struct buf *bp; 690 { 691 struct fdc_softc *fdc = (void *) device_parent(&fd->sc_dev); 692 693 /* 694 * Move this drive to the end of the queue to give others a `fair' 695 * chance. We only force a switch if N operations are completed while 696 * another drive is waiting to be serviced, since there is a long motor 697 * startup delay whenever we switch. 698 */ 699 (void)BUFQ_GET(fd->sc_q); 700 if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) { 701 fd->sc_ops = 0; 702 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); 703 if (BUFQ_PEEK(fd->sc_q) != NULL) 704 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); 705 else 706 fd->sc_active = 0; 707 } 708 bp->b_resid = fd->sc_bcount; 709 fd->sc_skip = 0; 710 711 biodone(bp); 712 /* turn off motor 5s from now */ 713 callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd); 714 fdc->sc_state = DEVIDLE; 715 } 716 717 int 718 fdread(dev, uio, flags) 719 dev_t dev; 720 struct uio *uio; 721 int flags; 722 { 723 return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio)); 724 } 725 726 int 727 fdwrite(dev, uio, flags) 728 dev_t dev; 729 struct uio *uio; 730 int flags; 731 { 732 return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio)); 733 } 734 735 void 736 fd_set_motor(fdc, reset) 737 struct fdc_softc *fdc; 738 int reset; 739 { 740 struct fd_softc *fd; 741 u_char status; 742 int n; 743 744 if ((fd = fdc->sc_drives.tqh_first) != NULL) 745 status = fd->sc_drive; 746 else 747 status = 0; 748 if (!reset) 749 status |= FDO_FRST | FDO_FDMAEN; 750 for (n = 0; n < 4; n++) 751 if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR)) 752 status |= FDO_MOEN(n); 753 wrt_fdc_reg(fdout, status); 754 } 755 756 void 757 fd_motor_off(arg) 758 void *arg; 759 { 760 struct fd_softc *fd = arg; 761 int s; 762 763 s = splbio(); 764 fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); 765 fd_set_motor((struct fdc_softc *) device_parent(&fd->sc_dev), 0); 766 splx(s); 767 } 768 769 void 770 fd_motor_on(arg) 771 void *arg; 772 { 773 struct fd_softc *fd = arg; 774 struct fdc_softc *fdc = (void *) device_parent(&fd->sc_dev); 775 int s; 776 777 s = splbio(); 778 fd->sc_flags &= ~FD_MOTOR_WAIT; 779 if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT)) 780 (void) fdcintr(fdc); 781 splx(s); 782 } 783 784 int 785 fdcresult(fdc) 786 struct fdc_softc *fdc; 787 { 788 u_char i; 789 int j = 100000, 790 n = 0; 791 792 for (; j; j--) { 793 i = rd_fdc_reg(fdsts) & (NE7_DIO | NE7_RQM | NE7_CB); 794 if (i == NE7_RQM) 795 return n; 796 if (i == (NE7_DIO | NE7_RQM | NE7_CB)) { 797 if (n >= sizeof(fdc->sc_status)) { 798 log(LOG_ERR, "fdcresult: overrun\n"); 799 return -1; 800 } 801 fdc->sc_status[n++] = rd_fdc_reg(fddata); 802 } 803 else delay(10); 804 } 805 log(LOG_ERR, "fdcresult: timeout\n"); 806 return -1; 807 } 808 809 int 810 out_fdc(x) 811 u_char x; 812 { 813 int i = 100000; 814 815 while (((rd_fdc_reg(fdsts) & (NE7_DIO|NE7_RQM)) != NE7_RQM) && i-- > 0) 816 delay(1); 817 if (i <= 0) 818 return -1; 819 wrt_fdc_reg(fddata, x); 820 return 0; 821 } 822 823 int 824 fdopen(dev_t dev, int flags, int mode, struct lwp *l) 825 { 826 struct fd_softc *fd; 827 struct fd_type *type; 828 829 fd = device_lookup_private(&hdfd_cd, FDUNIT(dev)); 830 if (fd == NULL) 831 return ENXIO; 832 type = fd_dev_to_type(fd, dev); 833 if (type == NULL) 834 return ENXIO; 835 836 if ((fd->sc_flags & FD_OPEN) != 0 && 837 fd->sc_type != type) 838 return EBUSY; 839 840 fd->sc_type = type; 841 fd->sc_cylin = -1; 842 fd->sc_flags |= FD_OPEN; 843 fdgetdisklabel(fd, dev); 844 845 return 0; 846 } 847 848 int 849 fdclose(dev_t dev, int flags, int mode, struct lwp *l) 850 { 851 struct fd_softc *fd = device_lookup_private(&hdfd_cd, FDUNIT(dev)); 852 853 fd->sc_flags &= ~(FD_OPEN|FD_HAVELAB); 854 fd->sc_opts &= ~(FDOPT_NORETRY|FDOPT_SILENT); 855 return 0; 856 } 857 858 void 859 fdcstart(fdc) 860 struct fdc_softc *fdc; 861 { 862 863 #ifdef DIAGNOSTIC 864 /* only got here if controller's drive queue was inactive; should 865 be in idle state */ 866 if (fdc->sc_state != DEVIDLE) { 867 printf("fdcstart: not idle\n"); 868 return; 869 } 870 #endif 871 (void) fdcintr(fdc); 872 } 873 874 static void 875 fdcpstatus(struct fdc_softc *fdc) 876 { 877 char bits[64]; 878 879 snprintb(bits, sizeof(bits), NE7_ST0BITS, fdc->sc_status[0]); 880 printf(" (st0 %s", bits); 881 snprintb(bits, sizeof(bits), NE7_ST1BITS, fdc->sc_status[1]); 882 printf(" st1 %s", bits); 883 snprintb(bits, sizeof(bits), NE7_ST2BITS, fdc->sc_status[2]); 884 printf(" st2 %s", bits); 885 printf(" cyl %d head %d sec %d)\n", 886 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]); 887 } 888 889 void 890 fdcstatus(dv, n, s) 891 struct device *dv; 892 int n; 893 const char *s; 894 { 895 struct fdc_softc *fdc = (void *) device_parent(dv); 896 char bits[64]; 897 898 if (n == 0) { 899 out_fdc(NE7CMD_SENSEI); 900 (void) fdcresult(fdc); 901 n = 2; 902 } 903 904 printf("%s: %s", dv->dv_xname, s); 905 906 switch (n) { 907 case 0: 908 printf("\n"); 909 break; 910 case 2: 911 snprintb(bits, sizeof(bits), NE7_ST0BITS, fdc->sc_status[0]); 912 printf(" (st0 %s cyl %d)\n", bits, fdc->sc_status[1]); 913 break; 914 case 7: 915 fdcpstatus(fdc); 916 break; 917 #ifdef DIAGNOSTIC 918 default: 919 printf("\nfdcstatus: weird size"); 920 break; 921 #endif 922 } 923 } 924 925 void 926 fdctimeout(arg) 927 void *arg; 928 { 929 struct fdc_softc *fdc = arg; 930 struct fd_softc *fd = fdc->sc_drives.tqh_first; 931 int s; 932 933 s = splbio(); 934 fdcstatus(&fd->sc_dev, 0, "timeout"); 935 936 if (BUFQ_PEEK(fd->sc_q) != NULL) 937 fdc->sc_state++; 938 else 939 fdc->sc_state = DEVIDLE; 940 941 (void) fdcintr(fdc); 942 splx(s); 943 } 944 945 void 946 fdcpseudointr(arg) 947 void *arg; 948 { 949 int s; 950 951 /* Just ensure it has the right spl. */ 952 s = splbio(); 953 (void) fdcintr(arg); 954 splx(s); 955 } 956 957 int 958 fdcintr(arg) 959 void *arg; 960 { 961 struct fdc_softc *fdc = arg; 962 #define st0 fdc->sc_status[0] 963 #define st1 fdc->sc_status[1] 964 #define cyl fdc->sc_status[1] 965 966 struct fd_softc *fd; 967 struct buf *bp; 968 int read, head, sec, i, nblks; 969 struct fd_type *type; 970 struct ne7_fd_formb *finfo = NULL; 971 972 loop: 973 /* Is there a drive for the controller to do a transfer with? */ 974 fd = fdc->sc_drives.tqh_first; 975 if (fd == NULL) { 976 fdc->sc_state = DEVIDLE; 977 return 1; 978 } 979 980 /* Is there a transfer to this drive? If not, deactivate drive. */ 981 bp = BUFQ_PEEK(fd->sc_q); 982 if (bp == NULL) { 983 fd->sc_ops = 0; 984 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); 985 fd->sc_active = 0; 986 goto loop; 987 } 988 989 if (bp->b_flags & B_FORMAT) 990 finfo = (struct ne7_fd_formb *)bp->b_data; 991 992 switch (fdc->sc_state) { 993 case DEVIDLE: 994 fdc->sc_errors = 0; 995 fdc->sc_overruns = 0; 996 fd->sc_skip = 0; 997 fd->sc_bcount = bp->b_bcount; 998 fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE); 999 callout_stop(&fd->sc_motoroff_ch); 1000 if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) { 1001 fdc->sc_state = MOTORWAIT; 1002 return 1; 1003 } 1004 if ((fd->sc_flags & FD_MOTOR) == 0) { 1005 /* Turn on the motor, being careful about pairing. */ 1006 struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1]; 1007 if (ofd && ofd->sc_flags & FD_MOTOR) { 1008 callout_stop(&ofd->sc_motoroff_ch); 1009 ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); 1010 } 1011 fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT; 1012 fd_set_motor(fdc, 0); 1013 fdc->sc_state = MOTORWAIT; 1014 /* Allow .25s for motor to stabilize. */ 1015 callout_reset(&fd->sc_motoron_ch, hz / 4, 1016 fd_motor_on, fd); 1017 return 1; 1018 } 1019 /* Make sure the right drive is selected. */ 1020 fd_set_motor(fdc, 0); 1021 1022 /* fall through */ 1023 case DOSEEK: 1024 doseek: 1025 if (fd->sc_cylin == bp->b_cylinder) 1026 goto doio; 1027 1028 out_fdc(NE7CMD_SPECIFY);/* specify command */ 1029 out_fdc(fd->sc_type->steprate); 1030 out_fdc(0x7); /* XXX head load time == 6ms - non-DMA */ 1031 1032 fdc_ienable(); 1033 1034 out_fdc(NE7CMD_SEEK); /* seek function */ 1035 out_fdc(fd->sc_drive); /* drive number */ 1036 out_fdc(bp->b_cylinder * fd->sc_type->step); 1037 1038 fd->sc_cylin = -1; 1039 fdc->sc_state = SEEKWAIT; 1040 1041 iostat_seek(fd->sc_dk.dk_stats); 1042 disk_busy(&fd->sc_dk); 1043 1044 callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc); 1045 return 1; 1046 1047 case DOIO: 1048 doio: 1049 if (finfo) 1050 fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) - 1051 (char *)finfo; 1052 1053 type = fd->sc_type; 1054 sec = fd->sc_blkno % type->seccyl; 1055 head = sec / type->sectrac; 1056 sec -= head * type->sectrac; 1057 nblks = type->sectrac - sec; 1058 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE); 1059 nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE); 1060 fd->sc_nblks = nblks; 1061 fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE; 1062 #ifdef DIAGNOSTIC 1063 { 1064 int block; 1065 1066 block = (fd->sc_cylin * type->heads + head) 1067 * type->sectrac + sec; 1068 if (block != fd->sc_blkno) { 1069 printf("fdcintr: block %d != blkno %qd\n", 1070 block, fd->sc_blkno); 1071 #ifdef DDB 1072 Debugger(); 1073 #endif 1074 } 1075 } 1076 #endif 1077 read = bp->b_flags & B_READ ? 1 : 0; 1078 1079 /* 1080 * Setup pseudo-DMA address & count 1081 */ 1082 fddmaaddr = (char *)bp->b_data + fd->sc_skip; 1083 fddmalen = fd->sc_nbytes; 1084 1085 wrt_fdc_reg(fdctl, type->rate); 1086 #ifdef FD_DEBUG 1087 printf("fdcintr: %s drive %d track %d head %d sec %d" 1088 " nblks %d\n", read ? "read" : "write", 1089 fd->sc_drive, fd->sc_cylin, head, sec, nblks); 1090 #endif 1091 fdc_ienable(); 1092 1093 if (finfo) { 1094 /* formatting */ 1095 if (out_fdc(NE7CMD_FORMAT) < 0) { 1096 fdc->sc_errors = 4; 1097 fdcretry(fdc); 1098 goto loop; 1099 } 1100 out_fdc((head << 2) | fd->sc_drive); 1101 out_fdc(finfo->fd_formb_secshift); 1102 out_fdc(finfo->fd_formb_nsecs); 1103 out_fdc(finfo->fd_formb_gaplen); 1104 out_fdc(finfo->fd_formb_fillbyte); 1105 } else { 1106 if (read) 1107 out_fdc(NE7CMD_READ); /* READ */ 1108 else 1109 out_fdc(NE7CMD_WRITE); /* WRITE */ 1110 out_fdc((head << 2) | fd->sc_drive); 1111 out_fdc(fd->sc_cylin); /* track */ 1112 out_fdc(head); /* head */ 1113 out_fdc(sec + 1); /* sector +1 */ 1114 out_fdc(type->secsize); /* sector size */ 1115 out_fdc(sec + nblks); /* last sectors */ 1116 out_fdc(type->gap1); /* gap1 size */ 1117 out_fdc(type->datalen); /* data length */ 1118 } 1119 fdc->sc_state = IOCOMPLETE; 1120 1121 disk_busy(&fd->sc_dk); 1122 1123 /* allow 2 seconds for operation */ 1124 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc); 1125 return 1; /* will return later */ 1126 1127 case SEEKWAIT: 1128 callout_stop(&fdc->sc_timo_ch); 1129 fdc->sc_state = SEEKCOMPLETE; 1130 /* allow 1/50 second for heads to settle */ 1131 callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc); 1132 return 1; 1133 1134 case SEEKCOMPLETE: 1135 /* no data on seek */ 1136 disk_unbusy(&fd->sc_dk, 0, 0); 1137 1138 /* Make sure seek really happened. */ 1139 out_fdc(NE7CMD_SENSEI); 1140 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || 1141 cyl != bp->b_cylinder * fd->sc_type->step) { 1142 #ifdef FD_DEBUG 1143 fdcstatus(&fd->sc_dev, 2, "seek failed"); 1144 #endif 1145 fdcretry(fdc); 1146 goto loop; 1147 } 1148 fd->sc_cylin = bp->b_cylinder; 1149 goto doio; 1150 1151 case IOTIMEDOUT: 1152 case SEEKTIMEDOUT: 1153 case RECALTIMEDOUT: 1154 case RESETTIMEDOUT: 1155 fdcretry(fdc); 1156 goto loop; 1157 1158 case IOCOMPLETE: /* IO DONE, post-analyze */ 1159 callout_stop(&fdc->sc_timo_ch); 1160 1161 disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid), 1162 (bp->b_flags & B_READ)); 1163 1164 if (fdcresult(fdc) != 7 || (st1 & 0x37) != 0) { 1165 /* 1166 * As the damn chip doesn't seem to have a FIFO, 1167 * accept a few overruns as a fact of life *sigh* 1168 */ 1169 if ((st1 & 0x10) && (++fdc->sc_overruns < 4)) { 1170 fdc->sc_state = DOSEEK; 1171 goto loop; 1172 } 1173 #ifdef FD_DEBUG 1174 fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ? 1175 "read failed" : "write failed"); 1176 printf("blkno %qd nblks %d\n", 1177 fd->sc_blkno, fd->sc_nblks); 1178 #endif 1179 fdcretry(fdc); 1180 goto loop; 1181 } 1182 if (fdc->sc_errors) { 1183 diskerr(bp, "fd", "soft error", LOG_PRINTF, 1184 fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL); 1185 printf("\n"); 1186 fdc->sc_errors = 0; 1187 } 1188 fdc->sc_overruns = 0; 1189 fd->sc_blkno += fd->sc_nblks; 1190 fd->sc_skip += fd->sc_nbytes; 1191 fd->sc_bcount -= fd->sc_nbytes; 1192 if (!finfo && fd->sc_bcount > 0) { 1193 bp->b_cylinder = fd->sc_blkno / fd->sc_type->seccyl; 1194 goto doseek; 1195 } 1196 fdfinish(fd, bp); 1197 goto loop; 1198 1199 case DORESET: 1200 /* try a reset, keep motor on */ 1201 fd_set_motor(fdc, 1); 1202 delay(100); 1203 fd_set_motor(fdc, 0); 1204 fdc->sc_state = RESETCOMPLETE; 1205 callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc); 1206 return 1; /* will return later */ 1207 1208 case RESETCOMPLETE: 1209 callout_stop(&fdc->sc_timo_ch); 1210 /* clear the controller output buffer */ 1211 for (i = 0; i < 4; i++) { 1212 out_fdc(NE7CMD_SENSEI); 1213 (void) fdcresult(fdc); 1214 } 1215 1216 /* fall through */ 1217 case DORECAL: 1218 fdc_ienable(); 1219 1220 out_fdc(NE7CMD_RECAL); /* recalibrate function */ 1221 out_fdc(fd->sc_drive); 1222 fdc->sc_state = RECALWAIT; 1223 callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc); 1224 return 1; /* will return later */ 1225 1226 case RECALWAIT: 1227 callout_stop(&fdc->sc_timo_ch); 1228 fdc->sc_state = RECALCOMPLETE; 1229 /* allow 1/30 second for heads to settle */ 1230 callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc); 1231 return 1; /* will return later */ 1232 1233 case RECALCOMPLETE: 1234 out_fdc(NE7CMD_SENSEI); 1235 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) { 1236 #ifdef FD_DEBUG 1237 fdcstatus(&fd->sc_dev, 2, "recalibrate failed"); 1238 #endif 1239 fdcretry(fdc); 1240 goto loop; 1241 } 1242 fd->sc_cylin = 0; 1243 goto doseek; 1244 1245 case MOTORWAIT: 1246 if (fd->sc_flags & FD_MOTOR_WAIT) 1247 return 1; /* time's not up yet */ 1248 goto doseek; 1249 1250 default: 1251 fdcstatus(&fd->sc_dev, 0, "stray interrupt"); 1252 return 1; 1253 } 1254 #ifdef DIAGNOSTIC 1255 panic("fdcintr: impossible"); 1256 #endif 1257 #undef st0 1258 #undef st1 1259 #undef cyl 1260 } 1261 1262 void 1263 fdcretry(fdc) 1264 struct fdc_softc *fdc; 1265 { 1266 struct fd_softc *fd; 1267 struct buf *bp; 1268 1269 fd = fdc->sc_drives.tqh_first; 1270 bp = BUFQ_PEEK(fd->sc_q); 1271 1272 if (fd->sc_opts & FDOPT_NORETRY) 1273 goto fail; 1274 1275 switch (fdc->sc_errors) { 1276 case 0: 1277 /* try again */ 1278 fdc->sc_state = DOSEEK; 1279 break; 1280 1281 case 1: case 2: case 3: 1282 /* didn't work; try recalibrating */ 1283 fdc->sc_state = DORECAL; 1284 break; 1285 1286 case 4: 1287 /* still no go; reset the bastard */ 1288 fdc->sc_state = DORESET; 1289 break; 1290 1291 default: 1292 fail: 1293 if ((fd->sc_opts & FDOPT_SILENT) == 0) { 1294 diskerr(bp, "fd", "hard error", LOG_PRINTF, 1295 fd->sc_skip / FDC_BSIZE, 1296 (struct disklabel *)NULL); 1297 fdcpstatus(fdc); 1298 } 1299 bp->b_error = EIO; 1300 fdfinish(fd, bp); 1301 } 1302 fdc->sc_errors++; 1303 } 1304 1305 int 1306 fdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) 1307 { 1308 struct fd_softc *fd; 1309 struct disklabel buffer; 1310 int error; 1311 struct fdformat_parms *form_parms; 1312 struct fdformat_cmd *form_cmd; 1313 struct ne7_fd_formb *fd_formb; 1314 unsigned int scratch; 1315 int il[FD_MAX_NSEC + 1]; 1316 register int i, j; 1317 1318 fd = device_lookup_private(&hdfd_cd, FDUNIT(dev)); 1319 1320 switch (cmd) { 1321 case DIOCGDINFO: 1322 fdgetdisklabel(fd, dev); 1323 *(struct disklabel *)addr = *(fd->sc_dk.dk_label); 1324 return 0; 1325 1326 case DIOCGPART: 1327 fdgetdisklabel(fd, dev); 1328 ((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label; 1329 ((struct partinfo *)addr)->part = 1330 &fd->sc_dk.dk_label->d_partitions[RAW_PART]; 1331 return(0); 1332 1333 case DIOCWLABEL: 1334 if ((flag & FWRITE) == 0) 1335 return EBADF; 1336 /* XXX do something */ 1337 return 0; 1338 1339 case DIOCSDINFO: 1340 case DIOCWDINFO: 1341 if ((flag & FWRITE) == 0) 1342 return EBADF; 1343 1344 fd->sc_flags &= ~FD_HAVELAB; /* Invalid */ 1345 error = setdisklabel(&buffer, (struct disklabel *)addr, 0,NULL); 1346 if (error) 1347 return error; 1348 1349 if (cmd == DIOCWDINFO) 1350 error = writedisklabel(dev, fdstrategy, &buffer, NULL); 1351 return error; 1352 1353 case FDIOCGETFORMAT: 1354 form_parms = (struct fdformat_parms *)addr; 1355 form_parms->fdformat_version = FDFORMAT_VERSION; 1356 form_parms->nbps = 128 * (1 << fd->sc_type->secsize); 1357 form_parms->ncyl = fd->sc_type->tracks; 1358 form_parms->nspt = fd->sc_type->sectrac; 1359 form_parms->ntrk = fd->sc_type->heads; 1360 form_parms->stepspercyl = fd->sc_type->step; 1361 form_parms->gaplen = fd->sc_type->gap2; 1362 form_parms->fillbyte = fd->sc_type->fillbyte; 1363 form_parms->interleave = fd->sc_type->interleave; 1364 switch (fd->sc_type->rate) { 1365 case FDC_500KBPS: 1366 form_parms->xfer_rate = 500 * 1024; 1367 break; 1368 case FDC_300KBPS: 1369 form_parms->xfer_rate = 300 * 1024; 1370 break; 1371 case FDC_250KBPS: 1372 form_parms->xfer_rate = 250 * 1024; 1373 break; 1374 case FDC_125KBPS: 1375 form_parms->xfer_rate = 125 * 1024; 1376 break; 1377 default: 1378 return EINVAL; 1379 } 1380 return 0; 1381 1382 case FDIOCSETFORMAT: 1383 if((flag & FWRITE) == 0) 1384 return EBADF; /* must be opened for writing */ 1385 form_parms = (struct fdformat_parms *)addr; 1386 if (form_parms->fdformat_version != FDFORMAT_VERSION) 1387 return EINVAL; /* wrong version of formatting prog */ 1388 1389 scratch = form_parms->nbps >> 7; 1390 if ((form_parms->nbps & 0x7f) || ffs(scratch) == 0 || 1391 scratch & ~(1 << (ffs(scratch)-1))) 1392 /* not a power-of-two multiple of 128 */ 1393 return EINVAL; 1394 1395 switch (form_parms->xfer_rate) { 1396 case 500 * 1024: 1397 fd->sc_type->rate = FDC_500KBPS; 1398 break; 1399 case 300 * 1024: 1400 fd->sc_type->rate = FDC_300KBPS; 1401 break; 1402 case 250 * 1024: 1403 fd->sc_type->rate = FDC_250KBPS; 1404 break; 1405 case 125 * 1024: 1406 fd->sc_type->rate = FDC_125KBPS; 1407 break; 1408 default: 1409 return EINVAL; 1410 } 1411 1412 if (form_parms->nspt > FD_MAX_NSEC || 1413 form_parms->fillbyte > 0xff || 1414 form_parms->interleave > 0xff) 1415 return EINVAL; 1416 fd->sc_type->sectrac = form_parms->nspt; 1417 if (form_parms->ntrk != 2 && form_parms->ntrk != 1) 1418 return EINVAL; 1419 fd->sc_type->heads = form_parms->ntrk; 1420 fd->sc_type->seccyl = form_parms->nspt * form_parms->ntrk; 1421 fd->sc_type->secsize = ffs(scratch)-1; 1422 fd->sc_type->gap2 = form_parms->gaplen; 1423 fd->sc_type->tracks = form_parms->ncyl; 1424 fd->sc_type->size = fd->sc_type->seccyl * form_parms->ncyl * 1425 form_parms->nbps / DEV_BSIZE; 1426 fd->sc_type->step = form_parms->stepspercyl; 1427 fd->sc_type->fillbyte = form_parms->fillbyte; 1428 fd->sc_type->interleave = form_parms->interleave; 1429 return 0; 1430 1431 case FDIOCFORMAT_TRACK: 1432 if((flag & FWRITE) == 0) 1433 return EBADF; /* must be opened for writing */ 1434 form_cmd = (struct fdformat_cmd *)addr; 1435 if (form_cmd->formatcmd_version != FDFORMAT_VERSION) 1436 return EINVAL; /* wrong version of formatting prog */ 1437 1438 if (form_cmd->head >= fd->sc_type->heads || 1439 form_cmd->cylinder >= fd->sc_type->tracks) { 1440 return EINVAL; 1441 } 1442 1443 fd_formb = malloc(sizeof(struct ne7_fd_formb), 1444 M_TEMP, M_NOWAIT); 1445 if (fd_formb == 0) 1446 return ENOMEM; 1447 1448 fd_formb->head = form_cmd->head; 1449 fd_formb->cyl = form_cmd->cylinder; 1450 fd_formb->transfer_rate = fd->sc_type->rate; 1451 fd_formb->fd_formb_secshift = fd->sc_type->secsize; 1452 fd_formb->fd_formb_nsecs = fd->sc_type->sectrac; 1453 fd_formb->fd_formb_gaplen = fd->sc_type->gap2; 1454 fd_formb->fd_formb_fillbyte = fd->sc_type->fillbyte; 1455 1456 bzero(il,sizeof il); 1457 for (j = 0, i = 1; i <= fd_formb->fd_formb_nsecs; i++) { 1458 while (il[(j%fd_formb->fd_formb_nsecs)+1]) 1459 j++; 1460 il[(j%fd_formb->fd_formb_nsecs)+1] = i; 1461 j += fd->sc_type->interleave; 1462 } 1463 for (i = 0; i < fd_formb->fd_formb_nsecs; i++) { 1464 fd_formb->fd_formb_cylno(i) = form_cmd->cylinder; 1465 fd_formb->fd_formb_headno(i) = form_cmd->head; 1466 fd_formb->fd_formb_secno(i) = il[i+1]; 1467 fd_formb->fd_formb_secsize(i) = fd->sc_type->secsize; 1468 } 1469 1470 error = fdformat(dev, fd_formb, l->l_proc); 1471 free(fd_formb, M_TEMP); 1472 return error; 1473 1474 case FDIOCGETOPTS: /* get drive options */ 1475 *(int *)addr = fd->sc_opts; 1476 return 0; 1477 1478 case FDIOCSETOPTS: /* set drive options */ 1479 fd->sc_opts = *(int *)addr; 1480 return 0; 1481 1482 1483 default: 1484 return ENOTTY; 1485 } 1486 1487 #ifdef DIAGNOSTIC 1488 panic("fdioctl: impossible"); 1489 #endif 1490 } 1491 1492 int 1493 fdformat(dev_t dev, struct ne7_fd_formb *finfo, struct proc *p) 1494 { 1495 int rv = 0; 1496 struct fd_softc *fd = device_lookup_private(&hdfd_cd, FDUNIT(dev)); 1497 struct fd_type *type = fd->sc_type; 1498 struct buf *bp; 1499 1500 /* set up a buffer header for fdstrategy() */ 1501 bp = getiobuf(NULL, false); 1502 if(bp == 0) 1503 return ENOBUFS; 1504 bzero((void *)bp, sizeof(struct buf)); 1505 bp->b_flags = B_PHYS | B_FORMAT; 1506 bp->b_cflags |= BC_BUSY; 1507 bp->b_proc = p; 1508 bp->b_dev = dev; 1509 1510 /* 1511 * calculate a fake blkno, so fdstrategy() would initiate a 1512 * seek to the requested cylinder 1513 */ 1514 bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads) 1515 + finfo->head * type->sectrac) * FDC_BSIZE / DEV_BSIZE; 1516 1517 bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs; 1518 bp->b_data = (void *)finfo; 1519 1520 #ifdef DEBUG 1521 printf("fdformat: blkno %x count %lx\n", bp->b_blkno, bp->b_bcount); 1522 #endif 1523 1524 /* now do the format */ 1525 fdstrategy(bp); 1526 1527 /* ...and wait for it to complete */ 1528 mutex_enter(bp->b_objlock); 1529 while(!(bp->b_oflags & BO_DONE)) { 1530 rv = cv_timedwait(&bp->b_done, bp->b_objlock, 20 * hz); 1531 if (rv == EWOULDBLOCK) 1532 break; 1533 } 1534 mutex_exit(bp->b_objlock); 1535 1536 if (rv == EWOULDBLOCK) { 1537 /* timed out */ 1538 rv = EIO; 1539 biodone(bp); 1540 } else if (bp->b_error != 0) { 1541 rv = bp->b_error; 1542 } 1543 putiobuf(bp); 1544 return rv; 1545 } 1546 1547 1548 /* 1549 * Obtain a disklabel. Either a real one from the disk or, if there 1550 * is none, a fake one. 1551 */ 1552 static void 1553 fdgetdisklabel(fd, dev) 1554 struct fd_softc *fd; 1555 dev_t dev; 1556 { 1557 struct disklabel *lp; 1558 struct cpu_disklabel cpulab; 1559 1560 if (fd->sc_flags & FD_HAVELAB) 1561 return; /* Already got one */ 1562 1563 lp = fd->sc_dk.dk_label; 1564 1565 bzero(lp, sizeof(*lp)); 1566 bzero(&cpulab, sizeof(cpulab)); 1567 1568 lp->d_secpercyl = fd->sc_type->seccyl; 1569 lp->d_type = DTYPE_FLOPPY; 1570 lp->d_secsize = FDC_BSIZE; 1571 lp->d_secperunit = fd->sc_type->size; 1572 1573 /* 1574 * If there is no label on the disk: fake one 1575 */ 1576 if (readdisklabel(dev, fdstrategy, lp, &cpulab) != NULL) 1577 fdgetdefaultlabel(fd, lp, RAW_PART); 1578 fd->sc_flags |= FD_HAVELAB; 1579 1580 if ((FDC_BSIZE * fd->sc_type->size) 1581 < (lp->d_secsize * lp->d_secperunit)) { 1582 /* 1583 * XXX: Ignore these fields. If you drop a vnddisk 1584 * on more than one floppy, you'll get disturbing 1585 * sounds! 1586 */ 1587 lp->d_secpercyl = fd->sc_type->seccyl; 1588 lp->d_type = DTYPE_FLOPPY; 1589 lp->d_secsize = FDC_BSIZE; 1590 lp->d_secperunit = fd->sc_type->size; 1591 } 1592 } 1593 1594 /* 1595 * Build defaultdisk label. For now we only create a label from what we 1596 * know from 'sc'. 1597 */ 1598 static void 1599 fdgetdefaultlabel(fd, lp, part) 1600 struct fd_softc *fd; 1601 struct disklabel *lp; 1602 int part; 1603 { 1604 bzero(lp, sizeof(struct disklabel)); 1605 1606 lp->d_secsize = 128 * (1 << fd->sc_type->secsize); 1607 lp->d_ntracks = fd->sc_type->heads; 1608 lp->d_nsectors = fd->sc_type->sectrac; 1609 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 1610 lp->d_ncylinders = fd->sc_type->size / lp->d_secpercyl; 1611 lp->d_secperunit = fd->sc_type->size; 1612 1613 lp->d_type = DTYPE_FLOPPY; 1614 lp->d_rpm = 300; /* good guess I suppose. */ 1615 lp->d_interleave = 1; /* FIXME: is this OK? */ 1616 lp->d_bbsize = 0; 1617 lp->d_sbsize = 0; 1618 lp->d_npartitions = part + 1; 1619 lp->d_trkseek = 6000; /* Who cares... */ 1620 lp->d_magic = DISKMAGIC; 1621 lp->d_magic2 = DISKMAGIC; 1622 lp->d_checksum = dkcksum(lp); 1623 lp->d_partitions[part].p_size = lp->d_secperunit; 1624 lp->d_partitions[part].p_fstype = FS_UNUSED; 1625 lp->d_partitions[part].p_fsize = 1024; 1626 lp->d_partitions[part].p_frag = 8; 1627 } 1628