Annotation of sys/arch/sparc64/dev/fd.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: fd.c,v 1.18 2007/06/20 18:15:46 deraadt Exp $ */
! 2: /* $NetBSD: fd.c,v 1.112 2003/08/07 16:29:35 agc Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 2000 The NetBSD Foundation, Inc.
! 6: * All rights reserved.
! 7: *
! 8: * This code is derived from software contributed to The NetBSD Foundation
! 9: * by Paul Kranenburg.
! 10: *
! 11: * Redistribution and use in source and binary forms, with or without
! 12: * modification, are permitted provided that the following conditions
! 13: * are met:
! 14: * 1. Redistributions of source code must retain the above copyright
! 15: * notice, this list of conditions and the following disclaimer.
! 16: * 2. Redistributions in binary form must reproduce the above copyright
! 17: * notice, this list of conditions and the following disclaimer in the
! 18: * documentation and/or other materials provided with the distribution.
! 19: * 3. All advertising materials mentioning features or use of this software
! 20: * must display the following acknowledgement:
! 21: * This product includes software developed by the NetBSD
! 22: * Foundation, Inc. and its contributors.
! 23: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 24: * contributors may be used to endorse or promote products derived
! 25: * from this software without specific prior written permission.
! 26: *
! 27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 37: * POSSIBILITY OF SUCH DAMAGE.
! 38: */
! 39:
! 40: /*-
! 41: * Copyright (c) 1990 The Regents of the University of California.
! 42: * All rights reserved.
! 43: *
! 44: * This code is derived from software contributed to Berkeley by
! 45: * Don Ahn.
! 46: *
! 47: * Redistribution and use in source and binary forms, with or without
! 48: * modification, are permitted provided that the following conditions
! 49: * are met:
! 50: * 1. Redistributions of source code must retain the above copyright
! 51: * notice, this list of conditions and the following disclaimer.
! 52: * 2. Redistributions in binary form must reproduce the above copyright
! 53: * notice, this list of conditions and the following disclaimer in the
! 54: * documentation and/or other materials provided with the distribution.
! 55: * 3. Neither the name of the University nor the names of its contributors
! 56: * may be used to endorse or promote products derived from this software
! 57: * without specific prior written permission.
! 58: *
! 59: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 60: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 61: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 62: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 63: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 64: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 65: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 66: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 67: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 68: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 69: * SUCH DAMAGE.
! 70: *
! 71: * @(#)fd.c 7.4 (Berkeley) 5/25/91
! 72: */
! 73:
! 74: /*-
! 75: * Copyright (c) 1993, 1994, 1995 Charles M. Hannum.
! 76: * Copyright (c) 1995 Paul Kranenburg.
! 77: *
! 78: * This code is derived from software contributed to Berkeley by
! 79: * Don Ahn.
! 80: *
! 81: * Redistribution and use in source and binary forms, with or without
! 82: * modification, are permitted provided that the following conditions
! 83: * are met:
! 84: * 1. Redistributions of source code must retain the above copyright
! 85: * notice, this list of conditions and the following disclaimer.
! 86: * 2. Redistributions in binary form must reproduce the above copyright
! 87: * notice, this list of conditions and the following disclaimer in the
! 88: * documentation and/or other materials provided with the distribution.
! 89: * 3. All advertising materials mentioning features or use of this software
! 90: * must display the following acknowledgement:
! 91: * This product includes software developed by the University of
! 92: * California, Berkeley and its contributors.
! 93: * 4. Neither the name of the University nor the names of its contributors
! 94: * may be used to endorse or promote products derived from this software
! 95: * without specific prior written permission.
! 96: *
! 97: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 98: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 99: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 100: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 101: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 102: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 103: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 104: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 105: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 106: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 107: * SUCH DAMAGE.
! 108: *
! 109: * @(#)fd.c 7.4 (Berkeley) 5/25/91
! 110: */
! 111:
! 112: #include <sys/param.h>
! 113: #include <sys/systm.h>
! 114: #include <sys/timeout.h>
! 115: #include <sys/kernel.h>
! 116: #include <sys/file.h>
! 117: #include <sys/ioctl.h>
! 118: #include <sys/conf.h>
! 119: #include <sys/device.h>
! 120: #include <sys/disklabel.h>
! 121: #include <sys/disk.h>
! 122: #include <sys/buf.h>
! 123: #include <sys/malloc.h>
! 124: #include <sys/proc.h>
! 125: #include <sys/uio.h>
! 126: #include <sys/mtio.h>
! 127: #include <sys/stat.h>
! 128: #include <sys/syslog.h>
! 129: #include <sys/queue.h>
! 130:
! 131: #include <dev/cons.h>
! 132:
! 133: #include <uvm/uvm_extern.h>
! 134:
! 135: #include <machine/autoconf.h>
! 136: #include <machine/conf.h>
! 137: #include <machine/intr.h>
! 138: #include <machine/ioctl_fd.h>
! 139:
! 140: #include <sparc64/dev/auxioreg.h>
! 141: #include <sparc64/dev/auxiovar.h>
! 142: #include <sparc64/dev/ebusreg.h>
! 143: #include <sparc64/dev/ebusvar.h>
! 144: #include <sparc64/dev/fdreg.h>
! 145: #include <sparc64/dev/fdvar.h>
! 146:
! 147: #define FDUNIT(dev) ((minor(dev) / MAXPARTITIONS) / 8)
! 148: #define FDTYPE(dev) ((minor(dev) / MAXPARTITIONS) % 8)
! 149:
! 150: #define FTC_FLIP \
! 151: do { \
! 152: auxio_fd_control(AUXIO_LED_FTC); \
! 153: auxio_fd_control(0); \
! 154: } while (0)
! 155:
! 156: /* XXX misuse a flag to identify format operation */
! 157: #define B_FORMAT B_XXX
! 158:
! 159: #ifdef FD_DEBUG
! 160: int fdc_debug = 0;
! 161: #endif
! 162:
! 163: enum fdc_state {
! 164: DEVIDLE = 0,
! 165: MOTORWAIT, /* 1 */
! 166: DOSEEK, /* 2 */
! 167: SEEKWAIT, /* 3 */
! 168: SEEKTIMEDOUT, /* 4 */
! 169: SEEKCOMPLETE, /* 5 */
! 170: DOIO, /* 6 */
! 171: IOCOMPLETE, /* 7 */
! 172: IOTIMEDOUT, /* 8 */
! 173: IOCLEANUPWAIT, /* 9 */
! 174: IOCLEANUPTIMEDOUT,/*10 */
! 175: DORESET, /* 11 */
! 176: RESETCOMPLETE, /* 12 */
! 177: RESETTIMEDOUT, /* 13 */
! 178: DORECAL, /* 14 */
! 179: RECALWAIT, /* 15 */
! 180: RECALTIMEDOUT, /* 16 */
! 181: RECALCOMPLETE, /* 17 */
! 182: DODSKCHG, /* 18 */
! 183: DSKCHGWAIT, /* 19 */
! 184: DSKCHGTIMEDOUT, /* 20 */
! 185: };
! 186:
! 187: /* software state, per controller */
! 188: struct fdc_softc {
! 189: struct device sc_dev; /* boilerplate */
! 190: bus_space_tag_t sc_bustag;
! 191:
! 192: struct timeout fdctimeout_to;
! 193: struct timeout fdcpseudointr_to;
! 194:
! 195: struct fd_softc *sc_fd[4]; /* pointers to children */
! 196: TAILQ_HEAD(drivehead, fd_softc) sc_drives;
! 197: enum fdc_state sc_state;
! 198: int sc_flags;
! 199: #define FDC_EBUS 0x01
! 200: #define FDC_NEEDHEADSETTLE 0x02
! 201: #define FDC_EIS 0x04
! 202: #define FDC_NEEDMOTORWAIT 0x08
! 203: #define FDC_NOEJECT 0x10
! 204: int sc_errors; /* number of retries so far */
! 205: int sc_overruns; /* number of DMA overruns */
! 206: int sc_cfg; /* current configuration */
! 207: struct fdcio sc_io;
! 208: #define sc_handle sc_io.fdcio_handle
! 209: #define sc_itask sc_io.fdcio_itask
! 210: #define sc_istatus sc_io.fdcio_istatus
! 211: #define sc_data sc_io.fdcio_data
! 212: #define sc_tc sc_io.fdcio_tc
! 213: #define sc_nstat sc_io.fdcio_nstat
! 214: #define sc_status sc_io.fdcio_status
! 215:
! 216: void *sc_sicookie; /* softintr(9) cookie */
! 217: };
! 218:
! 219: /* controller driver configuration */
! 220: int fdcmatch_sbus(struct device *, void *, void *);
! 221: int fdcmatch_ebus(struct device *, void *, void *);
! 222: void fdcattach_sbus(struct device *, struct device *, void *);
! 223: void fdcattach_ebus(struct device *, struct device *, void *);
! 224:
! 225: int fdcattach(struct fdc_softc *, int);
! 226:
! 227: struct cfattach fdc_sbus_ca = {
! 228: sizeof(struct fdc_softc), fdcmatch_sbus, fdcattach_sbus
! 229: };
! 230:
! 231: struct cfattach fdc_ebus_ca = {
! 232: sizeof(struct fdc_softc), fdcmatch_ebus, fdcattach_ebus
! 233: };
! 234:
! 235: struct cfdriver fdc_cd = {
! 236: NULL, "fdc", DV_DULL
! 237: };
! 238:
! 239: __inline struct fd_type *fd_dev_to_type(struct fd_softc *, dev_t);
! 240:
! 241: /* The order of entries in the following table is important -- BEWARE! */
! 242: struct fd_type fd_types[] = {
! 243: { 18,2,36,2,0xff,0xcf,0x1b,0x54,80,2880,1,FDC_500KBPS, "1.44MB" }, /* 1.44MB diskette */
! 244: { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS, "720KB" }, /* 3.5" 720kB diskette */
! 245: { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS, "360KB/x" }, /* 360kB in 720kB drive */
! 246: { 8,2,16,3,0xff,0xdf,0x35,0x74,77,1232,1,FDC_500KBPS, "1.2MB/NEC" } /* 1.2 MB japanese format */
! 247: };
! 248:
! 249: /* software state, per disk (with up to 4 disks per ctlr) */
! 250: struct fd_softc {
! 251: struct device sc_dv; /* generic device info */
! 252: struct disk sc_dk; /* generic disk info */
! 253:
! 254: struct fd_type *sc_deftype; /* default type descriptor */
! 255: struct fd_type *sc_type; /* current type descriptor */
! 256:
! 257: struct timeout sc_motoron_to;
! 258: struct timeout sc_motoroff_to;
! 259:
! 260: daddr64_t sc_blkno; /* starting block number */
! 261: int sc_bcount; /* byte count left */
! 262: int sc_skip; /* bytes already transferred */
! 263: int sc_nblks; /* number of blocks currently transferring */
! 264: int sc_nbytes; /* number of bytes currently transferring */
! 265:
! 266: int sc_drive; /* physical unit number */
! 267: int sc_flags;
! 268: #define FD_OPEN 0x01 /* it's open */
! 269: #define FD_MOTOR 0x02 /* motor should be on */
! 270: #define FD_MOTOR_WAIT 0x04 /* motor coming up */
! 271: int sc_cylin; /* where we think the head is */
! 272: int sc_opts; /* user-set options */
! 273:
! 274: void *sc_sdhook; /* shutdownhook cookie */
! 275:
! 276: TAILQ_ENTRY(fd_softc) sc_drivechain;
! 277: int sc_ops; /* I/O ops since last switch */
! 278: struct buf sc_q; /* pending I/O requests */
! 279: };
! 280:
! 281: /* floppy driver configuration */
! 282: int fdmatch(struct device *, void *, void *);
! 283: void fdattach(struct device *, struct device *, void *);
! 284:
! 285: struct cfattach fd_ca = {
! 286: sizeof(struct fd_softc), fdmatch, fdattach
! 287: };
! 288:
! 289: struct cfdriver fd_cd = {
! 290: NULL, "fd", DV_DISK
! 291: };
! 292:
! 293: void fdgetdisklabel(dev_t);
! 294: int fd_get_parms(struct fd_softc *);
! 295: void fdstrategy(struct buf *);
! 296: void fdstart(struct fd_softc *);
! 297: int fdprint(void *, const char *);
! 298:
! 299: struct dkdriver fddkdriver = { fdstrategy };
! 300:
! 301: struct fd_type *fd_nvtotype(char *, int, int);
! 302: void fd_set_motor(struct fdc_softc *fdc);
! 303: void fd_motor_off(void *arg);
! 304: void fd_motor_on(void *arg);
! 305: int fdcresult(struct fdc_softc *fdc);
! 306: int fdc_wrfifo(struct fdc_softc *fdc, u_char x);
! 307: void fdcstart(struct fdc_softc *fdc);
! 308: void fdcstatus(struct fdc_softc *fdc, char *s);
! 309: void fdc_reset(struct fdc_softc *fdc);
! 310: int fdc_diskchange(struct fdc_softc *fdc);
! 311: void fdctimeout(void *arg);
! 312: void fdcpseudointr(void *arg);
! 313: int fdchwintr(void *);
! 314: void fdcswintr(void *);
! 315: int fdcstate(struct fdc_softc *);
! 316: void fdcretry(struct fdc_softc *fdc);
! 317: void fdfinish(struct fd_softc *fd, struct buf *bp);
! 318: int fdformat(dev_t, struct fd_formb *, struct proc *);
! 319: void fd_do_eject(struct fd_softc *);
! 320: static int fdconf(struct fdc_softc *);
! 321:
! 322: int
! 323: fdcmatch_sbus(parent, match, aux)
! 324: struct device *parent;
! 325: void *match, *aux;
! 326: {
! 327: struct sbus_attach_args *sa = aux;
! 328:
! 329: return (strcmp("SUNW,fdtwo", sa->sa_name) == 0);
! 330: }
! 331:
! 332: void
! 333: fdcattach_sbus(parent, self, aux)
! 334: struct device *parent, *self;
! 335: void *aux;
! 336: {
! 337: struct fdc_softc *fdc = (void *)self;
! 338: struct sbus_attach_args *sa = aux;
! 339:
! 340: if (sa->sa_nintr == 0) {
! 341: printf(": no interrupt line configured\n");
! 342: return;
! 343: }
! 344:
! 345: if (auxio_fd_control(0) != 0) {
! 346: printf(": can't attach before auxio\n");
! 347: return;
! 348: }
! 349:
! 350: fdc->sc_bustag = sa->sa_bustag;
! 351:
! 352: if (sbus_bus_map(sa->sa_bustag,
! 353: sa->sa_slot, sa->sa_offset, sa->sa_size,
! 354: BUS_SPACE_MAP_LINEAR, 0, &fdc->sc_handle) != 0) {
! 355: printf(": cannot map control registers\n");
! 356: return;
! 357: }
! 358:
! 359: if (strcmp(getpropstring(sa->sa_node, "status"), "disabled") == 0) {
! 360: printf(": no drives attached\n");
! 361: return;
! 362: }
! 363:
! 364: if (getproplen(sa->sa_node, "manual") >= 0)
! 365: fdc->sc_flags |= FDC_NOEJECT;
! 366:
! 367: if (fdcattach(fdc, sa->sa_pri) != 0)
! 368: bus_space_unmap(sa->sa_bustag, fdc->sc_handle, sa->sa_size);
! 369: }
! 370:
! 371: int
! 372: fdcmatch_ebus(parent, match, aux)
! 373: struct device *parent;
! 374: void *match, *aux;
! 375: {
! 376: struct ebus_attach_args *ea = aux;
! 377:
! 378: return (strcmp("fdthree", ea->ea_name) == 0);
! 379: }
! 380:
! 381: void
! 382: fdcattach_ebus(parent, self, aux)
! 383: struct device *parent, *self;
! 384: void *aux;
! 385: {
! 386: struct fdc_softc *fdc = (void *)self;
! 387: struct ebus_attach_args *ea = aux;
! 388:
! 389: if (ea->ea_nintrs == 0) {
! 390: printf(": no interrupt line configured\n");
! 391: return;
! 392: }
! 393:
! 394: if (ea->ea_nregs < 3) {
! 395: printf(": expected 3 registers, only got %d\n",
! 396: ea->ea_nregs);
! 397: return;
! 398: }
! 399:
! 400: if (ea->ea_nvaddrs > 0) {
! 401: if (bus_space_map(ea->ea_memtag, ea->ea_vaddrs[0], 0,
! 402: BUS_SPACE_MAP_PROMADDRESS, &fdc->sc_handle) != 0) {
! 403: printf(": can't map control registers\n");
! 404: return;
! 405: }
! 406: fdc->sc_bustag = ea->ea_memtag;
! 407: } else if (ebus_bus_map(ea->ea_memtag, 0,
! 408: EBUS_PADDR_FROM_REG(&ea->ea_regs[0]),
! 409: ea->ea_regs[0].size, 0, 0, &fdc->sc_handle) == 0) {
! 410: fdc->sc_bustag = ea->ea_memtag;
! 411: } else if (ebus_bus_map(ea->ea_iotag, 0,
! 412: EBUS_PADDR_FROM_REG(&ea->ea_regs[0]),
! 413: ea->ea_regs[0].size, 0, 0, &fdc->sc_handle) == 0) {
! 414: fdc->sc_bustag = ea->ea_iotag;
! 415: } else {
! 416: printf(": can't map control registers\n");
! 417: return;
! 418: }
! 419:
! 420: if (strcmp(getpropstring(ea->ea_node, "status"), "disabled") == 0) {
! 421: printf(": no drives attached\n");
! 422: return;
! 423: }
! 424:
! 425: fdc->sc_flags |= FDC_EBUS;
! 426:
! 427: if (getproplen(ea->ea_node, "manual") >= 0)
! 428: fdc->sc_flags |= FDC_NOEJECT;
! 429:
! 430: /* XXX unmapping if it fails */
! 431: fdcattach(fdc, ea->ea_intrs[0]);
! 432: }
! 433:
! 434: /*
! 435: * Arguments passed between fdcattach and fdprobe.
! 436: */
! 437: struct fdc_attach_args {
! 438: int fa_drive;
! 439: struct fd_type *fa_deftype;
! 440: };
! 441:
! 442: /*
! 443: * Print the location of a disk drive (called just before attaching the
! 444: * the drive). If `fdc' is not NULL, the drive was found but was not
! 445: * in the system config file; print the drive name as well.
! 446: * Return QUIET (config_find ignores this if the device was configured) to
! 447: * avoid printing `fdN not configured' messages.
! 448: */
! 449: int
! 450: fdprint(aux, fdc)
! 451: void *aux;
! 452: const char *fdc;
! 453: {
! 454: register struct fdc_attach_args *fa = aux;
! 455:
! 456: if (!fdc)
! 457: printf(" drive %d", fa->fa_drive);
! 458: return (QUIET);
! 459: }
! 460:
! 461: /*
! 462: * Configure several parameters and features on the FDC.
! 463: * Return 0 on success.
! 464: */
! 465: static int
! 466: fdconf(fdc)
! 467: struct fdc_softc *fdc;
! 468: {
! 469: int vroom;
! 470:
! 471: if (fdc_wrfifo(fdc, NE7CMD_DUMPREG) || fdcresult(fdc) != 10)
! 472: return (-1);
! 473:
! 474: /*
! 475: * dumpreg[7] seems to be a motor-off timeout; set it to whatever
! 476: * the PROM thinks is appropriate.
! 477: */
! 478: if ((vroom = fdc->sc_status[7]) == 0)
! 479: vroom = 0x64;
! 480:
! 481: /* Configure controller to use FIFO and Implied Seek */
! 482: if (fdc_wrfifo(fdc, NE7CMD_CFG) != 0)
! 483: return (-1);
! 484: if (fdc_wrfifo(fdc, vroom) != 0)
! 485: return (-1);
! 486: if (fdc_wrfifo(fdc, fdc->sc_cfg) != 0)
! 487: return (-1);
! 488: if (fdc_wrfifo(fdc, 0) != 0) /* PRETRK */
! 489: return (-1);
! 490: /* No result phase for the NE7CMD_CFG command */
! 491:
! 492: /* Lock configuration across soft resets. */
! 493: if (fdc_wrfifo(fdc, NE7CMD_LOCK | CFG_LOCK) != 0 ||
! 494: fdcresult(fdc) != 1) {
! 495: #ifdef FD_DEBUG
! 496: printf("fdconf: CFGLOCK failed");
! 497: #endif
! 498: return (-1);
! 499: }
! 500:
! 501: return (0);
! 502: #if 0
! 503: if (fdc_wrfifo(fdc, NE7CMD_VERSION) == 0 &&
! 504: fdcresult(fdc) == 1 && fdc->sc_status[0] == 0x90) {
! 505: if (fdc_debug)
! 506: printf("[version cmd]");
! 507: }
! 508: #endif
! 509: }
! 510:
! 511: int
! 512: fdcattach(fdc, pri)
! 513: struct fdc_softc *fdc;
! 514: int pri;
! 515: {
! 516: struct fdc_attach_args fa;
! 517: int drive_attached;
! 518:
! 519: timeout_set(&fdc->fdctimeout_to, fdctimeout, fdc);
! 520: timeout_set(&fdc->fdcpseudointr_to, fdcpseudointr, fdc);
! 521:
! 522: fdc->sc_state = DEVIDLE;
! 523: fdc->sc_itask = FDC_ITASK_NONE;
! 524: fdc->sc_istatus = FDC_ISTATUS_NONE;
! 525: fdc->sc_flags |= FDC_EIS | FDC_NEEDMOTORWAIT;
! 526: TAILQ_INIT(&fdc->sc_drives);
! 527:
! 528: /*
! 529: * Configure controller; enable FIFO, Implied seek, no POLL mode?.
! 530: * Note: CFG_EFIFO is active-low, initial threshold value: 8
! 531: */
! 532: fdc->sc_cfg = CFG_EIS|/*CFG_EFIFO|*/CFG_POLL|(8 & CFG_THRHLD_MASK);
! 533: if (fdconf(fdc) != 0) {
! 534: printf("\n%s: no drives attached\n", fdc->sc_dev.dv_xname);
! 535: return (-1);
! 536: }
! 537:
! 538: if (bus_intr_establish(fdc->sc_bustag, pri, IPL_BIO,
! 539: 0, fdchwintr, fdc, fdc->sc_dev.dv_xname) == NULL) {
! 540: printf("\n%s: cannot register interrupt handler\n",
! 541: fdc->sc_dev.dv_xname);
! 542: return (-1);
! 543: }
! 544:
! 545: fdc->sc_sicookie = softintr_establish(IPL_BIO, fdcswintr, fdc);
! 546: if (fdc->sc_sicookie == NULL) {
! 547: printf("\n%s: cannot register soft interrupt handler\n",
! 548: fdc->sc_dev.dv_xname);
! 549: return (-1);
! 550: }
! 551:
! 552: printf(" softpri %d", PIL_FDSOFT);
! 553: if (fdc->sc_flags & FDC_NOEJECT)
! 554: printf(": manual eject");
! 555: printf("\n");
! 556:
! 557: /* physical limit: four drives per controller. */
! 558: drive_attached = 0;
! 559: for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
! 560: fa.fa_deftype = NULL; /* unknown */
! 561: fa.fa_deftype = &fd_types[0]; /* XXX */
! 562: if (config_found(&fdc->sc_dev, (void *)&fa, fdprint) != NULL)
! 563: drive_attached = 1;
! 564: }
! 565:
! 566: if (drive_attached == 0) {
! 567: /* XXX - dis-establish interrupts here */
! 568: /* return (-1); */
! 569: }
! 570:
! 571: return (0);
! 572: }
! 573:
! 574: int
! 575: fdmatch(parent, match, aux)
! 576: struct device *parent;
! 577: void *match;
! 578: void *aux;
! 579: {
! 580: struct fdc_softc *fdc = (void *)parent;
! 581: bus_space_tag_t t = fdc->sc_bustag;
! 582: bus_space_handle_t h = fdc->sc_handle;
! 583: struct fdc_attach_args *fa = aux;
! 584: int drive = fa->fa_drive;
! 585: int n, ok;
! 586:
! 587: if (drive > 0)
! 588: /* XXX - for now, punt on more than one drive */
! 589: return (0);
! 590:
! 591: /* select drive and turn on motor */
! 592: bus_space_write_1(t, h, FDREG77_DOR,
! 593: drive | FDO_FRST | FDO_MOEN(drive));
! 594: /* wait for motor to spin up */
! 595: delay(250000);
! 596:
! 597: fdc->sc_nstat = 0;
! 598: fdc_wrfifo(fdc, NE7CMD_RECAL);
! 599: fdc_wrfifo(fdc, drive);
! 600:
! 601: /* Wait for recalibration to complete */
! 602: for (n = 0; n < 10000; n++) {
! 603: u_int8_t v;
! 604:
! 605: delay(1000);
! 606: v = bus_space_read_1(t, h, FDREG77_MSR);
! 607: if ((v & (NE7_RQM|NE7_DIO|NE7_CB)) == NE7_RQM) {
! 608: /* wait a bit longer till device *really* is ready */
! 609: delay(100000);
! 610: if (fdc_wrfifo(fdc, NE7CMD_SENSEI))
! 611: break;
! 612: if (fdcresult(fdc) == 1 && fdc->sc_status[0] == 0x80)
! 613: /*
! 614: * Got `invalid command'; we interpret it
! 615: * to mean that the re-calibrate hasn't in
! 616: * fact finished yet
! 617: */
! 618: continue;
! 619: break;
! 620: }
! 621: }
! 622: n = fdc->sc_nstat;
! 623: #ifdef FD_DEBUG
! 624: if (fdc_debug) {
! 625: int i;
! 626: printf("fdprobe: %d stati:", n);
! 627: for (i = 0; i < n; i++)
! 628: printf(" 0x%x", fdc->sc_status[i]);
! 629: printf("\n");
! 630: }
! 631: #endif
! 632: ok = (n == 2 && (fdc->sc_status[0] & 0xf8) == 0x20) ? 1 : 0;
! 633:
! 634: /* deselect drive and turn motor off */
! 635: bus_space_write_1(t, h, FDREG77_DOR, FDO_FRST | FDO_DS);
! 636:
! 637: return (ok);
! 638: }
! 639:
! 640: /*
! 641: * Controller is working, and drive responded. Attach it.
! 642: */
! 643: void
! 644: fdattach(parent, self, aux)
! 645: struct device *parent, *self;
! 646: void *aux;
! 647: {
! 648: struct fdc_softc *fdc = (void *)parent;
! 649: struct fd_softc *fd = (void *)self;
! 650: struct fdc_attach_args *fa = aux;
! 651: struct fd_type *type = fa->fa_deftype;
! 652: int drive = fa->fa_drive;
! 653:
! 654: timeout_set(&fd->sc_motoron_to, fd_motor_on, fd);
! 655: timeout_set(&fd->sc_motoroff_to, fd_motor_off, fd);
! 656:
! 657: /* XXX Allow `flags' to override device type? */
! 658:
! 659: if (type)
! 660: printf(": %s %d cyl, %d head, %d sec\n", type->name,
! 661: type->tracks, type->heads, type->sectrac);
! 662: else
! 663: printf(": density unknown\n");
! 664:
! 665: fd->sc_cylin = -1;
! 666: fd->sc_drive = drive;
! 667: fd->sc_deftype = type;
! 668: fdc->sc_fd[drive] = fd;
! 669:
! 670: fdc_wrfifo(fdc, NE7CMD_SPECIFY);
! 671: fdc_wrfifo(fdc, type->steprate);
! 672: /* XXX head load time == 6ms */
! 673: fdc_wrfifo(fdc, 6 | NE7_SPECIFY_NODMA);
! 674:
! 675: /*
! 676: * Initialize and attach the disk structure.
! 677: */
! 678: fd->sc_dk.dk_name = fd->sc_dv.dv_xname;
! 679: fd->sc_dk.dk_driver = &fddkdriver;
! 680: disk_attach(&fd->sc_dk);
! 681:
! 682: /* Make sure the drive motor gets turned off at shutdown time. */
! 683: fd->sc_sdhook = shutdownhook_establish(fd_motor_off, fd);
! 684: }
! 685:
! 686: __inline struct fd_type *
! 687: fd_dev_to_type(fd, dev)
! 688: struct fd_softc *fd;
! 689: dev_t dev;
! 690: {
! 691: int type = FDTYPE(dev);
! 692:
! 693: if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
! 694: return (NULL);
! 695: return (type ? &fd_types[type - 1] : fd->sc_deftype);
! 696: }
! 697:
! 698: void
! 699: fdstrategy(bp)
! 700: register struct buf *bp; /* IO operation to perform */
! 701: {
! 702: struct fd_softc *fd;
! 703: int unit = FDUNIT(bp->b_dev);
! 704: int sz;
! 705: int s;
! 706:
! 707: /* Valid unit, controller, and request? */
! 708: if (unit >= fd_cd.cd_ndevs ||
! 709: (fd = fd_cd.cd_devs[unit]) == 0 ||
! 710: bp->b_blkno < 0 ||
! 711: (((bp->b_bcount % FD_BSIZE(fd)) != 0 ||
! 712: (bp->b_blkno * DEV_BSIZE) % FD_BSIZE(fd) != 0) &&
! 713: (bp->b_flags & B_FORMAT) == 0)) {
! 714: bp->b_error = EINVAL;
! 715: goto bad;
! 716: }
! 717:
! 718: /* If it's a null transfer, return immediately. */
! 719: if (bp->b_bcount == 0)
! 720: goto done;
! 721:
! 722: sz = howmany(bp->b_bcount, DEV_BSIZE);
! 723:
! 724: if (bp->b_blkno + sz > (fd->sc_type->size * DEV_BSIZE) / FD_BSIZE(fd)) {
! 725: sz = (fd->sc_type->size * DEV_BSIZE) / FD_BSIZE(fd)
! 726: - bp->b_blkno;
! 727: if (sz == 0) {
! 728: /* If exactly at end of disk, return EOF. */
! 729: bp->b_resid = bp->b_bcount;
! 730: goto done;
! 731: }
! 732: if (sz < 0) {
! 733: /* If past end of disk, return EINVAL. */
! 734: bp->b_error = EINVAL;
! 735: goto bad;
! 736: }
! 737: /* Otherwise, truncate request. */
! 738: bp->b_bcount = sz << DEV_BSHIFT;
! 739: }
! 740:
! 741: bp->b_cylinder = (bp->b_blkno * DEV_BSIZE) /
! 742: (FD_BSIZE(fd) * fd->sc_type->seccyl);
! 743:
! 744: #ifdef FD_DEBUG
! 745: if (fdc_debug > 1)
! 746: printf("fdstrategy: b_blkno %lld b_bcount %d blkno %lld cylin %d\n",
! 747: bp->b_blkno, bp->b_bcount,
! 748: fd->sc_blkno, bp->b_cylinder);
! 749: #endif
! 750:
! 751: /* Queue transfer on drive, activate drive and controller if idle. */
! 752: s = splbio();
! 753: disksort(&fd->sc_q, bp);
! 754: timeout_del(&fd->sc_motoroff_to); /* a good idea */
! 755: if (!fd->sc_q.b_active)
! 756: fdstart(fd);
! 757: #ifdef DIAGNOSTIC
! 758: else {
! 759: struct fdc_softc *fdc = (void *)fd->sc_dv.dv_parent;
! 760: if (fdc->sc_state == DEVIDLE) {
! 761: printf("fdstrategy: controller inactive\n");
! 762: fdcstart(fdc);
! 763: }
! 764: }
! 765: #endif
! 766: splx(s);
! 767: return;
! 768:
! 769: bad:
! 770: bp->b_flags |= B_ERROR;
! 771: done:
! 772: /* Toss transfer; we're done early. */
! 773: s = splbio();
! 774: biodone(bp);
! 775: splx(s);
! 776: }
! 777:
! 778: void
! 779: fdstart(fd)
! 780: struct fd_softc *fd;
! 781: {
! 782: struct fdc_softc *fdc = (void *)fd->sc_dv.dv_parent;
! 783: int active = !TAILQ_EMPTY(&fdc->sc_drives);
! 784:
! 785: /* Link into controller queue. */
! 786: fd->sc_q.b_active = 1;
! 787: TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
! 788:
! 789: /* If controller not already active, start it. */
! 790: if (!active)
! 791: fdcstart(fdc);
! 792: }
! 793:
! 794: void
! 795: fdfinish(fd, bp)
! 796: struct fd_softc *fd;
! 797: struct buf *bp;
! 798: {
! 799: struct fdc_softc *fdc = (void *)fd->sc_dv.dv_parent;
! 800:
! 801: /*
! 802: * Move this drive to the end of the queue to give others a `fair'
! 803: * chance. We only force a switch if N operations are completed while
! 804: * another drive is waiting to be serviced, since there is a long motor
! 805: * startup delay whenever we switch.
! 806: */
! 807: if (TAILQ_NEXT(fd, sc_drivechain) != NULL && ++fd->sc_ops >= 8) {
! 808: fd->sc_ops = 0;
! 809: TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
! 810: if (bp->b_actf) {
! 811: TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
! 812: } else
! 813: fd->sc_q.b_active = 0;
! 814: }
! 815: bp->b_resid = fd->sc_bcount;
! 816: fd->sc_skip = 0;
! 817: fd->sc_q.b_actf = bp->b_actf;
! 818:
! 819: biodone(bp);
! 820: /* turn off motor 5s from now */
! 821: timeout_add(&fd->sc_motoroff_to, 5 * hz);
! 822: fdc->sc_state = DEVIDLE;
! 823: }
! 824:
! 825: void
! 826: fdc_reset(fdc)
! 827: struct fdc_softc *fdc;
! 828: {
! 829: bus_space_tag_t t = fdc->sc_bustag;
! 830: bus_space_handle_t h = fdc->sc_handle;
! 831:
! 832: bus_space_write_1(t, h, FDREG77_DOR, FDO_FDMAEN | FDO_MOEN(0));
! 833:
! 834: bus_space_write_1(t, h, FDREG77_DRS, DRS_RESET);
! 835: delay(10);
! 836: bus_space_write_1(t, h, FDREG77_DRS, 0);
! 837:
! 838: bus_space_write_1(t, h, FDREG77_DOR,
! 839: FDO_FRST | FDO_FDMAEN | FDO_DS);
! 840: #ifdef FD_DEBUG
! 841: if (fdc_debug)
! 842: printf("fdc reset\n");
! 843: #endif
! 844: }
! 845:
! 846: void
! 847: fd_set_motor(fdc)
! 848: struct fdc_softc *fdc;
! 849: {
! 850: struct fd_softc *fd;
! 851: u_char status;
! 852: int n;
! 853:
! 854: status = FDO_FRST | FDO_FDMAEN;
! 855: if ((fd = TAILQ_FIRST(&fdc->sc_drives)) != NULL)
! 856: status |= fd->sc_drive;
! 857:
! 858: for (n = 0; n < 4; n++)
! 859: if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR))
! 860: status |= FDO_MOEN(n);
! 861: bus_space_write_1(fdc->sc_bustag, fdc->sc_handle,
! 862: FDREG77_DOR, status);
! 863: }
! 864:
! 865: void
! 866: fd_motor_off(arg)
! 867: void *arg;
! 868: {
! 869: struct fd_softc *fd = arg;
! 870: int s;
! 871:
! 872: s = splbio();
! 873: fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
! 874: fd_set_motor((struct fdc_softc *)fd->sc_dv.dv_parent);
! 875: splx(s);
! 876: }
! 877:
! 878: void
! 879: fd_motor_on(arg)
! 880: void *arg;
! 881: {
! 882: struct fd_softc *fd = arg;
! 883: struct fdc_softc *fdc = (void *)fd->sc_dv.dv_parent;
! 884: int s;
! 885:
! 886: s = splbio();
! 887: fd->sc_flags &= ~FD_MOTOR_WAIT;
! 888: if (fd == TAILQ_FIRST(&fdc->sc_drives) && fdc->sc_state == MOTORWAIT)
! 889: (void) fdcstate(fdc);
! 890: splx(s);
! 891: }
! 892:
! 893: /*
! 894: * Get status bytes off the FDC after a command has finished
! 895: * Returns the number of status bytes read; -1 on error.
! 896: * The return value is also stored in `sc_nstat'.
! 897: */
! 898: int
! 899: fdcresult(fdc)
! 900: struct fdc_softc *fdc;
! 901: {
! 902: bus_space_tag_t t = fdc->sc_bustag;
! 903: bus_space_handle_t h = fdc->sc_handle;
! 904: int j, n = 0;
! 905:
! 906: for (j = 100000; j; j--) {
! 907: u_int8_t v = bus_space_read_1(t, h, FDREG77_MSR);
! 908: v &= (NE7_DIO | NE7_RQM | NE7_CB);
! 909: if (v == NE7_RQM)
! 910: return (fdc->sc_nstat = n);
! 911: if (v == (NE7_DIO | NE7_RQM | NE7_CB)) {
! 912: if (n >= sizeof(fdc->sc_status)) {
! 913: log(LOG_ERR, "fdcresult: overrun\n");
! 914: return (-1);
! 915: }
! 916: fdc->sc_status[n++] =
! 917: bus_space_read_1(t, h, FDREG77_FIFO);
! 918: } else
! 919: delay(1);
! 920: }
! 921:
! 922: log(LOG_ERR, "fdcresult: timeout\n");
! 923: return (fdc->sc_nstat = -1);
! 924: }
! 925:
! 926: /*
! 927: * Write a command byte to the FDC.
! 928: * Returns 0 on success; -1 on failure (i.e. timeout)
! 929: */
! 930: int
! 931: fdc_wrfifo(fdc, x)
! 932: struct fdc_softc *fdc;
! 933: u_int8_t x;
! 934: {
! 935: bus_space_tag_t t = fdc->sc_bustag;
! 936: bus_space_handle_t h = fdc->sc_handle;
! 937: int i;
! 938:
! 939: for (i = 100000; i-- != 0;) {
! 940: u_int8_t v = bus_space_read_1(t, h, FDREG77_MSR);
! 941: if ((v & (NE7_DIO|NE7_RQM)) == NE7_RQM) {
! 942: /* The chip is ready */
! 943: bus_space_write_1(t, h, FDREG77_FIFO, x);
! 944: return (0);
! 945: }
! 946: delay(1);
! 947: }
! 948: return (-1);
! 949: }
! 950:
! 951: int
! 952: fdc_diskchange(fdc)
! 953: struct fdc_softc *fdc;
! 954: {
! 955: bus_space_tag_t t = fdc->sc_bustag;
! 956: bus_space_handle_t h = fdc->sc_handle;
! 957:
! 958: u_int8_t v = bus_space_read_1(t, h, FDREG77_DIR);
! 959: return ((v & FDI_DCHG) != 0);
! 960: }
! 961:
! 962: int
! 963: fdopen(dev, flags, fmt, p)
! 964: dev_t dev;
! 965: int flags, fmt;
! 966: struct proc *p;
! 967: {
! 968: int unit, pmask;
! 969: struct fd_softc *fd;
! 970: struct fd_type *type;
! 971:
! 972: unit = FDUNIT(dev);
! 973: if (unit >= fd_cd.cd_ndevs)
! 974: return (ENXIO);
! 975: fd = fd_cd.cd_devs[unit];
! 976: if (fd == NULL)
! 977: return (ENXIO);
! 978: type = fd_dev_to_type(fd, dev);
! 979: if (type == NULL)
! 980: return (ENXIO);
! 981:
! 982: if ((fd->sc_flags & FD_OPEN) != 0 &&
! 983: fd->sc_type != type)
! 984: return (EBUSY);
! 985:
! 986: fd->sc_type = type;
! 987: fd->sc_cylin = -1;
! 988: fd->sc_flags |= FD_OPEN;
! 989:
! 990: /*
! 991: * Only update the disklabel if we're not open anywhere else.
! 992: */
! 993: if (fd->sc_dk.dk_openmask == 0)
! 994: fdgetdisklabel(dev);
! 995:
! 996: pmask = (1 << DISKPART(dev));
! 997:
! 998: switch (fmt) {
! 999: case S_IFCHR:
! 1000: fd->sc_dk.dk_copenmask |= pmask;
! 1001: break;
! 1002:
! 1003: case S_IFBLK:
! 1004: fd->sc_dk.dk_bopenmask |= pmask;
! 1005: break;
! 1006: }
! 1007: fd->sc_dk.dk_openmask =
! 1008: fd->sc_dk.dk_copenmask | fd->sc_dk.dk_bopenmask;
! 1009:
! 1010: return (0);
! 1011: }
! 1012:
! 1013: int
! 1014: fdclose(dev, flags, fmt, p)
! 1015: dev_t dev;
! 1016: int flags, fmt;
! 1017: struct proc *p;
! 1018: {
! 1019: struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
! 1020: int pmask = (1 << DISKPART(dev));
! 1021:
! 1022: fd->sc_flags &= ~FD_OPEN;
! 1023: fd->sc_opts &= ~(FDOPT_NORETRY|FDOPT_SILENT);
! 1024:
! 1025: switch (fmt) {
! 1026: case S_IFCHR:
! 1027: fd->sc_dk.dk_copenmask &= ~pmask;
! 1028: break;
! 1029:
! 1030: case S_IFBLK:
! 1031: fd->sc_dk.dk_bopenmask &= ~pmask;
! 1032: break;
! 1033: }
! 1034: fd->sc_dk.dk_openmask =
! 1035: fd->sc_dk.dk_copenmask | fd->sc_dk.dk_bopenmask;
! 1036:
! 1037: return (0);
! 1038: }
! 1039:
! 1040: int
! 1041: fdread(dev, uio, flag)
! 1042: dev_t dev;
! 1043: struct uio *uio;
! 1044: int flag;
! 1045: {
! 1046:
! 1047: return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
! 1048: }
! 1049:
! 1050: int
! 1051: fdwrite(dev, uio, flag)
! 1052: dev_t dev;
! 1053: struct uio *uio;
! 1054: int flag;
! 1055: {
! 1056:
! 1057: return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
! 1058: }
! 1059:
! 1060: void
! 1061: fdcstart(fdc)
! 1062: struct fdc_softc *fdc;
! 1063: {
! 1064:
! 1065: #ifdef DIAGNOSTIC
! 1066: /* only got here if controller's drive queue was inactive; should
! 1067: be in idle state */
! 1068: if (fdc->sc_state != DEVIDLE) {
! 1069: printf("fdcstart: not idle\n");
! 1070: return;
! 1071: }
! 1072: #endif
! 1073: (void) fdcstate(fdc);
! 1074: }
! 1075:
! 1076: void
! 1077: fdcstatus(fdc, s)
! 1078: struct fdc_softc *fdc;
! 1079: char *s;
! 1080: {
! 1081: struct fd_softc *fd = TAILQ_FIRST(&fdc->sc_drives);
! 1082: int n;
! 1083:
! 1084: /* Just print last status */
! 1085: n = fdc->sc_nstat;
! 1086:
! 1087: #if 0
! 1088: if (n == 0) {
! 1089: fdc_wrfifo(fdc, NE7CMD_SENSEI);
! 1090: (void) fdcresult(fdc);
! 1091: n = 2;
! 1092: }
! 1093: #endif
! 1094:
! 1095: printf("%s: %s: state %d",
! 1096: fd ? fd->sc_dv.dv_xname : "fdc", s, fdc->sc_state);
! 1097:
! 1098: switch (n) {
! 1099: case 0:
! 1100: printf("\n");
! 1101: break;
! 1102: case 2:
! 1103: printf(" (st0 %b cyl %d)\n",
! 1104: fdc->sc_status[0], NE7_ST0BITS,
! 1105: fdc->sc_status[1]);
! 1106: break;
! 1107: case 7:
! 1108: printf(" (st0 %b st1 %b st2 %b cyl %d head %d sec %d)\n",
! 1109: fdc->sc_status[0], NE7_ST0BITS,
! 1110: fdc->sc_status[1], NE7_ST1BITS,
! 1111: fdc->sc_status[2], NE7_ST2BITS,
! 1112: fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
! 1113: break;
! 1114: #ifdef DIAGNOSTIC
! 1115: default:
! 1116: printf(" fdcstatus: weird size: %d\n", n);
! 1117: break;
! 1118: #endif
! 1119: }
! 1120: }
! 1121:
! 1122: void
! 1123: fdctimeout(arg)
! 1124: void *arg;
! 1125: {
! 1126: struct fdc_softc *fdc = arg;
! 1127: struct fd_softc *fd;
! 1128: int s;
! 1129:
! 1130: s = splbio();
! 1131: fd = TAILQ_FIRST(&fdc->sc_drives);
! 1132: if (fd == NULL) {
! 1133: printf("%s: timeout but no I/O pending: state %d, istatus=%d\n",
! 1134: fdc->sc_dev.dv_xname, fdc->sc_state, fdc->sc_istatus);
! 1135: fdc->sc_state = DEVIDLE;
! 1136: goto out;
! 1137: }
! 1138:
! 1139: if (fd->sc_q.b_actf)
! 1140: fdc->sc_state++;
! 1141: else
! 1142: fdc->sc_state = DEVIDLE;
! 1143:
! 1144: (void) fdcstate(fdc);
! 1145: out:
! 1146: splx(s);
! 1147:
! 1148: }
! 1149:
! 1150: void
! 1151: fdcpseudointr(arg)
! 1152: void *arg;
! 1153: {
! 1154: struct fdc_softc *fdc = arg;
! 1155: int s;
! 1156:
! 1157: /* Just ensure it has the right spl. */
! 1158: s = splbio();
! 1159: (void) fdcstate(fdc);
! 1160: splx(s);
! 1161: }
! 1162:
! 1163:
! 1164: /*
! 1165: * Hardware interrupt entry point.
! 1166: * Unfortunately, we have no reliable way to determine that the
! 1167: * interrupt really came from the floppy controller; just hope
! 1168: * that the other devices that share this interrupt can do better..
! 1169: */
! 1170: int
! 1171: fdchwintr(arg)
! 1172: void *arg;
! 1173: {
! 1174: struct fdc_softc *fdc = arg;
! 1175: bus_space_tag_t t = fdc->sc_bustag;
! 1176: bus_space_handle_t h = fdc->sc_handle;
! 1177:
! 1178: switch (fdc->sc_itask) {
! 1179: case FDC_ITASK_NONE:
! 1180: return (0);
! 1181: case FDC_ITASK_SENSEI:
! 1182: if (fdc_wrfifo(fdc, NE7CMD_SENSEI) != 0 || fdcresult(fdc) == -1)
! 1183: fdc->sc_istatus = FDC_ISTATUS_ERROR;
! 1184: else
! 1185: fdc->sc_istatus = FDC_ISTATUS_DONE;
! 1186: softintr_schedule(fdc->sc_sicookie);
! 1187: return (1);
! 1188: case FDC_ITASK_RESULT:
! 1189: if (fdcresult(fdc) == -1)
! 1190: fdc->sc_istatus = FDC_ISTATUS_ERROR;
! 1191: else
! 1192: fdc->sc_istatus = FDC_ISTATUS_DONE;
! 1193: softintr_schedule(fdc->sc_sicookie);
! 1194: return (1);
! 1195: case FDC_ITASK_DMA:
! 1196: /* Proceed with pseudo-DMA below */
! 1197: break;
! 1198: default:
! 1199: printf("fdc: stray hard interrupt: itask=%d\n", fdc->sc_itask);
! 1200: fdc->sc_istatus = FDC_ISTATUS_SPURIOUS;
! 1201: softintr_schedule(fdc->sc_sicookie);
! 1202: return (1);
! 1203: }
! 1204:
! 1205: /*
! 1206: * Pseudo DMA in progress
! 1207: */
! 1208: for (;;) {
! 1209: u_int8_t msr;
! 1210:
! 1211: msr = bus_space_read_1(t, h, FDREG77_MSR);
! 1212:
! 1213: if ((msr & NE7_RQM) == 0)
! 1214: /* That's all this round */
! 1215: break;
! 1216:
! 1217: if ((msr & NE7_NDM) == 0) {
! 1218: fdcresult(fdc);
! 1219: fdc->sc_istatus = FDC_ISTATUS_DONE;
! 1220: softintr_schedule(fdc->sc_sicookie);
! 1221: #ifdef FD_DEBUG
! 1222: if (fdc_debug > 1)
! 1223: printf("fdc: overrun: msr = %x, tc = %d\n",
! 1224: msr, fdc->sc_tc);
! 1225: #endif
! 1226: break;
! 1227: }
! 1228:
! 1229: /* Another byte can be transferred */
! 1230: if ((msr & NE7_DIO) != 0)
! 1231: *fdc->sc_data =
! 1232: bus_space_read_1(t, h, FDREG77_FIFO);
! 1233: else
! 1234: bus_space_write_1(t, h, FDREG77_FIFO,
! 1235: *fdc->sc_data);
! 1236:
! 1237: fdc->sc_data++;
! 1238: if (--fdc->sc_tc == 0) {
! 1239: fdc->sc_istatus = FDC_ISTATUS_DONE;
! 1240: FTC_FLIP;
! 1241: fdcresult(fdc);
! 1242: softintr_schedule(fdc->sc_sicookie);
! 1243: break;
! 1244: }
! 1245: }
! 1246: return (1);
! 1247: }
! 1248:
! 1249: void
! 1250: fdcswintr(arg)
! 1251: void *arg;
! 1252: {
! 1253: struct fdc_softc *fdc = arg;
! 1254: int s;
! 1255:
! 1256: if (fdc->sc_istatus == FDC_ISTATUS_NONE)
! 1257: /* This (software) interrupt is not for us */
! 1258: return;
! 1259:
! 1260: switch (fdc->sc_istatus) {
! 1261: case FDC_ISTATUS_ERROR:
! 1262: printf("fdc: ierror status: state %d\n", fdc->sc_state);
! 1263: break;
! 1264: case FDC_ISTATUS_SPURIOUS:
! 1265: printf("fdc: spurious interrupt: state %d\n", fdc->sc_state);
! 1266: break;
! 1267: }
! 1268:
! 1269: s = splbio();
! 1270: fdcstate(fdc);
! 1271: splx(s);
! 1272: return;
! 1273: }
! 1274:
! 1275: int
! 1276: fdcstate(fdc)
! 1277: struct fdc_softc *fdc;
! 1278: {
! 1279: #define st0 fdc->sc_status[0]
! 1280: #define st1 fdc->sc_status[1]
! 1281: #define cyl fdc->sc_status[1]
! 1282: #define FDC_WRFIFO(fdc, c) \
! 1283: do { \
! 1284: if (fdc_wrfifo(fdc, (c))) { \
! 1285: goto xxx; \
! 1286: } \
! 1287: } while(0)
! 1288:
! 1289: struct fd_softc *fd;
! 1290: struct buf *bp;
! 1291: int read, head, sec, nblks;
! 1292: struct fd_type *type;
! 1293: struct fd_formb *finfo = NULL;
! 1294:
! 1295: if (fdc->sc_istatus == FDC_ISTATUS_ERROR) {
! 1296: /* Prevent loop if the reset sequence produces errors */
! 1297: if (fdc->sc_state != RESETCOMPLETE &&
! 1298: fdc->sc_state != RECALWAIT &&
! 1299: fdc->sc_state != RECALCOMPLETE)
! 1300: fdc->sc_state = DORESET;
! 1301: }
! 1302:
! 1303: /* Clear I task/status field */
! 1304: fdc->sc_istatus = FDC_ISTATUS_NONE;
! 1305: fdc->sc_itask = FDC_ITASK_NONE;
! 1306:
! 1307: loop:
! 1308: /* Is there a drive for the controller to do a transfer with? */
! 1309: fd = TAILQ_FIRST(&fdc->sc_drives);
! 1310: if (fd == NULL) {
! 1311: fdc->sc_state = DEVIDLE;
! 1312: return (0);
! 1313: }
! 1314:
! 1315: /* Is there a transfer to this drive? If not, deactivate drive. */
! 1316: bp = fd->sc_q.b_actf;
! 1317: if (bp == NULL) {
! 1318: fd->sc_ops = 0;
! 1319: TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
! 1320: fd->sc_q.b_active = 0;
! 1321: goto loop;
! 1322: }
! 1323:
! 1324: if (bp->b_flags & B_FORMAT)
! 1325: finfo = (struct fd_formb *)bp->b_data;
! 1326:
! 1327: switch (fdc->sc_state) {
! 1328: case DEVIDLE:
! 1329: fdc->sc_errors = 0;
! 1330: fd->sc_skip = 0;
! 1331: fd->sc_bcount = bp->b_bcount;
! 1332: fd->sc_blkno = (bp->b_blkno * DEV_BSIZE) / FD_BSIZE(fd);
! 1333: timeout_del(&fd->sc_motoroff_to);
! 1334: if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
! 1335: fdc->sc_state = MOTORWAIT;
! 1336: return (1);
! 1337: }
! 1338: if ((fd->sc_flags & FD_MOTOR) == 0) {
! 1339: /* Turn on the motor, being careful about pairing. */
! 1340: struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1];
! 1341: if (ofd && ofd->sc_flags & FD_MOTOR) {
! 1342: timeout_del(&ofd->sc_motoroff_to);
! 1343: ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
! 1344: }
! 1345: fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
! 1346: fd_set_motor(fdc);
! 1347: fdc->sc_state = MOTORWAIT;
! 1348: if ((fdc->sc_flags & FDC_NEEDMOTORWAIT) != 0) { /*XXX*/
! 1349: /* Allow .25s for motor to stabilize. */
! 1350: timeout_add(&fd->sc_motoron_to, hz / 4);
! 1351: } else {
! 1352: fd->sc_flags &= ~FD_MOTOR_WAIT;
! 1353: goto loop;
! 1354: }
! 1355: return (1);
! 1356: }
! 1357: /* Make sure the right drive is selected. */
! 1358: fd_set_motor(fdc);
! 1359:
! 1360: if (fdc_diskchange(fdc))
! 1361: goto dodskchg;
! 1362:
! 1363: /*FALLTHROUGH*/
! 1364: case DOSEEK:
! 1365: doseek:
! 1366: if ((fdc->sc_flags & FDC_EIS) &&
! 1367: (bp->b_flags & B_FORMAT) == 0) {
! 1368: fd->sc_cylin = bp->b_cylinder;
! 1369: /* We use implied seek */
! 1370: goto doio;
! 1371: }
! 1372:
! 1373: if (fd->sc_cylin == bp->b_cylinder)
! 1374: goto doio;
! 1375:
! 1376: fd->sc_cylin = -1;
! 1377: fdc->sc_state = SEEKWAIT;
! 1378: fdc->sc_nstat = 0;
! 1379:
! 1380: fd->sc_dk.dk_seek++;
! 1381:
! 1382: disk_busy(&fd->sc_dk);
! 1383: timeout_add(&fdc->fdctimeout_to, 4 * hz);
! 1384:
! 1385: /* specify command */
! 1386: FDC_WRFIFO(fdc, NE7CMD_SPECIFY);
! 1387: FDC_WRFIFO(fdc, fd->sc_type->steprate);
! 1388: /* XXX head load time == 6ms */
! 1389: FDC_WRFIFO(fdc, 6 | NE7_SPECIFY_NODMA);
! 1390:
! 1391: fdc->sc_itask = FDC_ITASK_SENSEI;
! 1392: /* seek function */
! 1393: FDC_WRFIFO(fdc, NE7CMD_SEEK);
! 1394: FDC_WRFIFO(fdc, fd->sc_drive); /* drive number */
! 1395: FDC_WRFIFO(fdc, bp->b_cylinder * fd->sc_type->step);
! 1396: return (1);
! 1397:
! 1398: case DODSKCHG:
! 1399: dodskchg:
! 1400: /*
! 1401: * Disk change: force a seek operation by going to cyl 1
! 1402: * followed by a recalibrate.
! 1403: */
! 1404: disk_busy(&fd->sc_dk);
! 1405: timeout_add(&fdc->fdctimeout_to, 4 * hz);
! 1406: fd->sc_cylin = -1;
! 1407: fdc->sc_nstat = 0;
! 1408: fdc->sc_state = DSKCHGWAIT;
! 1409:
! 1410: fdc->sc_itask = FDC_ITASK_SENSEI;
! 1411: /* seek function */
! 1412: FDC_WRFIFO(fdc, NE7CMD_SEEK);
! 1413: FDC_WRFIFO(fdc, fd->sc_drive); /* drive number */
! 1414: FDC_WRFIFO(fdc, 1 * fd->sc_type->step);
! 1415: return (1);
! 1416:
! 1417: case DSKCHGWAIT:
! 1418: timeout_del(&fdc->fdctimeout_to);
! 1419: disk_unbusy(&fd->sc_dk, 0, 0);
! 1420: if (fdc->sc_nstat != 2 || (st0 & 0xf8) != 0x20 ||
! 1421: cyl != 1 * fd->sc_type->step) {
! 1422: fdcstatus(fdc, "dskchg seek failed");
! 1423: fdc->sc_state = DORESET;
! 1424: } else
! 1425: fdc->sc_state = DORECAL;
! 1426:
! 1427: if (fdc_diskchange(fdc)) {
! 1428: printf("%s: cannot clear disk change status\n",
! 1429: fdc->sc_dev.dv_xname);
! 1430: fdc->sc_state = DORESET;
! 1431: }
! 1432: goto loop;
! 1433:
! 1434: case DOIO:
! 1435: doio:
! 1436: if (finfo != NULL)
! 1437: fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) -
! 1438: (char *)finfo;
! 1439: type = fd->sc_type;
! 1440: sec = fd->sc_blkno % type->seccyl;
! 1441: nblks = type->seccyl - sec;
! 1442: nblks = min(nblks, fd->sc_bcount / FD_BSIZE(fd));
! 1443: nblks = min(nblks, FDC_MAXIOSIZE / FD_BSIZE(fd));
! 1444: fd->sc_nblks = nblks;
! 1445: fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FD_BSIZE(fd);
! 1446: head = sec / type->sectrac;
! 1447: sec -= head * type->sectrac;
! 1448: #ifdef DIAGNOSTIC
! 1449: {
! 1450: daddr64_t block;
! 1451:
! 1452: block = (fd->sc_cylin * type->heads + head) *
! 1453: type->sectrac + sec;
! 1454: if (block != fd->sc_blkno) {
! 1455: printf("fdcintr: block %lld != blkno %d\n",
! 1456: block, (int)fd->sc_blkno);
! 1457: #if defined(FD_DEBUG) && defined(DDB)
! 1458: Debugger();
! 1459: #endif
! 1460: }
! 1461: }
! 1462: #endif
! 1463: read = bp->b_flags & B_READ;
! 1464:
! 1465: /* Setup for pseudo DMA */
! 1466: fdc->sc_data = bp->b_data + fd->sc_skip;
! 1467: fdc->sc_tc = fd->sc_nbytes;
! 1468:
! 1469: bus_space_write_1(fdc->sc_bustag, fdc->sc_handle,
! 1470: FDREG77_DRS, type->rate);
! 1471: #ifdef FD_DEBUG
! 1472: if (fdc_debug > 1)
! 1473: printf("fdcstate: doio: %s drive %d "
! 1474: "track %d head %d sec %d nblks %d\n",
! 1475: finfo ? "format" :
! 1476: (read ? "read" : "write"),
! 1477: fd->sc_drive, fd->sc_cylin, head, sec, nblks);
! 1478: #endif
! 1479: fdc->sc_state = IOCOMPLETE;
! 1480: fdc->sc_itask = FDC_ITASK_DMA;
! 1481: fdc->sc_nstat = 0;
! 1482:
! 1483: disk_busy(&fd->sc_dk);
! 1484:
! 1485: /* allow 3 seconds for operation */
! 1486: timeout_add(&fdc->fdctimeout_to, 3 * hz);
! 1487:
! 1488: if (finfo != NULL) {
! 1489: /* formatting */
! 1490: FDC_WRFIFO(fdc, NE7CMD_FORMAT);
! 1491: FDC_WRFIFO(fdc, (head << 2) | fd->sc_drive);
! 1492: FDC_WRFIFO(fdc, finfo->fd_formb_secshift);
! 1493: FDC_WRFIFO(fdc, finfo->fd_formb_nsecs);
! 1494: FDC_WRFIFO(fdc, finfo->fd_formb_gaplen);
! 1495: FDC_WRFIFO(fdc, finfo->fd_formb_fillbyte);
! 1496: } else {
! 1497: if (read)
! 1498: FDC_WRFIFO(fdc, NE7CMD_READ);
! 1499: else
! 1500: FDC_WRFIFO(fdc, NE7CMD_WRITE);
! 1501: FDC_WRFIFO(fdc, (head << 2) | fd->sc_drive);
! 1502: FDC_WRFIFO(fdc, fd->sc_cylin); /*track*/
! 1503: FDC_WRFIFO(fdc, head);
! 1504: FDC_WRFIFO(fdc, sec + 1); /*sector+1*/
! 1505: FDC_WRFIFO(fdc, type->secsize); /*sector size*/
! 1506: FDC_WRFIFO(fdc, type->sectrac); /*secs/track*/
! 1507: FDC_WRFIFO(fdc, type->gap1); /*gap1 size*/
! 1508: FDC_WRFIFO(fdc, type->datalen); /*data length*/
! 1509: }
! 1510:
! 1511: return (1); /* will return later */
! 1512:
! 1513: case SEEKWAIT:
! 1514: timeout_del(&fdc->fdctimeout_to);
! 1515: fdc->sc_state = SEEKCOMPLETE;
! 1516: if (fdc->sc_flags & FDC_NEEDHEADSETTLE) {
! 1517: /* allow 1/50 second for heads to settle */
! 1518: timeout_add(&fdc->fdcpseudointr_to, hz / 50);
! 1519: return (1); /* will return later */
! 1520: }
! 1521: /*FALLTHROUGH*/
! 1522: case SEEKCOMPLETE:
! 1523: /* no data on seek */
! 1524: disk_unbusy(&fd->sc_dk, 0, 0);
! 1525:
! 1526: /* Make sure seek really happened. */
! 1527: if (fdc->sc_nstat != 2 || (st0 & 0xf8) != 0x20 ||
! 1528: cyl != bp->b_cylinder * fd->sc_type->step) {
! 1529: #ifdef FD_DEBUG
! 1530: if (fdc_debug)
! 1531: fdcstatus(fdc, "seek failed");
! 1532: #endif
! 1533: fdcretry(fdc);
! 1534: goto loop;
! 1535: }
! 1536: fd->sc_cylin = bp->b_cylinder;
! 1537: goto doio;
! 1538:
! 1539: case IOTIMEDOUT:
! 1540: /*
! 1541: * Try to abort the I/O operation without resetting
! 1542: * the chip first. Poke TC and arrange to pick up
! 1543: * the timed out I/O command's status.
! 1544: */
! 1545: fdc->sc_itask = FDC_ITASK_RESULT;
! 1546: fdc->sc_state = IOCLEANUPWAIT;
! 1547: fdc->sc_nstat = 0;
! 1548: /* 1/10 second should be enough */
! 1549: timeout_add(&fdc->fdctimeout_to, hz / 10);
! 1550: return (1);
! 1551:
! 1552: case IOCLEANUPTIMEDOUT:
! 1553: case SEEKTIMEDOUT:
! 1554: case RECALTIMEDOUT:
! 1555: case RESETTIMEDOUT:
! 1556: case DSKCHGTIMEDOUT:
! 1557: fdcstatus(fdc, "timeout");
! 1558:
! 1559: /* All other timeouts always roll through to a chip reset */
! 1560: fdcretry(fdc);
! 1561:
! 1562: /* Force reset, no matter what fdcretry() says */
! 1563: fdc->sc_state = DORESET;
! 1564: goto loop;
! 1565:
! 1566: case IOCLEANUPWAIT: /* IO FAILED, cleanup succeeded */
! 1567: timeout_del(&fdc->fdctimeout_to);
! 1568: disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid),
! 1569: (bp->b_flags & B_READ));
! 1570: fdcretry(fdc);
! 1571: goto loop;
! 1572:
! 1573: case IOCOMPLETE: /* IO DONE, post-analyze */
! 1574: timeout_del(&fdc->fdctimeout_to);
! 1575:
! 1576: disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid),
! 1577: (bp->b_flags & B_READ));
! 1578:
! 1579: if (fdc->sc_nstat != 7 || st1 != 0 ||
! 1580: ((st0 & 0xf8) != 0 &&
! 1581: ((st0 & 0xf8) != 0x20 || (fdc->sc_cfg & CFG_EIS) == 0))) {
! 1582: #ifdef FD_DEBUG
! 1583: if (fdc_debug) {
! 1584: fdcstatus(fdc,
! 1585: bp->b_flags & B_READ
! 1586: ? "read failed" : "write failed");
! 1587: printf("blkno %lld nblks %d nstat %d tc %d\n",
! 1588: fd->sc_blkno, fd->sc_nblks,
! 1589: fdc->sc_nstat, fdc->sc_tc);
! 1590: }
! 1591: #endif
! 1592: if (fdc->sc_nstat == 7 &&
! 1593: (st1 & ST1_OVERRUN) == ST1_OVERRUN) {
! 1594:
! 1595: /*
! 1596: * Silently retry overruns if no other
! 1597: * error bit is set. Adjust threshold.
! 1598: */
! 1599: int thr = fdc->sc_cfg & CFG_THRHLD_MASK;
! 1600: if (thr < 15) {
! 1601: thr++;
! 1602: fdc->sc_cfg &= ~CFG_THRHLD_MASK;
! 1603: fdc->sc_cfg |= (thr & CFG_THRHLD_MASK);
! 1604: #ifdef FD_DEBUG
! 1605: if (fdc_debug)
! 1606: printf("fdc: %d -> threshold\n", thr);
! 1607: #endif
! 1608: fdconf(fdc);
! 1609: fdc->sc_overruns = 0;
! 1610: }
! 1611: if (++fdc->sc_overruns < 3) {
! 1612: fdc->sc_state = DOIO;
! 1613: goto loop;
! 1614: }
! 1615: }
! 1616: fdcretry(fdc);
! 1617: goto loop;
! 1618: }
! 1619: if (fdc->sc_errors) {
! 1620: diskerr(bp, "fd", "soft error", LOG_PRINTF,
! 1621: fd->sc_skip / FD_BSIZE(fd),
! 1622: (struct disklabel *)NULL);
! 1623: printf("\n");
! 1624: fdc->sc_errors = 0;
! 1625: } else {
! 1626: if (--fdc->sc_overruns < -20) {
! 1627: int thr = fdc->sc_cfg & CFG_THRHLD_MASK;
! 1628: if (thr > 0) {
! 1629: thr--;
! 1630: fdc->sc_cfg &= ~CFG_THRHLD_MASK;
! 1631: fdc->sc_cfg |= (thr & CFG_THRHLD_MASK);
! 1632: #ifdef FD_DEBUG
! 1633: if (fdc_debug)
! 1634: printf("fdc: %d -> threshold\n", thr);
! 1635: #endif
! 1636: fdconf(fdc);
! 1637: }
! 1638: fdc->sc_overruns = 0;
! 1639: }
! 1640: }
! 1641: fd->sc_blkno += fd->sc_nblks;
! 1642: fd->sc_skip += fd->sc_nbytes;
! 1643: fd->sc_bcount -= fd->sc_nbytes;
! 1644: if (finfo == NULL && fd->sc_bcount > 0) {
! 1645: bp->b_cylinder = fd->sc_blkno / fd->sc_type->seccyl;
! 1646: goto doseek;
! 1647: }
! 1648: fdfinish(fd, bp);
! 1649: goto loop;
! 1650:
! 1651: case DORESET:
! 1652: /* try a reset, keep motor on */
! 1653: fd_set_motor(fdc);
! 1654: delay(100);
! 1655: fdc->sc_nstat = 0;
! 1656: fdc->sc_itask = FDC_ITASK_SENSEI;
! 1657: fdc->sc_state = RESETCOMPLETE;
! 1658: timeout_add(&fdc->fdctimeout_to, hz / 2);
! 1659: fdc_reset(fdc);
! 1660: return (1); /* will return later */
! 1661:
! 1662: case RESETCOMPLETE:
! 1663: timeout_del(&fdc->fdctimeout_to);
! 1664: fdconf(fdc);
! 1665:
! 1666: /* FALLTHROUGH */
! 1667: case DORECAL:
! 1668: fdc->sc_state = RECALWAIT;
! 1669: fdc->sc_itask = FDC_ITASK_SENSEI;
! 1670: fdc->sc_nstat = 0;
! 1671: timeout_add(&fdc->fdctimeout_to, 5 * hz);
! 1672: /* recalibrate function */
! 1673: FDC_WRFIFO(fdc, NE7CMD_RECAL);
! 1674: FDC_WRFIFO(fdc, fd->sc_drive);
! 1675: return (1); /* will return later */
! 1676:
! 1677: case RECALWAIT:
! 1678: timeout_del(&fdc->fdctimeout_to);
! 1679: fdc->sc_state = RECALCOMPLETE;
! 1680: if (fdc->sc_flags & FDC_NEEDHEADSETTLE) {
! 1681: /* allow 1/30 second for heads to settle */
! 1682: timeout_add(&fdc->fdcpseudointr_to, hz / 30);
! 1683: return (1); /* will return later */
! 1684: }
! 1685:
! 1686: case RECALCOMPLETE:
! 1687: if (fdc->sc_nstat != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
! 1688: #ifdef FD_DEBUG
! 1689: if (fdc_debug)
! 1690: fdcstatus(fdc, "recalibrate failed");
! 1691: #endif
! 1692: fdcretry(fdc);
! 1693: goto loop;
! 1694: }
! 1695: fd->sc_cylin = 0;
! 1696: goto doseek;
! 1697:
! 1698: case MOTORWAIT:
! 1699: if (fd->sc_flags & FD_MOTOR_WAIT)
! 1700: return (1); /* time's not up yet */
! 1701: goto doseek;
! 1702:
! 1703: default:
! 1704: fdcstatus(fdc, "stray interrupt");
! 1705: return (1);
! 1706: }
! 1707: #ifdef DIAGNOSTIC
! 1708: panic("fdcintr: impossible");
! 1709: #endif
! 1710:
! 1711: xxx:
! 1712: /*
! 1713: * We get here if the chip locks up in FDC_WRFIFO()
! 1714: * Cancel any operation and schedule a reset
! 1715: */
! 1716: timeout_del(&fdc->fdctimeout_to);
! 1717: fdcretry(fdc);
! 1718: fdc->sc_state = DORESET;
! 1719: goto loop;
! 1720:
! 1721: #undef st0
! 1722: #undef st1
! 1723: #undef cyl
! 1724: }
! 1725:
! 1726: void
! 1727: fdcretry(fdc)
! 1728: struct fdc_softc *fdc;
! 1729: {
! 1730: struct fd_softc *fd;
! 1731: struct buf *bp;
! 1732: int error = EIO;
! 1733:
! 1734: fd = TAILQ_FIRST(&fdc->sc_drives);
! 1735: bp = fd->sc_q.b_actf;
! 1736:
! 1737: fdc->sc_overruns = 0;
! 1738: if (fd->sc_opts & FDOPT_NORETRY)
! 1739: goto fail;
! 1740:
! 1741: switch (fdc->sc_errors) {
! 1742: case 0:
! 1743: if (fdc->sc_nstat == 7 &&
! 1744: (fdc->sc_status[0] & 0xd8) == 0x40 &&
! 1745: (fdc->sc_status[1] & 0x2) == 0x2) {
! 1746: printf("%s: read-only medium\n", fd->sc_dv.dv_xname);
! 1747: error = EROFS;
! 1748: goto failsilent;
! 1749: }
! 1750: /* try again */
! 1751: fdc->sc_state =
! 1752: (fdc->sc_flags & FDC_EIS) ? DOIO : DOSEEK;
! 1753: break;
! 1754:
! 1755: case 1: case 2: case 3:
! 1756: /* didn't work; try recalibrating */
! 1757: fdc->sc_state = DORECAL;
! 1758: break;
! 1759:
! 1760: case 4:
! 1761: if (fdc->sc_nstat == 7 &&
! 1762: fdc->sc_status[0] == 0 &&
! 1763: fdc->sc_status[1] == 0 &&
! 1764: fdc->sc_status[2] == 0) {
! 1765: /*
! 1766: * We've retried a few times and we've got
! 1767: * valid status and all three status bytes
! 1768: * are zero. Assume this condition is the
! 1769: * result of no disk loaded into the drive.
! 1770: */
! 1771: printf("%s: no medium?\n", fd->sc_dv.dv_xname);
! 1772: error = ENODEV;
! 1773: goto failsilent;
! 1774: }
! 1775:
! 1776: /* still no go; reset the bastard */
! 1777: fdc->sc_state = DORESET;
! 1778: break;
! 1779:
! 1780: default:
! 1781: fail:
! 1782: if ((fd->sc_opts & FDOPT_SILENT) == 0) {
! 1783: diskerr(bp, "fd", "hard error", LOG_PRINTF,
! 1784: fd->sc_skip / FD_BSIZE(fd),
! 1785: (struct disklabel *)NULL);
! 1786: printf("\n");
! 1787: fdcstatus(fdc, "controller status");
! 1788: }
! 1789:
! 1790: failsilent:
! 1791: bp->b_flags |= B_ERROR;
! 1792: bp->b_error = error;
! 1793: fdfinish(fd, bp);
! 1794: }
! 1795: fdc->sc_errors++;
! 1796: }
! 1797:
! 1798: daddr64_t
! 1799: fdsize(dev)
! 1800: dev_t dev;
! 1801: {
! 1802:
! 1803: /* Swapping to floppies would not make sense. */
! 1804: return (-1);
! 1805: }
! 1806:
! 1807: int
! 1808: fddump(dev, blkno, va, size)
! 1809: dev_t dev;
! 1810: daddr64_t blkno;
! 1811: caddr_t va;
! 1812: size_t size;
! 1813: {
! 1814:
! 1815: /* Not implemented. */
! 1816: return (EINVAL);
! 1817: }
! 1818:
! 1819: int
! 1820: fdioctl(dev, cmd, addr, flag, p)
! 1821: dev_t dev;
! 1822: u_long cmd;
! 1823: caddr_t addr;
! 1824: int flag;
! 1825: struct proc *p;
! 1826: {
! 1827: struct fd_softc *fd;
! 1828: struct fdc_softc *fdc;
! 1829: int unit;
! 1830: int error;
! 1831: #ifdef FD_DEBUG
! 1832: int i;
! 1833: #endif
! 1834:
! 1835: unit = FDUNIT(dev);
! 1836: if (unit >= fd_cd.cd_ndevs)
! 1837: return (ENXIO);
! 1838:
! 1839: fd = fd_cd.cd_devs[FDUNIT(dev)];
! 1840: fdc = (struct fdc_softc *)fd->sc_dv.dv_parent;
! 1841:
! 1842: switch (cmd) {
! 1843: case DIOCGDINFO:
! 1844: *(struct disklabel *)addr = *(fd->sc_dk.dk_label);
! 1845: return 0;
! 1846:
! 1847: case DIOCWLABEL:
! 1848: if ((flag & FWRITE) == 0)
! 1849: return EBADF;
! 1850: /* XXX do something */
! 1851: return (0);
! 1852:
! 1853: case DIOCWDINFO:
! 1854: if ((flag & FWRITE) == 0)
! 1855: return (EBADF);
! 1856:
! 1857: error = setdisklabel(fd->sc_dk.dk_label,
! 1858: (struct disklabel *)addr, 0);
! 1859: if (error)
! 1860: return (error);
! 1861:
! 1862: error = writedisklabel(DISKLABELDEV(dev), fdstrategy,
! 1863: fd->sc_dk.dk_label);
! 1864: return (error);
! 1865:
! 1866: case DIOCLOCK:
! 1867: /*
! 1868: * Nothing to do here, really.
! 1869: */
! 1870: return (0);
! 1871:
! 1872: case MTIOCTOP:
! 1873: if (((struct mtop *)addr)->mt_op != MTOFFL)
! 1874: return (EIO);
! 1875: /* FALLTHROUGH */
! 1876: case DIOCEJECT:
! 1877: if (fdc->sc_flags & FDC_NOEJECT)
! 1878: return (ENODEV);
! 1879: fd_do_eject(fd);
! 1880: return (0);
! 1881:
! 1882: case FD_FORM:
! 1883: if ((flag & FWRITE) == 0)
! 1884: return (EBADF); /* must be opened for writing */
! 1885: else if (((struct fd_formb *)addr)->format_version !=
! 1886: FD_FORMAT_VERSION)
! 1887: return (EINVAL);/* wrong version of formatting prog */
! 1888: else
! 1889: return fdformat(dev, (struct fd_formb *)addr, p);
! 1890: break;
! 1891:
! 1892: case FD_GTYPE: /* get drive options */
! 1893: *(struct fd_type *)addr = *fd->sc_type;
! 1894: return (0);
! 1895:
! 1896: case FD_GOPTS: /* get drive options */
! 1897: *(int *)addr = fd->sc_opts;
! 1898: return (0);
! 1899:
! 1900: case FD_SOPTS: /* set drive options */
! 1901: fd->sc_opts = *(int *)addr;
! 1902: return (0);
! 1903:
! 1904: #ifdef FD_DEBUG
! 1905: case _IO('f', 100):
! 1906: fdc_wrfifo(fdc, NE7CMD_DUMPREG);
! 1907: fdcresult(fdc);
! 1908: printf("fdc: dumpreg(%d regs): <", fdc->sc_nstat);
! 1909: for (i = 0; i < fdc->sc_nstat; i++)
! 1910: printf(" 0x%x", fdc->sc_status[i]);
! 1911: printf(">\n");
! 1912: return (0);
! 1913:
! 1914: case _IOW('f', 101, int):
! 1915: fdc->sc_cfg &= ~CFG_THRHLD_MASK;
! 1916: fdc->sc_cfg |= (*(int *)addr & CFG_THRHLD_MASK);
! 1917: fdconf(fdc);
! 1918: return (0);
! 1919:
! 1920: case _IO('f', 102):
! 1921: fdc_wrfifo(fdc, NE7CMD_SENSEI);
! 1922: fdcresult(fdc);
! 1923: printf("fdc: sensei(%d regs): <", fdc->sc_nstat);
! 1924: for (i=0; i< fdc->sc_nstat; i++)
! 1925: printf(" 0x%x", fdc->sc_status[i]);
! 1926: printf(">\n");
! 1927: return (0);
! 1928: #endif
! 1929: default:
! 1930: return (ENOTTY);
! 1931: }
! 1932: }
! 1933:
! 1934: int
! 1935: fdformat(dev, finfo, p)
! 1936: dev_t dev;
! 1937: struct fd_formb *finfo;
! 1938: struct proc *p;
! 1939: {
! 1940: int rv = 0;
! 1941: struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
! 1942: struct fd_type *type = fd->sc_type;
! 1943: struct buf *bp;
! 1944:
! 1945: /* set up a buffer header for fdstrategy() */
! 1946: bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT);
! 1947: if (bp == NULL)
! 1948: return (ENOBUFS);
! 1949:
! 1950: bzero((void *)bp, sizeof(struct buf));
! 1951: bp->b_flags = B_BUSY | B_PHYS | B_FORMAT;
! 1952: bp->b_proc = p;
! 1953: bp->b_dev = dev;
! 1954:
! 1955: /*
! 1956: * Calculate a fake blkno, so fdstrategy() would initiate a
! 1957: * seek to the requested cylinder.
! 1958: */
! 1959: bp->b_blkno = ((finfo->cyl * (type->sectrac * type->heads)
! 1960: + finfo->head * type->sectrac) * FD_BSIZE(fd))
! 1961: / DEV_BSIZE;
! 1962:
! 1963: bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
! 1964: bp->b_data = (caddr_t)finfo;
! 1965:
! 1966: #ifdef FD_DEBUG
! 1967: if (fdc_debug) {
! 1968: int i;
! 1969:
! 1970: printf("fdformat: blkno 0x%llx count %ld\n",
! 1971: (unsigned long long)bp->b_blkno, bp->b_bcount);
! 1972:
! 1973: printf("\tcyl:\t%d\n", finfo->cyl);
! 1974: printf("\thead:\t%d\n", finfo->head);
! 1975: printf("\tnsecs:\t%d\n", finfo->fd_formb_nsecs);
! 1976: printf("\tsshft:\t%d\n", finfo->fd_formb_secshift);
! 1977: printf("\tgaplen:\t%d\n", finfo->fd_formb_gaplen);
! 1978: printf("\ttrack data:");
! 1979: for (i = 0; i < finfo->fd_formb_nsecs; i++) {
! 1980: printf(" [c%d h%d s%d]",
! 1981: finfo->fd_formb_cylno(i),
! 1982: finfo->fd_formb_headno(i),
! 1983: finfo->fd_formb_secno(i) );
! 1984: if (finfo->fd_formb_secsize(i) != 2)
! 1985: printf("<sz:%d>", finfo->fd_formb_secsize(i));
! 1986: }
! 1987: printf("\n");
! 1988: }
! 1989: #endif
! 1990:
! 1991: /* now do the format */
! 1992: fdstrategy(bp);
! 1993:
! 1994: /* ...and wait for it to complete */
! 1995: rv = biowait(bp);
! 1996: free(bp, M_TEMP);
! 1997: return (rv);
! 1998: }
! 1999:
! 2000: void
! 2001: fdgetdisklabel(dev)
! 2002: dev_t dev;
! 2003: {
! 2004: int unit = FDUNIT(dev);
! 2005: struct fd_softc *fd = fd_cd.cd_devs[unit];
! 2006: struct disklabel *lp = fd->sc_dk.dk_label;
! 2007: char *errstring;
! 2008:
! 2009: bzero(lp, sizeof(struct disklabel));
! 2010:
! 2011: lp->d_type = DTYPE_FLOPPY;
! 2012: lp->d_secsize = FD_BSIZE(fd);
! 2013: lp->d_secpercyl = fd->sc_type->seccyl;
! 2014: lp->d_nsectors = fd->sc_type->sectrac;
! 2015: lp->d_ncylinders = fd->sc_type->tracks;
! 2016: lp->d_ntracks = fd->sc_type->heads; /* Go figure... */
! 2017: DL_SETDSIZE(lp, (daddr64_t)lp->d_secpercyl * lp->d_ncylinders);
! 2018: lp->d_rpm = 300; /* XXX like it matters... */
! 2019:
! 2020: strncpy(lp->d_typename, "floppy disk", sizeof(lp->d_typename));
! 2021: strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
! 2022: lp->d_interleave = 1;
! 2023: lp->d_version = 1;
! 2024:
! 2025: lp->d_magic = DISKMAGIC;
! 2026: lp->d_magic2 = DISKMAGIC;
! 2027: lp->d_checksum = dkcksum(lp);
! 2028:
! 2029: /*
! 2030: * Call the generic disklabel extraction routine. If there's
! 2031: * not a label there, fake it.
! 2032: */
! 2033: errstring = readdisklabel(DISKLABELDEV(dev), fdstrategy, lp, 0);
! 2034: if (errstring) {
! 2035: /*printf("%s: %s\n", fd->sc_dv.dv_xname, errstring);*/
! 2036: }
! 2037: }
! 2038:
! 2039: void
! 2040: fd_do_eject(fd)
! 2041: struct fd_softc *fd;
! 2042: {
! 2043: struct fdc_softc *fdc = (void *)fd->sc_dv.dv_parent;
! 2044: bus_space_tag_t t = fdc->sc_bustag;
! 2045: bus_space_handle_t h = fdc->sc_handle;
! 2046: u_int8_t dor = FDO_FRST | FDO_FDMAEN | FDO_MOEN(0);
! 2047:
! 2048: bus_space_write_1(t, h, FDREG77_DOR, dor | FDO_EJ);
! 2049: delay(10);
! 2050: bus_space_write_1(t, h, FDREG77_DOR, FDO_FRST | FDO_DS);
! 2051: }
CVSweb