Annotation of sys/arch/sparc/dev/xd.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: xd.c,v 1.41 2007/07/01 19:06:57 miod Exp $ */
! 2: /* $NetBSD: xd.c,v 1.37 1997/07/29 09:58:16 fair Exp $ */
! 3:
! 4: /*
! 5: *
! 6: * Copyright (c) 1995 Charles D. Cranor
! 7: * All rights reserved.
! 8: *
! 9: * Redistribution and use in source and binary forms, with or without
! 10: * modification, are permitted provided that the following conditions
! 11: * are met:
! 12: * 1. Redistributions of source code must retain the above copyright
! 13: * notice, this list of conditions and the following disclaimer.
! 14: * 2. Redistributions in binary form must reproduce the above copyright
! 15: * notice, this list of conditions and the following disclaimer in the
! 16: * documentation and/or other materials provided with the distribution.
! 17: * 3. All advertising materials mentioning features or use of this software
! 18: * must display the following acknowledgement:
! 19: * This product includes software developed by Charles D. Cranor.
! 20: * 4. The name of the author may not be used to endorse or promote products
! 21: * derived from this software without specific prior written permission.
! 22: *
! 23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 25: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 26: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 27: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 28: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 29: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 30: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 31: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 32: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 33: */
! 34:
! 35: /*
! 36: *
! 37: * x d . c x y l o g i c s 7 5 3 / 7 0 5 3 v m e / s m d d r i v e r
! 38: *
! 39: * author: Chuck Cranor <chuck@ccrc.wustl.edu>
! 40: * id: $NetBSD: xd.c,v 1.37 1997/07/29 09:58:16 fair Exp $
! 41: * started: 27-Feb-95
! 42: * references: [1] Xylogics Model 753 User's Manual
! 43: * part number: 166-753-001, Revision B, May 21, 1988.
! 44: * "Your Partner For Performance"
! 45: * [2] other NetBSD disk device drivers
! 46: *
! 47: * Special thanks go to Scott E. Campbell of Xylogics, Inc. for taking
! 48: * the time to answer some of my questions about the 753/7053.
! 49: *
! 50: * note: the 753 and the 7053 are programmed the same way, but are
! 51: * different sizes. the 753 is a 6U VME card, while the 7053 is a 9U
! 52: * VME card (found in many VME based suns).
! 53: */
! 54:
! 55: #undef XDC_DEBUG /* full debug */
! 56: #define XDC_DIAG /* extra sanity checks */
! 57: #if defined(DIAGNOSTIC) && !defined(XDC_DIAG)
! 58: #define XDC_DIAG /* link in with master DIAG option */
! 59: #endif
! 60:
! 61: #include <sys/param.h>
! 62: #include <sys/proc.h>
! 63: #include <sys/systm.h>
! 64: #include <sys/kernel.h>
! 65: #include <sys/file.h>
! 66: #include <sys/stat.h>
! 67: #include <sys/ioctl.h>
! 68: #include <sys/buf.h>
! 69: #include <sys/uio.h>
! 70: #include <sys/malloc.h>
! 71: #include <sys/device.h>
! 72: #include <sys/disklabel.h>
! 73: #include <sys/disk.h>
! 74: #include <sys/syslog.h>
! 75: #include <sys/dkbad.h>
! 76: #include <sys/conf.h>
! 77: #include <sys/timeout.h>
! 78:
! 79: #include <uvm/uvm_extern.h>
! 80:
! 81: #include <machine/autoconf.h>
! 82: #include <dev/sun/disklabel.h>
! 83: #include <machine/conf.h>
! 84:
! 85: #include <sparc/dev/xdreg.h>
! 86: #include <sparc/dev/xdvar.h>
! 87: #include <sparc/dev/xio.h>
! 88: #include <sparc/sparc/vaddrs.h>
! 89: #include <sparc/sparc/cpuvar.h>
! 90:
! 91: /*
! 92: * macros
! 93: */
! 94:
! 95: /*
! 96: * XDC_TWAIT: add iorq "N" to tail of SC's wait queue
! 97: */
! 98: #define XDC_TWAIT(SC, N) { \
! 99: (SC)->waitq[(SC)->waitend] = (N); \
! 100: (SC)->waitend = ((SC)->waitend + 1) % XDC_MAXIOPB; \
! 101: (SC)->nwait++; \
! 102: }
! 103:
! 104: /*
! 105: * XDC_HWAIT: add iorq "N" to head of SC's wait queue
! 106: */
! 107: #define XDC_HWAIT(SC, N) { \
! 108: (SC)->waithead = ((SC)->waithead == 0) ? \
! 109: (XDC_MAXIOPB - 1) : ((SC)->waithead - 1); \
! 110: (SC)->waitq[(SC)->waithead] = (N); \
! 111: (SC)->nwait++; \
! 112: }
! 113:
! 114: /*
! 115: * XDC_GET_WAITER: gets the first request waiting on the waitq
! 116: * and removes it (so it can be submitted)
! 117: */
! 118: #define XDC_GET_WAITER(XDCSC, RQ) { \
! 119: (RQ) = (XDCSC)->waitq[(XDCSC)->waithead]; \
! 120: (XDCSC)->waithead = ((XDCSC)->waithead + 1) % XDC_MAXIOPB; \
! 121: xdcsc->nwait--; \
! 122: }
! 123:
! 124: /*
! 125: * XDC_FREE: add iorq "N" to SC's free list
! 126: */
! 127: #define XDC_FREE(SC, N) { \
! 128: (SC)->freereq[(SC)->nfree++] = (N); \
! 129: (SC)->reqs[N].mode = 0; \
! 130: if ((SC)->nfree == 1) wakeup(&(SC)->nfree); \
! 131: }
! 132:
! 133:
! 134: /*
! 135: * XDC_RQALLOC: allocate an iorq off the free list (assume nfree > 0).
! 136: */
! 137: #define XDC_RQALLOC(XDCSC) (XDCSC)->freereq[--((XDCSC)->nfree)]
! 138:
! 139: /*
! 140: * XDC_GO: start iopb ADDR (DVMA addr in a u_long) on XDC
! 141: */
! 142: #define XDC_GO(XDC, ADDR) { \
! 143: (XDC)->xdc_iopbaddr0 = ((ADDR) & 0xff); \
! 144: (ADDR) = ((ADDR) >> 8); \
! 145: (XDC)->xdc_iopbaddr1 = ((ADDR) & 0xff); \
! 146: (ADDR) = ((ADDR) >> 8); \
! 147: (XDC)->xdc_iopbaddr2 = ((ADDR) & 0xff); \
! 148: (ADDR) = ((ADDR) >> 8); \
! 149: (XDC)->xdc_iopbaddr3 = (ADDR); \
! 150: (XDC)->xdc_iopbamod = XDC_ADDRMOD; \
! 151: (XDC)->xdc_csr = XDC_ADDIOPB; /* go! */ \
! 152: }
! 153:
! 154: /*
! 155: * XDC_WAIT: wait for XDC's csr "BITS" to come on in "TIME".
! 156: * LCV is a counter. If it goes to zero then we timed out.
! 157: */
! 158: #define XDC_WAIT(XDC, LCV, TIME, BITS) { \
! 159: (LCV) = (TIME); \
! 160: while ((LCV) > 0) { \
! 161: if ((XDC)->xdc_csr & (BITS)) break; \
! 162: (LCV) = (LCV) - 1; \
! 163: DELAY(1); \
! 164: } \
! 165: }
! 166:
! 167: /*
! 168: * XDC_DONE: don't need IORQ, get error code and free (done after xdc_cmd)
! 169: */
! 170: #define XDC_DONE(SC,RQ,ER) { \
! 171: if ((RQ) == XD_ERR_FAIL) { \
! 172: (ER) = (RQ); \
! 173: } else { \
! 174: if ((SC)->ndone-- == XDC_SUBWAITLIM) \
! 175: wakeup(&(SC)->ndone); \
! 176: (ER) = (SC)->reqs[RQ].errno; \
! 177: XDC_FREE((SC), (RQ)); \
! 178: } \
! 179: }
! 180:
! 181: /*
! 182: * XDC_ADVANCE: advance iorq's pointers by a number of sectors
! 183: */
! 184: #define XDC_ADVANCE(IORQ, N) { \
! 185: if (N) { \
! 186: (IORQ)->sectcnt -= (N); \
! 187: (IORQ)->blockno += (N); \
! 188: (IORQ)->dbuf += ((N)*XDFM_BPS); \
! 189: } \
! 190: }
! 191:
! 192: /*
! 193: * note - addresses you can sleep on:
! 194: * [1] & of xd_softc's "state" (waiting for a chance to attach a drive)
! 195: * [2] & of xdc_softc's "nfree" (waiting for a free iorq/iopb)
! 196: * [3] & of xdc_softc's "ndone" (waiting for number of done iorq/iopb's
! 197: * to drop below XDC_SUBWAITLIM)
! 198: * [4] & an iorq (waiting for an XD_SUB_WAIT iorq to finish)
! 199: */
! 200:
! 201:
! 202: /*
! 203: * function prototypes
! 204: * "xdc_*" functions are internal, all others are external interfaces
! 205: */
! 206:
! 207: extern int pil_to_vme[]; /* from obio.c */
! 208:
! 209: /* internals */
! 210: int xdc_cmd(struct xdc_softc *, int, int, int, int, int, char *, int);
! 211: char *xdc_e2str(int);
! 212: int xdc_error(struct xdc_softc *, struct xd_iorq *,
! 213: struct xd_iopb *, int, int);
! 214: int xdc_ioctlcmd(struct xd_softc *, dev_t dev, struct xd_iocmd *);
! 215: void xdc_perror(struct xd_iorq *, struct xd_iopb *, int);
! 216: int xdc_piodriver(struct xdc_softc *, int, int);
! 217: int xdc_remove_iorq(struct xdc_softc *);
! 218: int xdc_reset(struct xdc_softc *, int, int, int, struct xd_softc *);
! 219: inline void xdc_rqinit(struct xd_iorq *, struct xdc_softc *,
! 220: struct xd_softc *, int, u_long, int,
! 221: caddr_t, struct buf *);
! 222: void xdc_rqtopb(struct xd_iorq *, struct xd_iopb *, int, int);
! 223: void xdc_start(struct xdc_softc *, int);
! 224: int xdc_startbuf(struct xdc_softc *, struct xd_softc *, struct buf *);
! 225: int xdc_submit_iorq(struct xdc_softc *, int, int);
! 226: void xdc_tick(void *);
! 227: void xdc_xdreset(struct xdc_softc *, struct xd_softc *);
! 228:
! 229: /* machine interrupt hook */
! 230: int xdcintr(void *);
! 231:
! 232: /* autoconf */
! 233: int xdcmatch(struct device *, void *, void *);
! 234: void xdcattach(struct device *, struct device *, void *);
! 235: int xdmatch(struct device *, void *, void *);
! 236: void xdattach(struct device *, struct device *, void *);
! 237:
! 238: static void xddummystrat(struct buf *);
! 239: int xdgetdisklabel(struct xd_softc *, void *);
! 240:
! 241: /*
! 242: * cfdrivers: device driver interface to autoconfig
! 243: */
! 244:
! 245: struct cfattach xdc_ca = {
! 246: sizeof(struct xdc_softc), xdcmatch, xdcattach
! 247: };
! 248:
! 249:
! 250: struct cfdriver xdc_cd = {
! 251: NULL, "xdc", DV_DULL
! 252: };
! 253:
! 254: struct cfattach xd_ca = {
! 255: sizeof(struct xd_softc), xdmatch, xdattach
! 256: };
! 257:
! 258: struct cfdriver xd_cd = {
! 259: NULL, "xd", DV_DISK
! 260: };
! 261:
! 262: struct xdc_attach_args { /* this is the "aux" args to xdattach */
! 263: int driveno; /* unit number */
! 264: char *buf; /* scratch buffer for reading disk label */
! 265: char *dvmabuf; /* DVMA address of above */
! 266: int fullmode; /* submit mode */
! 267: int booting; /* are we booting or not? */
! 268: };
! 269:
! 270: /*
! 271: * dkdriver
! 272: */
! 273:
! 274: struct dkdriver xddkdriver = {xdstrategy};
! 275:
! 276: /*
! 277: * start: disk label fix code (XXX)
! 278: */
! 279:
! 280: static void *xd_labeldata;
! 281:
! 282: static void
! 283: xddummystrat(bp)
! 284: struct buf *bp;
! 285: {
! 286: if (bp->b_bcount != XDFM_BPS)
! 287: panic("xddummystrat");
! 288: bcopy(xd_labeldata, bp->b_data, XDFM_BPS);
! 289: bp->b_flags |= B_DONE;
! 290: bp->b_flags &= ~B_BUSY;
! 291: }
! 292:
! 293: int
! 294: xdgetdisklabel(xd, b)
! 295: struct xd_softc *xd;
! 296: void *b;
! 297: {
! 298: struct disklabel *lp = xd->sc_dk.dk_label;
! 299: struct sun_disklabel *sl = b;
! 300: char *err;
! 301:
! 302: bzero(lp, sizeof(struct disklabel));
! 303: /* Required parameters for readdisklabel() */
! 304: lp->d_secsize = XDFM_BPS;
! 305: if (sl->sl_magic == SUN_DKMAGIC) {
! 306: lp->d_secpercyl = sl->sl_nsectors * sl->sl_ntracks;
! 307: DL_SETDSIZE(lp, (daddr64_t)lp->d_secpercyl * sl->sl_ncylinders);
! 308: } else {
! 309: lp->d_secpercyl = 1;
! 310: }
! 311:
! 312: /* We already have the label data in `b'; setup for dummy strategy */
! 313: xd_labeldata = b;
! 314:
! 315: err = readdisklabel(MAKEDISKDEV(0, xd->sc_dev.dv_unit, RAW_PART),
! 316: xddummystrat, lp, 0);
! 317: if (err) {
! 318: /*printf("%s: %s\n", xd->sc_dev.dv_xname, err);*/
! 319: return (XD_ERR_FAIL);
! 320: }
! 321:
! 322: /* Ok, we have the label; fill in `pcyl' if there's SunOS magic */
! 323: sl = b;
! 324: if (sl->sl_magic == SUN_DKMAGIC)
! 325: xd->pcyl = sl->sl_pcylinders;
! 326: else {
! 327: printf("%s: WARNING: no `pcyl' in disk label.\n",
! 328: xd->sc_dev.dv_xname);
! 329: xd->pcyl = lp->d_ncylinders +
! 330: lp->d_acylinders;
! 331: printf("%s: WARNING: guessing pcyl=%d (ncyl+acyl)\n",
! 332: xd->sc_dev.dv_xname, xd->pcyl);
! 333: }
! 334:
! 335: xd->ncyl = lp->d_ncylinders;
! 336: xd->acyl = lp->d_acylinders;
! 337: xd->nhead = lp->d_ntracks;
! 338: xd->nsect = lp->d_nsectors;
! 339: xd->sectpercyl = lp->d_secpercyl;
! 340: return (XD_ERR_AOK);
! 341: }
! 342:
! 343: /*
! 344: * end: disk label fix code (XXX)
! 345: */
! 346:
! 347: /*
! 348: * a u t o c o n f i g f u n c t i o n s
! 349: */
! 350:
! 351: /*
! 352: * xdcmatch: determine if xdc is present or not. we do a
! 353: * soft reset to detect the xdc.
! 354: */
! 355:
! 356: int xdcmatch(parent, vcf, aux)
! 357: struct device *parent;
! 358: void *vcf, *aux;
! 359: {
! 360: struct cfdata *cf = vcf;
! 361: struct confargs *ca = aux;
! 362: struct romaux *ra = &ca->ca_ra;
! 363: struct xdc *xdc;
! 364: int del = 0;
! 365:
! 366: if (strcmp(cf->cf_driver->cd_name, ra->ra_name))
! 367: return (0);
! 368:
! 369: switch (ca->ca_bustype) {
! 370: case BUS_OBIO:
! 371: case BUS_SBUS:
! 372: case BUS_VME16:
! 373: default:
! 374: return (0);
! 375: case BUS_VME32:
! 376: xdc = (struct xdc *) ra->ra_vaddr;
! 377: if (probeget((caddr_t) &xdc->xdc_csr, 1) == -1)
! 378: return (0);
! 379: xdc->xdc_csr = XDC_RESET;
! 380: XDC_WAIT(xdc, del, XDC_RESETUSEC, XDC_RESET);
! 381: if (del <= 0)
! 382: return (0);
! 383: return (1);
! 384: }
! 385: }
! 386:
! 387: /*
! 388: * xdcattach: attach controller
! 389: */
! 390: void
! 391: xdcattach(parent, self, aux)
! 392: struct device *parent, *self;
! 393: void *aux;
! 394:
! 395: {
! 396: struct xdc_softc *xdc = (void *) self;
! 397: struct confargs *ca = aux;
! 398: struct xdc_attach_args xa;
! 399: int lcv, rqno, err, pri;
! 400: struct xd_iopb_ctrl *ctl;
! 401:
! 402: /* get addressing and intr level stuff from autoconfig and load it
! 403: * into our xdc_softc. */
! 404:
! 405: ca->ca_ra.ra_vaddr = mapiodev(ca->ca_ra.ra_reg, 0, sizeof(struct xdc));
! 406:
! 407: xdc->xdc = (struct xdc *) ca->ca_ra.ra_vaddr;
! 408: pri = ca->ca_ra.ra_intr[0].int_pri;
! 409: xdc->ipl = pil_to_vme[pri];
! 410: xdc->vector = ca->ca_ra.ra_intr[0].int_vec;
! 411: printf(" pri %d", pri);
! 412:
! 413: for (lcv = 0; lcv < XDC_MAXDEV; lcv++)
! 414: xdc->sc_drives[lcv] = (struct xd_softc *) 0;
! 415:
! 416: /* allocate and zero buffers
! 417: *
! 418: * note: we simplify the code by allocating the max number of iopbs and
! 419: * iorq's up front. thus, we avoid linked lists and the costs
! 420: * associated with them in exchange for wasting a little memory. */
! 421:
! 422: xdc->dvmaiopb = (struct xd_iopb *)
! 423: dvma_malloc(XDC_MAXIOPB * sizeof(struct xd_iopb), &xdc->iopbase,
! 424: M_NOWAIT);
! 425: xdc->iopbase = xdc->dvmaiopb; /* XXX TMP HACK */
! 426: bzero(xdc->iopbase, XDC_MAXIOPB * sizeof(struct xd_iopb));
! 427: /* Setup device view of DVMA address */
! 428: xdc->dvmaiopb = (struct xd_iopb *) ((u_long) xdc->iopbase - DVMA_BASE);
! 429:
! 430: xdc->reqs = (struct xd_iorq *)
! 431: malloc(XDC_MAXIOPB * sizeof(struct xd_iorq), M_DEVBUF, M_NOWAIT);
! 432: if (xdc->reqs == NULL)
! 433: panic("xdc malloc");
! 434: bzero(xdc->reqs, XDC_MAXIOPB * sizeof(struct xd_iorq));
! 435:
! 436: /* init free list, iorq to iopb pointers, and non-zero fields in the
! 437: * iopb which never change. */
! 438:
! 439: for (lcv = 0; lcv < XDC_MAXIOPB; lcv++) {
! 440: xdc->reqs[lcv].iopb = &xdc->iopbase[lcv];
! 441: xdc->freereq[lcv] = lcv;
! 442: xdc->iopbase[lcv].fixd = 1; /* always the same */
! 443: xdc->iopbase[lcv].naddrmod = XDC_ADDRMOD; /* always the same */
! 444: xdc->iopbase[lcv].intr_vec = xdc->vector; /* always the same */
! 445: }
! 446: xdc->nfree = XDC_MAXIOPB;
! 447: xdc->nrun = 0;
! 448: xdc->waithead = xdc->waitend = xdc->nwait = 0;
! 449: xdc->ndone = 0;
! 450:
! 451: /* init queue of waiting bufs */
! 452:
! 453: xdc->sc_wq.b_active = 0;
! 454: xdc->sc_wq.b_actf = 0;
! 455: xdc->sc_wq.b_actb = &xdc->sc_wq.b_actf;
! 456:
! 457: /*
! 458: * section 7 of the manual tells us how to init the controller:
! 459: * - read controller parameters (6/0)
! 460: * - write controller parameters (5/0)
! 461: */
! 462:
! 463: /* read controller parameters and insure we have a 753/7053 */
! 464:
! 465: rqno = xdc_cmd(xdc, XDCMD_RDP, XDFUN_CTL, 0, 0, 0, 0, XD_SUB_POLL);
! 466: if (rqno == XD_ERR_FAIL) {
! 467: printf(": couldn't read controller params\n");
! 468: return; /* shouldn't ever happen */
! 469: }
! 470: ctl = (struct xd_iopb_ctrl *) & xdc->iopbase[rqno];
! 471: if (ctl->ctype != XDCT_753) {
! 472: if (xdc->reqs[rqno].errno)
! 473: printf(": %s: ", xdc_e2str(xdc->reqs[rqno].errno));
! 474: printf(": doesn't identify as a 753/7053\n");
! 475: XDC_DONE(xdc, rqno, err);
! 476: return;
! 477: }
! 478: printf(": Xylogics 753/7053, PROM=0x%x.%02x.%02x\n",
! 479: ctl->eprom_partno, ctl->eprom_lvl, ctl->eprom_rev);
! 480: XDC_DONE(xdc, rqno, err);
! 481:
! 482: /* now write controller parameters (xdc_cmd sets all params for us) */
! 483:
! 484: rqno = xdc_cmd(xdc, XDCMD_WRP, XDFUN_CTL, 0, 0, 0, 0, XD_SUB_POLL);
! 485: XDC_DONE(xdc, rqno, err);
! 486: if (err) {
! 487: printf("%s: controller config error: %s\n",
! 488: xdc->sc_dev.dv_xname, xdc_e2str(err));
! 489: return;
! 490: }
! 491: /* link in interrupt with higher level software */
! 492:
! 493: xdc->sc_ih.ih_fun = xdcintr;
! 494: xdc->sc_ih.ih_arg = xdc;
! 495: vmeintr_establish(ca->ca_ra.ra_intr[0].int_vec,
! 496: ca->ca_ra.ra_intr[0].int_pri, &xdc->sc_ih, IPL_BIO,
! 497: self->dv_xname);
! 498:
! 499: /* now we must look for disks using autoconfig */
! 500: xa.dvmabuf = (char *)dvma_malloc(XDFM_BPS, &xa.buf, M_NOWAIT);
! 501: xa.fullmode = XD_SUB_POLL;
! 502: xa.booting = 1;
! 503:
! 504: if (ca->ca_ra.ra_bp && ca->ca_ra.ra_bp->val[0] == -1 &&
! 505: ca->ca_ra.ra_bp->val[1] == xdc->sc_dev.dv_unit) {
! 506: bootpath_store(1, ca->ca_ra.ra_bp + 1); /* advance bootpath */
! 507: }
! 508:
! 509: for (xa.driveno = 0; xa.driveno < XDC_MAXDEV; xa.driveno++)
! 510: (void) config_found(self, (void *) &xa, NULL);
! 511:
! 512: dvma_free(xa.dvmabuf, XDFM_BPS, &xa.buf);
! 513: bootpath_store(1, NULL);
! 514:
! 515: /* start the watchdog clock */
! 516: timeout_set(&xdc->xdc_tick_tmo, xdc_tick, xdc);
! 517: timeout_add(&xdc->xdc_tick_tmo, XDC_TICKCNT);
! 518:
! 519: }
! 520:
! 521: /*
! 522: * xdmatch: probe for disk.
! 523: *
! 524: * note: we almost always say disk is present. this allows us to
! 525: * spin up and configure a disk after the system is booted (we can
! 526: * call xdattach!).
! 527: */
! 528: int
! 529: xdmatch(parent, vcf, aux)
! 530: struct device *parent;
! 531: void *vcf, *aux;
! 532: {
! 533: struct cfdata *cf = vcf;
! 534: struct xdc_attach_args *xa = aux;
! 535:
! 536: /* looking for autoconf wildcard or exact match */
! 537:
! 538: if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != xa->driveno)
! 539: return 0;
! 540:
! 541: return 1;
! 542:
! 543: }
! 544:
! 545: /*
! 546: * xdattach: attach a disk. this can be called from autoconf and also
! 547: * from xdopen/xdstrategy.
! 548: */
! 549: void
! 550: xdattach(parent, self, aux)
! 551: struct device *parent, *self;
! 552: void *aux;
! 553:
! 554: {
! 555: struct xd_softc *xd = (void *) self;
! 556: struct xdc_softc *xdc = (void *) parent;
! 557: struct xdc_attach_args *xa = aux;
! 558: int rqno, err, spt = 0, mb, blk, lcv, fmode, s = 0, newstate;
! 559: struct xd_iopb_drive *driopb;
! 560: struct dkbad *dkb;
! 561: struct bootpath *bp;
! 562:
! 563: /*
! 564: * Always re-initialize the disk structure. We want statistics
! 565: * to start with a clean slate.
! 566: */
! 567: bzero(&xd->sc_dk, sizeof(xd->sc_dk));
! 568: xd->sc_dk.dk_driver = &xddkdriver;
! 569: xd->sc_dk.dk_name = xd->sc_dev.dv_xname;
! 570:
! 571: /* if booting, init the xd_softc */
! 572:
! 573: if (xa->booting) {
! 574: xd->state = XD_DRIVE_UNKNOWN; /* to start */
! 575: xd->flags = 0;
! 576: xd->parent = xdc;
! 577: }
! 578: xd->xd_drive = xa->driveno;
! 579: fmode = xa->fullmode;
! 580: xdc->sc_drives[xa->driveno] = xd;
! 581:
! 582: /* if not booting, make sure we are the only process in the attach for
! 583: * this drive. if locked out, sleep on it. */
! 584:
! 585: if (!xa->booting) {
! 586: s = splbio();
! 587: while (xd->state == XD_DRIVE_ATTACHING) {
! 588: if (tsleep(&xd->state, PRIBIO, "xdattach", 0)) {
! 589: splx(s);
! 590: return;
! 591: }
! 592: }
! 593: printf("%s at %s",
! 594: xd->sc_dev.dv_xname, xd->parent->sc_dev.dv_xname);
! 595: }
! 596: /* we now have control */
! 597:
! 598: xd->state = XD_DRIVE_ATTACHING;
! 599: newstate = XD_DRIVE_UNKNOWN;
! 600:
! 601: /* first try and reset the drive */
! 602:
! 603: rqno = xdc_cmd(xdc, XDCMD_RST, 0, xd->xd_drive, 0, 0, 0, fmode);
! 604: XDC_DONE(xdc, rqno, err);
! 605: if (err == XD_ERR_NRDY) {
! 606: printf(" drive %d: off-line\n", xa->driveno);
! 607: goto done;
! 608: }
! 609: if (err) {
! 610: printf(": ERROR 0x%02x (%s)\n", err, xdc_e2str(err));
! 611: goto done;
! 612: }
! 613: printf(" drive %d: ready\n", xa->driveno);
! 614:
! 615: /* now set format parameters */
! 616:
! 617: rqno = xdc_cmd(xdc, XDCMD_WRP, XDFUN_FMT, xd->xd_drive, 0, 0, 0, fmode);
! 618: XDC_DONE(xdc, rqno, err);
! 619: if (err) {
! 620: printf("%s: write format parameters failed: %s\n",
! 621: xd->sc_dev.dv_xname, xdc_e2str(err));
! 622: goto done;
! 623: }
! 624:
! 625: /* get drive parameters */
! 626: rqno = xdc_cmd(xdc, XDCMD_RDP, XDFUN_DRV, xd->xd_drive, 0, 0, 0, fmode);
! 627: if (rqno != XD_ERR_FAIL) {
! 628: driopb = (struct xd_iopb_drive *) & xdc->iopbase[rqno];
! 629: spt = driopb->sectpertrk;
! 630: }
! 631: XDC_DONE(xdc, rqno, err);
! 632: if (err) {
! 633: printf("%s: read drive parameters failed: %s\n",
! 634: xd->sc_dev.dv_xname, xdc_e2str(err));
! 635: goto done;
! 636: }
! 637:
! 638: /*
! 639: * now set drive parameters (to semi-bogus values) so we can read the
! 640: * disk label.
! 641: */
! 642: xd->pcyl = xd->ncyl = 1;
! 643: xd->acyl = 0;
! 644: xd->nhead = 1;
! 645: xd->nsect = 1;
! 646: xd->sectpercyl = 1;
! 647: for (lcv = 0; lcv < NBT_BAD; lcv++) /* init empty bad144 table */
! 648: xd->dkb.bt_bad[lcv].bt_cyl = xd->dkb.bt_bad[lcv].bt_trksec = 0xffff;
! 649: rqno = xdc_cmd(xdc, XDCMD_WRP, XDFUN_DRV, xd->xd_drive, 0, 0, 0, fmode);
! 650: XDC_DONE(xdc, rqno, err);
! 651: if (err) {
! 652: printf("%s: write drive parameters failed: %s\n",
! 653: xd->sc_dev.dv_xname, xdc_e2str(err));
! 654: goto done;
! 655: }
! 656:
! 657: /* read disk label */
! 658: rqno = xdc_cmd(xdc, XDCMD_RD, 0, xd->xd_drive, 0, 1, xa->dvmabuf, fmode);
! 659: XDC_DONE(xdc, rqno, err);
! 660: if (err) {
! 661: printf("%s: reading disk label failed: %s\n",
! 662: xd->sc_dev.dv_xname, xdc_e2str(err));
! 663: goto done;
! 664: }
! 665: newstate = XD_DRIVE_NOLABEL;
! 666:
! 667: xd->hw_spt = spt;
! 668: /* Attach the disk: must be before getdisklabel to malloc label */
! 669: disk_attach(&xd->sc_dk);
! 670:
! 671: if (xdgetdisklabel(xd, xa->buf) != XD_ERR_AOK)
! 672: goto done;
! 673:
! 674: /* inform the user of what is up */
! 675: printf("%s: <%s>, pcyl %d, hw_spt %d\n", xd->sc_dev.dv_xname,
! 676: xa->buf, xd->pcyl, spt);
! 677: mb = xd->ncyl * (xd->nhead * xd->nsect) / (1048576 / XDFM_BPS);
! 678: printf("%s: %dMB, %d cyl, %d head, %d sec, %d bytes/sec\n",
! 679: xd->sc_dev.dv_xname, mb, xd->ncyl, xd->nhead, xd->nsect,
! 680: XDFM_BPS);
! 681:
! 682: /* now set the real drive parameters! */
! 683:
! 684: rqno = xdc_cmd(xdc, XDCMD_WRP, XDFUN_DRV, xd->xd_drive, 0, 0, 0, fmode);
! 685: XDC_DONE(xdc, rqno, err);
! 686: if (err) {
! 687: printf("%s: write real drive parameters failed: %s\n",
! 688: xd->sc_dev.dv_xname, xdc_e2str(err));
! 689: goto done;
! 690: }
! 691: newstate = XD_DRIVE_ONLINE;
! 692:
! 693: /*
! 694: * read bad144 table. this table resides on the first sector of the
! 695: * last track of the disk (i.e. second cyl of "acyl" area).
! 696: */
! 697:
! 698: blk = (xd->ncyl + xd->acyl - 1) * (xd->nhead * xd->nsect) + /* last cyl */
! 699: (xd->nhead - 1) * xd->nsect; /* last head */
! 700: rqno = xdc_cmd(xdc, XDCMD_RD, 0, xd->xd_drive, blk, 1, xa->dvmabuf, fmode);
! 701: XDC_DONE(xdc, rqno, err);
! 702: if (err) {
! 703: printf("%s: reading bad144 failed: %s\n",
! 704: xd->sc_dev.dv_xname, xdc_e2str(err));
! 705: goto done;
! 706: }
! 707:
! 708: /* check dkbad for sanity */
! 709: dkb = (struct dkbad *) xa->buf;
! 710: for (lcv = 0; lcv < NBT_BAD; lcv++) {
! 711: if ((dkb->bt_bad[lcv].bt_cyl == 0xffff ||
! 712: dkb->bt_bad[lcv].bt_cyl == 0) &&
! 713: dkb->bt_bad[lcv].bt_trksec == 0xffff)
! 714: continue; /* blank */
! 715: if (dkb->bt_bad[lcv].bt_cyl >= xd->ncyl)
! 716: break;
! 717: if ((dkb->bt_bad[lcv].bt_trksec >> 8) >= xd->nhead)
! 718: break;
! 719: if ((dkb->bt_bad[lcv].bt_trksec & 0xff) >= xd->nsect)
! 720: break;
! 721: }
! 722: if (lcv != NBT_BAD) {
! 723: printf("%s: warning: invalid bad144 sector!\n",
! 724: xd->sc_dev.dv_xname);
! 725: } else {
! 726: bcopy(xa->buf, &xd->dkb, XDFM_BPS);
! 727: }
! 728:
! 729: if (xa->booting) {
! 730: /* restore bootpath! (do this via attach_args again?)*/
! 731: bp = bootpath_store(0, NULL);
! 732: if (bp && strcmp("xd", bp->name) == 0 &&
! 733: xd->xd_drive == bp->val[0])
! 734: bp->dev = &xd->sc_dev;
! 735: }
! 736:
! 737: done:
! 738: xd->state = newstate;
! 739: if (!xa->booting) {
! 740: wakeup(&xd->state);
! 741: splx(s);
! 742: }
! 743: }
! 744:
! 745: /*
! 746: * end of autoconfig functions
! 747: */
! 748:
! 749: /*
! 750: * { b , c } d e v s w f u n c t i o n s
! 751: */
! 752:
! 753: /*
! 754: * xdclose: close device
! 755: */
! 756: int
! 757: xdclose(dev, flag, fmt, p)
! 758: dev_t dev;
! 759: int flag, fmt;
! 760: struct proc *p;
! 761: {
! 762: struct xd_softc *xd = xd_cd.cd_devs[DISKUNIT(dev)];
! 763: int part = DISKPART(dev);
! 764:
! 765: /* clear mask bits */
! 766:
! 767: switch (fmt) {
! 768: case S_IFCHR:
! 769: xd->sc_dk.dk_copenmask &= ~(1 << part);
! 770: break;
! 771: case S_IFBLK:
! 772: xd->sc_dk.dk_bopenmask &= ~(1 << part);
! 773: break;
! 774: }
! 775: xd->sc_dk.dk_openmask = xd->sc_dk.dk_copenmask | xd->sc_dk.dk_bopenmask;
! 776:
! 777: return 0;
! 778: }
! 779:
! 780: /*
! 781: * xddump: crash dump system
! 782: */
! 783: int
! 784: xddump(dev, blkno, va, size)
! 785: dev_t dev;
! 786: daddr64_t blkno;
! 787: caddr_t va;
! 788: size_t size;
! 789: {
! 790: int unit, part;
! 791: struct xd_softc *xd;
! 792:
! 793: unit = DISKUNIT(dev);
! 794: if (unit >= xd_cd.cd_ndevs)
! 795: return ENXIO;
! 796: part = DISKPART(dev);
! 797:
! 798: xd = xd_cd.cd_devs[unit];
! 799:
! 800: printf("%s%c: crash dump not supported (yet)\n", xd->sc_dev.dv_xname,
! 801: 'a' + part);
! 802:
! 803: return ENXIO;
! 804:
! 805: /* outline: globals: "dumplo" == sector number of partition to start
! 806: * dump at (convert to physical sector with partition table)
! 807: * "dumpsize" == size of dump in clicks "physmem" == size of physical
! 808: * memory (clicks, ctob() to get bytes) (normal case: dumpsize ==
! 809: * physmem)
! 810: *
! 811: * dump a copy of physical memory to the dump device starting at sector
! 812: * "dumplo" in the swap partition (make sure > 0). map in pages as
! 813: * we go. use polled I/O.
! 814: *
! 815: * XXX how to handle NON_CONTIG? */
! 816:
! 817: }
! 818:
! 819: /*
! 820: * xdioctl: ioctls on XD drives. based on ioctl's of other netbsd disks.
! 821: */
! 822: int
! 823: xdioctl(dev, command, addr, flag, p)
! 824: dev_t dev;
! 825: u_long command;
! 826: caddr_t addr;
! 827: int flag;
! 828: struct proc *p;
! 829:
! 830: {
! 831: struct xd_softc *xd;
! 832: struct xd_iocmd *xio;
! 833: int error, s, unit;
! 834:
! 835: unit = DISKUNIT(dev);
! 836:
! 837: if (unit >= xd_cd.cd_ndevs || (xd = xd_cd.cd_devs[unit]) == NULL)
! 838: return (ENXIO);
! 839:
! 840: /* switch on ioctl type */
! 841:
! 842: switch (command) {
! 843: case DIOCSBAD: /* set bad144 info */
! 844: if ((flag & FWRITE) == 0)
! 845: return EBADF;
! 846: s = splbio();
! 847: bcopy(addr, &xd->dkb, sizeof(xd->dkb));
! 848: splx(s);
! 849: return 0;
! 850:
! 851: case DIOCGDINFO: /* get disk label */
! 852: bcopy(xd->sc_dk.dk_label, addr, sizeof(struct disklabel));
! 853: return 0;
! 854:
! 855: case DIOCGPART: /* get partition info */
! 856: ((struct partinfo *) addr)->disklab = xd->sc_dk.dk_label;
! 857: ((struct partinfo *) addr)->part =
! 858: &xd->sc_dk.dk_label->d_partitions[DISKPART(dev)];
! 859: return 0;
! 860:
! 861: case DIOCSDINFO: /* set disk label */
! 862: if ((flag & FWRITE) == 0)
! 863: return EBADF;
! 864: error = setdisklabel(xd->sc_dk.dk_label,
! 865: (struct disklabel *) addr, /* xd->sc_dk.dk_openmask : */ 0);
! 866: if (error == 0) {
! 867: if (xd->state == XD_DRIVE_NOLABEL)
! 868: xd->state = XD_DRIVE_ONLINE;
! 869: }
! 870: return error;
! 871:
! 872: case DIOCWLABEL: /* change write status of disk label */
! 873: if ((flag & FWRITE) == 0)
! 874: return EBADF;
! 875: if (*(int *) addr)
! 876: xd->flags |= XD_WLABEL;
! 877: else
! 878: xd->flags &= ~XD_WLABEL;
! 879: return 0;
! 880:
! 881: case DIOCWDINFO: /* write disk label */
! 882: if ((flag & FWRITE) == 0)
! 883: return EBADF;
! 884: error = setdisklabel(xd->sc_dk.dk_label,
! 885: (struct disklabel *) addr, /* xd->sc_dk.dk_openmask : */ 0);
! 886: if (error == 0) {
! 887: if (xd->state == XD_DRIVE_NOLABEL)
! 888: xd->state = XD_DRIVE_ONLINE;
! 889:
! 890: /* Simulate opening partition 0 so write succeeds. */
! 891: xd->sc_dk.dk_openmask |= (1 << 0);
! 892: error = writedisklabel(DISKLABELDEV(dev), xdstrategy,
! 893: xd->sc_dk.dk_label);
! 894: xd->sc_dk.dk_openmask =
! 895: xd->sc_dk.dk_copenmask | xd->sc_dk.dk_bopenmask;
! 896: }
! 897: return error;
! 898:
! 899: case DIOSXDCMD:
! 900: xio = (struct xd_iocmd *) addr;
! 901: if ((error = suser(p, 0)) != 0)
! 902: return (error);
! 903: return (xdc_ioctlcmd(xd, dev, xio));
! 904:
! 905: default:
! 906: return ENOTTY;
! 907: }
! 908: }
! 909: /*
! 910: * xdopen: open drive
! 911: */
! 912:
! 913: int
! 914: xdopen(dev, flag, fmt, p)
! 915: dev_t dev;
! 916: int flag, fmt;
! 917: struct proc *p;
! 918: {
! 919: int unit, part;
! 920: struct xd_softc *xd;
! 921: struct xdc_attach_args xa;
! 922:
! 923: /* first, could it be a valid target? */
! 924:
! 925: unit = DISKUNIT(dev);
! 926: if (unit >= xd_cd.cd_ndevs || (xd = xd_cd.cd_devs[unit]) == NULL)
! 927: return (ENXIO);
! 928: part = DISKPART(dev);
! 929:
! 930: /* do we need to attach the drive? */
! 931:
! 932: if (xd->state == XD_DRIVE_UNKNOWN) {
! 933: xa.driveno = xd->xd_drive;
! 934: xa.dvmabuf = (char *)dvma_malloc(XDFM_BPS, &xa.buf, M_NOWAIT);
! 935: xa.fullmode = XD_SUB_WAIT;
! 936: xa.booting = 0;
! 937: xdattach((struct device *) xd->parent, (struct device *) xd, &xa);
! 938: dvma_free(xa.dvmabuf, XDFM_BPS, &xa.buf);
! 939: if (xd->state == XD_DRIVE_UNKNOWN) {
! 940: return (EIO);
! 941: }
! 942: }
! 943: /* check for partition */
! 944:
! 945: if (part != RAW_PART &&
! 946: (part >= xd->sc_dk.dk_label->d_npartitions ||
! 947: xd->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) {
! 948: return (ENXIO);
! 949: }
! 950: /* set open masks */
! 951:
! 952: switch (fmt) {
! 953: case S_IFCHR:
! 954: xd->sc_dk.dk_copenmask |= (1 << part);
! 955: break;
! 956: case S_IFBLK:
! 957: xd->sc_dk.dk_bopenmask |= (1 << part);
! 958: break;
! 959: }
! 960: xd->sc_dk.dk_openmask = xd->sc_dk.dk_copenmask | xd->sc_dk.dk_bopenmask;
! 961:
! 962: return 0;
! 963: }
! 964:
! 965: int
! 966: xdread(dev, uio, flags)
! 967: dev_t dev;
! 968: struct uio *uio;
! 969: int flags;
! 970: {
! 971:
! 972: return (physio(xdstrategy, NULL, dev, B_READ, minphys, uio));
! 973: }
! 974:
! 975: int
! 976: xdwrite(dev, uio, flags)
! 977: dev_t dev;
! 978: struct uio *uio;
! 979: int flags;
! 980: {
! 981:
! 982: return (physio(xdstrategy, NULL, dev, B_WRITE, minphys, uio));
! 983: }
! 984:
! 985:
! 986: /*
! 987: * xdsize: return size of a partition for a dump
! 988: */
! 989:
! 990: daddr64_t
! 991: xdsize(dev)
! 992: dev_t dev;
! 993:
! 994: {
! 995: struct xd_softc *xdsc;
! 996: int unit, part, size, omask;
! 997:
! 998: /* valid unit? */
! 999: unit = DISKUNIT(dev);
! 1000: if (unit >= xd_cd.cd_ndevs || (xdsc = xd_cd.cd_devs[unit]) == NULL)
! 1001: return (-1);
! 1002:
! 1003: part = DISKPART(dev);
! 1004: omask = xdsc->sc_dk.dk_openmask & (1 << part);
! 1005:
! 1006: if (omask == 0 && xdopen(dev, 0, S_IFBLK, NULL) != 0)
! 1007: return (-1);
! 1008:
! 1009: /* do it */
! 1010: if (xdsc->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP)
! 1011: size = -1; /* only give valid size for swap partitions */
! 1012: else
! 1013: size = DL_GETPSIZE(&xdsc->sc_dk.dk_label->d_partitions[part]) *
! 1014: (xdsc->sc_dk.dk_label->d_secsize / DEV_BSIZE);
! 1015: if (omask == 0 && xdclose(dev, 0, S_IFBLK, NULL) != 0)
! 1016: return (-1);
! 1017: return (size);
! 1018: }
! 1019: /*
! 1020: * xdstrategy: buffering system interface to xd.
! 1021: */
! 1022:
! 1023: void
! 1024: xdstrategy(bp)
! 1025: struct buf *bp;
! 1026:
! 1027: {
! 1028: struct xd_softc *xd;
! 1029: struct xdc_softc *parent;
! 1030: struct buf *wq;
! 1031: int s, unit;
! 1032: struct xdc_attach_args xa;
! 1033:
! 1034: unit = DISKUNIT(bp->b_dev);
! 1035:
! 1036: /* check for live device */
! 1037:
! 1038: if (unit >= xd_cd.cd_ndevs || (xd = xd_cd.cd_devs[unit]) == 0 ||
! 1039: bp->b_blkno < 0 ||
! 1040: (bp->b_bcount % xd->sc_dk.dk_label->d_secsize) != 0) {
! 1041: bp->b_error = EINVAL;
! 1042: goto bad;
! 1043: }
! 1044: /* do we need to attach the drive? */
! 1045:
! 1046: if (xd->state == XD_DRIVE_UNKNOWN) {
! 1047: xa.driveno = xd->xd_drive;
! 1048: xa.dvmabuf = (char *)dvma_malloc(XDFM_BPS, &xa.buf, M_NOWAIT);
! 1049: xa.fullmode = XD_SUB_WAIT;
! 1050: xa.booting = 0;
! 1051: xdattach((struct device *)xd->parent, (struct device *)xd, &xa);
! 1052: dvma_free(xa.dvmabuf, XDFM_BPS, &xa.buf);
! 1053: if (xd->state == XD_DRIVE_UNKNOWN) {
! 1054: bp->b_error = EIO;
! 1055: goto bad;
! 1056: }
! 1057: }
! 1058: if (xd->state != XD_DRIVE_ONLINE && DISKPART(bp->b_dev) != RAW_PART) {
! 1059: /* no I/O to unlabeled disks, unless raw partition */
! 1060: bp->b_error = EIO;
! 1061: goto bad;
! 1062: }
! 1063: /* short circuit zero length request */
! 1064:
! 1065: if (bp->b_bcount == 0)
! 1066: goto done;
! 1067:
! 1068: /* check bounds with label (disksubr.c). Determine the size of the
! 1069: * transfer, and make sure it is within the boundaries of the
! 1070: * partition. Adjust transfer if needed, and signal errors or early
! 1071: * completion. */
! 1072:
! 1073: if (bounds_check_with_label(bp, xd->sc_dk.dk_label,
! 1074: (xd->flags & XD_WLABEL) != 0) <= 0)
! 1075: goto done;
! 1076:
! 1077: /*
! 1078: * now we know we have a valid buf structure that we need to do I/O
! 1079: * on.
! 1080: *
! 1081: * note that we don't disksort because the controller has a sorting
! 1082: * algorithm built into the hardware.
! 1083: */
! 1084:
! 1085: s = splbio(); /* protect the queues */
! 1086:
! 1087: /* first, give jobs in front of us a chance */
! 1088: parent = xd->parent;
! 1089: while (parent->nfree > 0 && parent->sc_wq.b_actf)
! 1090: if (xdc_startbuf(parent, NULL, NULL) != XD_ERR_AOK)
! 1091: break;
! 1092:
! 1093: /* if there are no free iorq's, then we just queue and return. the
! 1094: * buffs will get picked up later by xdcintr().
! 1095: */
! 1096:
! 1097: if (parent->nfree == 0) {
! 1098: wq = &xd->parent->sc_wq;
! 1099: bp->b_actf = 0;
! 1100: bp->b_actb = wq->b_actb;
! 1101: *wq->b_actb = bp;
! 1102: wq->b_actb = &bp->b_actf;
! 1103: splx(s);
! 1104: return;
! 1105: }
! 1106:
! 1107: /* now we have free iopb's and we are at splbio... start 'em up */
! 1108: if (xdc_startbuf(parent, xd, bp) != XD_ERR_AOK) {
! 1109: splx(s);
! 1110: return;
! 1111: }
! 1112:
! 1113: /* done! */
! 1114:
! 1115: splx(s);
! 1116: return;
! 1117:
! 1118: bad: /* tells upper layers we have an error */
! 1119: bp->b_flags |= B_ERROR;
! 1120: done: /* tells upper layers we are done with this
! 1121: * buf */
! 1122: bp->b_resid = bp->b_bcount;
! 1123: s = splbio();
! 1124: biodone(bp);
! 1125: splx(s);
! 1126: }
! 1127: /*
! 1128: * end of {b,c}devsw functions
! 1129: */
! 1130:
! 1131: /*
! 1132: * i n t e r r u p t f u n c t i o n
! 1133: *
! 1134: * xdcintr: hardware interrupt.
! 1135: */
! 1136: int
! 1137: xdcintr(v)
! 1138: void *v;
! 1139:
! 1140: {
! 1141: struct xdc_softc *xdcsc = v;
! 1142:
! 1143: /* remove as many done IOPBs as possible */
! 1144:
! 1145: xdc_remove_iorq(xdcsc);
! 1146:
! 1147: /* start any iorq's already waiting */
! 1148:
! 1149: xdc_start(xdcsc, XDC_MAXIOPB);
! 1150:
! 1151: /* fill up any remaining iorq's with queue'd buffers */
! 1152:
! 1153: while (xdcsc->nfree > 0 && xdcsc->sc_wq.b_actf)
! 1154: if (xdc_startbuf(xdcsc, NULL, NULL) != XD_ERR_AOK)
! 1155: break;
! 1156:
! 1157: return (1);
! 1158: }
! 1159: /*
! 1160: * end of interrupt function
! 1161: */
! 1162:
! 1163: /*
! 1164: * i n t e r n a l f u n c t i o n s
! 1165: */
! 1166:
! 1167: /*
! 1168: * xdc_rqinit: fill out the fields of an I/O request
! 1169: */
! 1170:
! 1171: inline void
! 1172: xdc_rqinit(rq, xdc, xd, md, blk, cnt, db, bp)
! 1173: struct xd_iorq *rq;
! 1174: struct xdc_softc *xdc;
! 1175: struct xd_softc *xd;
! 1176: int md;
! 1177: u_long blk;
! 1178: int cnt;
! 1179: caddr_t db;
! 1180: struct buf *bp;
! 1181: {
! 1182: rq->xdc = xdc;
! 1183: rq->xd = xd;
! 1184: rq->ttl = XDC_MAXTTL + 10;
! 1185: rq->mode = md;
! 1186: rq->tries = rq->errno = rq->lasterror = 0;
! 1187: rq->blockno = blk;
! 1188: rq->sectcnt = cnt;
! 1189: rq->dbuf = rq->dbufbase = db;
! 1190: rq->buf = bp;
! 1191: }
! 1192: /*
! 1193: * xdc_rqtopb: load up an IOPB based on an iorq
! 1194: */
! 1195:
! 1196: void
! 1197: xdc_rqtopb(iorq, iopb, cmd, subfun)
! 1198: struct xd_iorq *iorq;
! 1199: struct xd_iopb *iopb;
! 1200: int cmd, subfun;
! 1201:
! 1202: {
! 1203: u_long block, dp;
! 1204:
! 1205: /* standard stuff */
! 1206:
! 1207: iopb->errs = iopb->done = 0;
! 1208: iopb->comm = cmd;
! 1209: iopb->errno = iopb->status = 0;
! 1210: iopb->subfun = subfun;
! 1211: if (iorq->xd)
! 1212: iopb->unit = iorq->xd->xd_drive;
! 1213: else
! 1214: iopb->unit = 0;
! 1215:
! 1216: /* check for alternate IOPB format */
! 1217:
! 1218: if (cmd == XDCMD_WRP) {
! 1219: switch (subfun) {
! 1220: case XDFUN_CTL:{
! 1221: struct xd_iopb_ctrl *ctrl =
! 1222: (struct xd_iopb_ctrl *) iopb;
! 1223: iopb->lll = 0;
! 1224: iopb->intl = (XD_STATE(iorq->mode) == XD_SUB_POLL)
! 1225: ? 0
! 1226: : iorq->xdc->ipl;
! 1227: ctrl->param_a = XDPA_TMOD | XDPA_DACF;
! 1228: ctrl->param_b = XDPB_ROR | XDPB_TDT_3_2USEC;
! 1229: ctrl->param_c = XDPC_OVS | XDPC_COP | XDPC_ASR |
! 1230: XDPC_RBC | XDPC_ECC2;
! 1231: ctrl->throttle = XDC_THROTTLE;
! 1232: #ifdef __sparc__
! 1233: if (CPU_ISSUN4 && cpuinfo.cpu_type == CPUTYP_4_300)
! 1234: ctrl->delay = XDC_DELAY_4_300;
! 1235: else
! 1236: ctrl->delay = XDC_DELAY_SPARC;
! 1237: #endif
! 1238: #ifdef sun3
! 1239: ctrl->delay = XDC_DELAY_SUN3;
! 1240: #endif
! 1241: break;
! 1242: }
! 1243: case XDFUN_DRV:{
! 1244: struct xd_iopb_drive *drv =
! 1245: (struct xd_iopb_drive *)iopb;
! 1246: /* we assume that the disk label has the right
! 1247: * info */
! 1248: if (XD_STATE(iorq->mode) == XD_SUB_POLL)
! 1249: drv->dparam_ipl = (XDC_DPARAM << 3);
! 1250: else
! 1251: drv->dparam_ipl = (XDC_DPARAM << 3) |
! 1252: iorq->xdc->ipl;
! 1253: drv->maxsect = iorq->xd->nsect - 1;
! 1254: drv->maxsector = drv->maxsect;
! 1255: /* note: maxsector != maxsect only if you are
! 1256: * doing cyl sparing */
! 1257: drv->headoff = 0;
! 1258: drv->maxcyl = iorq->xd->pcyl - 1;
! 1259: drv->maxhead = iorq->xd->nhead - 1;
! 1260: break;
! 1261: }
! 1262: case XDFUN_FMT:{
! 1263: struct xd_iopb_format *form =
! 1264: (struct xd_iopb_format *) iopb;
! 1265: if (XD_STATE(iorq->mode) == XD_SUB_POLL)
! 1266: form->interleave_ipl = (XDC_INTERLEAVE << 3);
! 1267: else
! 1268: form->interleave_ipl = (XDC_INTERLEAVE << 3) |
! 1269: iorq->xdc->ipl;
! 1270: form->field1 = XDFM_FIELD1;
! 1271: form->field2 = XDFM_FIELD2;
! 1272: form->field3 = XDFM_FIELD3;
! 1273: form->field4 = XDFM_FIELD4;
! 1274: form->bytespersec = XDFM_BPS;
! 1275: form->field6 = XDFM_FIELD6;
! 1276: form->field7 = XDFM_FIELD7;
! 1277: break;
! 1278: }
! 1279: }
! 1280: } else {
! 1281:
! 1282: /* normal IOPB case (harmless to RDP command) */
! 1283:
! 1284: iopb->lll = 0;
! 1285: iopb->intl = (XD_STATE(iorq->mode) == XD_SUB_POLL)
! 1286: ? 0
! 1287: : iorq->xdc->ipl;
! 1288: iopb->sectcnt = iorq->sectcnt;
! 1289: block = iorq->blockno;
! 1290: if (iorq->xd == NULL || block == 0) {
! 1291: iopb->sectno = iopb->headno = iopb->cylno = 0;
! 1292: } else {
! 1293: iopb->sectno = block % iorq->xd->nsect;
! 1294: block = block / iorq->xd->nsect;
! 1295: iopb->headno = block % iorq->xd->nhead;
! 1296: block = block / iorq->xd->nhead;
! 1297: iopb->cylno = block;
! 1298: }
! 1299: dp = (u_long) iorq->dbuf - DVMA_BASE;
! 1300: dp = iopb->daddr = (iorq->dbuf == NULL) ? 0 : dp;
! 1301: iopb->addrmod = ((dp + (XDFM_BPS * iorq->sectcnt)) > 0x1000000)
! 1302: ? XDC_ADDRMOD32
! 1303: : XDC_ADDRMOD;
! 1304: }
! 1305: }
! 1306:
! 1307: /*
! 1308: * xdc_cmd: front end for POLL'd and WAIT'd commands. Returns rqno.
! 1309: * If you've already got an IORQ, you can call submit directly (currently
! 1310: * there is no need to do this). NORM requests are handled separately.
! 1311: */
! 1312: int
! 1313: xdc_cmd(xdcsc, cmd, subfn, unit, block, scnt, dptr, fullmode)
! 1314: struct xdc_softc *xdcsc;
! 1315: int cmd, subfn, unit, block, scnt;
! 1316: char *dptr;
! 1317: int fullmode;
! 1318:
! 1319: {
! 1320: int rqno, submode = XD_STATE(fullmode), retry;
! 1321: struct xd_iorq *iorq;
! 1322: struct xd_iopb *iopb;
! 1323:
! 1324: /* get iorq/iopb */
! 1325: switch (submode) {
! 1326: case XD_SUB_POLL:
! 1327: while (xdcsc->nfree == 0) {
! 1328: if (xdc_piodriver(xdcsc, 0, 1) != XD_ERR_AOK)
! 1329: return (XD_ERR_FAIL);
! 1330: }
! 1331: break;
! 1332: case XD_SUB_WAIT:
! 1333: retry = 1;
! 1334: while (retry) {
! 1335: while (xdcsc->nfree == 0) {
! 1336: if (tsleep(&xdcsc->nfree, PRIBIO, "xdnfree", 0))
! 1337: return (XD_ERR_FAIL);
! 1338: }
! 1339: while (xdcsc->ndone > XDC_SUBWAITLIM) {
! 1340: if (tsleep(&xdcsc->ndone, PRIBIO, "xdsubwait", 0))
! 1341: return (XD_ERR_FAIL);
! 1342: }
! 1343: if (xdcsc->nfree)
! 1344: retry = 0; /* got it */
! 1345: }
! 1346: break;
! 1347: default:
! 1348: return (XD_ERR_FAIL); /* illegal */
! 1349: }
! 1350: if (xdcsc->nfree == 0)
! 1351: panic("xdcmd nfree");
! 1352: rqno = XDC_RQALLOC(xdcsc);
! 1353: iorq = &xdcsc->reqs[rqno];
! 1354: iopb = iorq->iopb;
! 1355:
! 1356:
! 1357: /* init iorq/iopb */
! 1358:
! 1359: xdc_rqinit(iorq, xdcsc,
! 1360: (unit == XDC_NOUNIT) ? NULL : xdcsc->sc_drives[unit],
! 1361: fullmode, block, scnt, dptr, NULL);
! 1362:
! 1363: /* load IOPB from iorq */
! 1364:
! 1365: xdc_rqtopb(iorq, iopb, cmd, subfn);
! 1366:
! 1367: /* submit it for processing */
! 1368:
! 1369: xdc_submit_iorq(xdcsc, rqno, fullmode); /* error code will be in iorq */
! 1370:
! 1371: return (rqno);
! 1372: }
! 1373: /*
! 1374: * xdc_startbuf
! 1375: * start a buffer running, assumes nfree > 0
! 1376: */
! 1377:
! 1378: int
! 1379: xdc_startbuf(xdcsc, xdsc, bp)
! 1380: struct xdc_softc *xdcsc;
! 1381: struct xd_softc *xdsc;
! 1382: struct buf *bp;
! 1383:
! 1384: {
! 1385: int rqno, partno;
! 1386: struct xd_iorq *iorq;
! 1387: struct xd_iopb *iopb;
! 1388: struct buf *wq;
! 1389: u_long block;
! 1390: caddr_t dbuf;
! 1391:
! 1392: if (!xdcsc->nfree)
! 1393: panic("xdc_startbuf free");
! 1394: rqno = XDC_RQALLOC(xdcsc);
! 1395: iorq = &xdcsc->reqs[rqno];
! 1396: iopb = iorq->iopb;
! 1397:
! 1398: /* get buf */
! 1399:
! 1400: if (bp == NULL) {
! 1401: bp = xdcsc->sc_wq.b_actf;
! 1402: if (!bp)
! 1403: panic("xdc_startbuf bp");
! 1404: wq = bp->b_actf;
! 1405: if (wq)
! 1406: wq->b_actb = bp->b_actb;
! 1407: else
! 1408: xdcsc->sc_wq.b_actb = bp->b_actb;
! 1409: *bp->b_actb = wq;
! 1410: xdsc = xdcsc->sc_drives[DISKUNIT(bp->b_dev)];
! 1411: }
! 1412: partno = DISKPART(bp->b_dev);
! 1413: #ifdef XDC_DEBUG
! 1414: printf("xdc_startbuf: %s%c: %s block %lld\n",
! 1415: xdsc->sc_dev.dv_xname, 'a' + partno,
! 1416: (bp->b_flags & B_READ) ? "read" : "write", bp->b_blkno);
! 1417: printf("xdc_startbuf: b_bcount %d, b_data 0x%x\n",
! 1418: bp->b_bcount, bp->b_data);
! 1419: #endif
! 1420:
! 1421: /*
! 1422: * load request. we have to calculate the correct block number based
! 1423: * on partition info.
! 1424: *
! 1425: * note that iorq points to the buffer as mapped into DVMA space,
! 1426: * where as the bp->b_data points to its non-DVMA mapping.
! 1427: */
! 1428:
! 1429: block = bp->b_blkno + ((partno == RAW_PART) ? 0 :
! 1430: DL_GETPOFFSET(&xdsc->sc_dk.dk_label->d_partitions[partno]));
! 1431:
! 1432: dbuf = kdvma_mapin(bp->b_data, bp->b_bcount, 0);
! 1433: if (dbuf == NULL) { /* out of DVMA space */
! 1434: printf("%s: warning: out of DVMA space\n",
! 1435: xdcsc->sc_dev.dv_xname);
! 1436: XDC_FREE(xdcsc, rqno);
! 1437: wq = &xdcsc->sc_wq; /* put at end of queue */
! 1438: bp->b_actf = 0;
! 1439: bp->b_actb = wq->b_actb;
! 1440: *wq->b_actb = bp;
! 1441: wq->b_actb = &bp->b_actf;
! 1442: return (XD_ERR_FAIL); /* XXX: need some sort of
! 1443: * call-back scheme here? */
! 1444: }
! 1445:
! 1446: /* init iorq and load iopb from it */
! 1447:
! 1448: xdc_rqinit(iorq, xdcsc, xdsc, XD_SUB_NORM | XD_MODE_VERBO, block,
! 1449: bp->b_bcount / XDFM_BPS, dbuf, bp);
! 1450:
! 1451: xdc_rqtopb(iorq, iopb, (bp->b_flags & B_READ) ? XDCMD_RD : XDCMD_WR, 0);
! 1452:
! 1453: /* Instrumentation. */
! 1454: disk_busy(&xdsc->sc_dk);
! 1455:
! 1456: /* now submit [note that xdc_submit_iorq can never fail on NORM reqs] */
! 1457:
! 1458: xdc_submit_iorq(xdcsc, rqno, XD_SUB_NORM);
! 1459: return (XD_ERR_AOK);
! 1460: }
! 1461:
! 1462:
! 1463: /*
! 1464: * xdc_submit_iorq: submit an iorq for processing. returns XD_ERR_AOK
! 1465: * if ok. if it fail returns an error code. type is XD_SUB_*.
! 1466: *
! 1467: * note: caller frees iorq in all cases except NORM
! 1468: *
! 1469: * return value:
! 1470: * NORM: XD_AOK (req pending), XD_FAIL (couldn't submit request)
! 1471: * WAIT: XD_AOK (success), <error-code> (failed)
! 1472: * POLL: <same as WAIT>
! 1473: * NOQ : <same as NORM>
! 1474: *
! 1475: * there are three sources for i/o requests:
! 1476: * [1] xdstrategy: normal block I/O, using "struct buf" system.
! 1477: * [2] autoconfig/crash dump: these are polled I/O requests, no interrupts.
! 1478: * [3] open/ioctl: these are I/O requests done in the context of a process,
! 1479: * and the process should block until they are done.
! 1480: *
! 1481: * software state is stored in the iorq structure. each iorq has an
! 1482: * iopb structure. the hardware understands the iopb structure.
! 1483: * every command must go through an iopb. a 7053 can only handle
! 1484: * XDC_MAXIOPB (31) active iopbs at one time. iopbs are allocated in
! 1485: * DVMA space at boot up time. what happens if we run out of iopb's?
! 1486: * for i/o type [1], the buffers are queued at the "buff" layer and
! 1487: * picked up later by the interrupt routine. for case [2] the
! 1488: * programmed i/o driver is called with a special flag that says
! 1489: * return when one iopb is free. for case [3] the process can sleep
! 1490: * on the iorq free list until some iopbs are available.
! 1491: */
! 1492:
! 1493:
! 1494: int
! 1495: xdc_submit_iorq(xdcsc, iorqno, type)
! 1496: struct xdc_softc *xdcsc;
! 1497: int iorqno;
! 1498: int type;
! 1499:
! 1500: {
! 1501: u_long iopbaddr;
! 1502: struct xd_iorq *iorq = &xdcsc->reqs[iorqno];
! 1503:
! 1504: #ifdef XDC_DEBUG
! 1505: printf("xdc_submit_iorq(%s, no=%d, type=%d)\n", xdcsc->sc_dev.dv_xname,
! 1506: iorqno, type);
! 1507: #endif
! 1508:
! 1509: /* first check and see if controller is busy */
! 1510: if (xdcsc->xdc->xdc_csr & XDC_ADDING) {
! 1511: #ifdef XDC_DEBUG
! 1512: printf("xdc_submit_iorq: XDC not ready (ADDING)\n");
! 1513: #endif
! 1514: if (type == XD_SUB_NOQ)
! 1515: return (XD_ERR_FAIL); /* failed */
! 1516: XDC_TWAIT(xdcsc, iorqno); /* put at end of waitq */
! 1517: switch (type) {
! 1518: case XD_SUB_NORM:
! 1519: return XD_ERR_AOK; /* success */
! 1520: case XD_SUB_WAIT:
! 1521: while (iorq->iopb->done == 0) {
! 1522: tsleep(iorq, PRIBIO, "xdiorq", 0);
! 1523: }
! 1524: return (iorq->errno);
! 1525: case XD_SUB_POLL:
! 1526: return (xdc_piodriver(xdcsc, iorqno, 0));
! 1527: default:
! 1528: panic("xdc_submit_iorq adding");
! 1529: }
! 1530: }
! 1531: #ifdef XDC_DEBUG
! 1532: {
! 1533: u_char *rio = (u_char *) iorq->iopb;
! 1534: int sz = sizeof(struct xd_iopb), lcv;
! 1535: printf("%s: aio #%d [",
! 1536: xdcsc->sc_dev.dv_xname, iorq - xdcsc->reqs);
! 1537: for (lcv = 0; lcv < sz; lcv++)
! 1538: printf(" %02x", rio[lcv]);
! 1539: printf("]\n");
! 1540: }
! 1541: #endif /* XDC_DEBUG */
! 1542:
! 1543: /* controller not busy, start command */
! 1544: iopbaddr = (u_long) iorq->iopb - (u_long) DVMA_BASE;
! 1545: XDC_GO(xdcsc->xdc, iopbaddr); /* go! */
! 1546: xdcsc->nrun++;
! 1547: /* command now running, wrap it up */
! 1548: switch (type) {
! 1549: case XD_SUB_NORM:
! 1550: case XD_SUB_NOQ:
! 1551: return (XD_ERR_AOK); /* success */
! 1552: case XD_SUB_WAIT:
! 1553: while (iorq->iopb->done == 0) {
! 1554: tsleep(iorq, PRIBIO, "xdiorq", 0);
! 1555: }
! 1556: return (iorq->errno);
! 1557: case XD_SUB_POLL:
! 1558: return (xdc_piodriver(xdcsc, iorqno, 0));
! 1559: default:
! 1560: panic("xdc_submit_iorq wrap up");
! 1561: }
! 1562: panic("xdc_submit_iorq");
! 1563: return 0; /* not reached */
! 1564: }
! 1565:
! 1566:
! 1567: /*
! 1568: * xdc_piodriver
! 1569: *
! 1570: * programmed i/o driver. this function takes over the computer
! 1571: * and drains off all i/o requests. it returns the status of the iorq
! 1572: * the caller is interesting in. if freeone is true, then it returns
! 1573: * when there is a free iorq.
! 1574: */
! 1575: int
! 1576: xdc_piodriver(xdcsc, iorqno, freeone)
! 1577: struct xdc_softc *xdcsc;
! 1578: int iorqno;
! 1579: int freeone;
! 1580:
! 1581: {
! 1582: int nreset = 0;
! 1583: int retval = 0;
! 1584: u_long count;
! 1585: struct xdc *xdc = xdcsc->xdc;
! 1586: #ifdef XDC_DEBUG
! 1587: printf("xdc_piodriver(%s, %d, freeone=%d)\n", xdcsc->sc_dev.dv_xname,
! 1588: iorqno, freeone);
! 1589: #endif
! 1590:
! 1591: while (xdcsc->nwait || xdcsc->nrun) {
! 1592: #ifdef XDC_DEBUG
! 1593: printf("xdc_piodriver: wait=%d, run=%d\n",
! 1594: xdcsc->nwait, xdcsc->nrun);
! 1595: #endif
! 1596: XDC_WAIT(xdc, count, XDC_MAXTIME, (XDC_REMIOPB | XDC_F_ERROR));
! 1597: #ifdef XDC_DEBUG
! 1598: printf("xdc_piodriver: done wait with count = %d\n", count);
! 1599: #endif
! 1600: /* we expect some progress soon */
! 1601: if (count == 0 && nreset >= 2) {
! 1602: xdc_reset(xdcsc, 0, XD_RSET_ALL, XD_ERR_FAIL, 0);
! 1603: #ifdef XDC_DEBUG
! 1604: printf("xdc_piodriver: timeout\n");
! 1605: #endif
! 1606: return (XD_ERR_FAIL);
! 1607: }
! 1608: if (count == 0) {
! 1609: if (xdc_reset(xdcsc, 0,
! 1610: (nreset++ == 0) ? XD_RSET_NONE : iorqno,
! 1611: XD_ERR_FAIL,
! 1612: 0) == XD_ERR_FAIL)
! 1613: return (XD_ERR_FAIL); /* flushes all but POLL
! 1614: * requests, resets */
! 1615: continue;
! 1616: }
! 1617: xdc_remove_iorq(xdcsc); /* could resubmit request */
! 1618: if (freeone) {
! 1619: if (xdcsc->nrun < XDC_MAXIOPB) {
! 1620: #ifdef XDC_DEBUG
! 1621: printf("xdc_piodriver: done: one free\n");
! 1622: #endif
! 1623: return (XD_ERR_AOK);
! 1624: }
! 1625: continue; /* don't xdc_start */
! 1626: }
! 1627: xdc_start(xdcsc, XDC_MAXIOPB);
! 1628: }
! 1629:
! 1630: /* get return value */
! 1631:
! 1632: retval = xdcsc->reqs[iorqno].errno;
! 1633:
! 1634: #ifdef XDC_DEBUG
! 1635: printf("xdc_piodriver: done, retval = 0x%x (%s)\n",
! 1636: xdcsc->reqs[iorqno].errno, xdc_e2str(xdcsc->reqs[iorqno].errno));
! 1637: #endif
! 1638:
! 1639: /* now that we've drained everything, start up any bufs that have
! 1640: * queued */
! 1641:
! 1642: while (xdcsc->nfree > 0 && xdcsc->sc_wq.b_actf)
! 1643: if (xdc_startbuf(xdcsc, NULL, NULL) != XD_ERR_AOK)
! 1644: break;
! 1645:
! 1646: return (retval);
! 1647: }
! 1648:
! 1649: /*
! 1650: * xdc_reset: reset one drive. NOTE: assumes xdc was just reset.
! 1651: * we steal iopb[0] for this, but we put it back when we are done.
! 1652: */
! 1653: void
! 1654: xdc_xdreset(xdcsc, xdsc)
! 1655: struct xdc_softc *xdcsc;
! 1656: struct xd_softc *xdsc;
! 1657:
! 1658: {
! 1659: struct xd_iopb tmpiopb;
! 1660: u_long addr;
! 1661: int del;
! 1662: bcopy(xdcsc->iopbase, &tmpiopb, sizeof(tmpiopb));
! 1663: bzero(xdcsc->iopbase, sizeof(tmpiopb));
! 1664: xdcsc->iopbase->comm = XDCMD_RST;
! 1665: xdcsc->iopbase->unit = xdsc->xd_drive;
! 1666: addr = (u_long) xdcsc->dvmaiopb;
! 1667: XDC_GO(xdcsc->xdc, addr); /* go! */
! 1668: XDC_WAIT(xdcsc->xdc, del, XDC_RESETUSEC, XDC_REMIOPB);
! 1669: if (del <= 0 || xdcsc->iopbase->errs) {
! 1670: printf("%s: off-line: %s\n", xdcsc->sc_dev.dv_xname,
! 1671: xdc_e2str(xdcsc->iopbase->errno));
! 1672: xdcsc->xdc->xdc_csr = XDC_RESET;
! 1673: XDC_WAIT(xdcsc->xdc, del, XDC_RESETUSEC, XDC_RESET);
! 1674: if (del <= 0)
! 1675: panic("xdc_reset");
! 1676: } else {
! 1677: xdcsc->xdc->xdc_csr = XDC_CLRRIO; /* clear RIO */
! 1678: }
! 1679: bcopy(&tmpiopb, xdcsc->iopbase, sizeof(tmpiopb));
! 1680: }
! 1681:
! 1682:
! 1683: /*
! 1684: * xdc_reset: reset everything: requests are marked as errors except
! 1685: * a polled request (which is resubmitted)
! 1686: */
! 1687: int
! 1688: xdc_reset(xdcsc, quiet, blastmode, error, xdsc)
! 1689: struct xdc_softc *xdcsc;
! 1690: int quiet, blastmode, error;
! 1691: struct xd_softc *xdsc;
! 1692:
! 1693: {
! 1694: int del = 0, lcv, retval = XD_ERR_AOK;
! 1695: int oldfree = xdcsc->nfree;
! 1696:
! 1697: /* soft reset hardware */
! 1698:
! 1699: if (!quiet)
! 1700: printf("%s: soft reset\n", xdcsc->sc_dev.dv_xname);
! 1701: xdcsc->xdc->xdc_csr = XDC_RESET;
! 1702: XDC_WAIT(xdcsc->xdc, del, XDC_RESETUSEC, XDC_RESET);
! 1703: if (del <= 0) {
! 1704: blastmode = XD_RSET_ALL; /* dead, flush all requests */
! 1705: retval = XD_ERR_FAIL;
! 1706: }
! 1707: if (xdsc)
! 1708: xdc_xdreset(xdcsc, xdsc);
! 1709:
! 1710: /* fix queues based on "blast-mode" */
! 1711:
! 1712: for (lcv = 0; lcv < XDC_MAXIOPB; lcv++) {
! 1713: struct xd_iorq *iorq = &xdcsc->reqs[lcv];
! 1714:
! 1715: if (XD_STATE(iorq->mode) != XD_SUB_POLL &&
! 1716: XD_STATE(iorq->mode) != XD_SUB_WAIT &&
! 1717: XD_STATE(iorq->mode) != XD_SUB_NORM)
! 1718: /* is it active? */
! 1719: continue;
! 1720:
! 1721: xdcsc->nrun--; /* it isn't running any more */
! 1722: if (blastmode == XD_RSET_ALL || blastmode != lcv) {
! 1723: /* failed */
! 1724: iorq->errno = error;
! 1725: xdcsc->iopbase[lcv].done = xdcsc->iopbase[lcv].errs = 1;
! 1726: switch (XD_STATE(xdcsc->reqs[lcv].mode)) {
! 1727: case XD_SUB_NORM:
! 1728: iorq->buf->b_error = EIO;
! 1729: iorq->buf->b_flags |= B_ERROR;
! 1730: iorq->buf->b_resid =
! 1731: iorq->sectcnt * XDFM_BPS;
! 1732: dvma_mapout((vaddr_t)iorq->dbufbase,
! 1733: (vaddr_t)iorq->buf->b_data,
! 1734: iorq->buf->b_bcount);
! 1735: disk_unbusy(&xdcsc->reqs[lcv].xd->sc_dk,
! 1736: (xdcsc->reqs[lcv].buf->b_bcount -
! 1737: xdcsc->reqs[lcv].buf->b_resid),
! 1738: (xdcsc->reqs[lcv].buf->b_flags & B_READ));
! 1739: biodone(iorq->buf);
! 1740: XDC_FREE(xdcsc, lcv); /* add to free list */
! 1741: break;
! 1742: case XD_SUB_WAIT:
! 1743: wakeup(iorq);
! 1744: case XD_SUB_POLL:
! 1745: xdcsc->ndone++;
! 1746: iorq->mode =
! 1747: XD_NEWSTATE(iorq->mode, XD_SUB_DONE);
! 1748: break;
! 1749: }
! 1750:
! 1751: } else {
! 1752:
! 1753: /* resubmit, put at front of wait queue */
! 1754: XDC_HWAIT(xdcsc, lcv);
! 1755: }
! 1756: }
! 1757:
! 1758: /*
! 1759: * now, if stuff is waiting, start it.
! 1760: * since we just reset it should go
! 1761: */
! 1762: xdc_start(xdcsc, XDC_MAXIOPB);
! 1763:
! 1764: /* ok, we did it */
! 1765: if (oldfree == 0 && xdcsc->nfree)
! 1766: wakeup(&xdcsc->nfree);
! 1767:
! 1768: #ifdef XDC_DIAG
! 1769: del = xdcsc->nwait + xdcsc->nrun + xdcsc->nfree + xdcsc->ndone;
! 1770: if (del != XDC_MAXIOPB)
! 1771: printf("%s: diag: xdc_reset miscount (%d should be %d)!\n",
! 1772: xdcsc->sc_dev.dv_xname, del, XDC_MAXIOPB);
! 1773: else
! 1774: if (xdcsc->ndone > XDC_MAXIOPB - XDC_SUBWAITLIM)
! 1775: printf("%s: diag: lots of done jobs (%d)\n",
! 1776: xdcsc->sc_dev.dv_xname, xdcsc->ndone);
! 1777: #endif
! 1778: printf("RESET DONE\n");
! 1779: return (retval);
! 1780: }
! 1781: /*
! 1782: * xdc_start: start all waiting buffers
! 1783: */
! 1784:
! 1785: void
! 1786: xdc_start(xdcsc, maxio)
! 1787: struct xdc_softc *xdcsc;
! 1788: int maxio;
! 1789:
! 1790: {
! 1791: int rqno;
! 1792: while (maxio && xdcsc->nwait &&
! 1793: (xdcsc->xdc->xdc_csr & XDC_ADDING) == 0) {
! 1794: XDC_GET_WAITER(xdcsc, rqno); /* note: rqno is an "out"
! 1795: * param */
! 1796: if (xdc_submit_iorq(xdcsc, rqno, XD_SUB_NOQ) != XD_ERR_AOK)
! 1797: panic("xdc_start"); /* should never happen */
! 1798: maxio--;
! 1799: }
! 1800: }
! 1801: /*
! 1802: * xdc_remove_iorq: remove "done" IOPB's.
! 1803: */
! 1804:
! 1805: int
! 1806: xdc_remove_iorq(xdcsc)
! 1807: struct xdc_softc *xdcsc;
! 1808:
! 1809: {
! 1810: int errno, rqno, comm, errs;
! 1811: struct xdc *xdc = xdcsc->xdc;
! 1812: struct xd_iopb *iopb;
! 1813: struct xd_iorq *iorq;
! 1814: struct buf *bp;
! 1815:
! 1816: if (xdc->xdc_csr & XDC_F_ERROR) {
! 1817: /*
! 1818: * FATAL ERROR: should never happen under normal use. This
! 1819: * error is so bad, you can't even tell which IOPB is bad, so
! 1820: * we dump them all.
! 1821: */
! 1822: errno = xdc->xdc_f_err;
! 1823: printf("%s: fatal error 0x%02x: %s\n", xdcsc->sc_dev.dv_xname,
! 1824: errno, xdc_e2str(errno));
! 1825: if (xdc_reset(xdcsc, 0, XD_RSET_ALL, errno, 0) != XD_ERR_AOK) {
! 1826: printf("%s: soft reset failed!\n",
! 1827: xdcsc->sc_dev.dv_xname);
! 1828: panic("xdc_remove_iorq: controller DEAD");
! 1829: }
! 1830: return (XD_ERR_AOK);
! 1831: }
! 1832:
! 1833: /*
! 1834: * get iopb that is done
! 1835: *
! 1836: * hmm... I used to read the address of the done IOPB off the VME
! 1837: * registers and calculate the rqno directly from that. that worked
! 1838: * until I started putting a load on the controller. when loaded, i
! 1839: * would get interrupts but neither the REMIOPB or F_ERROR bits would
! 1840: * be set, even after DELAY'ing a while! later on the timeout
! 1841: * routine would detect IOPBs that were marked "running" but their
! 1842: * "done" bit was set. rather than dealing directly with this
! 1843: * problem, it is just easier to look at all running IOPB's for the
! 1844: * done bit.
! 1845: */
! 1846: if (xdc->xdc_csr & XDC_REMIOPB) {
! 1847: xdc->xdc_csr = XDC_CLRRIO;
! 1848: }
! 1849:
! 1850: for (rqno = 0; rqno < XDC_MAXIOPB; rqno++) {
! 1851: iorq = &xdcsc->reqs[rqno];
! 1852: if (iorq->mode == 0 || XD_STATE(iorq->mode) == XD_SUB_DONE)
! 1853: continue; /* free, or done */
! 1854: iopb = &xdcsc->iopbase[rqno];
! 1855: if (iopb->done == 0)
! 1856: continue; /* not done yet */
! 1857:
! 1858: #ifdef XDC_DEBUG
! 1859: {
! 1860: u_char *rio = (u_char *) iopb;
! 1861: int sz = sizeof(struct xd_iopb), lcv;
! 1862: printf("%s: rio #%d [", xdcsc->sc_dev.dv_xname, rqno);
! 1863: for (lcv = 0; lcv < sz; lcv++)
! 1864: printf(" %02x", rio[lcv]);
! 1865: printf("]\n");
! 1866: }
! 1867: #endif /* XDC_DEBUG */
! 1868:
! 1869: xdcsc->nrun--;
! 1870:
! 1871: comm = iopb->comm;
! 1872: errs = iopb->errs;
! 1873:
! 1874: if (errs)
! 1875: iorq->errno = iopb->errno;
! 1876: else
! 1877: iorq->errno = 0;
! 1878:
! 1879: /* handle non-fatal errors */
! 1880:
! 1881: if (errs &&
! 1882: xdc_error(xdcsc, iorq, iopb, rqno, comm) == XD_ERR_AOK)
! 1883: continue; /* AOK: we resubmitted it */
! 1884:
! 1885:
! 1886: /* this iorq is now done (hasn't been restarted or anything) */
! 1887:
! 1888: if ((iorq->mode & XD_MODE_VERBO) && iorq->lasterror)
! 1889: xdc_perror(iorq, iopb, 0);
! 1890:
! 1891: /* now, if read/write check to make sure we got all the data
! 1892: * we needed. (this may not be the case if we got an error in
! 1893: * the middle of a multisector request). */
! 1894:
! 1895: if ((iorq->mode & XD_MODE_B144) != 0 && errs == 0 &&
! 1896: (comm == XDCMD_RD || comm == XDCMD_WR)) {
! 1897: /* we just successfully processed a bad144 sector
! 1898: * note: if we are in bad 144 mode, the pointers have
! 1899: * been advanced already (see above) and are pointing
! 1900: * at the bad144 sector. to exit bad144 mode, we
! 1901: * must advance the pointers 1 sector and issue a new
! 1902: * request if there are still sectors left to process
! 1903: *
! 1904: */
! 1905: XDC_ADVANCE(iorq, 1); /* advance 1 sector */
! 1906:
! 1907: /* exit b144 mode */
! 1908: iorq->mode = iorq->mode & (~XD_MODE_B144);
! 1909:
! 1910: if (iorq->sectcnt) { /* more to go! */
! 1911: iorq->lasterror = iorq->errno = iopb->errno = 0;
! 1912: iopb->errs = iopb->done = 0;
! 1913: iorq->tries = 0;
! 1914: iopb->sectcnt = iorq->sectcnt;
! 1915: iopb->cylno = iorq->blockno /
! 1916: iorq->xd->sectpercyl;
! 1917: iopb->headno =
! 1918: (iorq->blockno / iorq->xd->nhead) %
! 1919: iorq->xd->nhead;
! 1920: iopb->sectno = iorq->blockno % XDFM_BPS;
! 1921: iopb->daddr = (u_long) iorq->dbuf - DVMA_BASE;
! 1922: XDC_HWAIT(xdcsc, rqno);
! 1923: xdc_start(xdcsc, 1); /* resubmit */
! 1924: continue;
! 1925: }
! 1926: }
! 1927: /* final cleanup, totally done with this request */
! 1928:
! 1929: switch (XD_STATE(iorq->mode)) {
! 1930: case XD_SUB_NORM:
! 1931: bp = iorq->buf;
! 1932: if (errs) {
! 1933: bp->b_error = EIO;
! 1934: bp->b_flags |= B_ERROR;
! 1935: bp->b_resid = iorq->sectcnt * XDFM_BPS;
! 1936: } else {
! 1937: bp->b_resid = 0; /* done */
! 1938: }
! 1939: dvma_mapout((vaddr_t) iorq->dbufbase,
! 1940: (vaddr_t) bp->b_data,
! 1941: bp->b_bcount);
! 1942: disk_unbusy(&iorq->xd->sc_dk,
! 1943: (bp->b_bcount - bp->b_resid),
! 1944: (bp->b_flags & B_READ));
! 1945: XDC_FREE(xdcsc, rqno);
! 1946: biodone(bp);
! 1947: break;
! 1948: case XD_SUB_WAIT:
! 1949: iorq->mode = XD_NEWSTATE(iorq->mode, XD_SUB_DONE);
! 1950: xdcsc->ndone++;
! 1951: wakeup(iorq);
! 1952: break;
! 1953: case XD_SUB_POLL:
! 1954: iorq->mode = XD_NEWSTATE(iorq->mode, XD_SUB_DONE);
! 1955: xdcsc->ndone++;
! 1956: break;
! 1957: }
! 1958: }
! 1959:
! 1960: return (XD_ERR_AOK);
! 1961: }
! 1962:
! 1963: /*
! 1964: * xdc_perror: print error.
! 1965: * - if still_trying is true: we got an error, retried and got a
! 1966: * different error. in that case lasterror is the old error,
! 1967: * and errno is the new one.
! 1968: * - if still_trying is not true, then if we ever had an error it
! 1969: * is in lasterror. also, if iorq->errno == 0, then we recovered
! 1970: * from that error (otherwise iorq->errno == iorq->lasterror).
! 1971: */
! 1972: void
! 1973: xdc_perror(iorq, iopb, still_trying)
! 1974: struct xd_iorq *iorq;
! 1975: struct xd_iopb *iopb;
! 1976: int still_trying;
! 1977:
! 1978: {
! 1979:
! 1980: int error = iorq->lasterror;
! 1981:
! 1982: printf("%s", (iorq->xd) ? iorq->xd->sc_dev.dv_xname
! 1983: : iorq->xdc->sc_dev.dv_xname);
! 1984: if (iorq->buf)
! 1985: printf("%c: ", 'a' + DISKPART(iorq->buf->b_dev));
! 1986: if (iopb->comm == XDCMD_RD || iopb->comm == XDCMD_WR)
! 1987: printf("%s %d/%d/%d: ",
! 1988: (iopb->comm == XDCMD_RD) ? "read" : "write",
! 1989: iopb->cylno, iopb->headno, iopb->sectno);
! 1990: printf("%s", xdc_e2str(error));
! 1991:
! 1992: if (still_trying)
! 1993: printf(" [still trying, new error=%s]", xdc_e2str(iorq->errno));
! 1994: else
! 1995: if (iorq->errno == 0)
! 1996: printf(" [recovered in %d tries]", iorq->tries);
! 1997:
! 1998: printf("\n");
! 1999: }
! 2000:
! 2001: /*
! 2002: * xdc_error: non-fatal error encountered... recover.
! 2003: * return AOK if resubmitted, return FAIL if this iopb is done
! 2004: */
! 2005: int
! 2006: xdc_error(xdcsc, iorq, iopb, rqno, comm)
! 2007: struct xdc_softc *xdcsc;
! 2008: struct xd_iorq *iorq;
! 2009: struct xd_iopb *iopb;
! 2010: int rqno, comm;
! 2011:
! 2012: {
! 2013: int errno = iorq->errno;
! 2014: int erract = errno & XD_ERA_MASK;
! 2015: int oldmode, advance, i;
! 2016:
! 2017: if (erract == XD_ERA_RSET) { /* some errors require a reset */
! 2018: oldmode = iorq->mode;
! 2019: iorq->mode = XD_SUB_DONE | (~XD_SUB_MASK & oldmode);
! 2020: xdcsc->ndone++;
! 2021: /* make xdc_start ignore us */
! 2022: xdc_reset(xdcsc, 1, XD_RSET_NONE, errno, iorq->xd);
! 2023: iorq->mode = oldmode;
! 2024: xdcsc->ndone--;
! 2025: }
! 2026: /* check for read/write to a sector in bad144 table if bad: redirect
! 2027: * request to bad144 area */
! 2028:
! 2029: if ((comm == XDCMD_RD || comm == XDCMD_WR) &&
! 2030: (iorq->mode & XD_MODE_B144) == 0) {
! 2031: advance = iorq->sectcnt - iopb->sectcnt;
! 2032: XDC_ADVANCE(iorq, advance);
! 2033: if ((i = isbad(&iorq->xd->dkb, iorq->blockno / iorq->xd->sectpercyl,
! 2034: (iorq->blockno / iorq->xd->nsect) % iorq->xd->nhead,
! 2035: iorq->blockno % iorq->xd->nsect)) != -1) {
! 2036: iorq->mode |= XD_MODE_B144; /* enter bad144 mode &
! 2037: * redirect */
! 2038: iopb->errno = iopb->done = iopb->errs = 0;
! 2039: iopb->sectcnt = 1;
! 2040: iopb->cylno = (iorq->xd->ncyl + iorq->xd->acyl) - 2;
! 2041: /* second to last acyl */
! 2042: i = iorq->xd->sectpercyl - 1 - i; /* follow bad144
! 2043: * standard */
! 2044: iopb->headno = i / iorq->xd->nhead;
! 2045: iopb->sectno = i % iorq->xd->nhead;
! 2046: XDC_HWAIT(xdcsc, rqno);
! 2047: xdc_start(xdcsc, 1); /* resubmit */
! 2048: return (XD_ERR_AOK); /* recovered! */
! 2049: }
! 2050: }
! 2051:
! 2052: /*
! 2053: * it isn't a bad144 sector, must be real error! see if we can retry
! 2054: * it?
! 2055: */
! 2056: if ((iorq->mode & XD_MODE_VERBO) && iorq->lasterror)
! 2057: xdc_perror(iorq, iopb, 1); /* inform of error state
! 2058: * change */
! 2059: iorq->lasterror = errno;
! 2060:
! 2061: if ((erract == XD_ERA_RSET || erract == XD_ERA_HARD)
! 2062: && iorq->tries < XDC_MAXTRIES) { /* retry? */
! 2063: iorq->tries++;
! 2064: iorq->errno = iopb->errno = iopb->done = iopb->errs = 0;
! 2065: XDC_HWAIT(xdcsc, rqno);
! 2066: xdc_start(xdcsc, 1); /* restart */
! 2067: return (XD_ERR_AOK); /* recovered! */
! 2068: }
! 2069:
! 2070: /* failed to recover from this error */
! 2071: return (XD_ERR_FAIL);
! 2072: }
! 2073:
! 2074: /*
! 2075: * xdc_tick: make sure xd is still alive and ticking (err, kicking).
! 2076: */
! 2077: void
! 2078: xdc_tick(arg)
! 2079: void *arg;
! 2080:
! 2081: {
! 2082: struct xdc_softc *xdcsc = arg;
! 2083: int lcv, s, reset = 0;
! 2084: #ifdef XDC_DIAG
! 2085: int wait, run, free, done, whd = 0;
! 2086: u_char fqc[XDC_MAXIOPB], wqc[XDC_MAXIOPB], mark[XDC_MAXIOPB];
! 2087: s = splbio();
! 2088: wait = xdcsc->nwait;
! 2089: run = xdcsc->nrun;
! 2090: free = xdcsc->nfree;
! 2091: done = xdcsc->ndone;
! 2092: bcopy(xdcsc->waitq, wqc, sizeof(wqc));
! 2093: bcopy(xdcsc->freereq, fqc, sizeof(fqc));
! 2094: splx(s);
! 2095: if (wait + run + free + done != XDC_MAXIOPB) {
! 2096: printf("%s: diag: IOPB miscount (got w/f/r/d %d/%d/%d/%d, wanted %d)\n",
! 2097: xdcsc->sc_dev.dv_xname, wait, free, run, done, XDC_MAXIOPB);
! 2098: bzero(mark, sizeof(mark));
! 2099: printf("FREE: ");
! 2100: for (lcv = free; lcv > 0; lcv--) {
! 2101: printf("%d ", fqc[lcv - 1]);
! 2102: mark[fqc[lcv - 1]] = 1;
! 2103: }
! 2104: printf("\nWAIT: ");
! 2105: lcv = wait;
! 2106: while (lcv > 0) {
! 2107: printf("%d ", wqc[whd]);
! 2108: mark[wqc[whd]] = 1;
! 2109: whd = (whd + 1) % XDC_MAXIOPB;
! 2110: lcv--;
! 2111: }
! 2112: printf("\n");
! 2113: for (lcv = 0; lcv < XDC_MAXIOPB; lcv++) {
! 2114: if (mark[lcv] == 0)
! 2115: printf("MARK: running %d: mode %d done %d errs %d errno 0x%x ttl %d buf %p\n",
! 2116: lcv, xdcsc->reqs[lcv].mode,
! 2117: xdcsc->iopbase[lcv].done,
! 2118: xdcsc->iopbase[lcv].errs,
! 2119: xdcsc->iopbase[lcv].errno,
! 2120: xdcsc->reqs[lcv].ttl, xdcsc->reqs[lcv].buf);
! 2121: }
! 2122: } else
! 2123: if (done > XDC_MAXIOPB - XDC_SUBWAITLIM)
! 2124: printf("%s: diag: lots of done jobs (%d)\n",
! 2125: xdcsc->sc_dev.dv_xname, done);
! 2126:
! 2127: #endif
! 2128: #ifdef XDC_DEBUG
! 2129: printf("%s: tick: csr 0x%x, w/f/r/d %d/%d/%d/%d\n",
! 2130: xdcsc->sc_dev.dv_xname,
! 2131: xdcsc->xdc->xdc_csr, xdcsc->nwait, xdcsc->nfree, xdcsc->nrun,
! 2132: xdcsc->ndone);
! 2133: for (lcv = 0; lcv < XDC_MAXIOPB; lcv++) {
! 2134: if (xdcsc->reqs[lcv].mode)
! 2135: printf("running %d: mode %d done %d errs %d errno 0x%x\n",
! 2136: lcv,
! 2137: xdcsc->reqs[lcv].mode, xdcsc->iopbase[lcv].done,
! 2138: xdcsc->iopbase[lcv].errs, xdcsc->iopbase[lcv].errno);
! 2139: }
! 2140: #endif
! 2141:
! 2142: /* reduce ttl for each request if one goes to zero, reset xdc */
! 2143: s = splbio();
! 2144: for (lcv = 0; lcv < XDC_MAXIOPB; lcv++) {
! 2145: if (xdcsc->reqs[lcv].mode == 0 ||
! 2146: XD_STATE(xdcsc->reqs[lcv].mode) == XD_SUB_DONE)
! 2147: continue;
! 2148: xdcsc->reqs[lcv].ttl--;
! 2149: if (xdcsc->reqs[lcv].ttl == 0)
! 2150: reset = 1;
! 2151: }
! 2152: if (reset) {
! 2153: printf("%s: watchdog timeout\n", xdcsc->sc_dev.dv_xname);
! 2154: xdc_reset(xdcsc, 0, XD_RSET_NONE, XD_ERR_FAIL, NULL);
! 2155: }
! 2156: splx(s);
! 2157:
! 2158: /* until next time */
! 2159:
! 2160: timeout_add(&xdcsc->xdc_tick_tmo, XDC_TICKCNT);
! 2161: }
! 2162:
! 2163: /*
! 2164: * xdc_ioctlcmd: this function provides a user level interface to the
! 2165: * controller via ioctl. this allows "format" programs to be written
! 2166: * in user code, and is also useful for some debugging. we return
! 2167: * an error code. called at user priority.
! 2168: */
! 2169: int
! 2170: xdc_ioctlcmd(xd, dev, xio)
! 2171: struct xd_softc *xd;
! 2172: dev_t dev;
! 2173: struct xd_iocmd *xio;
! 2174:
! 2175: {
! 2176: int s, err, rqno, dummy;
! 2177: caddr_t dvmabuf = NULL, buf = NULL;
! 2178: struct xdc_softc *xdcsc;
! 2179:
! 2180: /* check sanity of requested command */
! 2181:
! 2182: switch (xio->cmd) {
! 2183:
! 2184: case XDCMD_NOP: /* no op: everything should be zero */
! 2185: if (xio->subfn || xio->dptr || xio->dlen ||
! 2186: xio->block || xio->sectcnt)
! 2187: return (EINVAL);
! 2188: break;
! 2189:
! 2190: case XDCMD_RD: /* read / write sectors (up to XD_IOCMD_MAXS) */
! 2191: case XDCMD_WR:
! 2192: if (xio->subfn || xio->sectcnt > XD_IOCMD_MAXS ||
! 2193: xio->sectcnt * XDFM_BPS != xio->dlen || xio->dptr == NULL)
! 2194: return (EINVAL);
! 2195: break;
! 2196:
! 2197: case XDCMD_SK: /* seek: doesn't seem useful to export this */
! 2198: return (EINVAL);
! 2199:
! 2200: case XDCMD_WRP: /* write parameters */
! 2201: return (EINVAL);/* not useful, except maybe drive
! 2202: * parameters... but drive parameters should
! 2203: * go via disklabel changes */
! 2204:
! 2205: case XDCMD_RDP: /* read parameters */
! 2206: if (xio->subfn != XDFUN_DRV ||
! 2207: xio->dlen || xio->block || xio->dptr)
! 2208: return (EINVAL); /* allow read drive params to
! 2209: * get hw_spt */
! 2210: xio->sectcnt = xd->hw_spt; /* we already know the answer */
! 2211: return (0);
! 2212: break;
! 2213:
! 2214: case XDCMD_XRD: /* extended read/write */
! 2215: case XDCMD_XWR:
! 2216:
! 2217: switch (xio->subfn) {
! 2218:
! 2219: case XDFUN_THD:/* track headers */
! 2220: if (xio->sectcnt != xd->hw_spt ||
! 2221: (xio->block % xd->nsect) != 0 ||
! 2222: xio->dlen != XD_IOCMD_HSZ * xd->hw_spt ||
! 2223: xio->dptr == NULL)
! 2224: return (EINVAL);
! 2225: xio->sectcnt = 0;
! 2226: break;
! 2227:
! 2228: case XDFUN_FMT:/* NOTE: also XDFUN_VFY */
! 2229: if (xio->cmd == XDCMD_XRD)
! 2230: return (EINVAL); /* no XDFUN_VFY */
! 2231: if (xio->sectcnt || xio->dlen ||
! 2232: (xio->block % xd->nsect) != 0 || xio->dptr)
! 2233: return (EINVAL);
! 2234: break;
! 2235:
! 2236: case XDFUN_HDR:/* header, header verify, data, data ECC */
! 2237: return (EINVAL); /* not yet */
! 2238:
! 2239: case XDFUN_DM: /* defect map */
! 2240: case XDFUN_DMX:/* defect map (alternate location) */
! 2241: if (xio->sectcnt || xio->dlen != XD_IOCMD_DMSZ ||
! 2242: (xio->block % xd->nsect) != 0 || xio->dptr == NULL)
! 2243: return (EINVAL);
! 2244: break;
! 2245:
! 2246: default:
! 2247: return (EINVAL);
! 2248: }
! 2249: break;
! 2250:
! 2251: case XDCMD_TST: /* diagnostics */
! 2252: return (EINVAL);
! 2253:
! 2254: default:
! 2255: return (EINVAL);/* ??? */
! 2256: }
! 2257:
! 2258: /* create DVMA buffer for request if needed */
! 2259:
! 2260: if (xio->dlen) {
! 2261: dvmabuf = dvma_malloc(xio->dlen, &buf, M_WAITOK);
! 2262: if (xio->cmd == XDCMD_WR || xio->cmd == XDCMD_XWR) {
! 2263: if ((err = copyin(xio->dptr, buf, xio->dlen)) != 0) {
! 2264: dvma_free(dvmabuf, xio->dlen, &buf);
! 2265: return (err);
! 2266: }
! 2267: }
! 2268: }
! 2269: /* do it! */
! 2270:
! 2271: err = 0;
! 2272: xdcsc = xd->parent;
! 2273: s = splbio();
! 2274: rqno = xdc_cmd(xdcsc, xio->cmd, xio->subfn, xd->xd_drive, xio->block,
! 2275: xio->sectcnt, dvmabuf, XD_SUB_WAIT);
! 2276: if (rqno == XD_ERR_FAIL) {
! 2277: err = EIO;
! 2278: goto done;
! 2279: }
! 2280: xio->errno = xdcsc->reqs[rqno].errno;
! 2281: xio->tries = xdcsc->reqs[rqno].tries;
! 2282: XDC_DONE(xdcsc, rqno, dummy);
! 2283:
! 2284: if (xio->cmd == XDCMD_RD || xio->cmd == XDCMD_XRD)
! 2285: err = copyout(buf, xio->dptr, xio->dlen);
! 2286:
! 2287: done:
! 2288: splx(s);
! 2289: if (dvmabuf)
! 2290: dvma_free(dvmabuf, xio->dlen, &buf);
! 2291: return (err);
! 2292: }
! 2293:
! 2294: /*
! 2295: * xdc_e2str: convert error code number into an error string
! 2296: */
! 2297: char *
! 2298: xdc_e2str(no)
! 2299: int no;
! 2300: {
! 2301: switch (no) {
! 2302: case XD_ERR_FAIL:
! 2303: return ("Software fatal error");
! 2304: case XD_ERR_AOK:
! 2305: return ("Successful completion");
! 2306: case XD_ERR_ICYL:
! 2307: return ("Illegal cylinder address");
! 2308: case XD_ERR_IHD:
! 2309: return ("Illegal head address");
! 2310: case XD_ERR_ISEC:
! 2311: return ("Illgal sector address");
! 2312: case XD_ERR_CZER:
! 2313: return ("Count zero");
! 2314: case XD_ERR_UIMP:
! 2315: return ("Unimplemented command");
! 2316: case XD_ERR_IF1:
! 2317: return ("Illegal field length 1");
! 2318: case XD_ERR_IF2:
! 2319: return ("Illegal field length 2");
! 2320: case XD_ERR_IF3:
! 2321: return ("Illegal field length 3");
! 2322: case XD_ERR_IF4:
! 2323: return ("Illegal field length 4");
! 2324: case XD_ERR_IF5:
! 2325: return ("Illegal field length 5");
! 2326: case XD_ERR_IF6:
! 2327: return ("Illegal field length 6");
! 2328: case XD_ERR_IF7:
! 2329: return ("Illegal field length 7");
! 2330: case XD_ERR_ISG:
! 2331: return ("Illegal scatter/gather length");
! 2332: case XD_ERR_ISPT:
! 2333: return ("Not enough sectors per track");
! 2334: case XD_ERR_ALGN:
! 2335: return ("Next IOPB address alignment error");
! 2336: case XD_ERR_SGAL:
! 2337: return ("Scatter/gather address alignment error");
! 2338: case XD_ERR_SGEC:
! 2339: return ("Scatter/gather with auto-ECC");
! 2340: case XD_ERR_SECC:
! 2341: return ("Soft ECC corrected");
! 2342: case XD_ERR_SIGN:
! 2343: return ("ECC ignored");
! 2344: case XD_ERR_ASEK:
! 2345: return ("Auto-seek retry recovered");
! 2346: case XD_ERR_RTRY:
! 2347: return ("Soft retry recovered");
! 2348: case XD_ERR_HECC:
! 2349: return ("Hard data ECC");
! 2350: case XD_ERR_NHDR:
! 2351: return ("Header not found");
! 2352: case XD_ERR_NRDY:
! 2353: return ("Drive not ready");
! 2354: case XD_ERR_TOUT:
! 2355: return ("Operation timeout");
! 2356: case XD_ERR_VTIM:
! 2357: return ("VMEDMA timeout");
! 2358: case XD_ERR_DSEQ:
! 2359: return ("Disk sequencer error");
! 2360: case XD_ERR_HDEC:
! 2361: return ("Header ECC error");
! 2362: case XD_ERR_RVFY:
! 2363: return ("Read verify");
! 2364: case XD_ERR_VFER:
! 2365: return ("Fatal VMEDMA error");
! 2366: case XD_ERR_VBUS:
! 2367: return ("VMEbus error");
! 2368: case XD_ERR_DFLT:
! 2369: return ("Drive faulted");
! 2370: case XD_ERR_HECY:
! 2371: return ("Header error/cylinder");
! 2372: case XD_ERR_HEHD:
! 2373: return ("Header error/head");
! 2374: case XD_ERR_NOCY:
! 2375: return ("Drive not on-cylinder");
! 2376: case XD_ERR_SEEK:
! 2377: return ("Seek error");
! 2378: case XD_ERR_ILSS:
! 2379: return ("Illegal sector size");
! 2380: case XD_ERR_SEC:
! 2381: return ("Soft ECC");
! 2382: case XD_ERR_WPER:
! 2383: return ("Write-protect error");
! 2384: case XD_ERR_IRAM:
! 2385: return ("IRAM self test failure");
! 2386: case XD_ERR_MT3:
! 2387: return ("Maintenance test 3 failure (DSKCEL RAM)");
! 2388: case XD_ERR_MT4:
! 2389: return ("Maintenance test 4 failure (header shift reg)");
! 2390: case XD_ERR_MT5:
! 2391: return ("Maintenance test 5 failure (VMEDMA regs)");
! 2392: case XD_ERR_MT6:
! 2393: return ("Maintenance test 6 failure (REGCEL chip)");
! 2394: case XD_ERR_MT7:
! 2395: return ("Maintenance test 7 failure (buffer parity)");
! 2396: case XD_ERR_MT8:
! 2397: return ("Maintenance test 8 failure (disk FIFO)");
! 2398: case XD_ERR_IOCK:
! 2399: return ("IOPB checksum miscompare");
! 2400: case XD_ERR_IODM:
! 2401: return ("IOPB DMA fatal");
! 2402: case XD_ERR_IOAL:
! 2403: return ("IOPB address alignment error");
! 2404: case XD_ERR_FIRM:
! 2405: return ("Firmware error");
! 2406: case XD_ERR_MMOD:
! 2407: return ("Illegal maintenance mode test number");
! 2408: case XD_ERR_ACFL:
! 2409: return ("ACFAIL asserted");
! 2410: default:
! 2411: return ("Unknown error");
! 2412: }
! 2413: }
CVSweb