Home | History | Annotate | Line # | Download | only in pci
mlx_pci.c revision 1.1.2.3
      1 /*	$NetBSD: mlx_pci.c,v 1.1.2.3 2001/03/12 13:31:09 bouyer Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2001 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Andrew Doran.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *        This product includes software developed by the NetBSD
     21  *        Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 /*-
     40  * Copyright (c) 1999 Michael Smith
     41  * All rights reserved.
     42  *
     43  * Redistribution and use in source and binary forms, with or without
     44  * modification, are permitted provided that the following conditions
     45  * are met:
     46  * 1. Redistributions of source code must retain the above copyright
     47  *    notice, this list of conditions and the following disclaimer.
     48  * 2. Redistributions in binary form must reproduce the above copyright
     49  *    notice, this list of conditions and the following disclaimer in the
     50  *    documentation and/or other materials provided with the distribution.
     51  *
     52  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     53  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     54  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     55  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     56  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     57  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     58  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     59  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     60  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     61  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     62  * SUCH DAMAGE.
     63  *
     64  * from FreeBSD: mlx_pci.c,v 1.4.2.4 2000/10/28 10:48:09 msmith Exp
     65  */
     66 
     67 /*
     68  * PCI front-end for the mlx(4) driver.
     69  */
     70 
     71 #include <sys/param.h>
     72 #include <sys/systm.h>
     73 #include <sys/kernel.h>
     74 #include <sys/device.h>
     75 #include <sys/queue.h>
     76 #include <sys/callout.h>
     77 
     78 #include <machine/endian.h>
     79 #include <machine/bus.h>
     80 
     81 #include <dev/ic/mlxreg.h>
     82 #include <dev/ic/mlxio.h>
     83 #include <dev/ic/mlxvar.h>
     84 
     85 #include <dev/pci/pcireg.h>
     86 #include <dev/pci/pcivar.h>
     87 #include <dev/pci/pcidevs.h>
     88 
     89 static void	mlx_pci_attach(struct device *, struct device *, void *);
     90 static int	mlx_pci_match(struct device *, struct cfdata *, void *);
     91 static const struct mlx_pci_ident *mlx_pci_findmpi(struct pci_attach_args *);
     92 
     93 static int	mlx_v3_submit(struct mlx_softc *, struct mlx_ccb *);
     94 static int	mlx_v3_findcomplete(struct mlx_softc *, u_int *, u_int *);
     95 static void	mlx_v3_intaction(struct mlx_softc *, int);
     96 static int	mlx_v3_fw_handshake(struct mlx_softc *, int *, int *, int *);
     97 
     98 static int	mlx_v4_submit(struct mlx_softc *, struct mlx_ccb *);
     99 static int	mlx_v4_findcomplete(struct mlx_softc *, u_int *, u_int *);
    100 static void	mlx_v4_intaction(struct mlx_softc *, int);
    101 static int	mlx_v4_fw_handshake(struct mlx_softc *, int *, int *, int *);
    102 
    103 static int	mlx_v5_submit(struct mlx_softc *, struct mlx_ccb *);
    104 static int	mlx_v5_findcomplete(struct mlx_softc *, u_int *, u_int *);
    105 static void	mlx_v5_intaction(struct mlx_softc *, int);
    106 static int	mlx_v5_fw_handshake(struct mlx_softc *, int *, int *, int *);
    107 
    108 struct mlx_pci_ident {
    109 	u_short	mpi_vendor;
    110 	u_short	mpi_product;
    111 	u_short	mpi_subvendor;
    112 	u_short	mpi_subproduct;
    113 	int	mpi_iftype;
    114 } static const mlx_pci_ident[] = {
    115 	{
    116 		PCI_VENDOR_MYLEX,
    117 		PCI_PRODUCT_MYLEX_RAID_V2,
    118 		0x0000,
    119 		0x0000,
    120 		2,
    121 	},
    122 	{
    123 		PCI_VENDOR_MYLEX,
    124 		PCI_PRODUCT_MYLEX_RAID_V3,
    125 		0x0000,
    126 		0x0000,
    127 		3,
    128 	},
    129 	{
    130 		PCI_VENDOR_MYLEX,
    131 		PCI_PRODUCT_MYLEX_RAID_V4,
    132 		0x0000,
    133 		0x0000,
    134 		4,
    135 	},
    136 	{
    137 		PCI_VENDOR_DEC,
    138 		PCI_PRODUCT_DEC_SWXCR,
    139 		PCI_VENDOR_MYLEX,
    140 		PCI_PRODUCT_MYLEX_RAID_V5,
    141 		5,
    142 	},
    143 };
    144 
    145 struct cfattach mlx_pci_ca = {
    146 	sizeof(struct mlx_softc), mlx_pci_match, mlx_pci_attach
    147 };
    148 
    149 /*
    150  * Try to find a `mlx_pci_ident' entry corresponding to this board.
    151  */
    152 static const struct mlx_pci_ident *
    153 mlx_pci_findmpi(struct pci_attach_args *pa)
    154 {
    155 	const struct mlx_pci_ident *mpi, *maxmpi;
    156 	pcireg_t reg;
    157 
    158 	mpi = mlx_pci_ident;
    159 	maxmpi = mpi + sizeof(mlx_pci_ident) / sizeof(mlx_pci_ident[0]);
    160 
    161 	for (; mpi < maxmpi; mpi++) {
    162 		if (PCI_VENDOR(pa->pa_id) != mpi->mpi_vendor ||
    163 		    PCI_PRODUCT(pa->pa_id) != mpi->mpi_product)
    164 			continue;
    165 
    166 		if (mpi->mpi_subvendor == 0x0000)
    167 			return (mpi);
    168 
    169 		reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
    170 
    171 		if (PCI_VENDOR(reg) == mpi->mpi_subvendor &&
    172 		    PCI_PRODUCT(reg) == mpi->mpi_subproduct)
    173 			return (mpi);
    174 	}
    175 
    176 	return (NULL);
    177 }
    178 
    179 /*
    180  * Match a supported board.
    181  */
    182 static int
    183 mlx_pci_match(struct device *parent, struct cfdata *cfdata, void *aux)
    184 {
    185 
    186 	return (mlx_pci_findmpi(aux) != NULL);
    187 }
    188 
    189 /*
    190  * Attach a supported board.
    191  */
    192 static void
    193 mlx_pci_attach(struct device *parent, struct device *self, void *aux)
    194 {
    195 	struct pci_attach_args *pa;
    196 	struct mlx_softc *mlx;
    197 	pci_chipset_tag_t pc;
    198 	pci_intr_handle_t ih;
    199 	pcireg_t reg;
    200 	const char *intrstr;
    201 	int ior, memr, i;
    202 	const struct mlx_pci_ident *mpi;
    203 
    204 	mlx = (struct mlx_softc *)self;
    205 	pa = aux;
    206 	pc = pa->pa_pc;
    207 	mpi = mlx_pci_findmpi(aux);
    208 
    209 	mlx->mlx_dmat = pa->pa_dmat;
    210 	mlx->mlx_iftype = mpi->mpi_iftype;
    211 
    212 	printf(": Mylex RAID (v%d interface)\n", mpi->mpi_iftype);
    213 
    214 	/*
    215 	 * Map the PCI register window.
    216 	 */
    217 	memr = -1;
    218 	ior = -1;
    219 
    220 	for (i = 0x10; i <= 0x14; i += 4) {
    221 		reg = pci_conf_read(pa->pa_pc, pa->pa_tag, i);
    222 
    223 		if (PCI_MAPREG_TYPE(reg) == PCI_MAPREG_TYPE_IO) {
    224 			if (ior == -1 && PCI_MAPREG_IO_SIZE(reg) != 0)
    225 				ior = i;
    226 		} else {
    227 			if (memr == -1 && PCI_MAPREG_MEM_SIZE(reg) != 0)
    228 				memr = i;
    229 		}
    230 	}
    231 
    232 	if (memr != -1)
    233 		if (pci_mapreg_map(pa, memr, PCI_MAPREG_TYPE_MEM, 0,
    234 		    &mlx->mlx_iot, &mlx->mlx_ioh, NULL, NULL))
    235 			memr = -1;
    236 	if (ior != -1)
    237 		if (pci_mapreg_map(pa, ior, PCI_MAPREG_TYPE_IO, 0,
    238 		    &mlx->mlx_iot, &mlx->mlx_ioh, NULL, NULL))
    239 		    	ior = -1;
    240 	if (memr == -1 && ior == -1) {
    241 		printf("%s: can't map i/o or memory space\n", self->dv_xname);
    242 		return;
    243 	}
    244 
    245 	/* Enable the device. */
    246 	reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
    247 	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
    248 	    reg | PCI_COMMAND_MASTER_ENABLE);
    249 
    250 	/* Map and establish the interrupt. */
    251 	if (pci_intr_map(pa, &ih)) {
    252 		printf("%s: can't map interrupt\n", self->dv_xname);
    253 		return;
    254 	}
    255 	intrstr = pci_intr_string(pc, ih);
    256 	mlx->mlx_ih = pci_intr_establish(pc, ih, IPL_BIO, mlx_intr, mlx);
    257 	if (mlx->mlx_ih == NULL) {
    258 		printf("%s: can't establish interrupt", self->dv_xname);
    259 		if (intrstr != NULL)
    260 			printf(" at %s", intrstr);
    261 		printf("\n");
    262 		return;
    263 	}
    264 
    265 	/* Select linkage based on controller interface type. */
    266 	switch (mlx->mlx_iftype) {
    267 	case 2:
    268 	case 3:
    269 		mlx->mlx_submit = mlx_v3_submit;
    270 		mlx->mlx_findcomplete = mlx_v3_findcomplete;
    271 		mlx->mlx_intaction = mlx_v3_intaction;
    272 		mlx->mlx_fw_handshake = mlx_v3_fw_handshake;
    273 		break;
    274 
    275 	case 4:
    276 		mlx->mlx_submit = mlx_v4_submit;
    277 		mlx->mlx_findcomplete = mlx_v4_findcomplete;
    278 		mlx->mlx_intaction = mlx_v4_intaction;
    279 		mlx->mlx_fw_handshake = mlx_v4_fw_handshake;
    280 		break;
    281 
    282 	case 5:
    283 		mlx->mlx_submit = mlx_v5_submit;
    284 		mlx->mlx_findcomplete = mlx_v5_findcomplete;
    285 		mlx->mlx_intaction = mlx_v5_intaction;
    286 		mlx->mlx_fw_handshake = mlx_v5_fw_handshake;
    287 		break;
    288 	}
    289 
    290 	mlx_init(mlx, intrstr);
    291 }
    292 
    293 /*
    294  * ================= V3 interface linkage =================
    295  */
    296 
    297 /*
    298  * Try to give (mc) to the controller.  Returns 1 if successful, 0 on
    299  * failure (the controller is not ready to take a command).
    300  *
    301  * Must be called at splbio or in a fashion that prevents reentry.
    302  */
    303 static int
    304 mlx_v3_submit(struct mlx_softc *mlx, struct mlx_ccb *mc)
    305 {
    306 
    307 	/* Ready for our command? */
    308 	if ((mlx_inb(mlx, MLX_V3REG_IDB) & MLX_V3_IDB_FULL) == 0) {
    309 		/* Copy mailbox data to window. */
    310 		bus_space_write_region_1(mlx->mlx_iot, mlx->mlx_ioh,
    311 		    MLX_V3REG_MAILBOX, mc->mc_mbox, MLX_V3_MAILBOX_LEN);
    312 		bus_space_barrier(mlx->mlx_iot, mlx->mlx_ioh,
    313 		    MLX_V3REG_MAILBOX, MLX_V3_MAILBOX_LEN,
    314 		    BUS_SPACE_BARRIER_WRITE);
    315 
    316 		/* Post command. */
    317 		mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_FULL);
    318 		return (1);
    319 	}
    320 
    321 	return (0);
    322 }
    323 
    324 /*
    325  * See if a command has been completed, if so acknowledge its completion and
    326  * recover the slot number and status code.
    327  *
    328  * Must be called at splbio or in a fashion that prevents reentry.
    329  */
    330 static int
    331 mlx_v3_findcomplete(struct mlx_softc *mlx, u_int *slot, u_int *status)
    332 {
    333 
    334 	/* Status available? */
    335 	if ((mlx_inb(mlx, MLX_V3REG_ODB) & MLX_V3_ODB_SAVAIL) != 0) {
    336 		*slot = mlx_inb(mlx, MLX_V3REG_STATUS_IDENT);
    337 		*status = mlx_inw(mlx, MLX_V3REG_STATUS);
    338 
    339 		/* Acknowledge completion. */
    340 		mlx_outb(mlx, MLX_V3REG_ODB, MLX_V3_ODB_SAVAIL);
    341 		mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_SACK);
    342 		return (1);
    343 	}
    344 
    345 	return (0);
    346 }
    347 
    348 /*
    349  * Enable/disable interrupts as requested. (No acknowledge required)
    350  *
    351  * Must be called at splbio or in a fashion that prevents reentry.
    352  */
    353 static void
    354 mlx_v3_intaction(struct mlx_softc *mlx, int action)
    355 {
    356 
    357 	mlx_outb(mlx, MLX_V3REG_IE, action != 0);
    358 }
    359 
    360 /*
    361  * Poll for firmware error codes during controller initialisation.
    362  *
    363  * Returns 0 if initialisation is complete, 1 if still in progress but no
    364  * error has been fetched, 2 if an error has been retrieved.
    365  */
    366 static int
    367 mlx_v3_fw_handshake(struct mlx_softc *mlx, int *error, int *param1, int *param2)
    368 {
    369 	u_int8_t fwerror;
    370 
    371 	/* First time around, clear any hardware completion status. */
    372 	if ((mlx->mlx_flags & MLXF_FW_INITTED) == 0) {
    373 		mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_SACK);
    374 		DELAY(1000);
    375 		mlx->mlx_flags |= MLXF_FW_INITTED;
    376 	}
    377 
    378 	/* Init in progress? */
    379 	if ((mlx_inb(mlx, MLX_V3REG_IDB) & MLX_V3_IDB_INIT_BUSY) == 0)
    380 		return (0);
    381 
    382 	/* Test error value. */
    383 	fwerror = mlx_inb(mlx, MLX_V3REG_FWERROR);
    384 
    385 	if ((fwerror & MLX_V3_FWERROR_PEND) == 0)
    386 		return (1);
    387 
    388 	/* Mask status pending bit, fetch status. */
    389 	*error = fwerror & ~MLX_V3_FWERROR_PEND;
    390 	*param1 = mlx_inb(mlx, MLX_V3REG_FWERROR_PARAM1);
    391 	*param2 = mlx_inb(mlx, MLX_V3REG_FWERROR_PARAM2);
    392 
    393 	/* Acknowledge. */
    394 	mlx_outb(mlx, MLX_V3REG_FWERROR, 0);
    395 
    396 	return (2);
    397 }
    398 
    399 /*
    400  * ================= V4 interface linkage =================
    401  */
    402 
    403 /*
    404  * Try to give (mc) to the controller.  Returns 1 if successful, 0 on
    405  * failure (the controller is not ready to take a command).
    406  *
    407  * Must be called at splbio or in a fashion that prevents reentry.
    408  */
    409 static int
    410 mlx_v4_submit(struct mlx_softc *mlx, struct mlx_ccb *mc)
    411 {
    412 
    413 	/* Ready for our command? */
    414 	if ((mlx_inl(mlx, MLX_V4REG_IDB) & MLX_V4_IDB_FULL) == 0) {
    415 		/* Copy mailbox data to window. */
    416 		bus_space_write_region_4(mlx->mlx_iot, mlx->mlx_ioh,
    417 		    MLX_V4REG_MAILBOX, (const u_int32_t *)mc->mc_mbox,
    418 		    MLX_V4_MAILBOX_LEN >> 2);
    419 		bus_space_barrier(mlx->mlx_iot, mlx->mlx_ioh,
    420 		    MLX_V4REG_MAILBOX, MLX_V4_MAILBOX_LEN,
    421 		    BUS_SPACE_BARRIER_WRITE);
    422 
    423 		/* Post command. */
    424 		mlx_outl(mlx, MLX_V4REG_IDB, MLX_V4_IDB_HWMBOX_CMD);
    425 		return (1);
    426 	}
    427 
    428 	return (0);
    429 }
    430 
    431 /*
    432  * See if a command has been completed, if so acknowledge its completion and
    433  * recover the slot number and status code.
    434  *
    435  * Must be called at splbio or in a fashion that prevents reentry.
    436  */
    437 static int
    438 mlx_v4_findcomplete(struct mlx_softc *mlx, u_int *slot, u_int *status)
    439 {
    440 
    441 	/* Status available? */
    442 	if ((mlx_inl(mlx, MLX_V4REG_ODB) & MLX_V4_ODB_HWSAVAIL) != 0) {
    443 		*slot = mlx_inb(mlx, MLX_V4REG_STATUS_IDENT);
    444 		*status = mlx_inw(mlx, MLX_V4REG_STATUS);
    445 
    446 		/* Acknowledge completion. */
    447 		mlx_outl(mlx, MLX_V4REG_ODB, MLX_V4_ODB_HWMBOX_ACK);
    448 		mlx_outl(mlx, MLX_V4REG_IDB, MLX_V4_IDB_SACK);
    449 		return (1);
    450 	}
    451 
    452 	return (0);
    453 }
    454 
    455 /*
    456  * Enable/disable interrupts as requested.
    457  *
    458  * Must be called at splbio or in a fashion that prevents reentry.
    459  */
    460 static void
    461 mlx_v4_intaction(struct mlx_softc *mlx, int action)
    462 {
    463 	u_int32_t ier;
    464 
    465 	if (!action)
    466 		ier = MLX_V4_IE_MASK | MLX_V4_IE_DISINT;
    467 	else
    468 		ier = MLX_V4_IE_MASK & ~MLX_V4_IE_DISINT;
    469 
    470 	mlx_outl(mlx, MLX_V4REG_IE, ier);
    471 }
    472 
    473 /*
    474  * Poll for firmware error codes during controller initialisation.
    475  *
    476  * Returns 0 if initialisation is complete, 1 if still in progress but no
    477  * error has been fetched, 2 if an error has been retrieved.
    478  */
    479 static int
    480 mlx_v4_fw_handshake(struct mlx_softc *mlx, int *error, int *param1, int *param2)
    481 {
    482 	u_int8_t fwerror;
    483 
    484 	/* First time around, clear any hardware completion status. */
    485 	if ((mlx->mlx_flags & MLXF_FW_INITTED) == 0) {
    486 		mlx_outl(mlx, MLX_V4REG_IDB, MLX_V4_IDB_SACK);
    487 		DELAY(1000);
    488 		mlx->mlx_flags |= MLXF_FW_INITTED;
    489 	}
    490 
    491 	/* Init in progress? */
    492 	if ((mlx_inl(mlx, MLX_V4REG_IDB) & MLX_V4_IDB_INIT_BUSY) == 0)
    493 		return (0);
    494 
    495 	/* Test error value */
    496 	fwerror = mlx_inb(mlx, MLX_V4REG_FWERROR);
    497 	if ((fwerror & MLX_V4_FWERROR_PEND) == 0)
    498 		return (1);
    499 
    500 	/* Mask status pending bit, fetch status. */
    501 	*error = fwerror & ~MLX_V4_FWERROR_PEND;
    502 	*param1 = mlx_inb(mlx, MLX_V4REG_FWERROR_PARAM1);
    503 	*param2 = mlx_inb(mlx, MLX_V4REG_FWERROR_PARAM2);
    504 
    505 	/* Acknowledge. */
    506 	mlx_outb(mlx, MLX_V4REG_FWERROR, 0);
    507 
    508 	return (2);
    509 }
    510 
    511 /*
    512  * ================= V5 interface linkage =================
    513  */
    514 
    515 /*
    516  * Try to give (mc) to the controller.  Returns 1 if successful, 0 on failure
    517  * (the controller is not ready to take a command).
    518  *
    519  * Must be called at splbio or in a fashion that prevents reentry.
    520  */
    521 static int
    522 mlx_v5_submit(struct mlx_softc *mlx, struct mlx_ccb *mc)
    523 {
    524 
    525 	/* Ready for our command? */
    526 	if ((mlx_inb(mlx, MLX_V5REG_IDB) & MLX_V5_IDB_EMPTY) != 0) {
    527 		/* Copy mailbox data to window. */
    528 		bus_space_write_region_4(mlx->mlx_iot, mlx->mlx_ioh,
    529 		    MLX_V5REG_MAILBOX, (const u_int32_t *)mc->mc_mbox,
    530 		    MLX_V5_MAILBOX_LEN >> 2);
    531 		bus_space_barrier(mlx->mlx_iot, mlx->mlx_ioh,
    532 		    MLX_V5REG_MAILBOX, MLX_V5_MAILBOX_LEN,
    533 		    BUS_SPACE_BARRIER_WRITE);
    534 
    535 		/* Post command */
    536 		mlx_outb(mlx, MLX_V5REG_IDB, MLX_V5_IDB_HWMBOX_CMD);
    537 		return (1);
    538 	}
    539 
    540 	return (0);
    541 }
    542 
    543 /*
    544  * See if a command has been completed, if so acknowledge its completion and
    545  * recover the slot number and status code.
    546  *
    547  * Must be called at splbio or in a fashion that prevents reentry.
    548  */
    549 static int
    550 mlx_v5_findcomplete(struct mlx_softc *mlx, u_int *slot, u_int *status)
    551 {
    552 
    553 	/* Status available? */
    554 	if ((mlx_inb(mlx, MLX_V5REG_ODB) & MLX_V5_ODB_HWSAVAIL) != 0) {
    555 		*slot = mlx_inb(mlx, MLX_V5REG_STATUS_IDENT);
    556 		*status = mlx_inw(mlx, MLX_V5REG_STATUS);
    557 
    558 		/* Acknowledge completion. */
    559 		mlx_outb(mlx, MLX_V5REG_ODB, MLX_V5_ODB_HWMBOX_ACK);
    560 		mlx_outb(mlx, MLX_V5REG_IDB, MLX_V5_IDB_SACK);
    561 		return (1);
    562 	}
    563 
    564 	return (0);
    565 }
    566 
    567 /*
    568  * Enable/disable interrupts as requested.
    569  *
    570  * Must be called at splbio or in a fashion that prevents reentry.
    571  */
    572 static void
    573 mlx_v5_intaction(struct mlx_softc *mlx, int action)
    574 {
    575 	u_int8_t ier;
    576 
    577 	if (!action)
    578 		ier = 0xff & MLX_V5_IE_DISINT;
    579 	else
    580 		ier = 0xff & ~MLX_V5_IE_DISINT;
    581 
    582 	mlx_outb(mlx, MLX_V5REG_IE, ier);
    583 }
    584 
    585 /*
    586  * Poll for firmware error codes during controller initialisation.
    587  *
    588  * Returns 0 if initialisation is complete, 1 if still in progress but no
    589  * error has been fetched, 2 if an error has been retrieved.
    590  */
    591 static int
    592 mlx_v5_fw_handshake(struct mlx_softc *mlx, int *error, int *param1, int *param2)
    593 {
    594 	u_int8_t fwerror;
    595 
    596 	/* First time around, clear any hardware completion status. */
    597 	if ((mlx->mlx_flags & MLXF_FW_INITTED) == 0) {
    598 		mlx_outb(mlx, MLX_V5REG_IDB, MLX_V5_IDB_SACK);
    599 		DELAY(1000);
    600 		mlx->mlx_flags |= MLXF_FW_INITTED;
    601 	}
    602 
    603 	/* Init in progress? */
    604 	if ((mlx_inb(mlx, MLX_V5REG_IDB) & MLX_V5_IDB_INIT_DONE) != 0)
    605 		return (0);
    606 
    607 	/* Test for error value. */
    608 	fwerror = mlx_inb(mlx, MLX_V5REG_FWERROR);
    609 	if ((fwerror & MLX_V5_FWERROR_PEND) == 0)
    610 		return (1);
    611 
    612 	/* Mask status pending bit, fetch status. */
    613 	*error = fwerror & ~MLX_V5_FWERROR_PEND;
    614 	*param1 = mlx_inb(mlx, MLX_V5REG_FWERROR_PARAM1);
    615 	*param2 = mlx_inb(mlx, MLX_V5REG_FWERROR_PARAM2);
    616 
    617 	/* Acknowledge. */
    618 	mlx_outb(mlx, MLX_V5REG_FWERROR, 0xff);
    619 
    620 	return (2);
    621 }
    622