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