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