Home | History | Annotate | Line # | Download | only in pci
mlx_pci.c revision 1.25
      1 /*	$NetBSD: mlx_pci.c,v 1.25 2014/03/29 19:28:25 christos 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.25 2014/03/29 19:28:25 christos 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_NEW(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 	char intrbuf[PCI_INTRSTR_LEN];
    204 
    205 	mlx = device_private(self);
    206 	pa = aux;
    207 	pc = pa->pa_pc;
    208 	mpi = mlx_pci_findmpi(aux);
    209 
    210 	mlx->mlx_dv = self;
    211 	mlx->mlx_dmat = pa->pa_dmat;
    212 	mlx->mlx_ci.ci_iftype = mpi->mpi_iftype;
    213 
    214 	printf(": Mylex RAID (v%d interface)\n", mpi->mpi_iftype);
    215 
    216 	/*
    217 	 * Map the PCI register window.
    218 	 */
    219 	memr = -1;
    220 	ior = -1;
    221 
    222 	for (i = 0x10; i <= 0x14; i += 4) {
    223 		reg = pci_conf_read(pa->pa_pc, pa->pa_tag, i);
    224 
    225 		if (PCI_MAPREG_TYPE(reg) == PCI_MAPREG_TYPE_IO) {
    226 			if (ior == -1 && PCI_MAPREG_IO_SIZE(reg) != 0)
    227 				ior = i;
    228 		} else {
    229 			if (memr == -1 && PCI_MAPREG_MEM_SIZE(reg) != 0)
    230 				memr = i;
    231 		}
    232 	}
    233 
    234 	if (memr != -1)
    235 		if (pci_mapreg_map(pa, memr, PCI_MAPREG_TYPE_MEM, 0,
    236 		    &memt, &memh, NULL, NULL))
    237 			memr = -1;
    238 	if (ior != -1)
    239 		if (pci_mapreg_map(pa, ior, PCI_MAPREG_TYPE_IO, 0,
    240 		    &iot, &ioh, NULL, NULL))
    241 		    	ior = -1;
    242 
    243 	if (memr != -1) {
    244 		mlx->mlx_iot = memt;
    245 		mlx->mlx_ioh = memh;
    246 	} else if (ior != -1) {
    247 		mlx->mlx_iot = iot;
    248 		mlx->mlx_ioh = ioh;
    249 	} else {
    250 		aprint_error_dev(self, "can't map i/o or memory space\n");
    251 		return;
    252 	}
    253 
    254 	/* Enable the device. */
    255 	reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
    256 	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
    257 	    reg | PCI_COMMAND_MASTER_ENABLE);
    258 
    259 	/* Map and establish the interrupt. */
    260 	if (pci_intr_map(pa, &ih)) {
    261 		aprint_error_dev(self, "can't map interrupt\n");
    262 		return;
    263 	}
    264 	intrstr = pci_intr_string(pc, ih, intrbuf, sizeof(intrbuf));
    265 	mlx->mlx_ih = pci_intr_establish(pc, ih, IPL_BIO, mlx_intr, mlx);
    266 	if (mlx->mlx_ih == NULL) {
    267 		aprint_error_dev(self, "can't establish interrupt");
    268 		if (intrstr != NULL)
    269 			aprint_error(" at %s", intrstr);
    270 		aprint_error("\n");
    271 		return;
    272 	}
    273 
    274 	/* Select linkage based on controller interface type. */
    275 	switch (mlx->mlx_ci.ci_iftype) {
    276 	case 2:
    277 	case 3:
    278 		mlx->mlx_submit = mlx_v3_submit;
    279 		mlx->mlx_findcomplete = mlx_v3_findcomplete;
    280 		mlx->mlx_intaction = mlx_v3_intaction;
    281 		mlx->mlx_fw_handshake = mlx_v3_fw_handshake;
    282 #ifdef MLX_RESET
    283 		mlx->mlx_reset = mlx_v3_reset;
    284 #endif
    285 		break;
    286 
    287 	case 4:
    288 		mlx->mlx_submit = mlx_v4_submit;
    289 		mlx->mlx_findcomplete = mlx_v4_findcomplete;
    290 		mlx->mlx_intaction = mlx_v4_intaction;
    291 		mlx->mlx_fw_handshake = mlx_v4_fw_handshake;
    292 		break;
    293 
    294 	case 5:
    295 		mlx->mlx_submit = mlx_v5_submit;
    296 		mlx->mlx_findcomplete = mlx_v5_findcomplete;
    297 		mlx->mlx_intaction = mlx_v5_intaction;
    298 		mlx->mlx_fw_handshake = mlx_v5_fw_handshake;
    299 		break;
    300 	}
    301 
    302 	mlx_init(mlx, intrstr);
    303 }
    304 
    305 /*
    306  * ================= V3 interface linkage =================
    307  */
    308 
    309 /*
    310  * Try to give (mc) to the controller.  Returns 1 if successful, 0 on
    311  * failure (the controller is not ready to take a command).
    312  *
    313  * Must be called at splbio or in a fashion that prevents reentry.
    314  */
    315 static int
    316 mlx_v3_submit(struct mlx_softc *mlx, struct mlx_ccb *mc)
    317 {
    318 
    319 	/* Ready for our command? */
    320 	if ((mlx_inb(mlx, MLX_V3REG_IDB) & MLX_V3_IDB_FULL) == 0) {
    321 		/* Copy mailbox data to window. */
    322 		bus_space_write_region_1(mlx->mlx_iot, mlx->mlx_ioh,
    323 		    MLX_V3REG_MAILBOX, mc->mc_mbox, 13);
    324 		bus_space_barrier(mlx->mlx_iot, mlx->mlx_ioh,
    325 		    MLX_V3REG_MAILBOX, 13,
    326 		    BUS_SPACE_BARRIER_WRITE);
    327 
    328 		/* Post command. */
    329 		mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_FULL);
    330 		return (1);
    331 	}
    332 
    333 	return (0);
    334 }
    335 
    336 /*
    337  * See if a command has been completed, if so acknowledge its completion and
    338  * recover the slot number and status code.
    339  *
    340  * Must be called at splbio or in a fashion that prevents reentry.
    341  */
    342 static int
    343 mlx_v3_findcomplete(struct mlx_softc *mlx, u_int *slot, u_int *status)
    344 {
    345 
    346 	/* Status available? */
    347 	if ((mlx_inb(mlx, MLX_V3REG_ODB) & MLX_V3_ODB_SAVAIL) != 0) {
    348 		*slot = mlx_inb(mlx, MLX_V3REG_STATUS_IDENT);
    349 		*status = mlx_inw(mlx, MLX_V3REG_STATUS);
    350 
    351 		/* Acknowledge completion. */
    352 		mlx_outb(mlx, MLX_V3REG_ODB, MLX_V3_ODB_SAVAIL);
    353 		mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_SACK);
    354 		return (1);
    355 	}
    356 
    357 	return (0);
    358 }
    359 
    360 /*
    361  * Enable/disable interrupts as requested. (No acknowledge required)
    362  *
    363  * Must be called at splbio or in a fashion that prevents reentry.
    364  */
    365 static void
    366 mlx_v3_intaction(struct mlx_softc *mlx, int action)
    367 {
    368 
    369 	mlx_outb(mlx, MLX_V3REG_IE, action != 0);
    370 }
    371 
    372 /*
    373  * Poll for firmware error codes during controller initialisation.
    374  *
    375  * Returns 0 if initialisation is complete, 1 if still in progress but no
    376  * error has been fetched, 2 if an error has been retrieved.
    377  */
    378 static int
    379 mlx_v3_fw_handshake(struct mlx_softc *mlx, int *error, int *param1, int *param2)
    380 {
    381 	u_int8_t fwerror;
    382 
    383 	/* First time around, clear any hardware completion status. */
    384 	if ((mlx->mlx_flags & MLXF_FW_INITTED) == 0) {
    385 		mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_SACK);
    386 		DELAY(1000);
    387 		mlx->mlx_flags |= MLXF_FW_INITTED;
    388 	}
    389 
    390 	/* Init in progress? */
    391 	if ((mlx_inb(mlx, MLX_V3REG_IDB) & MLX_V3_IDB_INIT_BUSY) == 0)
    392 		return (0);
    393 
    394 	/* Test error value. */
    395 	fwerror = mlx_inb(mlx, MLX_V3REG_FWERROR);
    396 
    397 	if ((fwerror & MLX_V3_FWERROR_PEND) == 0)
    398 		return (1);
    399 
    400 	/* Mask status pending bit, fetch status. */
    401 	*error = fwerror & ~MLX_V3_FWERROR_PEND;
    402 	*param1 = mlx_inb(mlx, MLX_V3REG_FWERROR_PARAM1);
    403 	*param2 = mlx_inb(mlx, MLX_V3REG_FWERROR_PARAM2);
    404 
    405 	/* Acknowledge. */
    406 	mlx_outb(mlx, MLX_V3REG_FWERROR, 0);
    407 
    408 	return (2);
    409 }
    410 
    411 #ifdef MLX_RESET
    412 /*
    413  * Reset the controller.  Return non-zero on failure.
    414  */
    415 static int
    416 mlx_v3_reset(struct mlx_softc *mlx)
    417 {
    418 	int i;
    419 
    420 	mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_SACK);
    421 	delay(1000000);
    422 
    423 	/* Wait up to 2 minutes for the bit to clear. */
    424 	for (i = 120; i != 0; i--) {
    425 		delay(1000000);
    426 		if ((mlx_inb(mlx, MLX_V3REG_IDB) & MLX_V3_IDB_SACK) == 0)
    427 			break;
    428 	}
    429 	if (i == 0) {
    430 		/* ZZZ */
    431 		printf("mlx0: SACK didn't clear\n");
    432 		return (-1);
    433 	}
    434 
    435 	mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_RESET);
    436 
    437 	/* Wait up to 5 seconds for the bit to clear. */
    438 	for (i = 5; i != 0; i--) {
    439 		delay(1000000);
    440 		if ((mlx_inb(mlx, MLX_V3REG_IDB) & MLX_V3_IDB_RESET) == 0)
    441 			break;
    442 	}
    443 	if (i == 0) {
    444 		/* ZZZ */
    445 		printf("mlx0: RESET didn't clear\n");
    446 		return (-1);
    447 	}
    448 
    449 	return (0);
    450 }
    451 #endif	/* MLX_RESET */
    452 
    453 /*
    454  * ================= V4 interface linkage =================
    455  */
    456 
    457 /*
    458  * Try to give (mc) to the controller.  Returns 1 if successful, 0 on
    459  * failure (the controller is not ready to take a command).
    460  *
    461  * Must be called at splbio or in a fashion that prevents reentry.
    462  */
    463 static int
    464 mlx_v4_submit(struct mlx_softc *mlx, struct mlx_ccb *mc)
    465 {
    466 
    467 	/* Ready for our command? */
    468 	if ((mlx_inl(mlx, MLX_V4REG_IDB) & MLX_V4_IDB_FULL) == 0) {
    469 		/* Copy mailbox data to window. */
    470 		bus_space_write_region_1(mlx->mlx_iot, mlx->mlx_ioh,
    471 		    MLX_V4REG_MAILBOX, mc->mc_mbox, 13);
    472 		bus_space_barrier(mlx->mlx_iot, mlx->mlx_ioh,
    473 		    MLX_V4REG_MAILBOX, 13,
    474 		    BUS_SPACE_BARRIER_WRITE);
    475 
    476 		/* Post command. */
    477 		mlx_outl(mlx, MLX_V4REG_IDB, MLX_V4_IDB_HWMBOX_CMD);
    478 		return (1);
    479 	}
    480 
    481 	return (0);
    482 }
    483 
    484 /*
    485  * See if a command has been completed, if so acknowledge its completion and
    486  * recover the slot number and status code.
    487  *
    488  * Must be called at splbio or in a fashion that prevents reentry.
    489  */
    490 static int
    491 mlx_v4_findcomplete(struct mlx_softc *mlx, u_int *slot, u_int *status)
    492 {
    493 
    494 	/* Status available? */
    495 	if ((mlx_inl(mlx, MLX_V4REG_ODB) & MLX_V4_ODB_HWSAVAIL) != 0) {
    496 		*slot = mlx_inb(mlx, MLX_V4REG_STATUS_IDENT);
    497 		*status = mlx_inw(mlx, MLX_V4REG_STATUS);
    498 
    499 		/* Acknowledge completion. */
    500 		mlx_outl(mlx, MLX_V4REG_ODB, MLX_V4_ODB_HWMBOX_ACK);
    501 		mlx_outl(mlx, MLX_V4REG_IDB, MLX_V4_IDB_SACK);
    502 		return (1);
    503 	}
    504 
    505 	return (0);
    506 }
    507 
    508 /*
    509  * Enable/disable interrupts as requested.
    510  *
    511  * Must be called at splbio or in a fashion that prevents reentry.
    512  */
    513 static void
    514 mlx_v4_intaction(struct mlx_softc *mlx, int action)
    515 {
    516 	u_int32_t ier;
    517 
    518 	if (!action)
    519 		ier = MLX_V4_IE_MASK | MLX_V4_IE_DISINT;
    520 	else
    521 		ier = MLX_V4_IE_MASK & ~MLX_V4_IE_DISINT;
    522 
    523 	mlx_outl(mlx, MLX_V4REG_IE, ier);
    524 }
    525 
    526 /*
    527  * Poll for firmware error codes during controller initialisation.
    528  *
    529  * Returns 0 if initialisation is complete, 1 if still in progress but no
    530  * error has been fetched, 2 if an error has been retrieved.
    531  */
    532 static int
    533 mlx_v4_fw_handshake(struct mlx_softc *mlx, int *error, int *param1, int *param2)
    534 {
    535 	u_int8_t fwerror;
    536 
    537 	/* First time around, clear any hardware completion status. */
    538 	if ((mlx->mlx_flags & MLXF_FW_INITTED) == 0) {
    539 		mlx_outl(mlx, MLX_V4REG_IDB, MLX_V4_IDB_SACK);
    540 		DELAY(1000);
    541 		mlx->mlx_flags |= MLXF_FW_INITTED;
    542 	}
    543 
    544 	/* Init in progress? */
    545 	if ((mlx_inl(mlx, MLX_V4REG_IDB) & MLX_V4_IDB_INIT_BUSY) == 0)
    546 		return (0);
    547 
    548 	/* Test error value */
    549 	fwerror = mlx_inb(mlx, MLX_V4REG_FWERROR);
    550 	if ((fwerror & MLX_V4_FWERROR_PEND) == 0)
    551 		return (1);
    552 
    553 	/* Mask status pending bit, fetch status. */
    554 	*error = fwerror & ~MLX_V4_FWERROR_PEND;
    555 	*param1 = mlx_inb(mlx, MLX_V4REG_FWERROR_PARAM1);
    556 	*param2 = mlx_inb(mlx, MLX_V4REG_FWERROR_PARAM2);
    557 
    558 	/* Acknowledge. */
    559 	mlx_outb(mlx, MLX_V4REG_FWERROR, 0);
    560 
    561 	return (2);
    562 }
    563 
    564 /*
    565  * ================= V5 interface linkage =================
    566  */
    567 
    568 /*
    569  * Try to give (mc) to the controller.  Returns 1 if successful, 0 on failure
    570  * (the controller is not ready to take a command).
    571  *
    572  * Must be called at splbio or in a fashion that prevents reentry.
    573  */
    574 static int
    575 mlx_v5_submit(struct mlx_softc *mlx, struct mlx_ccb *mc)
    576 {
    577 
    578 	/* Ready for our command? */
    579 	if ((mlx_inb(mlx, MLX_V5REG_IDB) & MLX_V5_IDB_EMPTY) != 0) {
    580 		/* Copy mailbox data to window. */
    581 		bus_space_write_region_1(mlx->mlx_iot, mlx->mlx_ioh,
    582 		    MLX_V5REG_MAILBOX, mc->mc_mbox, 13);
    583 		bus_space_barrier(mlx->mlx_iot, mlx->mlx_ioh,
    584 		    MLX_V5REG_MAILBOX, 13,
    585 		    BUS_SPACE_BARRIER_WRITE);
    586 
    587 		/* Post command */
    588 		mlx_outb(mlx, MLX_V5REG_IDB, MLX_V5_IDB_HWMBOX_CMD);
    589 		return (1);
    590 	}
    591 
    592 	return (0);
    593 }
    594 
    595 /*
    596  * See if a command has been completed, if so acknowledge its completion and
    597  * recover the slot number and status code.
    598  *
    599  * Must be called at splbio or in a fashion that prevents reentry.
    600  */
    601 static int
    602 mlx_v5_findcomplete(struct mlx_softc *mlx, u_int *slot, u_int *status)
    603 {
    604 
    605 	/* Status available? */
    606 	if ((mlx_inb(mlx, MLX_V5REG_ODB) & MLX_V5_ODB_HWSAVAIL) != 0) {
    607 		*slot = mlx_inb(mlx, MLX_V5REG_STATUS_IDENT);
    608 		*status = mlx_inw(mlx, MLX_V5REG_STATUS);
    609 
    610 		/* Acknowledge completion. */
    611 		mlx_outb(mlx, MLX_V5REG_ODB, MLX_V5_ODB_HWMBOX_ACK);
    612 		mlx_outb(mlx, MLX_V5REG_IDB, MLX_V5_IDB_SACK);
    613 		return (1);
    614 	}
    615 
    616 	return (0);
    617 }
    618 
    619 /*
    620  * Enable/disable interrupts as requested.
    621  *
    622  * Must be called at splbio or in a fashion that prevents reentry.
    623  */
    624 static void
    625 mlx_v5_intaction(struct mlx_softc *mlx, int action)
    626 {
    627 	u_int8_t ier;
    628 
    629 	if (!action)
    630 		ier = 0xff & MLX_V5_IE_DISINT;
    631 	else
    632 		ier = 0xff & ~MLX_V5_IE_DISINT;
    633 
    634 	mlx_outb(mlx, MLX_V5REG_IE, ier);
    635 }
    636 
    637 /*
    638  * Poll for firmware error codes during controller initialisation.
    639  *
    640  * Returns 0 if initialisation is complete, 1 if still in progress but no
    641  * error has been fetched, 2 if an error has been retrieved.
    642  */
    643 static int
    644 mlx_v5_fw_handshake(struct mlx_softc *mlx, int *error, int *param1, int *param2)
    645 {
    646 	u_int8_t fwerror;
    647 
    648 	/* First time around, clear any hardware completion status. */
    649 	if ((mlx->mlx_flags & MLXF_FW_INITTED) == 0) {
    650 		mlx_outb(mlx, MLX_V5REG_IDB, MLX_V5_IDB_SACK);
    651 		DELAY(1000);
    652 		mlx->mlx_flags |= MLXF_FW_INITTED;
    653 	}
    654 
    655 	/* Init in progress? */
    656 	if ((mlx_inb(mlx, MLX_V5REG_IDB) & MLX_V5_IDB_INIT_DONE) != 0)
    657 		return (0);
    658 
    659 	/* Test for error value. */
    660 	fwerror = mlx_inb(mlx, MLX_V5REG_FWERROR);
    661 	if ((fwerror & MLX_V5_FWERROR_PEND) == 0)
    662 		return (1);
    663 
    664 	/* Mask status pending bit, fetch status. */
    665 	*error = fwerror & ~MLX_V5_FWERROR_PEND;
    666 	*param1 = mlx_inb(mlx, MLX_V5REG_FWERROR_PARAM1);
    667 	*param2 = mlx_inb(mlx, MLX_V5REG_FWERROR_PARAM2);
    668 
    669 	/* Acknowledge. */
    670 	mlx_outb(mlx, MLX_V5REG_FWERROR, 0xff);
    671 
    672 	return (2);
    673 }
    674