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