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