1 | /* $NetBSD: svwsata.c,v 1.19 2014/03/29 19:28:25 christos Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 2005 Mark Kettenis |
5 | * |
6 | * Permission to use, copy, modify, and distribute this software for any |
7 | * purpose with or without fee is hereby granted, provided that the above |
8 | * copyright notice and this permission notice appear in all copies. |
9 | * |
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 | */ |
18 | |
19 | #include <sys/cdefs.h> |
20 | __KERNEL_RCSID(0, "$NetBSD: svwsata.c,v 1.19 2014/03/29 19:28:25 christos Exp $" ); |
21 | |
22 | #include <sys/param.h> |
23 | #include <sys/systm.h> |
24 | |
25 | #include <dev/ata/atareg.h> |
26 | #include <dev/ata/satareg.h> |
27 | #include <dev/ata/satavar.h> |
28 | #include <dev/pci/pcivar.h> |
29 | #include <dev/pci/pcidevs.h> |
30 | #include <dev/pci/pciidereg.h> |
31 | #include <dev/pci/pciidevar.h> |
32 | #include <dev/pci/pciide_svwsata_reg.h> |
33 | |
34 | static int svwsata_match(device_t, cfdata_t, void *); |
35 | static void svwsata_attach(device_t, device_t, void *); |
36 | |
37 | static void svwsata_chip_map(struct pciide_softc *, |
38 | const struct pci_attach_args *); |
39 | static void svwsata_mapreg_dma(struct pciide_softc *, |
40 | const struct pci_attach_args *); |
41 | static void svwsata_mapchan(struct pciide_channel *); |
42 | |
43 | CFATTACH_DECL_NEW(svwsata, sizeof(struct pciide_softc), |
44 | svwsata_match, svwsata_attach, pciide_detach, NULL); |
45 | |
46 | static const struct pciide_product_desc pciide_svwsata_products[] = { |
47 | { PCI_PRODUCT_SERVERWORKS_K2_SATA, |
48 | 0, |
49 | "ServerWorks K2 SATA Controller" , |
50 | svwsata_chip_map |
51 | }, |
52 | { PCI_PRODUCT_SERVERWORKS_FRODO4_SATA, |
53 | 0, |
54 | "ServerWorks Frodo4 SATA Controller" , |
55 | svwsata_chip_map |
56 | }, |
57 | { PCI_PRODUCT_SERVERWORKS_FRODO8_SATA, |
58 | 0, |
59 | "ServerWorks Frodo8 SATA Controller" , |
60 | svwsata_chip_map |
61 | }, |
62 | { PCI_PRODUCT_SERVERWORKS_HT1000_SATA_1, |
63 | 0, |
64 | "ServerWorks HT-1000 SATA Controller" , |
65 | svwsata_chip_map |
66 | }, |
67 | { PCI_PRODUCT_SERVERWORKS_HT1000_SATA_2, |
68 | 0, |
69 | "ServerWorks HT-1000 SATA Controller" , |
70 | svwsata_chip_map |
71 | }, |
72 | { 0, |
73 | 0, |
74 | NULL, |
75 | NULL, |
76 | } |
77 | }; |
78 | |
79 | static int |
80 | svwsata_match(device_t parent, cfdata_t match, void *aux) |
81 | { |
82 | struct pci_attach_args *pa = aux; |
83 | |
84 | if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_SERVERWORKS) { |
85 | if (pciide_lookup_product(pa->pa_id, |
86 | pciide_svwsata_products)) |
87 | return (2); |
88 | } |
89 | return (0); |
90 | } |
91 | |
92 | static void |
93 | svwsata_attach(device_t parent, device_t self, void *aux) |
94 | { |
95 | struct pci_attach_args *pa = aux; |
96 | struct pciide_softc *sc = device_private(self); |
97 | |
98 | sc->sc_wdcdev.sc_atac.atac_dev = self; |
99 | |
100 | pciide_common_attach(sc, pa, |
101 | pciide_lookup_product(pa->pa_id, pciide_svwsata_products)); |
102 | } |
103 | |
104 | static void |
105 | svwsata_chip_map(struct pciide_softc *sc, const struct pci_attach_args *pa) |
106 | { |
107 | struct pciide_channel *cp; |
108 | pci_intr_handle_t intrhandle; |
109 | pcireg_t interface; |
110 | const char *intrstr; |
111 | int channel; |
112 | char intrbuf[PCI_INTRSTR_LEN]; |
113 | |
114 | /* The 4-port version has a dummy second function. */ |
115 | if (pci_conf_read(sc->sc_pc, sc->sc_tag, |
116 | PCI_MAPREG_START + 0x14) == 0) { |
117 | aprint_normal("\n" ); |
118 | return; |
119 | } |
120 | |
121 | if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x14, |
122 | PCI_MAPREG_TYPE_MEM | |
123 | PCI_MAPREG_MEM_TYPE_32BIT, 0, |
124 | &sc->sc_ba5_st, &sc->sc_ba5_sh, |
125 | NULL, &sc->sc_ba5_ss) != 0) { |
126 | aprint_error(": unable to map BA5 register space\n" ); |
127 | return; |
128 | } |
129 | |
130 | aprint_verbose_dev(sc->sc_wdcdev.sc_atac.atac_dev, |
131 | "bus-master DMA support present" ); |
132 | svwsata_mapreg_dma(sc, pa); |
133 | aprint_verbose("\n" ); |
134 | |
135 | sc->sc_wdcdev.cap = WDC_CAPABILITY_WIDEREGS; |
136 | |
137 | sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_DATA16 | ATAC_CAP_DATA32; |
138 | sc->sc_wdcdev.sc_atac.atac_pio_cap = 4; |
139 | if (sc->sc_dma_ok) { |
140 | sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_DMA | ATAC_CAP_UDMA; |
141 | sc->sc_wdcdev.irqack = pciide_irqack; |
142 | sc->sc_wdcdev.sc_atac.atac_dma_cap = 2; |
143 | sc->sc_wdcdev.sc_atac.atac_udma_cap = 6; |
144 | } |
145 | |
146 | sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray; |
147 | sc->sc_wdcdev.sc_atac.atac_nchannels = 4; |
148 | sc->sc_wdcdev.sc_atac.atac_set_modes = sata_setup_channel; |
149 | |
150 | /* We can use SControl and SStatus to probe for drives. */ |
151 | sc->sc_wdcdev.sc_atac.atac_probe = wdc_sataprobe; |
152 | sc->sc_wdcdev.wdc_maxdrives = 1; |
153 | |
154 | wdc_allocate_regs(&sc->sc_wdcdev); |
155 | |
156 | /* Map and establish the interrupt handler. */ |
157 | if(pci_intr_map(pa, &intrhandle) != 0) { |
158 | aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev, |
159 | "couldn't map native-PCI interrupt\n" ); |
160 | return; |
161 | } |
162 | intrstr = pci_intr_string(pa->pa_pc, intrhandle, intrbuf, sizeof(intrbuf)); |
163 | sc->sc_pci_ih = pci_intr_establish(pa->pa_pc, intrhandle, IPL_BIO, |
164 | pciide_pci_intr, sc); |
165 | if (sc->sc_pci_ih != NULL) { |
166 | aprint_normal_dev(sc->sc_wdcdev.sc_atac.atac_dev, |
167 | "using %s for native-PCI interrupt\n" , |
168 | intrstr ? intrstr : "unknown interrupt" ); |
169 | } else { |
170 | aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev, |
171 | "couldn't establish native-PCI interrupt" ); |
172 | if (intrstr != NULL) |
173 | aprint_error(" at %s" , intrstr); |
174 | aprint_error("\n" ); |
175 | return; |
176 | } |
177 | |
178 | interface = PCIIDE_INTERFACE_BUS_MASTER_DMA | |
179 | PCIIDE_INTERFACE_PCI(0) | PCIIDE_INTERFACE_PCI(1); |
180 | |
181 | |
182 | for (channel = 0; channel < sc->sc_wdcdev.sc_atac.atac_nchannels; |
183 | channel++) { |
184 | cp = &sc->pciide_channels[channel]; |
185 | |
186 | if (pciide_chansetup(sc, channel, interface) == 0) |
187 | continue; |
188 | svwsata_mapchan(cp); |
189 | } |
190 | } |
191 | |
192 | static void |
193 | svwsata_mapreg_dma(struct pciide_softc *sc, const struct pci_attach_args *pa) |
194 | { |
195 | struct pciide_channel *pc; |
196 | int chan, reg; |
197 | bus_size_t size; |
198 | |
199 | sc->sc_wdcdev.dma_arg = sc; |
200 | sc->sc_wdcdev.dma_init = pciide_dma_init; |
201 | sc->sc_wdcdev.dma_start = pciide_dma_start; |
202 | sc->sc_wdcdev.dma_finish = pciide_dma_finish; |
203 | |
204 | if (device_cfdata(sc->sc_wdcdev.sc_atac.atac_dev)->cf_flags & |
205 | PCIIDE_OPTIONS_NODMA) { |
206 | aprint_normal( |
207 | ", but unused (forced off by config file)" ); |
208 | sc->sc_dma_ok = 0; |
209 | return; |
210 | } |
211 | |
212 | /* |
213 | * Slice off a subregion of BA5 for each of the channel's DMA |
214 | * registers. |
215 | */ |
216 | |
217 | sc->sc_dma_iot = sc->sc_ba5_st; |
218 | for (chan = 0; chan < 4; chan++) { |
219 | pc = &sc->pciide_channels[chan]; |
220 | for (reg = 0; reg < IDEDMA_NREGS; reg++) { |
221 | size = 4; |
222 | if (size > (IDEDMA_SCH_OFFSET - reg)) |
223 | size = IDEDMA_SCH_OFFSET - reg; |
224 | if (bus_space_subregion(sc->sc_ba5_st, |
225 | sc->sc_ba5_sh, |
226 | (chan << 8) + SVWSATA_DMA + reg, |
227 | size, &pc->dma_iohs[reg]) != 0) { |
228 | sc->sc_dma_ok = 0; |
229 | aprint_normal(", but can't subregion offset " |
230 | "%lu size %lu" , |
231 | (u_long) (chan << 8) + SVWSATA_DMA + reg, |
232 | (u_long) size); |
233 | return; |
234 | } |
235 | } |
236 | } |
237 | |
238 | /* DMA registers all set up! */ |
239 | sc->sc_dmat = pa->pa_dmat; |
240 | sc->sc_dma_ok = 1; |
241 | } |
242 | |
243 | static void |
244 | svwsata_mapchan(struct pciide_channel *cp) |
245 | { |
246 | struct ata_channel *wdc_cp = &cp->ata_channel; |
247 | struct pciide_softc *sc = CHAN_TO_PCIIDE(wdc_cp); |
248 | struct wdc_regs *wdr = CHAN_TO_WDC_REGS(wdc_cp); |
249 | int i; |
250 | |
251 | cp->compat = 0; |
252 | cp->ih = sc->sc_pci_ih; |
253 | |
254 | wdr->cmd_iot = sc->sc_ba5_st; |
255 | if (bus_space_subregion(sc->sc_ba5_st, sc->sc_ba5_sh, |
256 | (wdc_cp->ch_channel << 8) + SVWSATA_TF0, |
257 | SVWSATA_TF8 - SVWSATA_TF0, &wdr->cmd_baseioh) != 0) { |
258 | aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev, |
259 | "couldn't map %s cmd regs\n" , cp->name); |
260 | goto bad; |
261 | } |
262 | |
263 | wdr->ctl_iot = sc->sc_ba5_st; |
264 | if (bus_space_subregion(sc->sc_ba5_st, sc->sc_ba5_sh, |
265 | (wdc_cp->ch_channel << 8) + SVWSATA_TF8, 4, |
266 | &cp->ctl_baseioh) != 0) { |
267 | aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev, |
268 | "couldn't map %s ctl regs\n" , cp->name); |
269 | goto bad; |
270 | } |
271 | wdr->ctl_ioh = cp->ctl_baseioh; |
272 | |
273 | for (i = 0; i < WDC_NREG; i++) { |
274 | if (bus_space_subregion(wdr->cmd_iot, wdr->cmd_baseioh, |
275 | i << 2, i == 0 ? 4 : 1, |
276 | &wdr->cmd_iohs[i]) != 0) { |
277 | aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev, |
278 | "couldn't subregion %s channel cmd regs\n" , |
279 | cp->name); |
280 | goto bad; |
281 | } |
282 | } |
283 | wdc_init_shadow_regs(wdc_cp); |
284 | wdr->data32iot = wdr->cmd_iot; |
285 | wdr->data32ioh = wdr->cmd_iohs[0]; |
286 | |
287 | |
288 | wdr->sata_iot = sc->sc_ba5_st; |
289 | wdr->sata_baseioh = sc->sc_ba5_sh; |
290 | if (bus_space_subregion(wdr->sata_iot, wdr->sata_baseioh, |
291 | (wdc_cp->ch_channel << 8) + SVWSATA_SSTATUS, 1, |
292 | &wdr->sata_status) != 0) { |
293 | aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev, |
294 | "couldn't map channel %d sata_status regs\n" , |
295 | wdc_cp->ch_channel); |
296 | goto bad; |
297 | } |
298 | if (bus_space_subregion(wdr->sata_iot, wdr->sata_baseioh, |
299 | (wdc_cp->ch_channel << 8) + SVWSATA_SERROR, 1, |
300 | &wdr->sata_error) != 0) { |
301 | aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev, |
302 | "couldn't map channel %d sata_error regs\n" , |
303 | wdc_cp->ch_channel); |
304 | goto bad; |
305 | } |
306 | if (bus_space_subregion(wdr->sata_iot, wdr->sata_baseioh, |
307 | (wdc_cp->ch_channel << 8) + SVWSATA_SCONTROL, 1, |
308 | &wdr->sata_control) != 0) { |
309 | aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev, |
310 | "couldn't map channel %d sata_control regs\n" , |
311 | wdc_cp->ch_channel); |
312 | goto bad; |
313 | } |
314 | |
315 | bus_space_write_4(sc->sc_ba5_st, sc->sc_ba5_sh, |
316 | (wdc_cp->ch_channel << 8) + SVWSATA_SICR1, |
317 | bus_space_read_4(sc->sc_ba5_st, sc->sc_ba5_sh, |
318 | (wdc_cp->ch_channel << 8) + SVWSATA_SICR1) |
319 | & ~0x00040000); |
320 | bus_space_write_4(sc->sc_ba5_st, sc->sc_ba5_sh, |
321 | (wdc_cp->ch_channel << 8) + SVWSATA_SERROR, 0xffffffff); |
322 | bus_space_write_4(sc->sc_ba5_st, sc->sc_ba5_sh, |
323 | (wdc_cp->ch_channel << 8) + SVWSATA_SIM, 0); |
324 | |
325 | wdcattach(wdc_cp); |
326 | return; |
327 | |
328 | bad: |
329 | cp->ata_channel.ch_flags |= ATACH_DISABLED; |
330 | } |
331 | |