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