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