1 /* $NetBSD: fd.c,v 1.12 2002/11/01 11:31:50 mrg 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 #include <sys/conf.h> 115 116 #include <uvm/uvm_extern.h> 117 118 #include <arm/fiq.h> 119 120 #include <machine/cpu.h> 121 #include <machine/intr.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 CFATTACH_DECL(fdc, sizeof(struct fdc_softc), 190 fdcprobe, fdcattach, NULL, NULL); 191 192 /* 193 * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how 194 * we tell them apart. 195 */ 196 struct fd_type { 197 int sectrac; /* sectors per track */ 198 int heads; /* number of heads */ 199 int seccyl; /* sectors per cylinder */ 200 int secsize; /* size code for sectors */ 201 int datalen; /* data len when secsize = 0 */ 202 int steprate; /* step rate and head unload time */ 203 int gap1; /* gap len between sectors */ 204 int gap2; /* formatting gap */ 205 int cyls; /* total num of cylinders */ 206 int size; /* size of disk in sectors */ 207 int step; /* steps per cylinder */ 208 int rate; /* transfer speed code */ 209 u_char fillbyte; /* format fill byte */ 210 u_char interleave; /* interleave factor (formatting) */ 211 char *name; 212 }; 213 214 /* The order of entries in the following table is important -- BEWARE! */ 215 struct fd_type fd_types[] = { 216 { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,0xf6,1, "1.44MB" }, /* 1.44MB diskette */ 217 { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS,0xf6,1, "1.2MB" }, /* 1.2 MB AT-diskettes */ 218 { 9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS,0xf6,1, "360KB/AT" }, /* 360kB in 1.2MB drive */ 219 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS,0xf6,1, "360KB/PC" }, /* 360kB PC diskettes */ 220 { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS,0xf6,1, "720KB" }, /* 3.5" 720kB diskette */ 221 { 9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS,0xf6,1, "720KB/x" }, /* 720kB in 1.2MB drive */ 222 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS,0xf6,1, "360KB/x" }, /* 360kB in 720kB drive */ 223 }; 224 225 /* software state, per disk (with up to 4 disks per ctlr) */ 226 struct fd_softc { 227 struct device sc_dev; 228 struct disk sc_dk; 229 230 struct fd_type *sc_deftype; /* default type descriptor */ 231 struct fd_type *sc_type; /* current type descriptor */ 232 struct fd_type sc_type_copy; /* copy for fiddling when formatting */ 233 234 struct callout sc_motoron_ch; 235 struct callout sc_motoroff_ch; 236 237 daddr_t sc_blkno; /* starting block number */ 238 int sc_bcount; /* byte count left */ 239 int sc_opts; /* user-set options */ 240 int sc_skip; /* bytes already transferred */ 241 int sc_nblks; /* number of blocks currently transferring */ 242 int sc_nbytes; /* number of bytes currently transferring */ 243 244 int sc_drive; /* physical unit number */ 245 int sc_flags; 246 #define FD_OPEN 0x01 /* it's open */ 247 #define FD_MOTOR 0x02 /* motor should be on */ 248 #define FD_MOTOR_WAIT 0x04 /* motor coming up */ 249 int sc_cylin; /* where we think the head is */ 250 251 void *sc_sdhook; /* saved shutdown hook for drive. */ 252 253 TAILQ_ENTRY(fd_softc) sc_drivechain; 254 int sc_ops; /* I/O ops since last switch */ 255 struct bufq_state sc_q; /* pending I/O requests */ 256 int sc_active; /* number of active I/O operations */ 257 }; 258 259 /* floppy driver configuration */ 260 int fdprobe __P((struct device *, struct cfdata *, void *)); 261 void fdattach __P((struct device *, struct device *, void *)); 262 263 extern char floppy_read_fiq[], floppy_read_fiq_end[]; 264 extern char floppy_write_fiq[], floppy_write_fiq_end[]; 265 266 CFATTACH_DECL(fd, sizeof(struct fd_softc), 267 fdprobe, fdattach, NULL, NULL); 268 269 extern struct cfdriver fd_cd; 270 271 dev_type_open(fdopen); 272 dev_type_close(fdclose); 273 dev_type_read(fdread); 274 dev_type_write(fdwrite); 275 dev_type_ioctl(fdioctl); 276 dev_type_strategy(fdstrategy); 277 278 const struct bdevsw fd_bdevsw = { 279 fdopen, fdclose, fdstrategy, fdioctl, nodump, nosize, D_DISK 280 }; 281 282 const struct cdevsw fd_cdevsw = { 283 fdopen, fdclose, fdread, fdwrite, fdioctl, 284 nostop, notty, nopoll, nommap, nokqfilter, D_DISK 285 }; 286 287 void fdgetdisklabel __P((struct fd_softc *)); 288 int fd_get_parms __P((struct fd_softc *)); 289 void fdstart __P((struct fd_softc *)); 290 291 struct dkdriver fddkdriver = { fdstrategy }; 292 293 struct fd_type *fd_nvtotype __P((char *, int, int)); 294 void fd_set_motor __P((struct fdc_softc *fdc, int reset)); 295 void fd_motor_off __P((void *arg)); 296 void fd_motor_on __P((void *arg)); 297 int fdcresult __P((struct fdc_softc *fdc)); 298 int out_fdc __P((bus_space_tag_t iot, bus_space_handle_t ioh, u_char x)); 299 void fdcstart __P((struct fdc_softc *fdc)); 300 void fdcstatus __P((struct device *dv, int n, char *s)); 301 void fdctimeout __P((void *arg)); 302 void fdcpseudointr __P((void *arg)); 303 int fdcintr __P((void *)); 304 void fdcretry __P((struct fdc_softc *fdc)); 305 void fdfinish __P((struct fd_softc *fd, struct buf *bp)); 306 __inline struct fd_type *fd_dev_to_type __P((struct fd_softc *, dev_t)); 307 int fdformat __P((dev_t, struct ne7_fd_formb *, struct proc *)); 308 309 int 310 fdcprobe(parent, cf, aux) 311 struct device *parent; 312 struct cfdata *cf; 313 void *aux; 314 { 315 struct pioc_attach_args *pa = aux; 316 bus_space_tag_t iot; 317 bus_space_handle_t ioh; 318 int rv; 319 320 if (pa->pa_name && strcmp(pa->pa_name, "fdc") != 0) 321 return(0); 322 323 iot = pa->pa_iot; 324 rv = 0; 325 326 /* Map the i/o space. */ 327 if (bus_space_map(iot, pa->pa_iobase + pa->pa_offset, FDC_NPORT, 0, &ioh)) 328 return 0; 329 330 /* reset */ 331 bus_space_write_2(iot, ioh, fdout, 0); 332 delay(100); 333 bus_space_write_2(iot, ioh, fdout, FDO_FRST); 334 335 /* see if it can handle a command */ 336 if (out_fdc(iot, ioh, NE7CMD_SPECIFY) < 0) 337 goto out; 338 out_fdc(iot, ioh, 0xdf); 339 out_fdc(iot, ioh, 2); 340 341 rv = 1; 342 pa->pa_iosize = FDC_NPORT; 343 344 out: 345 bus_space_unmap(iot, ioh, FDC_NPORT); 346 return rv; 347 } 348 349 /* 350 * Arguments passed between fdcattach and fdprobe. 351 */ 352 struct fdc_attach_args { 353 int fa_drive; 354 struct fd_type *fa_deftype; 355 }; 356 357 /* 358 * Print the location of a disk drive (called just before attaching the 359 * the drive). If `fdc' is not NULL, the drive was found but was not 360 * in the system config file; print the drive name as well. 361 * Return QUIET (config_find ignores this if the device was configured) to 362 * avoid printing `fdN not configured' messages. 363 */ 364 int 365 fdprint(aux, fdc) 366 void *aux; 367 const char *fdc; 368 { 369 register struct fdc_attach_args *fa = aux; 370 371 if (!fdc) 372 printf(" drive %d", fa->fa_drive); 373 return QUIET; 374 } 375 376 void 377 fdcattach(parent, self, aux) 378 struct device *parent, *self; 379 void *aux; 380 { 381 struct fdc_softc *fdc = (void *)self; 382 bus_space_tag_t iot; 383 bus_space_handle_t ioh; 384 struct pioc_attach_args *pa = aux; 385 struct fdc_attach_args fa; 386 int type; 387 388 iot = pa->pa_iot; 389 390 /* Re-map the I/O space. */ 391 if (bus_space_map(iot, pa->pa_iobase + pa->pa_offset, FDC_NPORT, 0, &ioh)) 392 panic("fdcattach: couldn't map I/O ports"); 393 394 fdc->sc_iot = iot; 395 fdc->sc_ioh = ioh; 396 397 fdc->sc_drq = pa->pa_iobase + pa->pa_offset + pa->pa_drq; 398 fdc->sc_state = DEVIDLE; 399 TAILQ_INIT(&fdc->sc_drives); 400 401 printf("\n"); 402 403 callout_init(&fdc->sc_timo_ch); 404 callout_init(&fdc->sc_intr_ch); 405 406 fdc->sc_ih = intr_claim(pa->pa_irq, IPL_BIO, "fdc", 407 fdcintr, fdc); 408 if (!fdc->sc_ih) 409 panic("%s: Cannot claim IRQ %d", self->dv_xname, pa->pa_irq); 410 411 #if 0 412 /* 413 * The NVRAM info only tells us about the first two disks on the 414 * `primary' floppy controller. 415 */ 416 if (fdc->sc_dev.dv_unit == 0) 417 type = mc146818_read(NULL, NVRAM_DISKETTE); /* XXX softc */ 418 else 419 type = -1; 420 #endif 421 type = 0x10; /* XXX - hardcoded for 1 floppy */ 422 423 /* physical limit: four drives per controller. */ 424 for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) { 425 if (type >= 0 && fa.fa_drive < 2) 426 fa.fa_deftype = fd_nvtotype(fdc->sc_dev.dv_xname, 427 type, fa.fa_drive); 428 else 429 fa.fa_deftype = NULL; /* unknown */ 430 (void)config_found(self, (void *)&fa, fdprint); 431 } 432 } 433 434 int 435 fdprobe(parent, cf, aux) 436 struct device *parent; 437 struct cfdata *cf; 438 void *aux; 439 { 440 struct fdc_softc *fdc = (void *)parent; 441 struct fdc_attach_args *fa = aux; 442 int drive = fa->fa_drive; 443 bus_space_tag_t iot = fdc->sc_iot; 444 bus_space_handle_t ioh = fdc->sc_ioh; 445 int n; 446 447 if (cf->cf_loc[FDCCF_DRIVE] != FDCCF_DRIVE_DEFAULT 448 && cf->cf_loc[FDCCF_DRIVE] != drive) 449 return 0; 450 /* 451 * XXX 452 * This is to work around some odd interactions between this driver 453 * and SMC Ethernet cards. 454 */ 455 456 /* Don't need this for arm32 port but leave for the time being (it won't hurt) */ 457 458 if (cf->cf_loc[FDCCF_DRIVE] == FDCCF_DRIVE_DEFAULT && drive >= 2) 459 return 0; 460 461 /* select drive and turn on motor */ 462 bus_space_write_2(iot, ioh, fdout, drive | FDO_FRST | FDO_MOEN(drive)); 463 /* wait for motor to spin up */ 464 delay(250000); 465 out_fdc(iot, ioh, NE7CMD_RECAL); 466 out_fdc(iot, ioh, drive); 467 /* wait for recalibrate */ 468 delay(2000000); 469 out_fdc(iot, ioh, NE7CMD_SENSEI); 470 n = fdcresult(fdc); 471 #ifdef FD_DEBUG 472 { 473 int i; 474 printf("fdprobe: status"); 475 for (i = 0; i < n; i++) 476 printf(" %x", fdc->sc_status[i]); 477 printf("\n"); 478 } 479 #endif 480 /* turn off motor */ 481 bus_space_write_1(iot, ioh, fdout, FDO_FRST); 482 483 if (n != 2 || (fdc->sc_status[0] & 0xf8) != 0x20) 484 return 0; 485 486 return 1; 487 } 488 489 /* 490 * Controller is working, and drive responded. Attach it. 491 */ 492 void 493 fdattach(parent, self, aux) 494 struct device *parent, *self; 495 void *aux; 496 { 497 struct fdc_softc *fdc = (void *)parent; 498 struct fd_softc *fd = (void *)self; 499 struct fdc_attach_args *fa = aux; 500 struct fd_type *type = fa->fa_deftype; 501 int drive = fa->fa_drive; 502 503 callout_init(&fd->sc_motoron_ch); 504 callout_init(&fd->sc_motoroff_ch); 505 506 /* XXX Allow `flags' to override device type? */ 507 508 if (type) 509 printf(": %s %d cyl, %d head, %d sec\n", type->name, 510 type->cyls, type->heads, type->sectrac); 511 else 512 printf(": density unknown\n"); 513 514 bufq_alloc(&fd->sc_q, BUFQ_DISKSORT|BUFQ_SORT_CYLINDER); 515 fd->sc_cylin = -1; 516 fd->sc_drive = drive; 517 fd->sc_deftype = type; 518 fdc->sc_fd[drive] = fd; 519 520 /* 521 * Initialize and attach the disk structure. 522 */ 523 fd->sc_dk.dk_name = fd->sc_dev.dv_xname; 524 fd->sc_dk.dk_driver = &fddkdriver; 525 disk_attach(&fd->sc_dk); 526 527 /* Needed to power off if the motor is on when we halt. */ 528 529 } 530 531 /* 532 * Translate nvram type into internal data structure. Return NULL for 533 * none/unknown/unusable. 534 */ 535 struct fd_type * 536 fd_nvtotype(fdc, nvraminfo, drive) 537 char *fdc; 538 int nvraminfo, drive; 539 { 540 int type; 541 542 type = (drive == 0 ? nvraminfo : nvraminfo << 4) & 0xf0; 543 switch (type) { 544 #ifndef RC7500 545 case 0x00 : 546 return NULL; 547 #else 548 case 0x00 : 549 #endif /* !RC7500 */ 550 case 0x10 : 551 return &fd_types[0]; 552 default: 553 printf("%s: drive %d: unknown device type 0x%x\n", 554 fdc, drive, type); 555 return NULL; 556 } 557 } 558 559 __inline struct fd_type * 560 fd_dev_to_type(fd, dev) 561 struct fd_softc *fd; 562 dev_t dev; 563 { 564 int type = FDTYPE(dev); 565 566 if (type > (sizeof(fd_types) / sizeof(fd_types[0]))) 567 return NULL; 568 return type ? &fd_types[type - 1] : fd->sc_deftype; 569 } 570 571 void 572 fdstrategy(bp) 573 register struct buf *bp; /* IO operation to perform */ 574 { 575 struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(bp->b_dev)]; 576 int sz; 577 int s; 578 579 /* Valid unit, controller, and request? */ 580 if (bp->b_blkno < 0 || 581 ((bp->b_bcount % FDC_BSIZE) != 0 && 582 (bp->b_flags & B_FORMAT) == 0)) { 583 bp->b_error = EINVAL; 584 goto bad; 585 } 586 587 /* If it's a null transfer, return immediately. */ 588 if (bp->b_bcount == 0) 589 goto done; 590 591 sz = howmany(bp->b_bcount, FDC_BSIZE); 592 593 if (bp->b_blkno + sz > fd->sc_type->size) { 594 sz = fd->sc_type->size - bp->b_blkno; 595 if (sz == 0) { 596 /* If exactly at end of disk, return EOF. */ 597 goto done; 598 } 599 if (sz < 0) { 600 /* If past end of disk, return EINVAL. */ 601 bp->b_error = EINVAL; 602 goto bad; 603 } 604 /* Otherwise, truncate request. */ 605 bp->b_bcount = sz << DEV_BSHIFT; 606 } 607 608 bp->b_rawblkno = bp->b_blkno; 609 bp->b_cylinder = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE) / fd->sc_type->seccyl; 610 611 #ifdef FD_DEBUG 612 printf("fdstrategy: b_blkno %d b_bcount %d blkno %d cylin %d sz %d\n", 613 bp->b_blkno, bp->b_bcount, fd->sc_blkno, bp->b_cylinder, sz); 614 #endif 615 616 /* Queue transfer on drive, activate drive and controller if idle. */ 617 s = splbio(); 618 BUFQ_PUT(&fd->sc_q, bp); 619 callout_stop(&fd->sc_motoroff_ch); /* a good idea */ 620 if (fd->sc_active == 0) 621 fdstart(fd); 622 #ifdef DIAGNOSTIC 623 else { 624 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; 625 if (fdc->sc_state == DEVIDLE) { 626 printf("fdstrategy: controller inactive\n"); 627 fdcstart(fdc); 628 } 629 } 630 #endif 631 splx(s); 632 return; 633 634 bad: 635 bp->b_flags |= B_ERROR; 636 done: 637 /* Toss transfer; we're done early. */ 638 bp->b_resid = bp->b_bcount; 639 biodone(bp); 640 } 641 642 void 643 fdstart(fd) 644 struct fd_softc *fd; 645 { 646 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; 647 int active = fdc->sc_drives.tqh_first != 0; 648 649 /* Link into controller queue. */ 650 fd->sc_active = 1; 651 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); 652 653 /* If controller not already active, start it. */ 654 if (!active) 655 fdcstart(fdc); 656 } 657 658 void 659 fdfinish(fd, bp) 660 struct fd_softc *fd; 661 struct buf *bp; 662 { 663 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; 664 665 /* 666 * Move this drive to the end of the queue to give others a `fair' 667 * chance. We only force a switch if N operations are completed while 668 * another drive is waiting to be serviced, since there is a long motor 669 * startup delay whenever we switch. 670 */ 671 (void)BUFQ_GET(&fd->sc_q); 672 if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) { 673 fd->sc_ops = 0; 674 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); 675 if (BUFQ_PEEK(&fd->sc_q) != NULL) 676 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); 677 else 678 fd->sc_active = 0; 679 } 680 bp->b_resid = fd->sc_bcount; 681 fd->sc_skip = 0; 682 683 biodone(bp); 684 /* turn off motor 5s from now */ 685 callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd); 686 fdc->sc_state = DEVIDLE; 687 } 688 689 int 690 fdread(dev, uio, flags) 691 dev_t dev; 692 struct uio *uio; 693 int flags; 694 { 695 696 return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio)); 697 } 698 699 int 700 fdwrite(dev, uio, flags) 701 dev_t dev; 702 struct uio *uio; 703 int flags; 704 { 705 706 return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio)); 707 } 708 709 void 710 fd_set_motor(fdc, reset) 711 struct fdc_softc *fdc; 712 int reset; 713 { 714 struct fd_softc *fd; 715 u_char status; 716 int n; 717 718 if ((fd = fdc->sc_drives.tqh_first) != NULL) 719 status = fd->sc_drive; 720 else 721 status = 0; 722 if (!reset) 723 status |= FDO_FRST | FDO_FDMAEN; 724 for (n = 0; n < 4; n++) 725 if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR)) 726 status |= FDO_MOEN(n); 727 bus_space_write_2(fdc->sc_iot, fdc->sc_ioh, fdout, status); 728 } 729 730 void 731 fd_motor_off(arg) 732 void *arg; 733 { 734 struct fd_softc *fd = arg; 735 int s; 736 737 s = splbio(); 738 fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); 739 fd_set_motor((struct fdc_softc *)fd->sc_dev.dv_parent, 0); 740 splx(s); 741 } 742 743 void 744 fd_motor_on(arg) 745 void *arg; 746 { 747 struct fd_softc *fd = arg; 748 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; 749 int s; 750 751 s = splbio(); 752 fd->sc_flags &= ~FD_MOTOR_WAIT; 753 if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT)) 754 (void) fdcintr(fdc); 755 splx(s); 756 } 757 758 int 759 fdcresult(fdc) 760 struct fdc_softc *fdc; 761 { 762 bus_space_tag_t iot = fdc->sc_iot; 763 bus_space_handle_t ioh = fdc->sc_ioh; 764 u_char i; 765 int j = 100000, 766 n = 0; 767 768 for (; j; j--) { 769 i = bus_space_read_1(iot, ioh, fdsts) & 770 (NE7_DIO | NE7_RQM | NE7_CB); 771 if (i == NE7_RQM) 772 return n; 773 if (i == (NE7_DIO | NE7_RQM | NE7_CB)) { 774 if (n >= sizeof(fdc->sc_status)) { 775 log(LOG_ERR, "fdcresult: overrun\n"); 776 return -1; 777 } 778 fdc->sc_status[n++] = 779 bus_space_read_1(iot, ioh, fddata); 780 } 781 delay(10); 782 } 783 log(LOG_ERR, "fdcresult: timeout\n"); 784 return -1; 785 } 786 787 int 788 out_fdc(iot, ioh, x) 789 bus_space_tag_t iot; 790 bus_space_handle_t ioh; 791 u_char x; 792 { 793 int i = 100000; 794 795 while ((bus_space_read_1(iot, ioh, fdsts) & NE7_DIO) && i-- > 0); 796 if (i <= 0) 797 return -1; 798 while ((bus_space_read_1(iot, ioh, fdsts) & NE7_RQM) == 0 && i-- > 0); 799 if (i <= 0) 800 return -1; 801 bus_space_write_2(iot, ioh, fddata, x); 802 return 0; 803 } 804 805 int 806 fdopen(dev, flags, mode, p) 807 dev_t dev; 808 int flags; 809 int mode; 810 struct proc *p; 811 { 812 int unit; 813 struct fd_softc *fd; 814 struct fd_type *type; 815 816 unit = FDUNIT(dev); 817 if (unit >= fd_cd.cd_ndevs) 818 return ENXIO; 819 fd = fd_cd.cd_devs[unit]; 820 if (fd == 0) 821 return ENXIO; 822 type = fd_dev_to_type(fd, dev); 823 if (type == NULL) 824 return ENXIO; 825 826 if ((fd->sc_flags & FD_OPEN) != 0 && 827 memcmp(fd->sc_type, type, sizeof(*type))) 828 return EBUSY; 829 830 fd->sc_type_copy = *type; 831 fd->sc_type = &fd->sc_type_copy; 832 fd->sc_cylin = -1; 833 fd->sc_flags |= FD_OPEN; 834 835 return 0; 836 } 837 838 int 839 fdclose(dev, flags, mode, p) 840 dev_t dev; 841 int flags; 842 int mode; 843 struct proc *p; 844 { 845 struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)]; 846 847 fd->sc_flags &= ~FD_OPEN; 848 fd->sc_opts &= ~(FDOPT_NORETRY|FDOPT_SILENT); 849 return 0; 850 } 851 852 void 853 fdcstart(fdc) 854 struct fdc_softc *fdc; 855 { 856 857 #ifdef DIAGNOSTIC 858 /* only got here if controller's drive queue was inactive; should 859 be in idle state */ 860 if (fdc->sc_state != DEVIDLE) { 861 printf("fdcstart: not idle\n"); 862 return; 863 } 864 #endif 865 (void) fdcintr(fdc); 866 } 867 868 void 869 fdcstatus(dv, n, s) 870 struct device *dv; 871 int n; 872 char *s; 873 { 874 struct fdc_softc *fdc = (void *)dv->dv_parent; 875 char bits[64]; 876 877 if (n == 0) { 878 out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI); 879 (void) fdcresult(fdc); 880 n = 2; 881 } 882 883 printf("%s: %s", dv->dv_xname, s); 884 885 switch (n) { 886 case 0: 887 printf("\n"); 888 break; 889 case 2: 890 printf(" (st0 %s cyl %d)\n", 891 bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS, 892 bits, sizeof(bits)), fdc->sc_status[1]); 893 break; 894 case 7: 895 printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0], 896 NE7_ST0BITS, bits, sizeof(bits))); 897 printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1], 898 NE7_ST1BITS, bits, sizeof(bits))); 899 printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2], 900 NE7_ST2BITS, bits, sizeof(bits))); 901 printf(" cyl %d head %d sec %d)\n", 902 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]); 903 break; 904 #ifdef DIAGNOSTIC 905 default: 906 printf("\nfdcstatus: weird size"); 907 break; 908 #endif 909 } 910 } 911 912 void 913 fdctimeout(arg) 914 void *arg; 915 { 916 struct fdc_softc *fdc = arg; 917 struct fd_softc *fd = fdc->sc_drives.tqh_first; 918 int s; 919 920 s = splbio(); 921 #ifdef DEBUG 922 log(LOG_ERR,"fdctimeout: state %d\n", fdc->sc_state); 923 #endif 924 fdcstatus(&fd->sc_dev, 0, "timeout"); 925 926 if (BUFQ_PEEK(&fd->sc_q) != NULL) 927 fdc->sc_state++; 928 else 929 fdc->sc_state = DEVIDLE; 930 931 (void) fdcintr(fdc); 932 splx(s); 933 } 934 935 void 936 fdcpseudointr(arg) 937 void *arg; 938 { 939 int s; 940 941 /* Just ensure it has the right spl. */ 942 s = splbio(); 943 (void) fdcintr(arg); 944 splx(s); 945 } 946 947 int 948 fdcintr(arg) 949 void *arg; 950 { 951 struct fdc_softc *fdc = arg; 952 #define st0 fdc->sc_status[0] 953 #define cyl fdc->sc_status[1] 954 struct fd_softc *fd; 955 struct buf *bp; 956 bus_space_tag_t iot = fdc->sc_iot; 957 bus_space_handle_t ioh = fdc->sc_ioh; 958 int read, head, sec, i, nblks; 959 struct fd_type *type; 960 struct ne7_fd_formb *finfo = NULL; 961 962 loop: 963 /* Is there a drive for the controller to do a transfer with? */ 964 fd = fdc->sc_drives.tqh_first; 965 if (fd == NULL) { 966 fdc->sc_state = DEVIDLE; 967 return 1; 968 } 969 970 /* Is there a transfer to this drive? If not, deactivate drive. */ 971 bp = BUFQ_PEEK(&fd->sc_q); 972 if (bp == NULL) { 973 fd->sc_ops = 0; 974 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); 975 fd->sc_active = 0; 976 goto loop; 977 } 978 979 if (bp->b_flags & B_FORMAT) 980 finfo = (struct ne7_fd_formb *)bp->b_data; 981 982 switch (fdc->sc_state) { 983 case DEVIDLE: 984 fdc->sc_errors = 0; 985 fd->sc_skip = 0; 986 fd->sc_bcount = bp->b_bcount; 987 fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE); 988 callout_stop(&fd->sc_motoroff_ch); 989 if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) { 990 fdc->sc_state = MOTORWAIT; 991 return 1; 992 } 993 if ((fd->sc_flags & FD_MOTOR) == 0) { 994 /* Turn on the motor, being careful about pairing. */ 995 struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1]; 996 if (ofd && ofd->sc_flags & FD_MOTOR) { 997 callout_stop(&ofd->sc_motoroff_ch); 998 ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT); 999 } 1000 fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT; 1001 fd_set_motor(fdc, 0); 1002 fdc->sc_state = MOTORWAIT; 1003 /* Allow .25s for motor to stabilize. */ 1004 callout_reset(&fd->sc_motoron_ch, hz / 4, 1005 fd_motor_on, fd); 1006 return 1; 1007 } 1008 /* Make sure the right drive is selected. */ 1009 fd_set_motor(fdc, 0); 1010 1011 /* fall through */ 1012 case DOSEEK: 1013 doseek: 1014 if (fd->sc_cylin == bp->b_cylinder) 1015 goto doio; 1016 1017 #if 1 1018 out_fdc(iot, ioh, NE7CMD_CONFIGURE);/* configure command */ 1019 out_fdc(iot, ioh, 0); 1020 out_fdc(iot, ioh, 0x18); 1021 out_fdc(iot, ioh, 0); 1022 #endif 1023 out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */ 1024 out_fdc(iot, ioh, fd->sc_type->steprate); 1025 out_fdc(iot, ioh, 6); /* XXX head load time == 6ms */ 1026 1027 out_fdc(iot, ioh, NE7CMD_SEEK); /* seek function */ 1028 out_fdc(iot, ioh, fd->sc_drive); /* drive number */ 1029 out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step); 1030 1031 fd->sc_cylin = -1; 1032 fdc->sc_state = SEEKWAIT; 1033 1034 fd->sc_dk.dk_seek++; 1035 disk_busy(&fd->sc_dk); 1036 1037 callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc); 1038 return 1; 1039 1040 case DOIO: 1041 doio: 1042 type = fd->sc_type; 1043 if (finfo) 1044 fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) - 1045 (char *)finfo; 1046 sec = fd->sc_blkno % type->seccyl; 1047 nblks = type->seccyl - sec; 1048 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE); 1049 nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE); 1050 fd->sc_nblks = nblks; 1051 fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE; 1052 head = sec / type->sectrac; 1053 sec -= head * type->sectrac; 1054 #ifdef DIAGNOSTIC 1055 {int block; 1056 block = (fd->sc_cylin * type->heads + head) * type->sectrac + sec; 1057 if (block != fd->sc_blkno) { 1058 printf("fdcintr: block %d != blkno %d\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, p) 1327 dev_t dev; 1328 u_long cmd; 1329 caddr_t addr; 1330 int flag; 1331 struct proc *p; 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, p); 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, p) 1509 dev_t dev; 1510 struct ne7_fd_formb *finfo; 1511 struct proc *p; 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 = p; 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 %x count %lx\n", bp->b_blkno, bp->b_bcount); 1539 #endif 1540 1541 /* now do the format */ 1542 fdstrategy(bp); 1543 1544 /* ...and wait for it to complete */ 1545 s = splbio(); 1546 while(!(bp->b_flags & B_DONE)) { 1547 rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz); 1548 if (rv == EWOULDBLOCK) 1549 break; 1550 } 1551 splx(s); 1552 1553 if (rv == EWOULDBLOCK) { 1554 /* timed out */ 1555 rv = EIO; 1556 biodone(bp); 1557 } 1558 if(bp->b_flags & B_ERROR) { 1559 rv = bp->b_error; 1560 } 1561 free(bp, M_TEMP); 1562 return rv; 1563 } 1564 1565 #include "md.h" 1566 #if NMD > 0 1567 1568 #include <dev/md.h> 1569 1570 int load_memory_disc_from_floppy __P((struct md_conf *md, dev_t dev)); 1571 1572 int 1573 load_memory_disc_from_floppy(md, dev) 1574 struct md_conf *md; 1575 dev_t dev; 1576 { 1577 struct buf *bp; 1578 int loop; 1579 int s; 1580 int type; 1581 int floppysize; 1582 1583 if (bdevsw_lookup(dev) != &fd_bdevsw) 1584 return(EINVAL); 1585 1586 if (md->md_type == MD_UNCONFIGURED || md->md_addr == 0) 1587 return(EBUSY); 1588 1589 type = FDTYPE(dev) - 1; 1590 if (type < 0) type = 0; 1591 floppysize = fd_types[type].size << (fd_types[type].secsize + 7); 1592 1593 if (md->md_size < floppysize) { 1594 printf("Memory disc is not big enough for floppy image\n"); 1595 return(EINVAL); 1596 } 1597 1598 /* We have the memory disk ! */ 1599 1600 printf("Loading memory disc : %4dK ", 0); 1601 1602 /* obtain a buffer */ 1603 1604 bp = geteblk(fd_types[type].sectrac * DEV_BSIZE); 1605 1606 /* request no partition relocation by driver on I/O operations */ 1607 1608 bp->b_dev = dev; 1609 1610 s = spl0(); 1611 1612 if (fdopen(bp->b_dev, 0, 0, curproc) != 0) { 1613 brelse(bp); 1614 printf("Cannot open floppy device\n"); 1615 return(EINVAL); 1616 } 1617 1618 for (loop = 0; 1619 loop < (floppysize / DEV_BSIZE / fd_types[type].sectrac); 1620 ++loop) { 1621 printf("\x08\x08\x08\x08\x08\x08%4dK ", 1622 loop * fd_types[type].sectrac * DEV_BSIZE / 1024); 1623 bp->b_blkno = loop * fd_types[type].sectrac; 1624 bp->b_bcount = fd_types[type].sectrac * DEV_BSIZE; 1625 bp->b_flags |= B_READ; 1626 bp->b_error = 0; 1627 bp->b_resid = 0; 1628 fdstrategy(bp); 1629 1630 if (biowait(bp)) 1631 panic("Cannot load floppy image"); 1632 1633 memcpy((caddr_t)md->md_addr + loop * fd_types[type].sectrac 1634 * DEV_BSIZE, (caddr_t)bp->b_data, 1635 fd_types[type].sectrac * DEV_BSIZE); 1636 } 1637 printf("\x08\x08\x08\x08\x08\x08%4dK done\n", 1638 loop * fd_types[type].sectrac * DEV_BSIZE / 1024); 1639 1640 fdclose(bp->b_dev, 0, 0, curproc); 1641 1642 brelse(bp); 1643 1644 splx(s); 1645 return(0); 1646 } 1647 1648 #endif 1649