1 /* $NetBSD: hdfd.c,v 1.59 2007/10/17 19:53:47 garbled 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.59 2007/10/17 19:53:47 garbled 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(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 done; 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 done; 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 *) device_parent(&fd->sc_dev); 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 done: 668 /* Toss transfer; we're done early. */ 669 bp->b_resid = bp->b_bcount; 670 biodone(bp); 671 } 672 673 void 674 fdstart(fd) 675 struct fd_softc *fd; 676 { 677 struct fdc_softc *fdc = (void *) device_parent(&fd->sc_dev); 678 int active = fdc->sc_drives.tqh_first != 0; 679 680 /* Link into controller queue. */ 681 fd->sc_active = 1; 682 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); 683 684 /* If controller not already active, start it. */ 685 if (!active) 686 fdcstart(fdc); 687 } 688 689 void 690 fdfinish(fd, bp) 691 struct fd_softc *fd; 692 struct buf *bp; 693 { 694 struct fdc_softc *fdc = (void *) device_parent(&fd->sc_dev); 695 696 /* 697 * Move this drive to the end of the queue to give others a `fair' 698 * chance. We only force a switch if N operations are completed while 699 * another drive is waiting to be serviced, since there is a long motor 700 * startup delay whenever we switch. 701 */ 702 (void)BUFQ_GET(fd->sc_q); 703 if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) { 704 fd->sc_ops = 0; 705 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); 706 if (BUFQ_PEEK(fd->sc_q) != NULL) 707 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); 708 else 709 fd->sc_active = 0; 710 } 711 bp->b_resid = fd->sc_bcount; 712 fd->sc_skip = 0; 713 714 biodone(bp); 715 /* turn off motor 5s from now */ 716 callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd); 717 fdc->sc_state = DEVIDLE; 718 } 719 720 int 721 fdread(dev, uio, flags) 722 dev_t dev; 723 struct uio *uio; 724 int flags; 725 { 726 return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio)); 727 } 728 729 int 730 fdwrite(dev, uio, flags) 731 dev_t dev; 732 struct uio *uio; 733 int flags; 734 { 735 return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio)); 736 } 737 738 void 739 fd_set_motor(fdc, reset) 740 struct fdc_softc *fdc; 741 int reset; 742 { 743 struct fd_softc *fd; 744 u_char status; 745 int n; 746 747 if ((fd = fdc->sc_drives.tqh_first) != NULL) 748 status = fd->sc_drive; 749 else 750 status = 0; 751 if (!reset) 752 status |= FDO_FRST | FDO_FDMAEN; 753 for (n = 0; n < 4; n++) 754 if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR)) 755 status |= FDO_MOEN(n); 756 wrt_fdc_reg(fdout, status); 757 } 758 759 void 760 fd_motor_off(arg) 761 void *arg; 762 { 763 struct fd_softc *fd = arg; 764 int s; 765 766 s = splbio(); 767 fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); 768 fd_set_motor((struct fdc_softc *) device_parent(&fd->sc_dev), 0); 769 splx(s); 770 } 771 772 void 773 fd_motor_on(arg) 774 void *arg; 775 { 776 struct fd_softc *fd = arg; 777 struct fdc_softc *fdc = (void *) device_parent(&fd->sc_dev); 778 int s; 779 780 s = splbio(); 781 fd->sc_flags &= ~FD_MOTOR_WAIT; 782 if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT)) 783 (void) fdcintr(fdc); 784 splx(s); 785 } 786 787 int 788 fdcresult(fdc) 789 struct fdc_softc *fdc; 790 { 791 u_char i; 792 int j = 100000, 793 n = 0; 794 795 for (; j; j--) { 796 i = rd_fdc_reg(fdsts) & (NE7_DIO | NE7_RQM | NE7_CB); 797 if (i == NE7_RQM) 798 return n; 799 if (i == (NE7_DIO | NE7_RQM | NE7_CB)) { 800 if (n >= sizeof(fdc->sc_status)) { 801 log(LOG_ERR, "fdcresult: overrun\n"); 802 return -1; 803 } 804 fdc->sc_status[n++] = rd_fdc_reg(fddata); 805 } 806 else delay(10); 807 } 808 log(LOG_ERR, "fdcresult: timeout\n"); 809 return -1; 810 } 811 812 int 813 out_fdc(x) 814 u_char x; 815 { 816 int i = 100000; 817 818 while (((rd_fdc_reg(fdsts) & (NE7_DIO|NE7_RQM)) != NE7_RQM) && i-- > 0) 819 delay(1); 820 if (i <= 0) 821 return -1; 822 wrt_fdc_reg(fddata, x); 823 return 0; 824 } 825 826 int 827 fdopen(dev, flags, mode, l) 828 dev_t dev; 829 int flags; 830 int mode; 831 struct lwp *l; 832 { 833 int unit; 834 struct fd_softc *fd; 835 struct fd_type *type; 836 837 unit = FDUNIT(dev); 838 if (unit >= hdfd_cd.cd_ndevs) 839 return ENXIO; 840 fd = hdfd_cd.cd_devs[unit]; 841 if (fd == 0) 842 return ENXIO; 843 type = fd_dev_to_type(fd, dev); 844 if (type == NULL) 845 return ENXIO; 846 847 if ((fd->sc_flags & FD_OPEN) != 0 && 848 fd->sc_type != type) 849 return EBUSY; 850 851 fd->sc_type = type; 852 fd->sc_cylin = -1; 853 fd->sc_flags |= FD_OPEN; 854 fdgetdisklabel(fd, dev); 855 856 return 0; 857 } 858 859 int 860 fdclose(dev, flags, mode, l) 861 dev_t dev; 862 int flags; 863 int mode; 864 struct lwp *l; 865 { 866 struct fd_softc *fd = hdfd_cd.cd_devs[FDUNIT(dev)]; 867 868 fd->sc_flags &= ~(FD_OPEN|FD_HAVELAB); 869 fd->sc_opts &= ~(FDOPT_NORETRY|FDOPT_SILENT); 870 return 0; 871 } 872 873 void 874 fdcstart(fdc) 875 struct fdc_softc *fdc; 876 { 877 878 #ifdef DIAGNOSTIC 879 /* only got here if controller's drive queue was inactive; should 880 be in idle state */ 881 if (fdc->sc_state != DEVIDLE) { 882 printf("fdcstart: not idle\n"); 883 return; 884 } 885 #endif 886 (void) fdcintr(fdc); 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 printf(" (st0 %s cyl %d)\n", 912 bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS, 913 bits, sizeof(bits)), fdc->sc_status[1]); 914 break; 915 case 7: 916 printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0], 917 NE7_ST0BITS, bits, sizeof(bits))); 918 printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1], 919 NE7_ST1BITS, bits, sizeof(bits))); 920 printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2], 921 NE7_ST2BITS, bits, sizeof(bits))); 922 printf(" cyl %d head %d sec %d)\n", 923 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]); 924 break; 925 #ifdef DIAGNOSTIC 926 default: 927 printf("\nfdcstatus: weird size"); 928 break; 929 #endif 930 } 931 } 932 933 void 934 fdctimeout(arg) 935 void *arg; 936 { 937 struct fdc_softc *fdc = arg; 938 struct fd_softc *fd = fdc->sc_drives.tqh_first; 939 int s; 940 941 s = splbio(); 942 fdcstatus(&fd->sc_dev, 0, "timeout"); 943 944 if (BUFQ_PEEK(fd->sc_q) != NULL) 945 fdc->sc_state++; 946 else 947 fdc->sc_state = DEVIDLE; 948 949 (void) fdcintr(fdc); 950 splx(s); 951 } 952 953 void 954 fdcpseudointr(arg) 955 void *arg; 956 { 957 int s; 958 959 /* Just ensure it has the right spl. */ 960 s = splbio(); 961 (void) fdcintr(arg); 962 splx(s); 963 } 964 965 int 966 fdcintr(arg) 967 void *arg; 968 { 969 struct fdc_softc *fdc = arg; 970 #define st0 fdc->sc_status[0] 971 #define st1 fdc->sc_status[1] 972 #define cyl fdc->sc_status[1] 973 974 struct fd_softc *fd; 975 struct buf *bp; 976 int read, head, sec, i, nblks; 977 struct fd_type *type; 978 struct ne7_fd_formb *finfo = NULL; 979 980 loop: 981 /* Is there a drive for the controller to do a transfer with? */ 982 fd = fdc->sc_drives.tqh_first; 983 if (fd == NULL) { 984 fdc->sc_state = DEVIDLE; 985 return 1; 986 } 987 988 /* Is there a transfer to this drive? If not, deactivate drive. */ 989 bp = BUFQ_PEEK(fd->sc_q); 990 if (bp == NULL) { 991 fd->sc_ops = 0; 992 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); 993 fd->sc_active = 0; 994 goto loop; 995 } 996 997 if (bp->b_flags & B_FORMAT) 998 finfo = (struct ne7_fd_formb *)bp->b_data; 999 1000 switch (fdc->sc_state) { 1001 case DEVIDLE: 1002 fdc->sc_errors = 0; 1003 fdc->sc_overruns = 0; 1004 fd->sc_skip = 0; 1005 fd->sc_bcount = bp->b_bcount; 1006 fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE); 1007 callout_stop(&fd->sc_motoroff_ch); 1008 if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) { 1009 fdc->sc_state = MOTORWAIT; 1010 return 1; 1011 } 1012 if ((fd->sc_flags & FD_MOTOR) == 0) { 1013 /* Turn on the motor, being careful about pairing. */ 1014 struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1]; 1015 if (ofd && ofd->sc_flags & FD_MOTOR) { 1016 callout_stop(&ofd->sc_motoroff_ch); 1017 ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); 1018 } 1019 fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT; 1020 fd_set_motor(fdc, 0); 1021 fdc->sc_state = MOTORWAIT; 1022 /* Allow .25s for motor to stabilize. */ 1023 callout_reset(&fd->sc_motoron_ch, hz / 4, 1024 fd_motor_on, fd); 1025 return 1; 1026 } 1027 /* Make sure the right drive is selected. */ 1028 fd_set_motor(fdc, 0); 1029 1030 /* fall through */ 1031 case DOSEEK: 1032 doseek: 1033 if (fd->sc_cylin == bp->b_cylinder) 1034 goto doio; 1035 1036 out_fdc(NE7CMD_SPECIFY);/* specify command */ 1037 out_fdc(fd->sc_type->steprate); 1038 out_fdc(0x7); /* XXX head load time == 6ms - non-DMA */ 1039 1040 fdc_ienable(); 1041 1042 out_fdc(NE7CMD_SEEK); /* seek function */ 1043 out_fdc(fd->sc_drive); /* drive number */ 1044 out_fdc(bp->b_cylinder * fd->sc_type->step); 1045 1046 fd->sc_cylin = -1; 1047 fdc->sc_state = SEEKWAIT; 1048 1049 iostat_seek(fd->sc_dk.dk_stats); 1050 disk_busy(&fd->sc_dk); 1051 1052 callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc); 1053 return 1; 1054 1055 case DOIO: 1056 doio: 1057 if (finfo) 1058 fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) - 1059 (char *)finfo; 1060 1061 type = fd->sc_type; 1062 sec = fd->sc_blkno % type->seccyl; 1063 head = sec / type->sectrac; 1064 sec -= head * type->sectrac; 1065 nblks = type->sectrac - sec; 1066 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE); 1067 nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE); 1068 fd->sc_nblks = nblks; 1069 fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE; 1070 #ifdef DIAGNOSTIC 1071 { 1072 int block; 1073 1074 block = (fd->sc_cylin * type->heads + head) 1075 * type->sectrac + sec; 1076 if (block != fd->sc_blkno) { 1077 printf("fdcintr: block %d != blkno %qd\n", 1078 block, fd->sc_blkno); 1079 #ifdef DDB 1080 Debugger(); 1081 #endif 1082 } 1083 } 1084 #endif 1085 read = bp->b_flags & B_READ ? 1 : 0; 1086 1087 /* 1088 * Setup pseudo-DMA address & count 1089 */ 1090 fddmaaddr = (char *)bp->b_data + fd->sc_skip; 1091 fddmalen = fd->sc_nbytes; 1092 1093 wrt_fdc_reg(fdctl, type->rate); 1094 #ifdef FD_DEBUG 1095 printf("fdcintr: %s drive %d track %d head %d sec %d" 1096 " nblks %d\n", read ? "read" : "write", 1097 fd->sc_drive, fd->sc_cylin, head, sec, nblks); 1098 #endif 1099 fdc_ienable(); 1100 1101 if (finfo) { 1102 /* formatting */ 1103 if (out_fdc(NE7CMD_FORMAT) < 0) { 1104 fdc->sc_errors = 4; 1105 fdcretry(fdc); 1106 goto loop; 1107 } 1108 out_fdc((head << 2) | fd->sc_drive); 1109 out_fdc(finfo->fd_formb_secshift); 1110 out_fdc(finfo->fd_formb_nsecs); 1111 out_fdc(finfo->fd_formb_gaplen); 1112 out_fdc(finfo->fd_formb_fillbyte); 1113 } else { 1114 if (read) 1115 out_fdc(NE7CMD_READ); /* READ */ 1116 else 1117 out_fdc(NE7CMD_WRITE); /* WRITE */ 1118 out_fdc((head << 2) | fd->sc_drive); 1119 out_fdc(fd->sc_cylin); /* track */ 1120 out_fdc(head); /* head */ 1121 out_fdc(sec + 1); /* sector +1 */ 1122 out_fdc(type->secsize); /* sector size */ 1123 out_fdc(sec + nblks); /* last sectors */ 1124 out_fdc(type->gap1); /* gap1 size */ 1125 out_fdc(type->datalen); /* data length */ 1126 } 1127 fdc->sc_state = IOCOMPLETE; 1128 1129 disk_busy(&fd->sc_dk); 1130 1131 /* allow 2 seconds for operation */ 1132 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc); 1133 return 1; /* will return later */ 1134 1135 case SEEKWAIT: 1136 callout_stop(&fdc->sc_timo_ch); 1137 fdc->sc_state = SEEKCOMPLETE; 1138 /* allow 1/50 second for heads to settle */ 1139 callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc); 1140 return 1; 1141 1142 case SEEKCOMPLETE: 1143 /* no data on seek */ 1144 disk_unbusy(&fd->sc_dk, 0, 0); 1145 1146 /* Make sure seek really happened. */ 1147 out_fdc(NE7CMD_SENSEI); 1148 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || 1149 cyl != bp->b_cylinder * fd->sc_type->step) { 1150 #ifdef FD_DEBUG 1151 fdcstatus(&fd->sc_dev, 2, "seek failed"); 1152 #endif 1153 fdcretry(fdc); 1154 goto loop; 1155 } 1156 fd->sc_cylin = bp->b_cylinder; 1157 goto doio; 1158 1159 case IOTIMEDOUT: 1160 case SEEKTIMEDOUT: 1161 case RECALTIMEDOUT: 1162 case RESETTIMEDOUT: 1163 fdcretry(fdc); 1164 goto loop; 1165 1166 case IOCOMPLETE: /* IO DONE, post-analyze */ 1167 callout_stop(&fdc->sc_timo_ch); 1168 1169 disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid), 1170 (bp->b_flags & B_READ)); 1171 1172 if (fdcresult(fdc) != 7 || (st1 & 0x37) != 0) { 1173 /* 1174 * As the damn chip doesn't seem to have a FIFO, 1175 * accept a few overruns as a fact of life *sigh* 1176 */ 1177 if ((st1 & 0x10) && (++fdc->sc_overruns < 4)) { 1178 fdc->sc_state = DOSEEK; 1179 goto loop; 1180 } 1181 #ifdef FD_DEBUG 1182 fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ? 1183 "read failed" : "write failed"); 1184 printf("blkno %qd nblks %d\n", 1185 fd->sc_blkno, fd->sc_nblks); 1186 #endif 1187 fdcretry(fdc); 1188 goto loop; 1189 } 1190 if (fdc->sc_errors) { 1191 diskerr(bp, "fd", "soft error", LOG_PRINTF, 1192 fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL); 1193 printf("\n"); 1194 fdc->sc_errors = 0; 1195 } 1196 fdc->sc_overruns = 0; 1197 fd->sc_blkno += fd->sc_nblks; 1198 fd->sc_skip += fd->sc_nbytes; 1199 fd->sc_bcount -= fd->sc_nbytes; 1200 if (!finfo && fd->sc_bcount > 0) { 1201 bp->b_cylinder = fd->sc_blkno / fd->sc_type->seccyl; 1202 goto doseek; 1203 } 1204 fdfinish(fd, bp); 1205 goto loop; 1206 1207 case DORESET: 1208 /* try a reset, keep motor on */ 1209 fd_set_motor(fdc, 1); 1210 delay(100); 1211 fd_set_motor(fdc, 0); 1212 fdc->sc_state = RESETCOMPLETE; 1213 callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc); 1214 return 1; /* will return later */ 1215 1216 case RESETCOMPLETE: 1217 callout_stop(&fdc->sc_timo_ch); 1218 /* clear the controller output buffer */ 1219 for (i = 0; i < 4; i++) { 1220 out_fdc(NE7CMD_SENSEI); 1221 (void) fdcresult(fdc); 1222 } 1223 1224 /* fall through */ 1225 case DORECAL: 1226 fdc_ienable(); 1227 1228 out_fdc(NE7CMD_RECAL); /* recalibrate function */ 1229 out_fdc(fd->sc_drive); 1230 fdc->sc_state = RECALWAIT; 1231 callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc); 1232 return 1; /* will return later */ 1233 1234 case RECALWAIT: 1235 callout_stop(&fdc->sc_timo_ch); 1236 fdc->sc_state = RECALCOMPLETE; 1237 /* allow 1/30 second for heads to settle */ 1238 callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc); 1239 return 1; /* will return later */ 1240 1241 case RECALCOMPLETE: 1242 out_fdc(NE7CMD_SENSEI); 1243 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) { 1244 #ifdef FD_DEBUG 1245 fdcstatus(&fd->sc_dev, 2, "recalibrate failed"); 1246 #endif 1247 fdcretry(fdc); 1248 goto loop; 1249 } 1250 fd->sc_cylin = 0; 1251 goto doseek; 1252 1253 case MOTORWAIT: 1254 if (fd->sc_flags & FD_MOTOR_WAIT) 1255 return 1; /* time's not up yet */ 1256 goto doseek; 1257 1258 default: 1259 fdcstatus(&fd->sc_dev, 0, "stray interrupt"); 1260 return 1; 1261 } 1262 #ifdef DIAGNOSTIC 1263 panic("fdcintr: impossible"); 1264 #endif 1265 #undef st0 1266 #undef st1 1267 #undef cyl 1268 } 1269 1270 void 1271 fdcretry(fdc) 1272 struct fdc_softc *fdc; 1273 { 1274 char bits[64]; 1275 struct fd_softc *fd; 1276 struct buf *bp; 1277 1278 fd = fdc->sc_drives.tqh_first; 1279 bp = BUFQ_PEEK(fd->sc_q); 1280 1281 if (fd->sc_opts & FDOPT_NORETRY) 1282 goto fail; 1283 1284 switch (fdc->sc_errors) { 1285 case 0: 1286 /* try again */ 1287 fdc->sc_state = DOSEEK; 1288 break; 1289 1290 case 1: case 2: case 3: 1291 /* didn't work; try recalibrating */ 1292 fdc->sc_state = DORECAL; 1293 break; 1294 1295 case 4: 1296 /* still no go; reset the bastard */ 1297 fdc->sc_state = DORESET; 1298 break; 1299 1300 default: 1301 fail: 1302 if ((fd->sc_opts & FDOPT_SILENT) == 0) { 1303 diskerr(bp, "fd", "hard error", LOG_PRINTF, 1304 fd->sc_skip / FDC_BSIZE, 1305 (struct disklabel *)NULL); 1306 1307 printf(" (st0 %s", 1308 bitmask_snprintf(fdc->sc_status[0], 1309 NE7_ST0BITS, bits, 1310 sizeof(bits))); 1311 printf(" st1 %s", 1312 bitmask_snprintf(fdc->sc_status[1], 1313 NE7_ST1BITS, bits, 1314 sizeof(bits))); 1315 printf(" st2 %s", 1316 bitmask_snprintf(fdc->sc_status[2], 1317 NE7_ST2BITS, bits, 1318 sizeof(bits))); 1319 printf(" cyl %d head %d sec %d)\n", 1320 fdc->sc_status[3], 1321 fdc->sc_status[4], 1322 fdc->sc_status[5]); 1323 } 1324 bp->b_error = EIO; 1325 fdfinish(fd, bp); 1326 } 1327 fdc->sc_errors++; 1328 } 1329 1330 int 1331 fdioctl(dev, cmd, addr, flag, l) 1332 dev_t dev; 1333 u_long cmd; 1334 void *addr; 1335 int flag; 1336 struct lwp *l; 1337 { 1338 struct fd_softc *fd; 1339 struct disklabel buffer; 1340 int error; 1341 struct fdformat_parms *form_parms; 1342 struct fdformat_cmd *form_cmd; 1343 struct ne7_fd_formb *fd_formb; 1344 unsigned int scratch; 1345 int il[FD_MAX_NSEC + 1]; 1346 register int i, j; 1347 1348 fd = hdfd_cd.cd_devs[FDUNIT(dev)]; 1349 1350 switch (cmd) { 1351 case DIOCGDINFO: 1352 fdgetdisklabel(fd, dev); 1353 *(struct disklabel *)addr = *(fd->sc_dk.dk_label); 1354 return 0; 1355 1356 case DIOCGPART: 1357 fdgetdisklabel(fd, dev); 1358 ((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label; 1359 ((struct partinfo *)addr)->part = 1360 &fd->sc_dk.dk_label->d_partitions[RAW_PART]; 1361 return(0); 1362 1363 case DIOCWLABEL: 1364 if ((flag & FWRITE) == 0) 1365 return EBADF; 1366 /* XXX do something */ 1367 return 0; 1368 1369 case DIOCSDINFO: 1370 case DIOCWDINFO: 1371 if ((flag & FWRITE) == 0) 1372 return EBADF; 1373 1374 fd->sc_flags &= ~FD_HAVELAB; /* Invalid */ 1375 error = setdisklabel(&buffer, (struct disklabel *)addr, 0,NULL); 1376 if (error) 1377 return error; 1378 1379 if (cmd == DIOCWDINFO) 1380 error = writedisklabel(dev, fdstrategy, &buffer, NULL); 1381 return error; 1382 1383 case FDIOCGETFORMAT: 1384 form_parms = (struct fdformat_parms *)addr; 1385 form_parms->fdformat_version = FDFORMAT_VERSION; 1386 form_parms->nbps = 128 * (1 << fd->sc_type->secsize); 1387 form_parms->ncyl = fd->sc_type->tracks; 1388 form_parms->nspt = fd->sc_type->sectrac; 1389 form_parms->ntrk = fd->sc_type->heads; 1390 form_parms->stepspercyl = fd->sc_type->step; 1391 form_parms->gaplen = fd->sc_type->gap2; 1392 form_parms->fillbyte = fd->sc_type->fillbyte; 1393 form_parms->interleave = fd->sc_type->interleave; 1394 switch (fd->sc_type->rate) { 1395 case FDC_500KBPS: 1396 form_parms->xfer_rate = 500 * 1024; 1397 break; 1398 case FDC_300KBPS: 1399 form_parms->xfer_rate = 300 * 1024; 1400 break; 1401 case FDC_250KBPS: 1402 form_parms->xfer_rate = 250 * 1024; 1403 break; 1404 case FDC_125KBPS: 1405 form_parms->xfer_rate = 125 * 1024; 1406 break; 1407 default: 1408 return EINVAL; 1409 } 1410 return 0; 1411 1412 case FDIOCSETFORMAT: 1413 if((flag & FWRITE) == 0) 1414 return EBADF; /* must be opened for writing */ 1415 form_parms = (struct fdformat_parms *)addr; 1416 if (form_parms->fdformat_version != FDFORMAT_VERSION) 1417 return EINVAL; /* wrong version of formatting prog */ 1418 1419 scratch = form_parms->nbps >> 7; 1420 if ((form_parms->nbps & 0x7f) || ffs(scratch) == 0 || 1421 scratch & ~(1 << (ffs(scratch)-1))) 1422 /* not a power-of-two multiple of 128 */ 1423 return EINVAL; 1424 1425 switch (form_parms->xfer_rate) { 1426 case 500 * 1024: 1427 fd->sc_type->rate = FDC_500KBPS; 1428 break; 1429 case 300 * 1024: 1430 fd->sc_type->rate = FDC_300KBPS; 1431 break; 1432 case 250 * 1024: 1433 fd->sc_type->rate = FDC_250KBPS; 1434 break; 1435 case 125 * 1024: 1436 fd->sc_type->rate = FDC_125KBPS; 1437 break; 1438 default: 1439 return EINVAL; 1440 } 1441 1442 if (form_parms->nspt > FD_MAX_NSEC || 1443 form_parms->fillbyte > 0xff || 1444 form_parms->interleave > 0xff) 1445 return EINVAL; 1446 fd->sc_type->sectrac = form_parms->nspt; 1447 if (form_parms->ntrk != 2 && form_parms->ntrk != 1) 1448 return EINVAL; 1449 fd->sc_type->heads = form_parms->ntrk; 1450 fd->sc_type->seccyl = form_parms->nspt * form_parms->ntrk; 1451 fd->sc_type->secsize = ffs(scratch)-1; 1452 fd->sc_type->gap2 = form_parms->gaplen; 1453 fd->sc_type->tracks = form_parms->ncyl; 1454 fd->sc_type->size = fd->sc_type->seccyl * form_parms->ncyl * 1455 form_parms->nbps / DEV_BSIZE; 1456 fd->sc_type->step = form_parms->stepspercyl; 1457 fd->sc_type->fillbyte = form_parms->fillbyte; 1458 fd->sc_type->interleave = form_parms->interleave; 1459 return 0; 1460 1461 case FDIOCFORMAT_TRACK: 1462 if((flag & FWRITE) == 0) 1463 return EBADF; /* must be opened for writing */ 1464 form_cmd = (struct fdformat_cmd *)addr; 1465 if (form_cmd->formatcmd_version != FDFORMAT_VERSION) 1466 return EINVAL; /* wrong version of formatting prog */ 1467 1468 if (form_cmd->head >= fd->sc_type->heads || 1469 form_cmd->cylinder >= fd->sc_type->tracks) { 1470 return EINVAL; 1471 } 1472 1473 fd_formb = malloc(sizeof(struct ne7_fd_formb), 1474 M_TEMP, M_NOWAIT); 1475 if (fd_formb == 0) 1476 return ENOMEM; 1477 1478 fd_formb->head = form_cmd->head; 1479 fd_formb->cyl = form_cmd->cylinder; 1480 fd_formb->transfer_rate = fd->sc_type->rate; 1481 fd_formb->fd_formb_secshift = fd->sc_type->secsize; 1482 fd_formb->fd_formb_nsecs = fd->sc_type->sectrac; 1483 fd_formb->fd_formb_gaplen = fd->sc_type->gap2; 1484 fd_formb->fd_formb_fillbyte = fd->sc_type->fillbyte; 1485 1486 bzero(il,sizeof il); 1487 for (j = 0, i = 1; i <= fd_formb->fd_formb_nsecs; i++) { 1488 while (il[(j%fd_formb->fd_formb_nsecs)+1]) 1489 j++; 1490 il[(j%fd_formb->fd_formb_nsecs)+1] = i; 1491 j += fd->sc_type->interleave; 1492 } 1493 for (i = 0; i < fd_formb->fd_formb_nsecs; i++) { 1494 fd_formb->fd_formb_cylno(i) = form_cmd->cylinder; 1495 fd_formb->fd_formb_headno(i) = form_cmd->head; 1496 fd_formb->fd_formb_secno(i) = il[i+1]; 1497 fd_formb->fd_formb_secsize(i) = fd->sc_type->secsize; 1498 } 1499 1500 error = fdformat(dev, fd_formb, l->l_proc); 1501 free(fd_formb, M_TEMP); 1502 return error; 1503 1504 case FDIOCGETOPTS: /* get drive options */ 1505 *(int *)addr = fd->sc_opts; 1506 return 0; 1507 1508 case FDIOCSETOPTS: /* set drive options */ 1509 fd->sc_opts = *(int *)addr; 1510 return 0; 1511 1512 1513 default: 1514 return ENOTTY; 1515 } 1516 1517 #ifdef DIAGNOSTIC 1518 panic("fdioctl: impossible"); 1519 #endif 1520 } 1521 1522 int 1523 fdformat(dev, finfo, p) 1524 dev_t dev; 1525 struct ne7_fd_formb *finfo; 1526 struct proc *p; 1527 { 1528 int rv = 0, s; 1529 struct fd_softc *fd = hdfd_cd.cd_devs[FDUNIT(dev)]; 1530 struct fd_type *type = fd->sc_type; 1531 struct buf *bp; 1532 1533 /* set up a buffer header for fdstrategy() */ 1534 bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT); 1535 if(bp == 0) 1536 return ENOBUFS; 1537 bzero((void *)bp, sizeof(struct buf)); 1538 bp->b_flags = B_BUSY | B_PHYS | B_FORMAT; 1539 bp->b_proc = p; 1540 bp->b_dev = dev; 1541 1542 /* 1543 * calculate a fake blkno, so fdstrategy() would initiate a 1544 * seek to the requested cylinder 1545 */ 1546 bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads) 1547 + finfo->head * type->sectrac) * FDC_BSIZE / DEV_BSIZE; 1548 1549 bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs; 1550 bp->b_data = (void *)finfo; 1551 1552 #ifdef DEBUG 1553 printf("fdformat: blkno %x count %lx\n", bp->b_blkno, bp->b_bcount); 1554 #endif 1555 1556 /* now do the format */ 1557 fdstrategy(bp); 1558 1559 /* ...and wait for it to complete */ 1560 s = splbio(); 1561 while(!(bp->b_flags & B_DONE)) { 1562 rv = tsleep((void *)bp, PRIBIO, "fdform", 20 * hz); 1563 if (rv == EWOULDBLOCK) 1564 break; 1565 } 1566 splx(s); 1567 1568 if (rv == EWOULDBLOCK) { 1569 /* timed out */ 1570 rv = EIO; 1571 biodone(bp); 1572 } else if (bp->b_error != 0) { 1573 rv = bp->b_error; 1574 } 1575 free(bp, M_TEMP); 1576 return rv; 1577 } 1578 1579 1580 /* 1581 * Obtain a disklabel. Either a real one from the disk or, if there 1582 * is none, a fake one. 1583 */ 1584 static void 1585 fdgetdisklabel(fd, dev) 1586 struct fd_softc *fd; 1587 dev_t dev; 1588 { 1589 struct disklabel *lp; 1590 struct cpu_disklabel cpulab; 1591 1592 if (fd->sc_flags & FD_HAVELAB) 1593 return; /* Already got one */ 1594 1595 lp = fd->sc_dk.dk_label; 1596 1597 bzero(lp, sizeof(*lp)); 1598 bzero(&cpulab, sizeof(cpulab)); 1599 1600 lp->d_secpercyl = fd->sc_type->seccyl; 1601 lp->d_type = DTYPE_FLOPPY; 1602 lp->d_secsize = FDC_BSIZE; 1603 lp->d_secperunit = fd->sc_type->size; 1604 1605 /* 1606 * If there is no label on the disk: fake one 1607 */ 1608 if (readdisklabel(dev, fdstrategy, lp, &cpulab) != NULL) 1609 fdgetdefaultlabel(fd, lp, RAW_PART); 1610 fd->sc_flags |= FD_HAVELAB; 1611 1612 if ((FDC_BSIZE * fd->sc_type->size) 1613 < (lp->d_secsize * lp->d_secperunit)) { 1614 /* 1615 * XXX: Ignore these fields. If you drop a vnddisk 1616 * on more than one floppy, you'll get disturbing 1617 * sounds! 1618 */ 1619 lp->d_secpercyl = fd->sc_type->seccyl; 1620 lp->d_type = DTYPE_FLOPPY; 1621 lp->d_secsize = FDC_BSIZE; 1622 lp->d_secperunit = fd->sc_type->size; 1623 } 1624 } 1625 1626 /* 1627 * Build defaultdisk label. For now we only create a label from what we 1628 * know from 'sc'. 1629 */ 1630 static void 1631 fdgetdefaultlabel(fd, lp, part) 1632 struct fd_softc *fd; 1633 struct disklabel *lp; 1634 int part; 1635 { 1636 bzero(lp, sizeof(struct disklabel)); 1637 1638 lp->d_secsize = 128 * (1 << fd->sc_type->secsize); 1639 lp->d_ntracks = fd->sc_type->heads; 1640 lp->d_nsectors = fd->sc_type->sectrac; 1641 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 1642 lp->d_ncylinders = fd->sc_type->size / lp->d_secpercyl; 1643 lp->d_secperunit = fd->sc_type->size; 1644 1645 lp->d_type = DTYPE_FLOPPY; 1646 lp->d_rpm = 300; /* good guess I suppose. */ 1647 lp->d_interleave = 1; /* FIXME: is this OK? */ 1648 lp->d_bbsize = 0; 1649 lp->d_sbsize = 0; 1650 lp->d_npartitions = part + 1; 1651 lp->d_trkseek = 6000; /* Who cares... */ 1652 lp->d_magic = DISKMAGIC; 1653 lp->d_magic2 = DISKMAGIC; 1654 lp->d_checksum = dkcksum(lp); 1655 lp->d_partitions[part].p_size = lp->d_secperunit; 1656 lp->d_partitions[part].p_fstype = FS_UNUSED; 1657 lp->d_partitions[part].p_fsize = 1024; 1658 lp->d_partitions[part].p_frag = 8; 1659 } 1660