- Fix a number of bugs with the configuration stuff.

- Bash the passthrough interface into working order.
- Add an ioctl to retrieve the `tidmap'.
This commit is contained in:
ad 2001-01-03 21:04:01 +00:00
parent 8494f44b67
commit 5fcbd5f722
2 changed files with 120 additions and 39 deletions

View File

@ -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);
}

View File

@ -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_ */