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