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