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