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