1 /* $NetBSD: rccide.c,v 1.18 2008/03/18 20:46:37 cube Exp $ */
4 * Copyright (c) 2003 By Noon Software, Inc. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The names of the authors may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: rccide.c,v 1.18 2008/03/18 20:46:37 cube Exp $");
32 #include <sys/param.h>
33 #include <sys/systm.h>
35 #include <dev/pci/pcivar.h>
36 #include <dev/pci/pcidevs.h>
37 #include <dev/pci/pciidereg.h>
38 #include <dev/pci/pciidevar.h>
40 static void serverworks_chip_map(struct pciide_softc
*,
41 struct pci_attach_args
*);
42 static void serverworks_setup_channel(struct ata_channel
*);
43 static int serverworks_pci_intr(void *);
44 static int serverworkscsb6_pci_intr(void *);
46 static int rccide_match(device_t
, cfdata_t
, void *);
47 static void rccide_attach(device_t
, device_t
, void *);
49 CFATTACH_DECL_NEW(rccide
, sizeof(struct pciide_softc
),
50 rccide_match
, rccide_attach
, NULL
, NULL
);
52 static const struct pciide_product_desc pciide_serverworks_products
[] = {
53 { PCI_PRODUCT_SERVERWORKS_OSB4_IDE
,
55 "ServerWorks OSB4 IDE Controller",
58 { PCI_PRODUCT_SERVERWORKS_CSB5_IDE
,
60 "ServerWorks CSB5 IDE Controller",
63 { PCI_PRODUCT_SERVERWORKS_CSB6_IDE
,
65 "ServerWorks CSB6 RAID/IDE Controller",
68 { PCI_PRODUCT_SERVERWORKS_CSB6_RAID
,
70 "ServerWorks CSB6 RAID/IDE Controller",
73 { PCI_PRODUCT_SERVERWORKS_HT1000_IDE
,
75 "ServerWorks HT-1000 IDE Controller",
86 rccide_match(device_t parent
, cfdata_t match
, void *aux
)
88 struct pci_attach_args
*pa
= aux
;
90 if (PCI_VENDOR(pa
->pa_id
) == PCI_VENDOR_SERVERWORKS
&&
91 PCI_CLASS(pa
->pa_class
) == PCI_CLASS_MASS_STORAGE
&&
92 PCI_SUBCLASS(pa
->pa_class
) == PCI_SUBCLASS_MASS_STORAGE_IDE
) {
93 if (pciide_lookup_product(pa
->pa_id
,
94 pciide_serverworks_products
))
101 rccide_attach(device_t parent
, device_t self
, void *aux
)
103 struct pci_attach_args
*pa
= aux
;
104 struct pciide_softc
*sc
= device_private(self
);
106 sc
->sc_wdcdev
.sc_atac
.atac_dev
= self
;
108 pciide_common_attach(sc
, pa
,
109 pciide_lookup_product(pa
->pa_id
, pciide_serverworks_products
));
113 serverworks_chip_map(struct pciide_softc
*sc
, struct pci_attach_args
*pa
)
115 struct pciide_channel
*cp
;
116 pcireg_t interface
= PCI_INTERFACE(pa
->pa_class
);
119 bus_size_t cmdsize
, ctlsize
;
121 if (pciide_chipen(sc
, pa
) == 0)
124 aprint_verbose_dev(sc
->sc_wdcdev
.sc_atac
.atac_dev
,
125 "bus-master DMA support present");
126 pciide_mapreg_dma(sc
, pa
);
127 aprint_verbose("\n");
128 sc
->sc_wdcdev
.sc_atac
.atac_cap
= ATAC_CAP_DATA16
| ATAC_CAP_DATA32
;
131 sc
->sc_wdcdev
.sc_atac
.atac_cap
|= ATAC_CAP_DMA
| ATAC_CAP_UDMA
;
132 sc
->sc_wdcdev
.irqack
= pciide_irqack
;
134 sc
->sc_wdcdev
.sc_atac
.atac_pio_cap
= 4;
135 sc
->sc_wdcdev
.sc_atac
.atac_dma_cap
= 2;
136 switch (sc
->sc_pp
->ide_product
) {
137 case PCI_PRODUCT_SERVERWORKS_OSB4_IDE
:
138 sc
->sc_wdcdev
.sc_atac
.atac_udma_cap
= 2;
140 case PCI_PRODUCT_SERVERWORKS_CSB5_IDE
:
141 if (PCI_REVISION(pa
->pa_class
) < 0x92)
142 sc
->sc_wdcdev
.sc_atac
.atac_udma_cap
= 4;
144 sc
->sc_wdcdev
.sc_atac
.atac_udma_cap
= 5;
146 case PCI_PRODUCT_SERVERWORKS_CSB6_IDE
:
147 case PCI_PRODUCT_SERVERWORKS_CSB6_RAID
:
148 case PCI_PRODUCT_SERVERWORKS_HT1000_IDE
:
149 sc
->sc_wdcdev
.sc_atac
.atac_udma_cap
= 5;
153 sc
->sc_wdcdev
.sc_atac
.atac_set_modes
= serverworks_setup_channel
;
154 sc
->sc_wdcdev
.sc_atac
.atac_channels
= sc
->wdc_chanarray
;
155 sc
->sc_wdcdev
.sc_atac
.atac_nchannels
= 2;
157 wdc_allocate_regs(&sc
->sc_wdcdev
);
159 for (channel
= 0; channel
< sc
->sc_wdcdev
.sc_atac
.atac_nchannels
;
161 cp
= &sc
->pciide_channels
[channel
];
162 if (pciide_chansetup(sc
, channel
, interface
) == 0)
164 switch (sc
->sc_pp
->ide_product
) {
165 case PCI_PRODUCT_SERVERWORKS_CSB6_IDE
:
166 case PCI_PRODUCT_SERVERWORKS_CSB6_RAID
:
167 pciide_mapchan(pa
, cp
, interface
, &cmdsize
, &ctlsize
,
168 serverworkscsb6_pci_intr
);
171 pciide_mapchan(pa
, cp
, interface
, &cmdsize
, &ctlsize
,
172 serverworks_pci_intr
);
176 pcib_tag
= pci_make_tag(pa
->pa_pc
, pa
->pa_bus
, pa
->pa_device
, 0);
177 pci_conf_write(pa
->pa_pc
, pcib_tag
, 0x64,
178 (pci_conf_read(pa
->pa_pc
, pcib_tag
, 0x64) & ~0x2000) | 0x4000);
182 serverworks_setup_channel(struct ata_channel
*chp
)
184 struct ata_drive_datas
*drvp
;
185 struct atac_softc
*atac
= chp
->ch_atac
;
186 struct pciide_channel
*cp
= CHAN_TO_PCHAN(chp
);
187 struct pciide_softc
*sc
= CHAN_TO_PCIIDE(chp
);
188 int channel
= chp
->ch_channel
;
190 u_int32_t pio_time
, dma_time
, pio_mode
, udma_mode
;
191 u_int32_t idedma_ctl
;
192 static const u_int8_t pio_modes
[5] = {0x5d, 0x47, 0x34, 0x22, 0x20};
193 static const u_int8_t dma_modes
[3] = {0x77, 0x21, 0x20};
195 /* setup DMA if needed */
196 pciide_channel_dma_setup(cp
);
198 pio_time
= pci_conf_read(sc
->sc_pc
, sc
->sc_tag
, 0x40);
199 dma_time
= pci_conf_read(sc
->sc_pc
, sc
->sc_tag
, 0x44);
200 pio_mode
= pci_conf_read(sc
->sc_pc
, sc
->sc_tag
, 0x48);
201 udma_mode
= pci_conf_read(sc
->sc_pc
, sc
->sc_tag
, 0x54);
203 pio_time
&= ~(0xffff << (16 * channel
));
204 dma_time
&= ~(0xffff << (16 * channel
));
205 pio_mode
&= ~(0xff << (8 * channel
+ 16));
206 udma_mode
&= ~(0xff << (8 * channel
+ 16));
207 udma_mode
&= ~(3 << (2 * channel
));
211 /* Per drive settings */
212 for (drive
= 0; drive
< 2; drive
++) {
213 drvp
= &chp
->ch_drive
[drive
];
214 /* If no drive, skip */
215 if ((drvp
->drive_flags
& DRIVE
) == 0)
217 unit
= drive
+ 2 * channel
;
218 /* add timing values, setup DMA if needed */
219 pio_time
|= pio_modes
[drvp
->PIO_mode
] << (8 * (unit
^1));
220 pio_mode
|= drvp
->PIO_mode
<< (4 * unit
+ 16);
221 if ((atac
->atac_cap
& ATAC_CAP_UDMA
) &&
222 (drvp
->drive_flags
& DRIVE_UDMA
)) {
223 /* use Ultra/DMA, check for 80-pin cable */
224 if (drvp
->UDMA_mode
> 2 &&
225 (PCI_PRODUCT(pci_conf_read(sc
->sc_pc
, sc
->sc_tag
,
227 & (1 << (14 + channel
))) == 0)
229 dma_time
|= dma_modes
[drvp
->DMA_mode
] << (8 * (unit
^1));
230 udma_mode
|= drvp
->UDMA_mode
<< (4 * unit
+ 16);
231 udma_mode
|= 1 << unit
;
232 idedma_ctl
|= IDEDMA_CTL_DRV_DMA(drive
);
233 } else if ((atac
->atac_cap
& ATAC_CAP_DMA
) &&
234 (drvp
->drive_flags
& DRIVE_DMA
)) {
235 /* use Multiword DMA */
237 drvp
->drive_flags
&= ~DRIVE_UDMA
;
239 dma_time
|= dma_modes
[drvp
->DMA_mode
] << (8 * (unit
^1));
240 idedma_ctl
|= IDEDMA_CTL_DRV_DMA(drive
);
244 drvp
->drive_flags
&= ~(DRIVE_UDMA
| DRIVE_DMA
);
249 pci_conf_write(sc
->sc_pc
, sc
->sc_tag
, 0x40, pio_time
);
250 pci_conf_write(sc
->sc_pc
, sc
->sc_tag
, 0x44, dma_time
);
251 if (sc
->sc_pp
->ide_product
!= PCI_PRODUCT_SERVERWORKS_OSB4_IDE
)
252 pci_conf_write(sc
->sc_pc
, sc
->sc_tag
, 0x48, pio_mode
);
253 pci_conf_write(sc
->sc_pc
, sc
->sc_tag
, 0x54, udma_mode
);
255 if (idedma_ctl
!= 0) {
256 /* Add software bits in status register */
257 bus_space_write_1(sc
->sc_dma_iot
, cp
->dma_iohs
[IDEDMA_CTL
], 0,
263 serverworks_pci_intr(void *arg
)
265 struct pciide_softc
*sc
= arg
;
266 struct pciide_channel
*cp
;
267 struct ata_channel
*wdc_cp
;
271 for (i
= 0; i
< sc
->sc_wdcdev
.sc_atac
.atac_nchannels
; i
++) {
272 cp
= &sc
->pciide_channels
[i
];
273 dmastat
= bus_space_read_1(sc
->sc_dma_iot
,
274 cp
->dma_iohs
[IDEDMA_CTL
], 0);
275 if ((dmastat
& (IDEDMA_CTL_ACT
| IDEDMA_CTL_INTR
)) !=
278 wdc_cp
= &cp
->ata_channel
;
279 crv
= wdcintr(wdc_cp
);
281 aprint_error("%s:%d: bogus intr\n",
282 device_xname(sc
->sc_wdcdev
.sc_atac
.atac_dev
), i
);
283 bus_space_write_1(sc
->sc_dma_iot
,
284 cp
->dma_iohs
[IDEDMA_CTL
], 0, dmastat
);
292 serverworkscsb6_pci_intr(void *arg
)
294 struct pciide_softc
*sc
= arg
;
295 struct pciide_channel
*cp
;
296 struct ata_channel
*wdc_cp
;
300 for (i
= 0; i
< sc
->sc_wdcdev
.sc_atac
.atac_nchannels
; i
++) {
301 cp
= &sc
->pciide_channels
[i
];
302 wdc_cp
= &cp
->ata_channel
;
304 * The CSB6 doesn't assert IDEDMA_CTL_INTR for non-DMA commands.
305 * Until we find a way to know if the controller posted an
306 * interrupt, always call wdcintr(), which will try to guess
307 * if the interrupt was for us or not (and checks
308 * IDEDMA_CTL_INTR for DMA commands only).
310 crv
= wdcintr(wdc_cp
);