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