xref: /netbsd-src/sys/dev/pci/mlx_pci.c (revision deb6f0161a9109e7de9b519dc8dfb9478668dcdd)
1 /*	$NetBSD: mlx_pci.c,v 1.26 2016/09/27 03:33:32 pgoyette 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.26 2016/09/27 03:33:32 pgoyette 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(pc, ih, IPL_BIO, mlx_intr, mlx);
276 	if (mlx->mlx_ih == NULL) {
277 		aprint_error_dev(self, "can't establish interrupt");
278 		if (intrstr != NULL)
279 			aprint_error(" at %s", intrstr);
280 		aprint_error("\n");
281 		return;
282 	}
283 
284 	/* Select linkage based on controller interface type. */
285 	switch (mlx->mlx_ci.ci_iftype) {
286 	case 2:
287 	case 3:
288 		mlx->mlx_submit = mlx_v3_submit;
289 		mlx->mlx_findcomplete = mlx_v3_findcomplete;
290 		mlx->mlx_intaction = mlx_v3_intaction;
291 		mlx->mlx_fw_handshake = mlx_v3_fw_handshake;
292 #ifdef MLX_RESET
293 		mlx->mlx_reset = mlx_v3_reset;
294 #endif
295 		break;
296 
297 	case 4:
298 		mlx->mlx_submit = mlx_v4_submit;
299 		mlx->mlx_findcomplete = mlx_v4_findcomplete;
300 		mlx->mlx_intaction = mlx_v4_intaction;
301 		mlx->mlx_fw_handshake = mlx_v4_fw_handshake;
302 		break;
303 
304 	case 5:
305 		mlx->mlx_submit = mlx_v5_submit;
306 		mlx->mlx_findcomplete = mlx_v5_findcomplete;
307 		mlx->mlx_intaction = mlx_v5_intaction;
308 		mlx->mlx_fw_handshake = mlx_v5_fw_handshake;
309 		break;
310 	}
311 
312 	mlx_init(mlx, intrstr);
313 }
314 
315 /*
316  * ================= V3 interface linkage =================
317  */
318 
319 /*
320  * Try to give (mc) to the controller.  Returns 1 if successful, 0 on
321  * failure (the controller is not ready to take a command).
322  *
323  * Must be called at splbio or in a fashion that prevents reentry.
324  */
325 static int
326 mlx_v3_submit(struct mlx_softc *mlx, struct mlx_ccb *mc)
327 {
328 
329 	/* Ready for our command? */
330 	if ((mlx_inb(mlx, MLX_V3REG_IDB) & MLX_V3_IDB_FULL) == 0) {
331 		/* Copy mailbox data to window. */
332 		bus_space_write_region_1(mlx->mlx_iot, mlx->mlx_ioh,
333 		    MLX_V3REG_MAILBOX, mc->mc_mbox, 13);
334 		bus_space_barrier(mlx->mlx_iot, mlx->mlx_ioh,
335 		    MLX_V3REG_MAILBOX, 13,
336 		    BUS_SPACE_BARRIER_WRITE);
337 
338 		/* Post command. */
339 		mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_FULL);
340 		return (1);
341 	}
342 
343 	return (0);
344 }
345 
346 /*
347  * See if a command has been completed, if so acknowledge its completion and
348  * recover the slot number and status code.
349  *
350  * Must be called at splbio or in a fashion that prevents reentry.
351  */
352 static int
353 mlx_v3_findcomplete(struct mlx_softc *mlx, u_int *slot, u_int *status)
354 {
355 
356 	/* Status available? */
357 	if ((mlx_inb(mlx, MLX_V3REG_ODB) & MLX_V3_ODB_SAVAIL) != 0) {
358 		*slot = mlx_inb(mlx, MLX_V3REG_STATUS_IDENT);
359 		*status = mlx_inw(mlx, MLX_V3REG_STATUS);
360 
361 		/* Acknowledge completion. */
362 		mlx_outb(mlx, MLX_V3REG_ODB, MLX_V3_ODB_SAVAIL);
363 		mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_SACK);
364 		return (1);
365 	}
366 
367 	return (0);
368 }
369 
370 /*
371  * Enable/disable interrupts as requested. (No acknowledge required)
372  *
373  * Must be called at splbio or in a fashion that prevents reentry.
374  */
375 static void
376 mlx_v3_intaction(struct mlx_softc *mlx, int action)
377 {
378 
379 	mlx_outb(mlx, MLX_V3REG_IE, action != 0);
380 }
381 
382 /*
383  * Poll for firmware error codes during controller initialisation.
384  *
385  * Returns 0 if initialisation is complete, 1 if still in progress but no
386  * error has been fetched, 2 if an error has been retrieved.
387  */
388 static int
389 mlx_v3_fw_handshake(struct mlx_softc *mlx, int *error, int *param1, int *param2)
390 {
391 	u_int8_t fwerror;
392 
393 	/* First time around, clear any hardware completion status. */
394 	if ((mlx->mlx_flags & MLXF_FW_INITTED) == 0) {
395 		mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_SACK);
396 		DELAY(1000);
397 		mlx->mlx_flags |= MLXF_FW_INITTED;
398 	}
399 
400 	/* Init in progress? */
401 	if ((mlx_inb(mlx, MLX_V3REG_IDB) & MLX_V3_IDB_INIT_BUSY) == 0)
402 		return (0);
403 
404 	/* Test error value. */
405 	fwerror = mlx_inb(mlx, MLX_V3REG_FWERROR);
406 
407 	if ((fwerror & MLX_V3_FWERROR_PEND) == 0)
408 		return (1);
409 
410 	/* Mask status pending bit, fetch status. */
411 	*error = fwerror & ~MLX_V3_FWERROR_PEND;
412 	*param1 = mlx_inb(mlx, MLX_V3REG_FWERROR_PARAM1);
413 	*param2 = mlx_inb(mlx, MLX_V3REG_FWERROR_PARAM2);
414 
415 	/* Acknowledge. */
416 	mlx_outb(mlx, MLX_V3REG_FWERROR, 0);
417 
418 	return (2);
419 }
420 
421 #ifdef MLX_RESET
422 /*
423  * Reset the controller.  Return non-zero on failure.
424  */
425 static int
426 mlx_v3_reset(struct mlx_softc *mlx)
427 {
428 	int i;
429 
430 	mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_SACK);
431 	delay(1000000);
432 
433 	/* Wait up to 2 minutes for the bit to clear. */
434 	for (i = 120; i != 0; i--) {
435 		delay(1000000);
436 		if ((mlx_inb(mlx, MLX_V3REG_IDB) & MLX_V3_IDB_SACK) == 0)
437 			break;
438 	}
439 	if (i == 0) {
440 		/* ZZZ */
441 		printf("mlx0: SACK didn't clear\n");
442 		return (-1);
443 	}
444 
445 	mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_RESET);
446 
447 	/* Wait up to 5 seconds for the bit to clear. */
448 	for (i = 5; i != 0; i--) {
449 		delay(1000000);
450 		if ((mlx_inb(mlx, MLX_V3REG_IDB) & MLX_V3_IDB_RESET) == 0)
451 			break;
452 	}
453 	if (i == 0) {
454 		/* ZZZ */
455 		printf("mlx0: RESET didn't clear\n");
456 		return (-1);
457 	}
458 
459 	return (0);
460 }
461 #endif	/* MLX_RESET */
462 
463 /*
464  * ================= V4 interface linkage =================
465  */
466 
467 /*
468  * Try to give (mc) to the controller.  Returns 1 if successful, 0 on
469  * failure (the controller is not ready to take a command).
470  *
471  * Must be called at splbio or in a fashion that prevents reentry.
472  */
473 static int
474 mlx_v4_submit(struct mlx_softc *mlx, struct mlx_ccb *mc)
475 {
476 
477 	/* Ready for our command? */
478 	if ((mlx_inl(mlx, MLX_V4REG_IDB) & MLX_V4_IDB_FULL) == 0) {
479 		/* Copy mailbox data to window. */
480 		bus_space_write_region_1(mlx->mlx_iot, mlx->mlx_ioh,
481 		    MLX_V4REG_MAILBOX, mc->mc_mbox, 13);
482 		bus_space_barrier(mlx->mlx_iot, mlx->mlx_ioh,
483 		    MLX_V4REG_MAILBOX, 13,
484 		    BUS_SPACE_BARRIER_WRITE);
485 
486 		/* Post command. */
487 		mlx_outl(mlx, MLX_V4REG_IDB, MLX_V4_IDB_HWMBOX_CMD);
488 		return (1);
489 	}
490 
491 	return (0);
492 }
493 
494 /*
495  * See if a command has been completed, if so acknowledge its completion and
496  * recover the slot number and status code.
497  *
498  * Must be called at splbio or in a fashion that prevents reentry.
499  */
500 static int
501 mlx_v4_findcomplete(struct mlx_softc *mlx, u_int *slot, u_int *status)
502 {
503 
504 	/* Status available? */
505 	if ((mlx_inl(mlx, MLX_V4REG_ODB) & MLX_V4_ODB_HWSAVAIL) != 0) {
506 		*slot = mlx_inb(mlx, MLX_V4REG_STATUS_IDENT);
507 		*status = mlx_inw(mlx, MLX_V4REG_STATUS);
508 
509 		/* Acknowledge completion. */
510 		mlx_outl(mlx, MLX_V4REG_ODB, MLX_V4_ODB_HWMBOX_ACK);
511 		mlx_outl(mlx, MLX_V4REG_IDB, MLX_V4_IDB_SACK);
512 		return (1);
513 	}
514 
515 	return (0);
516 }
517 
518 /*
519  * Enable/disable interrupts as requested.
520  *
521  * Must be called at splbio or in a fashion that prevents reentry.
522  */
523 static void
524 mlx_v4_intaction(struct mlx_softc *mlx, int action)
525 {
526 	u_int32_t ier;
527 
528 	if (!action)
529 		ier = MLX_V4_IE_MASK | MLX_V4_IE_DISINT;
530 	else
531 		ier = MLX_V4_IE_MASK & ~MLX_V4_IE_DISINT;
532 
533 	mlx_outl(mlx, MLX_V4REG_IE, ier);
534 }
535 
536 /*
537  * Poll for firmware error codes during controller initialisation.
538  *
539  * Returns 0 if initialisation is complete, 1 if still in progress but no
540  * error has been fetched, 2 if an error has been retrieved.
541  */
542 static int
543 mlx_v4_fw_handshake(struct mlx_softc *mlx, int *error, int *param1, int *param2)
544 {
545 	u_int8_t fwerror;
546 
547 	/* First time around, clear any hardware completion status. */
548 	if ((mlx->mlx_flags & MLXF_FW_INITTED) == 0) {
549 		mlx_outl(mlx, MLX_V4REG_IDB, MLX_V4_IDB_SACK);
550 		DELAY(1000);
551 		mlx->mlx_flags |= MLXF_FW_INITTED;
552 	}
553 
554 	/* Init in progress? */
555 	if ((mlx_inl(mlx, MLX_V4REG_IDB) & MLX_V4_IDB_INIT_BUSY) == 0)
556 		return (0);
557 
558 	/* Test error value */
559 	fwerror = mlx_inb(mlx, MLX_V4REG_FWERROR);
560 	if ((fwerror & MLX_V4_FWERROR_PEND) == 0)
561 		return (1);
562 
563 	/* Mask status pending bit, fetch status. */
564 	*error = fwerror & ~MLX_V4_FWERROR_PEND;
565 	*param1 = mlx_inb(mlx, MLX_V4REG_FWERROR_PARAM1);
566 	*param2 = mlx_inb(mlx, MLX_V4REG_FWERROR_PARAM2);
567 
568 	/* Acknowledge. */
569 	mlx_outb(mlx, MLX_V4REG_FWERROR, 0);
570 
571 	return (2);
572 }
573 
574 /*
575  * ================= V5 interface linkage =================
576  */
577 
578 /*
579  * Try to give (mc) to the controller.  Returns 1 if successful, 0 on failure
580  * (the controller is not ready to take a command).
581  *
582  * Must be called at splbio or in a fashion that prevents reentry.
583  */
584 static int
585 mlx_v5_submit(struct mlx_softc *mlx, struct mlx_ccb *mc)
586 {
587 
588 	/* Ready for our command? */
589 	if ((mlx_inb(mlx, MLX_V5REG_IDB) & MLX_V5_IDB_EMPTY) != 0) {
590 		/* Copy mailbox data to window. */
591 		bus_space_write_region_1(mlx->mlx_iot, mlx->mlx_ioh,
592 		    MLX_V5REG_MAILBOX, mc->mc_mbox, 13);
593 		bus_space_barrier(mlx->mlx_iot, mlx->mlx_ioh,
594 		    MLX_V5REG_MAILBOX, 13,
595 		    BUS_SPACE_BARRIER_WRITE);
596 
597 		/* Post command */
598 		mlx_outb(mlx, MLX_V5REG_IDB, MLX_V5_IDB_HWMBOX_CMD);
599 		return (1);
600 	}
601 
602 	return (0);
603 }
604 
605 /*
606  * See if a command has been completed, if so acknowledge its completion and
607  * recover the slot number and status code.
608  *
609  * Must be called at splbio or in a fashion that prevents reentry.
610  */
611 static int
612 mlx_v5_findcomplete(struct mlx_softc *mlx, u_int *slot, u_int *status)
613 {
614 
615 	/* Status available? */
616 	if ((mlx_inb(mlx, MLX_V5REG_ODB) & MLX_V5_ODB_HWSAVAIL) != 0) {
617 		*slot = mlx_inb(mlx, MLX_V5REG_STATUS_IDENT);
618 		*status = mlx_inw(mlx, MLX_V5REG_STATUS);
619 
620 		/* Acknowledge completion. */
621 		mlx_outb(mlx, MLX_V5REG_ODB, MLX_V5_ODB_HWMBOX_ACK);
622 		mlx_outb(mlx, MLX_V5REG_IDB, MLX_V5_IDB_SACK);
623 		return (1);
624 	}
625 
626 	return (0);
627 }
628 
629 /*
630  * Enable/disable interrupts as requested.
631  *
632  * Must be called at splbio or in a fashion that prevents reentry.
633  */
634 static void
635 mlx_v5_intaction(struct mlx_softc *mlx, int action)
636 {
637 	u_int8_t ier;
638 
639 	if (!action)
640 		ier = 0xff & MLX_V5_IE_DISINT;
641 	else
642 		ier = 0xff & ~MLX_V5_IE_DISINT;
643 
644 	mlx_outb(mlx, MLX_V5REG_IE, ier);
645 }
646 
647 /*
648  * Poll for firmware error codes during controller initialisation.
649  *
650  * Returns 0 if initialisation is complete, 1 if still in progress but no
651  * error has been fetched, 2 if an error has been retrieved.
652  */
653 static int
654 mlx_v5_fw_handshake(struct mlx_softc *mlx, int *error, int *param1, int *param2)
655 {
656 	u_int8_t fwerror;
657 
658 	/* First time around, clear any hardware completion status. */
659 	if ((mlx->mlx_flags & MLXF_FW_INITTED) == 0) {
660 		mlx_outb(mlx, MLX_V5REG_IDB, MLX_V5_IDB_SACK);
661 		DELAY(1000);
662 		mlx->mlx_flags |= MLXF_FW_INITTED;
663 	}
664 
665 	/* Init in progress? */
666 	if ((mlx_inb(mlx, MLX_V5REG_IDB) & MLX_V5_IDB_INIT_DONE) != 0)
667 		return (0);
668 
669 	/* Test for error value. */
670 	fwerror = mlx_inb(mlx, MLX_V5REG_FWERROR);
671 	if ((fwerror & MLX_V5_FWERROR_PEND) == 0)
672 		return (1);
673 
674 	/* Mask status pending bit, fetch status. */
675 	*error = fwerror & ~MLX_V5_FWERROR_PEND;
676 	*param1 = mlx_inb(mlx, MLX_V5REG_FWERROR_PARAM1);
677 	*param2 = mlx_inb(mlx, MLX_V5REG_FWERROR_PARAM2);
678 
679 	/* Acknowledge. */
680 	mlx_outb(mlx, MLX_V5REG_FWERROR, 0xff);
681 
682 	return (2);
683 }
684 
685 MODULE(MODULE_CLASS_DRIVER, mlx_pci, "mlx,pci");
686 
687 #ifdef _MODULE
688 /*
689  * XXX Don't allow ioconf.c to redefine the "struct cfdriver ld_cd"
690  * XXX it will be defined in the common-code module
691  */
692 #undef  CFDRIVER_DECL
693 #define CFDRIVER_DECL(name, class, attr)
694 #include "ioconf.c"
695 #endif
696 
697 static int
698 mlx_pci_modcmd(modcmd_t cmd, void *opaque)
699 {
700 	int error = 0;
701 
702 #ifdef _MODULE
703 	switch (cmd) {
704 	case MODULE_CMD_INIT:
705 		/*
706 		 * We skip over the first entry in cfdriver[] array
707 		 * since the cfdriver is attached by the common
708 		 * (non-attachment-specific) code.
709 		 */
710 		error = config_init_component(&cfdriver_ioconf_mlx_pci[1],
711 		    cfattach_ioconf_mlx_pci, cfdata_ioconf_mlx_pci);
712 		break;
713 	case MODULE_CMD_FINI:
714 		error = config_fini_component(&cfdriver_ioconf_mlx_pci[1],
715 		    cfattach_ioconf_mlx_pci, cfdata_ioconf_mlx_pci);
716 		break;
717 	default:
718 		error = ENOTTY;
719 		break;
720 	}
721 #endif
722 
723 	return error;
724 }
725