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