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