1 /* $NetBSD: hdfd.c,v 1.62 2008/06/13 08:50:12 cegger Exp $ */ 2 3 /*- 4 * Copyright (c) 1996 Leo Weppelman 5 * Copyright (c) 1990 The Regents of the University of California. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Don Ahn. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * @(#)fd.c 7.4 (Berkeley) 5/25/91 36 */ 37 38 /*- 39 * Copyright (c) 1993, 1994, 1995, 1996 40 * Charles M. Hannum. All rights reserved. 41 * 42 * This code is derived from software contributed to Berkeley by 43 * Don Ahn. 44 * 45 * Redistribution and use in source and binary forms, with or without 46 * modification, are permitted provided that the following conditions 47 * are met: 48 * 1. Redistributions of source code must retain the above copyright 49 * notice, this list of conditions and the following disclaimer. 50 * 2. Redistributions in binary form must reproduce the above copyright 51 * notice, this list of conditions and the following disclaimer in the 52 * documentation and/or other materials provided with the distribution. 53 * 3. All advertising materials mentioning features or use of this software 54 * must display the following acknowledgement: 55 * This product includes software developed by the University of 56 * California, Berkeley and its contributors. 57 * 4. Neither the name of the University nor the names of its contributors 58 * may be used to endorse or promote products derived from this software 59 * without specific prior written permission. 60 * 61 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 62 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 63 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 64 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 65 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 66 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 67 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 68 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 69 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 70 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 71 * SUCH DAMAGE. 72 * 73 * @(#)fd.c 7.4 (Berkeley) 5/25/91 74 */ 75 76 /* 77 * Floppy formatting facilities merged from FreeBSD fd.c driver: 78 * Id: fd.c,v 1.53 1995/03/12 22:40:56 joerg Exp 79 * which carries the same copyright/redistribution notice as shown above with 80 * the addition of the following statement before the "Redistribution and 81 * use ..." clause: 82 * 83 * Copyright (c) 1993, 1994 by 84 * jc@irbs.UUCP (John Capo) 85 * vak@zebub.msk.su (Serge Vakulenko) 86 * ache@astral.msk.su (Andrew A. Chernov) 87 * 88 * Copyright (c) 1993, 1994, 1995 by 89 * joerg_wunsch@uriah.sax.de (Joerg Wunsch) 90 * dufault@hda.com (Peter Dufault) 91 */ 92 93 #include <sys/cdefs.h> 94 __KERNEL_RCSID(0, "$NetBSD: hdfd.c,v 1.62 2008/06/13 08:50:12 cegger Exp $"); 95 96 #include "opt_ddb.h" 97 98 #include <sys/param.h> 99 #include <sys/systm.h> 100 #include <sys/callout.h> 101 #include <sys/kernel.h> 102 #include <sys/file.h> 103 #include <sys/ioctl.h> 104 #include <sys/device.h> 105 #include <sys/disklabel.h> 106 #include <sys/disk.h> 107 #include <sys/buf.h> 108 #include <sys/bufq.h> 109 #include <sys/malloc.h> 110 #include <sys/uio.h> 111 #include <sys/syslog.h> 112 #include <sys/queue.h> 113 #include <sys/proc.h> 114 #include <sys/fdio.h> 115 #include <sys/conf.h> 116 117 #include <uvm/uvm_extern.h> 118 119 #include <machine/cpu.h> 120 #include <machine/bus.h> 121 #include <machine/iomap.h> 122 #include <machine/mfp.h> 123 124 #include <atari/dev/hdfdreg.h> 125 #include <atari/atari/intr.h> 126 #include <atari/atari/device.h> 127 128 #include "locators.h" 129 130 /* 131 * {b,c}devsw[] function prototypes 132 */ 133 dev_type_open(fdopen); 134 dev_type_close(fdclose); 135 dev_type_read(fdread); 136 dev_type_write(fdwrite); 137 dev_type_ioctl(fdioctl); 138 dev_type_strategy(fdstrategy); 139 140 volatile u_char *fdio_addr; 141 142 #define wrt_fdc_reg(reg, val) { fdio_addr[reg] = val; } 143 #define rd_fdc_reg(reg) ( fdio_addr[reg] ) 144 145 #define fdc_ienable() MFP2->mf_ierb |= IB_DCHG; 146 147 /* 148 * Interface to the pseudo-DMA handler 149 */ 150 void fddma_intr(void); 151 void * fddmaaddr = NULL; 152 int fddmalen = 0; 153 154 extern void mfp_hdfd_nf __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 void 875 fdcstatus(dv, n, s) 876 struct device *dv; 877 int n; 878 const char *s; 879 { 880 struct fdc_softc *fdc = (void *) device_parent(dv); 881 char bits[64]; 882 883 if (n == 0) { 884 out_fdc(NE7CMD_SENSEI); 885 (void) fdcresult(fdc); 886 n = 2; 887 } 888 889 printf("%s: %s", dv->dv_xname, s); 890 891 switch (n) { 892 case 0: 893 printf("\n"); 894 break; 895 case 2: 896 printf(" (st0 %s cyl %d)\n", 897 bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS, 898 bits, sizeof(bits)), fdc->sc_status[1]); 899 break; 900 case 7: 901 printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0], 902 NE7_ST0BITS, bits, sizeof(bits))); 903 printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1], 904 NE7_ST1BITS, bits, sizeof(bits))); 905 printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2], 906 NE7_ST2BITS, bits, sizeof(bits))); 907 printf(" cyl %d head %d sec %d)\n", 908 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]); 909 break; 910 #ifdef DIAGNOSTIC 911 default: 912 printf("\nfdcstatus: weird size"); 913 break; 914 #endif 915 } 916 } 917 918 void 919 fdctimeout(arg) 920 void *arg; 921 { 922 struct fdc_softc *fdc = arg; 923 struct fd_softc *fd = fdc->sc_drives.tqh_first; 924 int s; 925 926 s = splbio(); 927 fdcstatus(&fd->sc_dev, 0, "timeout"); 928 929 if (BUFQ_PEEK(fd->sc_q) != NULL) 930 fdc->sc_state++; 931 else 932 fdc->sc_state = DEVIDLE; 933 934 (void) fdcintr(fdc); 935 splx(s); 936 } 937 938 void 939 fdcpseudointr(arg) 940 void *arg; 941 { 942 int s; 943 944 /* Just ensure it has the right spl. */ 945 s = splbio(); 946 (void) fdcintr(arg); 947 splx(s); 948 } 949 950 int 951 fdcintr(arg) 952 void *arg; 953 { 954 struct fdc_softc *fdc = arg; 955 #define st0 fdc->sc_status[0] 956 #define st1 fdc->sc_status[1] 957 #define cyl fdc->sc_status[1] 958 959 struct fd_softc *fd; 960 struct buf *bp; 961 int read, head, sec, i, nblks; 962 struct fd_type *type; 963 struct ne7_fd_formb *finfo = NULL; 964 965 loop: 966 /* Is there a drive for the controller to do a transfer with? */ 967 fd = fdc->sc_drives.tqh_first; 968 if (fd == NULL) { 969 fdc->sc_state = DEVIDLE; 970 return 1; 971 } 972 973 /* Is there a transfer to this drive? If not, deactivate drive. */ 974 bp = BUFQ_PEEK(fd->sc_q); 975 if (bp == NULL) { 976 fd->sc_ops = 0; 977 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); 978 fd->sc_active = 0; 979 goto loop; 980 } 981 982 if (bp->b_flags & B_FORMAT) 983 finfo = (struct ne7_fd_formb *)bp->b_data; 984 985 switch (fdc->sc_state) { 986 case DEVIDLE: 987 fdc->sc_errors = 0; 988 fdc->sc_overruns = 0; 989 fd->sc_skip = 0; 990 fd->sc_bcount = bp->b_bcount; 991 fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE); 992 callout_stop(&fd->sc_motoroff_ch); 993 if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) { 994 fdc->sc_state = MOTORWAIT; 995 return 1; 996 } 997 if ((fd->sc_flags & FD_MOTOR) == 0) { 998 /* Turn on the motor, being careful about pairing. */ 999 struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1]; 1000 if (ofd && ofd->sc_flags & FD_MOTOR) { 1001 callout_stop(&ofd->sc_motoroff_ch); 1002 ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); 1003 } 1004 fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT; 1005 fd_set_motor(fdc, 0); 1006 fdc->sc_state = MOTORWAIT; 1007 /* Allow .25s for motor to stabilize. */ 1008 callout_reset(&fd->sc_motoron_ch, hz / 4, 1009 fd_motor_on, fd); 1010 return 1; 1011 } 1012 /* Make sure the right drive is selected. */ 1013 fd_set_motor(fdc, 0); 1014 1015 /* fall through */ 1016 case DOSEEK: 1017 doseek: 1018 if (fd->sc_cylin == bp->b_cylinder) 1019 goto doio; 1020 1021 out_fdc(NE7CMD_SPECIFY);/* specify command */ 1022 out_fdc(fd->sc_type->steprate); 1023 out_fdc(0x7); /* XXX head load time == 6ms - non-DMA */ 1024 1025 fdc_ienable(); 1026 1027 out_fdc(NE7CMD_SEEK); /* seek function */ 1028 out_fdc(fd->sc_drive); /* drive number */ 1029 out_fdc(bp->b_cylinder * fd->sc_type->step); 1030 1031 fd->sc_cylin = -1; 1032 fdc->sc_state = SEEKWAIT; 1033 1034 iostat_seek(fd->sc_dk.dk_stats); 1035 disk_busy(&fd->sc_dk); 1036 1037 callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc); 1038 return 1; 1039 1040 case DOIO: 1041 doio: 1042 if (finfo) 1043 fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) - 1044 (char *)finfo; 1045 1046 type = fd->sc_type; 1047 sec = fd->sc_blkno % type->seccyl; 1048 head = sec / type->sectrac; 1049 sec -= head * type->sectrac; 1050 nblks = type->sectrac - sec; 1051 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE); 1052 nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE); 1053 fd->sc_nblks = nblks; 1054 fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE; 1055 #ifdef DIAGNOSTIC 1056 { 1057 int block; 1058 1059 block = (fd->sc_cylin * type->heads + head) 1060 * type->sectrac + sec; 1061 if (block != fd->sc_blkno) { 1062 printf("fdcintr: block %d != blkno %qd\n", 1063 block, fd->sc_blkno); 1064 #ifdef DDB 1065 Debugger(); 1066 #endif 1067 } 1068 } 1069 #endif 1070 read = bp->b_flags & B_READ ? 1 : 0; 1071 1072 /* 1073 * Setup pseudo-DMA address & count 1074 */ 1075 fddmaaddr = (char *)bp->b_data + fd->sc_skip; 1076 fddmalen = fd->sc_nbytes; 1077 1078 wrt_fdc_reg(fdctl, type->rate); 1079 #ifdef FD_DEBUG 1080 printf("fdcintr: %s drive %d track %d head %d sec %d" 1081 " nblks %d\n", read ? "read" : "write", 1082 fd->sc_drive, fd->sc_cylin, head, sec, nblks); 1083 #endif 1084 fdc_ienable(); 1085 1086 if (finfo) { 1087 /* formatting */ 1088 if (out_fdc(NE7CMD_FORMAT) < 0) { 1089 fdc->sc_errors = 4; 1090 fdcretry(fdc); 1091 goto loop; 1092 } 1093 out_fdc((head << 2) | fd->sc_drive); 1094 out_fdc(finfo->fd_formb_secshift); 1095 out_fdc(finfo->fd_formb_nsecs); 1096 out_fdc(finfo->fd_formb_gaplen); 1097 out_fdc(finfo->fd_formb_fillbyte); 1098 } else { 1099 if (read) 1100 out_fdc(NE7CMD_READ); /* READ */ 1101 else 1102 out_fdc(NE7CMD_WRITE); /* WRITE */ 1103 out_fdc((head << 2) | fd->sc_drive); 1104 out_fdc(fd->sc_cylin); /* track */ 1105 out_fdc(head); /* head */ 1106 out_fdc(sec + 1); /* sector +1 */ 1107 out_fdc(type->secsize); /* sector size */ 1108 out_fdc(sec + nblks); /* last sectors */ 1109 out_fdc(type->gap1); /* gap1 size */ 1110 out_fdc(type->datalen); /* data length */ 1111 } 1112 fdc->sc_state = IOCOMPLETE; 1113 1114 disk_busy(&fd->sc_dk); 1115 1116 /* allow 2 seconds for operation */ 1117 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc); 1118 return 1; /* will return later */ 1119 1120 case SEEKWAIT: 1121 callout_stop(&fdc->sc_timo_ch); 1122 fdc->sc_state = SEEKCOMPLETE; 1123 /* allow 1/50 second for heads to settle */ 1124 callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc); 1125 return 1; 1126 1127 case SEEKCOMPLETE: 1128 /* no data on seek */ 1129 disk_unbusy(&fd->sc_dk, 0, 0); 1130 1131 /* Make sure seek really happened. */ 1132 out_fdc(NE7CMD_SENSEI); 1133 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || 1134 cyl != bp->b_cylinder * fd->sc_type->step) { 1135 #ifdef FD_DEBUG 1136 fdcstatus(&fd->sc_dev, 2, "seek failed"); 1137 #endif 1138 fdcretry(fdc); 1139 goto loop; 1140 } 1141 fd->sc_cylin = bp->b_cylinder; 1142 goto doio; 1143 1144 case IOTIMEDOUT: 1145 case SEEKTIMEDOUT: 1146 case RECALTIMEDOUT: 1147 case RESETTIMEDOUT: 1148 fdcretry(fdc); 1149 goto loop; 1150 1151 case IOCOMPLETE: /* IO DONE, post-analyze */ 1152 callout_stop(&fdc->sc_timo_ch); 1153 1154 disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid), 1155 (bp->b_flags & B_READ)); 1156 1157 if (fdcresult(fdc) != 7 || (st1 & 0x37) != 0) { 1158 /* 1159 * As the damn chip doesn't seem to have a FIFO, 1160 * accept a few overruns as a fact of life *sigh* 1161 */ 1162 if ((st1 & 0x10) && (++fdc->sc_overruns < 4)) { 1163 fdc->sc_state = DOSEEK; 1164 goto loop; 1165 } 1166 #ifdef FD_DEBUG 1167 fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ? 1168 "read failed" : "write failed"); 1169 printf("blkno %qd nblks %d\n", 1170 fd->sc_blkno, fd->sc_nblks); 1171 #endif 1172 fdcretry(fdc); 1173 goto loop; 1174 } 1175 if (fdc->sc_errors) { 1176 diskerr(bp, "fd", "soft error", LOG_PRINTF, 1177 fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL); 1178 printf("\n"); 1179 fdc->sc_errors = 0; 1180 } 1181 fdc->sc_overruns = 0; 1182 fd->sc_blkno += fd->sc_nblks; 1183 fd->sc_skip += fd->sc_nbytes; 1184 fd->sc_bcount -= fd->sc_nbytes; 1185 if (!finfo && fd->sc_bcount > 0) { 1186 bp->b_cylinder = fd->sc_blkno / fd->sc_type->seccyl; 1187 goto doseek; 1188 } 1189 fdfinish(fd, bp); 1190 goto loop; 1191 1192 case DORESET: 1193 /* try a reset, keep motor on */ 1194 fd_set_motor(fdc, 1); 1195 delay(100); 1196 fd_set_motor(fdc, 0); 1197 fdc->sc_state = RESETCOMPLETE; 1198 callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc); 1199 return 1; /* will return later */ 1200 1201 case RESETCOMPLETE: 1202 callout_stop(&fdc->sc_timo_ch); 1203 /* clear the controller output buffer */ 1204 for (i = 0; i < 4; i++) { 1205 out_fdc(NE7CMD_SENSEI); 1206 (void) fdcresult(fdc); 1207 } 1208 1209 /* fall through */ 1210 case DORECAL: 1211 fdc_ienable(); 1212 1213 out_fdc(NE7CMD_RECAL); /* recalibrate function */ 1214 out_fdc(fd->sc_drive); 1215 fdc->sc_state = RECALWAIT; 1216 callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc); 1217 return 1; /* will return later */ 1218 1219 case RECALWAIT: 1220 callout_stop(&fdc->sc_timo_ch); 1221 fdc->sc_state = RECALCOMPLETE; 1222 /* allow 1/30 second for heads to settle */ 1223 callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc); 1224 return 1; /* will return later */ 1225 1226 case RECALCOMPLETE: 1227 out_fdc(NE7CMD_SENSEI); 1228 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) { 1229 #ifdef FD_DEBUG 1230 fdcstatus(&fd->sc_dev, 2, "recalibrate failed"); 1231 #endif 1232 fdcretry(fdc); 1233 goto loop; 1234 } 1235 fd->sc_cylin = 0; 1236 goto doseek; 1237 1238 case MOTORWAIT: 1239 if (fd->sc_flags & FD_MOTOR_WAIT) 1240 return 1; /* time's not up yet */ 1241 goto doseek; 1242 1243 default: 1244 fdcstatus(&fd->sc_dev, 0, "stray interrupt"); 1245 return 1; 1246 } 1247 #ifdef DIAGNOSTIC 1248 panic("fdcintr: impossible"); 1249 #endif 1250 #undef st0 1251 #undef st1 1252 #undef cyl 1253 } 1254 1255 void 1256 fdcretry(fdc) 1257 struct fdc_softc *fdc; 1258 { 1259 char bits[64]; 1260 struct fd_softc *fd; 1261 struct buf *bp; 1262 1263 fd = fdc->sc_drives.tqh_first; 1264 bp = BUFQ_PEEK(fd->sc_q); 1265 1266 if (fd->sc_opts & FDOPT_NORETRY) 1267 goto fail; 1268 1269 switch (fdc->sc_errors) { 1270 case 0: 1271 /* try again */ 1272 fdc->sc_state = DOSEEK; 1273 break; 1274 1275 case 1: case 2: case 3: 1276 /* didn't work; try recalibrating */ 1277 fdc->sc_state = DORECAL; 1278 break; 1279 1280 case 4: 1281 /* still no go; reset the bastard */ 1282 fdc->sc_state = DORESET; 1283 break; 1284 1285 default: 1286 fail: 1287 if ((fd->sc_opts & FDOPT_SILENT) == 0) { 1288 diskerr(bp, "fd", "hard error", LOG_PRINTF, 1289 fd->sc_skip / FDC_BSIZE, 1290 (struct disklabel *)NULL); 1291 1292 printf(" (st0 %s", 1293 bitmask_snprintf(fdc->sc_status[0], 1294 NE7_ST0BITS, bits, 1295 sizeof(bits))); 1296 printf(" st1 %s", 1297 bitmask_snprintf(fdc->sc_status[1], 1298 NE7_ST1BITS, bits, 1299 sizeof(bits))); 1300 printf(" st2 %s", 1301 bitmask_snprintf(fdc->sc_status[2], 1302 NE7_ST2BITS, bits, 1303 sizeof(bits))); 1304 printf(" cyl %d head %d sec %d)\n", 1305 fdc->sc_status[3], 1306 fdc->sc_status[4], 1307 fdc->sc_status[5]); 1308 } 1309 bp->b_error = EIO; 1310 fdfinish(fd, bp); 1311 } 1312 fdc->sc_errors++; 1313 } 1314 1315 int 1316 fdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) 1317 { 1318 struct fd_softc *fd; 1319 struct disklabel buffer; 1320 int error; 1321 struct fdformat_parms *form_parms; 1322 struct fdformat_cmd *form_cmd; 1323 struct ne7_fd_formb *fd_formb; 1324 unsigned int scratch; 1325 int il[FD_MAX_NSEC + 1]; 1326 register int i, j; 1327 1328 fd = device_lookup_private(&hdfd_cd, FDUNIT(dev)); 1329 1330 switch (cmd) { 1331 case DIOCGDINFO: 1332 fdgetdisklabel(fd, dev); 1333 *(struct disklabel *)addr = *(fd->sc_dk.dk_label); 1334 return 0; 1335 1336 case DIOCGPART: 1337 fdgetdisklabel(fd, dev); 1338 ((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label; 1339 ((struct partinfo *)addr)->part = 1340 &fd->sc_dk.dk_label->d_partitions[RAW_PART]; 1341 return(0); 1342 1343 case DIOCWLABEL: 1344 if ((flag & FWRITE) == 0) 1345 return EBADF; 1346 /* XXX do something */ 1347 return 0; 1348 1349 case DIOCSDINFO: 1350 case DIOCWDINFO: 1351 if ((flag & FWRITE) == 0) 1352 return EBADF; 1353 1354 fd->sc_flags &= ~FD_HAVELAB; /* Invalid */ 1355 error = setdisklabel(&buffer, (struct disklabel *)addr, 0,NULL); 1356 if (error) 1357 return error; 1358 1359 if (cmd == DIOCWDINFO) 1360 error = writedisklabel(dev, fdstrategy, &buffer, NULL); 1361 return error; 1362 1363 case FDIOCGETFORMAT: 1364 form_parms = (struct fdformat_parms *)addr; 1365 form_parms->fdformat_version = FDFORMAT_VERSION; 1366 form_parms->nbps = 128 * (1 << fd->sc_type->secsize); 1367 form_parms->ncyl = fd->sc_type->tracks; 1368 form_parms->nspt = fd->sc_type->sectrac; 1369 form_parms->ntrk = fd->sc_type->heads; 1370 form_parms->stepspercyl = fd->sc_type->step; 1371 form_parms->gaplen = fd->sc_type->gap2; 1372 form_parms->fillbyte = fd->sc_type->fillbyte; 1373 form_parms->interleave = fd->sc_type->interleave; 1374 switch (fd->sc_type->rate) { 1375 case FDC_500KBPS: 1376 form_parms->xfer_rate = 500 * 1024; 1377 break; 1378 case FDC_300KBPS: 1379 form_parms->xfer_rate = 300 * 1024; 1380 break; 1381 case FDC_250KBPS: 1382 form_parms->xfer_rate = 250 * 1024; 1383 break; 1384 case FDC_125KBPS: 1385 form_parms->xfer_rate = 125 * 1024; 1386 break; 1387 default: 1388 return EINVAL; 1389 } 1390 return 0; 1391 1392 case FDIOCSETFORMAT: 1393 if((flag & FWRITE) == 0) 1394 return EBADF; /* must be opened for writing */ 1395 form_parms = (struct fdformat_parms *)addr; 1396 if (form_parms->fdformat_version != FDFORMAT_VERSION) 1397 return EINVAL; /* wrong version of formatting prog */ 1398 1399 scratch = form_parms->nbps >> 7; 1400 if ((form_parms->nbps & 0x7f) || ffs(scratch) == 0 || 1401 scratch & ~(1 << (ffs(scratch)-1))) 1402 /* not a power-of-two multiple of 128 */ 1403 return EINVAL; 1404 1405 switch (form_parms->xfer_rate) { 1406 case 500 * 1024: 1407 fd->sc_type->rate = FDC_500KBPS; 1408 break; 1409 case 300 * 1024: 1410 fd->sc_type->rate = FDC_300KBPS; 1411 break; 1412 case 250 * 1024: 1413 fd->sc_type->rate = FDC_250KBPS; 1414 break; 1415 case 125 * 1024: 1416 fd->sc_type->rate = FDC_125KBPS; 1417 break; 1418 default: 1419 return EINVAL; 1420 } 1421 1422 if (form_parms->nspt > FD_MAX_NSEC || 1423 form_parms->fillbyte > 0xff || 1424 form_parms->interleave > 0xff) 1425 return EINVAL; 1426 fd->sc_type->sectrac = form_parms->nspt; 1427 if (form_parms->ntrk != 2 && form_parms->ntrk != 1) 1428 return EINVAL; 1429 fd->sc_type->heads = form_parms->ntrk; 1430 fd->sc_type->seccyl = form_parms->nspt * form_parms->ntrk; 1431 fd->sc_type->secsize = ffs(scratch)-1; 1432 fd->sc_type->gap2 = form_parms->gaplen; 1433 fd->sc_type->tracks = form_parms->ncyl; 1434 fd->sc_type->size = fd->sc_type->seccyl * form_parms->ncyl * 1435 form_parms->nbps / DEV_BSIZE; 1436 fd->sc_type->step = form_parms->stepspercyl; 1437 fd->sc_type->fillbyte = form_parms->fillbyte; 1438 fd->sc_type->interleave = form_parms->interleave; 1439 return 0; 1440 1441 case FDIOCFORMAT_TRACK: 1442 if((flag & FWRITE) == 0) 1443 return EBADF; /* must be opened for writing */ 1444 form_cmd = (struct fdformat_cmd *)addr; 1445 if (form_cmd->formatcmd_version != FDFORMAT_VERSION) 1446 return EINVAL; /* wrong version of formatting prog */ 1447 1448 if (form_cmd->head >= fd->sc_type->heads || 1449 form_cmd->cylinder >= fd->sc_type->tracks) { 1450 return EINVAL; 1451 } 1452 1453 fd_formb = malloc(sizeof(struct ne7_fd_formb), 1454 M_TEMP, M_NOWAIT); 1455 if (fd_formb == 0) 1456 return ENOMEM; 1457 1458 fd_formb->head = form_cmd->head; 1459 fd_formb->cyl = form_cmd->cylinder; 1460 fd_formb->transfer_rate = fd->sc_type->rate; 1461 fd_formb->fd_formb_secshift = fd->sc_type->secsize; 1462 fd_formb->fd_formb_nsecs = fd->sc_type->sectrac; 1463 fd_formb->fd_formb_gaplen = fd->sc_type->gap2; 1464 fd_formb->fd_formb_fillbyte = fd->sc_type->fillbyte; 1465 1466 bzero(il,sizeof il); 1467 for (j = 0, i = 1; i <= fd_formb->fd_formb_nsecs; i++) { 1468 while (il[(j%fd_formb->fd_formb_nsecs)+1]) 1469 j++; 1470 il[(j%fd_formb->fd_formb_nsecs)+1] = i; 1471 j += fd->sc_type->interleave; 1472 } 1473 for (i = 0; i < fd_formb->fd_formb_nsecs; i++) { 1474 fd_formb->fd_formb_cylno(i) = form_cmd->cylinder; 1475 fd_formb->fd_formb_headno(i) = form_cmd->head; 1476 fd_formb->fd_formb_secno(i) = il[i+1]; 1477 fd_formb->fd_formb_secsize(i) = fd->sc_type->secsize; 1478 } 1479 1480 error = fdformat(dev, fd_formb, l->l_proc); 1481 free(fd_formb, M_TEMP); 1482 return error; 1483 1484 case FDIOCGETOPTS: /* get drive options */ 1485 *(int *)addr = fd->sc_opts; 1486 return 0; 1487 1488 case FDIOCSETOPTS: /* set drive options */ 1489 fd->sc_opts = *(int *)addr; 1490 return 0; 1491 1492 1493 default: 1494 return ENOTTY; 1495 } 1496 1497 #ifdef DIAGNOSTIC 1498 panic("fdioctl: impossible"); 1499 #endif 1500 } 1501 1502 int 1503 fdformat(dev_t dev, struct ne7_fd_formb *finfo, struct proc *p) 1504 { 1505 int rv = 0; 1506 struct fd_softc *fd = device_lookup_private(&hdfd_cd, FDUNIT(dev)); 1507 struct fd_type *type = fd->sc_type; 1508 struct buf *bp; 1509 1510 /* set up a buffer header for fdstrategy() */ 1511 bp = getiobuf(NULL, false); 1512 if(bp == 0) 1513 return ENOBUFS; 1514 bzero((void *)bp, sizeof(struct buf)); 1515 bp->b_flags = B_PHYS | B_FORMAT; 1516 bp->b_cflags |= BC_BUSY; 1517 bp->b_proc = p; 1518 bp->b_dev = dev; 1519 1520 /* 1521 * calculate a fake blkno, so fdstrategy() would initiate a 1522 * seek to the requested cylinder 1523 */ 1524 bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads) 1525 + finfo->head * type->sectrac) * FDC_BSIZE / DEV_BSIZE; 1526 1527 bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs; 1528 bp->b_data = (void *)finfo; 1529 1530 #ifdef DEBUG 1531 printf("fdformat: blkno %x count %lx\n", bp->b_blkno, bp->b_bcount); 1532 #endif 1533 1534 /* now do the format */ 1535 fdstrategy(bp); 1536 1537 /* ...and wait for it to complete */ 1538 mutex_enter(bp->b_objlock); 1539 while(!(bp->b_oflags & BO_DONE)) { 1540 rv = cv_timedwait(&bp->b_done, bp->b_objlock, 20 * hz); 1541 if (rv == EWOULDBLOCK) 1542 break; 1543 } 1544 mutex_exit(bp->b_objlock); 1545 1546 if (rv == EWOULDBLOCK) { 1547 /* timed out */ 1548 rv = EIO; 1549 biodone(bp); 1550 } else if (bp->b_error != 0) { 1551 rv = bp->b_error; 1552 } 1553 putiobuf(bp); 1554 return rv; 1555 } 1556 1557 1558 /* 1559 * Obtain a disklabel. Either a real one from the disk or, if there 1560 * is none, a fake one. 1561 */ 1562 static void 1563 fdgetdisklabel(fd, dev) 1564 struct fd_softc *fd; 1565 dev_t dev; 1566 { 1567 struct disklabel *lp; 1568 struct cpu_disklabel cpulab; 1569 1570 if (fd->sc_flags & FD_HAVELAB) 1571 return; /* Already got one */ 1572 1573 lp = fd->sc_dk.dk_label; 1574 1575 bzero(lp, sizeof(*lp)); 1576 bzero(&cpulab, sizeof(cpulab)); 1577 1578 lp->d_secpercyl = fd->sc_type->seccyl; 1579 lp->d_type = DTYPE_FLOPPY; 1580 lp->d_secsize = FDC_BSIZE; 1581 lp->d_secperunit = fd->sc_type->size; 1582 1583 /* 1584 * If there is no label on the disk: fake one 1585 */ 1586 if (readdisklabel(dev, fdstrategy, lp, &cpulab) != NULL) 1587 fdgetdefaultlabel(fd, lp, RAW_PART); 1588 fd->sc_flags |= FD_HAVELAB; 1589 1590 if ((FDC_BSIZE * fd->sc_type->size) 1591 < (lp->d_secsize * lp->d_secperunit)) { 1592 /* 1593 * XXX: Ignore these fields. If you drop a vnddisk 1594 * on more than one floppy, you'll get disturbing 1595 * sounds! 1596 */ 1597 lp->d_secpercyl = fd->sc_type->seccyl; 1598 lp->d_type = DTYPE_FLOPPY; 1599 lp->d_secsize = FDC_BSIZE; 1600 lp->d_secperunit = fd->sc_type->size; 1601 } 1602 } 1603 1604 /* 1605 * Build defaultdisk label. For now we only create a label from what we 1606 * know from 'sc'. 1607 */ 1608 static void 1609 fdgetdefaultlabel(fd, lp, part) 1610 struct fd_softc *fd; 1611 struct disklabel *lp; 1612 int part; 1613 { 1614 bzero(lp, sizeof(struct disklabel)); 1615 1616 lp->d_secsize = 128 * (1 << fd->sc_type->secsize); 1617 lp->d_ntracks = fd->sc_type->heads; 1618 lp->d_nsectors = fd->sc_type->sectrac; 1619 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 1620 lp->d_ncylinders = fd->sc_type->size / lp->d_secpercyl; 1621 lp->d_secperunit = fd->sc_type->size; 1622 1623 lp->d_type = DTYPE_FLOPPY; 1624 lp->d_rpm = 300; /* good guess I suppose. */ 1625 lp->d_interleave = 1; /* FIXME: is this OK? */ 1626 lp->d_bbsize = 0; 1627 lp->d_sbsize = 0; 1628 lp->d_npartitions = part + 1; 1629 lp->d_trkseek = 6000; /* Who cares... */ 1630 lp->d_magic = DISKMAGIC; 1631 lp->d_magic2 = DISKMAGIC; 1632 lp->d_checksum = dkcksum(lp); 1633 lp->d_partitions[part].p_size = lp->d_secperunit; 1634 lp->d_partitions[part].p_fstype = FS_UNUSED; 1635 lp->d_partitions[part].p_fsize = 1024; 1636 lp->d_partitions[part].p_frag = 8; 1637 } 1638