1 /* $NetBSD: ahc_cardbus.c,v 1.28 2009/05/16 06:44:05 tsutsui Exp $ */
4 * Copyright (c) 2000, 2005 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
34 * CardBus front-end for the Adaptec AIC-7xxx family of SCSI controllers.
40 #include <sys/cdefs.h>
41 __KERNEL_RCSID(0, "$NetBSD: ahc_cardbus.c,v 1.28 2009/05/16 06:44:05 tsutsui Exp $");
43 #include "opt_ahc_cardbus.h"
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/malloc.h>
48 #include <sys/kernel.h>
49 #include <sys/queue.h>
50 #include <sys/device.h>
55 #include <dev/scsipi/scsi_all.h>
56 #include <dev/scsipi/scsipi_all.h>
57 #include <dev/scsipi/scsiconf.h>
59 #include <dev/pci/pcireg.h>
61 #include <dev/cardbus/cardbusvar.h>
62 #include <dev/pci/pcidevs.h>
64 #include <dev/ic/aic7xxx_osm.h>
65 #include <dev/ic/aic7xxx_inline.h>
68 #ifndef AHC_CARDBUS_DEFAULT_SCSI_ID
69 #define AHC_CARDBUS_DEFAULT_SCSI_ID 0x7
72 #define AHC_CARDBUS_IOBA 0x10
73 #define AHC_CARDBUS_MMBA 0x14
75 struct ahc_cardbus_softc
{
76 struct ahc_softc sc_ahc
; /* real AHC */
78 /* CardBus-specific goo. */
79 cardbus_devfunc_t sc_ct
; /* our CardBus devfuncs */
80 cardbus_intr_line_t sc_intrline
; /* our interrupt line */
83 int sc_cbenable
; /* what CardBus access type to enable */
84 int sc_csr
; /* CSR bits */
88 int ahc_cardbus_match(device_t
, cfdata_t
, void *);
89 void ahc_cardbus_attach(device_t
, device_t
, void *);
90 int ahc_cardbus_detach(device_t
, int);
92 CFATTACH_DECL_NEW(ahc_cardbus
, sizeof(struct ahc_cardbus_softc
),
93 ahc_cardbus_match
, ahc_cardbus_attach
, ahc_cardbus_detach
, NULL
);
96 ahc_cardbus_match(device_t parent
, cfdata_t match
, void *aux
)
98 struct cardbus_attach_args
*ca
= aux
;
100 if (CARDBUS_VENDOR(ca
->ca_id
) == PCI_VENDOR_ADP
&&
101 CARDBUS_PRODUCT(ca
->ca_id
) == PCI_PRODUCT_ADP_APA1480
)
108 ahc_cardbus_attach(device_t parent
, device_t self
, void *aux
)
110 struct cardbus_attach_args
*ca
= aux
;
111 struct ahc_cardbus_softc
*csc
= device_private(self
);
112 struct ahc_softc
*ahc
= &csc
->sc_ahc
;
113 cardbus_devfunc_t ct
= ca
->ca_ct
;
114 cardbus_chipset_tag_t cc
= ct
->ct_cc
;
115 cardbus_function_tag_t cf
= ct
->ct_cf
;
117 bus_space_handle_t bsh
;
125 csc
->sc_tag
= ca
->ca_tag
;
126 csc
->sc_intrline
= ca
->ca_intrline
;
128 printf(": Adaptec ADP-1480 SCSI\n");
133 csc
->sc_csr
= PCI_COMMAND_MASTER_ENABLE
;
134 if (Cardbus_mapreg_map(csc
->sc_ct
, AHC_CARDBUS_MMBA
,
135 PCI_MAPREG_TYPE_MEM
|PCI_MAPREG_MEM_TYPE_32BIT
, 0,
136 &bst
, &bsh
, NULL
, &csc
->sc_size
) == 0) {
137 csc
->sc_cbenable
= CARDBUS_MEM_ENABLE
;
138 csc
->sc_csr
|= PCI_COMMAND_MEM_ENABLE
;
139 } else if (Cardbus_mapreg_map(csc
->sc_ct
, AHC_CARDBUS_IOBA
,
140 PCI_MAPREG_TYPE_IO
, 0, &bst
, &bsh
, NULL
, &csc
->sc_size
) == 0) {
141 csc
->sc_cbenable
= CARDBUS_IO_ENABLE
;
142 csc
->sc_csr
|= PCI_COMMAND_IO_ENABLE
;
144 printf("%s: unable to map device registers\n",
149 /* Make sure the right access type is on the CardBus bridge. */
150 (*ct
->ct_cf
->cardbus_ctrl
)(cc
, csc
->sc_cbenable
);
151 (*ct
->ct_cf
->cardbus_ctrl
)(cc
, CARDBUS_BM_ENABLE
);
153 /* Enable the appropriate bits in the PCI CSR. */
154 reg
= cardbus_conf_read(cc
, cf
, ca
->ca_tag
, PCI_COMMAND_STATUS_REG
);
155 reg
&= ~(PCI_COMMAND_IO_ENABLE
|PCI_COMMAND_MEM_ENABLE
);
157 cardbus_conf_write(cc
, cf
, ca
->ca_tag
, PCI_COMMAND_STATUS_REG
, reg
);
160 * Make sure the latency timer is set to some reasonable
163 reg
= cardbus_conf_read(cc
, cf
, ca
->ca_tag
, PCI_BHLC_REG
);
164 if (PCI_LATTIMER(reg
) < 0x20) {
165 reg
&= ~(PCI_LATTIMER_MASK
<< PCI_LATTIMER_SHIFT
);
166 reg
|= (0x20 << PCI_LATTIMER_SHIFT
);
167 cardbus_conf_write(cc
, cf
, ca
->ca_tag
, PCI_BHLC_REG
, reg
);
170 ahc_set_name(ahc
, device_xname(ahc
->sc_dev
));
172 ahc
->parent_dmat
= ca
->ca_dmat
;
177 * ADP-1480 is always an AIC-7860.
179 ahc
->chip
= AHC_AIC7860
| AHC_PCI
;
180 ahc
->features
= AHC_AIC7860_FE
|AHC_REMOVABLE
;
181 ahc
->bugs
|= AHC_TMODE_WIDEODD_BUG
|AHC_CACHETHEN_BUG
|AHC_PCI_MWI_BUG
;
182 if (PCI_REVISION(ca
->ca_class
) >= 1)
183 ahc
->bugs
|= AHC_PCI_2_1_RETRY_BUG
;
185 if (ahc_softc_init(ahc
) != 0)
189 * On all CardBus adapters, we allow SCB paging.
191 ahc
->flags
= AHC_PAGESCBS
;
195 ahc_intr_enable(ahc
, FALSE
);
200 * Establish the interrupt.
202 ahc
->ih
= cardbus_intr_establish(cc
, cf
, ca
->ca_intrline
, IPL_BIO
,
204 if (ahc
->ih
== NULL
) {
205 printf("%s: unable to establish interrupt\n",
210 ahc
->seep_config
= malloc(sizeof(*ahc
->seep_config
),
212 if (ahc
->seep_config
== NULL
)
215 ahc_check_extport(ahc
, &sxfrctl1
);
217 * Take the LED out of diagnostic mode.
219 sblkctl
= ahc_inb(ahc
, SBLKCTL
);
220 ahc_outb(ahc
, SBLKCTL
, (sblkctl
& ~(DIAGLEDEN
|DIAGLEDON
)));
223 * I don't know where this is set in the SEEPROM or by the
224 * BIOS, so we default to 100%.
226 ahc_outb(ahc
, DSPCISTATUS
, DFTHRSH_100
);
228 if (ahc
->flags
& AHC_USEDEFAULTS
) {
231 * Assume only one connector and always turn
234 our_id
= AHC_CARDBUS_DEFAULT_SCSI_ID
;
236 ahc_outb(ahc
, SCSICONF
, our_id
| ENSPCHK
| RESET_SCSI
);
237 ahc
->our_id
= our_id
;
240 printf("%s: aic7860", ahc_name(ahc
));
243 * Record our termination setting for the
244 * generic initialization routine.
246 if ((sxfrctl1
& STPWEN
) != 0)
247 ahc
->flags
|= AHC_TERM_ENB_A
;
258 ahc_cardbus_detach(device_t self
, int flags
)
260 struct ahc_cardbus_softc
*csc
= device_private(self
);
261 struct ahc_softc
*ahc
= &csc
->sc_ahc
;
265 rv
= ahc_detach(ahc
, flags
);
270 cardbus_intr_disestablish(csc
->sc_ct
->ct_cc
,
271 csc
->sc_ct
->ct_cf
, ahc
->ih
);
275 if (csc
->sc_cbenable
) {
276 if (csc
->sc_cbenable
== CARDBUS_MEM_ENABLE
)
277 Cardbus_mapreg_unmap(csc
->sc_ct
, AHC_CARDBUS_MMBA
,
278 ahc
->tag
, ahc
->bsh
, csc
->sc_size
);
279 else if (csc
->sc_cbenable
== CARDBUS_IO_ENABLE
)
280 Cardbus_mapreg_unmap(csc
->sc_ct
, AHC_CARDBUS_IOBA
,
281 ahc
->tag
, ahc
->bsh
, csc
->sc_size
);
282 csc
->sc_cbenable
= 0;