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