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
88static void mlx_pci_attach(device_t, device_t, void *);
89static int mlx_pci_match(device_t, cfdata_t, void *);
90static const struct mlx_pci_ident *mlx_pci_findmpi(struct pci_attach_args *);
91
92static int mlx_v3_submit(struct mlx_softc *, struct mlx_ccb *);
93static int mlx_v3_findcomplete(struct mlx_softc *, u_int *, u_int *);
94static void mlx_v3_intaction(struct mlx_softc *, int);
95static int mlx_v3_fw_handshake(struct mlx_softc *, int *, int *, int *);
96#ifdef MLX_RESET
97static int mlx_v3_reset(struct mlx_softc *);
98#endif
99
100static int mlx_v4_submit(struct mlx_softc *, struct mlx_ccb *);
101static int mlx_v4_findcomplete(struct mlx_softc *, u_int *, u_int *);
102static void mlx_v4_intaction(struct mlx_softc *, int);
103static int mlx_v4_fw_handshake(struct mlx_softc *, int *, int *, int *);
104
105static int mlx_v5_submit(struct mlx_softc *, struct mlx_ccb *);
106static int mlx_v5_findcomplete(struct mlx_softc *, u_int *, u_int *);
107static void mlx_v5_intaction(struct mlx_softc *, int);
108static int mlx_v5_fw_handshake(struct mlx_softc *, int *, int *, int *);
109
110static 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
147static int
148mlx_pci_rescan(device_t self, const char *attr, const int *flag)
149{
150
151 return mlx_configure(device_private(self), 1);
152}
153
154CFATTACH_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 */
160static const struct mlx_pci_ident *
161mlx_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 */
190static int
191mlx_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 */
200static void
201mlx_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 */
325static int
326mlx_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 */
352static int
353mlx_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 */
375static void
376mlx_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 */
388static int
389mlx_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 */
425static int
426mlx_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 */
473static int
474mlx_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 */
500static int
501mlx_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 */
523static void
524mlx_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 */
542static int
543mlx_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 */
584static int
585mlx_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 */
611static int
612mlx_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 */
634static void
635mlx_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 */
653static int
654mlx_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
685MODULE(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
697static int
698mlx_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