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