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