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