aac.c revision 1.3.2.4 1 1.3.2.4 thorpej /* $NetBSD: aac.c,v 1.3.2.4 2003/01/03 17:07:38 thorpej Exp $ */
2 1.3.2.2 nathanw
3 1.3.2.2 nathanw /*-
4 1.3.2.2 nathanw * Copyright (c) 2002 The NetBSD Foundation, Inc.
5 1.3.2.2 nathanw * All rights reserved.
6 1.3.2.2 nathanw *
7 1.3.2.2 nathanw * This code is derived from software contributed to The NetBSD Foundation
8 1.3.2.2 nathanw * by Andrew Doran.
9 1.3.2.2 nathanw *
10 1.3.2.2 nathanw * Redistribution and use in source and binary forms, with or without
11 1.3.2.2 nathanw * modification, are permitted provided that the following conditions
12 1.3.2.2 nathanw * are met:
13 1.3.2.2 nathanw * 1. Redistributions of source code must retain the above copyright
14 1.3.2.2 nathanw * notice, this list of conditions and the following disclaimer.
15 1.3.2.2 nathanw * 2. Redistributions in binary form must reproduce the above copyright
16 1.3.2.2 nathanw * notice, this list of conditions and the following disclaimer in the
17 1.3.2.2 nathanw * documentation and/or other materials provided with the distribution.
18 1.3.2.2 nathanw * 3. All advertising materials mentioning features or use of this software
19 1.3.2.2 nathanw * must display the following acknowledgement:
20 1.3.2.2 nathanw * This product includes software developed by the NetBSD
21 1.3.2.2 nathanw * Foundation, Inc. and its contributors.
22 1.3.2.2 nathanw * 4. Neither the name of The NetBSD Foundation nor the names of its
23 1.3.2.2 nathanw * contributors may be used to endorse or promote products derived
24 1.3.2.2 nathanw * from this software without specific prior written permission.
25 1.3.2.2 nathanw *
26 1.3.2.2 nathanw * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 1.3.2.2 nathanw * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 1.3.2.2 nathanw * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 1.3.2.2 nathanw * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 1.3.2.2 nathanw * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 1.3.2.2 nathanw * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 1.3.2.2 nathanw * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 1.3.2.2 nathanw * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 1.3.2.2 nathanw * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 1.3.2.2 nathanw * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 1.3.2.2 nathanw * POSSIBILITY OF SUCH DAMAGE.
37 1.3.2.2 nathanw */
38 1.3.2.2 nathanw
39 1.3.2.2 nathanw /*-
40 1.3.2.2 nathanw * Copyright (c) 2001 Scott Long
41 1.3.2.2 nathanw * Copyright (c) 2001 Adaptec, Inc.
42 1.3.2.2 nathanw * Copyright (c) 2000 Michael Smith
43 1.3.2.2 nathanw * Copyright (c) 2000 BSDi
44 1.3.2.2 nathanw * Copyright (c) 2000 Niklas Hallqvist
45 1.3.2.2 nathanw * All rights reserved.
46 1.3.2.2 nathanw *
47 1.3.2.2 nathanw * Redistribution and use in source and binary forms, with or without
48 1.3.2.2 nathanw * modification, are permitted provided that the following conditions
49 1.3.2.2 nathanw * are met:
50 1.3.2.2 nathanw * 1. Redistributions of source code must retain the above copyright
51 1.3.2.2 nathanw * notice, this list of conditions and the following disclaimer.
52 1.3.2.2 nathanw * 2. Redistributions in binary form must reproduce the above copyright
53 1.3.2.2 nathanw * notice, this list of conditions and the following disclaimer in the
54 1.3.2.2 nathanw * documentation and/or other materials provided with the distribution.
55 1.3.2.2 nathanw *
56 1.3.2.2 nathanw * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
57 1.3.2.2 nathanw * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
58 1.3.2.2 nathanw * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
59 1.3.2.2 nathanw * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
60 1.3.2.2 nathanw * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
61 1.3.2.2 nathanw * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
62 1.3.2.2 nathanw * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
63 1.3.2.2 nathanw * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
64 1.3.2.2 nathanw * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
65 1.3.2.2 nathanw * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
66 1.3.2.2 nathanw * SUCH DAMAGE.
67 1.3.2.2 nathanw */
68 1.3.2.2 nathanw
69 1.3.2.2 nathanw /*
70 1.3.2.2 nathanw * Driver for the Adaptec 'FSA' family of PCI/SCSI RAID adapters.
71 1.3.2.2 nathanw *
72 1.3.2.2 nathanw * TODO:
73 1.3.2.2 nathanw *
74 1.3.2.2 nathanw * o Management interface.
75 1.3.2.2 nathanw * o Look again at some of the portability issues.
76 1.3.2.2 nathanw * o Handle various AIFs (e.g., notification that a container is going away).
77 1.3.2.2 nathanw */
78 1.3.2.2 nathanw
79 1.3.2.2 nathanw #include <sys/cdefs.h>
80 1.3.2.4 thorpej __KERNEL_RCSID(0, "$NetBSD: aac.c,v 1.3.2.4 2003/01/03 17:07:38 thorpej Exp $");
81 1.3.2.2 nathanw
82 1.3.2.2 nathanw #include "locators.h"
83 1.3.2.2 nathanw
84 1.3.2.2 nathanw #include <sys/param.h>
85 1.3.2.2 nathanw #include <sys/systm.h>
86 1.3.2.2 nathanw #include <sys/buf.h>
87 1.3.2.2 nathanw #include <sys/device.h>
88 1.3.2.2 nathanw #include <sys/kernel.h>
89 1.3.2.2 nathanw #include <sys/malloc.h>
90 1.3.2.2 nathanw
91 1.3.2.2 nathanw #include <machine/bus.h>
92 1.3.2.2 nathanw
93 1.3.2.2 nathanw #include <uvm/uvm_extern.h>
94 1.3.2.2 nathanw
95 1.3.2.2 nathanw #include <dev/ic/aacreg.h>
96 1.3.2.2 nathanw #include <dev/ic/aacvar.h>
97 1.3.2.2 nathanw #include <dev/ic/aac_tables.h>
98 1.3.2.2 nathanw
99 1.3.2.2 nathanw int aac_check_firmware(struct aac_softc *);
100 1.3.2.2 nathanw void aac_describe_controller(struct aac_softc *);
101 1.3.2.2 nathanw int aac_dequeue_fib(struct aac_softc *, int, u_int32_t *,
102 1.3.2.2 nathanw struct aac_fib **);
103 1.3.2.2 nathanw int aac_enqueue_fib(struct aac_softc *, int, struct aac_fib *);
104 1.3.2.2 nathanw void aac_host_command(struct aac_softc *);
105 1.3.2.2 nathanw void aac_host_response(struct aac_softc *);
106 1.3.2.2 nathanw int aac_init(struct aac_softc *);
107 1.3.2.2 nathanw int aac_print(void *, const char *);
108 1.3.2.2 nathanw void aac_shutdown(void *);
109 1.3.2.2 nathanw void aac_startup(struct aac_softc *);
110 1.3.2.2 nathanw int aac_sync_command(struct aac_softc *, u_int32_t, u_int32_t,
111 1.3.2.2 nathanw u_int32_t, u_int32_t, u_int32_t, u_int32_t *);
112 1.3.2.2 nathanw int aac_sync_fib(struct aac_softc *, u_int32_t, u_int32_t, void *,
113 1.3.2.2 nathanw u_int16_t, void *, u_int16_t *);
114 1.3.2.2 nathanw int aac_submatch(struct device *, struct cfdata *, void *);
115 1.3.2.2 nathanw
116 1.3.2.2 nathanw #ifdef AAC_DEBUG
117 1.3.2.2 nathanw void aac_print_fib(struct aac_softc *, struct aac_fib *, char *);
118 1.3.2.2 nathanw #endif
119 1.3.2.2 nathanw
120 1.3.2.2 nathanw /*
121 1.3.2.2 nathanw * Adapter-space FIB queue manipulation.
122 1.3.2.2 nathanw *
123 1.3.2.2 nathanw * Note that the queue implementation here is a little funky; neither the PI or
124 1.3.2.2 nathanw * CI will ever be zero. This behaviour is a controller feature.
125 1.3.2.2 nathanw */
126 1.3.2.2 nathanw static struct {
127 1.3.2.2 nathanw int size;
128 1.3.2.2 nathanw int notify;
129 1.3.2.2 nathanw } const aac_qinfo[] = {
130 1.3.2.2 nathanw { AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL },
131 1.3.2.2 nathanw { AAC_HOST_HIGH_CMD_ENTRIES, 0 },
132 1.3.2.2 nathanw { AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY },
133 1.3.2.2 nathanw { AAC_ADAP_HIGH_CMD_ENTRIES, 0 },
134 1.3.2.2 nathanw { AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL },
135 1.3.2.2 nathanw { AAC_HOST_HIGH_RESP_ENTRIES, 0 },
136 1.3.2.2 nathanw { AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY },
137 1.3.2.2 nathanw { AAC_ADAP_HIGH_RESP_ENTRIES, 0 }
138 1.3.2.2 nathanw };
139 1.3.2.2 nathanw
140 1.3.2.2 nathanw #ifdef AAC_DEBUG
141 1.3.2.2 nathanw int aac_debug = AAC_DEBUG;
142 1.3.2.2 nathanw #endif
143 1.3.2.2 nathanw
144 1.3.2.2 nathanw void *aac_sdh;
145 1.3.2.2 nathanw
146 1.3.2.2 nathanw extern struct cfdriver aac_cd;
147 1.3.2.2 nathanw
148 1.3.2.2 nathanw int
149 1.3.2.2 nathanw aac_attach(struct aac_softc *sc)
150 1.3.2.2 nathanw {
151 1.3.2.2 nathanw struct aac_attach_args aaca;
152 1.3.2.2 nathanw int nsegs, i, rv, state, size;
153 1.3.2.2 nathanw struct aac_ccb *ac;
154 1.3.2.2 nathanw struct aac_fib *fib;
155 1.3.2.2 nathanw bus_addr_t fibpa;
156 1.3.2.2 nathanw
157 1.3.2.2 nathanw SIMPLEQ_INIT(&sc->sc_ccb_free);
158 1.3.2.2 nathanw SIMPLEQ_INIT(&sc->sc_ccb_queue);
159 1.3.2.2 nathanw SIMPLEQ_INIT(&sc->sc_ccb_complete);
160 1.3.2.2 nathanw
161 1.3.2.2 nathanw /*
162 1.3.2.2 nathanw * Disable interrupts before we do anything.
163 1.3.2.2 nathanw */
164 1.3.2.2 nathanw AAC_MASK_INTERRUPTS(sc);
165 1.3.2.2 nathanw
166 1.3.2.2 nathanw /*
167 1.3.2.2 nathanw * Initialise the adapter.
168 1.3.2.2 nathanw */
169 1.3.2.2 nathanw if (aac_check_firmware(sc))
170 1.3.2.2 nathanw return (EINVAL);
171 1.3.2.2 nathanw
172 1.3.2.2 nathanw if ((rv = aac_init(sc)) != 0)
173 1.3.2.2 nathanw return (rv);
174 1.3.2.2 nathanw aac_startup(sc);
175 1.3.2.2 nathanw
176 1.3.2.2 nathanw /*
177 1.3.2.2 nathanw * Print a little information about the controller.
178 1.3.2.2 nathanw */
179 1.3.2.2 nathanw aac_describe_controller(sc);
180 1.3.2.2 nathanw
181 1.3.2.2 nathanw /*
182 1.3.2.2 nathanw * Initialize the ccbs.
183 1.3.2.2 nathanw */
184 1.3.2.2 nathanw sc->sc_ccbs = malloc(sizeof(*ac) * AAC_NCCBS, M_DEVBUF,
185 1.3.2.2 nathanw M_NOWAIT | M_ZERO);
186 1.3.2.2 nathanw if (sc->sc_ccbs == NULL) {
187 1.3.2.2 nathanw printf("%s: memory allocation failure\n", sc->sc_dv.dv_xname);
188 1.3.2.2 nathanw return (ENOMEM);
189 1.3.2.2 nathanw }
190 1.3.2.2 nathanw state = 0;
191 1.3.2.2 nathanw size = sizeof(*fib) * AAC_NCCBS;
192 1.3.2.2 nathanw
193 1.3.2.2 nathanw if ((rv = bus_dmamap_create(sc->sc_dmat, size, 1, size,
194 1.3.2.2 nathanw 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &sc->sc_fibs_dmamap)) != 0) {
195 1.3.2.2 nathanw printf("%s: cannot create fibs dmamap\n",
196 1.3.2.2 nathanw sc->sc_dv.dv_xname);
197 1.3.2.2 nathanw goto bail_out;
198 1.3.2.2 nathanw }
199 1.3.2.2 nathanw state++;
200 1.3.2.2 nathanw if ((rv = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0,
201 1.3.2.2 nathanw &sc->sc_fibs_seg, 1, &nsegs, BUS_DMA_NOWAIT)) != 0) {
202 1.3.2.2 nathanw printf("%s: can't allocate fibs structure\n",
203 1.3.2.2 nathanw sc->sc_dv.dv_xname);
204 1.3.2.2 nathanw goto bail_out;
205 1.3.2.2 nathanw }
206 1.3.2.2 nathanw state++;
207 1.3.2.2 nathanw if ((rv = bus_dmamem_map(sc->sc_dmat, &sc->sc_fibs_seg, nsegs, size,
208 1.3.2.2 nathanw (caddr_t *)&sc->sc_fibs, 0)) != 0) {
209 1.3.2.2 nathanw printf("%s: can't map fibs structure\n",
210 1.3.2.2 nathanw sc->sc_dv.dv_xname);
211 1.3.2.2 nathanw goto bail_out;
212 1.3.2.2 nathanw }
213 1.3.2.2 nathanw state++;
214 1.3.2.2 nathanw if ((rv = bus_dmamap_load(sc->sc_dmat, sc->sc_fibs_dmamap, sc->sc_fibs,
215 1.3.2.2 nathanw size, NULL, BUS_DMA_NOWAIT)) != 0) {
216 1.3.2.2 nathanw printf("%s: cannot load fibs dmamap\n", sc->sc_dv.dv_xname);
217 1.3.2.2 nathanw goto bail_out;
218 1.3.2.2 nathanw }
219 1.3.2.2 nathanw state++;
220 1.3.2.2 nathanw
221 1.3.2.2 nathanw memset(sc->sc_fibs, 0, size);
222 1.3.2.2 nathanw fibpa = sc->sc_fibs_seg.ds_addr;
223 1.3.2.2 nathanw fib = sc->sc_fibs;
224 1.3.2.2 nathanw
225 1.3.2.2 nathanw for (i = 0, ac = sc->sc_ccbs; i < AAC_NCCBS; i++, ac++) {
226 1.3.2.2 nathanw rv = bus_dmamap_create(sc->sc_dmat, AAC_MAX_XFER,
227 1.3.2.2 nathanw AAC_MAX_SGENTRIES, AAC_MAX_XFER, 0,
228 1.3.2.2 nathanw BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &ac->ac_dmamap_xfer);
229 1.3.2.2 nathanw if (rv) {
230 1.3.2.2 nathanw while (--ac >= sc->sc_ccbs)
231 1.3.2.2 nathanw bus_dmamap_destroy(sc->sc_dmat,
232 1.3.2.2 nathanw ac->ac_dmamap_xfer);
233 1.3.2.2 nathanw printf("%s: cannot create ccb dmamap (%d)",
234 1.3.2.2 nathanw sc->sc_dv.dv_xname, rv);
235 1.3.2.2 nathanw goto bail_out;
236 1.3.2.2 nathanw }
237 1.3.2.2 nathanw
238 1.3.2.2 nathanw ac->ac_fib = fib++;
239 1.3.2.2 nathanw ac->ac_fibphys = fibpa;
240 1.3.2.2 nathanw fibpa += sizeof(*fib);
241 1.3.2.2 nathanw aac_ccb_free(sc, ac);
242 1.3.2.2 nathanw }
243 1.3.2.2 nathanw
244 1.3.2.2 nathanw /*
245 1.3.2.2 nathanw * Attach devices.
246 1.3.2.2 nathanw */
247 1.3.2.2 nathanw for (i = 0; i < AAC_MAX_CONTAINERS; i++) {
248 1.3.2.2 nathanw if (!sc->sc_hdr[i].hd_present)
249 1.3.2.2 nathanw continue;
250 1.3.2.2 nathanw aaca.aaca_unit = i;
251 1.3.2.2 nathanw config_found_sm(&sc->sc_dv, &aaca, aac_print, aac_submatch);
252 1.3.2.2 nathanw }
253 1.3.2.2 nathanw
254 1.3.2.2 nathanw /*
255 1.3.2.2 nathanw * Enable interrupts, and register our shutdown hook.
256 1.3.2.2 nathanw */
257 1.3.2.2 nathanw sc->sc_flags |= AAC_ONLINE;
258 1.3.2.2 nathanw AAC_UNMASK_INTERRUPTS(sc);
259 1.3.2.2 nathanw if (aac_sdh != NULL)
260 1.3.2.2 nathanw shutdownhook_establish(aac_shutdown, NULL);
261 1.3.2.2 nathanw return (0);
262 1.3.2.2 nathanw
263 1.3.2.2 nathanw bail_out:
264 1.3.2.2 nathanw bus_dmamap_unload(sc->sc_dmat, sc->sc_common_dmamap);
265 1.3.2.2 nathanw bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_common,
266 1.3.2.2 nathanw sizeof(*sc->sc_common));
267 1.3.2.2 nathanw bus_dmamem_free(sc->sc_dmat, &sc->sc_common_seg, 1);
268 1.3.2.2 nathanw bus_dmamap_destroy(sc->sc_dmat, sc->sc_common_dmamap);
269 1.3.2.2 nathanw
270 1.3.2.2 nathanw if (state > 3)
271 1.3.2.2 nathanw bus_dmamap_unload(sc->sc_dmat, sc->sc_fibs_dmamap);
272 1.3.2.2 nathanw if (state > 2)
273 1.3.2.2 nathanw bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_fibs, size);
274 1.3.2.2 nathanw if (state > 1)
275 1.3.2.2 nathanw bus_dmamem_free(sc->sc_dmat, &sc->sc_fibs_seg, 1);
276 1.3.2.2 nathanw if (state > 0)
277 1.3.2.2 nathanw bus_dmamap_destroy(sc->sc_dmat, sc->sc_fibs_dmamap);
278 1.3.2.2 nathanw
279 1.3.2.2 nathanw free(sc->sc_ccbs, M_DEVBUF);
280 1.3.2.2 nathanw return (rv);
281 1.3.2.2 nathanw }
282 1.3.2.2 nathanw
283 1.3.2.2 nathanw /*
284 1.3.2.2 nathanw * Print autoconfiguration message for a sub-device.
285 1.3.2.2 nathanw */
286 1.3.2.2 nathanw int
287 1.3.2.2 nathanw aac_print(void *aux, const char *pnp)
288 1.3.2.2 nathanw {
289 1.3.2.2 nathanw struct aac_attach_args *aaca;
290 1.3.2.2 nathanw
291 1.3.2.2 nathanw aaca = aux;
292 1.3.2.2 nathanw
293 1.3.2.2 nathanw if (pnp != NULL)
294 1.3.2.4 thorpej aprint_normal("block device at %s", pnp);
295 1.3.2.4 thorpej aprint_normal(" unit %d", aaca->aaca_unit);
296 1.3.2.2 nathanw return (UNCONF);
297 1.3.2.2 nathanw }
298 1.3.2.2 nathanw
299 1.3.2.2 nathanw /*
300 1.3.2.2 nathanw * Match a sub-device.
301 1.3.2.2 nathanw */
302 1.3.2.2 nathanw int
303 1.3.2.2 nathanw aac_submatch(struct device *parent, struct cfdata *cf, void *aux)
304 1.3.2.2 nathanw {
305 1.3.2.2 nathanw struct aac_attach_args *aaca;
306 1.3.2.2 nathanw
307 1.3.2.2 nathanw aaca = aux;
308 1.3.2.2 nathanw
309 1.3.2.2 nathanw if (cf->aaccf_unit != AACCF_UNIT_DEFAULT &&
310 1.3.2.2 nathanw cf->aaccf_unit != aaca->aaca_unit)
311 1.3.2.2 nathanw return (0);
312 1.3.2.2 nathanw
313 1.3.2.3 nathanw return (config_match(parent, cf, aux));
314 1.3.2.2 nathanw }
315 1.3.2.2 nathanw
316 1.3.2.2 nathanw /*
317 1.3.2.2 nathanw * Look up a text description of a numeric error code and return a pointer to
318 1.3.2.2 nathanw * same.
319 1.3.2.2 nathanw */
320 1.3.2.2 nathanw const char *
321 1.3.2.2 nathanw aac_describe_code(const struct aac_code_lookup *table, u_int32_t code)
322 1.3.2.2 nathanw {
323 1.3.2.2 nathanw int i;
324 1.3.2.2 nathanw
325 1.3.2.2 nathanw for (i = 0; table[i].string != NULL; i++)
326 1.3.2.2 nathanw if (table[i].code == code)
327 1.3.2.2 nathanw return (table[i].string);
328 1.3.2.2 nathanw
329 1.3.2.2 nathanw return (table[i + 1].string);
330 1.3.2.2 nathanw }
331 1.3.2.2 nathanw
332 1.3.2.2 nathanw void
333 1.3.2.2 nathanw aac_describe_controller(struct aac_softc *sc)
334 1.3.2.2 nathanw {
335 1.3.2.2 nathanw u_int8_t buf[AAC_FIB_DATASIZE];
336 1.3.2.2 nathanw u_int16_t bufsize;
337 1.3.2.2 nathanw struct aac_adapter_info *info;
338 1.3.2.2 nathanw u_int8_t arg;
339 1.3.2.2 nathanw
340 1.3.2.2 nathanw arg = 0;
341 1.3.2.2 nathanw if (aac_sync_fib(sc, RequestAdapterInfo, 0, &arg, sizeof(arg), &buf,
342 1.3.2.2 nathanw &bufsize)) {
343 1.3.2.2 nathanw printf("%s: RequestAdapterInfo failed\n", sc->sc_dv.dv_xname);
344 1.3.2.2 nathanw return;
345 1.3.2.2 nathanw }
346 1.3.2.2 nathanw if (bufsize != sizeof(*info)) {
347 1.3.2.2 nathanw printf("%s: "
348 1.3.2.2 nathanw "RequestAdapterInfo returned wrong data size (%d != %d)\n",
349 1.3.2.2 nathanw sc->sc_dv.dv_xname, bufsize, sizeof(*info));
350 1.3.2.2 nathanw return;
351 1.3.2.2 nathanw }
352 1.3.2.2 nathanw info = (struct aac_adapter_info *)&buf[0];
353 1.3.2.2 nathanw
354 1.3.2.2 nathanw printf("%s: %s at %dMHz, %dMB cache, %s, kernel %d.%d-%d\n",
355 1.3.2.2 nathanw sc->sc_dv.dv_xname,
356 1.3.2.2 nathanw aac_describe_code(aac_cpu_variant, le32toh(info->CpuVariant)),
357 1.3.2.2 nathanw le32toh(info->ClockSpeed),
358 1.3.2.2 nathanw le32toh(info->BufferMem) / (1024 * 1024),
359 1.3.2.2 nathanw aac_describe_code(aac_battery_platform,
360 1.3.2.2 nathanw le32toh(info->batteryPlatform)),
361 1.3.2.2 nathanw info->KernelRevision.external.comp.major,
362 1.3.2.2 nathanw info->KernelRevision.external.comp.minor,
363 1.3.2.2 nathanw info->KernelRevision.external.comp.dash);
364 1.3.2.2 nathanw
365 1.3.2.2 nathanw /* Save the kernel revision structure for later use. */
366 1.3.2.2 nathanw sc->sc_revision = info->KernelRevision;
367 1.3.2.2 nathanw }
368 1.3.2.2 nathanw
369 1.3.2.2 nathanw /*
370 1.3.2.2 nathanw * Retrieve the firmware version numbers. Dell PERC2/QC cards with firmware
371 1.3.2.2 nathanw * version 1.x are not compatible with this driver.
372 1.3.2.2 nathanw */
373 1.3.2.2 nathanw int
374 1.3.2.2 nathanw aac_check_firmware(struct aac_softc *sc)
375 1.3.2.2 nathanw {
376 1.3.2.2 nathanw u_int32_t major, minor;
377 1.3.2.2 nathanw
378 1.3.2.2 nathanw if ((sc->sc_quirks & AAC_QUIRK_PERC2QC) != 0) {
379 1.3.2.2 nathanw if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0,
380 1.3.2.2 nathanw NULL)) {
381 1.3.2.2 nathanw printf("%s: error reading firmware version\n",
382 1.3.2.2 nathanw sc->sc_dv.dv_xname);
383 1.3.2.2 nathanw return (1);
384 1.3.2.2 nathanw }
385 1.3.2.2 nathanw
386 1.3.2.2 nathanw /* These numbers are stored as ASCII! */
387 1.3.2.2 nathanw major = (AAC_GETREG4(sc, AAC_SA_MAILBOX + 4) & 0xff) - 0x30;
388 1.3.2.2 nathanw minor = (AAC_GETREG4(sc, AAC_SA_MAILBOX + 8) & 0xff) - 0x30;
389 1.3.2.2 nathanw if (major == 1) {
390 1.3.2.2 nathanw printf("%s: firmware version %d.%d not supported.\n",
391 1.3.2.2 nathanw sc->sc_dv.dv_xname, major, minor);
392 1.3.2.2 nathanw return (1);
393 1.3.2.2 nathanw }
394 1.3.2.2 nathanw }
395 1.3.2.2 nathanw
396 1.3.2.2 nathanw return (0);
397 1.3.2.2 nathanw }
398 1.3.2.2 nathanw
399 1.3.2.2 nathanw int
400 1.3.2.2 nathanw aac_init(struct aac_softc *sc)
401 1.3.2.2 nathanw {
402 1.3.2.2 nathanw int nsegs, i, rv, state, norm, high;
403 1.3.2.2 nathanw struct aac_adapter_init *ip;
404 1.3.2.2 nathanw u_int32_t code;
405 1.3.2.2 nathanw u_int8_t *qaddr;
406 1.3.2.2 nathanw
407 1.3.2.2 nathanw state = 0;
408 1.3.2.2 nathanw
409 1.3.2.2 nathanw /*
410 1.3.2.2 nathanw * First wait for the adapter to come ready.
411 1.3.2.2 nathanw */
412 1.3.2.2 nathanw for (i = 0; i < AAC_BOOT_TIMEOUT * 1000; i++) {
413 1.3.2.2 nathanw code = AAC_GET_FWSTATUS(sc);
414 1.3.2.2 nathanw if ((code & AAC_SELF_TEST_FAILED) != 0) {
415 1.3.2.2 nathanw printf("%s: FATAL: selftest failed\n",
416 1.3.2.2 nathanw sc->sc_dv.dv_xname);
417 1.3.2.2 nathanw return (ENXIO);
418 1.3.2.2 nathanw }
419 1.3.2.2 nathanw if ((code & AAC_KERNEL_PANIC) != 0) {
420 1.3.2.2 nathanw printf("%s: FATAL: controller kernel panic\n",
421 1.3.2.2 nathanw sc->sc_dv.dv_xname);
422 1.3.2.2 nathanw return (ENXIO);
423 1.3.2.2 nathanw }
424 1.3.2.2 nathanw if ((code & AAC_UP_AND_RUNNING) != 0)
425 1.3.2.2 nathanw break;
426 1.3.2.2 nathanw DELAY(1000);
427 1.3.2.2 nathanw }
428 1.3.2.2 nathanw if (i == AAC_BOOT_TIMEOUT * 1000) {
429 1.3.2.2 nathanw printf("%s: FATAL: controller not coming ready, status %x\n",
430 1.3.2.2 nathanw sc->sc_dv.dv_xname, code);
431 1.3.2.2 nathanw return (ENXIO);
432 1.3.2.2 nathanw }
433 1.3.2.2 nathanw
434 1.3.2.2 nathanw if ((rv = bus_dmamap_create(sc->sc_dmat, sizeof(*sc->sc_common), 1,
435 1.3.2.2 nathanw sizeof(*sc->sc_common), 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
436 1.3.2.2 nathanw &sc->sc_common_dmamap)) != 0) {
437 1.3.2.2 nathanw printf("%s: cannot create common dmamap\n",
438 1.3.2.2 nathanw sc->sc_dv.dv_xname);
439 1.3.2.2 nathanw return (rv);
440 1.3.2.2 nathanw }
441 1.3.2.2 nathanw if ((rv = bus_dmamem_alloc(sc->sc_dmat, sizeof(*sc->sc_common),
442 1.3.2.2 nathanw PAGE_SIZE, 0, &sc->sc_common_seg, 1, &nsegs,
443 1.3.2.2 nathanw BUS_DMA_NOWAIT)) != 0) {
444 1.3.2.2 nathanw printf("%s: can't allocate common structure\n",
445 1.3.2.2 nathanw sc->sc_dv.dv_xname);
446 1.3.2.2 nathanw goto bail_out;
447 1.3.2.2 nathanw }
448 1.3.2.2 nathanw state++;
449 1.3.2.2 nathanw if ((rv = bus_dmamem_map(sc->sc_dmat, &sc->sc_common_seg, nsegs,
450 1.3.2.2 nathanw sizeof(*sc->sc_common), (caddr_t *)&sc->sc_common, 0)) != 0) {
451 1.3.2.2 nathanw printf("%s: can't map common structure\n",
452 1.3.2.2 nathanw sc->sc_dv.dv_xname);
453 1.3.2.2 nathanw goto bail_out;
454 1.3.2.2 nathanw }
455 1.3.2.2 nathanw state++;
456 1.3.2.2 nathanw if ((rv = bus_dmamap_load(sc->sc_dmat, sc->sc_common_dmamap,
457 1.3.2.2 nathanw sc->sc_common, sizeof(*sc->sc_common), NULL,
458 1.3.2.2 nathanw BUS_DMA_NOWAIT)) != 0) {
459 1.3.2.2 nathanw printf("%s: cannot load common dmamap\n", sc->sc_dv.dv_xname);
460 1.3.2.2 nathanw goto bail_out;
461 1.3.2.2 nathanw }
462 1.3.2.2 nathanw state++;
463 1.3.2.2 nathanw
464 1.3.2.2 nathanw memset(sc->sc_common, 0, sizeof(*sc->sc_common));
465 1.3.2.2 nathanw
466 1.3.2.2 nathanw /*
467 1.3.2.2 nathanw * Fill in the init structure. This tells the adapter about the
468 1.3.2.2 nathanw * physical location of various important shared data structures.
469 1.3.2.2 nathanw */
470 1.3.2.2 nathanw ip = &sc->sc_common->ac_init;
471 1.3.2.2 nathanw ip->InitStructRevision = htole32(AAC_INIT_STRUCT_REVISION);
472 1.3.2.2 nathanw
473 1.3.2.2 nathanw ip->AdapterFibsPhysicalAddress = htole32(sc->sc_common_seg.ds_addr +
474 1.3.2.2 nathanw offsetof(struct aac_common, ac_fibs));
475 1.3.2.2 nathanw ip->AdapterFibsVirtualAddress = htole32(&sc->sc_common->ac_fibs[0]);
476 1.3.2.2 nathanw ip->AdapterFibsSize =
477 1.3.2.2 nathanw htole32(AAC_ADAPTER_FIBS * sizeof(struct aac_fib));
478 1.3.2.2 nathanw ip->AdapterFibAlign = htole32(sizeof(struct aac_fib));
479 1.3.2.2 nathanw
480 1.3.2.2 nathanw ip->PrintfBufferAddress = htole32(sc->sc_common_seg.ds_addr +
481 1.3.2.2 nathanw offsetof(struct aac_common, ac_printf));
482 1.3.2.2 nathanw ip->PrintfBufferSize = htole32(AAC_PRINTF_BUFSIZE);
483 1.3.2.2 nathanw
484 1.3.2.2 nathanw ip->HostPhysMemPages = 0; /* not used? */
485 1.3.2.2 nathanw ip->HostElapsedSeconds = 0; /* reset later if invalid */
486 1.3.2.2 nathanw
487 1.3.2.2 nathanw /*
488 1.3.2.2 nathanw * Initialise FIB queues. Note that it appears that the layout of
489 1.3.2.2 nathanw * the indexes and the segmentation of the entries is mandated by
490 1.3.2.2 nathanw * the adapter, which is only told about the base of the queue index
491 1.3.2.2 nathanw * fields.
492 1.3.2.2 nathanw *
493 1.3.2.2 nathanw * The initial values of the indices are assumed to inform the
494 1.3.2.2 nathanw * adapter of the sizes of the respective queues.
495 1.3.2.2 nathanw *
496 1.3.2.2 nathanw * The Linux driver uses a much more complex scheme whereby several
497 1.3.2.2 nathanw * header records are kept for each queue. We use a couple of
498 1.3.2.2 nathanw * generic list manipulation functions which 'know' the size of each
499 1.3.2.2 nathanw * list by virtue of a table.
500 1.3.2.2 nathanw */
501 1.3.2.2 nathanw qaddr = &sc->sc_common->ac_qbuf[0] + AAC_QUEUE_ALIGN;
502 1.3.2.2 nathanw qaddr -= (u_int32_t)qaddr % AAC_QUEUE_ALIGN; /* XXX not portable */
503 1.3.2.2 nathanw sc->sc_queues = (struct aac_queue_table *)qaddr;
504 1.3.2.2 nathanw ip->CommHeaderAddress = htole32(sc->sc_common_seg.ds_addr +
505 1.3.2.2 nathanw ((caddr_t)sc->sc_queues - (caddr_t)sc->sc_common));
506 1.3.2.2 nathanw memset(sc->sc_queues, 0, sizeof(struct aac_queue_table));
507 1.3.2.2 nathanw
508 1.3.2.2 nathanw norm = htole32(AAC_HOST_NORM_CMD_ENTRIES);
509 1.3.2.2 nathanw high = htole32(AAC_HOST_HIGH_CMD_ENTRIES);
510 1.3.2.2 nathanw
511 1.3.2.2 nathanw sc->sc_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
512 1.3.2.2 nathanw norm;
513 1.3.2.2 nathanw sc->sc_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
514 1.3.2.2 nathanw norm;
515 1.3.2.2 nathanw sc->sc_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
516 1.3.2.2 nathanw high;
517 1.3.2.2 nathanw sc->sc_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
518 1.3.2.2 nathanw high;
519 1.3.2.2 nathanw
520 1.3.2.2 nathanw norm = htole32(AAC_ADAP_NORM_CMD_ENTRIES);
521 1.3.2.2 nathanw high = htole32(AAC_ADAP_HIGH_CMD_ENTRIES);
522 1.3.2.2 nathanw
523 1.3.2.2 nathanw sc->sc_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
524 1.3.2.2 nathanw norm;
525 1.3.2.2 nathanw sc->sc_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] =
526 1.3.2.2 nathanw norm;
527 1.3.2.2 nathanw sc->sc_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] =
528 1.3.2.2 nathanw high;
529 1.3.2.2 nathanw sc->sc_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] =
530 1.3.2.2 nathanw high;
531 1.3.2.2 nathanw
532 1.3.2.2 nathanw norm = htole32(AAC_HOST_NORM_RESP_ENTRIES);
533 1.3.2.2 nathanw high = htole32(AAC_HOST_HIGH_RESP_ENTRIES);
534 1.3.2.2 nathanw
535 1.3.2.2 nathanw sc->sc_queues->
536 1.3.2.2 nathanw qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX] = norm;
537 1.3.2.2 nathanw sc->sc_queues->
538 1.3.2.2 nathanw qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX] = norm;
539 1.3.2.2 nathanw sc->sc_queues->
540 1.3.2.2 nathanw qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX] = high;
541 1.3.2.2 nathanw sc->sc_queues->
542 1.3.2.2 nathanw qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX] = high;
543 1.3.2.2 nathanw
544 1.3.2.2 nathanw norm = htole32(AAC_ADAP_NORM_RESP_ENTRIES);
545 1.3.2.2 nathanw high = htole32(AAC_ADAP_HIGH_RESP_ENTRIES);
546 1.3.2.2 nathanw
547 1.3.2.2 nathanw sc->sc_queues->
548 1.3.2.2 nathanw qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX] = norm;
549 1.3.2.2 nathanw sc->sc_queues->
550 1.3.2.2 nathanw qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX] = norm;
551 1.3.2.2 nathanw sc->sc_queues->
552 1.3.2.2 nathanw qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX] = high;
553 1.3.2.2 nathanw sc->sc_queues->
554 1.3.2.2 nathanw qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX] = high;
555 1.3.2.2 nathanw
556 1.3.2.2 nathanw sc->sc_qentries[AAC_HOST_NORM_CMD_QUEUE] =
557 1.3.2.2 nathanw &sc->sc_queues->qt_HostNormCmdQueue[0];
558 1.3.2.2 nathanw sc->sc_qentries[AAC_HOST_HIGH_CMD_QUEUE] =
559 1.3.2.2 nathanw &sc->sc_queues->qt_HostHighCmdQueue[0];
560 1.3.2.2 nathanw sc->sc_qentries[AAC_ADAP_NORM_CMD_QUEUE] =
561 1.3.2.2 nathanw &sc->sc_queues->qt_AdapNormCmdQueue[0];
562 1.3.2.2 nathanw sc->sc_qentries[AAC_ADAP_HIGH_CMD_QUEUE] =
563 1.3.2.2 nathanw &sc->sc_queues->qt_AdapHighCmdQueue[0];
564 1.3.2.2 nathanw sc->sc_qentries[AAC_HOST_NORM_RESP_QUEUE] =
565 1.3.2.2 nathanw &sc->sc_queues->qt_HostNormRespQueue[0];
566 1.3.2.2 nathanw sc->sc_qentries[AAC_HOST_HIGH_RESP_QUEUE] =
567 1.3.2.2 nathanw &sc->sc_queues->qt_HostHighRespQueue[0];
568 1.3.2.2 nathanw sc->sc_qentries[AAC_ADAP_NORM_RESP_QUEUE] =
569 1.3.2.2 nathanw &sc->sc_queues->qt_AdapNormRespQueue[0];
570 1.3.2.2 nathanw sc->sc_qentries[AAC_ADAP_HIGH_RESP_QUEUE] =
571 1.3.2.2 nathanw &sc->sc_queues->qt_AdapHighRespQueue[0];
572 1.3.2.2 nathanw
573 1.3.2.2 nathanw /*
574 1.3.2.2 nathanw * Do controller-type-specific initialisation
575 1.3.2.2 nathanw */
576 1.3.2.2 nathanw switch (sc->sc_hwif) {
577 1.3.2.2 nathanw case AAC_HWIF_I960RX:
578 1.3.2.2 nathanw AAC_SETREG4(sc, AAC_RX_ODBR, ~0);
579 1.3.2.2 nathanw break;
580 1.3.2.2 nathanw }
581 1.3.2.2 nathanw
582 1.3.2.2 nathanw bus_dmamap_sync(sc->sc_dmat, sc->sc_common_dmamap, 0,
583 1.3.2.2 nathanw sizeof(*sc->sc_common),
584 1.3.2.2 nathanw BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
585 1.3.2.2 nathanw
586 1.3.2.2 nathanw /*
587 1.3.2.2 nathanw * Give the init structure to the controller.
588 1.3.2.2 nathanw */
589 1.3.2.2 nathanw if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT,
590 1.3.2.2 nathanw sc->sc_common_seg.ds_addr + offsetof(struct aac_common, ac_init),
591 1.3.2.2 nathanw 0, 0, 0, NULL)) {
592 1.3.2.2 nathanw printf("%s: error establishing init structure\n",
593 1.3.2.2 nathanw sc->sc_dv.dv_xname);
594 1.3.2.2 nathanw rv = EIO;
595 1.3.2.2 nathanw goto bail_out;
596 1.3.2.2 nathanw }
597 1.3.2.2 nathanw
598 1.3.2.2 nathanw return (0);
599 1.3.2.2 nathanw
600 1.3.2.2 nathanw bail_out:
601 1.3.2.2 nathanw if (state > 2)
602 1.3.2.2 nathanw bus_dmamap_unload(sc->sc_dmat, sc->sc_common_dmamap);
603 1.3.2.2 nathanw if (state > 1)
604 1.3.2.2 nathanw bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_common,
605 1.3.2.2 nathanw sizeof(*sc->sc_common));
606 1.3.2.2 nathanw if (state > 0)
607 1.3.2.2 nathanw bus_dmamem_free(sc->sc_dmat, &sc->sc_common_seg, 1);
608 1.3.2.2 nathanw bus_dmamap_destroy(sc->sc_dmat, sc->sc_common_dmamap);
609 1.3.2.2 nathanw
610 1.3.2.2 nathanw return (rv);
611 1.3.2.2 nathanw }
612 1.3.2.2 nathanw
613 1.3.2.2 nathanw /*
614 1.3.2.2 nathanw * Probe for containers, create disks.
615 1.3.2.2 nathanw */
616 1.3.2.2 nathanw void
617 1.3.2.2 nathanw aac_startup(struct aac_softc *sc)
618 1.3.2.2 nathanw {
619 1.3.2.2 nathanw struct aac_mntinfo mi;
620 1.3.2.2 nathanw struct aac_mntinforesponse mir;
621 1.3.2.2 nathanw struct aac_drive *hd;
622 1.3.2.2 nathanw u_int16_t rsize;
623 1.3.2.2 nathanw int i;
624 1.3.2.2 nathanw
625 1.3.2.2 nathanw /*
626 1.3.2.2 nathanw * Loop over possible containers.
627 1.3.2.2 nathanw */
628 1.3.2.2 nathanw mi.Command = htole32(VM_NameServe);
629 1.3.2.2 nathanw mi.MntType = htole32(FT_FILESYS);
630 1.3.2.2 nathanw hd = sc->sc_hdr;
631 1.3.2.2 nathanw
632 1.3.2.2 nathanw for (i = 0; i < AAC_MAX_CONTAINERS; i++, hd++) {
633 1.3.2.2 nathanw /*
634 1.3.2.2 nathanw * Request information on this container.
635 1.3.2.2 nathanw */
636 1.3.2.2 nathanw mi.MntCount = htole32(i);
637 1.3.2.2 nathanw if (aac_sync_fib(sc, ContainerCommand, 0, &mi, sizeof(mi), &mir,
638 1.3.2.2 nathanw &rsize)) {
639 1.3.2.2 nathanw printf("%s: error probing container %d\n",
640 1.3.2.2 nathanw sc->sc_dv.dv_xname, i);
641 1.3.2.2 nathanw continue;
642 1.3.2.2 nathanw }
643 1.3.2.2 nathanw if (rsize != sizeof(mir)) {
644 1.3.2.2 nathanw printf("%s: container info response wrong size "
645 1.3.2.2 nathanw "(%d should be %d)\n",
646 1.3.2.2 nathanw sc->sc_dv.dv_xname, rsize, sizeof(mir));
647 1.3.2.2 nathanw continue;
648 1.3.2.2 nathanw }
649 1.3.2.2 nathanw
650 1.3.2.2 nathanw /*
651 1.3.2.2 nathanw * Check container volume type for validity. Note that many
652 1.3.2.2 nathanw * of the possible types may never show up.
653 1.3.2.2 nathanw */
654 1.3.2.2 nathanw if (le32toh(mir.Status) != ST_OK ||
655 1.3.2.2 nathanw le32toh(mir.MntTable[0].VolType) == CT_NONE)
656 1.3.2.2 nathanw continue;
657 1.3.2.2 nathanw
658 1.3.2.2 nathanw hd->hd_present = 1;
659 1.3.2.2 nathanw hd->hd_size = le32toh(mir.MntTable[0].Capacity);
660 1.3.2.2 nathanw hd->hd_devtype = le32toh(mir.MntTable[0].VolType);
661 1.3.2.2 nathanw hd->hd_size &= ~0x1f;
662 1.3.2.2 nathanw sc->sc_nunits++;
663 1.3.2.2 nathanw }
664 1.3.2.2 nathanw }
665 1.3.2.2 nathanw
666 1.3.2.2 nathanw void
667 1.3.2.2 nathanw aac_shutdown(void *cookie)
668 1.3.2.2 nathanw {
669 1.3.2.2 nathanw struct aac_softc *sc;
670 1.3.2.2 nathanw struct aac_close_command cc;
671 1.3.2.2 nathanw u_int32_t i;
672 1.3.2.2 nathanw
673 1.3.2.2 nathanw for (i = 0; i < aac_cd.cd_ndevs; i++) {
674 1.3.2.2 nathanw if ((sc = device_lookup(&aac_cd, i)) == NULL)
675 1.3.2.2 nathanw continue;
676 1.3.2.2 nathanw if ((sc->sc_flags & AAC_ONLINE) == 0)
677 1.3.2.2 nathanw continue;
678 1.3.2.2 nathanw
679 1.3.2.2 nathanw AAC_MASK_INTERRUPTS(sc);
680 1.3.2.2 nathanw
681 1.3.2.2 nathanw /*
682 1.3.2.2 nathanw * Send a Container shutdown followed by a HostShutdown FIB
683 1.3.2.2 nathanw * to the controller to convince it that we don't want to
684 1.3.2.2 nathanw * talk to it anymore. We've been closed and all I/O
685 1.3.2.2 nathanw * completed already
686 1.3.2.2 nathanw */
687 1.3.2.2 nathanw cc.Command = htole32(VM_CloseAll);
688 1.3.2.2 nathanw cc.ContainerId = 0xffffffff;
689 1.3.2.2 nathanw if (aac_sync_fib(sc, ContainerCommand, 0, &cc, sizeof(cc),
690 1.3.2.2 nathanw NULL, NULL)) {
691 1.3.2.2 nathanw printf("%s: unable to halt controller\n",
692 1.3.2.2 nathanw sc->sc_dv.dv_xname);
693 1.3.2.2 nathanw continue;
694 1.3.2.2 nathanw }
695 1.3.2.2 nathanw
696 1.3.2.2 nathanw /*
697 1.3.2.2 nathanw * Note that issuing this command to the controller makes it
698 1.3.2.2 nathanw * shut down but also keeps it from coming back up without a
699 1.3.2.2 nathanw * reset of the PCI bus.
700 1.3.2.2 nathanw */
701 1.3.2.2 nathanw if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN,
702 1.3.2.2 nathanw &i, sizeof(i), NULL, NULL))
703 1.3.2.2 nathanw printf("%s: unable to halt controller\n",
704 1.3.2.2 nathanw sc->sc_dv.dv_xname);
705 1.3.2.2 nathanw }
706 1.3.2.2 nathanw }
707 1.3.2.2 nathanw
708 1.3.2.2 nathanw /*
709 1.3.2.2 nathanw * Take an interrupt.
710 1.3.2.2 nathanw */
711 1.3.2.2 nathanw int
712 1.3.2.2 nathanw aac_intr(void *cookie)
713 1.3.2.2 nathanw {
714 1.3.2.2 nathanw struct aac_softc *sc;
715 1.3.2.2 nathanw u_int16_t reason;
716 1.3.2.2 nathanw int claimed;
717 1.3.2.2 nathanw
718 1.3.2.2 nathanw sc = cookie;
719 1.3.2.2 nathanw claimed = 0;
720 1.3.2.2 nathanw
721 1.3.2.2 nathanw AAC_DPRINTF(AAC_D_INTR, ("aac_intr(%p) ", sc));
722 1.3.2.2 nathanw
723 1.3.2.2 nathanw reason = AAC_GET_ISTATUS(sc);
724 1.3.2.2 nathanw AAC_DPRINTF(AAC_D_INTR, ("istatus 0x%04x ", reason));
725 1.3.2.2 nathanw
726 1.3.2.2 nathanw /*
727 1.3.2.2 nathanw * Controller wants to talk to the log. XXX Should we defer this?
728 1.3.2.2 nathanw */
729 1.3.2.2 nathanw if ((reason & AAC_DB_PRINTF) != 0) {
730 1.3.2.2 nathanw if (sc->sc_common->ac_printf[0] != '\0') {
731 1.3.2.2 nathanw printf("%s: WARNING: adapter logged message:\n",
732 1.3.2.2 nathanw sc->sc_dv.dv_xname);
733 1.3.2.2 nathanw printf("%s: %.*s", sc->sc_dv.dv_xname,
734 1.3.2.2 nathanw AAC_PRINTF_BUFSIZE, sc->sc_common->ac_printf);
735 1.3.2.2 nathanw sc->sc_common->ac_printf[0] = '\0';
736 1.3.2.2 nathanw }
737 1.3.2.2 nathanw AAC_CLEAR_ISTATUS(sc, AAC_DB_PRINTF);
738 1.3.2.2 nathanw AAC_QNOTIFY(sc, AAC_DB_PRINTF);
739 1.3.2.2 nathanw claimed = 1;
740 1.3.2.2 nathanw }
741 1.3.2.2 nathanw
742 1.3.2.2 nathanw /*
743 1.3.2.2 nathanw * Controller has a message for us?
744 1.3.2.2 nathanw */
745 1.3.2.2 nathanw if ((reason & AAC_DB_COMMAND_READY) != 0) {
746 1.3.2.2 nathanw aac_host_command(sc);
747 1.3.2.2 nathanw AAC_CLEAR_ISTATUS(sc, AAC_DB_COMMAND_READY);
748 1.3.2.2 nathanw claimed = 1;
749 1.3.2.2 nathanw }
750 1.3.2.2 nathanw
751 1.3.2.2 nathanw /*
752 1.3.2.2 nathanw * Controller has a response for us?
753 1.3.2.2 nathanw */
754 1.3.2.2 nathanw if ((reason & AAC_DB_RESPONSE_READY) != 0) {
755 1.3.2.2 nathanw aac_host_response(sc);
756 1.3.2.2 nathanw AAC_CLEAR_ISTATUS(sc, AAC_DB_RESPONSE_READY);
757 1.3.2.2 nathanw claimed = 1;
758 1.3.2.2 nathanw }
759 1.3.2.2 nathanw
760 1.3.2.2 nathanw /*
761 1.3.2.2 nathanw * Spurious interrupts that we don't use - reset the mask and clear
762 1.3.2.2 nathanw * the interrupts.
763 1.3.2.2 nathanw */
764 1.3.2.2 nathanw if ((reason & (AAC_DB_SYNC_COMMAND | AAC_DB_COMMAND_NOT_FULL |
765 1.3.2.2 nathanw AAC_DB_RESPONSE_NOT_FULL)) != 0) {
766 1.3.2.2 nathanw AAC_UNMASK_INTERRUPTS(sc);
767 1.3.2.2 nathanw AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND |
768 1.3.2.2 nathanw AAC_DB_COMMAND_NOT_FULL | AAC_DB_RESPONSE_NOT_FULL);
769 1.3.2.2 nathanw claimed = 1;
770 1.3.2.2 nathanw }
771 1.3.2.2 nathanw
772 1.3.2.2 nathanw return (claimed);
773 1.3.2.2 nathanw }
774 1.3.2.2 nathanw
775 1.3.2.2 nathanw /*
776 1.3.2.2 nathanw * Handle notification of one or more FIBs coming from the controller.
777 1.3.2.2 nathanw */
778 1.3.2.2 nathanw void
779 1.3.2.2 nathanw aac_host_command(struct aac_softc *sc)
780 1.3.2.2 nathanw {
781 1.3.2.2 nathanw struct aac_fib *fib;
782 1.3.2.2 nathanw u_int32_t fib_size;
783 1.3.2.2 nathanw
784 1.3.2.2 nathanw for (;;) {
785 1.3.2.2 nathanw if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE, &fib_size,
786 1.3.2.2 nathanw &fib))
787 1.3.2.2 nathanw break; /* nothing to do */
788 1.3.2.2 nathanw
789 1.3.2.2 nathanw bus_dmamap_sync(sc->sc_dmat, sc->sc_common_dmamap,
790 1.3.2.2 nathanw (caddr_t)fib - (caddr_t)sc->sc_common, sizeof(*fib),
791 1.3.2.2 nathanw BUS_DMASYNC_POSTREAD);
792 1.3.2.2 nathanw
793 1.3.2.2 nathanw switch (le16toh(fib->Header.Command)) {
794 1.3.2.2 nathanw case AifRequest:
795 1.3.2.2 nathanw #ifdef notyet
796 1.3.2.2 nathanw aac_handle_aif(sc,
797 1.3.2.2 nathanw (struct aac_aif_command *)&fib->data[0]);
798 1.3.2.2 nathanw #endif
799 1.3.2.2 nathanw break;
800 1.3.2.2 nathanw default:
801 1.3.2.2 nathanw printf("%s: unknown command from controller\n",
802 1.3.2.2 nathanw sc->sc_dv.dv_xname);
803 1.3.2.2 nathanw AAC_PRINT_FIB(sc, fib);
804 1.3.2.2 nathanw break;
805 1.3.2.2 nathanw }
806 1.3.2.2 nathanw
807 1.3.2.2 nathanw bus_dmamap_sync(sc->sc_dmat, sc->sc_common_dmamap,
808 1.3.2.2 nathanw (caddr_t)fib - (caddr_t)sc->sc_common, sizeof(*fib),
809 1.3.2.2 nathanw BUS_DMASYNC_PREREAD);
810 1.3.2.2 nathanw
811 1.3.2.2 nathanw /* XXX reply to FIBs requesting responses ?? */
812 1.3.2.2 nathanw /* XXX how do we return these FIBs to the controller? */
813 1.3.2.2 nathanw }
814 1.3.2.2 nathanw }
815 1.3.2.2 nathanw
816 1.3.2.2 nathanw /*
817 1.3.2.2 nathanw * Handle notification of one or more FIBs completed by the controller
818 1.3.2.2 nathanw */
819 1.3.2.2 nathanw void
820 1.3.2.2 nathanw aac_host_response(struct aac_softc *sc)
821 1.3.2.2 nathanw {
822 1.3.2.2 nathanw struct aac_ccb *ac;
823 1.3.2.2 nathanw struct aac_fib *fib;
824 1.3.2.2 nathanw u_int32_t fib_size;
825 1.3.2.2 nathanw
826 1.3.2.2 nathanw /*
827 1.3.2.2 nathanw * Look for completed FIBs on our queue.
828 1.3.2.2 nathanw */
829 1.3.2.2 nathanw for (;;) {
830 1.3.2.2 nathanw if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size,
831 1.3.2.2 nathanw &fib))
832 1.3.2.2 nathanw break; /* nothing to do */
833 1.3.2.2 nathanw
834 1.3.2.2 nathanw bus_dmamap_sync(sc->sc_dmat, sc->sc_fibs_dmamap,
835 1.3.2.2 nathanw (caddr_t)fib - (caddr_t)sc->sc_fibs, sizeof(*fib),
836 1.3.2.2 nathanw BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
837 1.3.2.2 nathanw
838 1.3.2.2 nathanw if ((fib->Header.SenderData & 0x80000000) == 0) {
839 1.3.2.2 nathanw /* Not valid; not sent by us. */
840 1.3.2.2 nathanw AAC_PRINT_FIB(sc, fib);
841 1.3.2.2 nathanw } else {
842 1.3.2.2 nathanw ac = (struct aac_ccb *)((caddr_t)sc->sc_ccbs +
843 1.3.2.2 nathanw (fib->Header.SenderData & 0x7fffffff));
844 1.3.2.2 nathanw fib->Header.SenderData = 0;
845 1.3.2.2 nathanw SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_complete, ac, ac_chain);
846 1.3.2.2 nathanw }
847 1.3.2.2 nathanw }
848 1.3.2.2 nathanw
849 1.3.2.2 nathanw /*
850 1.3.2.2 nathanw * Deal with any completed commands.
851 1.3.2.2 nathanw */
852 1.3.2.2 nathanw while ((ac = SIMPLEQ_FIRST(&sc->sc_ccb_complete)) != NULL) {
853 1.3.2.2 nathanw SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_complete, ac_chain);
854 1.3.2.2 nathanw ac->ac_flags |= AAC_CCB_COMPLETED;
855 1.3.2.2 nathanw
856 1.3.2.2 nathanw if (ac->ac_intr != NULL)
857 1.3.2.2 nathanw (*ac->ac_intr)(ac);
858 1.3.2.2 nathanw }
859 1.3.2.2 nathanw
860 1.3.2.2 nathanw /*
861 1.3.2.2 nathanw * Try to submit more commands.
862 1.3.2.2 nathanw */
863 1.3.2.2 nathanw if (! SIMPLEQ_EMPTY(&sc->sc_ccb_queue))
864 1.3.2.2 nathanw aac_ccb_enqueue(sc, NULL);
865 1.3.2.2 nathanw }
866 1.3.2.2 nathanw
867 1.3.2.2 nathanw /*
868 1.3.2.2 nathanw * Send a synchronous command to the controller and wait for a result.
869 1.3.2.2 nathanw */
870 1.3.2.2 nathanw int
871 1.3.2.2 nathanw aac_sync_command(struct aac_softc *sc, u_int32_t command, u_int32_t arg0,
872 1.3.2.2 nathanw u_int32_t arg1, u_int32_t arg2, u_int32_t arg3, u_int32_t *sp)
873 1.3.2.2 nathanw {
874 1.3.2.2 nathanw int i;
875 1.3.2.2 nathanw u_int32_t status;
876 1.3.2.2 nathanw int s;
877 1.3.2.2 nathanw
878 1.3.2.2 nathanw s = splbio();
879 1.3.2.2 nathanw
880 1.3.2.2 nathanw /* Populate the mailbox. */
881 1.3.2.2 nathanw AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3);
882 1.3.2.2 nathanw
883 1.3.2.2 nathanw /* Ensure the sync command doorbell flag is cleared. */
884 1.3.2.2 nathanw AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
885 1.3.2.2 nathanw
886 1.3.2.2 nathanw /* ... then set it to signal the adapter. */
887 1.3.2.2 nathanw AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND);
888 1.3.2.2 nathanw DELAY(AAC_SYNC_DELAY);
889 1.3.2.2 nathanw
890 1.3.2.2 nathanw /* Spin waiting for the command to complete. */
891 1.3.2.2 nathanw for (i = 0; i < AAC_IMMEDIATE_TIMEOUT * 1000; i++) {
892 1.3.2.2 nathanw if (AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND);
893 1.3.2.2 nathanw break;
894 1.3.2.2 nathanw DELAY(1000);
895 1.3.2.2 nathanw }
896 1.3.2.2 nathanw if (i == AAC_IMMEDIATE_TIMEOUT * 1000) {
897 1.3.2.2 nathanw splx(s);
898 1.3.2.2 nathanw return (EIO);
899 1.3.2.2 nathanw }
900 1.3.2.2 nathanw
901 1.3.2.2 nathanw /* Clear the completion flag. */
902 1.3.2.2 nathanw AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND);
903 1.3.2.2 nathanw
904 1.3.2.2 nathanw /* Get the command status. */
905 1.3.2.2 nathanw status = AAC_GET_MAILBOXSTATUS(sc);
906 1.3.2.2 nathanw splx(s);
907 1.3.2.2 nathanw if (sp != NULL)
908 1.3.2.2 nathanw *sp = status;
909 1.3.2.2 nathanw
910 1.3.2.2 nathanw return (0); /* XXX Check command return status? */
911 1.3.2.2 nathanw }
912 1.3.2.2 nathanw
913 1.3.2.2 nathanw /*
914 1.3.2.2 nathanw * Send a synchronous FIB to the controller and wait for a result.
915 1.3.2.2 nathanw */
916 1.3.2.2 nathanw int
917 1.3.2.2 nathanw aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate,
918 1.3.2.2 nathanw void *data, u_int16_t datasize, void *result,
919 1.3.2.2 nathanw u_int16_t *resultsize)
920 1.3.2.2 nathanw {
921 1.3.2.2 nathanw struct aac_fib *fib;
922 1.3.2.2 nathanw u_int32_t fibpa, status;
923 1.3.2.2 nathanw
924 1.3.2.2 nathanw fib = &sc->sc_common->ac_sync_fib;
925 1.3.2.2 nathanw fibpa = sc->sc_common_seg.ds_addr +
926 1.3.2.2 nathanw offsetof(struct aac_common, ac_sync_fib);
927 1.3.2.2 nathanw
928 1.3.2.2 nathanw if (datasize > AAC_FIB_DATASIZE)
929 1.3.2.2 nathanw return (EINVAL);
930 1.3.2.2 nathanw
931 1.3.2.2 nathanw /*
932 1.3.2.2 nathanw * Set up the sync FIB.
933 1.3.2.2 nathanw */
934 1.3.2.2 nathanw fib->Header.XferState = htole32(AAC_FIBSTATE_HOSTOWNED |
935 1.3.2.2 nathanw AAC_FIBSTATE_INITIALISED | AAC_FIBSTATE_EMPTY | xferstate);
936 1.3.2.2 nathanw fib->Header.Command = htole16(command);
937 1.3.2.2 nathanw fib->Header.StructType = AAC_FIBTYPE_TFIB;
938 1.3.2.2 nathanw fib->Header.Size = htole16(sizeof(*fib) + datasize);
939 1.3.2.2 nathanw fib->Header.SenderSize = htole16(sizeof(*fib));
940 1.3.2.2 nathanw fib->Header.SenderFibAddress = htole32((u_int32_t)fib); /* XXX */
941 1.3.2.2 nathanw fib->Header.ReceiverFibAddress = htole32(fibpa);
942 1.3.2.2 nathanw
943 1.3.2.2 nathanw /*
944 1.3.2.2 nathanw * Copy in data.
945 1.3.2.2 nathanw */
946 1.3.2.2 nathanw if (data != NULL) {
947 1.3.2.2 nathanw memcpy(fib->data, data, datasize);
948 1.3.2.2 nathanw fib->Header.XferState |=
949 1.3.2.2 nathanw htole32(AAC_FIBSTATE_FROMHOST | AAC_FIBSTATE_NORM);
950 1.3.2.2 nathanw }
951 1.3.2.2 nathanw
952 1.3.2.2 nathanw bus_dmamap_sync(sc->sc_dmat, sc->sc_common_dmamap,
953 1.3.2.2 nathanw (caddr_t)fib - (caddr_t)sc->sc_common, sizeof(*fib),
954 1.3.2.2 nathanw BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
955 1.3.2.2 nathanw
956 1.3.2.2 nathanw /*
957 1.3.2.2 nathanw * Give the FIB to the controller, wait for a response.
958 1.3.2.2 nathanw */
959 1.3.2.2 nathanw if (aac_sync_command(sc, AAC_MONKER_SYNCFIB, fibpa, 0, 0, 0, &status))
960 1.3.2.2 nathanw return (EIO);
961 1.3.2.2 nathanw
962 1.3.2.2 nathanw bus_dmamap_sync(sc->sc_dmat, sc->sc_common_dmamap,
963 1.3.2.2 nathanw (caddr_t)fib - (caddr_t)sc->sc_common, sizeof(*fib),
964 1.3.2.2 nathanw BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
965 1.3.2.2 nathanw
966 1.3.2.2 nathanw /*
967 1.3.2.2 nathanw * Copy out the result
968 1.3.2.2 nathanw */
969 1.3.2.2 nathanw if (result != NULL) {
970 1.3.2.2 nathanw *resultsize = le16toh(fib->Header.Size) - sizeof(fib->Header);
971 1.3.2.2 nathanw memcpy(result, fib->data, *resultsize);
972 1.3.2.2 nathanw }
973 1.3.2.2 nathanw
974 1.3.2.2 nathanw return (0);
975 1.3.2.2 nathanw }
976 1.3.2.2 nathanw
977 1.3.2.2 nathanw struct aac_ccb *
978 1.3.2.2 nathanw aac_ccb_alloc(struct aac_softc *sc, int flags)
979 1.3.2.2 nathanw {
980 1.3.2.2 nathanw struct aac_ccb *ac;
981 1.3.2.2 nathanw int s;
982 1.3.2.2 nathanw
983 1.3.2.2 nathanw AAC_DPRINTF(AAC_D_QUEUE, ("aac_ccb_alloc(%p, 0x%x) ", sc, flags));
984 1.3.2.2 nathanw
985 1.3.2.2 nathanw s = splbio();
986 1.3.2.2 nathanw ac = SIMPLEQ_FIRST(&sc->sc_ccb_free);
987 1.3.2.2 nathanw #ifdef DIAGNOSTIC
988 1.3.2.2 nathanw if (ac == NULL)
989 1.3.2.2 nathanw panic("aac_ccb_get: no free CCBS");
990 1.3.2.2 nathanw #endif
991 1.3.2.2 nathanw SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_free, ac_chain);
992 1.3.2.2 nathanw splx(s);
993 1.3.2.2 nathanw
994 1.3.2.2 nathanw ac->ac_flags = flags;
995 1.3.2.2 nathanw return (ac);
996 1.3.2.2 nathanw }
997 1.3.2.2 nathanw
998 1.3.2.2 nathanw void
999 1.3.2.2 nathanw aac_ccb_free(struct aac_softc *sc, struct aac_ccb *ac)
1000 1.3.2.2 nathanw {
1001 1.3.2.2 nathanw int s;
1002 1.3.2.2 nathanw
1003 1.3.2.2 nathanw AAC_DPRINTF(AAC_D_QUEUE, ("aac_ccb_free(%p, %p) ", sc, ac));
1004 1.3.2.2 nathanw
1005 1.3.2.2 nathanw ac->ac_flags = 0;
1006 1.3.2.2 nathanw ac->ac_intr = NULL;
1007 1.3.2.2 nathanw ac->ac_fib->Header.XferState = htole32(AAC_FIBSTATE_EMPTY);
1008 1.3.2.2 nathanw ac->ac_fib->Header.StructType = AAC_FIBTYPE_TFIB;
1009 1.3.2.2 nathanw ac->ac_fib->Header.Flags = 0;
1010 1.3.2.2 nathanw ac->ac_fib->Header.SenderSize = htole16(sizeof(*ac->ac_fib));
1011 1.3.2.2 nathanw
1012 1.3.2.2 nathanw #ifdef AAC_DEBUG
1013 1.3.2.2 nathanw /*
1014 1.3.2.2 nathanw * These are duplicated in aac_ccb_submit() to cover the case where
1015 1.3.2.2 nathanw * an intermediate stage may have destroyed them. They're left
1016 1.3.2.2 nathanw * initialised here for debugging purposes only.
1017 1.3.2.2 nathanw */
1018 1.3.2.2 nathanw ac->ac_fib->Header.SenderFibAddress = htole32((u_int32_t)ac->ac_fib);
1019 1.3.2.2 nathanw ac->ac_fib->Header.ReceiverFibAddress = htole32(ac->ac_fibphys);
1020 1.3.2.2 nathanw #endif
1021 1.3.2.2 nathanw
1022 1.3.2.2 nathanw s = splbio();
1023 1.3.2.2 nathanw SIMPLEQ_INSERT_HEAD(&sc->sc_ccb_free, ac, ac_chain);
1024 1.3.2.2 nathanw splx(s);
1025 1.3.2.2 nathanw }
1026 1.3.2.2 nathanw
1027 1.3.2.2 nathanw int
1028 1.3.2.2 nathanw aac_ccb_map(struct aac_softc *sc, struct aac_ccb *ac)
1029 1.3.2.2 nathanw {
1030 1.3.2.2 nathanw int error;
1031 1.3.2.2 nathanw
1032 1.3.2.2 nathanw AAC_DPRINTF(AAC_D_QUEUE, ("aac_ccb_map(%p, %p) ", sc, ac));
1033 1.3.2.2 nathanw
1034 1.3.2.2 nathanw #ifdef DIAGNOSTIC
1035 1.3.2.2 nathanw if ((ac->ac_flags & AAC_CCB_MAPPED) != 0)
1036 1.3.2.2 nathanw panic("aac_ccb_map: already mapped");
1037 1.3.2.2 nathanw #endif
1038 1.3.2.2 nathanw
1039 1.3.2.2 nathanw error = bus_dmamap_load(sc->sc_dmat, ac->ac_dmamap_xfer, ac->ac_data,
1040 1.3.2.2 nathanw ac->ac_datalen, NULL, BUS_DMA_NOWAIT | BUS_DMA_STREAMING |
1041 1.3.2.2 nathanw ((ac->ac_flags & AAC_CCB_DATA_IN) ? BUS_DMA_READ : BUS_DMA_WRITE));
1042 1.3.2.2 nathanw if (error) {
1043 1.3.2.2 nathanw printf("%s: aac_ccb_map: ", sc->sc_dv.dv_xname);
1044 1.3.2.2 nathanw if (error == EFBIG)
1045 1.3.2.2 nathanw printf("more than %d dma segs\n", AAC_MAX_SGENTRIES);
1046 1.3.2.2 nathanw else
1047 1.3.2.2 nathanw printf("error %d loading dma map\n", error);
1048 1.3.2.2 nathanw return (error);
1049 1.3.2.2 nathanw }
1050 1.3.2.2 nathanw
1051 1.3.2.2 nathanw bus_dmamap_sync(sc->sc_dmat, ac->ac_dmamap_xfer, 0, ac->ac_datalen,
1052 1.3.2.2 nathanw (ac->ac_flags & AAC_CCB_DATA_IN) ? BUS_DMASYNC_PREREAD :
1053 1.3.2.2 nathanw BUS_DMASYNC_PREWRITE);
1054 1.3.2.2 nathanw
1055 1.3.2.2 nathanw #ifdef DIAGNOSTIC
1056 1.3.2.2 nathanw ac->ac_flags |= AAC_CCB_MAPPED;
1057 1.3.2.2 nathanw #endif
1058 1.3.2.2 nathanw return (0);
1059 1.3.2.2 nathanw }
1060 1.3.2.2 nathanw
1061 1.3.2.2 nathanw void
1062 1.3.2.2 nathanw aac_ccb_unmap(struct aac_softc *sc, struct aac_ccb *ac)
1063 1.3.2.2 nathanw {
1064 1.3.2.2 nathanw
1065 1.3.2.2 nathanw AAC_DPRINTF(AAC_D_QUEUE, ("aac_ccb_unmap(%p, %p) ", sc, ac));
1066 1.3.2.2 nathanw
1067 1.3.2.2 nathanw #ifdef DIAGNOSTIC
1068 1.3.2.2 nathanw if ((ac->ac_flags & AAC_CCB_MAPPED) == 0)
1069 1.3.2.2 nathanw panic("aac_ccb_unmap: not mapped");
1070 1.3.2.2 nathanw #endif
1071 1.3.2.2 nathanw
1072 1.3.2.2 nathanw bus_dmamap_sync(sc->sc_dmat, ac->ac_dmamap_xfer, 0, ac->ac_datalen,
1073 1.3.2.2 nathanw (ac->ac_flags & AAC_CCB_DATA_IN) ? BUS_DMASYNC_POSTREAD :
1074 1.3.2.2 nathanw BUS_DMASYNC_POSTWRITE);
1075 1.3.2.2 nathanw bus_dmamap_unload(sc->sc_dmat, ac->ac_dmamap_xfer);
1076 1.3.2.2 nathanw
1077 1.3.2.2 nathanw #ifdef DIAGNOSTIC
1078 1.3.2.2 nathanw ac->ac_flags &= ~AAC_CCB_MAPPED;
1079 1.3.2.2 nathanw #endif
1080 1.3.2.2 nathanw }
1081 1.3.2.2 nathanw
1082 1.3.2.2 nathanw void
1083 1.3.2.2 nathanw aac_ccb_enqueue(struct aac_softc *sc, struct aac_ccb *ac)
1084 1.3.2.2 nathanw {
1085 1.3.2.2 nathanw int s;
1086 1.3.2.2 nathanw
1087 1.3.2.2 nathanw AAC_DPRINTF(AAC_D_QUEUE, ("aac_ccb_enqueue(%p, %p) ", sc, ac));
1088 1.3.2.2 nathanw
1089 1.3.2.2 nathanw s = splbio();
1090 1.3.2.2 nathanw
1091 1.3.2.2 nathanw if (ac != NULL)
1092 1.3.2.2 nathanw SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_queue, ac, ac_chain);
1093 1.3.2.2 nathanw
1094 1.3.2.2 nathanw while ((ac = SIMPLEQ_FIRST(&sc->sc_ccb_queue)) != NULL) {
1095 1.3.2.2 nathanw if (aac_ccb_submit(sc, ac))
1096 1.3.2.2 nathanw break;
1097 1.3.2.2 nathanw SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_queue, ac_chain);
1098 1.3.2.2 nathanw }
1099 1.3.2.2 nathanw
1100 1.3.2.2 nathanw splx(s);
1101 1.3.2.2 nathanw }
1102 1.3.2.2 nathanw
1103 1.3.2.2 nathanw int
1104 1.3.2.2 nathanw aac_ccb_submit(struct aac_softc *sc, struct aac_ccb *ac)
1105 1.3.2.2 nathanw {
1106 1.3.2.2 nathanw
1107 1.3.2.2 nathanw AAC_DPRINTF(AAC_D_QUEUE, ("aac_ccb_submit(%p, %p) ", sc, ac));
1108 1.3.2.2 nathanw
1109 1.3.2.2 nathanw /* Fix up the address values. */
1110 1.3.2.2 nathanw ac->ac_fib->Header.SenderFibAddress = htole32((u_int32_t)ac->ac_fib);
1111 1.3.2.2 nathanw ac->ac_fib->Header.ReceiverFibAddress = htole32(ac->ac_fibphys);
1112 1.3.2.2 nathanw
1113 1.3.2.2 nathanw /* Save a pointer to the command for speedy reverse-lookup. */
1114 1.3.2.2 nathanw ac->ac_fib->Header.SenderData =
1115 1.3.2.2 nathanw (u_int32_t)((caddr_t)ac - (caddr_t)sc->sc_ccbs) | 0x80000000;
1116 1.3.2.2 nathanw
1117 1.3.2.2 nathanw bus_dmamap_sync(sc->sc_dmat, sc->sc_fibs_dmamap,
1118 1.3.2.2 nathanw (caddr_t)ac->ac_fib - (caddr_t)sc->sc_fibs, sizeof(*ac->ac_fib),
1119 1.3.2.2 nathanw BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
1120 1.3.2.2 nathanw
1121 1.3.2.2 nathanw /* Put the FIB on the outbound queue. */
1122 1.3.2.2 nathanw return (aac_enqueue_fib(sc, AAC_ADAP_NORM_CMD_QUEUE, ac->ac_fib));
1123 1.3.2.2 nathanw }
1124 1.3.2.2 nathanw
1125 1.3.2.2 nathanw int
1126 1.3.2.2 nathanw aac_ccb_poll(struct aac_softc *sc, struct aac_ccb *ac, int timo)
1127 1.3.2.2 nathanw {
1128 1.3.2.2 nathanw int rv, s;
1129 1.3.2.2 nathanw
1130 1.3.2.2 nathanw AAC_DPRINTF(AAC_D_QUEUE, ("aac_ccb_poll(%p, %p, %d) ", sc, ac, timo));
1131 1.3.2.2 nathanw
1132 1.3.2.2 nathanw s = splbio();
1133 1.3.2.2 nathanw
1134 1.3.2.2 nathanw if ((rv = aac_ccb_submit(sc, ac)) != 0) {
1135 1.3.2.2 nathanw splx(s);
1136 1.3.2.2 nathanw return (rv);
1137 1.3.2.2 nathanw }
1138 1.3.2.2 nathanw
1139 1.3.2.2 nathanw for (timo *= 1000; timo != 0; timo--) {
1140 1.3.2.2 nathanw aac_intr(sc);
1141 1.3.2.2 nathanw if ((ac->ac_flags & AAC_CCB_COMPLETED) != 0)
1142 1.3.2.2 nathanw break;
1143 1.3.2.2 nathanw DELAY(100);
1144 1.3.2.2 nathanw }
1145 1.3.2.2 nathanw
1146 1.3.2.2 nathanw splx(s);
1147 1.3.2.2 nathanw return (timo == 0);
1148 1.3.2.2 nathanw }
1149 1.3.2.2 nathanw
1150 1.3.2.2 nathanw /*
1151 1.3.2.2 nathanw * Atomically insert an entry into the nominated queue, returns 0 on success
1152 1.3.2.2 nathanw * or EBUSY if the queue is full.
1153 1.3.2.2 nathanw *
1154 1.3.2.2 nathanw * XXX Note that it would be more efficient to defer notifying the
1155 1.3.2.2 nathanw * controller in the case where we may be inserting several entries in rapid
1156 1.3.2.2 nathanw * succession, but implementing this usefully is difficult.
1157 1.3.2.2 nathanw */
1158 1.3.2.2 nathanw int
1159 1.3.2.2 nathanw aac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_fib *fib)
1160 1.3.2.2 nathanw {
1161 1.3.2.2 nathanw u_int32_t fib_size, fib_addr, pi, ci;
1162 1.3.2.2 nathanw
1163 1.3.2.2 nathanw fib_size = le16toh(fib->Header.Size);
1164 1.3.2.2 nathanw fib_addr = le32toh(fib->Header.ReceiverFibAddress);
1165 1.3.2.2 nathanw
1166 1.3.2.2 nathanw bus_dmamap_sync(sc->sc_dmat, sc->sc_common_dmamap,
1167 1.3.2.2 nathanw (caddr_t)sc->sc_common->ac_qbuf - (caddr_t)sc->sc_common,
1168 1.3.2.2 nathanw sizeof(sc->sc_common->ac_qbuf),
1169 1.3.2.2 nathanw BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
1170 1.3.2.2 nathanw
1171 1.3.2.2 nathanw /* Get the producer/consumer indices. */
1172 1.3.2.2 nathanw pi = le32toh(sc->sc_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]);
1173 1.3.2.2 nathanw ci = le32toh(sc->sc_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]);
1174 1.3.2.2 nathanw
1175 1.3.2.2 nathanw /* Wrap the queue? */
1176 1.3.2.2 nathanw if (pi >= aac_qinfo[queue].size)
1177 1.3.2.2 nathanw pi = 0;
1178 1.3.2.2 nathanw
1179 1.3.2.2 nathanw /* Check for queue full. */
1180 1.3.2.2 nathanw if ((pi + 1) == ci)
1181 1.3.2.2 nathanw return (EAGAIN);
1182 1.3.2.2 nathanw
1183 1.3.2.2 nathanw /* Populate queue entry. */
1184 1.3.2.2 nathanw (sc->sc_qentries[queue] + pi)->aq_fib_size = htole32(fib_size);
1185 1.3.2.2 nathanw (sc->sc_qentries[queue] + pi)->aq_fib_addr = htole32(fib_addr);
1186 1.3.2.2 nathanw
1187 1.3.2.2 nathanw /* Update producer index. */
1188 1.3.2.2 nathanw sc->sc_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = htole32(pi + 1);
1189 1.3.2.2 nathanw
1190 1.3.2.2 nathanw bus_dmamap_sync(sc->sc_dmat, sc->sc_common_dmamap,
1191 1.3.2.2 nathanw (caddr_t)sc->sc_common->ac_qbuf - (caddr_t)sc->sc_common,
1192 1.3.2.2 nathanw sizeof(sc->sc_common->ac_qbuf),
1193 1.3.2.2 nathanw BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
1194 1.3.2.2 nathanw
1195 1.3.2.2 nathanw /* Notify the adapter if we know how. */
1196 1.3.2.2 nathanw if (aac_qinfo[queue].notify != 0)
1197 1.3.2.2 nathanw AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
1198 1.3.2.2 nathanw
1199 1.3.2.2 nathanw return (0);
1200 1.3.2.2 nathanw }
1201 1.3.2.2 nathanw
1202 1.3.2.2 nathanw /*
1203 1.3.2.2 nathanw * Atomically remove one entry from the nominated queue, returns 0 on success
1204 1.3.2.2 nathanw * or ENOENT if the queue is empty.
1205 1.3.2.2 nathanw */
1206 1.3.2.2 nathanw int
1207 1.3.2.2 nathanw aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size,
1208 1.3.2.2 nathanw struct aac_fib **fib_addr)
1209 1.3.2.2 nathanw {
1210 1.3.2.2 nathanw u_int32_t pi, ci;
1211 1.3.2.2 nathanw int notify;
1212 1.3.2.2 nathanw
1213 1.3.2.2 nathanw bus_dmamap_sync(sc->sc_dmat, sc->sc_common_dmamap,
1214 1.3.2.2 nathanw (caddr_t)sc->sc_common->ac_qbuf - (caddr_t)sc->sc_common,
1215 1.3.2.2 nathanw sizeof(sc->sc_common->ac_qbuf),
1216 1.3.2.2 nathanw BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
1217 1.3.2.2 nathanw
1218 1.3.2.2 nathanw /* Get the producer/consumer indices. */
1219 1.3.2.2 nathanw pi = le32toh(sc->sc_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]);
1220 1.3.2.2 nathanw ci = le32toh(sc->sc_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]);
1221 1.3.2.2 nathanw
1222 1.3.2.2 nathanw /* Check for queue empty. */
1223 1.3.2.2 nathanw if (ci == pi)
1224 1.3.2.2 nathanw return (ENOENT);
1225 1.3.2.2 nathanw
1226 1.3.2.2 nathanw notify = 0;
1227 1.3.2.2 nathanw if (ci == pi + 1)
1228 1.3.2.2 nathanw notify = 1;
1229 1.3.2.2 nathanw
1230 1.3.2.2 nathanw /* Wrap the queue? */
1231 1.3.2.2 nathanw if (ci >= aac_qinfo[queue].size)
1232 1.3.2.2 nathanw ci = 0;
1233 1.3.2.2 nathanw
1234 1.3.2.2 nathanw /* Fetch the entry. */
1235 1.3.2.2 nathanw *fib_size = le32toh((sc->sc_qentries[queue] + ci)->aq_fib_size);
1236 1.3.2.2 nathanw *fib_addr = le32toh((struct aac_fib *)
1237 1.3.2.2 nathanw (sc->sc_qentries[queue] + ci)->aq_fib_addr);
1238 1.3.2.2 nathanw
1239 1.3.2.2 nathanw /* Update consumer index. */
1240 1.3.2.2 nathanw sc->sc_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1;
1241 1.3.2.2 nathanw
1242 1.3.2.2 nathanw bus_dmamap_sync(sc->sc_dmat, sc->sc_common_dmamap,
1243 1.3.2.2 nathanw (caddr_t)sc->sc_common->ac_qbuf - (caddr_t)sc->sc_common,
1244 1.3.2.2 nathanw sizeof(sc->sc_common->ac_qbuf),
1245 1.3.2.2 nathanw BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
1246 1.3.2.2 nathanw
1247 1.3.2.2 nathanw /* If we have made the queue un-full, notify the adapter. */
1248 1.3.2.2 nathanw if (notify && (aac_qinfo[queue].notify != 0))
1249 1.3.2.2 nathanw AAC_QNOTIFY(sc, aac_qinfo[queue].notify);
1250 1.3.2.2 nathanw
1251 1.3.2.2 nathanw return (0);
1252 1.3.2.2 nathanw }
1253 1.3.2.2 nathanw
1254 1.3.2.2 nathanw #ifdef AAC_DEBUG
1255 1.3.2.2 nathanw /*
1256 1.3.2.2 nathanw * Print a FIB
1257 1.3.2.2 nathanw */
1258 1.3.2.2 nathanw void
1259 1.3.2.2 nathanw aac_print_fib(struct aac_softc *sc, struct aac_fib *fib, char *caller)
1260 1.3.2.2 nathanw {
1261 1.3.2.2 nathanw struct aac_blockread *br;
1262 1.3.2.2 nathanw struct aac_blockwrite *bw;
1263 1.3.2.2 nathanw struct aac_sg_table *sg;
1264 1.3.2.2 nathanw char buf[512];
1265 1.3.2.2 nathanw int i;
1266 1.3.2.2 nathanw
1267 1.3.2.2 nathanw printf("%s: FIB @ %p\n", caller, fib);
1268 1.3.2.2 nathanw bitmask_snprintf(le32toh(fib->Header.XferState),
1269 1.3.2.2 nathanw "\20"
1270 1.3.2.2 nathanw "\1HOSTOWNED"
1271 1.3.2.2 nathanw "\2ADAPTEROWNED"
1272 1.3.2.2 nathanw "\3INITIALISED"
1273 1.3.2.2 nathanw "\4EMPTY"
1274 1.3.2.2 nathanw "\5FROMPOOL"
1275 1.3.2.2 nathanw "\6FROMHOST"
1276 1.3.2.2 nathanw "\7FROMADAP"
1277 1.3.2.2 nathanw "\10REXPECTED"
1278 1.3.2.2 nathanw "\11RNOTEXPECTED"
1279 1.3.2.2 nathanw "\12DONEADAP"
1280 1.3.2.2 nathanw "\13DONEHOST"
1281 1.3.2.2 nathanw "\14HIGH"
1282 1.3.2.2 nathanw "\15NORM"
1283 1.3.2.2 nathanw "\16ASYNC"
1284 1.3.2.2 nathanw "\17PAGEFILEIO"
1285 1.3.2.2 nathanw "\20SHUTDOWN"
1286 1.3.2.2 nathanw "\21LAZYWRITE"
1287 1.3.2.2 nathanw "\22ADAPMICROFIB"
1288 1.3.2.2 nathanw "\23BIOSFIB"
1289 1.3.2.2 nathanw "\24FAST_RESPONSE"
1290 1.3.2.2 nathanw "\25APIFIB\n",
1291 1.3.2.2 nathanw buf,
1292 1.3.2.2 nathanw sizeof(buf));
1293 1.3.2.2 nathanw
1294 1.3.2.2 nathanw printf(" XferState %s\n", buf);
1295 1.3.2.2 nathanw printf(" Command %d\n", le16toh(fib->Header.Command));
1296 1.3.2.2 nathanw printf(" StructType %d\n", fib->Header.StructType);
1297 1.3.2.2 nathanw printf(" Flags 0x%x\n", fib->Header.Flags);
1298 1.3.2.2 nathanw printf(" Size %d\n", le16toh(fib->Header.Size));
1299 1.3.2.2 nathanw printf(" SenderSize %d\n", le16toh(fib->Header.SenderSize));
1300 1.3.2.2 nathanw printf(" SenderAddress 0x%x\n",
1301 1.3.2.2 nathanw le32toh(fib->Header.SenderFibAddress));
1302 1.3.2.2 nathanw printf(" ReceiverAddress 0x%x\n",
1303 1.3.2.2 nathanw le32toh(fib->Header.ReceiverFibAddress));
1304 1.3.2.2 nathanw printf(" SenderData 0x%x\n", fib->Header.SenderData);
1305 1.3.2.2 nathanw
1306 1.3.2.2 nathanw switch (fib->Header.Command) {
1307 1.3.2.2 nathanw case ContainerCommand: {
1308 1.3.2.2 nathanw br = (struct aac_blockread *)fib->data;
1309 1.3.2.2 nathanw bw = (struct aac_blockwrite *)fib->data;
1310 1.3.2.2 nathanw sg = NULL;
1311 1.3.2.2 nathanw
1312 1.3.2.2 nathanw if (le32toh(br->Command) == VM_CtBlockRead) {
1313 1.3.2.2 nathanw printf(" BlockRead: container %d 0x%x/%d\n",
1314 1.3.2.2 nathanw le32toh(br->ContainerId), le32toh(br->BlockNumber),
1315 1.3.2.2 nathanw le32toh(br->ByteCount));
1316 1.3.2.2 nathanw sg = &br->SgMap;
1317 1.3.2.2 nathanw }
1318 1.3.2.2 nathanw if (le32toh(bw->Command) == VM_CtBlockWrite) {
1319 1.3.2.2 nathanw printf(" BlockWrite: container %d 0x%x/%d (%s)\n",
1320 1.3.2.2 nathanw le32toh(bw->ContainerId), le32toh(bw->BlockNumber),
1321 1.3.2.2 nathanw le32toh(bw->ByteCount),
1322 1.3.2.2 nathanw le32toh(bw->Stable) == CSTABLE ?
1323 1.3.2.2 nathanw "stable" : "unstable");
1324 1.3.2.2 nathanw sg = &bw->SgMap;
1325 1.3.2.2 nathanw }
1326 1.3.2.2 nathanw if (sg != NULL) {
1327 1.3.2.2 nathanw printf(" %d s/g entries\n", le32toh(sg->SgCount));
1328 1.3.2.2 nathanw for (i = 0; i < le32toh(sg->SgCount); i++)
1329 1.3.2.2 nathanw printf(" 0x%08x/%d\n",
1330 1.3.2.2 nathanw le32toh(sg->SgEntry[i].SgAddress),
1331 1.3.2.2 nathanw le32toh(sg->SgEntry[i].SgByteCount));
1332 1.3.2.2 nathanw }
1333 1.3.2.2 nathanw break;
1334 1.3.2.2 nathanw }
1335 1.3.2.2 nathanw default:
1336 1.3.2.2 nathanw printf(" %16D\n", fib->data, " ");
1337 1.3.2.2 nathanw printf(" %16D\n", fib->data + 16, " ");
1338 1.3.2.2 nathanw break;
1339 1.3.2.2 nathanw }
1340 1.3.2.2 nathanw }
1341 1.3.2.2 nathanw #endif
1342