1 /* $NetBSD: mlx_pci.c,v 1.22 2009/05/12 08:23:01 cegger Exp $ */
4 * Copyright (c) 2001 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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.
33 * Copyright (c) 1999 Michael Smith
34 * All rights reserved.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
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.
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
57 * from FreeBSD: mlx_pci.c,v 1.4.2.4 2000/10/28 10:48:09 msmith Exp
61 * PCI front-end for the mlx(4) driver.
64 #include <sys/cdefs.h>
65 __KERNEL_RCSID(0, "$NetBSD: mlx_pci.c,v 1.22 2009/05/12 08:23:01 cegger Exp $");
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>
74 #include <machine/endian.h>
77 #include <dev/ic/mlxreg.h>
78 #include <dev/ic/mlxio.h>
79 #include <dev/ic/mlxvar.h>
81 #include <dev/pci/pcireg.h>
82 #include <dev/pci/pcivar.h>
83 #include <dev/pci/pcidevs.h>
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
*);
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 *);
94 static int mlx_v3_reset(struct mlx_softc
*);
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 *);
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 *);
107 static struct mlx_pci_ident
{
110 u_short mpi_subvendor
;
111 u_short mpi_subproduct
;
113 } const mlx_pci_ident
[] = {
116 PCI_PRODUCT_MYLEX_RAID_V2
,
123 PCI_PRODUCT_MYLEX_RAID_V3
,
130 PCI_PRODUCT_MYLEX_RAID_V4
,
137 PCI_PRODUCT_DEC_SWXCR
,
139 PCI_PRODUCT_MYLEX_RAID_V5
,
144 CFATTACH_DECL(mlx_pci
, sizeof(struct mlx_softc
),
145 mlx_pci_match
, mlx_pci_attach
, NULL
, NULL
);
148 * Try to find a `mlx_pci_ident' entry corresponding to this board.
150 static const struct mlx_pci_ident
*
151 mlx_pci_findmpi(struct pci_attach_args
*pa
)
153 const struct mlx_pci_ident
*mpi
, *maxmpi
;
157 maxmpi
= mpi
+ sizeof(mlx_pci_ident
) / sizeof(mlx_pci_ident
[0]);
159 for (; mpi
< maxmpi
; mpi
++) {
160 if (PCI_VENDOR(pa
->pa_id
) != mpi
->mpi_vendor
||
161 PCI_PRODUCT(pa
->pa_id
) != mpi
->mpi_product
)
164 if (mpi
->mpi_subvendor
== 0x0000)
167 reg
= pci_conf_read(pa
->pa_pc
, pa
->pa_tag
, PCI_SUBSYS_ID_REG
);
169 if (PCI_VENDOR(reg
) == mpi
->mpi_subvendor
&&
170 PCI_PRODUCT(reg
) == mpi
->mpi_subproduct
)
178 * Match a supported board.
181 mlx_pci_match(device_t parent
, cfdata_t cfdata
, void *aux
)
184 return (mlx_pci_findmpi(aux
) != NULL
);
188 * Attach a supported board.
191 mlx_pci_attach(device_t parent
, device_t self
, void *aux
)
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
;
202 const struct mlx_pci_ident
*mpi
;
204 mlx
= device_private(self
);
207 mpi
= mlx_pci_findmpi(aux
);
209 mlx
->mlx_dmat
= pa
->pa_dmat
;
210 mlx
->mlx_ci
.ci_iftype
= mpi
->mpi_iftype
;
212 printf(": Mylex RAID (v%d interface)\n", mpi
->mpi_iftype
);
215 * Map the PCI register window.
220 for (i
= 0x10; i
<= 0x14; i
+= 4) {
221 reg
= pci_conf_read(pa
->pa_pc
, pa
->pa_tag
, i
);
223 if (PCI_MAPREG_TYPE(reg
) == PCI_MAPREG_TYPE_IO
) {
224 if (ior
== -1 && PCI_MAPREG_IO_SIZE(reg
) != 0)
227 if (memr
== -1 && PCI_MAPREG_MEM_SIZE(reg
) != 0)
233 if (pci_mapreg_map(pa
, memr
, PCI_MAPREG_TYPE_MEM
, 0,
234 &memt
, &memh
, NULL
, NULL
))
237 if (pci_mapreg_map(pa
, ior
, PCI_MAPREG_TYPE_IO
, 0,
238 &iot
, &ioh
, NULL
, NULL
))
244 } else if (ior
!= -1) {
248 aprint_error_dev(self
, "can't map i/o or memory space\n");
252 /* Enable the device. */
253 reg
= pci_conf_read(pa
->pa_pc
, pa
->pa_tag
, PCI_COMMAND_STATUS_REG
);
254 pci_conf_write(pa
->pa_pc
, pa
->pa_tag
, PCI_COMMAND_STATUS_REG
,
255 reg
| PCI_COMMAND_MASTER_ENABLE
);
257 /* Map and establish the interrupt. */
258 if (pci_intr_map(pa
, &ih
)) {
259 aprint_error_dev(self
, "can't map interrupt\n");
262 intrstr
= pci_intr_string(pc
, ih
);
263 mlx
->mlx_ih
= pci_intr_establish(pc
, ih
, IPL_BIO
, mlx_intr
, mlx
);
264 if (mlx
->mlx_ih
== NULL
) {
265 aprint_error_dev(self
, "can't establish interrupt");
267 aprint_error(" at %s", intrstr
);
272 /* Select linkage based on controller interface type. */
273 switch (mlx
->mlx_ci
.ci_iftype
) {
276 mlx
->mlx_submit
= mlx_v3_submit
;
277 mlx
->mlx_findcomplete
= mlx_v3_findcomplete
;
278 mlx
->mlx_intaction
= mlx_v3_intaction
;
279 mlx
->mlx_fw_handshake
= mlx_v3_fw_handshake
;
281 mlx
->mlx_reset
= mlx_v3_reset
;
286 mlx
->mlx_submit
= mlx_v4_submit
;
287 mlx
->mlx_findcomplete
= mlx_v4_findcomplete
;
288 mlx
->mlx_intaction
= mlx_v4_intaction
;
289 mlx
->mlx_fw_handshake
= mlx_v4_fw_handshake
;
293 mlx
->mlx_submit
= mlx_v5_submit
;
294 mlx
->mlx_findcomplete
= mlx_v5_findcomplete
;
295 mlx
->mlx_intaction
= mlx_v5_intaction
;
296 mlx
->mlx_fw_handshake
= mlx_v5_fw_handshake
;
300 mlx_init(mlx
, intrstr
);
304 * ================= V3 interface linkage =================
308 * Try to give (mc) to the controller. Returns 1 if successful, 0 on
309 * failure (the controller is not ready to take a command).
311 * Must be called at splbio or in a fashion that prevents reentry.
314 mlx_v3_submit(struct mlx_softc
*mlx
, struct mlx_ccb
*mc
)
317 /* Ready for our command? */
318 if ((mlx_inb(mlx
, MLX_V3REG_IDB
) & MLX_V3_IDB_FULL
) == 0) {
319 /* Copy mailbox data to window. */
320 bus_space_write_region_1(mlx
->mlx_iot
, mlx
->mlx_ioh
,
321 MLX_V3REG_MAILBOX
, mc
->mc_mbox
, 13);
322 bus_space_barrier(mlx
->mlx_iot
, mlx
->mlx_ioh
,
323 MLX_V3REG_MAILBOX
, 13,
324 BUS_SPACE_BARRIER_WRITE
);
327 mlx_outb(mlx
, MLX_V3REG_IDB
, MLX_V3_IDB_FULL
);
335 * See if a command has been completed, if so acknowledge its completion and
336 * recover the slot number and status code.
338 * Must be called at splbio or in a fashion that prevents reentry.
341 mlx_v3_findcomplete(struct mlx_softc
*mlx
, u_int
*slot
, u_int
*status
)
344 /* Status available? */
345 if ((mlx_inb(mlx
, MLX_V3REG_ODB
) & MLX_V3_ODB_SAVAIL
) != 0) {
346 *slot
= mlx_inb(mlx
, MLX_V3REG_STATUS_IDENT
);
347 *status
= mlx_inw(mlx
, MLX_V3REG_STATUS
);
349 /* Acknowledge completion. */
350 mlx_outb(mlx
, MLX_V3REG_ODB
, MLX_V3_ODB_SAVAIL
);
351 mlx_outb(mlx
, MLX_V3REG_IDB
, MLX_V3_IDB_SACK
);
359 * Enable/disable interrupts as requested. (No acknowledge required)
361 * Must be called at splbio or in a fashion that prevents reentry.
364 mlx_v3_intaction(struct mlx_softc
*mlx
, int action
)
367 mlx_outb(mlx
, MLX_V3REG_IE
, action
!= 0);
371 * Poll for firmware error codes during controller initialisation.
373 * Returns 0 if initialisation is complete, 1 if still in progress but no
374 * error has been fetched, 2 if an error has been retrieved.
377 mlx_v3_fw_handshake(struct mlx_softc
*mlx
, int *error
, int *param1
, int *param2
)
381 /* First time around, clear any hardware completion status. */
382 if ((mlx
->mlx_flags
& MLXF_FW_INITTED
) == 0) {
383 mlx_outb(mlx
, MLX_V3REG_IDB
, MLX_V3_IDB_SACK
);
385 mlx
->mlx_flags
|= MLXF_FW_INITTED
;
388 /* Init in progress? */
389 if ((mlx_inb(mlx
, MLX_V3REG_IDB
) & MLX_V3_IDB_INIT_BUSY
) == 0)
392 /* Test error value. */
393 fwerror
= mlx_inb(mlx
, MLX_V3REG_FWERROR
);
395 if ((fwerror
& MLX_V3_FWERROR_PEND
) == 0)
398 /* Mask status pending bit, fetch status. */
399 *error
= fwerror
& ~MLX_V3_FWERROR_PEND
;
400 *param1
= mlx_inb(mlx
, MLX_V3REG_FWERROR_PARAM1
);
401 *param2
= mlx_inb(mlx
, MLX_V3REG_FWERROR_PARAM2
);
404 mlx_outb(mlx
, MLX_V3REG_FWERROR
, 0);
411 * Reset the controller. Return non-zero on failure.
414 mlx_v3_reset(struct mlx_softc
*mlx
)
418 mlx_outb(mlx
, MLX_V3REG_IDB
, MLX_V3_IDB_SACK
);
421 /* Wait up to 2 minutes for the bit to clear. */
422 for (i
= 120; i
!= 0; i
--) {
424 if ((mlx_inb(mlx
, MLX_V3REG_IDB
) & MLX_V3_IDB_SACK
) == 0)
429 printf("mlx0: SACK didn't clear\n");
433 mlx_outb(mlx
, MLX_V3REG_IDB
, MLX_V3_IDB_RESET
);
435 /* Wait up to 5 seconds for the bit to clear. */
436 for (i
= 5; i
!= 0; i
--) {
438 if ((mlx_inb(mlx
, MLX_V3REG_IDB
) & MLX_V3_IDB_RESET
) == 0)
443 printf("mlx0: RESET didn't clear\n");
449 #endif /* MLX_RESET */
452 * ================= V4 interface linkage =================
456 * Try to give (mc) to the controller. Returns 1 if successful, 0 on
457 * failure (the controller is not ready to take a command).
459 * Must be called at splbio or in a fashion that prevents reentry.
462 mlx_v4_submit(struct mlx_softc
*mlx
, struct mlx_ccb
*mc
)
465 /* Ready for our command? */
466 if ((mlx_inl(mlx
, MLX_V4REG_IDB
) & MLX_V4_IDB_FULL
) == 0) {
467 /* Copy mailbox data to window. */
468 bus_space_write_region_1(mlx
->mlx_iot
, mlx
->mlx_ioh
,
469 MLX_V4REG_MAILBOX
, mc
->mc_mbox
, 13);
470 bus_space_barrier(mlx
->mlx_iot
, mlx
->mlx_ioh
,
471 MLX_V4REG_MAILBOX
, 13,
472 BUS_SPACE_BARRIER_WRITE
);
475 mlx_outl(mlx
, MLX_V4REG_IDB
, MLX_V4_IDB_HWMBOX_CMD
);
483 * See if a command has been completed, if so acknowledge its completion and
484 * recover the slot number and status code.
486 * Must be called at splbio or in a fashion that prevents reentry.
489 mlx_v4_findcomplete(struct mlx_softc
*mlx
, u_int
*slot
, u_int
*status
)
492 /* Status available? */
493 if ((mlx_inl(mlx
, MLX_V4REG_ODB
) & MLX_V4_ODB_HWSAVAIL
) != 0) {
494 *slot
= mlx_inb(mlx
, MLX_V4REG_STATUS_IDENT
);
495 *status
= mlx_inw(mlx
, MLX_V4REG_STATUS
);
497 /* Acknowledge completion. */
498 mlx_outl(mlx
, MLX_V4REG_ODB
, MLX_V4_ODB_HWMBOX_ACK
);
499 mlx_outl(mlx
, MLX_V4REG_IDB
, MLX_V4_IDB_SACK
);
507 * Enable/disable interrupts as requested.
509 * Must be called at splbio or in a fashion that prevents reentry.
512 mlx_v4_intaction(struct mlx_softc
*mlx
, int action
)
517 ier
= MLX_V4_IE_MASK
| MLX_V4_IE_DISINT
;
519 ier
= MLX_V4_IE_MASK
& ~MLX_V4_IE_DISINT
;
521 mlx_outl(mlx
, MLX_V4REG_IE
, ier
);
525 * Poll for firmware error codes during controller initialisation.
527 * Returns 0 if initialisation is complete, 1 if still in progress but no
528 * error has been fetched, 2 if an error has been retrieved.
531 mlx_v4_fw_handshake(struct mlx_softc
*mlx
, int *error
, int *param1
, int *param2
)
535 /* First time around, clear any hardware completion status. */
536 if ((mlx
->mlx_flags
& MLXF_FW_INITTED
) == 0) {
537 mlx_outl(mlx
, MLX_V4REG_IDB
, MLX_V4_IDB_SACK
);
539 mlx
->mlx_flags
|= MLXF_FW_INITTED
;
542 /* Init in progress? */
543 if ((mlx_inl(mlx
, MLX_V4REG_IDB
) & MLX_V4_IDB_INIT_BUSY
) == 0)
546 /* Test error value */
547 fwerror
= mlx_inb(mlx
, MLX_V4REG_FWERROR
);
548 if ((fwerror
& MLX_V4_FWERROR_PEND
) == 0)
551 /* Mask status pending bit, fetch status. */
552 *error
= fwerror
& ~MLX_V4_FWERROR_PEND
;
553 *param1
= mlx_inb(mlx
, MLX_V4REG_FWERROR_PARAM1
);
554 *param2
= mlx_inb(mlx
, MLX_V4REG_FWERROR_PARAM2
);
557 mlx_outb(mlx
, MLX_V4REG_FWERROR
, 0);
563 * ================= V5 interface linkage =================
567 * Try to give (mc) to the controller. Returns 1 if successful, 0 on failure
568 * (the controller is not ready to take a command).
570 * Must be called at splbio or in a fashion that prevents reentry.
573 mlx_v5_submit(struct mlx_softc
*mlx
, struct mlx_ccb
*mc
)
576 /* Ready for our command? */
577 if ((mlx_inb(mlx
, MLX_V5REG_IDB
) & MLX_V5_IDB_EMPTY
) != 0) {
578 /* Copy mailbox data to window. */
579 bus_space_write_region_1(mlx
->mlx_iot
, mlx
->mlx_ioh
,
580 MLX_V5REG_MAILBOX
, mc
->mc_mbox
, 13);
581 bus_space_barrier(mlx
->mlx_iot
, mlx
->mlx_ioh
,
582 MLX_V5REG_MAILBOX
, 13,
583 BUS_SPACE_BARRIER_WRITE
);
586 mlx_outb(mlx
, MLX_V5REG_IDB
, MLX_V5_IDB_HWMBOX_CMD
);
594 * See if a command has been completed, if so acknowledge its completion and
595 * recover the slot number and status code.
597 * Must be called at splbio or in a fashion that prevents reentry.
600 mlx_v5_findcomplete(struct mlx_softc
*mlx
, u_int
*slot
, u_int
*status
)
603 /* Status available? */
604 if ((mlx_inb(mlx
, MLX_V5REG_ODB
) & MLX_V5_ODB_HWSAVAIL
) != 0) {
605 *slot
= mlx_inb(mlx
, MLX_V5REG_STATUS_IDENT
);
606 *status
= mlx_inw(mlx
, MLX_V5REG_STATUS
);
608 /* Acknowledge completion. */
609 mlx_outb(mlx
, MLX_V5REG_ODB
, MLX_V5_ODB_HWMBOX_ACK
);
610 mlx_outb(mlx
, MLX_V5REG_IDB
, MLX_V5_IDB_SACK
);
618 * Enable/disable interrupts as requested.
620 * Must be called at splbio or in a fashion that prevents reentry.
623 mlx_v5_intaction(struct mlx_softc
*mlx
, int action
)
628 ier
= 0xff & MLX_V5_IE_DISINT
;
630 ier
= 0xff & ~MLX_V5_IE_DISINT
;
632 mlx_outb(mlx
, MLX_V5REG_IE
, ier
);
636 * Poll for firmware error codes during controller initialisation.
638 * Returns 0 if initialisation is complete, 1 if still in progress but no
639 * error has been fetched, 2 if an error has been retrieved.
642 mlx_v5_fw_handshake(struct mlx_softc
*mlx
, int *error
, int *param1
, int *param2
)
646 /* First time around, clear any hardware completion status. */
647 if ((mlx
->mlx_flags
& MLXF_FW_INITTED
) == 0) {
648 mlx_outb(mlx
, MLX_V5REG_IDB
, MLX_V5_IDB_SACK
);
650 mlx
->mlx_flags
|= MLXF_FW_INITTED
;
653 /* Init in progress? */
654 if ((mlx_inb(mlx
, MLX_V5REG_IDB
) & MLX_V5_IDB_INIT_DONE
) != 0)
657 /* Test for error value. */
658 fwerror
= mlx_inb(mlx
, MLX_V5REG_FWERROR
);
659 if ((fwerror
& MLX_V5_FWERROR_PEND
) == 0)
662 /* Mask status pending bit, fetch status. */
663 *error
= fwerror
& ~MLX_V5_FWERROR_PEND
;
664 *param1
= mlx_inb(mlx
, MLX_V5REG_FWERROR_PARAM1
);
665 *param2
= mlx_inb(mlx
, MLX_V5REG_FWERROR_PARAM2
);
668 mlx_outb(mlx
, MLX_V5REG_FWERROR
, 0xff);