Annotation of sys/dev/i2o/iop.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: iop.c,v 1.29 2006/11/29 12:24:17 miod Exp $ */
! 2: /* $NetBSD: iop.c,v 1.12 2001/03/21 14:27:05 ad Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
! 6: * All rights reserved.
! 7: *
! 8: * This code is derived from software contributed to The NetBSD Foundation
! 9: * by Andrew Doran.
! 10: *
! 11: * Redistribution and use in source and binary forms, with or without
! 12: * modification, are permitted provided that the following conditions
! 13: * are met:
! 14: * 1. Redistributions of source code must retain the above copyright
! 15: * notice, this list of conditions and the following disclaimer.
! 16: * 2. Redistributions in binary form must reproduce the above copyright
! 17: * notice, this list of conditions and the following disclaimer in the
! 18: * documentation and/or other materials provided with the distribution.
! 19: * 3. All advertising materials mentioning features or use of this software
! 20: * must display the following acknowledgement:
! 21: * This product includes software developed by the NetBSD
! 22: * Foundation, Inc. and its contributors.
! 23: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 24: * contributors may be used to endorse or promote products derived
! 25: * from this software without specific prior written permission.
! 26: *
! 27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 37: * POSSIBILITY OF SUCH DAMAGE.
! 38: */
! 39:
! 40: /*
! 41: * Support for I2O IOPs (intelligent I/O processors).
! 42: */
! 43:
! 44: #include <sys/param.h>
! 45: #include <sys/systm.h>
! 46: #include <sys/kernel.h>
! 47: #include <sys/device.h>
! 48: #include <sys/queue.h>
! 49: #include <sys/proc.h>
! 50: #include <sys/malloc.h>
! 51: #include <sys/ioctl.h>
! 52: #include <sys/endian.h>
! 53: #include <sys/conf.h>
! 54: #include <sys/kthread.h>
! 55:
! 56: #include <uvm/uvm_extern.h>
! 57:
! 58: #include <machine/bus.h>
! 59:
! 60: #include <dev/i2o/i2o.h>
! 61: #include <dev/i2o/iopio.h>
! 62: #include <dev/i2o/iopreg.h>
! 63: #include <dev/i2o/iopvar.h>
! 64:
! 65: #define POLL(ms, cond) \
! 66: do { \
! 67: int i; \
! 68: for (i = (ms) * 10; i; i--) { \
! 69: if (cond) \
! 70: break; \
! 71: DELAY(100); \
! 72: } \
! 73: } while (/* CONSTCOND */0);
! 74:
! 75: #ifdef I2ODEBUG
! 76: #define DPRINTF(x) printf x
! 77: #else
! 78: #define DPRINTF(x)
! 79: #endif
! 80:
! 81: #ifdef I2OVERBOSE
! 82: #define IFVERBOSE(x) x
! 83: #define COMMENT(x) NULL
! 84: #else
! 85: #define IFVERBOSE(x)
! 86: #define COMMENT(x)
! 87: #endif
! 88:
! 89: #define IOP_ICTXHASH_NBUCKETS 16
! 90: #define IOP_ICTXHASH(ictx) (&iop_ictxhashtbl[(ictx) & iop_ictxhash])
! 91:
! 92: #define IOP_MAX_SEGS (((IOP_MAX_XFER + PAGE_SIZE - 1) / PAGE_SIZE) + 1)
! 93:
! 94: #define IOP_TCTX_SHIFT 12
! 95: #define IOP_TCTX_MASK ((1 << IOP_TCTX_SHIFT) - 1)
! 96:
! 97: LIST_HEAD(, iop_initiator) *iop_ictxhashtbl;
! 98: u_long iop_ictxhash;
! 99: void *iop_sdh;
! 100: struct i2o_systab *iop_systab;
! 101: int iop_systab_size;
! 102:
! 103: struct cfdriver iop_cd = {
! 104: NULL, "iop", DV_DULL
! 105: };
! 106:
! 107: #define IC_CONFIGURE 0x01
! 108: #define IC_PRIORITY 0x02
! 109:
! 110: struct iop_class {
! 111: u_short ic_class;
! 112: u_short ic_flags;
! 113: #ifdef I2OVERBOSE
! 114: const char *ic_caption;
! 115: #endif
! 116: } static const iop_class[] = {
! 117: {
! 118: I2O_CLASS_EXECUTIVE,
! 119: 0,
! 120: COMMENT("executive")
! 121: },
! 122: {
! 123: I2O_CLASS_DDM,
! 124: 0,
! 125: COMMENT("device driver module")
! 126: },
! 127: {
! 128: I2O_CLASS_RANDOM_BLOCK_STORAGE,
! 129: IC_CONFIGURE | IC_PRIORITY,
! 130: IFVERBOSE("random block storage")
! 131: },
! 132: {
! 133: I2O_CLASS_SEQUENTIAL_STORAGE,
! 134: IC_CONFIGURE | IC_PRIORITY,
! 135: IFVERBOSE("sequential storage")
! 136: },
! 137: {
! 138: I2O_CLASS_LAN,
! 139: IC_CONFIGURE | IC_PRIORITY,
! 140: IFVERBOSE("LAN port")
! 141: },
! 142: {
! 143: I2O_CLASS_WAN,
! 144: IC_CONFIGURE | IC_PRIORITY,
! 145: IFVERBOSE("WAN port")
! 146: },
! 147: {
! 148: I2O_CLASS_FIBRE_CHANNEL_PORT,
! 149: IC_CONFIGURE,
! 150: IFVERBOSE("fibrechannel port")
! 151: },
! 152: {
! 153: I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL,
! 154: 0,
! 155: COMMENT("fibrechannel peripheral")
! 156: },
! 157: {
! 158: I2O_CLASS_SCSI_PERIPHERAL,
! 159: 0,
! 160: COMMENT("SCSI peripheral")
! 161: },
! 162: {
! 163: I2O_CLASS_ATE_PORT,
! 164: IC_CONFIGURE,
! 165: IFVERBOSE("ATE port")
! 166: },
! 167: {
! 168: I2O_CLASS_ATE_PERIPHERAL,
! 169: 0,
! 170: COMMENT("ATE peripheral")
! 171: },
! 172: {
! 173: I2O_CLASS_FLOPPY_CONTROLLER,
! 174: IC_CONFIGURE,
! 175: IFVERBOSE("floppy controller")
! 176: },
! 177: {
! 178: I2O_CLASS_FLOPPY_DEVICE,
! 179: 0,
! 180: COMMENT("floppy device")
! 181: },
! 182: {
! 183: I2O_CLASS_BUS_ADAPTER_PORT,
! 184: IC_CONFIGURE,
! 185: IFVERBOSE("bus adapter port" )
! 186: },
! 187: };
! 188:
! 189: #if defined(I2ODEBUG) && defined(I2OVERBOSE)
! 190: static const char * const iop_status[] = {
! 191: "success",
! 192: "abort (dirty)",
! 193: "abort (no data transfer)",
! 194: "abort (partial transfer)",
! 195: "error (dirty)",
! 196: "error (no data transfer)",
! 197: "error (partial transfer)",
! 198: "undefined error code",
! 199: "process abort (dirty)",
! 200: "process abort (no data transfer)",
! 201: "process abort (partial transfer)",
! 202: "transaction error",
! 203: };
! 204: #endif
! 205:
! 206: static inline u_int32_t iop_inl(struct iop_softc *, int);
! 207: static inline void iop_outl(struct iop_softc *, int, u_int32_t);
! 208:
! 209: void iop_config_interrupts(struct device *);
! 210: void iop_configure_devices(struct iop_softc *, int, int);
! 211: void iop_devinfo(int, char *, size_t);
! 212: int iop_print(void *, const char *);
! 213: int iop_reconfigure(struct iop_softc *, u_int);
! 214: void iop_shutdown(void *);
! 215: int iop_submatch(struct device *, void *, void *);
! 216: #ifdef notyet
! 217: int iop_vendor_print(void *, const char *);
! 218: #endif
! 219:
! 220: void iop_adjqparam(struct iop_softc *, int);
! 221: void iop_create_reconf_thread(void *);
! 222: int iop_handle_reply(struct iop_softc *, u_int32_t);
! 223: int iop_hrt_get(struct iop_softc *);
! 224: int iop_hrt_get0(struct iop_softc *, struct i2o_hrt *, size_t);
! 225: void iop_intr_event(struct device *, struct iop_msg *, void *);
! 226: int iop_lct_get0(struct iop_softc *, struct i2o_lct *, size_t, u_int32_t);
! 227: void iop_msg_poll(struct iop_softc *, struct iop_msg *, int);
! 228: void iop_msg_wait(struct iop_softc *, struct iop_msg *, int);
! 229: int iop_ofifo_init(struct iop_softc *);
! 230: int iop_passthrough(struct iop_softc *, struct ioppt *);
! 231: int iop_post(struct iop_softc *, u_int32_t *);
! 232: void iop_reconf_thread(void *);
! 233: void iop_release_mfa(struct iop_softc *, u_int32_t);
! 234: int iop_reset(struct iop_softc *);
! 235: int iop_status_get(struct iop_softc *, int);
! 236: int iop_systab_set(struct iop_softc *);
! 237: void iop_tfn_print(struct iop_softc *, struct i2o_fault_notify *);
! 238:
! 239: #ifdef I2ODEBUG
! 240: void iop_reply_print(struct iop_softc *, struct i2o_reply *);
! 241: #endif
! 242:
! 243: cdev_decl(iop);
! 244:
! 245: static inline u_int32_t
! 246: iop_inl(struct iop_softc *sc, int off)
! 247: {
! 248:
! 249: bus_space_barrier(sc->sc_iot, sc->sc_ioh, off, 4,
! 250: BUS_SPACE_BARRIER_WRITE | BUS_SPACE_BARRIER_READ);
! 251: return (bus_space_read_4(sc->sc_iot, sc->sc_ioh, off));
! 252: }
! 253:
! 254: static inline void
! 255: iop_outl(struct iop_softc *sc, int off, u_int32_t val)
! 256: {
! 257:
! 258: bus_space_write_4(sc->sc_iot, sc->sc_ioh, off, val);
! 259: bus_space_barrier(sc->sc_iot, sc->sc_ioh, off, 4,
! 260: BUS_SPACE_BARRIER_WRITE);
! 261: }
! 262:
! 263: /*
! 264: * Initialise the IOP and our interface.
! 265: */
! 266: void
! 267: iop_init(struct iop_softc *sc, const char *intrstr)
! 268: {
! 269: struct iop_msg *im;
! 270: u_int32_t mask;
! 271: char ident[64];
! 272: int rv, i, nsegs;
! 273: int state = 0;
! 274:
! 275: if (iop_ictxhashtbl == NULL) {
! 276: iop_ictxhashtbl = hashinit(IOP_ICTXHASH_NBUCKETS, M_DEVBUF,
! 277: M_NOWAIT, &iop_ictxhash);
! 278: if (iop_ictxhashtbl == NULL) {
! 279: printf("%s: cannot allocate hashtable\n",
! 280: sc->sc_dv.dv_xname);
! 281: return;
! 282: }
! 283: }
! 284:
! 285: /* Reset the IOP and request status. */
! 286: printf("I2O adapter");
! 287:
! 288: /* Allocate a scratch DMA map for small miscellaneous shared data. */
! 289: if (bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1, PAGE_SIZE, 0,
! 290: BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &sc->sc_scr_dmamap) != 0) {
! 291: printf("%s: cannot create scratch dmamap\n",
! 292: sc->sc_dv.dv_xname);
! 293: return;
! 294: }
! 295: state++;
! 296:
! 297: if (bus_dmamem_alloc(sc->sc_dmat, PAGE_SIZE, PAGE_SIZE, 0,
! 298: sc->sc_scr_seg, 1, &nsegs, BUS_DMA_NOWAIT) != 0) {
! 299: printf("%s: cannot alloc scratch dmamem\n",
! 300: sc->sc_dv.dv_xname);
! 301: goto bail_out;
! 302: }
! 303: state++;
! 304:
! 305: if (bus_dmamem_map(sc->sc_dmat, sc->sc_scr_seg, nsegs, PAGE_SIZE,
! 306: &sc->sc_scr, 0)) {
! 307: printf("%s: cannot map scratch dmamem\n", sc->sc_dv.dv_xname);
! 308: goto bail_out;
! 309: }
! 310: state++;
! 311:
! 312: if (bus_dmamap_load(sc->sc_dmat, sc->sc_scr_dmamap, sc->sc_scr,
! 313: PAGE_SIZE, NULL, BUS_DMA_NOWAIT)) {
! 314: printf("%s: cannot load scratch dmamap\n", sc->sc_dv.dv_xname);
! 315: goto bail_out;
! 316: }
! 317: state++;
! 318:
! 319: if ((rv = iop_reset(sc)) != 0) {
! 320: printf("%s: not responding (reset)\n", sc->sc_dv.dv_xname);
! 321: goto bail_out;
! 322: }
! 323: if ((rv = iop_status_get(sc, 1)) != 0) {
! 324: printf("%s: not responding (get status)\n",
! 325: sc->sc_dv.dv_xname);
! 326: goto bail_out;
! 327: }
! 328: sc->sc_flags |= IOP_HAVESTATUS;
! 329: iop_strvis(sc, sc->sc_status.productid,
! 330: sizeof(sc->sc_status.productid), ident, sizeof(ident));
! 331: printf(" <%s>\n", ident);
! 332:
! 333: #ifdef I2ODEBUG
! 334: printf("%s: orgid=0x%04x version=%d\n", sc->sc_dv.dv_xname,
! 335: letoh16(sc->sc_status.orgid),
! 336: (letoh32(sc->sc_status.segnumber) >> 12) & 15);
! 337: printf("%s: type want have cbase\n", sc->sc_dv.dv_xname);
! 338: printf("%s: mem %04x %04x %08x\n", sc->sc_dv.dv_xname,
! 339: letoh32(sc->sc_status.desiredprivmemsize),
! 340: letoh32(sc->sc_status.currentprivmemsize),
! 341: letoh32(sc->sc_status.currentprivmembase));
! 342: printf("%s: i/o %04x %04x %08x\n", sc->sc_dv.dv_xname,
! 343: letoh32(sc->sc_status.desiredpriviosize),
! 344: letoh32(sc->sc_status.currentpriviosize),
! 345: letoh32(sc->sc_status.currentpriviobase));
! 346: #endif
! 347:
! 348: sc->sc_maxob = letoh32(sc->sc_status.maxoutboundmframes);
! 349: if (sc->sc_maxob > IOP_MAX_OUTBOUND)
! 350: sc->sc_maxob = IOP_MAX_OUTBOUND;
! 351: sc->sc_maxib = letoh32(sc->sc_status.maxinboundmframes);
! 352: if (sc->sc_maxib > IOP_MAX_INBOUND)
! 353: sc->sc_maxib = IOP_MAX_INBOUND;
! 354:
! 355: /* Allocate message wrappers. */
! 356: im = malloc(sizeof(*im) * sc->sc_maxib, M_DEVBUF, M_NOWAIT);
! 357: if (!im) {
! 358: printf("%s: couldn't allocate message", sc->sc_dv.dv_xname);
! 359: goto bail_out;
! 360: }
! 361: state++;
! 362:
! 363: bzero(im, sizeof(*im) * sc->sc_maxib);
! 364: sc->sc_ims = im;
! 365: SLIST_INIT(&sc->sc_im_freelist);
! 366:
! 367: for (i = 0; i < sc->sc_maxib; i++, im++) {
! 368: rv = bus_dmamap_create(sc->sc_dmat, IOP_MAX_XFER,
! 369: IOP_MAX_SEGS, IOP_MAX_XFER, 0,
! 370: BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
! 371: &im->im_xfer[0].ix_map);
! 372: if (rv != 0) {
! 373: printf("%s: couldn't create dmamap (%d)",
! 374: sc->sc_dv.dv_xname, rv);
! 375: goto bail_out;
! 376: }
! 377:
! 378: im->im_tctx = i;
! 379: SLIST_INSERT_HEAD(&sc->sc_im_freelist, im, im_chain);
! 380: }
! 381:
! 382: /* Initalise the IOP's outbound FIFO. */
! 383: if (iop_ofifo_init(sc) != 0) {
! 384: printf("%s: unable to init outbound FIFO\n",
! 385: sc->sc_dv.dv_xname);
! 386: goto bail_out;
! 387: }
! 388:
! 389: /* Configure shutdown hook before we start any device activity. */
! 390: if (iop_sdh == NULL)
! 391: iop_sdh = shutdownhook_establish(iop_shutdown, NULL);
! 392:
! 393: /* Ensure interrupts are enabled at the IOP. */
! 394: mask = iop_inl(sc, IOP_REG_INTR_MASK);
! 395: iop_outl(sc, IOP_REG_INTR_MASK, mask & ~IOP_INTR_OFIFO);
! 396:
! 397: if (intrstr != NULL)
! 398: printf("%s: interrupting at %s\n", sc->sc_dv.dv_xname,
! 399: intrstr);
! 400:
! 401: #ifdef I2ODEBUG
! 402: printf("%s: queue depths: inbound %d/%d, outbound %d/%d\n",
! 403: sc->sc_dv.dv_xname, sc->sc_maxib,
! 404: letoh32(sc->sc_status.maxinboundmframes),
! 405: sc->sc_maxob, letoh32(sc->sc_status.maxoutboundmframes));
! 406: #endif
! 407:
! 408: lockinit(&sc->sc_conflock, PRIBIO, "iopconf", 0, 0);
! 409:
! 410: startuphook_establish((void (*)(void *))iop_config_interrupts, sc);
! 411: return;
! 412:
! 413: bail_out:
! 414: if (state > 4)
! 415: free(im, M_DEVBUF);
! 416: if (state > 3)
! 417: bus_dmamap_unload(sc->sc_dmat, sc->sc_scr_dmamap);
! 418: if (state > 2)
! 419: bus_dmamem_unmap(sc->sc_dmat, sc->sc_scr, PAGE_SIZE);
! 420: if (state > 1)
! 421: bus_dmamem_free(sc->sc_dmat, sc->sc_scr_seg, nsegs);
! 422: if (state > 0)
! 423: bus_dmamap_destroy(sc->sc_dmat, sc->sc_scr_dmamap);
! 424: }
! 425:
! 426: /*
! 427: * Perform autoconfiguration tasks.
! 428: */
! 429: void
! 430: iop_config_interrupts(struct device *self)
! 431: {
! 432: struct iop_softc *sc, *iop;
! 433: struct i2o_systab_entry *ste;
! 434: int rv, i, niop;
! 435:
! 436: sc = (struct iop_softc *)self;
! 437: LIST_INIT(&sc->sc_iilist);
! 438:
! 439: printf("%s: configuring...\n", sc->sc_dv.dv_xname);
! 440:
! 441: if (iop_hrt_get(sc) != 0) {
! 442: printf("%s: unable to retrieve HRT\n", sc->sc_dv.dv_xname);
! 443: return;
! 444: }
! 445:
! 446: /*
! 447: * Build the system table.
! 448: */
! 449: if (iop_systab == NULL) {
! 450: for (i = 0, niop = 0; i < iop_cd.cd_ndevs; i++) {
! 451: iop = (struct iop_softc *)device_lookup(&iop_cd, i);
! 452: if (iop == NULL)
! 453: continue;
! 454: if ((iop->sc_flags & IOP_HAVESTATUS) == 0)
! 455: continue;
! 456: if (iop_status_get(iop, 1) != 0) {
! 457: printf("%s: unable to retrieve status\n",
! 458: sc->sc_dv.dv_xname);
! 459: iop->sc_flags &= ~IOP_HAVESTATUS;
! 460: continue;
! 461: }
! 462: niop++;
! 463: }
! 464: if (niop == 0)
! 465: return;
! 466:
! 467: i = sizeof(struct i2o_systab_entry) * (niop - 1) +
! 468: sizeof(struct i2o_systab);
! 469: iop_systab_size = i;
! 470: iop_systab = malloc(i, M_DEVBUF, M_NOWAIT);
! 471: if (!iop_systab)
! 472: return;
! 473:
! 474: bzero(iop_systab, i);
! 475: iop_systab->numentries = niop;
! 476: iop_systab->version = I2O_VERSION_11;
! 477:
! 478: for (i = 0, ste = iop_systab->entry; i < iop_cd.cd_ndevs; i++)
! 479: {
! 480: iop = (struct iop_softc *)device_lookup(&iop_cd, i);
! 481: if (iop == NULL)
! 482: continue;
! 483: if ((iop->sc_flags & IOP_HAVESTATUS) == 0)
! 484: continue;
! 485:
! 486: ste->orgid = iop->sc_status.orgid;
! 487: ste->iopid = iop->sc_dv.dv_unit + 2;
! 488: ste->segnumber =
! 489: htole32(letoh32(iop->sc_status.segnumber) & ~4095);
! 490: ste->iopcaps = iop->sc_status.iopcaps;
! 491: ste->inboundmsgframesize =
! 492: iop->sc_status.inboundmframesize;
! 493: ste->inboundmsgportaddresslow =
! 494: htole32(iop->sc_memaddr + IOP_REG_IFIFO);
! 495: ste++;
! 496: }
! 497: }
! 498:
! 499: /*
! 500: * Post the system table to the IOP and bring it to the OPERATIONAL
! 501: * state.
! 502: */
! 503: if (iop_systab_set(sc) != 0) {
! 504: printf("%s: unable to set system table\n", sc->sc_dv.dv_xname);
! 505: return;
! 506: }
! 507: if (iop_simple_cmd(sc, I2O_TID_IOP, I2O_EXEC_SYS_ENABLE, IOP_ICTX, 1,
! 508: 30000) != 0) {
! 509: printf("%s: unable to enable system\n", sc->sc_dv.dv_xname);
! 510: return;
! 511: }
! 512:
! 513: /*
! 514: * Set up an event handler for this IOP.
! 515: */
! 516: sc->sc_eventii.ii_dv = self;
! 517: sc->sc_eventii.ii_intr = iop_intr_event;
! 518: sc->sc_eventii.ii_flags = II_DISCARD | II_UTILITY;
! 519: sc->sc_eventii.ii_tid = I2O_TID_IOP;
! 520: iop_initiator_register(sc, &sc->sc_eventii);
! 521:
! 522: rv = iop_util_eventreg(sc, &sc->sc_eventii,
! 523: I2O_EVENT_EXEC_RESOURCE_LIMITS |
! 524: I2O_EVENT_EXEC_CONNECTION_FAIL |
! 525: I2O_EVENT_EXEC_ADAPTER_FAULT |
! 526: I2O_EVENT_EXEC_POWER_FAIL |
! 527: I2O_EVENT_EXEC_RESET_PENDING |
! 528: I2O_EVENT_EXEC_RESET_IMMINENT |
! 529: I2O_EVENT_EXEC_HARDWARE_FAIL |
! 530: I2O_EVENT_EXEC_XCT_CHANGE |
! 531: I2O_EVENT_EXEC_DDM_AVAILIBILITY |
! 532: I2O_EVENT_GEN_DEVICE_RESET |
! 533: I2O_EVENT_GEN_STATE_CHANGE |
! 534: I2O_EVENT_GEN_GENERAL_WARNING);
! 535: if (rv != 0) {
! 536: printf("%s: unable to register for events",
! 537: sc->sc_dv.dv_xname);
! 538: return;
! 539: }
! 540:
! 541: #ifdef notyet
! 542: /* Attempt to match and attach a product-specific extension. */
! 543: ia.ia_class = I2O_CLASS_ANY;
! 544: ia.ia_tid = I2O_TID_IOP;
! 545: config_found_sm(self, &ia, iop_vendor_print, iop_submatch);
! 546: #endif
! 547:
! 548: lockmgr(&sc->sc_conflock, LK_EXCLUSIVE, NULL);
! 549: if ((rv = iop_reconfigure(sc, 0)) == -1) {
! 550: printf("%s: configure failed (%d)\n", sc->sc_dv.dv_xname, rv);
! 551: return;
! 552: }
! 553: lockmgr(&sc->sc_conflock, LK_RELEASE, NULL);
! 554: kthread_create_deferred(iop_create_reconf_thread, sc);
! 555: }
! 556:
! 557: /*
! 558: * Create the reconfiguration thread. Called after the standard kernel
! 559: * threads have been created.
! 560: */
! 561: void
! 562: iop_create_reconf_thread(void *cookie)
! 563: {
! 564: struct iop_softc *sc;
! 565: int rv;
! 566:
! 567: sc = cookie;
! 568: sc->sc_flags |= IOP_ONLINE;
! 569:
! 570: rv = kthread_create(iop_reconf_thread, sc, &sc->sc_reconf_proc,
! 571: "%s", sc->sc_dv.dv_xname);
! 572: if (rv != 0) {
! 573: printf("%s: unable to create reconfiguration thread (%d)",
! 574: sc->sc_dv.dv_xname, rv);
! 575: return;
! 576: }
! 577: }
! 578:
! 579: /*
! 580: * Reconfiguration thread; listens for LCT change notification, and
! 581: * initiates re-configuration if received.
! 582: */
! 583: void
! 584: iop_reconf_thread(void *cookie)
! 585: {
! 586: struct iop_softc *sc = cookie;
! 587: struct i2o_lct lct;
! 588: u_int32_t chgind;
! 589: int rv;
! 590:
! 591: chgind = sc->sc_chgind + 1;
! 592:
! 593: for (;;) {
! 594: DPRINTF(("%s: async reconfig: requested 0x%08x\n",
! 595: sc->sc_dv.dv_xname, chgind));
! 596:
! 597: rv = iop_lct_get0(sc, &lct, sizeof(lct), chgind);
! 598:
! 599: DPRINTF(("%s: async reconfig: notified (0x%08x, %d)\n",
! 600: sc->sc_dv.dv_xname, letoh32(lct.changeindicator), rv));
! 601:
! 602: if (rv == 0 &&
! 603: lockmgr(&sc->sc_conflock, LK_EXCLUSIVE, NULL) == 0) {
! 604: iop_reconfigure(sc, letoh32(lct.changeindicator));
! 605: chgind = sc->sc_chgind + 1;
! 606: lockmgr(&sc->sc_conflock, LK_RELEASE, NULL);
! 607: }
! 608:
! 609: tsleep(iop_reconf_thread, PWAIT, "iopzzz", hz * 5);
! 610: }
! 611: }
! 612:
! 613: /*
! 614: * Reconfigure: find new and removed devices.
! 615: */
! 616: int
! 617: iop_reconfigure(struct iop_softc *sc, u_int chgind)
! 618: {
! 619: struct iop_msg *im;
! 620: struct i2o_hba_bus_scan mf;
! 621: struct i2o_lct_entry *le;
! 622: struct iop_initiator *ii, *nextii;
! 623: int rv, tid, i;
! 624:
! 625: /*
! 626: * If the reconfiguration request isn't the result of LCT change
! 627: * notification, then be more thorough: ask all bus ports to scan
! 628: * their busses. Wait up to 5 minutes for each bus port to complete
! 629: * the request.
! 630: */
! 631: if (chgind == 0) {
! 632: if ((rv = iop_lct_get(sc)) != 0) {
! 633: DPRINTF(("iop_reconfigure: unable to read LCT\n"));
! 634: return (rv);
! 635: }
! 636:
! 637: le = sc->sc_lct->entry;
! 638: for (i = 0; i < sc->sc_nlctent; i++, le++) {
! 639: if ((letoh16(le->classid) & I2O_CLASS_MASK) !=
! 640: I2O_CLASS_BUS_ADAPTER_PORT)
! 641: continue;
! 642: tid = letoh16(le->localtid) & I2O_CLASS_MASK;
! 643:
! 644: im = iop_msg_alloc(sc, NULL, IM_WAIT);
! 645:
! 646: mf.msgflags = I2O_MSGFLAGS(i2o_hba_bus_scan);
! 647: mf.msgfunc = I2O_MSGFUNC(tid, I2O_HBA_BUS_SCAN);
! 648: mf.msgictx = IOP_ICTX;
! 649: mf.msgtctx = im->im_tctx;
! 650:
! 651: DPRINTF(("%s: scanning bus %d\n", sc->sc_dv.dv_xname,
! 652: tid));
! 653:
! 654: rv = iop_msg_post(sc, im, &mf, 5*60*1000);
! 655: iop_msg_free(sc, im);
! 656: #ifdef I2ODEBUG
! 657: if (rv != 0)
! 658: printf("%s: bus scan failed, status =%d\n",
! 659: sc->sc_dv.dv_xname, rv);
! 660: #endif
! 661: }
! 662: } else if (chgind <= sc->sc_chgind) {
! 663: DPRINTF(("%s: LCT unchanged (async)\n", sc->sc_dv.dv_xname));
! 664: return (0);
! 665: }
! 666:
! 667: /* Re-read the LCT and determine if it has changed. */
! 668: if ((rv = iop_lct_get(sc)) != 0) {
! 669: DPRINTF(("iop_reconfigure: unable to re-read LCT\n"));
! 670: return (rv);
! 671: }
! 672: DPRINTF(("%s: %d LCT entries\n", sc->sc_dv.dv_xname, sc->sc_nlctent));
! 673:
! 674: chgind = letoh32(sc->sc_lct->changeindicator);
! 675: if (chgind == sc->sc_chgind) {
! 676: DPRINTF(("%s: LCT unchanged\n", sc->sc_dv.dv_xname));
! 677: return (0);
! 678: }
! 679: DPRINTF(("%s: LCT changed\n", sc->sc_dv.dv_xname));
! 680: sc->sc_chgind = chgind;
! 681:
! 682: if (sc->sc_tidmap != NULL)
! 683: free(sc->sc_tidmap, M_DEVBUF);
! 684: sc->sc_tidmap = malloc(sc->sc_nlctent * sizeof(struct iop_tidmap),
! 685: M_DEVBUF, M_NOWAIT);
! 686: if (!sc->sc_tidmap) {
! 687: DPRINTF(("iop_reconfigure: out of memory\n"));
! 688: return (ENOMEM);
! 689: }
! 690: bzero(sc->sc_tidmap, sc->sc_nlctent * sizeof(struct iop_tidmap));
! 691:
! 692: /* Allow 1 queued command per device while we're configuring. */
! 693: iop_adjqparam(sc, 1);
! 694:
! 695: /*
! 696: * Match and attach child devices. We configure high-level devices
! 697: * first so that any claims will propagate throughout the LCT,
! 698: * hopefully masking off aliased devices as a result.
! 699: *
! 700: * Re-reading the LCT at this point is a little dangerous, but we'll
! 701: * trust the IOP (and the operator) to behave itself...
! 702: */
! 703: iop_configure_devices(sc, IC_CONFIGURE | IC_PRIORITY,
! 704: IC_CONFIGURE | IC_PRIORITY);
! 705: if ((rv = iop_lct_get(sc)) != 0)
! 706: DPRINTF(("iop_reconfigure: unable to re-read LCT\n"));
! 707: iop_configure_devices(sc, IC_CONFIGURE | IC_PRIORITY,
! 708: IC_CONFIGURE);
! 709:
! 710: for (ii = LIST_FIRST(&sc->sc_iilist); ii != NULL; ii = nextii) {
! 711: nextii = LIST_NEXT(ii, ii_list);
! 712:
! 713: /* Detach devices that were configured, but are now gone. */
! 714: for (i = 0; i < sc->sc_nlctent; i++)
! 715: if (ii->ii_tid == sc->sc_tidmap[i].it_tid)
! 716: break;
! 717: if (i == sc->sc_nlctent ||
! 718: (sc->sc_tidmap[i].it_flags & IT_CONFIGURED) == 0)
! 719: config_detach(ii->ii_dv, DETACH_FORCE);
! 720:
! 721: /*
! 722: * Tell initiators that existed before the re-configuration
! 723: * to re-configure.
! 724: */
! 725: if (ii->ii_reconfig == NULL)
! 726: continue;
! 727: if ((rv = (*ii->ii_reconfig)(ii->ii_dv)) != 0)
! 728: printf("%s: %s failed reconfigure (%d)\n",
! 729: sc->sc_dv.dv_xname, ii->ii_dv->dv_xname, rv);
! 730: }
! 731:
! 732: /* Re-adjust queue parameters and return. */
! 733: if (sc->sc_nii != 0)
! 734: iop_adjqparam(sc, (sc->sc_maxib - sc->sc_nuii - IOP_MF_RESERVE)
! 735: / sc->sc_nii);
! 736:
! 737: return (0);
! 738: }
! 739:
! 740: /*
! 741: * Configure I2O devices into the system.
! 742: */
! 743: void
! 744: iop_configure_devices(struct iop_softc *sc, int mask, int maskval)
! 745: {
! 746: struct iop_attach_args ia;
! 747: struct iop_initiator *ii;
! 748: const struct i2o_lct_entry *le;
! 749: struct device *dv;
! 750: int i, j, nent;
! 751: u_int usertid;
! 752:
! 753: nent = sc->sc_nlctent;
! 754: for (i = 0, le = sc->sc_lct->entry; i < nent; i++, le++) {
! 755: sc->sc_tidmap[i].it_tid =
! 756: letoh16(le->localtid) & I2O_LCT_ENTRY_TID_MASK;
! 757:
! 758: /* Ignore the device if it's in use. */
! 759: usertid = letoh32(le->usertid) & I2O_LCT_ENTRY_TID_MASK;
! 760: if (usertid != I2O_TID_NONE && usertid != I2O_TID_HOST)
! 761: continue;
! 762:
! 763: ia.ia_class = letoh16(le->classid) & I2O_CLASS_MASK;
! 764: ia.ia_tid = sc->sc_tidmap[i].it_tid;
! 765:
! 766: /* Ignore uninteresting devices. */
! 767: for (j = 0; j < sizeof(iop_class) / sizeof(iop_class[0]); j++)
! 768: if (iop_class[j].ic_class == ia.ia_class)
! 769: break;
! 770: if (j < sizeof(iop_class) / sizeof(iop_class[0]) &&
! 771: (iop_class[j].ic_flags & mask) != maskval)
! 772: continue;
! 773:
! 774: /*
! 775: * Try to configure the device only if it's not already
! 776: * configured.
! 777: */
! 778: LIST_FOREACH(ii, &sc->sc_iilist, ii_list) {
! 779: if (ia.ia_tid == ii->ii_tid) {
! 780: sc->sc_tidmap[i].it_flags |= IT_CONFIGURED;
! 781: strlcpy(sc->sc_tidmap[i].it_dvname,
! 782: ii->ii_dv->dv_xname,
! 783: sizeof sc->sc_tidmap[i].it_dvname);
! 784: break;
! 785: }
! 786: }
! 787: if (ii != NULL)
! 788: continue;
! 789: dv = config_found_sm(&sc->sc_dv, &ia, iop_print, iop_submatch);
! 790: if (dv != NULL) {
! 791: sc->sc_tidmap[i].it_flags |= IT_CONFIGURED;
! 792: strlcpy(sc->sc_tidmap[i].it_dvname, dv->dv_xname,
! 793: sizeof sc->sc_tidmap[i].it_dvname);
! 794: }
! 795: }
! 796: }
! 797:
! 798: /*
! 799: * Adjust queue parameters for all child devices.
! 800: */
! 801: void
! 802: iop_adjqparam(struct iop_softc *sc, int mpi)
! 803: {
! 804: struct iop_initiator *ii;
! 805:
! 806: LIST_FOREACH(ii, &sc->sc_iilist, ii_list)
! 807: if (ii->ii_adjqparam != NULL)
! 808: (*ii->ii_adjqparam)(ii->ii_dv, mpi);
! 809: }
! 810:
! 811: void
! 812: iop_devinfo(int class, char *devinfo, size_t di_len)
! 813: {
! 814: #ifdef I2OVERBOSE
! 815: int i;
! 816:
! 817: for (i = 0; i < sizeof(iop_class) / sizeof(iop_class[0]); i++)
! 818: if (class == iop_class[i].ic_class)
! 819: break;
! 820:
! 821: if (i == sizeof(iop_class) / sizeof(iop_class[0]))
! 822: snprintf(devinfo, di_len, "device (class 0x%x)", class);
! 823: else
! 824: strlcpy(devinfo, iop_class[i].ic_caption, di_len);
! 825: #else
! 826:
! 827: snprintf(devinfo, di_len, "device (class 0x%x)", class);
! 828: #endif
! 829: }
! 830:
! 831: int
! 832: iop_print(void *aux, const char *pnp)
! 833: {
! 834: struct iop_attach_args *ia;
! 835: char devinfo[256];
! 836:
! 837: ia = aux;
! 838:
! 839: if (pnp != NULL) {
! 840: iop_devinfo(ia->ia_class, devinfo, sizeof devinfo);
! 841: printf("%s at %s", devinfo, pnp);
! 842: }
! 843: printf(" tid %d", ia->ia_tid);
! 844: return (UNCONF);
! 845: }
! 846:
! 847: #ifdef notyet
! 848: int
! 849: iop_vendor_print(void *aux, const char *pnp)
! 850: {
! 851:
! 852: if (pnp != NULL)
! 853: printf("vendor specific extension at %s", pnp);
! 854: return (UNCONF);
! 855: }
! 856: #endif
! 857:
! 858: int
! 859: iop_submatch(struct device *parent, void *vcf, void *aux)
! 860: {
! 861: struct cfdata *cf = vcf;
! 862: struct iop_attach_args *ia;
! 863:
! 864: ia = aux;
! 865:
! 866: if (cf->iopcf_tid != IOPCF_TID_DEFAULT && cf->iopcf_tid != ia->ia_tid)
! 867: return (0);
! 868:
! 869: return ((*cf->cf_attach->ca_match)(parent, cf, aux));
! 870: }
! 871:
! 872: /*
! 873: * Shut down all configured IOPs.
! 874: */
! 875: void
! 876: iop_shutdown(void *junk)
! 877: {
! 878: struct iop_softc *sc;
! 879: int i;
! 880:
! 881: printf("shutting down iop devices...");
! 882:
! 883: for (i = 0; i < iop_cd.cd_ndevs; i++) {
! 884: if (!(sc = (struct iop_softc *)device_lookup(&iop_cd, i)))
! 885: continue;
! 886: if ((sc->sc_flags & IOP_ONLINE) == 0)
! 887: continue;
! 888:
! 889: iop_simple_cmd(sc, I2O_TID_IOP, I2O_EXEC_SYS_QUIESCE, IOP_ICTX,
! 890: 0, 5000);
! 891:
! 892: if (letoh16(sc->sc_status.orgid) != I2O_ORG_AMI) {
! 893: /*
! 894: * Some AMI firmware revisions will go to sleep and
! 895: * never come back after this.
! 896: */
! 897: iop_simple_cmd(sc, I2O_TID_IOP, I2O_EXEC_IOP_CLEAR,
! 898: IOP_ICTX, 0, 1000);
! 899: }
! 900: }
! 901:
! 902: /* Wait. Some boards could still be flushing, stupidly enough. */
! 903: delay(5000*1000);
! 904: printf(" done.\n");
! 905: }
! 906:
! 907: /*
! 908: * Retrieve IOP status.
! 909: */
! 910: int
! 911: iop_status_get(struct iop_softc *sc, int nosleep)
! 912: {
! 913: struct i2o_exec_status_get mf;
! 914: paddr_t pa = sc->sc_scr_seg->ds_addr;
! 915: struct i2o_status *st = (struct i2o_status *)sc->sc_scr;
! 916: int rv;
! 917:
! 918: mf.msgflags = I2O_MSGFLAGS(i2o_exec_status_get);
! 919: mf.msgfunc = I2O_MSGFUNC(I2O_TID_IOP, I2O_EXEC_STATUS_GET);
! 920: mf.reserved[0] = 0;
! 921: mf.reserved[1] = 0;
! 922: mf.reserved[2] = 0;
! 923: mf.reserved[3] = 0;
! 924: mf.addrlow = pa & ~(u_int32_t)0;
! 925: mf.addrhigh = sizeof pa > sizeof mf.addrlow ? pa >> 32 : 0;
! 926: mf.length = sizeof(*st);
! 927:
! 928: bzero(st, sizeof(*st));
! 929: bus_dmamap_sync(sc->sc_dmat, sc->sc_scr_dmamap, 0, sizeof(*st),
! 930: BUS_DMASYNC_PREREAD);
! 931:
! 932: if ((rv = iop_post(sc, (u_int32_t *)&mf)))
! 933: return (rv);
! 934:
! 935: /* XXX */
! 936: POLL(2500,
! 937: (bus_dmamap_sync(sc->sc_dmat, sc->sc_scr_dmamap, 0,
! 938: sizeof(*st), BUS_DMASYNC_POSTREAD), st->syncbyte == 0xff));
! 939:
! 940: if (st->syncbyte != 0xff)
! 941: return (EIO);
! 942:
! 943: bcopy(st, &sc->sc_status, sizeof(sc->sc_status));
! 944: return (0);
! 945: }
! 946:
! 947: /*
! 948: * Initalize and populate the IOP's outbound FIFO.
! 949: */
! 950: int
! 951: iop_ofifo_init(struct iop_softc *sc)
! 952: {
! 953: bus_addr_t addr;
! 954: bus_dma_segment_t seg;
! 955: struct i2o_exec_outbound_init *mf;
! 956: u_int32_t mb[IOP_MAX_MSG_SIZE / sizeof(u_int32_t)];
! 957: u_int32_t *sw = (u_int32_t *)sc->sc_scr;
! 958: int i, rseg, rv;
! 959:
! 960: mf = (struct i2o_exec_outbound_init *)mb;
! 961: mf->msgflags = I2O_MSGFLAGS(i2o_exec_outbound_init);
! 962: mf->msgfunc = I2O_MSGFUNC(I2O_TID_IOP, I2O_EXEC_OUTBOUND_INIT);
! 963: mf->msgictx = IOP_ICTX;
! 964: mf->msgtctx = 0;
! 965: mf->pagesize = PAGE_SIZE;
! 966: mf->flags = IOP_INIT_CODE | ((IOP_MAX_MSG_SIZE >> 2) << 16);
! 967: mb[sizeof(*mf) / sizeof(u_int32_t) + 0] = sizeof(*sw) |
! 968: I2O_SGL_SIMPLE | I2O_SGL_END_BUFFER | I2O_SGL_END;
! 969: mb[sizeof(*mf) / sizeof(u_int32_t) + 1] = sc->sc_scr_seg->ds_addr;
! 970: mb[0] += 2 << 16;
! 971:
! 972: *sw = 0;
! 973: bus_dmamap_sync(sc->sc_dmat, sc->sc_scr_dmamap, 0, sizeof(*sw),
! 974: BUS_DMASYNC_PREREAD);
! 975:
! 976: /*
! 977: * The I2O spec says that there are two SGLs: one for the status
! 978: * word, and one for a list of discarded MFAs. It continues to say
! 979: * that if you don't want to get the list of MFAs, an IGNORE SGL is
! 980: * necessary; this isn't the case (and is in fact a bad thing).
! 981: */
! 982: if ((rv = iop_post(sc, mb)))
! 983: return (rv);
! 984:
! 985: /* XXX */
! 986: POLL(5000,
! 987: (bus_dmamap_sync(sc->sc_dmat, sc->sc_scr_dmamap, 0, sizeof(*sw),
! 988: BUS_DMASYNC_POSTREAD),
! 989: *sw == htole32(I2O_EXEC_OUTBOUND_INIT_COMPLETE)));
! 990: if (*sw != htole32(I2O_EXEC_OUTBOUND_INIT_COMPLETE)) {
! 991: printf("%s: outbound FIFO init failed (%d)\n",
! 992: sc->sc_dv.dv_xname, letoh32(*sw));
! 993: return (EIO);
! 994: }
! 995:
! 996: /* Allocate DMA safe memory for the reply frames. */
! 997: if (sc->sc_rep_phys == 0) {
! 998: sc->sc_rep_size = sc->sc_maxob * IOP_MAX_MSG_SIZE;
! 999:
! 1000: rv = bus_dmamem_alloc(sc->sc_dmat, sc->sc_rep_size, PAGE_SIZE,
! 1001: 0, &seg, 1, &rseg, BUS_DMA_NOWAIT);
! 1002: if (rv != 0) {
! 1003: printf("%s: dma alloc = %d\n", sc->sc_dv.dv_xname,
! 1004: rv);
! 1005: return (rv);
! 1006: }
! 1007:
! 1008: rv = bus_dmamem_map(sc->sc_dmat, &seg, rseg, sc->sc_rep_size,
! 1009: &sc->sc_rep, BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
! 1010: if (rv != 0) {
! 1011: printf("%s: dma map = %d\n", sc->sc_dv.dv_xname, rv);
! 1012: return (rv);
! 1013: }
! 1014:
! 1015: rv = bus_dmamap_create(sc->sc_dmat, sc->sc_rep_size, 1,
! 1016: sc->sc_rep_size, 0, BUS_DMA_NOWAIT, &sc->sc_rep_dmamap);
! 1017: if (rv != 0) {
! 1018: printf("%s: dma create = %d\n", sc->sc_dv.dv_xname,
! 1019: rv);
! 1020: return (rv);
! 1021: }
! 1022:
! 1023: rv = bus_dmamap_load(sc->sc_dmat, sc->sc_rep_dmamap,
! 1024: sc->sc_rep, sc->sc_rep_size, NULL, BUS_DMA_NOWAIT);
! 1025: if (rv != 0) {
! 1026: printf("%s: dma load = %d\n", sc->sc_dv.dv_xname, rv);
! 1027: return (rv);
! 1028: }
! 1029:
! 1030: sc->sc_rep_phys = sc->sc_rep_dmamap->dm_segs[0].ds_addr;
! 1031: }
! 1032:
! 1033: /* Populate the outbound FIFO. */
! 1034: for (i = sc->sc_maxob, addr = sc->sc_rep_phys; i != 0; i--) {
! 1035: iop_outl(sc, IOP_REG_OFIFO, (u_int32_t)addr);
! 1036: addr += IOP_MAX_MSG_SIZE;
! 1037: }
! 1038:
! 1039: return (0);
! 1040: }
! 1041:
! 1042: /*
! 1043: * Read the specified number of bytes from the IOP's hardware resource table.
! 1044: */
! 1045: int
! 1046: iop_hrt_get0(struct iop_softc *sc, struct i2o_hrt *hrt, size_t size)
! 1047: {
! 1048: struct iop_msg *im;
! 1049: struct i2o_exec_hrt_get *mf;
! 1050: u_int32_t mb[IOP_MAX_MSG_SIZE / sizeof(u_int32_t)];
! 1051: int rv;
! 1052:
! 1053: im = iop_msg_alloc(sc, NULL, IM_WAIT);
! 1054: mf = (struct i2o_exec_hrt_get *)mb;
! 1055: mf->msgflags = I2O_MSGFLAGS(i2o_exec_hrt_get);
! 1056: mf->msgfunc = I2O_MSGFUNC(I2O_TID_IOP, I2O_EXEC_HRT_GET);
! 1057: mf->msgictx = IOP_ICTX;
! 1058: mf->msgtctx = im->im_tctx;
! 1059:
! 1060: iop_msg_map(sc, im, mb, hrt, size, 0);
! 1061: rv = iop_msg_post(sc, im, mb, 30000);
! 1062: iop_msg_unmap(sc, im);
! 1063: iop_msg_free(sc, im);
! 1064: return (rv);
! 1065: }
! 1066:
! 1067: /*
! 1068: * Read the IOP's hardware resource table.
! 1069: */
! 1070: int
! 1071: iop_hrt_get(struct iop_softc *sc)
! 1072: {
! 1073: struct i2o_hrt hrthdr, *hrt;
! 1074: size_t size;
! 1075: int rv;
! 1076:
! 1077: rv = iop_hrt_get0(sc, &hrthdr, sizeof(hrthdr));
! 1078: if (rv != 0)
! 1079: return (rv);
! 1080:
! 1081: DPRINTF(("%s: %d hrt entries\n", sc->sc_dv.dv_xname,
! 1082: letoh16(hrthdr.numentries)));
! 1083:
! 1084: size = sizeof(struct i2o_hrt) +
! 1085: (letoh16(hrthdr.numentries) - 1) * sizeof(struct i2o_hrt_entry);
! 1086: hrt = (struct i2o_hrt *)malloc(size, M_DEVBUF, M_NOWAIT);
! 1087: if (!hrt)
! 1088: return (ENOMEM);
! 1089:
! 1090: if ((rv = iop_hrt_get0(sc, hrt, size)) != 0) {
! 1091: free(hrt, M_DEVBUF);
! 1092: return (rv);
! 1093: }
! 1094:
! 1095: if (sc->sc_hrt != NULL)
! 1096: free(sc->sc_hrt, M_DEVBUF);
! 1097: sc->sc_hrt = hrt;
! 1098: return (0);
! 1099: }
! 1100:
! 1101: /*
! 1102: * Request the specified number of bytes from the IOP's logical
! 1103: * configuration table. If a change indicator is specified, this
! 1104: * is a verbatim notification request, so the caller is prepared
! 1105: * to wait indefinitely.
! 1106: */
! 1107: int
! 1108: iop_lct_get0(struct iop_softc *sc, struct i2o_lct *lct, size_t size,
! 1109: u_int32_t chgind)
! 1110: {
! 1111: struct iop_msg *im;
! 1112: struct i2o_exec_lct_notify *mf;
! 1113: int rv;
! 1114: u_int32_t mb[IOP_MAX_MSG_SIZE / sizeof(u_int32_t)];
! 1115:
! 1116: im = iop_msg_alloc(sc, NULL, IM_WAIT);
! 1117: memset(lct, 0, size);
! 1118:
! 1119: mf = (struct i2o_exec_lct_notify *)mb;
! 1120: mf->msgflags = I2O_MSGFLAGS(i2o_exec_lct_notify);
! 1121: mf->msgfunc = I2O_MSGFUNC(I2O_TID_IOP, I2O_EXEC_LCT_NOTIFY);
! 1122: mf->msgictx = IOP_ICTX;
! 1123: mf->msgtctx = im->im_tctx;
! 1124: mf->classid = I2O_CLASS_ANY;
! 1125: mf->changeindicator = chgind;
! 1126:
! 1127: #ifdef I2ODEBUG
! 1128: printf("iop_lct_get0: reading LCT");
! 1129: if (chgind != 0)
! 1130: printf(" (async)");
! 1131: printf("\n");
! 1132: #endif
! 1133:
! 1134: iop_msg_map(sc, im, mb, lct, size, 0);
! 1135: rv = iop_msg_post(sc, im, mb, (chgind == 0 ? 120*1000 : 0));
! 1136: iop_msg_unmap(sc, im);
! 1137: iop_msg_free(sc, im);
! 1138: return (rv);
! 1139: }
! 1140:
! 1141: /*
! 1142: * Read the IOP's logical configuration table.
! 1143: */
! 1144: int
! 1145: iop_lct_get(struct iop_softc *sc)
! 1146: {
! 1147: size_t esize, size;
! 1148: int rv;
! 1149: struct i2o_lct *lct;
! 1150:
! 1151: esize = letoh32(sc->sc_status.expectedlctsize);
! 1152: lct = (struct i2o_lct *)malloc(esize, M_DEVBUF, M_WAITOK);
! 1153: if (lct == NULL)
! 1154: return (ENOMEM);
! 1155:
! 1156: if ((rv = iop_lct_get0(sc, lct, esize, 0)) != 0) {
! 1157: free(lct, M_DEVBUF);
! 1158: return (rv);
! 1159: }
! 1160:
! 1161: size = letoh16(lct->tablesize) << 2;
! 1162: if (esize != size) {
! 1163: free(lct, M_DEVBUF);
! 1164: lct = (struct i2o_lct *)malloc(size, M_DEVBUF, M_WAITOK);
! 1165: if (lct == NULL)
! 1166: return (ENOMEM);
! 1167:
! 1168: if ((rv = iop_lct_get0(sc, lct, size, 0)) != 0) {
! 1169: free(lct, M_DEVBUF);
! 1170: return (rv);
! 1171: }
! 1172: }
! 1173:
! 1174: /* Swap in the new LCT. */
! 1175: if (sc->sc_lct != NULL)
! 1176: free(sc->sc_lct, M_DEVBUF);
! 1177: sc->sc_lct = lct;
! 1178: sc->sc_nlctent = ((letoh16(sc->sc_lct->tablesize) << 2) -
! 1179: sizeof(struct i2o_lct) + sizeof(struct i2o_lct_entry)) /
! 1180: sizeof(struct i2o_lct_entry);
! 1181: return (0);
! 1182: }
! 1183:
! 1184: /*
! 1185: * Request the specified parameter group from the target. If an initiator
! 1186: * is specified (a) don't wait for the operation to complete, but instead
! 1187: * let the initiator's interrupt handler deal with the reply and (b) place a
! 1188: * pointer to the parameter group op in the wrapper's `im_dvcontext' field.
! 1189: */
! 1190: int
! 1191: iop_param_op(struct iop_softc *sc, int tid, struct iop_initiator *ii,
! 1192: int write, int group, void *buf, size_t size)
! 1193: {
! 1194: struct iop_msg *im;
! 1195: struct i2o_util_params_op *mf;
! 1196: struct i2o_reply *rf;
! 1197: int rv, func, op;
! 1198: struct iop_pgop *pgop;
! 1199: u_int32_t mb[IOP_MAX_MSG_SIZE / sizeof(u_int32_t)];
! 1200:
! 1201: im = iop_msg_alloc(sc, ii, (ii == NULL ? IM_WAIT : 0) | IM_NOSTATUS);
! 1202: if ((pgop = malloc(sizeof(*pgop), M_DEVBUF, M_WAITOK)) == NULL) {
! 1203: iop_msg_free(sc, im);
! 1204: return (ENOMEM);
! 1205: }
! 1206: if ((rf = malloc(sizeof(*rf), M_DEVBUF, M_WAITOK)) == NULL) {
! 1207: iop_msg_free(sc, im);
! 1208: free(pgop, M_DEVBUF);
! 1209: return (ENOMEM);
! 1210: }
! 1211: im->im_dvcontext = pgop;
! 1212: im->im_rb = rf;
! 1213:
! 1214: if (write) {
! 1215: func = I2O_UTIL_PARAMS_SET;
! 1216: op = I2O_PARAMS_OP_FIELD_SET;
! 1217: } else {
! 1218: func = I2O_UTIL_PARAMS_GET;
! 1219: op = I2O_PARAMS_OP_FIELD_GET;
! 1220: }
! 1221:
! 1222: mf = (struct i2o_util_params_op *)mb;
! 1223: mf->msgflags = I2O_MSGFLAGS(i2o_util_params_op);
! 1224: mf->msgfunc = I2O_MSGFUNC(tid, func);
! 1225: mf->msgictx = IOP_ICTX;
! 1226: mf->msgtctx = im->im_tctx;
! 1227: mf->flags = 0;
! 1228:
! 1229: pgop->olh.count = htole16(1);
! 1230: pgop->olh.reserved = htole16(0);
! 1231: pgop->oat.operation = htole16(op);
! 1232: pgop->oat.fieldcount = htole16(0xffff);
! 1233: pgop->oat.group = htole16(group);
! 1234:
! 1235: memset(buf, 0, size);
! 1236: iop_msg_map(sc, im, mb, pgop, sizeof(*pgop), 1);
! 1237: iop_msg_map(sc, im, mb, buf, size, write);
! 1238: rv = iop_msg_post(sc, im, mb, (ii == NULL ? 30000 : 0));
! 1239:
! 1240: /* Detect errors; let partial transfers to count as success. */
! 1241: if (ii == NULL && rv == 0) {
! 1242: if (rf->reqstatus == I2O_STATUS_ERROR_PARTIAL_XFER &&
! 1243: rf->detail == htole16(I2O_DSC_UNKNOWN_ERROR))
! 1244: rv = 0;
! 1245: else
! 1246: rv = (rf->reqstatus != 0 ? EIO : 0);
! 1247: }
! 1248:
! 1249: if (ii == NULL || rv != 0) {
! 1250: iop_msg_unmap(sc, im);
! 1251: iop_msg_free(sc, im);
! 1252: free(pgop, M_DEVBUF);
! 1253: free(rf, M_DEVBUF);
! 1254: }
! 1255:
! 1256: return (rv);
! 1257: }
! 1258:
! 1259: /*
! 1260: * Execute a simple command (no parameters).
! 1261: */
! 1262: int
! 1263: iop_simple_cmd(struct iop_softc *sc, int tid, int function, int ictx,
! 1264: int async, int timo)
! 1265: {
! 1266: struct iop_msg *im;
! 1267: struct i2o_msg mf;
! 1268: int rv, fl;
! 1269:
! 1270: fl = (async != 0 ? IM_WAIT : IM_POLL);
! 1271: im = iop_msg_alloc(sc, NULL, fl);
! 1272:
! 1273: mf.msgflags = I2O_MSGFLAGS(i2o_msg);
! 1274: mf.msgfunc = I2O_MSGFUNC(tid, function);
! 1275: mf.msgictx = ictx;
! 1276: mf.msgtctx = im->im_tctx;
! 1277:
! 1278: rv = iop_msg_post(sc, im, &mf, timo);
! 1279: iop_msg_free(sc, im);
! 1280: return (rv);
! 1281: }
! 1282:
! 1283: /*
! 1284: * Post the system table to the IOP.
! 1285: */
! 1286: int
! 1287: iop_systab_set(struct iop_softc *sc)
! 1288: {
! 1289: struct i2o_exec_sys_tab_set *mf;
! 1290: struct iop_msg *im;
! 1291: bus_space_handle_t bsh;
! 1292: bus_addr_t boo;
! 1293: u_int32_t mema[2], ioa[2];
! 1294: int rv;
! 1295: u_int32_t mb[IOP_MAX_MSG_SIZE / sizeof(u_int32_t)];
! 1296:
! 1297: im = iop_msg_alloc(sc, NULL, IM_WAIT);
! 1298:
! 1299: mf = (struct i2o_exec_sys_tab_set *)mb;
! 1300: mf->msgflags = I2O_MSGFLAGS(i2o_exec_sys_tab_set);
! 1301: mf->msgfunc = I2O_MSGFUNC(I2O_TID_IOP, I2O_EXEC_SYS_TAB_SET);
! 1302: mf->msgictx = IOP_ICTX;
! 1303: mf->msgtctx = im->im_tctx;
! 1304: mf->iopid = (sc->sc_dv.dv_unit + 2) << 12;
! 1305: mf->segnumber = 0;
! 1306:
! 1307: mema[1] = sc->sc_status.desiredprivmemsize;
! 1308: ioa[1] = sc->sc_status.desiredpriviosize;
! 1309:
! 1310: if (mema[1] != 0) {
! 1311: /*
! 1312: * XXX This will waste virtual memory. We need a flag to tell
! 1313: * bus_space_alloc to just reserve, not actually map the area.
! 1314: */
! 1315: rv = bus_space_alloc(sc->sc_bus_memt, 0, 0xffffffff,
! 1316: letoh32(mema[1]), PAGE_SIZE, 0, 0, &boo, &bsh);
! 1317: mema[0] = htole32(boo);
! 1318: if (rv != 0) {
! 1319: printf("%s: can't alloc priv mem space, err = %d\n",
! 1320: sc->sc_dv.dv_xname, rv);
! 1321: mema[0] = 0;
! 1322: mema[1] = 0;
! 1323: }
! 1324: }
! 1325:
! 1326: if (ioa[1] != 0) {
! 1327: /*
! 1328: * XXX This will potentially waste virtual memory. We
! 1329: * need a flag to tell bus_space_alloc to just
! 1330: * reserve, not actually map the area.
! 1331: */
! 1332: rv = bus_space_alloc(sc->sc_bus_iot, 0, 0xffff,
! 1333: letoh32(ioa[1]), 0, 0, 0, &boo, &bsh);
! 1334: ioa[0] = htole32(boo);
! 1335: if (rv != 0) {
! 1336: printf("%s: can't alloc priv i/o space, err = %d\n",
! 1337: sc->sc_dv.dv_xname, rv);
! 1338: ioa[0] = 0;
! 1339: ioa[1] = 0;
! 1340: }
! 1341: }
! 1342:
! 1343: iop_msg_map(sc, im, mb, iop_systab, iop_systab_size, 1);
! 1344: iop_msg_map(sc, im, mb, mema, sizeof(mema), 1);
! 1345: iop_msg_map(sc, im, mb, ioa, sizeof(ioa), 1);
! 1346: rv = iop_msg_post(sc, im, mb, 5000);
! 1347: iop_msg_unmap(sc, im);
! 1348: iop_msg_free(sc, im);
! 1349: return (rv);
! 1350: }
! 1351:
! 1352: /*
! 1353: * Reset the IOP. Must be called with interrupts disabled.
! 1354: */
! 1355: int
! 1356: iop_reset(struct iop_softc *sc)
! 1357: {
! 1358: struct i2o_exec_iop_reset mf;
! 1359: paddr_t pa = sc->sc_scr_seg->ds_addr;
! 1360: u_int32_t *sw = (u_int32_t *)sc->sc_scr;
! 1361: u_int32_t mfa;
! 1362: int rv = 0;
! 1363:
! 1364: mf.msgflags = I2O_MSGFLAGS(i2o_exec_iop_reset);
! 1365: mf.msgfunc = I2O_MSGFUNC(I2O_TID_IOP, I2O_EXEC_IOP_RESET);
! 1366: mf.reserved[0] = 0;
! 1367: mf.reserved[1] = 0;
! 1368: mf.reserved[2] = 0;
! 1369: mf.reserved[3] = 0;
! 1370: mf.statuslow = pa & ~(u_int32_t)0;
! 1371: mf.statushigh = sizeof pa > sizeof mf.statuslow ? pa >> 32 : 0;
! 1372:
! 1373: *sw = htole32(0);
! 1374: bus_dmamap_sync(sc->sc_dmat, sc->sc_scr_dmamap, 0, sizeof(*sw),
! 1375: BUS_DMASYNC_PREREAD);
! 1376:
! 1377: if ((rv = iop_post(sc, (u_int32_t *)&mf)))
! 1378: return (rv);
! 1379:
! 1380: /* XXX */
! 1381: POLL(2500,
! 1382: (bus_dmamap_sync(sc->sc_dmat, sc->sc_scr_dmamap, 0, sizeof(*sw),
! 1383: BUS_DMASYNC_POSTREAD), *sw != htole32(0)));
! 1384: if (*sw != htole32(I2O_RESET_IN_PROGRESS)) {
! 1385: printf("%s: reset rejected, status 0x%x\n",
! 1386: sc->sc_dv.dv_xname, letoh32(*sw));
! 1387: return (EIO);
! 1388: }
! 1389:
! 1390: /*
! 1391: * IOP is now in the INIT state. Wait no more than 10 seconds for
! 1392: * the inbound queue to become responsive.
! 1393: */
! 1394: POLL(10000, (mfa = iop_inl(sc, IOP_REG_IFIFO)) != IOP_MFA_EMPTY);
! 1395: if (mfa == IOP_MFA_EMPTY) {
! 1396: printf("%s: reset failed\n", sc->sc_dv.dv_xname);
! 1397: return (EIO);
! 1398: }
! 1399:
! 1400: iop_release_mfa(sc, mfa);
! 1401:
! 1402: return (0);
! 1403: }
! 1404:
! 1405: /*
! 1406: * Register a new initiator. Must be called with the configuration lock
! 1407: * held.
! 1408: */
! 1409: void
! 1410: iop_initiator_register(struct iop_softc *sc, struct iop_initiator *ii)
! 1411: {
! 1412: static int ictxgen;
! 1413: int s;
! 1414:
! 1415: /* 0 is reserved (by us) for system messages. */
! 1416: ii->ii_ictx = ++ictxgen;
! 1417:
! 1418: /*
! 1419: * `Utility initiators' don't make it onto the per-IOP initiator list
! 1420: * (which is used only for configuration), but do get one slot on
! 1421: * the inbound queue.
! 1422: */
! 1423: if ((ii->ii_flags & II_UTILITY) == 0) {
! 1424: LIST_INSERT_HEAD(&sc->sc_iilist, ii, ii_list);
! 1425: sc->sc_nii++;
! 1426: } else
! 1427: sc->sc_nuii++;
! 1428:
! 1429: s = splbio();
! 1430: LIST_INSERT_HEAD(IOP_ICTXHASH(ii->ii_ictx), ii, ii_hash);
! 1431: splx(s);
! 1432: }
! 1433:
! 1434: /*
! 1435: * Unregister an initiator. Must be called with the configuration lock
! 1436: * held.
! 1437: */
! 1438: void
! 1439: iop_initiator_unregister(struct iop_softc *sc, struct iop_initiator *ii)
! 1440: {
! 1441: int s;
! 1442:
! 1443: if ((ii->ii_flags & II_UTILITY) == 0) {
! 1444: LIST_REMOVE(ii, ii_list);
! 1445: sc->sc_nii--;
! 1446: } else
! 1447: sc->sc_nuii--;
! 1448:
! 1449: s = splbio();
! 1450: LIST_REMOVE(ii, ii_hash);
! 1451: splx(s);
! 1452: }
! 1453:
! 1454: /*
! 1455: * Handle a reply frame from the IOP.
! 1456: */
! 1457: int
! 1458: iop_handle_reply(struct iop_softc *sc, u_int32_t rmfa)
! 1459: {
! 1460: struct iop_msg *im;
! 1461: struct i2o_reply *rb;
! 1462: struct i2o_fault_notify *fn;
! 1463: struct iop_initiator *ii;
! 1464: u_int off, ictx, tctx, status, size;
! 1465:
! 1466: off = (int)(rmfa - sc->sc_rep_phys);
! 1467: rb = (struct i2o_reply *)(sc->sc_rep + off);
! 1468:
! 1469: /* Perform reply queue DMA synchronisation. XXX This is rubbish. */
! 1470: bus_dmamap_sync(sc->sc_dmat, sc->sc_rep_dmamap, off,
! 1471: sc->sc_rep_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD);
! 1472: if (--sc->sc_curib != 0)
! 1473: bus_dmamap_sync(sc->sc_dmat, sc->sc_rep_dmamap, 0,
! 1474: sc->sc_rep_size, BUS_DMASYNC_PREREAD);
! 1475:
! 1476: #ifdef I2ODEBUG
! 1477: if ((letoh32(rb->msgflags) & I2O_MSGFLAGS_64BIT) != 0)
! 1478: panic("iop_handle_reply: 64-bit reply");
! 1479: #endif
! 1480: /*
! 1481: * Find the initiator.
! 1482: */
! 1483: ictx = letoh32(rb->msgictx);
! 1484: if (ictx == IOP_ICTX)
! 1485: ii = NULL;
! 1486: else {
! 1487: ii = LIST_FIRST(IOP_ICTXHASH(ictx));
! 1488: for (; ii != NULL; ii = LIST_NEXT(ii, ii_hash))
! 1489: if (ii->ii_ictx == ictx)
! 1490: break;
! 1491: if (ii == NULL) {
! 1492: #ifdef I2ODEBUG
! 1493: iop_reply_print(sc, rb);
! 1494: #endif
! 1495: printf("%s: WARNING: bad ictx returned (%x)\n",
! 1496: sc->sc_dv.dv_xname, ictx);
! 1497: return (-1);
! 1498: }
! 1499: }
! 1500:
! 1501: /*
! 1502: * If we received a transport failure notice, we've got to dig the
! 1503: * transaction context (if any) out of the original message frame,
! 1504: * and then release the original MFA back to the inbound FIFO.
! 1505: */
! 1506: if ((rb->msgflags & I2O_MSGFLAGS_FAIL) != 0) {
! 1507: status = I2O_STATUS_SUCCESS;
! 1508:
! 1509: fn = (struct i2o_fault_notify *)rb;
! 1510: tctx = iop_inl(sc, fn->lowmfa + 12); /* XXX */
! 1511: iop_release_mfa(sc, fn->lowmfa);
! 1512: iop_tfn_print(sc, fn);
! 1513: } else {
! 1514: status = rb->reqstatus;
! 1515: tctx = letoh32(rb->msgtctx);
! 1516: }
! 1517:
! 1518: if (ii == NULL || (ii->ii_flags & II_DISCARD) == 0) {
! 1519: /*
! 1520: * This initiator tracks state using message wrappers.
! 1521: *
! 1522: * Find the originating message wrapper, and if requested
! 1523: * notify the initiator.
! 1524: */
! 1525: im = sc->sc_ims + (tctx & IOP_TCTX_MASK);
! 1526: if ((tctx & IOP_TCTX_MASK) > sc->sc_maxib ||
! 1527: (im->im_flags & IM_ALLOCED) == 0 ||
! 1528: tctx != im->im_tctx) {
! 1529: printf("%s: WARNING: bad tctx returned (0x%08x, %p)\n",
! 1530: sc->sc_dv.dv_xname, tctx, im);
! 1531: if (im != NULL)
! 1532: printf("%s: flags=0x%08x tctx=0x%08x\n",
! 1533: sc->sc_dv.dv_xname, im->im_flags,
! 1534: im->im_tctx);
! 1535: #ifdef I2ODEBUG
! 1536: if ((rb->msgflags & I2O_MSGFLAGS_FAIL) == 0)
! 1537: iop_reply_print(sc, rb);
! 1538: #endif
! 1539: return (-1);
! 1540: }
! 1541:
! 1542: if ((rb->msgflags & I2O_MSGFLAGS_FAIL) != 0)
! 1543: im->im_flags |= IM_FAIL;
! 1544:
! 1545: #ifdef I2ODEBUG
! 1546: if ((im->im_flags & IM_REPLIED) != 0)
! 1547: panic("%s: dup reply", sc->sc_dv.dv_xname);
! 1548: #endif
! 1549: im->im_flags |= IM_REPLIED;
! 1550:
! 1551: #ifdef I2ODEBUG
! 1552: if (status != I2O_STATUS_SUCCESS)
! 1553: iop_reply_print(sc, rb);
! 1554: #endif
! 1555: im->im_reqstatus = status;
! 1556:
! 1557: /* Copy the reply frame, if requested. */
! 1558: if (im->im_rb != NULL) {
! 1559: size = (letoh32(rb->msgflags) >> 14) & ~3;
! 1560: #ifdef I2ODEBUG
! 1561: if (size > IOP_MAX_MSG_SIZE)
! 1562: panic("iop_handle_reply: reply too large");
! 1563: #endif
! 1564: memcpy(im->im_rb, rb, size);
! 1565: }
! 1566:
! 1567: /* Notify the initiator. */
! 1568: if ((im->im_flags & IM_WAIT) != 0)
! 1569: wakeup(im);
! 1570: else if ((im->im_flags & (IM_POLL | IM_POLL_INTR)) != IM_POLL)
! 1571: (*ii->ii_intr)(ii->ii_dv, im, rb);
! 1572: } else {
! 1573: /*
! 1574: * This initiator discards message wrappers.
! 1575: *
! 1576: * Simply pass the reply frame to the initiator.
! 1577: */
! 1578: (*ii->ii_intr)(ii->ii_dv, NULL, rb);
! 1579: }
! 1580:
! 1581: return (status);
! 1582: }
! 1583:
! 1584: /*
! 1585: * Handle an interrupt from the IOP.
! 1586: */
! 1587: int
! 1588: iop_intr(void *arg)
! 1589: {
! 1590: struct iop_softc *sc;
! 1591: u_int32_t rmfa;
! 1592:
! 1593: sc = arg;
! 1594:
! 1595: if ((iop_inl(sc, IOP_REG_INTR_STATUS) & IOP_INTR_OFIFO) == 0)
! 1596: return (0);
! 1597:
! 1598: for (;;) {
! 1599: /* Double read to account for IOP bug. */
! 1600: if ((rmfa = iop_inl(sc, IOP_REG_OFIFO)) == IOP_MFA_EMPTY) {
! 1601: rmfa = iop_inl(sc, IOP_REG_OFIFO);
! 1602: if (rmfa == IOP_MFA_EMPTY)
! 1603: break;
! 1604: }
! 1605: iop_handle_reply(sc, rmfa);
! 1606: iop_outl(sc, IOP_REG_OFIFO, rmfa);
! 1607: }
! 1608:
! 1609: return (1);
! 1610: }
! 1611:
! 1612: /*
! 1613: * Handle an event signalled by the executive.
! 1614: */
! 1615: void
! 1616: iop_intr_event(struct device *dv, struct iop_msg *im, void *reply)
! 1617: {
! 1618: struct i2o_util_event_register_reply *rb;
! 1619: struct iop_softc *sc;
! 1620: u_int event;
! 1621:
! 1622: sc = (struct iop_softc *)dv;
! 1623: rb = reply;
! 1624:
! 1625: if ((rb->msgflags & I2O_MSGFLAGS_FAIL) != 0)
! 1626: return;
! 1627:
! 1628: event = letoh32(rb->event);
! 1629: printf("%s: event 0x%08x received\n", dv->dv_xname, event);
! 1630: }
! 1631:
! 1632: /*
! 1633: * Allocate a message wrapper.
! 1634: */
! 1635: struct iop_msg *
! 1636: iop_msg_alloc(struct iop_softc *sc, struct iop_initiator *ii, int flags)
! 1637: {
! 1638: struct iop_msg *im;
! 1639: static u_int tctxgen;
! 1640: int s, i;
! 1641:
! 1642: #ifdef I2ODEBUG
! 1643: if ((flags & IM_SYSMASK) != 0)
! 1644: panic("iop_msg_alloc: system flags specified");
! 1645: #endif
! 1646:
! 1647: s = splbio(); /* XXX */
! 1648: im = SLIST_FIRST(&sc->sc_im_freelist);
! 1649: #if defined(DIAGNOSTIC) || defined(I2ODEBUG)
! 1650: if (im == NULL)
! 1651: panic("iop_msg_alloc: no free wrappers");
! 1652: #endif
! 1653: SLIST_REMOVE_HEAD(&sc->sc_im_freelist, im_chain);
! 1654: splx(s);
! 1655:
! 1656: if (ii != NULL && (ii->ii_flags & II_DISCARD) != 0)
! 1657: flags |= IM_DISCARD;
! 1658:
! 1659: im->im_tctx = (im->im_tctx & IOP_TCTX_MASK) | tctxgen;
! 1660: tctxgen += (1 << IOP_TCTX_SHIFT);
! 1661: im->im_flags = flags | IM_ALLOCED;
! 1662: im->im_rb = NULL;
! 1663: i = 0;
! 1664: do {
! 1665: im->im_xfer[i++].ix_size = 0;
! 1666: } while (i < IOP_MAX_MSG_XFERS);
! 1667:
! 1668: return (im);
! 1669: }
! 1670:
! 1671: /*
! 1672: * Free a message wrapper.
! 1673: */
! 1674: void
! 1675: iop_msg_free(struct iop_softc *sc, struct iop_msg *im)
! 1676: {
! 1677: int s;
! 1678:
! 1679: #ifdef I2ODEBUG
! 1680: if ((im->im_flags & IM_ALLOCED) == 0)
! 1681: panic("iop_msg_free: wrapper not allocated");
! 1682: #endif
! 1683:
! 1684: im->im_flags = 0;
! 1685: s = splbio();
! 1686: SLIST_INSERT_HEAD(&sc->sc_im_freelist, im, im_chain);
! 1687: splx(s);
! 1688: }
! 1689:
! 1690: /*
! 1691: * Map a data transfer. Write a scatter-gather list into the message frame.
! 1692: */
! 1693: int
! 1694: iop_msg_map(struct iop_softc *sc, struct iop_msg *im, u_int32_t *mb,
! 1695: void *xferaddr, size_t xfersize, int out)
! 1696: {
! 1697: bus_dmamap_t dm;
! 1698: bus_dma_segment_t *ds;
! 1699: struct iop_xfer *ix;
! 1700: u_int rv, i, nsegs, flg, off, xn;
! 1701: u_int32_t *p;
! 1702:
! 1703: for (xn = 0, ix = im->im_xfer; xn < IOP_MAX_MSG_XFERS; xn++, ix++)
! 1704: if (ix->ix_size == 0)
! 1705: break;
! 1706:
! 1707: #ifdef I2ODEBUG
! 1708: if (xfersize == 0)
! 1709: panic("iop_msg_map: null transfer");
! 1710: if (xfersize > IOP_MAX_XFER)
! 1711: panic("iop_msg_map: transfer too large");
! 1712: if (xn == IOP_MAX_MSG_XFERS)
! 1713: panic("iop_msg_map: too many xfers");
! 1714: #endif
! 1715:
! 1716: /*
! 1717: * Only the first DMA map is static.
! 1718: */
! 1719: if (xn != 0) {
! 1720: rv = bus_dmamap_create(sc->sc_dmat, IOP_MAX_XFER,
! 1721: IOP_MAX_SEGS, IOP_MAX_XFER, 0,
! 1722: BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &ix->ix_map);
! 1723: if (rv != 0)
! 1724: return (rv);
! 1725: }
! 1726:
! 1727: dm = ix->ix_map;
! 1728: rv = bus_dmamap_load(sc->sc_dmat, dm, xferaddr, xfersize, NULL, 0);
! 1729: if (rv != 0)
! 1730: goto bad;
! 1731:
! 1732: /*
! 1733: * How many SIMPLE SG elements can we fit in this message?
! 1734: */
! 1735: off = mb[0] >> 16;
! 1736: p = mb + off;
! 1737: nsegs = ((IOP_MAX_MSG_SIZE / sizeof *mb) - off) >> 1;
! 1738:
! 1739: if (dm->dm_nsegs > nsegs) {
! 1740: bus_dmamap_unload(sc->sc_dmat, ix->ix_map);
! 1741: rv = EFBIG;
! 1742: DPRINTF(("iop_msg_map: too many segs\n"));
! 1743: goto bad;
! 1744: }
! 1745:
! 1746: nsegs = dm->dm_nsegs;
! 1747: xfersize = 0;
! 1748:
! 1749: /*
! 1750: * Write out the SG list.
! 1751: */
! 1752: if (out)
! 1753: flg = I2O_SGL_SIMPLE | I2O_SGL_DATA_OUT;
! 1754: else
! 1755: flg = I2O_SGL_SIMPLE;
! 1756:
! 1757: for (i = nsegs, ds = dm->dm_segs; i > 1; i--, p += 2, ds++) {
! 1758: p[0] = (u_int32_t)ds->ds_len | flg;
! 1759: p[1] = (u_int32_t)ds->ds_addr;
! 1760: xfersize += ds->ds_len;
! 1761: }
! 1762:
! 1763: p[0] = (u_int32_t)ds->ds_len | flg | I2O_SGL_END_BUFFER;
! 1764: p[1] = (u_int32_t)ds->ds_addr;
! 1765: xfersize += ds->ds_len;
! 1766:
! 1767: /* Fix up the transfer record, and sync the map. */
! 1768: ix->ix_flags = (out ? IX_OUT : IX_IN);
! 1769: ix->ix_size = xfersize;
! 1770: bus_dmamap_sync(sc->sc_dmat, ix->ix_map, 0, xfersize,
! 1771: out ? BUS_DMASYNC_POSTWRITE : BUS_DMASYNC_POSTREAD);
! 1772:
! 1773: /*
! 1774: * If this is the first xfer we've mapped for this message, adjust
! 1775: * the SGL offset field in the message header.
! 1776: */
! 1777: if ((im->im_flags & IM_SGLOFFADJ) == 0) {
! 1778: mb[0] += (mb[0] >> 12) & 0xf0;
! 1779: im->im_flags |= IM_SGLOFFADJ;
! 1780: }
! 1781: mb[0] += (nsegs << 17);
! 1782: return (0);
! 1783:
! 1784: bad:
! 1785: if (xn != 0)
! 1786: bus_dmamap_destroy(sc->sc_dmat, ix->ix_map);
! 1787: return (rv);
! 1788: }
! 1789:
! 1790: /*
! 1791: * Map a block I/O data transfer (different in that there's only one per
! 1792: * message maximum, and PAGE addressing may be used). Write a scatter
! 1793: * gather list into the message frame.
! 1794: */
! 1795: int
! 1796: iop_msg_map_bio(struct iop_softc *sc, struct iop_msg *im, u_int32_t *mb,
! 1797: void *xferaddr, int xfersize, int out)
! 1798: {
! 1799: bus_dma_segment_t *ds;
! 1800: bus_dmamap_t dm;
! 1801: struct iop_xfer *ix;
! 1802: u_int rv, i, nsegs, off, slen, tlen, flg;
! 1803: paddr_t saddr, eaddr;
! 1804: u_int32_t *p;
! 1805:
! 1806: #ifdef I2ODEBUG
! 1807: if (xfersize == 0)
! 1808: panic("iop_msg_map_bio: null transfer");
! 1809: if (xfersize > IOP_MAX_XFER)
! 1810: panic("iop_msg_map_bio: transfer too large");
! 1811: if ((im->im_flags & IM_SGLOFFADJ) != 0)
! 1812: panic("iop_msg_map_bio: SGLOFFADJ");
! 1813: #endif
! 1814:
! 1815: ix = im->im_xfer;
! 1816: dm = ix->ix_map;
! 1817: rv = bus_dmamap_load(sc->sc_dmat, dm, xferaddr, xfersize, NULL, 0);
! 1818: if (rv != 0)
! 1819: return (rv);
! 1820:
! 1821: off = mb[0] >> 16;
! 1822: nsegs = ((IOP_MAX_MSG_SIZE / 4) - off) >> 1;
! 1823:
! 1824: /*
! 1825: * If the transfer is highly fragmented and won't fit using SIMPLE
! 1826: * elements, use PAGE_LIST elements instead. SIMPLE elements are
! 1827: * potentially more efficient, both for us and the IOP.
! 1828: */
! 1829: if (dm->dm_nsegs > nsegs) {
! 1830: nsegs = 1;
! 1831: p = mb + off + 1;
! 1832:
! 1833: /* XXX This should be done with a bus_space flag. */
! 1834: for (i = dm->dm_nsegs, ds = dm->dm_segs; i > 0; i--, ds++) {
! 1835: slen = ds->ds_len;
! 1836: saddr = ds->ds_addr;
! 1837:
! 1838: while (slen > 0) {
! 1839: eaddr = (saddr + PAGE_SIZE) & ~(PAGE_SIZE - 1);
! 1840: tlen = min(eaddr - saddr, slen);
! 1841: slen -= tlen;
! 1842: *p++ = letoh32(saddr);
! 1843: saddr = eaddr;
! 1844: nsegs++;
! 1845: }
! 1846: }
! 1847:
! 1848: mb[off] = xfersize | I2O_SGL_PAGE_LIST | I2O_SGL_END_BUFFER |
! 1849: I2O_SGL_END;
! 1850: if (out)
! 1851: mb[off] |= I2O_SGL_DATA_OUT;
! 1852: } else {
! 1853: p = mb + off;
! 1854: nsegs = dm->dm_nsegs;
! 1855:
! 1856: if (out)
! 1857: flg = I2O_SGL_SIMPLE | I2O_SGL_DATA_OUT;
! 1858: else
! 1859: flg = I2O_SGL_SIMPLE;
! 1860:
! 1861: for (i = nsegs, ds = dm->dm_segs; i > 1; i--, p += 2, ds++) {
! 1862: p[0] = (u_int32_t)ds->ds_len | flg;
! 1863: p[1] = (u_int32_t)ds->ds_addr;
! 1864: }
! 1865:
! 1866: p[0] = (u_int32_t)ds->ds_len | flg | I2O_SGL_END_BUFFER |
! 1867: I2O_SGL_END;
! 1868: p[1] = (u_int32_t)ds->ds_addr;
! 1869: nsegs <<= 1;
! 1870: }
! 1871:
! 1872: /* Fix up the transfer record, and sync the map. */
! 1873: ix->ix_flags = (out ? IX_OUT : IX_IN);
! 1874: ix->ix_size = xfersize;
! 1875: bus_dmamap_sync(sc->sc_dmat, ix->ix_map, 0,
! 1876: ix->ix_map->dm_mapsize,
! 1877: out ? BUS_DMASYNC_POSTWRITE : BUS_DMASYNC_POSTREAD);
! 1878:
! 1879: /*
! 1880: * Adjust the SGL offset and total message size fields. We don't
! 1881: * set IM_SGLOFFADJ, since it's used only for SIMPLE elements.
! 1882: */
! 1883: mb[0] += ((off << 4) + (nsegs << 16));
! 1884: return (0);
! 1885: }
! 1886:
! 1887: /*
! 1888: * Unmap all data transfers associated with a message wrapper.
! 1889: */
! 1890: void
! 1891: iop_msg_unmap(struct iop_softc *sc, struct iop_msg *im)
! 1892: {
! 1893: struct iop_xfer *ix;
! 1894: int i;
! 1895:
! 1896: #ifdef I2ODEBUG
! 1897: if (im->im_xfer[0].ix_size == 0)
! 1898: panic("iop_msg_unmap: no transfers mapped");
! 1899: #endif
! 1900:
! 1901: for (ix = im->im_xfer, i = 0;;) {
! 1902: bus_dmamap_sync(sc->sc_dmat, ix->ix_map, 0, ix->ix_size,
! 1903: ix->ix_flags & IX_OUT ? BUS_DMASYNC_POSTWRITE :
! 1904: BUS_DMASYNC_POSTREAD);
! 1905: bus_dmamap_unload(sc->sc_dmat, ix->ix_map);
! 1906:
! 1907: /* Only the first DMA map is static. */
! 1908: if (i != 0)
! 1909: bus_dmamap_destroy(sc->sc_dmat, ix->ix_map);
! 1910: if ((++ix)->ix_size == 0)
! 1911: break;
! 1912: if (++i >= IOP_MAX_MSG_XFERS)
! 1913: break;
! 1914: }
! 1915: }
! 1916:
! 1917: /*
! 1918: * Post a message frame to the IOP's inbound queue.
! 1919: */
! 1920: int
! 1921: iop_post(struct iop_softc *sc, u_int32_t *mb)
! 1922: {
! 1923: u_int32_t mfa;
! 1924: int s;
! 1925: size_t size = mb[0] >> 14 & ~3;
! 1926:
! 1927: /* ZZZ */
! 1928: if (size > IOP_MAX_MSG_SIZE)
! 1929: panic("iop_post: frame too large");
! 1930:
! 1931: #ifdef I2ODEBUG
! 1932: {
! 1933: int i;
! 1934:
! 1935: printf("\niop_post\n");
! 1936: for (i = 0; i < size / sizeof *mb; i++)
! 1937: printf("%4d %08x\n", i, mb[i]);
! 1938: }
! 1939: #endif
! 1940:
! 1941: s = splbio(); /* XXX */
! 1942:
! 1943: /* Allocate a slot with the IOP. */
! 1944: if ((mfa = iop_inl(sc, IOP_REG_IFIFO)) == IOP_MFA_EMPTY)
! 1945: if ((mfa = iop_inl(sc, IOP_REG_IFIFO)) == IOP_MFA_EMPTY) {
! 1946: splx(s);
! 1947: printf("%s: mfa not forthcoming\n",
! 1948: sc->sc_dv.dv_xname);
! 1949: return (EAGAIN);
! 1950: }
! 1951:
! 1952: #ifdef I2ODEBUG
! 1953: printf("mfa = %u\n", mfa);
! 1954: #endif
! 1955:
! 1956: /* Copy out the message frame. */
! 1957: bus_space_write_region_4(sc->sc_iot, sc->sc_ioh, mfa, mb,
! 1958: size / sizeof *mb);
! 1959: bus_space_barrier(sc->sc_iot, sc->sc_ioh, mfa, size,
! 1960: BUS_SPACE_BARRIER_WRITE);
! 1961:
! 1962: /* Post the MFA back to the IOP. */
! 1963: iop_outl(sc, IOP_REG_IFIFO, mfa);
! 1964:
! 1965: splx(s);
! 1966: return (0);
! 1967: }
! 1968:
! 1969: /*
! 1970: * Post a message to the IOP and deal with completion.
! 1971: */
! 1972: int
! 1973: iop_msg_post(struct iop_softc *sc, struct iop_msg *im, void *xmb, int timo)
! 1974: {
! 1975: u_int32_t *mb = xmb;
! 1976: int rv, s;
! 1977: size_t size = mb[0] >> 14 & 3;
! 1978:
! 1979: /* Terminate the scatter/gather list chain. */
! 1980: if ((im->im_flags & IM_SGLOFFADJ) != 0)
! 1981: mb[size - 2] |= I2O_SGL_END;
! 1982:
! 1983: /* Perform reply buffer DMA synchronisation. */
! 1984: if (sc->sc_curib++ == 0)
! 1985: bus_dmamap_sync(sc->sc_dmat, sc->sc_rep_dmamap, 0,
! 1986: sc->sc_rep_size, BUS_DMASYNC_PREREAD);
! 1987:
! 1988: if ((rv = iop_post(sc, mb)) != 0)
! 1989: return (rv);
! 1990:
! 1991: if ((im->im_flags & IM_DISCARD) != 0)
! 1992: iop_msg_free(sc, im);
! 1993: else if ((im->im_flags & IM_POLL) != 0 && timo == 0) {
! 1994: /* XXX For ofifo_init(). */
! 1995: rv = 0;
! 1996: } else if ((im->im_flags & (IM_POLL | IM_WAIT)) != 0) {
! 1997: if ((im->im_flags & IM_POLL) != 0)
! 1998: iop_msg_poll(sc, im, timo);
! 1999: else
! 2000: iop_msg_wait(sc, im, timo);
! 2001:
! 2002: s = splbio();
! 2003: if ((im->im_flags & IM_REPLIED) != 0) {
! 2004: if ((im->im_flags & IM_NOSTATUS) != 0)
! 2005: rv = 0;
! 2006: else if ((im->im_flags & IM_FAIL) != 0)
! 2007: rv = ENXIO;
! 2008: else if (im->im_reqstatus != I2O_STATUS_SUCCESS)
! 2009: rv = EIO;
! 2010: else
! 2011: rv = 0;
! 2012: } else
! 2013: rv = EBUSY;
! 2014: splx(s);
! 2015: } else
! 2016: rv = 0;
! 2017:
! 2018: return (rv);
! 2019: }
! 2020:
! 2021: /*
! 2022: * Spin until the specified message is replied to.
! 2023: */
! 2024: void
! 2025: iop_msg_poll(struct iop_softc *sc, struct iop_msg *im, int timo)
! 2026: {
! 2027: u_int32_t rmfa;
! 2028: int s, status;
! 2029:
! 2030: s = splbio(); /* XXX */
! 2031:
! 2032: /* Wait for completion. */
! 2033: for (timo *= 10; timo != 0; timo--) {
! 2034: if ((iop_inl(sc, IOP_REG_INTR_STATUS) & IOP_INTR_OFIFO) != 0) {
! 2035: /* Double read to account for IOP bug. */
! 2036: rmfa = iop_inl(sc, IOP_REG_OFIFO);
! 2037: if (rmfa == IOP_MFA_EMPTY)
! 2038: rmfa = iop_inl(sc, IOP_REG_OFIFO);
! 2039: if (rmfa != IOP_MFA_EMPTY) {
! 2040: status = iop_handle_reply(sc, rmfa);
! 2041:
! 2042: /*
! 2043: * Return the reply frame to the IOP's
! 2044: * outbound FIFO.
! 2045: */
! 2046: iop_outl(sc, IOP_REG_OFIFO, rmfa);
! 2047: }
! 2048: }
! 2049: if ((im->im_flags & IM_REPLIED) != 0)
! 2050: break;
! 2051: DELAY(100);
! 2052: }
! 2053:
! 2054: if (timo == 0) {
! 2055: #ifdef I2ODEBUG
! 2056: printf("%s: poll - no reply\n", sc->sc_dv.dv_xname);
! 2057: if (iop_status_get(sc, 1) != 0)
! 2058: printf("iop_msg_poll: unable to retrieve status\n");
! 2059: else
! 2060: printf("iop_msg_poll: IOP state = %d\n",
! 2061: (letoh32(sc->sc_status.segnumber) >> 16) & 0xff);
! 2062: #endif
! 2063: }
! 2064:
! 2065: splx(s);
! 2066: }
! 2067:
! 2068: /*
! 2069: * Sleep until the specified message is replied to.
! 2070: */
! 2071: void
! 2072: iop_msg_wait(struct iop_softc *sc, struct iop_msg *im, int timo)
! 2073: {
! 2074: int s, rv;
! 2075:
! 2076: s = splbio();
! 2077: if ((im->im_flags & IM_REPLIED) != 0) {
! 2078: splx(s);
! 2079: return;
! 2080: }
! 2081: rv = tsleep(im, PRIBIO, "iopmsg", timo * hz / 1000);
! 2082: splx(s);
! 2083:
! 2084: #ifdef I2ODEBUG
! 2085: if (rv != 0) {
! 2086: printf("iop_msg_wait: tsleep() == %d\n", rv);
! 2087: if (iop_status_get(sc, 0) != 0)
! 2088: printf("iop_msg_wait: unable to retrieve status\n");
! 2089: else
! 2090: printf("iop_msg_wait: IOP state = %d\n",
! 2091: (letoh32(sc->sc_status.segnumber) >> 16) & 0xff);
! 2092: }
! 2093: #endif
! 2094: }
! 2095:
! 2096: /*
! 2097: * Release an unused message frame back to the IOP's inbound fifo.
! 2098: */
! 2099: void
! 2100: iop_release_mfa(struct iop_softc *sc, u_int32_t mfa)
! 2101: {
! 2102:
! 2103: /* Use the frame to issue a no-op. */
! 2104: iop_outl(sc, mfa, I2O_VERSION_11 | (4 << 16));
! 2105: iop_outl(sc, mfa + 4, I2O_MSGFUNC(I2O_TID_IOP, I2O_UTIL_NOP));
! 2106: iop_outl(sc, mfa + 8, 0);
! 2107: iop_outl(sc, mfa + 12, 0);
! 2108:
! 2109: iop_outl(sc, IOP_REG_IFIFO, mfa);
! 2110: }
! 2111:
! 2112: #ifdef I2ODEBUG
! 2113: /*
! 2114: * Dump a reply frame header.
! 2115: */
! 2116: void
! 2117: iop_reply_print(struct iop_softc *sc, struct i2o_reply *rb)
! 2118: {
! 2119: u_int function, detail;
! 2120: #ifdef I2OVERBOSE
! 2121: const char *statusstr;
! 2122: #endif
! 2123:
! 2124: function = (letoh32(rb->msgfunc) >> 24) & 0xff;
! 2125: detail = letoh16(rb->detail);
! 2126:
! 2127: printf("%s: reply:\n", sc->sc_dv.dv_xname);
! 2128:
! 2129: #ifdef I2OVERBOSE
! 2130: if (rb->reqstatus < sizeof(iop_status) / sizeof(iop_status[0]))
! 2131: statusstr = iop_status[rb->reqstatus];
! 2132: else
! 2133: statusstr = "undefined error code";
! 2134:
! 2135: printf("%s: function=0x%02x status=0x%02x (%s)\n",
! 2136: sc->sc_dv.dv_xname, function, rb->reqstatus, statusstr);
! 2137: #else
! 2138: printf("%s: function=0x%02x status=0x%02x\n",
! 2139: sc->sc_dv.dv_xname, function, rb->reqstatus);
! 2140: #endif
! 2141: printf("%s: detail=0x%04x ictx=0x%08x tctx=0x%08x\n",
! 2142: sc->sc_dv.dv_xname, detail, letoh32(rb->msgictx),
! 2143: letoh32(rb->msgtctx));
! 2144: printf("%s: tidi=%d tidt=%d flags=0x%02x\n", sc->sc_dv.dv_xname,
! 2145: (letoh32(rb->msgfunc) >> 12) & 4095, letoh32(rb->msgfunc) & 4095,
! 2146: (letoh32(rb->msgflags) >> 8) & 0xff);
! 2147: }
! 2148: #endif
! 2149:
! 2150: /*
! 2151: * Dump a transport failure reply.
! 2152: */
! 2153: void
! 2154: iop_tfn_print(struct iop_softc *sc, struct i2o_fault_notify *fn)
! 2155: {
! 2156:
! 2157: printf("%s: WARNING: transport failure:\n", sc->sc_dv.dv_xname);
! 2158:
! 2159: printf("%s: ictx=0x%08x tctx=0x%08x\n", sc->sc_dv.dv_xname,
! 2160: letoh32(fn->msgictx), letoh32(fn->msgtctx));
! 2161: printf("%s: failurecode=0x%02x severity=0x%02x\n",
! 2162: sc->sc_dv.dv_xname, fn->failurecode, fn->severity);
! 2163: printf("%s: highestver=0x%02x lowestver=0x%02x\n",
! 2164: sc->sc_dv.dv_xname, fn->highestver, fn->lowestver);
! 2165: }
! 2166:
! 2167: /*
! 2168: * Translate an I2O ASCII field into a C string.
! 2169: */
! 2170: void
! 2171: iop_strvis(struct iop_softc *sc, const char *src, int slen, char *dst, int dlen)
! 2172: {
! 2173: int hc, lc, i, nit;
! 2174:
! 2175: dlen--;
! 2176: lc = 0;
! 2177: hc = 0;
! 2178: i = 0;
! 2179:
! 2180: /*
! 2181: * DPT use NUL as a space, whereas AMI use it as a terminator. The
! 2182: * spec has nothing to say about it. Since AMI fields are usually
! 2183: * filled with junk after the terminator, ...
! 2184: */
! 2185: nit = (letoh16(sc->sc_status.orgid) != I2O_ORG_DPT);
! 2186:
! 2187: while (slen-- != 0 && dlen-- != 0) {
! 2188: if (nit && *src == '\0')
! 2189: break;
! 2190: else if (*src <= 0x20 || *src >= 0x7f) {
! 2191: if (hc)
! 2192: dst[i++] = ' ';
! 2193: } else {
! 2194: hc = 1;
! 2195: dst[i++] = *src;
! 2196: lc = i;
! 2197: }
! 2198: src++;
! 2199: }
! 2200:
! 2201: dst[lc] = '\0';
! 2202: }
! 2203:
! 2204: /*
! 2205: * Retrieve the DEVICE_IDENTITY parameter group from the target and dump it.
! 2206: */
! 2207: int
! 2208: iop_print_ident(struct iop_softc *sc, int tid)
! 2209: {
! 2210: struct {
! 2211: struct i2o_param_op_results pr;
! 2212: struct i2o_param_read_results prr;
! 2213: struct i2o_param_device_identity di;
! 2214: } __attribute__ ((__packed__)) p;
! 2215: char buf[32];
! 2216: int rv;
! 2217:
! 2218: rv = iop_param_op(sc, tid, NULL, 0, I2O_PARAM_DEVICE_IDENTITY, &p,
! 2219: sizeof(p));
! 2220: if (rv != 0)
! 2221: return (rv);
! 2222:
! 2223: iop_strvis(sc, p.di.vendorinfo, sizeof(p.di.vendorinfo), buf,
! 2224: sizeof(buf));
! 2225: printf(" <%s, ", buf);
! 2226: iop_strvis(sc, p.di.productinfo, sizeof(p.di.productinfo), buf,
! 2227: sizeof(buf));
! 2228: printf("%s, ", buf);
! 2229: iop_strvis(sc, p.di.revlevel, sizeof(p.di.revlevel), buf, sizeof(buf));
! 2230: printf("%s>", buf);
! 2231:
! 2232: return (0);
! 2233: }
! 2234:
! 2235: /*
! 2236: * Claim or unclaim the specified TID.
! 2237: */
! 2238: int
! 2239: iop_util_claim(struct iop_softc *sc, struct iop_initiator *ii, int release,
! 2240: int flags)
! 2241: {
! 2242: struct iop_msg *im;
! 2243: struct i2o_util_claim mf;
! 2244: int rv, func;
! 2245:
! 2246: func = release ? I2O_UTIL_CLAIM_RELEASE : I2O_UTIL_CLAIM;
! 2247: im = iop_msg_alloc(sc, ii, IM_WAIT);
! 2248:
! 2249: /* We can use the same structure, as they're identical. */
! 2250: mf.msgflags = I2O_MSGFLAGS(i2o_util_claim);
! 2251: mf.msgfunc = I2O_MSGFUNC(ii->ii_tid, func);
! 2252: mf.msgictx = ii->ii_ictx;
! 2253: mf.msgtctx = im->im_tctx;
! 2254: mf.flags = flags;
! 2255:
! 2256: rv = iop_msg_post(sc, im, &mf, 5000);
! 2257: iop_msg_free(sc, im);
! 2258: return (rv);
! 2259: }
! 2260:
! 2261: /*
! 2262: * Perform an abort.
! 2263: */
! 2264: int iop_util_abort(struct iop_softc *sc, struct iop_initiator *ii, int func,
! 2265: int tctxabort, int flags)
! 2266: {
! 2267: struct iop_msg *im;
! 2268: struct i2o_util_abort mf;
! 2269: int rv;
! 2270:
! 2271: im = iop_msg_alloc(sc, ii, IM_WAIT);
! 2272:
! 2273: mf.msgflags = I2O_MSGFLAGS(i2o_util_abort);
! 2274: mf.msgfunc = I2O_MSGFUNC(ii->ii_tid, I2O_UTIL_ABORT);
! 2275: mf.msgictx = ii->ii_ictx;
! 2276: mf.msgtctx = im->im_tctx;
! 2277: mf.flags = (func << 24) | flags;
! 2278: mf.tctxabort = tctxabort;
! 2279:
! 2280: rv = iop_msg_post(sc, im, &mf, 5000);
! 2281: iop_msg_free(sc, im);
! 2282: return (rv);
! 2283: }
! 2284:
! 2285: /*
! 2286: * Enable or disable reception of events for the specified device.
! 2287: */
! 2288: int iop_util_eventreg(struct iop_softc *sc, struct iop_initiator *ii, int mask)
! 2289: {
! 2290: struct iop_msg *im;
! 2291: struct i2o_util_event_register mf;
! 2292:
! 2293: im = iop_msg_alloc(sc, ii, 0);
! 2294:
! 2295: mf.msgflags = I2O_MSGFLAGS(i2o_util_event_register);
! 2296: mf.msgfunc = I2O_MSGFUNC(ii->ii_tid, I2O_UTIL_EVENT_REGISTER);
! 2297: mf.msgictx = ii->ii_ictx;
! 2298: mf.msgtctx = im->im_tctx;
! 2299: mf.eventmask = mask;
! 2300:
! 2301: /* This message is replied to only when events are signalled. */
! 2302: return (iop_msg_post(sc, im, &mf, 0));
! 2303: }
! 2304:
! 2305: int
! 2306: iopopen(dev_t dev, int flag, int mode, struct proc *p)
! 2307: {
! 2308: struct iop_softc *sc;
! 2309:
! 2310: if (!(sc = (struct iop_softc *)device_lookup(&iop_cd, minor(dev))))
! 2311: return (ENXIO);
! 2312: if ((sc->sc_flags & IOP_ONLINE) == 0)
! 2313: return (ENXIO);
! 2314: if ((sc->sc_flags & IOP_OPEN) != 0)
! 2315: return (EBUSY);
! 2316: sc->sc_flags |= IOP_OPEN;
! 2317:
! 2318: sc->sc_ptb = malloc(IOP_MAX_XFER * IOP_MAX_MSG_XFERS, M_DEVBUF,
! 2319: M_WAITOK);
! 2320: if (sc->sc_ptb == NULL) {
! 2321: sc->sc_flags ^= IOP_OPEN;
! 2322: return (ENOMEM);
! 2323: }
! 2324:
! 2325: return (0);
! 2326: }
! 2327:
! 2328: int
! 2329: iopclose(dev_t dev, int flag, int mode, struct proc *p)
! 2330: {
! 2331: struct iop_softc *sc;
! 2332:
! 2333: sc = (struct iop_softc *)device_lookup(&iop_cd, minor(dev)); /* XXX */
! 2334: free(sc->sc_ptb, M_DEVBUF);
! 2335: sc->sc_flags &= ~IOP_OPEN;
! 2336: return (0);
! 2337: }
! 2338:
! 2339: int
! 2340: iopioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
! 2341: {
! 2342: struct iop_softc *sc;
! 2343: struct iovec *iov;
! 2344: int rv, i;
! 2345:
! 2346: if (securelevel >= 2)
! 2347: return (EPERM);
! 2348:
! 2349: sc = (struct iop_softc *)device_lookup(&iop_cd, minor(dev)); /* XXX */
! 2350:
! 2351: switch (cmd) {
! 2352: case IOPIOCPT:
! 2353: return (iop_passthrough(sc, (struct ioppt *)data));
! 2354:
! 2355: case IOPIOCGSTATUS:
! 2356: iov = (struct iovec *)data;
! 2357: i = sizeof(struct i2o_status);
! 2358: if (i > iov->iov_len)
! 2359: i = iov->iov_len;
! 2360: else
! 2361: iov->iov_len = i;
! 2362: if ((rv = iop_status_get(sc, 0)) == 0)
! 2363: rv = copyout(&sc->sc_status, iov->iov_base, i);
! 2364: return (rv);
! 2365:
! 2366: case IOPIOCGLCT:
! 2367: case IOPIOCGTIDMAP:
! 2368: case IOPIOCRECONFIG:
! 2369: break;
! 2370:
! 2371: default:
! 2372: #if defined(DIAGNOSTIC) || defined(I2ODEBUG)
! 2373: printf("%s: unknown ioctl %lx\n", sc->sc_dv.dv_xname, cmd);
! 2374: #endif
! 2375: return (ENOTTY);
! 2376: }
! 2377:
! 2378: if ((rv = lockmgr(&sc->sc_conflock, LK_SHARED, NULL)) != 0)
! 2379: return (rv);
! 2380:
! 2381: switch (cmd) {
! 2382: case IOPIOCGLCT:
! 2383: iov = (struct iovec *)data;
! 2384: i = letoh16(sc->sc_lct->tablesize) << 2;
! 2385: if (i > iov->iov_len)
! 2386: i = iov->iov_len;
! 2387: else
! 2388: iov->iov_len = i;
! 2389: rv = copyout(sc->sc_lct, iov->iov_base, i);
! 2390: break;
! 2391:
! 2392: case IOPIOCRECONFIG:
! 2393: rv = iop_reconfigure(sc, 0);
! 2394: break;
! 2395:
! 2396: case IOPIOCGTIDMAP:
! 2397: iov = (struct iovec *)data;
! 2398: i = sizeof(struct iop_tidmap) * sc->sc_nlctent;
! 2399: if (i > iov->iov_len)
! 2400: i = iov->iov_len;
! 2401: else
! 2402: iov->iov_len = i;
! 2403: rv = copyout(sc->sc_tidmap, iov->iov_base, i);
! 2404: break;
! 2405: }
! 2406:
! 2407: lockmgr(&sc->sc_conflock, LK_RELEASE, NULL);
! 2408: return (rv);
! 2409: }
! 2410:
! 2411: int
! 2412: iop_passthrough(struct iop_softc *sc, struct ioppt *pt)
! 2413: {
! 2414: struct iop_msg *im;
! 2415: struct i2o_msg *mf;
! 2416: struct ioppt_buf *ptb;
! 2417: int rv, i, mapped;
! 2418: void *buf;
! 2419:
! 2420: mf = NULL;
! 2421: im = NULL;
! 2422: mapped = 1;
! 2423:
! 2424: if (pt->pt_msglen > IOP_MAX_MSG_SIZE ||
! 2425: pt->pt_msglen > (letoh16(sc->sc_status.inboundmframesize) << 2) ||
! 2426: pt->pt_msglen < sizeof(struct i2o_msg) ||
! 2427: pt->pt_nbufs > IOP_MAX_MSG_XFERS ||
! 2428: pt->pt_nbufs < 0 || pt->pt_replylen < 0 ||
! 2429: pt->pt_timo < 1000 || pt->pt_timo > 5*60*1000)
! 2430: return (EINVAL);
! 2431:
! 2432: for (i = 0; i < pt->pt_nbufs; i++)
! 2433: if (pt->pt_bufs[i].ptb_datalen > IOP_MAX_XFER) {
! 2434: rv = ENOMEM;
! 2435: goto bad;
! 2436: }
! 2437:
! 2438: mf = malloc(IOP_MAX_MSG_SIZE, M_DEVBUF, M_WAITOK);
! 2439: if (mf == NULL)
! 2440: return (ENOMEM);
! 2441:
! 2442: if ((rv = copyin(pt->pt_msg, mf, pt->pt_msglen)) != 0)
! 2443: goto bad;
! 2444:
! 2445: im = iop_msg_alloc(sc, NULL, IM_WAIT | IM_NOSTATUS);
! 2446: im->im_rb = (struct i2o_reply *)mf;
! 2447: mf->msgictx = IOP_ICTX;
! 2448: mf->msgtctx = im->im_tctx;
! 2449:
! 2450: for (i = 0; i < pt->pt_nbufs; i++) {
! 2451: ptb = &pt->pt_bufs[i];
! 2452: buf = sc->sc_ptb + i * IOP_MAX_XFER;
! 2453:
! 2454: if ((u_int)ptb->ptb_datalen > IOP_MAX_XFER) {
! 2455: rv = EINVAL;
! 2456: goto bad;
! 2457: }
! 2458:
! 2459: if (ptb->ptb_out != 0) {
! 2460: rv = copyin(ptb->ptb_data, buf, ptb->ptb_datalen);
! 2461: if (rv != 0)
! 2462: goto bad;
! 2463: }
! 2464:
! 2465: rv = iop_msg_map(sc, im, (u_int32_t *)mf, buf,
! 2466: ptb->ptb_datalen, ptb->ptb_out != 0);
! 2467: if (rv != 0)
! 2468: goto bad;
! 2469: mapped = 1;
! 2470: }
! 2471:
! 2472: if ((rv = iop_msg_post(sc, im, mf, pt->pt_timo)) != 0)
! 2473: goto bad;
! 2474:
! 2475: i = (letoh32(im->im_rb->msgflags) >> 14) & ~3;
! 2476: if (i > IOP_MAX_MSG_SIZE)
! 2477: i = IOP_MAX_MSG_SIZE;
! 2478: if (i > pt->pt_replylen)
! 2479: i = pt->pt_replylen;
! 2480: if ((rv = copyout(im->im_rb, pt->pt_reply, i)) != 0)
! 2481: goto bad;
! 2482:
! 2483: iop_msg_unmap(sc, im);
! 2484: mapped = 0;
! 2485:
! 2486: for (i = 0; i < pt->pt_nbufs; i++) {
! 2487: ptb = &pt->pt_bufs[i];
! 2488: if (ptb->ptb_out != 0)
! 2489: continue;
! 2490: buf = sc->sc_ptb + i * IOP_MAX_XFER;
! 2491: rv = copyout(buf, ptb->ptb_data, ptb->ptb_datalen);
! 2492: if (rv != 0)
! 2493: break;
! 2494: }
! 2495:
! 2496: bad:
! 2497: if (mapped != 0)
! 2498: iop_msg_unmap(sc, im);
! 2499: if (im != NULL)
! 2500: iop_msg_free(sc, im);
! 2501: if (mf != NULL)
! 2502: free(mf, M_DEVBUF);
! 2503: return (rv);
! 2504: }
CVSweb