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