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