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