1 /* $NetBSD: fd.c,v 1.23 2005/12/24 20:06:46 perry Exp $ */ 2 3 /*- 4 * Copyright (c) 1998 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 * from: fd.c,v 1.104 1997/01/09 04:30:08 mycroft Exp 72 */ 73 74 /* 75 * Floppy formatting facilities merged from FreeBSD fd.c driver: 76 * Id: fd.c,v 1.53 1995/03/12 22:40:56 joerg Exp 77 * which carries the same copyright/redistribution notice as shown above with 78 * the addition of the following statement before the "Redistribution and 79 * use ..." clause: 80 * 81 * Copyright (c) 1993, 1994 by 82 * jc@irbs.UUCP (John Capo) 83 * vak@zebub.msk.su (Serge Vakulenko) 84 * ache@astral.msk.su (Andrew A. Chernov) 85 * 86 * Copyright (c) 1993, 1994, 1995 by 87 * joerg_wunsch@uriah.sax.de (Joerg Wunsch) 88 * dufault@hda.com (Peter Dufault) 89 */ 90 91 #include <sys/cdefs.h> 92 __KERNEL_RCSID(0, "$NetBSD: fd.c,v 1.23 2005/12/24 20:06:46 perry Exp $"); 93 94 #include "opt_ddb.h" 95 96 #include <sys/param.h> 97 #include <sys/systm.h> 98 #include <sys/callout.h> 99 #include <sys/kernel.h> 100 #include <sys/file.h> 101 #include <sys/ioctl.h> 102 #include <sys/device.h> 103 #include <sys/disklabel.h> 104 #include <sys/disk.h> 105 #include <sys/buf.h> 106 #include <sys/bufq.h> 107 #include <sys/malloc.h> 108 #include <sys/uio.h> 109 #include <sys/syslog.h> 110 #include <sys/queue.h> 111 #include <sys/proc.h> 112 #include <sys/fdio.h> 113 #include <sys/conf.h> 114 115 #include <uvm/uvm_extern.h> 116 117 #include <arm/fiq.h> 118 119 #include <machine/cpu.h> 120 #include <machine/intr.h> 121 #include <machine/io.h> 122 #include <arm/arm32/katelib.h> 123 #include <machine/bus.h> 124 125 #include <arm/iomd/iomdreg.h> 126 #include <arm/iomd/iomdvar.h> 127 128 #include <acorn32/mainbus/piocvar.h> 129 #include <acorn32/mainbus/fdreg.h> 130 131 #include "locators.h" 132 133 #define NE7CMD_CONFIGURE 0x13 134 135 #define FDUNIT(dev) (minor(dev) / 8) 136 #define FDTYPE(dev) (minor(dev) % 8) 137 138 /* XXX misuse a flag to identify format operation */ 139 #define B_FORMAT B_XXX 140 141 enum fdc_state { 142 DEVIDLE = 0, 143 MOTORWAIT, 144 DOSEEK, 145 SEEKWAIT, 146 SEEKTIMEDOUT, 147 SEEKCOMPLETE, 148 DOIO, 149 IOCOMPLETE, 150 IOTIMEDOUT, 151 DORESET, 152 RESETCOMPLETE, 153 RESETTIMEDOUT, 154 DORECAL, 155 RECALWAIT, 156 RECALTIMEDOUT, 157 RECALCOMPLETE, 158 }; 159 160 /* software state, per controller */ 161 struct fdc_softc { 162 struct device sc_dev; /* boilerplate */ 163 void *sc_ih; 164 165 bus_space_tag_t sc_iot; /* ISA i/o space identifier */ 166 bus_space_handle_t sc_ioh; /* ISA io handle */ 167 168 struct callout sc_timo_ch; /* timeout callout */ 169 struct callout sc_intr_ch; /* pseudo-intr callout */ 170 171 /* ...for pseudo-DMA... */ 172 struct fiqhandler sc_fh; /* FIQ handler descriptor */ 173 struct fiqregs sc_fr; /* FIQ handler reg context */ 174 int sc_drq; 175 176 struct fd_softc *sc_fd[4]; /* pointers to children */ 177 TAILQ_HEAD(drivehead, fd_softc) sc_drives; 178 enum fdc_state sc_state; 179 int sc_errors; /* number of retries so far */ 180 u_char sc_status[7]; /* copy of registers */ 181 }; 182 183 /* controller driver configuration */ 184 int fdcprobe __P((struct device *, struct cfdata *, void *)); 185 int fdprint __P((void *, const char *)); 186 void fdcattach __P((struct device *, struct device *, void *)); 187 188 CFATTACH_DECL(fdc, sizeof(struct fdc_softc), 189 fdcprobe, fdcattach, NULL, NULL); 190 191 /* 192 * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how 193 * we tell them apart. 194 */ 195 struct fd_type { 196 int sectrac; /* sectors per track */ 197 int heads; /* number of heads */ 198 int seccyl; /* sectors per cylinder */ 199 int secsize; /* size code for sectors */ 200 int datalen; /* data len when secsize = 0 */ 201 int steprate; /* step rate and head unload time */ 202 int gap1; /* gap len between sectors */ 203 int gap2; /* formatting gap */ 204 int cyls; /* total num of cylinders */ 205 int size; /* size of disk in sectors */ 206 int step; /* steps per cylinder */ 207 int rate; /* transfer speed code */ 208 u_char fillbyte; /* format fill byte */ 209 u_char interleave; /* interleave factor (formatting) */ 210 const char *name; 211 }; 212 213 /* The order of entries in the following table is important -- BEWARE! */ 214 struct fd_type fd_types[] = { 215 { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,0xf6,1, "1.44MB" }, /* 1.44MB diskette */ 216 { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS,0xf6,1, "1.2MB" }, /* 1.2 MB AT-diskettes */ 217 { 9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS,0xf6,1, "360KB/AT" }, /* 360kB in 1.2MB drive */ 218 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS,0xf6,1, "360KB/PC" }, /* 360kB PC diskettes */ 219 { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS,0xf6,1, "720KB" }, /* 3.5" 720kB diskette */ 220 { 9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS,0xf6,1, "720KB/x" }, /* 720kB in 1.2MB drive */ 221 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS,0xf6,1, "360KB/x" }, /* 360kB in 720kB drive */ 222 }; 223 224 /* software state, per disk (with up to 4 disks per ctlr) */ 225 struct fd_softc { 226 struct device sc_dev; 227 struct disk sc_dk; 228 229 struct fd_type *sc_deftype; /* default type descriptor */ 230 struct fd_type *sc_type; /* current type descriptor */ 231 struct fd_type sc_type_copy; /* copy for fiddling when formatting */ 232 233 struct callout sc_motoron_ch; 234 struct callout sc_motoroff_ch; 235 236 daddr_t sc_blkno; /* starting block number */ 237 int sc_bcount; /* byte count left */ 238 int sc_opts; /* user-set options */ 239 int sc_skip; /* bytes already transferred */ 240 int sc_nblks; /* number of blocks currently transferring */ 241 int sc_nbytes; /* number of bytes currently transferring */ 242 243 int sc_drive; /* physical unit number */ 244 int sc_flags; 245 #define FD_OPEN 0x01 /* it's open */ 246 #define FD_MOTOR 0x02 /* motor should be on */ 247 #define FD_MOTOR_WAIT 0x04 /* motor coming up */ 248 int sc_cylin; /* where we think the head is */ 249 250 void *sc_sdhook; /* saved shutdown hook for drive. */ 251 252 TAILQ_ENTRY(fd_softc) sc_drivechain; 253 int sc_ops; /* I/O ops since last switch */ 254 struct bufq_state *sc_q;/* pending I/O requests */ 255 int sc_active; /* number of active I/O operations */ 256 }; 257 258 /* floppy driver configuration */ 259 int fdprobe __P((struct device *, struct cfdata *, void *)); 260 void fdattach __P((struct device *, struct device *, void *)); 261 262 extern char floppy_read_fiq[], floppy_read_fiq_end[]; 263 extern char floppy_write_fiq[], floppy_write_fiq_end[]; 264 265 CFATTACH_DECL(fd, sizeof(struct fd_softc), 266 fdprobe, fdattach, NULL, NULL); 267 268 extern struct cfdriver fd_cd; 269 270 dev_type_open(fdopen); 271 dev_type_close(fdclose); 272 dev_type_read(fdread); 273 dev_type_write(fdwrite); 274 dev_type_ioctl(fdioctl); 275 dev_type_strategy(fdstrategy); 276 277 const struct bdevsw fd_bdevsw = { 278 fdopen, fdclose, fdstrategy, fdioctl, nodump, nosize, D_DISK 279 }; 280 281 const struct cdevsw fd_cdevsw = { 282 fdopen, fdclose, fdread, fdwrite, fdioctl, 283 nostop, notty, nopoll, nommap, nokqfilter, D_DISK 284 }; 285 286 void fdgetdisklabel __P((struct fd_softc *)); 287 int fd_get_parms __P((struct fd_softc *)); 288 void fdstart __P((struct fd_softc *)); 289 290 struct dkdriver fddkdriver = { fdstrategy }; 291 292 struct fd_type *fd_nvtotype __P((char *, int, int)); 293 void fd_set_motor __P((struct fdc_softc *fdc, int reset)); 294 void fd_motor_off __P((void *arg)); 295 void fd_motor_on __P((void *arg)); 296 int fdcresult __P((struct fdc_softc *fdc)); 297 int out_fdc __P((bus_space_tag_t iot, bus_space_handle_t ioh, u_char x)); 298 void fdcstart __P((struct fdc_softc *fdc)); 299 void fdcstatus __P((struct device *dv, int n, const char *s)); 300 void fdctimeout __P((void *arg)); 301 void fdcpseudointr __P((void *arg)); 302 int fdcintr __P((void *)); 303 void fdcretry __P((struct fdc_softc *fdc)); 304 void fdfinish __P((struct fd_softc *fd, struct buf *bp)); 305 inline struct fd_type *fd_dev_to_type __P((struct fd_softc *, dev_t)); 306 int fdformat __P((dev_t, struct ne7_fd_formb *, struct lwp *)); 307 308 int 309 fdcprobe(parent, cf, aux) 310 struct device *parent; 311 struct cfdata *cf; 312 void *aux; 313 { 314 struct pioc_attach_args *pa = aux; 315 bus_space_tag_t iot; 316 bus_space_handle_t ioh; 317 int rv; 318 319 if (pa->pa_name && strcmp(pa->pa_name, "fdc") != 0) 320 return(0); 321 322 iot = pa->pa_iot; 323 rv = 0; 324 325 /* Map the i/o space. */ 326 if (bus_space_map(iot, pa->pa_iobase + pa->pa_offset, FDC_NPORT, 0, &ioh)) 327 return 0; 328 329 /* reset */ 330 bus_space_write_2(iot, ioh, fdout, 0); 331 delay(100); 332 bus_space_write_2(iot, ioh, fdout, FDO_FRST); 333 334 /* see if it can handle a command */ 335 if (out_fdc(iot, ioh, NE7CMD_SPECIFY) < 0) 336 goto out; 337 out_fdc(iot, ioh, 0xdf); 338 out_fdc(iot, ioh, 2); 339 340 rv = 1; 341 pa->pa_iosize = FDC_NPORT; 342 343 out: 344 bus_space_unmap(iot, ioh, FDC_NPORT); 345 return rv; 346 } 347 348 /* 349 * Arguments passed between fdcattach and fdprobe. 350 */ 351 struct fdc_attach_args { 352 int fa_drive; 353 struct fd_type *fa_deftype; 354 }; 355 356 /* 357 * Print the location of a disk drive (called just before attaching the 358 * the drive). If `fdc' is not NULL, the drive was found but was not 359 * in the system config file; print the drive name as well. 360 * Return QUIET (config_find ignores this if the device was configured) to 361 * avoid printing `fdN not configured' messages. 362 */ 363 int 364 fdprint(aux, fdc) 365 void *aux; 366 const char *fdc; 367 { 368 register struct fdc_attach_args *fa = aux; 369 370 if (!fdc) 371 aprint_normal(" drive %d", fa->fa_drive); 372 return QUIET; 373 } 374 375 void 376 fdcattach(parent, self, aux) 377 struct device *parent, *self; 378 void *aux; 379 { 380 struct fdc_softc *fdc = (void *)self; 381 bus_space_tag_t iot; 382 bus_space_handle_t ioh; 383 struct pioc_attach_args *pa = aux; 384 struct fdc_attach_args fa; 385 int type; 386 387 iot = pa->pa_iot; 388 389 /* Re-map the I/O space. */ 390 if (bus_space_map(iot, pa->pa_iobase + pa->pa_offset, FDC_NPORT, 0, &ioh)) 391 panic("fdcattach: couldn't map I/O ports"); 392 393 fdc->sc_iot = iot; 394 fdc->sc_ioh = ioh; 395 396 fdc->sc_drq = pa->pa_iobase + pa->pa_offset + pa->pa_drq; 397 fdc->sc_state = DEVIDLE; 398 TAILQ_INIT(&fdc->sc_drives); 399 400 printf("\n"); 401 402 callout_init(&fdc->sc_timo_ch); 403 callout_init(&fdc->sc_intr_ch); 404 405 fdc->sc_ih = intr_claim(pa->pa_irq, IPL_BIO, "fdc", 406 fdcintr, fdc); 407 if (!fdc->sc_ih) 408 panic("%s: Cannot claim IRQ %d", self->dv_xname, pa->pa_irq); 409 410 #if 0 411 /* 412 * The NVRAM info only tells us about the first two disks on the 413 * `primary' floppy controller. 414 */ 415 if (fdc->sc_dev.dv_unit == 0) 416 type = mc146818_read(NULL, NVRAM_DISKETTE); /* XXX softc */ 417 else 418 type = -1; 419 #endif 420 type = 0x10; /* XXX - hardcoded for 1 floppy */ 421 422 /* physical limit: four drives per controller. */ 423 for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) { 424 if (type >= 0 && fa.fa_drive < 2) 425 fa.fa_deftype = fd_nvtotype(fdc->sc_dev.dv_xname, 426 type, fa.fa_drive); 427 else 428 fa.fa_deftype = NULL; /* unknown */ 429 (void)config_found(self, (void *)&fa, fdprint); 430 } 431 } 432 433 int 434 fdprobe(parent, cf, aux) 435 struct device *parent; 436 struct cfdata *cf; 437 void *aux; 438 { 439 struct fdc_softc *fdc = (void *)parent; 440 struct fdc_attach_args *fa = aux; 441 int drive = fa->fa_drive; 442 bus_space_tag_t iot = fdc->sc_iot; 443 bus_space_handle_t ioh = fdc->sc_ioh; 444 int n; 445 446 if (cf->cf_loc[FDCCF_DRIVE] != FDCCF_DRIVE_DEFAULT 447 && cf->cf_loc[FDCCF_DRIVE] != drive) 448 return 0; 449 /* 450 * XXX 451 * This is to work around some odd interactions between this driver 452 * and SMC Ethernet cards. 453 */ 454 455 /* Don't need this for arm32 port but leave for the time being (it won't hurt) */ 456 457 if (cf->cf_loc[FDCCF_DRIVE] == FDCCF_DRIVE_DEFAULT && drive >= 2) 458 return 0; 459 460 /* select drive and turn on motor */ 461 bus_space_write_2(iot, ioh, fdout, drive | FDO_FRST | FDO_MOEN(drive)); 462 /* wait for motor to spin up */ 463 delay(250000); 464 out_fdc(iot, ioh, NE7CMD_RECAL); 465 out_fdc(iot, ioh, drive); 466 /* wait for recalibrate */ 467 delay(2000000); 468 out_fdc(iot, ioh, NE7CMD_SENSEI); 469 n = fdcresult(fdc); 470 #ifdef FD_DEBUG 471 { 472 int i; 473 printf("fdprobe: status"); 474 for (i = 0; i < n; i++) 475 printf(" %x", fdc->sc_status[i]); 476 printf("\n"); 477 } 478 #endif 479 /* turn off motor */ 480 bus_space_write_1(iot, ioh, fdout, FDO_FRST); 481 482 if (n != 2 || (fdc->sc_status[0] & 0xf8) != 0x20) 483 return 0; 484 485 return 1; 486 } 487 488 /* 489 * Controller is working, and drive responded. Attach it. 490 */ 491 void 492 fdattach(parent, self, aux) 493 struct device *parent, *self; 494 void *aux; 495 { 496 struct fdc_softc *fdc = (void *)parent; 497 struct fd_softc *fd = (void *)self; 498 struct fdc_attach_args *fa = aux; 499 struct fd_type *type = fa->fa_deftype; 500 int drive = fa->fa_drive; 501 502 callout_init(&fd->sc_motoron_ch); 503 callout_init(&fd->sc_motoroff_ch); 504 505 /* XXX Allow `flags' to override device type? */ 506 507 if (type) 508 printf(": %s %d cyl, %d head, %d sec\n", type->name, 509 type->cyls, type->heads, type->sectrac); 510 else 511 printf(": density unknown\n"); 512 513 bufq_alloc(&fd->sc_q, "disksort", BUFQ_SORT_CYLINDER); 514 fd->sc_cylin = -1; 515 fd->sc_drive = drive; 516 fd->sc_deftype = type; 517 fdc->sc_fd[drive] = fd; 518 519 /* 520 * Initialize and attach the disk structure. 521 */ 522 fd->sc_dk.dk_name = fd->sc_dev.dv_xname; 523 fd->sc_dk.dk_driver = &fddkdriver; 524 disk_attach(&fd->sc_dk); 525 526 /* Needed to power off if the motor is on when we halt. */ 527 528 } 529 530 /* 531 * Translate nvram type into internal data structure. Return NULL for 532 * none/unknown/unusable. 533 */ 534 struct fd_type * 535 fd_nvtotype(fdc, nvraminfo, drive) 536 char *fdc; 537 int nvraminfo, drive; 538 { 539 int type; 540 541 type = (drive == 0 ? nvraminfo : nvraminfo << 4) & 0xf0; 542 switch (type) { 543 #ifndef RC7500 544 case 0x00 : 545 return NULL; 546 #else 547 case 0x00 : 548 #endif /* !RC7500 */ 549 case 0x10 : 550 return &fd_types[0]; 551 default: 552 printf("%s: drive %d: unknown device type 0x%x\n", 553 fdc, drive, type); 554 return NULL; 555 } 556 } 557 558 inline struct fd_type * 559 fd_dev_to_type(fd, dev) 560 struct fd_softc *fd; 561 dev_t dev; 562 { 563 int type = FDTYPE(dev); 564 565 if (type > (sizeof(fd_types) / sizeof(fd_types[0]))) 566 return NULL; 567 return type ? &fd_types[type - 1] : fd->sc_deftype; 568 } 569 570 void 571 fdstrategy(bp) 572 register struct buf *bp; /* IO operation to perform */ 573 { 574 struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(bp->b_dev)]; 575 int sz; 576 int s; 577 578 /* Valid unit, controller, and request? */ 579 if (bp->b_blkno < 0 || 580 ((bp->b_bcount % FDC_BSIZE) != 0 && 581 (bp->b_flags & B_FORMAT) == 0)) { 582 bp->b_error = EINVAL; 583 goto bad; 584 } 585 586 /* If it's a null transfer, return immediately. */ 587 if (bp->b_bcount == 0) 588 goto done; 589 590 sz = howmany(bp->b_bcount, FDC_BSIZE); 591 592 if (bp->b_blkno + sz > fd->sc_type->size) { 593 sz = fd->sc_type->size - bp->b_blkno; 594 if (sz == 0) { 595 /* If exactly at end of disk, return EOF. */ 596 goto done; 597 } 598 if (sz < 0) { 599 /* If past end of disk, return EINVAL. */ 600 bp->b_error = EINVAL; 601 goto bad; 602 } 603 /* Otherwise, truncate request. */ 604 bp->b_bcount = sz << DEV_BSHIFT; 605 } 606 607 bp->b_rawblkno = bp->b_blkno; 608 bp->b_cylinder = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE) / fd->sc_type->seccyl; 609 610 #ifdef FD_DEBUG 611 printf("fdstrategy: b_blkno %d b_bcount %d blkno %d cylin %d sz %d\n", 612 bp->b_blkno, bp->b_bcount, fd->sc_blkno, bp->b_cylinder, sz); 613 #endif 614 615 /* Queue transfer on drive, activate drive and controller if idle. */ 616 s = splbio(); 617 BUFQ_PUT(fd->sc_q, bp); 618 callout_stop(&fd->sc_motoroff_ch); /* a good idea */ 619 if (fd->sc_active == 0) 620 fdstart(fd); 621 #ifdef DIAGNOSTIC 622 else { 623 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; 624 if (fdc->sc_state == DEVIDLE) { 625 printf("fdstrategy: controller inactive\n"); 626 fdcstart(fdc); 627 } 628 } 629 #endif 630 splx(s); 631 return; 632 633 bad: 634 bp->b_flags |= B_ERROR; 635 done: 636 /* Toss transfer; we're done early. */ 637 bp->b_resid = bp->b_bcount; 638 biodone(bp); 639 } 640 641 void 642 fdstart(fd) 643 struct fd_softc *fd; 644 { 645 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; 646 int active = fdc->sc_drives.tqh_first != 0; 647 648 /* Link into controller queue. */ 649 fd->sc_active = 1; 650 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); 651 652 /* If controller not already active, start it. */ 653 if (!active) 654 fdcstart(fdc); 655 } 656 657 void 658 fdfinish(fd, bp) 659 struct fd_softc *fd; 660 struct buf *bp; 661 { 662 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; 663 664 /* 665 * Move this drive to the end of the queue to give others a `fair' 666 * chance. We only force a switch if N operations are completed while 667 * another drive is waiting to be serviced, since there is a long motor 668 * startup delay whenever we switch. 669 */ 670 (void)BUFQ_GET(fd->sc_q); 671 if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) { 672 fd->sc_ops = 0; 673 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); 674 if (BUFQ_PEEK(fd->sc_q) != NULL) 675 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); 676 else 677 fd->sc_active = 0; 678 } 679 bp->b_resid = fd->sc_bcount; 680 fd->sc_skip = 0; 681 682 biodone(bp); 683 /* turn off motor 5s from now */ 684 callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd); 685 fdc->sc_state = DEVIDLE; 686 } 687 688 int 689 fdread(dev, uio, flags) 690 dev_t dev; 691 struct uio *uio; 692 int flags; 693 { 694 695 return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio)); 696 } 697 698 int 699 fdwrite(dev, uio, flags) 700 dev_t dev; 701 struct uio *uio; 702 int flags; 703 { 704 705 return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio)); 706 } 707 708 void 709 fd_set_motor(fdc, reset) 710 struct fdc_softc *fdc; 711 int reset; 712 { 713 struct fd_softc *fd; 714 u_char status; 715 int n; 716 717 if ((fd = fdc->sc_drives.tqh_first) != NULL) 718 status = fd->sc_drive; 719 else 720 status = 0; 721 if (!reset) 722 status |= FDO_FRST | FDO_FDMAEN; 723 for (n = 0; n < 4; n++) 724 if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR)) 725 status |= FDO_MOEN(n); 726 bus_space_write_2(fdc->sc_iot, fdc->sc_ioh, fdout, status); 727 } 728 729 void 730 fd_motor_off(arg) 731 void *arg; 732 { 733 struct fd_softc *fd = arg; 734 int s; 735 736 s = splbio(); 737 fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); 738 fd_set_motor((struct fdc_softc *)fd->sc_dev.dv_parent, 0); 739 splx(s); 740 } 741 742 void 743 fd_motor_on(arg) 744 void *arg; 745 { 746 struct fd_softc *fd = arg; 747 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; 748 int s; 749 750 s = splbio(); 751 fd->sc_flags &= ~FD_MOTOR_WAIT; 752 if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT)) 753 (void) fdcintr(fdc); 754 splx(s); 755 } 756 757 int 758 fdcresult(fdc) 759 struct fdc_softc *fdc; 760 { 761 bus_space_tag_t iot = fdc->sc_iot; 762 bus_space_handle_t ioh = fdc->sc_ioh; 763 u_char i; 764 int j = 100000, 765 n = 0; 766 767 for (; j; j--) { 768 i = bus_space_read_1(iot, ioh, fdsts) & 769 (NE7_DIO | NE7_RQM | NE7_CB); 770 if (i == NE7_RQM) 771 return n; 772 if (i == (NE7_DIO | NE7_RQM | NE7_CB)) { 773 if (n >= sizeof(fdc->sc_status)) { 774 log(LOG_ERR, "fdcresult: overrun\n"); 775 return -1; 776 } 777 fdc->sc_status[n++] = 778 bus_space_read_1(iot, ioh, fddata); 779 } 780 delay(10); 781 } 782 log(LOG_ERR, "fdcresult: timeout\n"); 783 return -1; 784 } 785 786 int 787 out_fdc(iot, ioh, x) 788 bus_space_tag_t iot; 789 bus_space_handle_t ioh; 790 u_char x; 791 { 792 int i = 100000; 793 794 while ((bus_space_read_1(iot, ioh, fdsts) & NE7_DIO) && i-- > 0); 795 if (i <= 0) 796 return -1; 797 while ((bus_space_read_1(iot, ioh, fdsts) & NE7_RQM) == 0 && i-- > 0); 798 if (i <= 0) 799 return -1; 800 bus_space_write_2(iot, ioh, fddata, x); 801 return 0; 802 } 803 804 int 805 fdopen(dev, flags, mode, l) 806 dev_t dev; 807 int flags; 808 int mode; 809 struct lwp *l; 810 { 811 int unit; 812 struct fd_softc *fd; 813 struct fd_type *type; 814 815 unit = FDUNIT(dev); 816 if (unit >= fd_cd.cd_ndevs) 817 return ENXIO; 818 fd = fd_cd.cd_devs[unit]; 819 if (fd == 0) 820 return ENXIO; 821 type = fd_dev_to_type(fd, dev); 822 if (type == NULL) 823 return ENXIO; 824 825 if ((fd->sc_flags & FD_OPEN) != 0 && 826 memcmp(fd->sc_type, type, sizeof(*type))) 827 return EBUSY; 828 829 fd->sc_type_copy = *type; 830 fd->sc_type = &fd->sc_type_copy; 831 fd->sc_cylin = -1; 832 fd->sc_flags |= FD_OPEN; 833 834 return 0; 835 } 836 837 int 838 fdclose(dev, flags, mode, l) 839 dev_t dev; 840 int flags; 841 int mode; 842 struct lwp *l; 843 { 844 struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)]; 845 846 fd->sc_flags &= ~FD_OPEN; 847 fd->sc_opts &= ~(FDOPT_NORETRY|FDOPT_SILENT); 848 return 0; 849 } 850 851 void 852 fdcstart(fdc) 853 struct fdc_softc *fdc; 854 { 855 856 #ifdef DIAGNOSTIC 857 /* only got here if controller's drive queue was inactive; should 858 be in idle state */ 859 if (fdc->sc_state != DEVIDLE) { 860 printf("fdcstart: not idle\n"); 861 return; 862 } 863 #endif 864 (void) fdcintr(fdc); 865 } 866 867 void 868 fdcstatus(dv, n, s) 869 struct device *dv; 870 int n; 871 const char *s; 872 { 873 struct fdc_softc *fdc = (void *)dv->dv_parent; 874 char bits[64]; 875 876 if (n == 0) { 877 out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI); 878 (void) fdcresult(fdc); 879 n = 2; 880 } 881 882 printf("%s: %s", dv->dv_xname, s); 883 884 switch (n) { 885 case 0: 886 printf("\n"); 887 break; 888 case 2: 889 printf(" (st0 %s cyl %d)\n", 890 bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS, 891 bits, sizeof(bits)), fdc->sc_status[1]); 892 break; 893 case 7: 894 printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0], 895 NE7_ST0BITS, bits, sizeof(bits))); 896 printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1], 897 NE7_ST1BITS, bits, sizeof(bits))); 898 printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2], 899 NE7_ST2BITS, bits, sizeof(bits))); 900 printf(" cyl %d head %d sec %d)\n", 901 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]); 902 break; 903 #ifdef DIAGNOSTIC 904 default: 905 printf("\nfdcstatus: weird size"); 906 break; 907 #endif 908 } 909 } 910 911 void 912 fdctimeout(arg) 913 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 #ifdef DEBUG 921 log(LOG_ERR,"fdctimeout: state %d\n", fdc->sc_state); 922 #endif 923 fdcstatus(&fd->sc_dev, 0, "timeout"); 924 925 if (BUFQ_PEEK(fd->sc_q) != NULL) 926 fdc->sc_state++; 927 else 928 fdc->sc_state = DEVIDLE; 929 930 (void) fdcintr(fdc); 931 splx(s); 932 } 933 934 void 935 fdcpseudointr(arg) 936 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(arg) 948 void *arg; 949 { 950 struct fdc_softc *fdc = arg; 951 #define st0 fdc->sc_status[0] 952 #define cyl fdc->sc_status[1] 953 struct fd_softc *fd; 954 struct buf *bp; 955 bus_space_tag_t iot = fdc->sc_iot; 956 bus_space_handle_t ioh = fdc->sc_ioh; 957 int read, head, sec, i, nblks; 958 struct fd_type *type; 959 struct ne7_fd_formb *finfo = NULL; 960 961 loop: 962 /* Is there a drive for the controller to do a transfer with? */ 963 fd = fdc->sc_drives.tqh_first; 964 if (fd == NULL) { 965 fdc->sc_state = DEVIDLE; 966 return 1; 967 } 968 969 /* Is there a transfer to this drive? If not, deactivate drive. */ 970 bp = BUFQ_PEEK(fd->sc_q); 971 if (bp == NULL) { 972 fd->sc_ops = 0; 973 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); 974 fd->sc_active = 0; 975 goto loop; 976 } 977 978 if (bp->b_flags & B_FORMAT) 979 finfo = (struct ne7_fd_formb *)bp->b_data; 980 981 switch (fdc->sc_state) { 982 case DEVIDLE: 983 fdc->sc_errors = 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 #if 1 1017 out_fdc(iot, ioh, NE7CMD_CONFIGURE);/* configure command */ 1018 out_fdc(iot, ioh, 0); 1019 out_fdc(iot, ioh, 0x18); 1020 out_fdc(iot, ioh, 0); 1021 #endif 1022 out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */ 1023 out_fdc(iot, ioh, fd->sc_type->steprate); 1024 out_fdc(iot, ioh, 6); /* XXX head load time == 6ms */ 1025 1026 out_fdc(iot, ioh, NE7CMD_SEEK); /* seek function */ 1027 out_fdc(iot, ioh, fd->sc_drive); /* drive number */ 1028 out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step); 1029 1030 fd->sc_cylin = -1; 1031 fdc->sc_state = SEEKWAIT; 1032 1033 fd->sc_dk.dk_seek++; 1034 disk_busy(&fd->sc_dk); 1035 1036 callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc); 1037 return 1; 1038 1039 case DOIO: 1040 doio: 1041 type = fd->sc_type; 1042 if (finfo) 1043 fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) - 1044 (char *)finfo; 1045 sec = fd->sc_blkno % type->seccyl; 1046 nblks = type->seccyl - sec; 1047 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE); 1048 nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE); 1049 fd->sc_nblks = nblks; 1050 fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE; 1051 head = sec / type->sectrac; 1052 sec -= head * type->sectrac; 1053 #ifdef DIAGNOSTIC 1054 {daddr_t block; 1055 block = (fd->sc_cylin * type->heads + head) * type->sectrac + sec; 1056 if (block != fd->sc_blkno) { 1057 printf("fdcintr: block %" PRId64 1058 " != blkno %" PRId64 "\n", 1059 block, fd->sc_blkno); 1060 #ifdef DDB 1061 Debugger(); 1062 #endif 1063 }} 1064 #endif 1065 read = bp->b_flags & B_READ; 1066 if (read) { 1067 fdc->sc_fh.fh_func = floppy_read_fiq; 1068 fdc->sc_fh.fh_size = floppy_read_fiq_end - 1069 floppy_read_fiq; 1070 } else { 1071 fdc->sc_fh.fh_func = floppy_write_fiq; 1072 fdc->sc_fh.fh_size = floppy_read_fiq_end - 1073 floppy_read_fiq; 1074 } 1075 fdc->sc_fh.fh_flags = 0; 1076 fdc->sc_fh.fh_regs = &fdc->sc_fr; 1077 fdc->sc_fr.fr_r9 = IOMD_BASE + (IOMD_FIQRQ << 2); 1078 fdc->sc_fr.fr_r10 = fd->sc_nbytes; 1079 fdc->sc_fr.fr_r11 = (u_int)(bp->b_data + fd->sc_skip); 1080 fdc->sc_fr.fr_r12 = fdc->sc_drq; 1081 #ifdef FD_DEBUG 1082 printf("fdc-doio:r9=%x r10=%x r11=%x r12=%x data=%x skip=%x\n", 1083 fdc->sc_fr.fr_r9, fdc->sc_fr.fh_r10, fdc->sc_fr.fh_r11, 1084 fdc->sc_fr.fh_r12, (u_int)bp->b_data, fd->sc_skip); 1085 #endif 1086 if (fiq_claim(&fdc->sc_fh) == -1) 1087 panic("%s: Cannot claim FIQ vector", fdc->sc_dev.dv_xname); 1088 IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x01); 1089 bus_space_write_2(iot, ioh, fdctl, type->rate); 1090 #ifdef FD_DEBUG 1091 printf("fdcintr: %s drive %d track %d head %d sec %d nblks %d\n", 1092 read ? "read" : "write", fd->sc_drive, fd->sc_cylin, 1093 head, sec, nblks); 1094 #endif 1095 if (finfo) { 1096 /* formatting */ 1097 if (out_fdc(iot, ioh, NE7CMD_FORMAT) < 0) { 1098 fdc->sc_errors = 4; 1099 fdcretry(fdc); 1100 goto loop; 1101 } 1102 out_fdc(iot, ioh, (head << 2) | fd->sc_drive); 1103 out_fdc(iot, ioh, finfo->fd_formb_secshift); 1104 out_fdc(iot, ioh, finfo->fd_formb_nsecs); 1105 out_fdc(iot, ioh, finfo->fd_formb_gaplen); 1106 out_fdc(iot, ioh, finfo->fd_formb_fillbyte); 1107 } else { 1108 if (read) 1109 out_fdc(iot, ioh, NE7CMD_READ); /* READ */ 1110 else 1111 out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */ 1112 out_fdc(iot, ioh, (head << 2) | fd->sc_drive); 1113 out_fdc(iot, ioh, fd->sc_cylin); /* track */ 1114 out_fdc(iot, ioh, head); 1115 out_fdc(iot, ioh, sec + 1); /* sector +1 */ 1116 out_fdc(iot, ioh, type->secsize);/* sector size */ 1117 out_fdc(iot, ioh, type->sectrac);/* sectors/track */ 1118 out_fdc(iot, ioh, type->gap1); /* gap1 size */ 1119 out_fdc(iot, ioh, type->datalen);/* data length */ 1120 } 1121 fdc->sc_state = IOCOMPLETE; 1122 1123 disk_busy(&fd->sc_dk); 1124 1125 /* allow 2 seconds for operation */ 1126 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc); 1127 return 1; /* will return later */ 1128 1129 case SEEKWAIT: 1130 callout_stop(&fdc->sc_timo_ch); 1131 fdc->sc_state = SEEKCOMPLETE; 1132 /* allow 1/50 second for heads to settle */ 1133 #if 0 1134 callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc); 1135 #endif 1136 return 1; 1137 1138 case SEEKCOMPLETE: 1139 /* no data on seek */ 1140 disk_unbusy(&fd->sc_dk, 0, 0); 1141 1142 /* Make sure seek really happened. */ 1143 out_fdc(iot, ioh, NE7CMD_SENSEI); 1144 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || 1145 cyl != bp->b_cylinder * fd->sc_type->step) { 1146 #ifdef FD_DEBUG 1147 fdcstatus(&fd->sc_dev, 2, "seek failed"); 1148 #endif 1149 fdcretry(fdc); 1150 goto loop; 1151 } 1152 fd->sc_cylin = bp->b_cylinder; 1153 goto doio; 1154 1155 case IOTIMEDOUT: 1156 fiq_release(&fdc->sc_fh); 1157 IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00); 1158 case SEEKTIMEDOUT: 1159 case RECALTIMEDOUT: 1160 case RESETTIMEDOUT: 1161 fdcretry(fdc); 1162 goto loop; 1163 1164 case IOCOMPLETE: /* IO DONE, post-analyze */ 1165 callout_stop(&fdc->sc_timo_ch); 1166 1167 disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid), 1168 (bp->b_flags & B_READ)); 1169 1170 if (fdcresult(fdc) != 7 || (st0 & 0xf8) != 0) { 1171 fiq_release(&fdc->sc_fh); 1172 IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00); 1173 #ifdef FD_DEBUG 1174 fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ? 1175 "read failed" : "write failed"); 1176 printf("blkno %d nblks %d\n", 1177 fd->sc_blkno, fd->sc_nblks); 1178 #endif 1179 fdcretry(fdc); 1180 goto loop; 1181 } 1182 fiq_release(&fdc->sc_fh); 1183 IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00); 1184 if (fdc->sc_errors) { 1185 #if 0 1186 diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF, 1187 fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL); 1188 printf("\n"); 1189 #endif 1190 fdc->sc_errors = 0; 1191 } 1192 fd->sc_blkno += fd->sc_nblks; 1193 fd->sc_skip += fd->sc_nbytes; 1194 fd->sc_bcount -= fd->sc_nbytes; 1195 if (!finfo && fd->sc_bcount > 0) { 1196 bp->b_cylinder = fd->sc_blkno / fd->sc_type->seccyl; 1197 goto doseek; 1198 } 1199 fdfinish(fd, bp); 1200 goto loop; 1201 1202 case DORESET: 1203 /* try a reset, keep motor on */ 1204 fd_set_motor(fdc, 1); 1205 delay(100); 1206 fd_set_motor(fdc, 0); 1207 fdc->sc_state = RESETCOMPLETE; 1208 callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc); 1209 return 1; /* will return later */ 1210 1211 case RESETCOMPLETE: 1212 callout_stop(&fdc->sc_timo_ch); 1213 /* clear the controller output buffer */ 1214 for (i = 0; i < 4; i++) { 1215 out_fdc(iot, ioh, NE7CMD_SENSEI); 1216 (void) fdcresult(fdc); 1217 } 1218 1219 /* fall through */ 1220 case DORECAL: 1221 out_fdc(iot, ioh, NE7CMD_RECAL); /* recalibrate function */ 1222 out_fdc(iot, ioh, fd->sc_drive); 1223 fdc->sc_state = RECALWAIT; 1224 callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc); 1225 return 1; /* will return later */ 1226 1227 case RECALWAIT: 1228 callout_stop(&fdc->sc_timo_ch); 1229 fdc->sc_state = RECALCOMPLETE; 1230 /* allow 1/30 second for heads to settle */ 1231 #if 0 1232 callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc); 1233 #endif 1234 return 1; /* will return later */ 1235 1236 case RECALCOMPLETE: 1237 out_fdc(iot, ioh, NE7CMD_SENSEI); 1238 if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) { 1239 #ifdef FD_DEBUG 1240 fdcstatus(&fd->sc_dev, 2, "recalibrate failed"); 1241 #endif 1242 fdcretry(fdc); 1243 goto loop; 1244 } 1245 fd->sc_cylin = 0; 1246 goto doseek; 1247 1248 case MOTORWAIT: 1249 if (fd->sc_flags & FD_MOTOR_WAIT) 1250 return 1; /* time's not up yet */ 1251 goto doseek; 1252 1253 default: 1254 fdcstatus(&fd->sc_dev, 0, "stray interrupt"); 1255 return 1; 1256 } 1257 #ifdef DIAGNOSTIC 1258 panic("fdcintr: impossible"); 1259 #endif 1260 #undef st0 1261 #undef cyl 1262 } 1263 1264 void 1265 fdcretry(fdc) 1266 struct fdc_softc *fdc; 1267 { 1268 char bits[64]; 1269 struct fd_softc *fd; 1270 struct buf *bp; 1271 1272 fd = fdc->sc_drives.tqh_first; 1273 bp = BUFQ_PEEK(fd->sc_q); 1274 1275 if (fd->sc_opts & FDOPT_NORETRY) 1276 goto fail; 1277 switch (fdc->sc_errors) { 1278 case 0: 1279 /* try again */ 1280 fdc->sc_state = DOSEEK; 1281 break; 1282 1283 case 1: case 2: case 3: 1284 /* didn't work; try recalibrating */ 1285 fdc->sc_state = DORECAL; 1286 break; 1287 1288 case 4: 1289 /* still no go; reset the bastard */ 1290 fdc->sc_state = DORESET; 1291 break; 1292 1293 default: 1294 fail: 1295 if ((fd->sc_opts & FDOPT_SILENT) == 0) { 1296 diskerr(bp, "fd", "hard error", LOG_PRINTF, 1297 fd->sc_skip / FDC_BSIZE, 1298 (struct disklabel *)NULL); 1299 1300 printf(" (st0 %s", 1301 bitmask_snprintf(fdc->sc_status[0], 1302 NE7_ST0BITS, bits, 1303 sizeof(bits))); 1304 printf(" st1 %s", 1305 bitmask_snprintf(fdc->sc_status[1], 1306 NE7_ST1BITS, bits, 1307 sizeof(bits))); 1308 printf(" st2 %s", 1309 bitmask_snprintf(fdc->sc_status[2], 1310 NE7_ST2BITS, bits, 1311 sizeof(bits))); 1312 printf(" cyl %d head %d sec %d)\n", 1313 fdc->sc_status[3], 1314 fdc->sc_status[4], 1315 fdc->sc_status[5]); 1316 } 1317 1318 bp->b_flags |= B_ERROR; 1319 bp->b_error = EIO; 1320 fdfinish(fd, bp); 1321 } 1322 fdc->sc_errors++; 1323 } 1324 1325 int 1326 fdioctl(dev, cmd, addr, flag, l) 1327 dev_t dev; 1328 u_long cmd; 1329 caddr_t addr; 1330 int flag; 1331 struct lwp *l; 1332 { 1333 struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)]; 1334 struct fdformat_parms *form_parms; 1335 struct fdformat_cmd *form_cmd; 1336 struct ne7_fd_formb *fd_formb; 1337 struct disklabel buffer; 1338 int error; 1339 unsigned int scratch; 1340 int il[FD_MAX_NSEC + 1]; 1341 register int i, j; 1342 1343 switch (cmd) { 1344 case DIOCGDINFO: 1345 memset(&buffer, 0, sizeof(buffer)); 1346 1347 buffer.d_secpercyl = fd->sc_type->seccyl; 1348 buffer.d_type = DTYPE_FLOPPY; 1349 buffer.d_secsize = FDC_BSIZE; 1350 1351 if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL) 1352 return EINVAL; 1353 1354 *(struct disklabel *)addr = buffer; 1355 return 0; 1356 1357 case DIOCWLABEL: 1358 if ((flag & FWRITE) == 0) 1359 return EBADF; 1360 /* XXX do something */ 1361 return 0; 1362 1363 case DIOCWDINFO: 1364 if ((flag & FWRITE) == 0) 1365 return EBADF; 1366 1367 error = setdisklabel(&buffer, (struct disklabel *)addr, 0, NULL); 1368 if (error) 1369 return error; 1370 1371 error = writedisklabel(dev, fdstrategy, &buffer, NULL); 1372 return error; 1373 1374 case FDIOCGETFORMAT: 1375 form_parms = (struct fdformat_parms *)addr; 1376 form_parms->fdformat_version = FDFORMAT_VERSION; 1377 form_parms->nbps = 128 * (1 << fd->sc_type->secsize); 1378 form_parms->ncyl = fd->sc_type->cyls; 1379 form_parms->nspt = fd->sc_type->sectrac; 1380 form_parms->ntrk = fd->sc_type->heads; 1381 form_parms->stepspercyl = fd->sc_type->step; 1382 form_parms->gaplen = fd->sc_type->gap2; 1383 form_parms->fillbyte = fd->sc_type->fillbyte; 1384 form_parms->interleave = fd->sc_type->interleave; 1385 switch (fd->sc_type->rate) { 1386 case FDC_500KBPS: 1387 form_parms->xfer_rate = 500 * 1024; 1388 break; 1389 case FDC_300KBPS: 1390 form_parms->xfer_rate = 300 * 1024; 1391 break; 1392 case FDC_250KBPS: 1393 form_parms->xfer_rate = 250 * 1024; 1394 break; 1395 default: 1396 return EINVAL; 1397 } 1398 return 0; 1399 1400 case FDIOCSETFORMAT: 1401 if((flag & FWRITE) == 0) 1402 return EBADF; /* must be opened for writing */ 1403 form_parms = (struct fdformat_parms *)addr; 1404 if (form_parms->fdformat_version != FDFORMAT_VERSION) 1405 return EINVAL; /* wrong version of formatting prog */ 1406 1407 scratch = form_parms->nbps >> 7; 1408 if ((form_parms->nbps & 0x7f) || ffs(scratch) == 0 || 1409 scratch & ~(1 << (ffs(scratch)-1))) 1410 /* not a power-of-two multiple of 128 */ 1411 return EINVAL; 1412 1413 switch (form_parms->xfer_rate) { 1414 case 500 * 1024: 1415 fd->sc_type->rate = FDC_500KBPS; 1416 break; 1417 case 300 * 1024: 1418 fd->sc_type->rate = FDC_300KBPS; 1419 break; 1420 case 250 * 1024: 1421 fd->sc_type->rate = FDC_250KBPS; 1422 break; 1423 default: 1424 return EINVAL; 1425 } 1426 1427 if (form_parms->nspt > FD_MAX_NSEC || 1428 form_parms->fillbyte > 0xff || 1429 form_parms->interleave > 0xff) 1430 return EINVAL; 1431 fd->sc_type->sectrac = form_parms->nspt; 1432 if (form_parms->ntrk != 2 && form_parms->ntrk != 1) 1433 return EINVAL; 1434 fd->sc_type->heads = form_parms->ntrk; 1435 fd->sc_type->seccyl = form_parms->nspt * form_parms->ntrk; 1436 fd->sc_type->secsize = ffs(scratch)-1; 1437 fd->sc_type->gap2 = form_parms->gaplen; 1438 fd->sc_type->cyls = form_parms->ncyl; 1439 fd->sc_type->size = fd->sc_type->seccyl * form_parms->ncyl * 1440 form_parms->nbps / DEV_BSIZE; 1441 fd->sc_type->step = form_parms->stepspercyl; 1442 fd->sc_type->fillbyte = form_parms->fillbyte; 1443 fd->sc_type->interleave = form_parms->interleave; 1444 return 0; 1445 1446 case FDIOCFORMAT_TRACK: 1447 if((flag & FWRITE) == 0) 1448 return EBADF; /* must be opened for writing */ 1449 form_cmd = (struct fdformat_cmd *)addr; 1450 if (form_cmd->formatcmd_version != FDFORMAT_VERSION) 1451 return EINVAL; /* wrong version of formatting prog */ 1452 1453 if (form_cmd->head >= fd->sc_type->heads || 1454 form_cmd->cylinder >= fd->sc_type->cyls) { 1455 return EINVAL; 1456 } 1457 1458 fd_formb = malloc(sizeof(struct ne7_fd_formb), 1459 M_TEMP, M_NOWAIT); 1460 if(fd_formb == 0) 1461 return ENOMEM; 1462 1463 1464 fd_formb->head = form_cmd->head; 1465 fd_formb->cyl = form_cmd->cylinder; 1466 fd_formb->transfer_rate = fd->sc_type->rate; 1467 fd_formb->fd_formb_secshift = fd->sc_type->secsize; 1468 fd_formb->fd_formb_nsecs = fd->sc_type->sectrac; 1469 fd_formb->fd_formb_gaplen = fd->sc_type->gap2; 1470 fd_formb->fd_formb_fillbyte = fd->sc_type->fillbyte; 1471 1472 memset(il, 0, sizeof il); 1473 for (j = 0, i = 1; i <= fd_formb->fd_formb_nsecs; i++) { 1474 while (il[(j%fd_formb->fd_formb_nsecs)+1]) 1475 j++; 1476 il[(j%fd_formb->fd_formb_nsecs)+1] = i; 1477 j += fd->sc_type->interleave; 1478 } 1479 for (i = 0; i < fd_formb->fd_formb_nsecs; i++) { 1480 fd_formb->fd_formb_cylno(i) = form_cmd->cylinder; 1481 fd_formb->fd_formb_headno(i) = form_cmd->head; 1482 fd_formb->fd_formb_secno(i) = il[i+1]; 1483 fd_formb->fd_formb_secsize(i) = fd->sc_type->secsize; 1484 } 1485 1486 error = fdformat(dev, fd_formb, l); 1487 free(fd_formb, M_TEMP); 1488 return error; 1489 1490 case FDIOCGETOPTS: /* get drive options */ 1491 *(int *)addr = fd->sc_opts; 1492 return 0; 1493 1494 case FDIOCSETOPTS: /* set drive options */ 1495 fd->sc_opts = *(int *)addr; 1496 return 0; 1497 1498 default: 1499 return ENOTTY; 1500 } 1501 1502 #ifdef DIAGNOSTIC 1503 panic("fdioctl: impossible"); 1504 #endif 1505 } 1506 1507 int 1508 fdformat(dev, finfo, l) 1509 dev_t dev; 1510 struct ne7_fd_formb *finfo; 1511 struct lwp *l; 1512 { 1513 int rv = 0, s; 1514 struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)]; 1515 struct fd_type *type = fd->sc_type; 1516 struct buf *bp; 1517 1518 /* set up a buffer header for fdstrategy() */ 1519 bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT); 1520 if(bp == 0) 1521 return ENOBUFS; 1522 memset((void *)bp, 0, sizeof(struct buf)); 1523 bp->b_flags = B_BUSY | B_PHYS | B_FORMAT; 1524 bp->b_proc = l->l_proc; 1525 bp->b_dev = dev; 1526 1527 /* 1528 * calculate a fake blkno, so fdstrategy() would initiate a 1529 * seek to the requested cylinder 1530 */ 1531 bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads) 1532 + finfo->head * type->sectrac) * FDC_BSIZE / DEV_BSIZE; 1533 1534 bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs; 1535 bp->b_data = (caddr_t)finfo; 1536 1537 #ifdef DEBUG 1538 printf("fdformat: blkno %llx count %lx\n", 1539 (unsigned long long)bp->b_blkno, bp->b_bcount); 1540 #endif 1541 1542 /* now do the format */ 1543 fdstrategy(bp); 1544 1545 /* ...and wait for it to complete */ 1546 s = splbio(); 1547 while(!(bp->b_flags & B_DONE)) { 1548 rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz); 1549 if (rv == EWOULDBLOCK) 1550 break; 1551 } 1552 splx(s); 1553 1554 if (rv == EWOULDBLOCK) { 1555 /* timed out */ 1556 rv = EIO; 1557 biodone(bp); 1558 } 1559 if(bp->b_flags & B_ERROR) { 1560 rv = bp->b_error; 1561 } 1562 free(bp, M_TEMP); 1563 return rv; 1564 } 1565 1566 #include "md.h" 1567 #if NMD > 0 1568 1569 #include <dev/md.h> 1570 1571 int load_memory_disc_from_floppy __P((struct md_conf *md, dev_t dev)); 1572 1573 int 1574 load_memory_disc_from_floppy(md, dev) 1575 struct md_conf *md; 1576 dev_t dev; 1577 { 1578 struct buf *bp; 1579 int loop; 1580 int s; 1581 int type; 1582 int floppysize; 1583 1584 if (bdevsw_lookup(dev) != &fd_bdevsw) 1585 return(EINVAL); 1586 1587 if (md->md_type == MD_UNCONFIGURED || md->md_addr == 0) 1588 return(EBUSY); 1589 1590 type = FDTYPE(dev) - 1; 1591 if (type < 0) type = 0; 1592 floppysize = fd_types[type].size << (fd_types[type].secsize + 7); 1593 1594 if (md->md_size < floppysize) { 1595 printf("Memory disc is not big enough for floppy image\n"); 1596 return(EINVAL); 1597 } 1598 1599 /* We have the memory disk ! */ 1600 1601 printf("Loading memory disc : %4dK ", 0); 1602 1603 /* obtain a buffer */ 1604 1605 bp = geteblk(fd_types[type].sectrac * DEV_BSIZE); 1606 1607 /* request no partition relocation by driver on I/O operations */ 1608 1609 bp->b_dev = dev; 1610 1611 s = spl0(); 1612 1613 if (fdopen(bp->b_dev, 0, 0, curlwp) != 0) { 1614 brelse(bp); 1615 printf("Cannot open floppy device\n"); 1616 return(EINVAL); 1617 } 1618 1619 for (loop = 0; 1620 loop < (floppysize / DEV_BSIZE / fd_types[type].sectrac); 1621 ++loop) { 1622 printf("\x08\x08\x08\x08\x08\x08%4dK ", 1623 loop * fd_types[type].sectrac * DEV_BSIZE / 1024); 1624 bp->b_blkno = loop * fd_types[type].sectrac; 1625 bp->b_bcount = fd_types[type].sectrac * DEV_BSIZE; 1626 bp->b_flags |= B_READ; 1627 bp->b_error = 0; 1628 bp->b_resid = 0; 1629 fdstrategy(bp); 1630 1631 if (biowait(bp)) 1632 panic("Cannot load floppy image"); 1633 1634 memcpy((caddr_t)md->md_addr + loop * fd_types[type].sectrac 1635 * DEV_BSIZE, (caddr_t)bp->b_data, 1636 fd_types[type].sectrac * DEV_BSIZE); 1637 } 1638 printf("\x08\x08\x08\x08\x08\x08%4dK done\n", 1639 loop * fd_types[type].sectrac * DEV_BSIZE / 1024); 1640 1641 fdclose(bp->b_dev, 0, 0, curlwp); 1642 1643 brelse(bp); 1644 1645 splx(s); 1646 return(0); 1647 } 1648 1649 #endif 1650