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