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