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