diff --git a/sys/dev/i2o/iop.c b/sys/dev/i2o/iop.c index ce6fec8fdf7b..a03d5da51c54 100644 --- a/sys/dev/i2o/iop.c +++ b/sys/dev/i2o/iop.c @@ -1,4 +1,4 @@ -/* $NetBSD: iop.c,v 1.8 2001/01/01 19:03:30 ad Exp $ */ +/* $NetBSD: iop.c,v 1.9 2001/01/03 21:04:01 ad Exp $ */ /*- * Copyright (c) 2000 The NetBSD Foundation, Inc. @@ -207,13 +207,14 @@ static void iop_config_interrupts(struct device *); static void iop_configure_devices(struct iop_softc *); static void iop_devinfo(int, char *); static int iop_print(void *, const char *); -static int iop_reconfigure(struct iop_softc *, u_int32_t); +static int iop_reconfigure(struct iop_softc *, u_int32_t, int); static void iop_shutdown(void *); static int iop_submatch(struct device *, struct cfdata *, void *); #ifdef notyet static int iop_vendor_print(void *, const char *); #endif +static void iop_create_reconf_thread(void *); static void iop_intr_event(struct device *, struct iop_msg *, void *); static int iop_hrt_get(struct iop_softc *); static int iop_hrt_get0(struct iop_softc *, struct i2o_hrt *, int); @@ -222,7 +223,7 @@ static int iop_lct_get0(struct iop_softc *, struct i2o_lct *, int, static int iop_msg_wait(struct iop_softc *, struct iop_msg *, int); static int iop_ofifo_init(struct iop_softc *); static int iop_handle_reply(struct iop_softc *, u_int32_t); -static void iop_reconfigure_proc(void *); +static void iop_reconf_thread(void *); static void iop_release_mfa(struct iop_softc *, u_int32_t); static int iop_reset(struct iop_softc *); static int iop_status_get(struct iop_softc *); @@ -451,17 +452,31 @@ iop_config_interrupts(struct device *self) config_found_sm(self, &ia, iop_vendor_print, iop_submatch); #endif - if ((rv = iop_reconfigure(sc, 0)) != 0) { + if ((rv = iop_reconfigure(sc, 0, 0)) != 0) { printf("%s: configure failed (%d)\n", sc->sc_dv.dv_xname, rv); return; } - sc->sc_flags |= IOP_ONLINE; + kthread_create(iop_create_reconf_thread, sc); +} - rv = kthread_create1(iop_reconfigure_proc, sc, &sc->sc_reconf_proc, +/* + * Create the reconfiguration thread. Called after the standard kernel + * threads have been created. + */ +static void +iop_create_reconf_thread(void *cookie) +{ + struct iop_softc *sc; + int rv; + + sc = cookie; + + sc->sc_flags |= IOP_ONLINE; + rv = kthread_create1(iop_reconf_thread, sc, &sc->sc_reconf_proc, "%s", sc->sc_dv.dv_xname); if (rv != 0) { - printf("%s: unable to create thread (%d)", + printf("%s: unable to create reconfiguration thread (%d)", sc->sc_dv.dv_xname, rv); return; } @@ -472,7 +487,7 @@ iop_config_interrupts(struct device *self) * initiates re-configuration if recieved. */ static void -iop_reconfigure_proc(void *cookie) +iop_reconf_thread(void *cookie) { struct iop_softc *sc; struct i2o_lct lct; @@ -486,10 +501,10 @@ iop_reconfigure_proc(void *cookie) if (iop_lct_get0(sc, &lct, sizeof(lct), chgind) == 0) { DPRINTF(("%s: async reconfiguration (0x%08x)\n", sc->sc_dv.dv_xname, le32toh(lct.changeindicator))); - iop_reconfigure(sc, lct.changeindicator); + iop_reconfigure(sc, lct.changeindicator, LK_NOWAIT); } - tsleep(iop_reconfigure_proc, PWAIT, "iopzzz", hz * 5); + tsleep(iop_reconf_thread, PWAIT, "iopzzz", hz * 5); } } @@ -497,7 +512,7 @@ iop_reconfigure_proc(void *cookie) * Reconfigure: find new and removed devices. */ static int -iop_reconfigure(struct iop_softc *sc, u_int32_t chgind) +iop_reconfigure(struct iop_softc *sc, u_int32_t chgind, int lkflags) { struct iop_msg *im; struct i2o_hba_bus_scan *mb; @@ -505,8 +520,8 @@ iop_reconfigure(struct iop_softc *sc, u_int32_t chgind) struct iop_initiator *ii, *nextii; int rv, tid, i; - rv = lockmgr(&sc->sc_conflock, LK_EXCLUSIVE | LK_RECURSEFAIL, NULL); - if (rv != 0) { + lkflags |= LK_EXCLUSIVE | LK_RECURSEFAIL; + if ((rv = lockmgr(&sc->sc_conflock, lkflags, NULL)) != 0) { DPRINTF(("iop_reconfigure: unable to acquire lock\n")); return (rv); } @@ -577,19 +592,18 @@ iop_reconfigure(struct iop_softc *sc, u_int32_t chgind) free(sc->sc_tidmap, M_DEVBUF); sc->sc_tidmap = malloc(sc->sc_nlctent * sizeof(struct iop_tidmap), M_DEVBUF, M_NOWAIT); - memset(sc->sc_tidmap, 0, sc->sc_nlctent * sizeof(struct iop_tidmap)); /* Match and attach child devices. */ iop_configure_devices(sc); for (ii = LIST_FIRST(&sc->sc_iilist); ii != NULL; ii = nextii) { - nextii = LIST_NEXT(ii, ii_list); + nextii = ii; + do { + if ((nextii = LIST_NEXT(nextii, ii_list)) == NULL) + break; + } while ((nextii->ii_flags & II_UTILITY) != 0); if ((ii->ii_flags & II_UTILITY) != 0) continue; - if ((ii->ii_flags & II_CONFIGURED) == 0) { - ii->ii_flags |= II_CONFIGURED; - continue; - } /* Detach devices that were configured, but are now gone. */ for (i = 0; i < sc->sc_nlctent; i++) @@ -625,10 +639,15 @@ iop_configure_devices(struct iop_softc *sc) struct iop_attach_args ia; struct iop_initiator *ii; const struct i2o_lct_entry *le; + struct device *dv; int i, j, nent; nent = sc->sc_nlctent; for (i = 0, le = sc->sc_lct->entry; i < nent; i++, le++) { + sc->sc_tidmap[i].it_tid = le32toh(le->localtid) & 4095; + sc->sc_tidmap[i].it_flags = 0; + sc->sc_tidmap[i].it_dvname[0] = '\0'; + /* * Ignore the device if it's in use. */ @@ -636,7 +655,7 @@ iop_configure_devices(struct iop_softc *sc) continue; ia.ia_class = le16toh(le->classid) & 4095; - ia.ia_tid = le32toh(le->localtid) & 4095; + ia.ia_tid = sc->sc_tidmap[i].it_tid; /* Ignore uninteresting devices. */ for (j = 0; j < sizeof(iop_class) / sizeof(iop_class[0]); j++) @@ -653,14 +672,21 @@ iop_configure_devices(struct iop_softc *sc) LIST_FOREACH(ii, &sc->sc_iilist, ii_list) { if ((ii->ii_flags & II_UTILITY) != 0) continue; - if (ia.ia_tid == ii->ii_tid) + if (ia.ia_tid == ii->ii_tid) { + sc->sc_tidmap[i].it_flags |= IT_CONFIGURED; + strcpy(sc->sc_tidmap[i].it_dvname, + ii->ii_dv->dv_xname); break; + } } if (ii != NULL) continue; - if (config_found_sm(&sc->sc_dv, &ia, iop_print, iop_submatch)) + dv = config_found_sm(&sc->sc_dv, &ia, iop_print, iop_submatch); + if (dv != NULL) { sc->sc_tidmap[i].it_flags |= IT_CONFIGURED; + strcpy(sc->sc_tidmap[i].it_dvname, dv->dv_xname); + } } } @@ -969,7 +995,12 @@ iop_lct_get0(struct iop_softc *sc, struct i2o_lct *lct, int size, mb->classid = I2O_CLASS_ANY; mb->changeindicator = chgind; - DPRINTF(("iop_lct_get0: reading LCT\n")); +#ifdef I2ODEBUG + printf("iop_lct_get0: reading LCT"); + if (chgind != 0) + printf(" (async)"); + printf("\n"); +#endif iop_msg_map(sc, im, lct, size, 0); rv = iop_msg_enqueue(sc, im, (chgind == 0 ? 120*1000 : 0)); @@ -1777,6 +1808,7 @@ iop_msg_wait(struct iop_softc *sc, struct iop_msg *im, int timo) (le32toh(sc->sc_status.segnumber) >> 16) & 0xff); } #endif + if ((im->im_flags & (IM_REPLIED | IM_NOSTATUS)) == IM_REPLIED) { rb = (struct i2o_reply *)im->im_msg; rv = (rb->reqstatus != I2O_STATUS_SUCCESS ? EIO : 0); @@ -1976,6 +2008,14 @@ iopopen(dev_t dev, int flag, int mode, struct proc *p) return (EIO); sc->sc_flags |= IOP_OPEN; + /* XXX */ + sc->sc_ptb = malloc(((MAXPHYS + 3) & ~3) * IOP_MAX_MSG_XFERS, M_DEVBUF, + M_WAITOK); + if (sc->sc_ptb == NULL) { + sc->sc_flags ^= IOP_OPEN; + return (ENOMEM); + } + return (0); } @@ -1985,7 +2025,8 @@ iopclose(dev_t dev, int flag, int mode, struct proc *p) struct iop_softc *sc; sc = device_lookup(&iop_cd, minor(dev)); - sc->sc_flags &= ~IOP_OPEN; + free(sc->sc_ptb, M_DEVBUF); + sc->sc_flags ^= IOP_OPEN; return (0); } @@ -1999,12 +2040,16 @@ iopioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) struct i2o_msg *mb; struct i2o_reply *rb; int rv, i; + struct ioppt_buf *ptb; + void *buf; if (securelevel >= 2) return (EPERM); sc = device_lookup(&iop_cd, minor(dev)); + PHOLD(p); + switch (cmd) { case IOPIOCPT: pt = (struct ioppt *)data; @@ -2019,6 +2064,9 @@ iopioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) rv = EINVAL; break; } + for (i = 0; i < pt->pt_nbufs; i++) + if (pt->pt_bufs[i].ptb_datalen > ((MAXPHYS + 3) & ~3)) + return (ENOMEM); rv = iop_msg_alloc(sc, NULL, &im, IM_NOINTR | IM_NOSTATUS); if (rv != 0) @@ -2034,12 +2082,18 @@ iopioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) mb->msgtctx = im->im_tctx; for (i = 0; i < pt->pt_nbufs; i++) { - rv = iop_msg_map(sc, im, pt->pt_bufs[i].ptb_data, - pt->pt_bufs[i].ptb_datalen, - pt->pt_bufs[i].ptb_out != 0); + ptb = &pt->pt_bufs[i]; + buf = sc->sc_ptb + i * ((MAXPHYS + 3) & ~3); + + if (ptb->ptb_out != 0) + rv = copyin(ptb->ptb_data, buf, + ptb->ptb_datalen); + + rv = iop_msg_map(sc, im, buf, ptb->ptb_datalen, + ptb->ptb_out != 0); if (rv != 0) { iop_msg_free(sc, NULL, im); - return (rv); + break; } } @@ -2053,12 +2107,20 @@ iopioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) rv = copyout(rb, pt->pt_reply, i); } + for (i = 0; i < pt->pt_nbufs; i++) { + ptb = &pt->pt_bufs[i]; + if (ptb->ptb_out != 0 || rv != 0) + continue; + rv = copyout(sc->sc_ptb + i * ((MAXPHYS + 3) & ~3), + ptb->ptb_data, ptb->ptb_datalen); + } + iop_msg_free(sc, NULL, im); break; case IOPIOCGLCT: iov = (struct iovec *)data; - rv = lockmgr(&sc->sc_conflock, LK_EXCLUSIVE, NULL); + rv = lockmgr(&sc->sc_conflock, LK_SHARED, NULL); if (rv == 0) { i = le16toh(sc->sc_lct->tablesize) << 2; if (i > iov->iov_len) @@ -2082,7 +2144,21 @@ iopioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) break; case IOPIOCRECONFIG: - rv = iop_reconfigure(sc, 0); + rv = iop_reconfigure(sc, 0, 0); + break; + + case IOPIOCGTIDMAP: + iov = (struct iovec *)data; + rv = lockmgr(&sc->sc_conflock, LK_SHARED, NULL); + if (rv == 0) { + i = sizeof(struct iop_tidmap) * sc->sc_nlctent; + if (i > iov->iov_len) + i = iov->iov_len; + else + iov->iov_len = i; + rv = copyout(sc->sc_tidmap, iov->iov_base, i); + lockmgr(&sc->sc_conflock, LK_RELEASE, NULL); + } break; default: @@ -2093,5 +2169,7 @@ iopioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) break; } + PRELE(p); + return (rv); } diff --git a/sys/dev/i2o/iopvar.h b/sys/dev/i2o/iopvar.h index 3e38400ef14a..06b2c74cfea0 100644 --- a/sys/dev/i2o/iopvar.h +++ b/sys/dev/i2o/iopvar.h @@ -1,4 +1,4 @@ -/* $NetBSD: iopvar.h,v 1.3 2000/12/03 13:17:03 ad Exp $ */ +/* $NetBSD: iopvar.h,v 1.4 2001/01/03 21:04:01 ad Exp $ */ /*- * Copyright (c) 2000 The NetBSD Foundation, Inc. @@ -71,6 +71,13 @@ struct iop_stat { #define IOP_MAX_HW_QUEUECNT 256 #define IOP_MAX_HW_REPLYCNT 256 +struct iop_tidmap { + u_short it_tid; + u_short it_flags; + char it_dvname[sizeof(((struct device *)NULL)->dv_xname)]; +}; +#define IT_CONFIGURED 0x02 /* target configured */ + #ifdef _KERNEL #include "locators.h" @@ -129,12 +136,6 @@ struct iop_initiator { #define IOP_ICTX 0 -struct iop_tidmap { - u_short it_tid; - u_short it_flags; -}; -#define IT_CONFIGURED 0x02 /* target configured */ - /* * Per-IOP context. */ @@ -162,6 +163,7 @@ struct iop_softc { int sc_maxqueuecnt; /* maximum # of msgs on h/w queue */ struct iop_initiator sc_eventii;/* IOP event handler */ struct proc *sc_reconf_proc;/* reconfiguration process */ + caddr_t sc_ptb; /* * Reply queue. @@ -228,8 +230,9 @@ struct ioppt { }; #define IOPIOCPT _IOWR('u', 0, struct ioppt) -#define IOPIOCGLCT _IOW('u', 1, struct iovec) -#define IOPIOCGSTATUS _IOW('u', 2, struct iovec) +#define IOPIOCGLCT _IOWR('u', 1, struct iovec) +#define IOPIOCGSTATUS _IOWR('u', 2, struct iovec) #define IOPIOCRECONFIG _IO('u', 3) +#define IOPIOCGTIDMAP _IOWR('u', 4, struct iovec) #endif /* !_I2O_IOPVAR_H_ */