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