1 /* $NetBSD: hdfd.c,v 1.40 2003/07/15 01:19:50 lukem Exp $ */ 2 3 /*- 4 * Copyright (c) 1996 Leo Weppelman 5 * Copyright (c) 1993, 1994, 1995, 1996 6 * Charles M. Hannum. All rights reserved. 7 * Copyright (c) 1990 The Regents of the University of California. 8 * All rights reserved. 9 * 10 * This code is derived from software contributed to Berkeley by 11 * Don Ahn. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. All advertising materials mentioning features or use of this software 22 * must display the following acknowledgement: 23 * This product includes software developed by the University of 24 * California, Berkeley and its contributors. 25 * 4. Neither the name of the University nor the names of its contributors 26 * may be used to endorse or promote products derived from this software 27 * without specific prior written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 39 * SUCH DAMAGE. 40 * 41 * @(#)fd.c 7.4 (Berkeley) 5/25/91 42 */ 43 44 /* 45 * Floppy formatting facilities merged from FreeBSD fd.c driver: 46 * Id: fd.c,v 1.53 1995/03/12 22:40:56 joerg Exp 47 * which carries the same copyright/redistribution notice as shown above with 48 * the addition of the following statement before the "Redistribution and 49 * use ..." clause: 50 * 51 * Copyright (c) 1993, 1994 by 52 * jc@irbs.UUCP (John Capo) 53 * vak@zebub.msk.su (Serge Vakulenko) 54 * ache@astral.msk.su (Andrew A. Chernov) 55 * 56 * Copyright (c) 1993, 1994, 1995 by 57 * joerg_wunsch@uriah.sax.de (Joerg Wunsch) 58 * dufault@hda.com (Peter Dufault) 59 */ 60 61 #include <sys/cdefs.h> 62 __KERNEL_RCSID(0, "$NetBSD: hdfd.c,v 1.40 2003/07/15 01:19:50 lukem Exp $"); 63 64 #include "opt_ddb.h" 65 66 #include <sys/param.h> 67 #include <sys/systm.h> 68 #include <sys/callout.h> 69 #include <sys/kernel.h> 70 #include <sys/file.h> 71 #include <sys/ioctl.h> 72 #include <sys/device.h> 73 #include <sys/disklabel.h> 74 #include <sys/disk.h> 75 #include <sys/buf.h> 76 #include <sys/malloc.h> 77 #include <sys/uio.h> 78 #include <sys/syslog.h> 79 #include <sys/queue.h> 80 #include <sys/proc.h> 81 #include <sys/fdio.h> 82 #include <sys/conf.h> 83 #include <sys/device.h> 84 85 #include <uvm/uvm_extern.h> 86 87 #include <machine/cpu.h> 88 #include <machine/bus.h> 89 #include <machine/iomap.h> 90 #include <machine/mfp.h> 91 92 #include <atari/dev/hdfdreg.h> 93 #include <atari/atari/intr.h> 94 #include <atari/atari/device.h> 95 96 #include "locators.h" 97 98 /* 99 * {b,c}devsw[] function prototypes 100 */ 101 dev_type_open(fdopen); 102 dev_type_close(fdclose); 103 dev_type_read(fdread); 104 dev_type_write(fdwrite); 105 dev_type_ioctl(fdioctl); 106 dev_type_strategy(fdstrategy); 107 108 volatile u_char *fdio_addr; 109 110 #define wrt_fdc_reg(reg, val) { fdio_addr[reg] = val; } 111 #define rd_fdc_reg(reg) ( fdio_addr[reg] ) 112 113 #define fdc_ienable() MFP2->mf_ierb |= IB_DCHG; 114 115 /* 116 * Interface to the pseudo-DMA handler 117 */ 118 void fddma_intr(void); 119 caddr_t fddmaaddr = NULL; 120 int fddmalen = 0; 121 122 extern void mfp_hdfd_nf __P((void)), mfp_hdfd_fifo __P((void)); 123 124 /* 125 * Argument to fdcintr..... 126 */ 127 static void *intr_arg = NULL; /* XXX: arg. to intr_establish() */ 128 129 130 131 #define FDUNIT(dev) (minor(dev) / 8) 132 #define FDTYPE(dev) (minor(dev) % 8) 133 134 /* XXX misuse a flag to identify format operation */ 135 #define B_FORMAT B_XXX 136 137 enum fdc_state { 138 DEVIDLE = 0, 139 MOTORWAIT, 140 DOSEEK, 141 SEEKWAIT, 142 SEEKTIMEDOUT, 143 SEEKCOMPLETE, 144 DOIO, 145 IOCOMPLETE, 146 IOTIMEDOUT, 147 DORESET, 148 RESETCOMPLETE, 149 RESETTIMEDOUT, 150 DORECAL, 151 RECALWAIT, 152 RECALTIMEDOUT, 153 RECALCOMPLETE, 154 }; 155 156 /* software state, per controller */ 157 struct fdc_softc { 158 struct device sc_dev; /* boilerplate */ 159 160 struct callout sc_timo_ch; /* timeout callout */ 161 struct callout sc_intr_ch; /* pseudo-intr callout */ 162 163 struct fd_softc *sc_fd[4]; /* pointers to children */ 164 TAILQ_HEAD(drivehead, fd_softc) sc_drives; 165 enum fdc_state sc_state; 166 int sc_errors; /* number of retries so far */ 167 int sc_overruns; /* number of overruns so far */ 168 u_char sc_status[7]; /* copy of registers */ 169 }; 170 171 /* controller driver configuration */ 172 int fdcprobe __P((struct device *, struct cfdata *, void *)); 173 int fdprint __P((void *, const char *)); 174 void fdcattach __P((struct device *, struct device *, void *)); 175 176 CFATTACH_DECL(fdc, sizeof(struct fdc_softc), 177 fdcprobe, fdcattach, NULL, NULL); 178 179 /* 180 * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how 181 * we tell them apart. 182 */ 183 struct fd_type { 184 int sectrac; /* sectors per track */ 185 int heads; /* number of heads */ 186 int seccyl; /* sectors per cylinder */ 187 int secsize; /* size code for sectors */ 188 int datalen; /* data len when secsize = 0 */ 189 int steprate; /* step rate and head unload time */ 190 int gap1; /* gap len between sectors */ 191 int gap2; /* formatting gap */ 192 int tracks; /* total num of tracks */ 193 int size; /* size of disk in sectors */ 194 int step; /* steps per cylinder */ 195 int rate; /* transfer speed code */ 196 u_char fillbyte; /* format fill byte */ 197 u_char interleave; /* interleave factor (formatting) */ 198 char *name; 199 }; 200 201 /* 202 * The order of entries in the following table is important -- BEWARE! 203 * The order of the types is the same as for the TT/Falcon.... 204 */ 205 struct fd_type fd_types[] = { 206 /* 360kB in 720kB drive */ 207 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_125KBPS,0xf6,1,"360KB" }, 208 /* 3.5" 720kB diskette */ 209 { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_125KBPS,0xf6,1,"720KB" }, 210 /* 1.44MB diskette */ 211 { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_250KBPS,0xf6,1,"1.44MB" }, 212 }; 213 214 /* software state, per disk (with up to 4 disks per ctlr) */ 215 struct fd_softc { 216 struct device sc_dev; 217 struct disk sc_dk; 218 219 struct fd_type *sc_deftype; /* default type descriptor */ 220 struct fd_type *sc_type; /* current type descriptor */ 221 222 struct callout sc_motoron_ch; 223 struct callout sc_motoroff_ch; 224 225 daddr_t sc_blkno; /* starting block number */ 226 int sc_bcount; /* byte count left */ 227 int sc_opts; /* user-set options */ 228 int sc_skip; /* bytes already transferred */ 229 int sc_nblks; /* #blocks currently transferring */ 230 int sc_nbytes; /* #bytes currently transferring */ 231 232 int sc_drive; /* physical unit number */ 233 int sc_flags; 234 #define FD_OPEN 0x01 /* it's open */ 235 #define FD_MOTOR 0x02 /* motor should be on */ 236 #define FD_MOTOR_WAIT 0x04 /* motor coming up */ 237 #define FD_HAVELAB 0x08 /* got a disklabel */ 238 int sc_cylin; /* where we think the head is */ 239 240 void *sc_sdhook; /* saved shutdown hook for drive. */ 241 242 TAILQ_ENTRY(fd_softc) sc_drivechain; 243 int sc_ops; /* I/O ops since last switch */ 244 struct bufq_state sc_q; /* pending I/O requests */ 245 int sc_active; /* number of active I/O operations */ 246 }; 247 248 /* floppy driver configuration */ 249 int fdprobe __P((struct device *, struct cfdata *, void *)); 250 void fdattach __P((struct device *, struct device *, void *)); 251 252 CFATTACH_DECL(hdfd, sizeof(struct fd_softc), 253 fdprobe, fdattach, NULL, NULL); 254 255 extern struct cfdriver hdfd_cd; 256 257 const struct bdevsw fd_bdevsw = { 258 fdopen, fdclose, fdstrategy, fdioctl, nodump, nosize, D_DISK 259 }; 260 261 const struct cdevsw fd_cdevsw = { 262 fdopen, fdclose, fdread, fdwrite, fdioctl, 263 nostop, notty, nopoll, nommap, nokqfilter, D_DISK 264 }; 265 266 void fdstart __P((struct fd_softc *)); 267 268 struct dkdriver fddkdriver = { fdstrategy }; 269 270 void fd_set_motor __P((struct fdc_softc *fdc, int reset)); 271 void fd_motor_off __P((void *arg)); 272 void fd_motor_on __P((void *arg)); 273 int fdcresult __P((struct fdc_softc *fdc)); 274 int out_fdc __P((u_char x)); 275 void fdc_ctrl_intr __P((struct clockframe)); 276 void fdcstart __P((struct fdc_softc *fdc)); 277 void fdcstatus __P((struct device *dv, int n, char *s)); 278 void fdctimeout __P((void *arg)); 279 void fdcpseudointr __P((void *arg)); 280 int fdcintr __P((void *)); 281 void fdcretry __P((struct fdc_softc *fdc)); 282 void fdfinish __P((struct fd_softc *fd, struct buf *bp)); 283 int fdformat __P((dev_t, struct ne7_fd_formb *, struct proc *)); 284 285 static void fdgetdisklabel __P((struct fd_softc *, dev_t)); 286 static void fdgetdefaultlabel __P((struct fd_softc *, struct disklabel *, 287 int)); 288 289 __inline struct fd_type *fd_dev_to_type __P((struct fd_softc *, dev_t)); 290 291 int 292 fdcprobe(parent, cfp, aux) 293 struct device *parent; 294 struct cfdata *cfp; 295 void *aux; 296 { 297 static int fdc_matched = 0; 298 bus_space_tag_t mb_tag; 299 300 /* Match only once */ 301 if(strcmp("fdc", aux) || fdc_matched) 302 return(0); 303 304 if (!atari_realconfig) 305 return 0; 306 307 if ((mb_tag = mb_alloc_bus_space_tag()) == NULL) 308 return 0; 309 310 if (bus_space_map(mb_tag, FD_IOBASE, FD_IOSIZE, 0, 311 (caddr_t*)&fdio_addr)) { 312 printf("fdcprobe: cannot map io-area\n"); 313 mb_free_bus_space_tag(mb_tag); 314 return (0); 315 } 316 317 #ifdef FD_DEBUG 318 printf("fdcprobe: I/O mapping done va: %p\n", fdio_addr); 319 #endif 320 321 /* reset */ 322 wrt_fdc_reg(fdout, 0); 323 delay(100); 324 wrt_fdc_reg(fdout, FDO_FRST); 325 326 /* see if it can handle a command */ 327 if (out_fdc(NE7CMD_SPECIFY) < 0) 328 goto out; 329 out_fdc(0xdf); 330 out_fdc(7); 331 332 fdc_matched = 1; 333 334 out: 335 if (fdc_matched == 0) { 336 bus_space_unmap(mb_tag, (caddr_t)fdio_addr, FD_IOSIZE); 337 mb_free_bus_space_tag(mb_tag); 338 } 339 340 return fdc_matched; 341 } 342 343 /* 344 * Arguments passed between fdcattach and fdprobe. 345 */ 346 struct fdc_attach_args { 347 int fa_drive; 348 struct fd_type *fa_deftype; 349 }; 350 351 /* 352 * Print the location of a disk drive (called just before attaching the 353 * the drive). If `fdc' is not NULL, the drive was found but was not 354 * in the system config file; print the drive name as well. 355 * Return QUIET (config_find ignores this if the device was configured) to 356 * avoid printing `fdN not configured' messages. 357 */ 358 int 359 fdprint(aux, fdc) 360 void *aux; 361 const char *fdc; 362 { 363 register struct fdc_attach_args *fa = aux; 364 365 if (!fdc) 366 aprint_normal(" drive %d", fa->fa_drive); 367 return QUIET; 368 } 369 370 void 371 fdcattach(parent, self, aux) 372 struct device *parent, *self; 373 void *aux; 374 { 375 struct fdc_softc *fdc = (void *)self; 376 struct fdc_attach_args fa; 377 int has_fifo; 378 379 has_fifo = 0; 380 381 fdc->sc_state = DEVIDLE; 382 TAILQ_INIT(&fdc->sc_drives); 383 384 out_fdc(NE7CMD_CONFIGURE); 385 if (out_fdc(0) == 0) { 386 out_fdc(0x1a); /* No polling, fifo depth = 10 */ 387 out_fdc(0); 388 389 /* Retain configuration across resets */ 390 out_fdc(NE7CMD_LOCK); 391 (void)fdcresult(fdc); 392 has_fifo = 1; 393 } 394 else { 395 (void)rd_fdc_reg(fddata); 396 printf(": no fifo"); 397 } 398 399 printf("\n"); 400 401 callout_init(&fdc->sc_timo_ch); 402 callout_init(&fdc->sc_intr_ch); 403 404 if (intr_establish(22, USER_VEC|FAST_VEC, 0, 405 (hw_ifun_t)(has_fifo ? mfp_hdfd_fifo : mfp_hdfd_nf), 406 NULL) == NULL) { 407 printf("fdcattach: Can't establish interrupt\n"); 408 return; 409 } 410 411 /* 412 * Setup the interrupt logic. 413 */ 414 MFP2->mf_iprb = (u_int8_t)~IB_DCHG; 415 MFP2->mf_imrb |= IB_DCHG; 416 MFP2->mf_aer |= 0x10; /* fdc int low->high */ 417 418 /* physical limit: four drives per controller. */ 419 for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) { 420 /* 421 * XXX: Choose something sensible as a default... 422 */ 423 fa.fa_deftype = &fd_types[2]; /* 1.44MB */ 424 (void)config_found(self, (void *)&fa, fdprint); 425 } 426 } 427 428 int 429 fdprobe(parent, cfp, aux) 430 struct device *parent; 431 struct cfdata *cfp; 432 void *aux; 433 { 434 struct fdc_softc *fdc = (void *)parent; 435 struct fdc_attach_args *fa = aux; 436 int drive = fa->fa_drive; 437 int n; 438 439 if (cfp->cf_loc[FDCCF_UNIT] != FDCCF_UNIT_DEFAULT && 440 cfp->cf_loc[FDCCF_UNIT] != drive) 441 return 0; 442 /* 443 * XXX 444 * This is to work around some odd interactions between this driver 445 * and SMC Ethernet cards. 446 */ 447 if (cfp->cf_loc[FDCCF_UNIT] == FDCCF_UNIT_DEFAULT && drive >= 2) 448 return 0; 449 450 /* select drive and turn on motor */ 451 wrt_fdc_reg(fdout, drive | FDO_FRST | FDO_MOEN(drive)); 452 453 /* wait for motor to spin up */ 454 delay(250000); 455 out_fdc(NE7CMD_RECAL); 456 out_fdc(drive); 457 458 /* wait for recalibrate */ 459 delay(2000000); 460 out_fdc(NE7CMD_SENSEI); 461 n = fdcresult(fdc); 462 463 #ifdef FD_DEBUG 464 { 465 int i; 466 printf("fdprobe: status"); 467 for (i = 0; i < n; i++) 468 printf(" %x", fdc->sc_status[i]); 469 printf("\n"); 470 } 471 #endif 472 intr_arg = (void*)fdc; 473 if (n != 2 || (fdc->sc_status[0] & 0xf8) != 0x20) 474 return 0; 475 /* turn off motor */ 476 wrt_fdc_reg(fdout, FDO_FRST); 477 478 return 1; 479 } 480 481 /* 482 * Controller is working, and drive responded. Attach it. 483 */ 484 void 485 fdattach(parent, self, aux) 486 struct device *parent, *self; 487 void *aux; 488 { 489 struct fdc_softc *fdc = (void *)parent; 490 struct fd_softc *fd = (void *)self; 491 struct fdc_attach_args *fa = aux; 492 struct fd_type *type = fa->fa_deftype; 493 int drive = fa->fa_drive; 494 495 callout_init(&fd->sc_motoron_ch); 496 callout_init(&fd->sc_motoroff_ch); 497 498 /* XXX Allow `flags' to override device type? */ 499 500 if (type) 501 printf(": %s %d cyl, %d head, %d sec\n", type->name, 502 type->tracks, type->heads, type->sectrac); 503 else 504 printf(": density unknown\n"); 505 506 bufq_alloc(&fd->sc_q, BUFQ_DISKSORT|BUFQ_SORT_CYLINDER); 507 fd->sc_cylin = -1; 508 fd->sc_drive = drive; 509 fd->sc_deftype = type; 510 fdc->sc_fd[drive] = fd; 511 512 /* 513 * Initialize and attach the disk structure. 514 */ 515 fd->sc_dk.dk_name = fd->sc_dev.dv_xname; 516 fd->sc_dk.dk_driver = &fddkdriver; 517 disk_attach(&fd->sc_dk); 518 519 /* Needed to power off if the motor is on when we halt. */ 520 fd->sc_sdhook = shutdownhook_establish(fd_motor_off, fd); 521 } 522 523 /* 524 * This is called from the assembly part of the interrupt handler 525 * when it is clear that the interrupt was not related to shoving 526 * data. 527 */ 528 void 529 fdc_ctrl_intr(frame) 530 struct clockframe frame; 531 { 532 int s; 533 534 /* 535 * Disable further interrupts. The fdcintr() routine 536 * explicitly enables them when needed. 537 */ 538 MFP2->mf_ierb &= ~IB_DCHG; 539 540 /* 541 * Set fddmalen to zero so no pseudo-DMA transfers will 542 * occur. 543 */ 544 fddmalen = 0; 545 546 if (!BASEPRI(frame.cf_sr)) { 547 /* 548 * We don't want to stay on ipl6..... 549 */ 550 add_sicallback((si_farg)fdcpseudointr, intr_arg, 0); 551 } 552 else { 553 s = splbio(); 554 (void) fdcintr(intr_arg); 555 splx(s); 556 } 557 } 558 559 __inline struct fd_type * 560 fd_dev_to_type(fd, dev) 561 struct fd_softc *fd; 562 dev_t dev; 563 { 564 int type = FDTYPE(dev); 565 566 if (type > (sizeof(fd_types) / sizeof(fd_types[0]))) 567 return NULL; 568 return type ? &fd_types[type - 1] : fd->sc_deftype; 569 } 570 571 void 572 fdstrategy(bp) 573 register struct buf *bp; /* IO operation to perform */ 574 { 575 struct fd_softc *fd = hdfd_cd.cd_devs[FDUNIT(bp->b_dev)]; 576 int sz; 577 int s; 578 579 /* Valid unit, controller, and request? */ 580 if (bp->b_blkno < 0 || 581 ((bp->b_bcount % FDC_BSIZE) != 0 && 582 (bp->b_flags & B_FORMAT) == 0)) { 583 bp->b_error = EINVAL; 584 goto bad; 585 } 586 587 /* If it's a null transfer, return immediately. */ 588 if (bp->b_bcount == 0) 589 goto done; 590 591 sz = howmany(bp->b_bcount, FDC_BSIZE); 592 593 if (bp->b_blkno + sz > fd->sc_type->size) { 594 sz = fd->sc_type->size - bp->b_blkno; 595 if (sz == 0) { 596 /* If exactly at end of disk, return EOF. */ 597 goto done; 598 } 599 if (sz < 0) { 600 /* If past end of disk, return EINVAL. */ 601 bp->b_error = EINVAL; 602 goto bad; 603 } 604 /* Otherwise, truncate request. */ 605 bp->b_bcount = sz << DEV_BSHIFT; 606 } 607 608 bp->b_rawblkno = bp->b_blkno; 609 bp->b_cylinder = bp->b_blkno / (FDC_BSIZE/DEV_BSIZE) / fd->sc_type->seccyl; 610 611 #ifdef FD_DEBUG 612 printf("fdstrategy: b_blkno %d b_bcount %ld blkno %qd cylin %ld sz" 613 " %d\n", bp->b_blkno, bp->b_bcount, (long)fd->sc_blkno, 614 bp->b_cylinder, sz); 615 #endif 616 617 /* Queue transfer on drive, activate drive and controller if idle. */ 618 s = splbio(); 619 BUFQ_PUT(&fd->sc_q, bp); 620 callout_stop(&fd->sc_motoroff_ch); /* a good idea */ 621 if (fd->sc_active == 0) 622 fdstart(fd); 623 #ifdef DIAGNOSTIC 624 else { 625 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; 626 if (fdc->sc_state == DEVIDLE) { 627 printf("fdstrategy: controller inactive\n"); 628 fdcstart(fdc); 629 } 630 } 631 #endif 632 splx(s); 633 return; 634 635 bad: 636 bp->b_flags |= B_ERROR; 637 done: 638 /* Toss transfer; we're done early. */ 639 bp->b_resid = bp->b_bcount; 640 biodone(bp); 641 } 642 643 void 644 fdstart(fd) 645 struct fd_softc *fd; 646 { 647 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; 648 int active = fdc->sc_drives.tqh_first != 0; 649 650 /* Link into controller queue. */ 651 fd->sc_active = 1; 652 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); 653 654 /* If controller not already active, start it. */ 655 if (!active) 656 fdcstart(fdc); 657 } 658 659 void 660 fdfinish(fd, bp) 661 struct fd_softc *fd; 662 struct buf *bp; 663 { 664 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; 665 666 /* 667 * Move this drive to the end of the queue to give others a `fair' 668 * chance. We only force a switch if N operations are completed while 669 * another drive is waiting to be serviced, since there is a long motor 670 * startup delay whenever we switch. 671 */ 672 (void)BUFQ_GET(&fd->sc_q); 673 if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) { 674 fd->sc_ops = 0; 675 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); 676 if (BUFQ_PEEK(&fd->sc_q) != NULL) 677 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); 678 else 679 fd->sc_active = 0; 680 } 681 bp->b_resid = fd->sc_bcount; 682 fd->sc_skip = 0; 683 684 biodone(bp); 685 /* turn off motor 5s from now */ 686 callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd); 687 fdc->sc_state = DEVIDLE; 688 } 689 690 int 691 fdread(dev, uio, flags) 692 dev_t dev; 693 struct uio *uio; 694 int flags; 695 { 696 return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio)); 697 } 698 699 int 700 fdwrite(dev, uio, flags) 701 dev_t dev; 702 struct uio *uio; 703 int flags; 704 { 705 return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio)); 706 } 707 708 void 709 fd_set_motor(fdc, reset) 710 struct fdc_softc *fdc; 711 int reset; 712 { 713 struct fd_softc *fd; 714 u_char status; 715 int n; 716 717 if ((fd = fdc->sc_drives.tqh_first) != NULL) 718 status = fd->sc_drive; 719 else 720 status = 0; 721 if (!reset) 722 status |= FDO_FRST | FDO_FDMAEN; 723 for (n = 0; n < 4; n++) 724 if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR)) 725 status |= FDO_MOEN(n); 726 wrt_fdc_reg(fdout, status); 727 } 728 729 void 730 fd_motor_off(arg) 731 void *arg; 732 { 733 struct fd_softc *fd = arg; 734 int s; 735 736 s = splbio(); 737 fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); 738 fd_set_motor((struct fdc_softc *)fd->sc_dev.dv_parent, 0); 739 splx(s); 740 } 741 742 void 743 fd_motor_on(arg) 744 void *arg; 745 { 746 struct fd_softc *fd = arg; 747 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; 748 int s; 749 750 s = splbio(); 751 fd->sc_flags &= ~FD_MOTOR_WAIT; 752 if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT)) 753 (void) fdcintr(fdc); 754 splx(s); 755 } 756 757 int 758 fdcresult(fdc) 759 struct fdc_softc *fdc; 760 { 761 u_char i; 762 int j = 100000, 763 n = 0; 764 765 for (; j; j--) { 766 i = rd_fdc_reg(fdsts) & (NE7_DIO | NE7_RQM | NE7_CB); 767 if (i == NE7_RQM) 768 return n; 769 if (i == (NE7_DIO | NE7_RQM | NE7_CB)) { 770 if (n >= sizeof(fdc->sc_status)) { 771 log(LOG_ERR, "fdcresult: overrun\n"); 772 return -1; 773 } 774 fdc->sc_status[n++] = rd_fdc_reg(fddata); 775 } 776 else delay(10); 777 } 778 log(LOG_ERR, "fdcresult: timeout\n"); 779 return -1; 780 } 781 782 int 783 out_fdc(x) 784 u_char x; 785 { 786 int i = 100000; 787 788 while (((rd_fdc_reg(fdsts) & (NE7_DIO|NE7_RQM)) != NE7_RQM) && i-- > 0) 789 delay(1); 790 if (i <= 0) 791 return -1; 792 wrt_fdc_reg(fddata, x); 793 return 0; 794 } 795 796 int 797 fdopen(dev, flags, mode, p) 798 dev_t dev; 799 int flags; 800 int mode; 801 struct proc *p; 802 { 803 int unit; 804 struct fd_softc *fd; 805 struct fd_type *type; 806 807 unit = FDUNIT(dev); 808 if (unit >= hdfd_cd.cd_ndevs) 809 return ENXIO; 810 fd = hdfd_cd.cd_devs[unit]; 811 if (fd == 0) 812 return ENXIO; 813 type = fd_dev_to_type(fd, dev); 814 if (type == NULL) 815 return ENXIO; 816 817 if ((fd->sc_flags & FD_OPEN) != 0 && 818 fd->sc_type != type) 819 return EBUSY; 820 821 fd->sc_type = type; 822 fd->sc_cylin = -1; 823 fd->sc_flags |= FD_OPEN; 824 fdgetdisklabel(fd, dev); 825 826 return 0; 827 } 828 829 int 830 fdclose(dev, flags, mode, p) 831 dev_t dev; 832 int flags; 833 int mode; 834 struct proc *p; 835 { 836 struct fd_softc *fd = hdfd_cd.cd_devs[FDUNIT(dev)]; 837 838 fd->sc_flags &= ~(FD_OPEN|FD_HAVELAB); 839 fd->sc_opts &= ~(FDOPT_NORETRY|FDOPT_SILENT); 840 return 0; 841 } 842 843 void 844 fdcstart(fdc) 845 struct fdc_softc *fdc; 846 { 847 848 #ifdef DIAGNOSTIC 849 /* only got here if controller's drive queue was inactive; should 850 be in idle state */ 851 if (fdc->sc_state != DEVIDLE) { 852 printf("fdcstart: not idle\n"); 853 return; 854 } 855 #endif 856 (void) fdcintr(fdc); 857 } 858 859 void 860 fdcstatus(dv, n, s) 861 struct device *dv; 862 int n; 863 char *s; 864 { 865 struct fdc_softc *fdc = (void *)dv->dv_parent; 866 char bits[64]; 867 868 if (n == 0) { 869 out_fdc(NE7CMD_SENSEI); 870 (void) fdcresult(fdc); 871 n = 2; 872 } 873 874 printf("%s: %s", dv->dv_xname, s); 875 876 switch (n) { 877 case 0: 878 printf("\n"); 879 break; 880 case 2: 881 printf(" (st0 %s cyl %d)\n", 882 bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS, 883 bits, sizeof(bits)), fdc->sc_status[1]); 884 break; 885 case 7: 886 printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0], 887 NE7_ST0BITS, bits, sizeof(bits))); 888 printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1], 889 NE7_ST1BITS, bits, sizeof(bits))); 890 printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2], 891 NE7_ST2BITS, bits, sizeof(bits))); 892 printf(" cyl %d head %d sec %d)\n", 893 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]); 894 break; 895 #ifdef DIAGNOSTIC 896 default: 897 printf("\nfdcstatus: weird size"); 898 break; 899 #endif 900 } 901 } 902 903 void 904 fdctimeout(arg) 905 void *arg; 906 { 907 struct fdc_softc *fdc = arg; 908 struct fd_softc *fd = fdc->sc_drives.tqh_first; 909 int s; 910 911 s = splbio(); 912 fdcstatus(&fd->sc_dev, 0, "timeout"); 913 914 if (BUFQ_PEEK(&fd->sc_q) != NULL) 915 fdc->sc_state++; 916 else 917 fdc->sc_state = DEVIDLE; 918 919 (void) fdcintr(fdc); 920 splx(s); 921 } 922 923 void 924 fdcpseudointr(arg) 925 void *arg; 926 { 927 int s; 928 929 /* Just ensure it has the right spl. */ 930 s = splbio(); 931 (void) fdcintr(arg); 932 splx(s); 933 } 934 935 int 936 fdcintr(arg) 937 void *arg; 938 { 939 struct fdc_softc *fdc = arg; 940 #define st0 fdc->sc_status[0] 941 #define st1 fdc->sc_status[1] 942 #define cyl fdc->sc_status[1] 943 944 struct fd_softc *fd; 945 struct buf *bp; 946 int read, head, sec, i, nblks; 947 struct fd_type *type; 948 struct ne7_fd_formb *finfo = NULL; 949 950 loop: 951 /* Is there a drive for the controller to do a transfer with? */ 952 fd = fdc->sc_drives.tqh_first; 953 if (fd == NULL) { 954 fdc->sc_state = DEVIDLE; 955 return 1; 956 } 957 958 /* Is there a transfer to this drive? If not, deactivate drive. */ 959 bp = BUFQ_PEEK(&fd->sc_q); 960 if (bp == NULL) { 961 fd->sc_ops = 0; 962 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); 963 fd->sc_active = 0; 964 goto loop; 965 } 966 967 if (bp->b_flags & B_FORMAT) 968 finfo = (struct ne7_fd_formb *)bp->b_data; 969 970 switch (fdc->sc_state) { 971 case DEVIDLE: 972 fdc->sc_errors = 0; 973 fdc->sc_overruns = 0; 974 fd->sc_skip = 0; 975 fd->sc_bcount = bp->b_bcount; 976 fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE); 977 callout_stop(&fd->sc_motoroff_ch); 978 if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) { 979 fdc->sc_state = MOTORWAIT; 980 return 1; 981 } 982 if ((fd->sc_flags & FD_MOTOR) == 0) { 983 /* Turn on the motor, being careful about pairing. */ 984 struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1]; 985 if (ofd && ofd->sc_flags & FD_MOTOR) { 986 callout_stop(&ofd->sc_motoroff_ch); 987 ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); 988 } 989 fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT; 990 fd_set_motor(fdc, 0); 991 fdc->sc_state = MOTORWAIT; 992 /* Allow .25s for motor to stabilize. */ 993 callout_reset(&fd->sc_motoron_ch, hz / 4, 994 fd_motor_on, fd); 995 return 1; 996 } 997 /* Make sure the right drive is selected. */ 998 fd_set_motor(fdc, 0); 999 1000 /* fall through */ 1001 case DOSEEK: 1002 doseek: 1003 if (fd->sc_cylin == bp->b_cylinder) 1004 goto doio; 1005 1006 out_fdc(NE7CMD_SPECIFY);/* specify command */ 1007 out_fdc(fd->sc_type->steprate); 1008 out_fdc(0x7); /* XXX head load time == 6ms - non-DMA */ 1009 1010 fdc_ienable(); 1011 1012 out_fdc(NE7CMD_SEEK); /* seek function */ 1013 out_fdc(fd->sc_drive); /* drive number */ 1014 out_fdc(bp->b_cylinder * fd->sc_type->step); 1015 1016 fd->sc_cylin = -1; 1017 fdc->sc_state = SEEKWAIT; 1018 1019 fd->sc_dk.dk_seek++; 1020 disk_busy(&fd->sc_dk); 1021 1022 callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc); 1023 return 1; 1024 1025 case DOIO: 1026 doio: 1027 if (finfo) 1028 fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) - 1029 (char *)finfo; 1030 1031 type = fd->sc_type; 1032 sec = fd->sc_blkno % type->seccyl; 1033 head = sec / type->sectrac; 1034 sec -= head * type->sectrac; 1035 nblks = type->sectrac - sec; 1036 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE); 1037 nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE); 1038 fd->sc_nblks = nblks; 1039 fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE; 1040 #ifdef DIAGNOSTIC 1041 { 1042 int block; 1043 1044 block = (fd->sc_cylin * type->heads + head) 1045 * type->sectrac + sec; 1046 if (block != fd->sc_blkno) { 1047 printf("fdcintr: block %d != blkno %qd\n", 1048 block, fd->sc_blkno); 1049 #ifdef DDB 1050 Debugger(); 1051 #endif 1052 } 1053 } 1054 #endif 1055 read = bp->b_flags & B_READ ? 1 : 0; 1056 1057 /* 1058 * Setup pseudo-DMA address & count 1059 */ 1060 fddmaaddr = bp->b_data + fd->sc_skip; 1061 fddmalen = fd->sc_nbytes; 1062 1063 wrt_fdc_reg(fdctl, type->rate); 1064 #ifdef FD_DEBUG 1065 printf("fdcintr: %s drive %d track %d head %d sec %d" 1066 " nblks %d\n", read ? "read" : "write", 1067 fd->sc_drive, fd->sc_cylin, head, sec, nblks); 1068 #endif 1069 fdc_ienable(); 1070 1071 if (finfo) { 1072 /* formatting */ 1073 if (out_fdc(NE7CMD_FORMAT) < 0) { 1074 fdc->sc_errors = 4; 1075 fdcretry(fdc); 1076 goto loop; 1077 } 1078 out_fdc((head << 2) | fd->sc_drive); 1079 out_fdc(finfo->fd_formb_secshift); 1080 out_fdc(finfo->fd_formb_nsecs); 1081 out_fdc(finfo->fd_formb_gaplen); 1082 out_fdc(finfo->fd_formb_fillbyte); 1083 } else { 1084 if (read) 1085 out_fdc(NE7CMD_READ); /* READ */ 1086 else 1087 out_fdc(NE7CMD_WRITE); /* WRITE */ 1088 out_fdc((head << 2) | fd->sc_drive); 1089 out_fdc(fd->sc_cylin); /* track */ 1090 out_fdc(head); /* head */ 1091 out_fdc(sec + 1); /* sector +1 */ 1092 out_fdc(type->secsize); /* sector size */ 1093 out_fdc(sec + nblks); /* last sectors */ 1094 out_fdc(type->gap1); /* gap1 size */ 1095 out_fdc(type->datalen); /* data length */ 1096 } 1097 fdc->sc_state = IOCOMPLETE; 1098 1099 disk_busy(&fd->sc_dk); 1100 1101 /* allow 2 seconds for operation */ 1102 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc); 1103 return 1; /* will return later */ 1104 1105 case SEEKWAIT: 1106 callout_stop(&fdc->sc_timo_ch); 1107 fdc->sc_state = SEEKCOMPLETE; 1108 /* allow 1/50 second for heads to settle */ 1109 callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc); 1110 return 1; 1111 1112 case SEEKCOMPLETE: 1113 /* no data on seek */ 1114 disk_unbusy(&fd->sc_dk, 0, 0); 1115 1116 /* Make sure seek really happened. */ 1117 out_fdc(NE7CMD_SENSEI); 1118 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || 1119 cyl != bp->b_cylinder * fd->sc_type->step) { 1120 #ifdef FD_DEBUG 1121 fdcstatus(&fd->sc_dev, 2, "seek failed"); 1122 #endif 1123 fdcretry(fdc); 1124 goto loop; 1125 } 1126 fd->sc_cylin = bp->b_cylinder; 1127 goto doio; 1128 1129 case IOTIMEDOUT: 1130 case SEEKTIMEDOUT: 1131 case RECALTIMEDOUT: 1132 case RESETTIMEDOUT: 1133 fdcretry(fdc); 1134 goto loop; 1135 1136 case IOCOMPLETE: /* IO DONE, post-analyze */ 1137 callout_stop(&fdc->sc_timo_ch); 1138 1139 disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid), 1140 (bp->b_flags & B_READ)); 1141 1142 if (fdcresult(fdc) != 7 || (st1 & 0x37) != 0) { 1143 /* 1144 * As the damn chip doesn't seem to have a FIFO, 1145 * accept a few overruns as a fact of life *sigh* 1146 */ 1147 if ((st1 & 0x10) && (++fdc->sc_overruns < 4)) { 1148 fdc->sc_state = DOSEEK; 1149 goto loop; 1150 } 1151 #ifdef FD_DEBUG 1152 fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ? 1153 "read failed" : "write failed"); 1154 printf("blkno %qd nblks %d\n", 1155 fd->sc_blkno, fd->sc_nblks); 1156 #endif 1157 fdcretry(fdc); 1158 goto loop; 1159 } 1160 if (fdc->sc_errors) { 1161 diskerr(bp, "fd", "soft error", LOG_PRINTF, 1162 fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL); 1163 printf("\n"); 1164 fdc->sc_errors = 0; 1165 } 1166 fdc->sc_overruns = 0; 1167 fd->sc_blkno += fd->sc_nblks; 1168 fd->sc_skip += fd->sc_nbytes; 1169 fd->sc_bcount -= fd->sc_nbytes; 1170 if (!finfo && fd->sc_bcount > 0) { 1171 bp->b_cylinder = fd->sc_blkno / fd->sc_type->seccyl; 1172 goto doseek; 1173 } 1174 fdfinish(fd, bp); 1175 goto loop; 1176 1177 case DORESET: 1178 /* try a reset, keep motor on */ 1179 fd_set_motor(fdc, 1); 1180 delay(100); 1181 fd_set_motor(fdc, 0); 1182 fdc->sc_state = RESETCOMPLETE; 1183 callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc); 1184 return 1; /* will return later */ 1185 1186 case RESETCOMPLETE: 1187 callout_stop(&fdc->sc_timo_ch); 1188 /* clear the controller output buffer */ 1189 for (i = 0; i < 4; i++) { 1190 out_fdc(NE7CMD_SENSEI); 1191 (void) fdcresult(fdc); 1192 } 1193 1194 /* fall through */ 1195 case DORECAL: 1196 fdc_ienable(); 1197 1198 out_fdc(NE7CMD_RECAL); /* recalibrate function */ 1199 out_fdc(fd->sc_drive); 1200 fdc->sc_state = RECALWAIT; 1201 callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc); 1202 return 1; /* will return later */ 1203 1204 case RECALWAIT: 1205 callout_stop(&fdc->sc_timo_ch); 1206 fdc->sc_state = RECALCOMPLETE; 1207 /* allow 1/30 second for heads to settle */ 1208 callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc); 1209 return 1; /* will return later */ 1210 1211 case RECALCOMPLETE: 1212 out_fdc(NE7CMD_SENSEI); 1213 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) { 1214 #ifdef FD_DEBUG 1215 fdcstatus(&fd->sc_dev, 2, "recalibrate failed"); 1216 #endif 1217 fdcretry(fdc); 1218 goto loop; 1219 } 1220 fd->sc_cylin = 0; 1221 goto doseek; 1222 1223 case MOTORWAIT: 1224 if (fd->sc_flags & FD_MOTOR_WAIT) 1225 return 1; /* time's not up yet */ 1226 goto doseek; 1227 1228 default: 1229 fdcstatus(&fd->sc_dev, 0, "stray interrupt"); 1230 return 1; 1231 } 1232 #ifdef DIAGNOSTIC 1233 panic("fdcintr: impossible"); 1234 #endif 1235 #undef st0 1236 #undef st1 1237 #undef cyl 1238 } 1239 1240 void 1241 fdcretry(fdc) 1242 struct fdc_softc *fdc; 1243 { 1244 char bits[64]; 1245 struct fd_softc *fd; 1246 struct buf *bp; 1247 1248 fd = fdc->sc_drives.tqh_first; 1249 bp = BUFQ_PEEK(&fd->sc_q); 1250 1251 if (fd->sc_opts & FDOPT_NORETRY) 1252 goto fail; 1253 1254 switch (fdc->sc_errors) { 1255 case 0: 1256 /* try again */ 1257 fdc->sc_state = DOSEEK; 1258 break; 1259 1260 case 1: case 2: case 3: 1261 /* didn't work; try recalibrating */ 1262 fdc->sc_state = DORECAL; 1263 break; 1264 1265 case 4: 1266 /* still no go; reset the bastard */ 1267 fdc->sc_state = DORESET; 1268 break; 1269 1270 default: 1271 fail: 1272 if ((fd->sc_opts & FDOPT_SILENT) == 0) { 1273 diskerr(bp, "fd", "hard error", LOG_PRINTF, 1274 fd->sc_skip / FDC_BSIZE, 1275 (struct disklabel *)NULL); 1276 1277 printf(" (st0 %s", 1278 bitmask_snprintf(fdc->sc_status[0], 1279 NE7_ST0BITS, bits, 1280 sizeof(bits))); 1281 printf(" st1 %s", 1282 bitmask_snprintf(fdc->sc_status[1], 1283 NE7_ST1BITS, bits, 1284 sizeof(bits))); 1285 printf(" st2 %s", 1286 bitmask_snprintf(fdc->sc_status[2], 1287 NE7_ST2BITS, bits, 1288 sizeof(bits))); 1289 printf(" cyl %d head %d sec %d)\n", 1290 fdc->sc_status[3], 1291 fdc->sc_status[4], 1292 fdc->sc_status[5]); 1293 } 1294 bp->b_flags |= B_ERROR; 1295 bp->b_error = EIO; 1296 fdfinish(fd, bp); 1297 } 1298 fdc->sc_errors++; 1299 } 1300 1301 int 1302 fdioctl(dev, cmd, addr, flag, p) 1303 dev_t dev; 1304 u_long cmd; 1305 caddr_t addr; 1306 int flag; 1307 struct proc *p; 1308 { 1309 struct fd_softc *fd; 1310 struct disklabel buffer; 1311 int error; 1312 struct fdformat_parms *form_parms; 1313 struct fdformat_cmd *form_cmd; 1314 struct ne7_fd_formb *fd_formb; 1315 unsigned int scratch; 1316 int il[FD_MAX_NSEC + 1]; 1317 register int i, j; 1318 1319 fd = hdfd_cd.cd_devs[FDUNIT(dev)]; 1320 1321 switch (cmd) { 1322 case DIOCGDINFO: 1323 fdgetdisklabel(fd, dev); 1324 *(struct disklabel *)addr = *(fd->sc_dk.dk_label); 1325 return 0; 1326 1327 case DIOCGPART: 1328 fdgetdisklabel(fd, dev); 1329 ((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label; 1330 ((struct partinfo *)addr)->part = 1331 &fd->sc_dk.dk_label->d_partitions[RAW_PART]; 1332 return(0); 1333 1334 case DIOCWLABEL: 1335 if ((flag & FWRITE) == 0) 1336 return EBADF; 1337 /* XXX do something */ 1338 return 0; 1339 1340 case DIOCSDINFO: 1341 case DIOCWDINFO: 1342 if ((flag & FWRITE) == 0) 1343 return EBADF; 1344 1345 fd->sc_flags &= ~FD_HAVELAB; /* Invalid */ 1346 error = setdisklabel(&buffer, (struct disklabel *)addr, 0,NULL); 1347 if (error) 1348 return error; 1349 1350 if (cmd == DIOCWDINFO) 1351 error = writedisklabel(dev, fdstrategy, &buffer, NULL); 1352 return error; 1353 1354 case FDIOCGETFORMAT: 1355 form_parms = (struct fdformat_parms *)addr; 1356 form_parms->fdformat_version = FDFORMAT_VERSION; 1357 form_parms->nbps = 128 * (1 << fd->sc_type->secsize); 1358 form_parms->ncyl = fd->sc_type->tracks; 1359 form_parms->nspt = fd->sc_type->sectrac; 1360 form_parms->ntrk = fd->sc_type->heads; 1361 form_parms->stepspercyl = fd->sc_type->step; 1362 form_parms->gaplen = fd->sc_type->gap2; 1363 form_parms->fillbyte = fd->sc_type->fillbyte; 1364 form_parms->interleave = fd->sc_type->interleave; 1365 switch (fd->sc_type->rate) { 1366 case FDC_500KBPS: 1367 form_parms->xfer_rate = 500 * 1024; 1368 break; 1369 case FDC_300KBPS: 1370 form_parms->xfer_rate = 300 * 1024; 1371 break; 1372 case FDC_250KBPS: 1373 form_parms->xfer_rate = 250 * 1024; 1374 break; 1375 case FDC_125KBPS: 1376 form_parms->xfer_rate = 125 * 1024; 1377 break; 1378 default: 1379 return EINVAL; 1380 } 1381 return 0; 1382 1383 case FDIOCSETFORMAT: 1384 if((flag & FWRITE) == 0) 1385 return EBADF; /* must be opened for writing */ 1386 form_parms = (struct fdformat_parms *)addr; 1387 if (form_parms->fdformat_version != FDFORMAT_VERSION) 1388 return EINVAL; /* wrong version of formatting prog */ 1389 1390 scratch = form_parms->nbps >> 7; 1391 if ((form_parms->nbps & 0x7f) || ffs(scratch) == 0 || 1392 scratch & ~(1 << (ffs(scratch)-1))) 1393 /* not a power-of-two multiple of 128 */ 1394 return EINVAL; 1395 1396 switch (form_parms->xfer_rate) { 1397 case 500 * 1024: 1398 fd->sc_type->rate = FDC_500KBPS; 1399 break; 1400 case 300 * 1024: 1401 fd->sc_type->rate = FDC_300KBPS; 1402 break; 1403 case 250 * 1024: 1404 fd->sc_type->rate = FDC_250KBPS; 1405 break; 1406 case 125 * 1024: 1407 fd->sc_type->rate = FDC_125KBPS; 1408 break; 1409 default: 1410 return EINVAL; 1411 } 1412 1413 if (form_parms->nspt > FD_MAX_NSEC || 1414 form_parms->fillbyte > 0xff || 1415 form_parms->interleave > 0xff) 1416 return EINVAL; 1417 fd->sc_type->sectrac = form_parms->nspt; 1418 if (form_parms->ntrk != 2 && form_parms->ntrk != 1) 1419 return EINVAL; 1420 fd->sc_type->heads = form_parms->ntrk; 1421 fd->sc_type->seccyl = form_parms->nspt * form_parms->ntrk; 1422 fd->sc_type->secsize = ffs(scratch)-1; 1423 fd->sc_type->gap2 = form_parms->gaplen; 1424 fd->sc_type->tracks = form_parms->ncyl; 1425 fd->sc_type->size = fd->sc_type->seccyl * form_parms->ncyl * 1426 form_parms->nbps / DEV_BSIZE; 1427 fd->sc_type->step = form_parms->stepspercyl; 1428 fd->sc_type->fillbyte = form_parms->fillbyte; 1429 fd->sc_type->interleave = form_parms->interleave; 1430 return 0; 1431 1432 case FDIOCFORMAT_TRACK: 1433 if((flag & FWRITE) == 0) 1434 return EBADF; /* must be opened for writing */ 1435 form_cmd = (struct fdformat_cmd *)addr; 1436 if (form_cmd->formatcmd_version != FDFORMAT_VERSION) 1437 return EINVAL; /* wrong version of formatting prog */ 1438 1439 if (form_cmd->head >= fd->sc_type->heads || 1440 form_cmd->cylinder >= fd->sc_type->tracks) { 1441 return EINVAL; 1442 } 1443 1444 fd_formb = malloc(sizeof(struct ne7_fd_formb), 1445 M_TEMP, M_NOWAIT); 1446 if (fd_formb == 0) 1447 return ENOMEM; 1448 1449 fd_formb->head = form_cmd->head; 1450 fd_formb->cyl = form_cmd->cylinder; 1451 fd_formb->transfer_rate = fd->sc_type->rate; 1452 fd_formb->fd_formb_secshift = fd->sc_type->secsize; 1453 fd_formb->fd_formb_nsecs = fd->sc_type->sectrac; 1454 fd_formb->fd_formb_gaplen = fd->sc_type->gap2; 1455 fd_formb->fd_formb_fillbyte = fd->sc_type->fillbyte; 1456 1457 bzero(il,sizeof il); 1458 for (j = 0, i = 1; i <= fd_formb->fd_formb_nsecs; i++) { 1459 while (il[(j%fd_formb->fd_formb_nsecs)+1]) 1460 j++; 1461 il[(j%fd_formb->fd_formb_nsecs)+1] = i; 1462 j += fd->sc_type->interleave; 1463 } 1464 for (i = 0; i < fd_formb->fd_formb_nsecs; i++) { 1465 fd_formb->fd_formb_cylno(i) = form_cmd->cylinder; 1466 fd_formb->fd_formb_headno(i) = form_cmd->head; 1467 fd_formb->fd_formb_secno(i) = il[i+1]; 1468 fd_formb->fd_formb_secsize(i) = fd->sc_type->secsize; 1469 } 1470 1471 error = fdformat(dev, fd_formb, p); 1472 free(fd_formb, M_TEMP); 1473 return error; 1474 1475 case FDIOCGETOPTS: /* get drive options */ 1476 *(int *)addr = fd->sc_opts; 1477 return 0; 1478 1479 case FDIOCSETOPTS: /* set drive options */ 1480 fd->sc_opts = *(int *)addr; 1481 return 0; 1482 1483 1484 default: 1485 return ENOTTY; 1486 } 1487 1488 #ifdef DIAGNOSTIC 1489 panic("fdioctl: impossible"); 1490 #endif 1491 } 1492 1493 int 1494 fdformat(dev, finfo, p) 1495 dev_t dev; 1496 struct ne7_fd_formb *finfo; 1497 struct proc *p; 1498 { 1499 int rv = 0, s; 1500 struct fd_softc *fd = hdfd_cd.cd_devs[FDUNIT(dev)]; 1501 struct fd_type *type = fd->sc_type; 1502 struct buf *bp; 1503 1504 /* set up a buffer header for fdstrategy() */ 1505 bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT); 1506 if(bp == 0) 1507 return ENOBUFS; 1508 bzero((void *)bp, sizeof(struct buf)); 1509 bp->b_flags = B_BUSY | B_PHYS | B_FORMAT; 1510 bp->b_proc = p; 1511 bp->b_dev = dev; 1512 1513 /* 1514 * calculate a fake blkno, so fdstrategy() would initiate a 1515 * seek to the requested cylinder 1516 */ 1517 bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads) 1518 + finfo->head * type->sectrac) * FDC_BSIZE / DEV_BSIZE; 1519 1520 bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs; 1521 bp->b_data = (caddr_t)finfo; 1522 1523 #ifdef DEBUG 1524 printf("fdformat: blkno %x count %lx\n", bp->b_blkno, bp->b_bcount); 1525 #endif 1526 1527 /* now do the format */ 1528 fdstrategy(bp); 1529 1530 /* ...and wait for it to complete */ 1531 s = splbio(); 1532 while(!(bp->b_flags & B_DONE)) { 1533 rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz); 1534 if (rv == EWOULDBLOCK) 1535 break; 1536 } 1537 splx(s); 1538 1539 if (rv == EWOULDBLOCK) { 1540 /* timed out */ 1541 rv = EIO; 1542 biodone(bp); 1543 } 1544 if(bp->b_flags & B_ERROR) { 1545 rv = bp->b_error; 1546 } 1547 free(bp, M_TEMP); 1548 return rv; 1549 } 1550 1551 1552 /* 1553 * Obtain a disklabel. Either a real one from the disk or, if there 1554 * is none, a fake one. 1555 */ 1556 static void 1557 fdgetdisklabel(fd, dev) 1558 struct fd_softc *fd; 1559 dev_t dev; 1560 { 1561 struct disklabel *lp; 1562 struct cpu_disklabel cpulab; 1563 1564 if (fd->sc_flags & FD_HAVELAB) 1565 return; /* Already got one */ 1566 1567 lp = fd->sc_dk.dk_label; 1568 1569 bzero(lp, sizeof(*lp)); 1570 bzero(&cpulab, sizeof(cpulab)); 1571 1572 lp->d_secpercyl = fd->sc_type->seccyl; 1573 lp->d_type = DTYPE_FLOPPY; 1574 lp->d_secsize = FDC_BSIZE; 1575 lp->d_secperunit = fd->sc_type->size; 1576 1577 /* 1578 * If there is no label on the disk: fake one 1579 */ 1580 if (readdisklabel(dev, fdstrategy, lp, &cpulab) != NULL) 1581 fdgetdefaultlabel(fd, lp, RAW_PART); 1582 fd->sc_flags |= FD_HAVELAB; 1583 1584 if ((FDC_BSIZE * fd->sc_type->size) 1585 < (lp->d_secsize * lp->d_secperunit)) { 1586 /* 1587 * XXX: Ignore these fields. If you drop a vnddisk 1588 * on more than one floppy, you'll get disturbing 1589 * sounds! 1590 */ 1591 lp->d_secpercyl = fd->sc_type->seccyl; 1592 lp->d_type = DTYPE_FLOPPY; 1593 lp->d_secsize = FDC_BSIZE; 1594 lp->d_secperunit = fd->sc_type->size; 1595 } 1596 } 1597 1598 /* 1599 * Build defaultdisk label. For now we only create a label from what we 1600 * know from 'sc'. 1601 */ 1602 static void 1603 fdgetdefaultlabel(fd, lp, part) 1604 struct fd_softc *fd; 1605 struct disklabel *lp; 1606 int part; 1607 { 1608 bzero(lp, sizeof(struct disklabel)); 1609 1610 lp->d_secsize = 128 * (1 << fd->sc_type->secsize); 1611 lp->d_ntracks = fd->sc_type->heads; 1612 lp->d_nsectors = fd->sc_type->sectrac; 1613 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 1614 lp->d_ncylinders = fd->sc_type->size / lp->d_secpercyl; 1615 lp->d_secperunit = fd->sc_type->size; 1616 1617 lp->d_type = DTYPE_FLOPPY; 1618 lp->d_rpm = 300; /* good guess I suppose. */ 1619 lp->d_interleave = 1; /* FIXME: is this OK? */ 1620 lp->d_bbsize = 0; 1621 lp->d_sbsize = 0; 1622 lp->d_npartitions = part + 1; 1623 lp->d_trkseek = 6000; /* Who cares... */ 1624 lp->d_magic = DISKMAGIC; 1625 lp->d_magic2 = DISKMAGIC; 1626 lp->d_checksum = dkcksum(lp); 1627 lp->d_partitions[part].p_size = lp->d_secperunit; 1628 lp->d_partitions[part].p_fstype = FS_UNUSED; 1629 lp->d_partitions[part].p_fsize = 1024; 1630 lp->d_partitions[part].p_frag = 8; 1631 } 1632