Home | History | Annotate | Line # | Download | only in pci
mlx_pci.c revision 1.1.2.2
      1 /*	$NetBSD: mlx_pci.c,v 1.1.2.2 2001/02/11 19:15:58 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, mc->mc_mbox, MLX_V4_MAILBOX_LEN >> 2);
    418 		bus_space_barrier(mlx->mlx_iot, mlx->mlx_ioh,
    419 		    MLX_V4REG_MAILBOX, MLX_V4_MAILBOX_LEN,
    420 		    BUS_SPACE_BARRIER_WRITE);
    421 
    422 		/* Post command. */
    423 		mlx_outl(mlx, MLX_V4REG_IDB, MLX_V4_IDB_HWMBOX_CMD);
    424 		return (1);
    425 	}
    426 
    427 	return (0);
    428 }
    429 
    430 /*
    431  * See if a command has been completed, if so acknowledge its completion and
    432  * recover the slot number and status code.
    433  *
    434  * Must be called at splbio or in a fashion that prevents reentry.
    435  */
    436 static int
    437 mlx_v4_findcomplete(struct mlx_softc *mlx, u_int *slot, u_int *status)
    438 {
    439 
    440 	/* Status available? */
    441 	if ((mlx_inl(mlx, MLX_V4REG_ODB) & MLX_V4_ODB_HWSAVAIL) != 0) {
    442 		*slot = mlx_inb(mlx, MLX_V4REG_STATUS_IDENT);
    443 		*status = mlx_inw(mlx, MLX_V4REG_STATUS);
    444 
    445 		/* Acknowledge completion. */
    446 		mlx_outl(mlx, MLX_V4REG_ODB, MLX_V4_ODB_HWMBOX_ACK);
    447 		mlx_outl(mlx, MLX_V4REG_IDB, MLX_V4_IDB_SACK);
    448 		return (1);
    449 	}
    450 
    451 	return (0);
    452 }
    453 
    454 /*
    455  * Enable/disable interrupts as requested.
    456  *
    457  * Must be called at splbio or in a fashion that prevents reentry.
    458  */
    459 static void
    460 mlx_v4_intaction(struct mlx_softc *mlx, int action)
    461 {
    462 	u_int32_t ier;
    463 
    464 	if (!action)
    465 		ier = MLX_V4_IE_MASK | MLX_V4_IE_DISINT;
    466 	else
    467 		ier = MLX_V4_IE_MASK & ~MLX_V4_IE_DISINT;
    468 
    469 	mlx_outl(mlx, MLX_V4REG_IE, ier);
    470 }
    471 
    472 /*
    473  * Poll for firmware error codes during controller initialisation.
    474  *
    475  * Returns 0 if initialisation is complete, 1 if still in progress but no
    476  * error has been fetched, 2 if an error has been retrieved.
    477  */
    478 static int
    479 mlx_v4_fw_handshake(struct mlx_softc *mlx, int *error, int *param1, int *param2)
    480 {
    481 	u_int8_t fwerror;
    482 
    483 	/* First time around, clear any hardware completion status. */
    484 	if ((mlx->mlx_flags & MLXF_FW_INITTED) == 0) {
    485 		mlx_outl(mlx, MLX_V4REG_IDB, MLX_V4_IDB_SACK);
    486 		DELAY(1000);
    487 		mlx->mlx_flags |= MLXF_FW_INITTED;
    488 	}
    489 
    490 	/* Init in progress? */
    491 	if ((mlx_inl(mlx, MLX_V4REG_IDB) & MLX_V4_IDB_INIT_BUSY) == 0)
    492 		return (0);
    493 
    494 	/* Test error value */
    495 	fwerror = mlx_inb(mlx, MLX_V4REG_FWERROR);
    496 	if ((fwerror & MLX_V4_FWERROR_PEND) == 0)
    497 		return (1);
    498 
    499 	/* Mask status pending bit, fetch status. */
    500 	*error = fwerror & ~MLX_V4_FWERROR_PEND;
    501 	*param1 = mlx_inb(mlx, MLX_V4REG_FWERROR_PARAM1);
    502 	*param2 = mlx_inb(mlx, MLX_V4REG_FWERROR_PARAM2);
    503 
    504 	/* Acknowledge. */
    505 	mlx_outb(mlx, MLX_V4REG_FWERROR, 0);
    506 
    507 	return (2);
    508 }
    509 
    510 /*
    511  * ================= V5 interface linkage =================
    512  */
    513 
    514 /*
    515  * Try to give (mc) to the controller.  Returns 1 if successful, 0 on failure
    516  * (the controller is not ready to take a command).
    517  *
    518  * Must be called at splbio or in a fashion that prevents reentry.
    519  */
    520 static int
    521 mlx_v5_submit(struct mlx_softc *mlx, struct mlx_ccb *mc)
    522 {
    523 
    524 	/* Ready for our command? */
    525 	if ((mlx_inb(mlx, MLX_V5REG_IDB) & MLX_V5_IDB_EMPTY) != 0) {
    526 		/* Copy mailbox data to window. */
    527 		bus_space_write_region_4(mlx->mlx_iot, mlx->mlx_ioh,
    528 		    MLX_V5REG_MAILBOX, mc->mc_mbox, MLX_V5_MAILBOX_LEN >> 2);
    529 		bus_space_barrier(mlx->mlx_iot, mlx->mlx_ioh,
    530 		    MLX_V5REG_MAILBOX, MLX_V5_MAILBOX_LEN,
    531 		    BUS_SPACE_BARRIER_WRITE);
    532 
    533 		/* Post command */
    534 		mlx_outb(mlx, MLX_V5REG_IDB, MLX_V5_IDB_HWMBOX_CMD);
    535 		return (1);
    536 	}
    537 
    538 	return (0);
    539 }
    540 
    541 /*
    542  * See if a command has been completed, if so acknowledge its completion and
    543  * recover the slot number and status code.
    544  *
    545  * Must be called at splbio or in a fashion that prevents reentry.
    546  */
    547 static int
    548 mlx_v5_findcomplete(struct mlx_softc *mlx, u_int *slot, u_int *status)
    549 {
    550 
    551 	/* Status available? */
    552 	if ((mlx_inb(mlx, MLX_V5REG_ODB) & MLX_V5_ODB_HWSAVAIL) != 0) {
    553 		*slot = mlx_inb(mlx, MLX_V5REG_STATUS_IDENT);
    554 		*status = mlx_inw(mlx, MLX_V5REG_STATUS);
    555 
    556 		/* Acknowledge completion. */
    557 		mlx_outb(mlx, MLX_V5REG_ODB, MLX_V5_ODB_HWMBOX_ACK);
    558 		mlx_outb(mlx, MLX_V5REG_IDB, MLX_V5_IDB_SACK);
    559 		return (1);
    560 	}
    561 
    562 	return (0);
    563 }
    564 
    565 /*
    566  * Enable/disable interrupts as requested.
    567  *
    568  * Must be called at splbio or in a fashion that prevents reentry.
    569  */
    570 static void
    571 mlx_v5_intaction(struct mlx_softc *mlx, int action)
    572 {
    573 	u_int8_t ier;
    574 
    575 	if (!action)
    576 		ier = 0xff & MLX_V5_IE_DISINT;
    577 	else
    578 		ier = 0xff & ~MLX_V5_IE_DISINT;
    579 
    580 	mlx_outb(mlx, MLX_V5REG_IE, ier);
    581 }
    582 
    583 /*
    584  * Poll for firmware error codes during controller initialisation.
    585  *
    586  * Returns 0 if initialisation is complete, 1 if still in progress but no
    587  * error has been fetched, 2 if an error has been retrieved.
    588  */
    589 static int
    590 mlx_v5_fw_handshake(struct mlx_softc *mlx, int *error, int *param1, int *param2)
    591 {
    592 	u_int8_t fwerror;
    593 
    594 	/* First time around, clear any hardware completion status. */
    595 	if ((mlx->mlx_flags & MLXF_FW_INITTED) == 0) {
    596 		mlx_outb(mlx, MLX_V5REG_IDB, MLX_V5_IDB_SACK);
    597 		DELAY(1000);
    598 		mlx->mlx_flags |= MLXF_FW_INITTED;
    599 	}
    600 
    601 	/* Init in progress? */
    602 	if ((mlx_inb(mlx, MLX_V5REG_IDB) & MLX_V5_IDB_INIT_DONE) != 0)
    603 		return (0);
    604 
    605 	/* Test for error value. */
    606 	fwerror = mlx_inb(mlx, MLX_V5REG_FWERROR);
    607 	if ((fwerror & MLX_V5_FWERROR_PEND) == 0)
    608 		return (1);
    609 
    610 	/* Mask status pending bit, fetch status. */
    611 	*error = fwerror & ~MLX_V5_FWERROR_PEND;
    612 	*param1 = mlx_inb(mlx, MLX_V5REG_FWERROR_PARAM1);
    613 	*param2 = mlx_inb(mlx, MLX_V5REG_FWERROR_PARAM2);
    614 
    615 	/* Acknowledge. */
    616 	mlx_outb(mlx, MLX_V5REG_FWERROR, 0xff);
    617 
    618 	return (2);
    619 }
    620