1183724Ssos/*-
2230132Suqs * Copyright (c) 1998 - 2008 S��ren Schmidt <sos@FreeBSD.org>
3183724Ssos * All rights reserved.
4183724Ssos *
5183724Ssos * Redistribution and use in source and binary forms, with or without
6183724Ssos * modification, are permitted provided that the following conditions
7183724Ssos * are met:
8183724Ssos * 1. Redistributions of source code must retain the above copyright
9183724Ssos *    notice, this list of conditions and the following disclaimer,
10183724Ssos *    without modification, immediately at the beginning of the file.
11183724Ssos * 2. Redistributions in binary form must reproduce the above copyright
12183724Ssos *    notice, this list of conditions and the following disclaimer in the
13183724Ssos *    documentation and/or other materials provided with the distribution.
14183724Ssos *
15183724Ssos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16183724Ssos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17183724Ssos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18183724Ssos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19183724Ssos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20183724Ssos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21183724Ssos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22183724Ssos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23183724Ssos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24183724Ssos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25183724Ssos */
26183724Ssos
27183724Ssos#include <sys/cdefs.h>
28183724Ssos__FBSDID("$FreeBSD$");
29183724Ssos
30183724Ssos#include <sys/param.h>
31183724Ssos#include <sys/module.h>
32183724Ssos#include <sys/systm.h>
33183724Ssos#include <sys/kernel.h>
34183724Ssos#include <sys/ata.h>
35183724Ssos#include <sys/bus.h>
36183724Ssos#include <sys/endian.h>
37183724Ssos#include <sys/malloc.h>
38183724Ssos#include <sys/lock.h>
39183724Ssos#include <sys/mutex.h>
40183724Ssos#include <sys/sema.h>
41183724Ssos#include <sys/taskqueue.h>
42183724Ssos#include <vm/uma.h>
43183724Ssos#include <machine/stdarg.h>
44183724Ssos#include <machine/resource.h>
45183724Ssos#include <machine/bus.h>
46183724Ssos#include <sys/rman.h>
47183724Ssos#include <dev/pci/pcivar.h>
48183724Ssos#include <dev/pci/pcireg.h>
49183724Ssos#include <dev/ata/ata-all.h>
50183724Ssos#include <dev/ata/ata-pci.h>
51183724Ssos#include <ata_if.h>
52183724Ssos
53183724Ssos/* local prototypes */
54183724Ssosstatic int ata_via_chipinit(device_t dev);
55188765Smavstatic int ata_via_ch_attach(device_t dev);
56188769Smavstatic int ata_via_ch_detach(device_t dev);
57183724Ssosstatic void ata_via_reset(device_t dev);
58214016Smavstatic int ata_via_status(device_t dev);
59200171Smavstatic int ata_via_old_setmode(device_t dev, int target, int mode);
60183724Ssosstatic void ata_via_southbridge_fixup(device_t dev);
61200171Smavstatic int ata_via_new_setmode(device_t dev, int target, int mode);
62200754Smavstatic int ata_via_sata_ch_attach(device_t dev);
63200754Smavstatic int ata_via_sata_getrev(device_t dev, int target);
64200754Smavstatic int ata_via_sata_setmode(device_t dev, int target, int mode);
65215449Smavstatic void ata_via_sata_reset(device_t dev);
66215449Smavstatic int ata_via_sata_scr_read(device_t dev, int port, int reg,
67215449Smav    u_int32_t *result);
68215449Smavstatic int ata_via_sata_scr_write(device_t dev, int port, int reg,
69215449Smav    u_int32_t value);
70215449Smavstatic int ata_via_sata_status(device_t dev);
71183724Ssos
72183724Ssos/* misc defines */
73183724Ssos#define VIA33           0
74183724Ssos#define VIA66           1
75183724Ssos#define VIA100          2
76183724Ssos#define VIA133          3
77183724Ssos
78183724Ssos#define VIACLK          0x01
79183724Ssos#define VIABUG          0x02
80183724Ssos#define VIABAR          0x04
81183724Ssos#define VIAAHCI         0x08
82200754Smav#define VIASATA         0x10
83183724Ssos
84183724Ssos/*
85183724Ssos * VIA Technologies Inc. chipset support functions
86183724Ssos */
87183724Ssosstatic int
88183724Ssosata_via_probe(device_t dev)
89183724Ssos{
90183724Ssos    struct ata_pci_controller *ctlr = device_get_softc(dev);
91242625Sdim    static const struct ata_chip_id ids[] =
92183724Ssos    {{ ATA_VIA82C586, 0x02, VIA33,  0x00,    ATA_UDMA2, "82C586B" },
93183724Ssos     { ATA_VIA82C586, 0x00, VIA33,  0x00,    ATA_WDMA2, "82C586" },
94183724Ssos     { ATA_VIA82C596, 0x12, VIA66,  VIACLK,  ATA_UDMA4, "82C596B" },
95183724Ssos     { ATA_VIA82C596, 0x00, VIA33,  0x00,    ATA_UDMA2, "82C596" },
96183724Ssos     { ATA_VIA82C686, 0x40, VIA100, VIABUG,  ATA_UDMA5, "82C686B"},
97183724Ssos     { ATA_VIA82C686, 0x10, VIA66,  VIACLK,  ATA_UDMA4, "82C686A" },
98183724Ssos     { ATA_VIA82C686, 0x00, VIA33,  0x00,    ATA_UDMA2, "82C686" },
99183724Ssos     { ATA_VIA8231,   0x00, VIA100, VIABUG,  ATA_UDMA5, "8231" },
100183724Ssos     { ATA_VIA8233,   0x00, VIA100, 0x00,    ATA_UDMA5, "8233" },
101183724Ssos     { ATA_VIA8233C,  0x00, VIA100, 0x00,    ATA_UDMA5, "8233C" },
102183724Ssos     { ATA_VIA8233A,  0x00, VIA133, 0x00,    ATA_UDMA6, "8233A" },
103183724Ssos     { ATA_VIA8235,   0x00, VIA133, 0x00,    ATA_UDMA6, "8235" },
104183724Ssos     { ATA_VIA8237,   0x00, VIA133, 0x00,    ATA_UDMA6, "8237" },
105183724Ssos     { ATA_VIA8237A,  0x00, VIA133, 0x00,    ATA_UDMA6, "8237A" },
106183724Ssos     { ATA_VIA8237S,  0x00, VIA133, 0x00,    ATA_UDMA6, "8237S" },
107198482Smav     { ATA_VIA8237_5372, 0x00, VIA133, 0x00, ATA_UDMA6, "8237" },
108198482Smav     { ATA_VIA8237_7372, 0x00, VIA133, 0x00, ATA_UDMA6, "8237" },
109183724Ssos     { ATA_VIA8251,   0x00, VIA133, 0x00,    ATA_UDMA6, "8251" },
110200754Smav     { ATA_VIACX700,  0x00, VIA133, VIASATA, ATA_SA150, "CX700" },
111200754Smav     { ATA_VIAVX800,  0x00, VIA133, VIASATA, ATA_SA150, "VX800" },
112200754Smav     { ATA_VIAVX855,  0x00, VIA133, 0x00,    ATA_UDMA6, "VX855" },
113215428Smav     { ATA_VIAVX900,  0x00, VIA133, VIASATA, ATA_SA300, "VX900" },
114183724Ssos     { 0, 0, 0, 0, 0, 0 }};
115242625Sdim    static const struct ata_chip_id new_ids[] =
116183724Ssos    {{ ATA_VIA6410,   0x00, 0,      0x00,    ATA_UDMA6, "6410" },
117183724Ssos     { ATA_VIA6420,   0x00, 7,      0x00,    ATA_SA150, "6420" },
118183724Ssos     { ATA_VIA6421,   0x00, 6,      VIABAR,  ATA_SA150, "6421" },
119183724Ssos     { ATA_VIA8237A,  0x00, 7,      0x00,    ATA_SA150, "8237A" },
120183724Ssos     { ATA_VIA8237S,  0x00, 7,      0x00,    ATA_SA150, "8237S" },
121198481Smav     { ATA_VIA8237_5372, 0x00, 7,   0x00,    ATA_SA300, "8237" },
122198481Smav     { ATA_VIA8237_7372, 0x00, 7,   0x00,    ATA_SA300, "8237" },
123183724Ssos     { ATA_VIA8251,   0x00, 0,      VIAAHCI, ATA_SA300, "8251" },
124183724Ssos     { 0, 0, 0, 0, 0, 0 }};
125183724Ssos
126183724Ssos    if (pci_get_vendor(dev) != ATA_VIA_ID)
127183724Ssos	return ENXIO;
128183724Ssos
129200754Smav    if (pci_get_devid(dev) == ATA_VIA82C571 ||
130200754Smav	pci_get_devid(dev) == ATA_VIACX700IDE ||
131215428Smav	pci_get_devid(dev) == ATA_VIASATAIDE ||
132215428Smav	pci_get_devid(dev) == ATA_VIASATAIDE2 ||
133215428Smav	pci_get_devid(dev) == ATA_VIASATAIDE3) {
134183724Ssos	if (!(ctlr->chip = ata_find_chip(dev, ids, -99)))
135183724Ssos	    return ENXIO;
136183724Ssos    }
137183724Ssos    else {
138183724Ssos	if (!(ctlr->chip = ata_match_chip(dev, new_ids)))
139183724Ssos	    return ENXIO;
140183724Ssos    }
141183724Ssos
142183724Ssos    ata_set_desc(dev);
143183724Ssos    ctlr->chipinit = ata_via_chipinit;
144194893Smav    return (BUS_PROBE_DEFAULT);
145183724Ssos}
146183724Ssos
147183724Ssosstatic int
148183724Ssosata_via_chipinit(device_t dev)
149183724Ssos{
150183724Ssos    struct ata_pci_controller *ctlr = device_get_softc(dev);
151183724Ssos
152183724Ssos    if (ata_setup_interrupt(dev, ata_generic_intr))
153183724Ssos	return ENXIO;
154200754Smav
155200754Smav    /* AHCI SATA */
156200754Smav    if (ctlr->chip->cfg2 & VIAAHCI) {
157200754Smav	if (ata_ahci_chipinit(dev) != ENXIO)
158200754Smav	    return (0);
159200754Smav    }
160215449Smav    /* 2 SATA with "SATA registers" at PCI config space + PATA on secondary */
161200754Smav    if (ctlr->chip->cfg2 & VIASATA) {
162200754Smav	ctlr->ch_attach = ata_via_sata_ch_attach;
163200754Smav	ctlr->setmode = ata_via_sata_setmode;
164200754Smav	ctlr->getrev = ata_via_sata_getrev;
165215449Smav	ctlr->reset = ata_via_sata_reset;
166200754Smav	return 0;
167200754Smav    }
168200754Smav    /* Legacy SATA/SATA+PATA with SATA registers in BAR(5). */
169183724Ssos    if (ctlr->chip->max_dma >= ATA_SA150) {
170183724Ssos	ctlr->r_type2 = SYS_RES_IOPORT;
171183724Ssos	ctlr->r_rid2 = PCIR_BAR(5);
172183724Ssos	if ((ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2,
173183724Ssos						   &ctlr->r_rid2, RF_ACTIVE))) {
174188765Smav	    ctlr->ch_attach = ata_via_ch_attach;
175188769Smav	    ctlr->ch_detach = ata_via_ch_detach;
176183724Ssos	    ctlr->reset = ata_via_reset;
177183724Ssos	}
178183724Ssos	if (ctlr->chip->cfg2 & VIABAR) {
179183724Ssos	    ctlr->channels = 3;
180183724Ssos	    ctlr->setmode = ata_via_new_setmode;
181200171Smav	} else
182183724Ssos	    ctlr->setmode = ata_sata_setmode;
183200171Smav	ctlr->getrev = ata_sata_getrev;
184183724Ssos	return 0;
185183724Ssos    }
186183724Ssos
187183724Ssos    /* prepare for ATA-66 on the 82C686a and 82C596b */
188183724Ssos    if (ctlr->chip->cfg2 & VIACLK)
189183724Ssos	pci_write_config(dev, 0x50, 0x030b030b, 4);
190183724Ssos
191183724Ssos    /* the southbridge might need the data corruption fix */
192183724Ssos    if (ctlr->chip->cfg2 & VIABUG)
193183724Ssos	ata_via_southbridge_fixup(dev);
194183724Ssos
195183724Ssos    /* set fifo configuration half'n'half */
196183724Ssos    pci_write_config(dev, 0x43,
197183724Ssos		     (pci_read_config(dev, 0x43, 1) & 0x90) | 0x2a, 1);
198183724Ssos
199183724Ssos    /* set status register read retry */
200183724Ssos    pci_write_config(dev, 0x44, pci_read_config(dev, 0x44, 1) | 0x08, 1);
201183724Ssos
202183724Ssos    /* set DMA read & end-of-sector fifo flush */
203183724Ssos    pci_write_config(dev, 0x46,
204183724Ssos		     (pci_read_config(dev, 0x46, 1) & 0x0c) | 0xf0, 1);
205183724Ssos
206183724Ssos    /* set sector size */
207183724Ssos    pci_write_config(dev, 0x60, DEV_BSIZE, 2);
208183724Ssos    pci_write_config(dev, 0x68, DEV_BSIZE, 2);
209183724Ssos
210183724Ssos    ctlr->setmode = ata_via_old_setmode;
211183724Ssos    return 0;
212183724Ssos}
213183724Ssos
214183724Ssosstatic int
215188765Smavata_via_ch_attach(device_t dev)
216183724Ssos{
217183724Ssos    struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
218183724Ssos    struct ata_channel *ch = device_get_softc(dev);
219183724Ssos
220183724Ssos    /* newer SATA chips has resources in one BAR for each channel */
221183724Ssos    if (ctlr->chip->cfg2 & VIABAR) {
222183724Ssos	struct resource *r_io;
223183724Ssos	int i, rid;
224183724Ssos
225188769Smav	ata_pci_dmainit(dev);
226188769Smav
227183724Ssos	rid = PCIR_BAR(ch->unit);
228183724Ssos	if (!(r_io = bus_alloc_resource_any(device_get_parent(dev),
229183724Ssos					    SYS_RES_IOPORT,
230183724Ssos					    &rid, RF_ACTIVE)))
231183724Ssos	    return ENXIO;
232183724Ssos
233183724Ssos	for (i = ATA_DATA; i <= ATA_COMMAND; i ++) {
234183724Ssos	    ch->r_io[i].res = r_io;
235183724Ssos	    ch->r_io[i].offset = i;
236183724Ssos	}
237183724Ssos	ch->r_io[ATA_CONTROL].res = r_io;
238183724Ssos	ch->r_io[ATA_CONTROL].offset = 2 + ATA_IOSIZE;
239183724Ssos	ch->r_io[ATA_IDX_ADDR].res = r_io;
240183724Ssos	ata_default_registers(dev);
241183724Ssos	for (i = ATA_BMCMD_PORT; i <= ATA_BMDTP_PORT; i++) {
242183724Ssos	    ch->r_io[i].res = ctlr->r_res1;
243183724Ssos	    ch->r_io[i].offset = (i - ATA_BMCMD_PORT)+(ch->unit * ATA_BMIOSIZE);
244183724Ssos	}
245183724Ssos	ata_pci_hw(dev);
246183724Ssos	if (ch->unit >= 2)
247183724Ssos	    return 0;
248183724Ssos    }
249183724Ssos    else {
250183724Ssos	/* setup the usual register normal pci style */
251188765Smav	if (ata_pci_ch_attach(dev))
252183724Ssos	    return ENXIO;
253183724Ssos    }
254183724Ssos
255183724Ssos    ch->r_io[ATA_SSTATUS].res = ctlr->r_res2;
256183724Ssos    ch->r_io[ATA_SSTATUS].offset = (ch->unit << ctlr->chip->cfg1);
257183724Ssos    ch->r_io[ATA_SERROR].res = ctlr->r_res2;
258183724Ssos    ch->r_io[ATA_SERROR].offset = 0x04 + (ch->unit << ctlr->chip->cfg1);
259183724Ssos    ch->r_io[ATA_SCONTROL].res = ctlr->r_res2;
260183724Ssos    ch->r_io[ATA_SCONTROL].offset = 0x08 + (ch->unit << ctlr->chip->cfg1);
261214016Smav    ch->hw.status = ata_via_status;
262183724Ssos    ch->flags |= ATA_NO_SLAVE;
263200171Smav    ch->flags |= ATA_SATA;
264214016Smav    ch->flags |= ATA_PERIODIC_POLL;
265183724Ssos
266214016Smav    ata_sata_scr_write(ch, -1, ATA_SERROR, 0xffffffff);
267214016Smav
268183724Ssos    return 0;
269183724Ssos}
270183724Ssos
271188769Smavstatic int
272188769Smavata_via_ch_detach(device_t dev)
273188769Smav{
274188769Smav    struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
275188769Smav    struct ata_channel *ch = device_get_softc(dev);
276188769Smav
277188769Smav    /* newer SATA chips has resources in one BAR for each channel */
278188769Smav    if (ctlr->chip->cfg2 & VIABAR) {
279188769Smav	int rid;
280188769Smav
281188769Smav	rid = PCIR_BAR(ch->unit);
282188769Smav	bus_release_resource(device_get_parent(dev),
283188769Smav	    SYS_RES_IOPORT, rid, ch->r_io[ATA_CONTROL].res);
284188769Smav
285188769Smav	ata_pci_dmafini(dev);
286188769Smav    }
287188769Smav    else {
288188769Smav	/* setup the usual register normal pci style */
289188769Smav	if (ata_pci_ch_detach(dev))
290188769Smav	    return ENXIO;
291188769Smav    }
292188769Smav
293188769Smav    return 0;
294188769Smav}
295188769Smav
296183724Ssosstatic void
297183724Ssosata_via_reset(device_t dev)
298183724Ssos{
299183724Ssos    struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
300183724Ssos    struct ata_channel *ch = device_get_softc(dev);
301183724Ssos
302183724Ssos    if ((ctlr->chip->cfg2 & VIABAR) && (ch->unit > 1))
303183724Ssos        ata_generic_reset(dev);
304209884Smav    else {
305190581Smav	if (ata_sata_phy_reset(dev, -1, 1))
306183724Ssos	    ata_generic_reset(dev);
307209884Smav	else
308209884Smav	    ch->devices = 0;
309209884Smav    }
310183724Ssos}
311183724Ssos
312200171Smavstatic int
313214016Smavata_via_status(device_t dev)
314214016Smav{
315214016Smav
316214016Smav	ata_sata_phy_check_events(dev, -1);
317214016Smav	return (ata_pci_status(dev));
318214016Smav}
319214016Smav
320214016Smavstatic int
321200171Smavata_via_new_setmode(device_t dev, int target, int mode)
322183724Ssos{
323200171Smav	device_t parent = device_get_parent(dev);
324200171Smav	struct ata_pci_controller *ctlr = device_get_softc(parent);
325200171Smav	struct ata_channel *ch = device_get_softc(dev);
326183724Ssos
327200171Smav	if ((ctlr->chip->cfg2 & VIABAR) && (ch->unit > 1)) {
328200171Smav	    int piomode;
329233282Smarius    	    static const uint8_t pio_timings[] =
330233282Smarius		{ 0xa8, 0x65, 0x65, 0x32, 0x20 };
331233282Smarius	    static const uint8_t dma_timings[] =
332233282Smarius		{ 0xee, 0xe8, 0xe6, 0xe4, 0xe2, 0xe1, 0xe0 };
333183724Ssos
334200171Smav	    /* This chip can't do WDMA. */
335200171Smav	    if (mode >= ATA_WDMA0 && mode < ATA_UDMA0)
336200171Smav		mode = ATA_PIO4;
337200171Smav	    if (mode >= ATA_UDMA0) {
338200171Smav		pci_write_config(parent, 0xb3,
339183724Ssos				 dma_timings[mode & ATA_MODE_MASK], 1);
340200171Smav		piomode = ATA_PIO4;
341200171Smav	    } else
342200171Smav		piomode = mode;
343200171Smav	    pci_write_config(parent, 0xab, pio_timings[ata_mode2idx(piomode)], 1);
344200171Smav	} else
345200171Smav		mode = ata_sata_setmode(dev, target, mode);
346200171Smav	return (mode);
347183724Ssos}
348183724Ssos
349200171Smavstatic int
350200171Smavata_via_old_setmode(device_t dev, int target, int mode)
351183724Ssos{
352200171Smav	device_t parent = device_get_parent(dev);
353200171Smav	struct ata_pci_controller *ctlr = device_get_softc(parent);
354200171Smav	struct ata_channel *ch = device_get_softc(dev);
355200171Smav	int devno = (ch->unit << 1) + target;
356200171Smav	int reg = 0x53 - devno;
357200171Smav	int piomode;
358233282Smarius	static const uint8_t timings[] =
359233282Smarius	    { 0xa8, 0x65, 0x42, 0x22, 0x20, 0xa8, 0x22, 0x20 };
360233282Smarius	static const uint8_t modes[][7] = {
361200171Smav	    { 0xc2, 0xc1, 0xc0, 0x00, 0x00, 0x00, 0x00 },   /* VIA ATA33 */
362200171Smav	    { 0xee, 0xec, 0xea, 0xe9, 0xe8, 0x00, 0x00 },   /* VIA ATA66 */
363200171Smav	    { 0xf7, 0xf6, 0xf4, 0xf2, 0xf1, 0xf0, 0x00 },   /* VIA ATA100 */
364200171Smav	    { 0xf7, 0xf7, 0xf6, 0xf4, 0xf2, 0xf1, 0xf0 } }; /* VIA ATA133 */
365183724Ssos
366200171Smav	mode = min(mode, ctlr->chip->max_dma);
367200171Smav	/* Set UDMA timings */
368200171Smav	if (mode >= ATA_UDMA0) {
369200171Smav	    pci_write_config(parent, reg,
370200171Smav			     modes[ctlr->chip->cfg1][mode & ATA_MODE_MASK], 1);
371200171Smav	    piomode = ATA_PIO4;
372200171Smav	} else {
373200171Smav	    pci_write_config(parent, reg, 0x8b, 1);
374200171Smav	    piomode = mode;
375200171Smav	}
376200171Smav	/* Set WDMA/PIO timings */
377213301Smav	pci_write_config(parent, reg - 0x08,timings[ata_mode2idx(piomode)], 1);
378200171Smav	return (mode);
379183724Ssos}
380183724Ssos
381183724Ssosstatic void
382183724Ssosata_via_southbridge_fixup(device_t dev)
383183724Ssos{
384183724Ssos    device_t *children;
385183724Ssos    int nchildren, i;
386183724Ssos
387183724Ssos    if (device_get_children(device_get_parent(dev), &children, &nchildren))
388183724Ssos	return;
389183724Ssos
390183724Ssos    for (i = 0; i < nchildren; i++) {
391183724Ssos	if (pci_get_devid(children[i]) == ATA_VIA8363 ||
392183724Ssos	    pci_get_devid(children[i]) == ATA_VIA8371 ||
393183724Ssos	    pci_get_devid(children[i]) == ATA_VIA8662 ||
394183724Ssos	    pci_get_devid(children[i]) == ATA_VIA8361) {
395183724Ssos	    u_int8_t reg76 = pci_read_config(children[i], 0x76, 1);
396183724Ssos
397183724Ssos	    if ((reg76 & 0xf0) != 0xd0) {
398183724Ssos		device_printf(dev,
399183724Ssos		"Correcting VIA config for southbridge data corruption bug\n");
400183724Ssos		pci_write_config(children[i], 0x75, 0x80, 1);
401183724Ssos		pci_write_config(children[i], 0x76, (reg76 & 0x0f) | 0xd0, 1);
402183724Ssos	    }
403183724Ssos	    break;
404183724Ssos	}
405183724Ssos    }
406183724Ssos    free(children, M_TEMP);
407183724Ssos}
408183724Ssos
409200754Smavstatic int
410200754Smavata_via_sata_ch_attach(device_t dev)
411200754Smav{
412200754Smav	struct ata_channel *ch = device_get_softc(dev);
413200754Smav
414200754Smav	if (ata_pci_ch_attach(dev))
415200754Smav		return ENXIO;
416215449Smav	if (ch->unit == 0) {
417215449Smav		ch->hw.status = ata_via_sata_status;
418215449Smav		ch->hw.pm_read = ata_via_sata_scr_read;
419215449Smav		ch->hw.pm_write = ata_via_sata_scr_write;
420215449Smav		ch->flags |= ATA_PERIODIC_POLL;
421200754Smav		ch->flags |= ATA_SATA;
422215449Smav		ata_sata_scr_write(ch, 0, ATA_SERROR, 0xffffffff);
423215449Smav		ata_sata_scr_write(ch, 1, ATA_SERROR, 0xffffffff);
424215449Smav	}
425200754Smav	return (0);
426200754Smav}
427200754Smav
428200754Smavstatic int
429200754Smavata_via_sata_getrev(device_t dev, int target)
430200754Smav{
431215449Smav	device_t parent = device_get_parent(dev);
432200754Smav	struct ata_channel *ch = device_get_softc(dev);
433200754Smav
434215449Smav	if (ch->unit == 0) {
435215449Smav		if (pci_read_config(parent, 0xa0 + target, 1) & 0x10)
436215449Smav			return (2);
437215449Smav		else
438215449Smav			return (1);
439215449Smav	}
440200754Smav	return (0);
441200754Smav}
442200754Smav
443200754Smavstatic int
444200754Smavata_via_sata_setmode(device_t dev, int target, int mode)
445200754Smav{
446200754Smav	struct ata_channel *ch = device_get_softc(dev);
447200754Smav
448200754Smav	if (ch->unit == 0)
449200754Smav		return (mode);
450200754Smav	return (ata_via_old_setmode(dev, target, mode));
451200754Smav}
452200754Smav
453215449Smavstatic void
454215449Smavata_via_sata_reset(device_t dev)
455215449Smav{
456215449Smav	struct ata_channel *ch = device_get_softc(dev);
457215449Smav	int devs;
458215449Smav
459215449Smav	if (ch->unit == 0) {
460215449Smav		devs = ata_sata_phy_reset(dev, 0, 0);
461215449Smav		DELAY(10000);
462215449Smav		devs += ata_sata_phy_reset(dev, 1, 0);
463215449Smav	} else
464215449Smav		devs = 1;
465215449Smav	if (devs)
466215449Smav		ata_generic_reset(dev);
467215451Smav	else
468215451Smav		ch->devices = 0;
469215449Smav}
470215449Smav
471215449Smavstatic int
472215449Smavata_via_sata_scr_read(device_t dev, int port, int reg, u_int32_t *result)
473215449Smav{
474215449Smav	device_t parent;
475215449Smav	uint32_t val;
476215449Smav
477215449Smav	parent = device_get_parent(dev);
478215449Smav	port = (port == 1) ? 1 : 0;
479215449Smav	switch (reg) {
480215449Smav	case ATA_SSTATUS:
481215449Smav		val = pci_read_config(parent, 0xa0 + port, 1);
482215449Smav		*result = val & 0x03;
483215449Smav		if (*result != ATA_SS_DET_NO_DEVICE) {
484215449Smav			if (val & 0x04)
485215449Smav				*result |= ATA_SS_IPM_PARTIAL;
486215449Smav			else if (val & 0x08)
487215449Smav				*result |= ATA_SS_IPM_SLUMBER;
488215449Smav			else
489215449Smav				*result |= ATA_SS_IPM_ACTIVE;
490215449Smav			if (val & 0x10)
491215449Smav				*result |= ATA_SS_SPD_GEN2;
492215449Smav			else
493215449Smav				*result |= ATA_SS_SPD_GEN1;
494215449Smav		}
495215449Smav		break;
496215449Smav	case ATA_SERROR:
497215449Smav		*result = pci_read_config(parent, 0xa8 + port * 4, 4);
498215449Smav		break;
499215449Smav	case ATA_SCONTROL:
500215449Smav		val = pci_read_config(parent, 0xa4 + port, 1);
501215449Smav		*result = 0;
502215449Smav		if (val & 0x01)
503215449Smav			*result |= ATA_SC_DET_RESET;
504215449Smav		if (val & 0x02)
505215449Smav			*result |= ATA_SC_DET_DISABLE;
506215449Smav		if (val & 0x04)
507215449Smav			*result |= ATA_SC_IPM_DIS_PARTIAL;
508215449Smav		if (val & 0x08)
509215449Smav			*result |= ATA_SC_IPM_DIS_SLUMBER;
510215449Smav		break;
511215449Smav	default:
512215449Smav		return (EINVAL);
513215449Smav	}
514215449Smav	return (0);
515215449Smav}
516215449Smav
517215449Smavstatic int
518215449Smavata_via_sata_scr_write(device_t dev, int port, int reg, u_int32_t value)
519215449Smav{
520215449Smav	device_t parent;
521215449Smav	uint32_t val;
522215449Smav
523215449Smav	parent = device_get_parent(dev);
524215449Smav	port = (port == 1) ? 1 : 0;
525215449Smav	switch (reg) {
526215449Smav	case ATA_SERROR:
527215449Smav		pci_write_config(parent, 0xa8 + port * 4, value, 4);
528215449Smav		break;
529215449Smav	case ATA_SCONTROL:
530215449Smav		val = 0;
531215449Smav		if (value & ATA_SC_DET_RESET)
532215449Smav			val |= 0x01;
533215449Smav		if (value & ATA_SC_DET_DISABLE)
534215449Smav			val |= 0x02;
535215449Smav		if (value & ATA_SC_IPM_DIS_PARTIAL)
536215449Smav			val |= 0x04;
537215449Smav		if (value & ATA_SC_IPM_DIS_SLUMBER)
538215449Smav			val |= 0x08;
539215449Smav		pci_write_config(parent, 0xa4 + port, val, 1);
540215449Smav		break;
541215449Smav	default:
542215449Smav		return (EINVAL);
543215449Smav	}
544215449Smav	return (0);
545215449Smav}
546215449Smav
547215449Smavstatic int
548215449Smavata_via_sata_status(device_t dev)
549215449Smav{
550215449Smav
551215449Smav	ata_sata_phy_check_events(dev, 0);
552215449Smav	ata_sata_phy_check_events(dev, 1);
553215449Smav	return (ata_pci_status(dev));
554215449Smav}
555215449Smav
556183724SsosATA_DECLARE_DRIVER(ata_via);
557183724SsosMODULE_DEPEND(ata_via, ata_ahci, 1, 1, 1);
558