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