Home | History | Annotate | Line # | Download | only in ic
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