tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: viaide at cardbus (VT6421A)



Hi,

Since the last email, I made some changes, mainly adding additional
unmapping on detach and a few cleanups.

I am not sure whether more diligent unmapping should be implemented in
the failure path of the attach process.

But otherwise, I didn't touch code for a while and consider myself
ready for the initial commit.

Still waiting for comments (or maybe opinions weather it should be
committed at all).

Thanks!

Regards,
Andrius V

On Wed, Sep 9, 2026 at 8:54 AM Andrius V <vezhlys%gmail.com@localhost> wrote:
>
> Hi,
>
> I would like to request a review of the attached viaide at cardbus patch.
> It is also available at:
> https://patch-diff.githubusercontent.com/raw/vezhlys/netbsd-src/pull/7.diff
>
> It supports the VT6421A controller only, which I believe is the only
> chip that was used in cardbus devices supported by viaide(4) driver.
>
> Initially, I didn't expect to work on this due to low practical need,
> but incidentally it appeared that my SATA cardbus controller had a VIA
> controller.
>
> After several sessions, I made a PoC by faking a "pci attachment".
> Once it worked, I was motivated enough to implement a proper solution.
>
> Creating an actual patch with cardbus glue was a bit more daunting:
> * I moved the VT6421 non-pci specific code to sys/dev/ic/vt6421.c
> (mainly from via_sata_chip_map_new).
>
> * PCI and cardbus has their
> pci/Cardbus_mapreg_map/conf_read/conf_write/intr_establish functions
> calls in their respective pci and cardbus driver.
> ic/vt6421.c code uses these pre-set values by the corresponding bus
> attachment to set up.
>
> The logic for PCI should not have changed. The cardbus driver just
> adds its own code for establishing interrupts, mapping registers, and
> other bus-specific setup.
>
> Tested on both cardbus and PCI (detection, mounting, format, writing
> files, suspend/resume device, smartctl etc).
>
> parts of dmesg:
> ...
> cbb0 at pci0 dev 8 function 0: Ricoh 5C475 PCI-CardBus Bridge (rev. 0x81)
> ...
> cbb0: osock_ctrl 0x400 sock_ctrl 0x400
> cbb0: wait took 0.040026s
> cbb0: cacheline 0x0 lattimer 0x20
> cbb0: bhlc 0x22000
> allocated pic ioapic0 type level pin 16 level 6 to cpu0 slot 9 idt entry 104
> cbb0: interrupting at ioapic0 pin 16
> cardslot0 at cbb0
> cardbus0 at cardslot0: bus 2 cacheline 0x0, lattimer 0x20
> pcmcia0 at cardslot0
> ...
> cbb0: wait took 0.031570s
> cb_reset: enter bcr 7e3010a
> cb_reset: wrote bcr 7e3010a
> cb_reset: wrote bcr 7a3010a
> cb_reset: end of delay
> cardbus0: id reg valid in 0 iterations
> viaide2 at cardbus0 function 0: VIA Technologies VT6421 Serial ATA Controller
> viaide2: bus-master DMA support present
> atabus3 at viaide2 channel 0
> atabus4 at viaide2 channel 1
> atabus5 at viaide2 channel 2
> waiting for devices: atabus1 atabus2 atabus3 atabus4 atabus5
> wd0 at atabus1 drive 0
> ...
> waiting for devices: atabus4 atabus5
> wd1 at atabus4 drive 0
> wd1: <Patriot P220 128GB>
> wd1: drive supports 16-sector PIO transfers, LBA48 addressing
> wd1: 119 GB, 248085 cyl, 16 head, 63 sec, 512 bytes/sect x 250069680 sectors
> waiting for devices: atabus4 atabus5
> wd1: 32-bit data port
> wd1: drive supports PIO mode 4, DMA mode 2, Ultra-DMA mode 6
> (Ultra/133), WRITE DMA FUA, NCQ (32 tags)
> wd1(viaide2:1:0): using PIO mode 4, Ultra-DMA mode 6 (Ultra/133)
> (using DMA), WRITE DMA FUA EXT
>
> Regards,
> Andrius V
--- viaideatcardbus.diff	2026-09-09 08:50:31.766545130 +0300
+++ viaideatcardbus2.diff	2026-09-14 13:05:47.571326243 +0300
@@ -84,10 +84,10 @@ index babcaa7ad087..cf4f73c75ae3 100644
  #
 diff --git a/sys/dev/cardbus/viaide_cardbus.c b/sys/dev/cardbus/viaide_cardbus.c
 new file mode 100644
-index 000000000000..cfdb41ad3b83
+index 000000000000..5849a6fec565
 --- /dev/null
 +++ b/sys/dev/cardbus/viaide_cardbus.c
-@@ -0,0 +1,248 @@
+@@ -0,0 +1,263 @@
 +/*	$NetBSD$	*/
 +
 +/*-
@@ -151,7 +151,6 @@ index 000000000000..cfdb41ad3b83
 +static int viaide_cardbus_detach(device_t, int);
 +static bool viaide_cardbus_suspend(device_t, const pmf_qual_t *);
 +static bool viaide_cardbus_resume(device_t, const pmf_qual_t *);
-+void via_sata_chip_map_new(struct pciide_softc *sc, const struct pci_attach_args *pa);
 +
 +static const struct viaide_cardbus_product {
 +
@@ -261,6 +260,12 @@ index 000000000000..cfdb41ad3b83
 +	csc->csc_tag = ca->ca_tag;
 +
 +	csc->csc_ih = Cardbus_intr_establish(ct, IPL_BIO, pciide_pci_intr, sc);
++	
++	if (csc->csc_ih == NULL) {
++			aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev,
++			    "couldn't establish interrupt\n");
++		return;
++	}
 +
 +	for (channel = 0; channel < VT6421_NCHANNELS; channel++) {
 +		vch = &chan_handlers[channel];
@@ -282,9 +287,17 @@ index 000000000000..cfdb41ad3b83
 +	struct viaide_cardbus_softc *csc = device_private(self);
 +	struct pciide_softc *sc = &csc->csc_sc;
 +	struct cardbus_devfunc *ct = csc->csc_ct;
-+	int rv;
++	int rv, channel;
++
++	for (channel = 0; channel < VT6421_NCHANNELS; channel++) {
++		Cardbus_mapreg_unmap(ct, PCI_BAR(channel), sc->sc_ba5_st, sc->sc_ba5_sh,
++			sc->sc_ba5_ss);
++	}
++	Cardbus_mapreg_unmap(ct, PCI_BAR5, sc->sc_ba5_st, sc->sc_ba5_sh,
++	    sc->sc_ba5_ss);
++	Cardbus_mapreg_unmap(ct, PCIIDE_REG_BUS_MASTER_DMA, sc->sc_ba5_st, sc->sc_ba5_sh,
++	    sc->sc_ba5_ss);
 +
-+	pmf_device_deregister(self);
 +	rv = pciide_common_detach(sc, flags);
 +	if (rv)
 +		return (rv);
@@ -293,6 +306,8 @@ index 000000000000..cfdb41ad3b83
 +		csc->csc_ih = NULL;
 +	}
 +
++	pmf_device_deregister(self);
++
 +	return 0;
 +}
 +
@@ -338,7 +353,7 @@ index 000000000000..cfdb41ad3b83
 +}
 diff --git a/sys/dev/ic/vt6421.c b/sys/dev/ic/vt6421.c
 new file mode 100644
-index 000000000000..52d203d09523
+index 000000000000..4da75497fdf2
 --- /dev/null
 +++ b/sys/dev/ic/vt6421.c
 @@ -0,0 +1,191 @@
@@ -370,7 +385,7 @@ index 000000000000..52d203d09523
 + * POSSIBILITY OF SUCH DAMAGE.
 + */
 + 
-+ #include <sys/cdefs.h>
++#include <sys/cdefs.h>
 +__KERNEL_RCSID(0, "$NetBSD$");
 +
 +#include <sys/param.h>
diff --git a/share/man/man4/viaide.4 b/share/man/man4/viaide.4
index dffa278d86f4..d47bec71a407 100644
--- a/share/man/man4/viaide.4
+++ b/share/man/man4/viaide.4
@@ -30,6 +30,7 @@
 .Nd AMD, NVIDIA and VIA IDE disk controllers driver
 .Sh SYNOPSIS
 .Cd "viaide* at pci? dev ? function ? flags 0x0000"
+.Cd "viaide* at cardbus? function ?"
 .Cd "options PCIIDE_AMD756_ENABLEDMA"
 .Sh DESCRIPTION
 The
@@ -61,6 +62,7 @@ problems where the IDE controller is wired up to the system incorrectly.
 .Sh SEE ALSO
 .Xr ata 4 ,
 .Xr atapi 4 ,
+.Xr cardbus 4 ,
 .Xr intro 4 ,
 .Xr pci 4 ,
 .Xr pciide 4 ,
diff --git a/sys/arch/amd64/conf/ALL b/sys/arch/amd64/conf/ALL
index 6e3b7f30c042..ca4b6189d58a 100644
--- a/sys/arch/amd64/conf/ALL
+++ b/sys/arch/amd64/conf/ALL
@@ -917,6 +917,7 @@ wdc*	at pcmcia? function ?
 # CardBus IDE controllers
 njata*	at cardbus? function ? flags 0x01	# Workbit NinjaATA-32
 siisata* at cardbus? function ? 		# SiI SteelVine controllers
+viaide* at cardbus? function ? 			# VIA VT6421 controller
 
 # ISA ST506, ESDI, and IDE controllers
 # Use flags 0x01 if you want to try to use 32bits data I/O (the driver will
diff --git a/sys/arch/amd64/conf/GENERIC b/sys/arch/amd64/conf/GENERIC
index 04e3aa3cf8c7..6c66a73fc3d7 100644
--- a/sys/arch/amd64/conf/GENERIC
+++ b/sys/arch/amd64/conf/GENERIC
@@ -760,6 +760,7 @@ wdc*	at pcmcia? function ?
 # CardBus IDE controllers
 njata*	at cardbus? function ? flags 0x01	# Workbit NinjaATA-32
 siisata* at cardbus? function ? 	# SiI SteelVine controllers
+viaide* at cardbus? function ? 		# VIA VT6421 controller
 
 # ISA ST506, ESDI, and IDE controllers
 # Use flags 0x01 if you want to try to use 32bits data I/O (the driver will
diff --git a/sys/arch/i386/conf/ALL b/sys/arch/i386/conf/ALL
index 70d9a3643619..c30bab800c63 100644
--- a/sys/arch/i386/conf/ALL
+++ b/sys/arch/i386/conf/ALL
@@ -1000,6 +1000,7 @@ wdc*	at pcmcia? function ?
 # CardBus IDE controllers
 njata*	at cardbus? function ? flags 0x01	# Workbit NinjaATA-32
 siisata* at cardbus? function ? 		# SiI SteelVine controllers
+viaide* at cardbus? function ? 			# VIA VT6421 controller
 
 # ISA ST506, ESDI, and IDE controllers
 # Use flags 0x01 if you want to try to use 32bits data I/O (the driver will
diff --git a/sys/arch/i386/conf/GENERIC b/sys/arch/i386/conf/GENERIC
index 34142aff3b5e..1f7a771859b8 100644
--- a/sys/arch/i386/conf/GENERIC
+++ b/sys/arch/i386/conf/GENERIC
@@ -906,6 +906,7 @@ wdc*	at pcmcia? function ?
 # CardBus IDE controllers
 njata*	at cardbus? function ? flags 0x01	# Workbit NinjaATA-32
 siisata* at cardbus? function ? 		# SiI SteelVine controllers
+viaide* at cardbus? function ? 			# VIA VT6421 controller
 
 # ISA ST506, ESDI, and IDE controllers
 # Use flags 0x01 if you want to try to use 32bits data I/O (the driver will
diff --git a/sys/dev/cardbus/files.cardbus b/sys/dev/cardbus/files.cardbus
index babcaa7ad087..cf4f73c75ae3 100644
--- a/sys/dev/cardbus/files.cardbus
+++ b/sys/dev/cardbus/files.cardbus
@@ -150,6 +150,11 @@ file	dev/cardbus/njata_cardbus.c	njata_cardbus
 attach	siisata at cardbus with siisata_cardbus
 file	dev/cardbus/siisata_cardbus.c	siisata_cardbus
 
+# VIA VT6421A SATA controllers
+#
+attach	viaide at cardbus with viaide_cardbus
+file	dev/cardbus/viaide_cardbus.c	viaide_cardbus
+
 #
 # SD Host Controller
 #
diff --git a/sys/dev/cardbus/viaide_cardbus.c b/sys/dev/cardbus/viaide_cardbus.c
new file mode 100644
index 000000000000..5849a6fec565
--- /dev/null
+++ b/sys/dev/cardbus/viaide_cardbus.c
@@ -0,0 +1,263 @@
+/*	$NetBSD$	*/
+
+/*-
+ * Copyright (c) 2026 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD$");
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+
+#include <dev/cardbus/cardbusvar.h>
+
+#include <dev/pci/pcidevs.h>
+#include <dev/pci/pciide_apollo_reg.h>
+#include <dev/pci/pciidereg.h>
+#include <dev/pci/pciidevar.h>
+
+#include <dev/ic/vt6421var.h>
+
+struct viaide_cardbus_softc {
+	struct pciide_softc csc_sc;
+	cardbus_chipset_tag_t csc_cc;
+	cardbus_function_tag_t csc_cf;
+	cardbus_devfunc_t csc_ct;
+	pcitag_t csc_tag;
+	bus_space_tag_t csc_iot;		/* CardBus I/O space tag */
+	bus_space_tag_t csc_memt;	/* CardBus MEM space tag */
+	rbus_tag_t csc_rbus_iot;		/* CardBus i/o rbus tag */
+	rbus_tag_t csc_rbus_memt;	/* CardBus mem rbus tag */
+	void *csc_ih;
+};
+
+static int viaide_cardbus_match(device_t, cfdata_t, void *);
+static void viaide_cardbus_attach(device_t, device_t, void *);
+static int viaide_cardbus_detach(device_t, int);
+static bool viaide_cardbus_suspend(device_t, const pmf_qual_t *);
+static bool viaide_cardbus_resume(device_t, const pmf_qual_t *);
+
+static const struct viaide_cardbus_product {
+
+	uint32_t ide_product;
+	const char *ide_name;
+} viaide_cardbus_products[] = {
+	{ PCI_PRODUCT_VIATECH_VT6421_RAID,
+	  "VIA Technologies VT6421 Serial ATA Controller"
+	},
+	{ 0,
+	  NULL
+	},
+};
+
+CFATTACH_DECL_NEW(viaide_cardbus, sizeof(struct viaide_cardbus_softc),
+    viaide_cardbus_match, viaide_cardbus_attach, viaide_cardbus_detach,
+    NULL);
+
+static const struct viaide_cardbus_product *
+viaide_cardbus_lookup(const struct cardbus_attach_args *ca)
+{
+	const struct viaide_cardbus_product *vcp;
+
+	for (vcp = viaide_cardbus_products; vcp->ide_product != 0; vcp++) {
+		if (PCI_VENDOR(ca->ca_id) == PCI_VENDOR_VIATECH &&
+		    PCI_PRODUCT(ca->ca_id) == vcp->ide_product)
+			return vcp;
+	}
+
+	return NULL;
+}
+
+static int
+viaide_cardbus_match(device_t parent, cfdata_t match, void *aux)
+{
+	struct cardbus_attach_args *ca = aux;
+
+	if (viaide_cardbus_lookup(ca) != NULL)
+		return 2;
+
+	return 0;
+}
+
+static void
+viaide_cardbus_attach(device_t parent, device_t self, void *aux)
+{
+	const struct cardbus_attach_args *ca = aux;
+	const struct viaide_cardbus_product *vcp;
+	struct viaide_cardbus_softc *csc = device_private(self);
+	struct pciide_softc *sc = &csc->csc_sc;
+	cardbus_devfunc_t ct = ca->ca_ct;
+	cardbus_chipset_tag_t cc = ct->ct_cc;
+	cardbus_function_tag_t cf = ct->ct_cf;
+	pcireg_t reg;
+	struct vt6421_chan_handler chan_handlers[VT6421_NCHANNELS];
+	struct vt6421_chan_handler *vch;
+	int csr, channel;
+
+	vcp = viaide_cardbus_lookup(ca);
+
+	aprint_naive(": SATA HBA\n");
+	aprint_normal(": %s\n", vcp->ide_name);
+
+	/* Map I/O registers */
+	csc->csc_sc.sc_dma_ok = (Cardbus_mapreg_map(ct, PCIIDE_REG_BUS_MASTER_DMA,
+                PCI_MAPREG_TYPE_IO, 0, &sc->sc_dma_iot, &sc->sc_dma_ioh, NULL, 
+			    &sc->sc_dma_ios)  == 0);
+
+	sc->sc_wdcdev.sc_atac.atac_dev = self;
+	aprint_verbose_dev(self, "bus-master DMA support present");
+	vt6421_mapreg_dma(sc, ca->ca_dmat);
+	aprint_verbose("\n");
+
+	if (Cardbus_mapreg_map(ct, PCI_BAR5, PCI_MAPREG_TYPE_IO, 0,
+			   &sc->sc_ba5_st, &sc->sc_ba5_sh, NULL, &sc->sc_ba5_ss)) {
+		aprint_error_dev(self, "couldn't map SATA regs\n");
+		return;
+	}
+
+	csc->csc_cc = cc;
+	csc->csc_cf = cf;
+	csc->csc_ct = ct;
+	csc->csc_tag = ca->ca_tag;
+
+#if NATA_DMA
+	/* Set up DMA defaults; these might be adjusted by chip_map. */
+	sc->sc_dma_maxsegsz = IDEDMA_BYTE_COUNT_MAX;
+	sc->sc_dma_boundary = IDEDMA_BYTE_COUNT_ALIGN;
+#endif
+
+	/*
+	 * Map the device.
+	 */
+	csr = PCI_COMMAND_MASTER_ENABLE;
+  
+	/* Enable the appropriate bits in the PCI CSR. */
+	reg = Cardbus_conf_read(ct, ca->ca_tag, PCI_COMMAND_STATUS_REG);
+	csr |= PCI_COMMAND_IO_ENABLE;
+	csr |= PCI_COMMAND_MEM_ENABLE;
+	reg |= csr;
+	Cardbus_conf_write(ct, ca->ca_tag, PCI_COMMAND_STATUS_REG, reg);
+
+	csc->csc_iot = ca->ca_iot;
+	csc->csc_memt = ca->ca_memt;
+	csc->csc_rbus_iot = ca->ca_rbus_iot;
+	csc->csc_rbus_memt = ca->ca_rbus_memt;
+	csc->csc_tag = ca->ca_tag;
+
+	csc->csc_ih = Cardbus_intr_establish(ct, IPL_BIO, pciide_pci_intr, sc);
+	
+	if (csc->csc_ih == NULL) {
+			aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev,
+			    "couldn't establish interrupt\n");
+		return;
+	}
+
+	for (channel = 0; channel < VT6421_NCHANNELS; channel++) {
+		vch = &chan_handlers[channel];
+		if (Cardbus_mapreg_map(ct, PCI_BAR(channel), PCI_MAPREG_TYPE_IO, 0,
+			    &vch->sc_cmd_st, &vch->sc_cmd_sh, NULL, &vch->sc_cmd_ios) != 0)
+			aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev,
+			    "couldn't map channel %d regs\n", channel);
+	}
+
+	vt6421_chip_map(sc, chan_handlers);
+
+	if (!pmf_device_register(self, viaide_cardbus_suspend, viaide_cardbus_resume))
+		aprint_error_dev(self, "couldn't establish power handler\n");
+}
+
+static int
+viaide_cardbus_detach(device_t self, int flags)
+{
+	struct viaide_cardbus_softc *csc = device_private(self);
+	struct pciide_softc *sc = &csc->csc_sc;
+	struct cardbus_devfunc *ct = csc->csc_ct;
+	int rv, channel;
+
+	for (channel = 0; channel < VT6421_NCHANNELS; channel++) {
+		Cardbus_mapreg_unmap(ct, PCI_BAR(channel), sc->sc_ba5_st, sc->sc_ba5_sh,
+			sc->sc_ba5_ss);
+	}
+	Cardbus_mapreg_unmap(ct, PCI_BAR5, sc->sc_ba5_st, sc->sc_ba5_sh,
+	    sc->sc_ba5_ss);
+	Cardbus_mapreg_unmap(ct, PCIIDE_REG_BUS_MASTER_DMA, sc->sc_ba5_st, sc->sc_ba5_sh,
+	    sc->sc_ba5_ss);
+
+	rv = pciide_common_detach(sc, flags);
+	if (rv)
+		return (rv);
+	if (csc->csc_ih != NULL) {
+		Cardbus_intr_disestablish(ct, csc->csc_ih);
+		csc->csc_ih = NULL;
+	}
+
+	pmf_device_deregister(self);
+
+	return 0;
+}
+
+static bool
+viaide_cardbus_suspend(device_t dv, const pmf_qual_t *qual)
+{
+	struct viaide_cardbus_softc *csc = device_private(dv);
+	struct pciide_softc *sc = &csc->csc_sc;
+	struct cardbus_devfunc *ct = csc->csc_ct;
+	int s;
+
+	s = splvm();
+
+	sc->sc_pm_reg[0] = Cardbus_conf_read(ct, csc->csc_tag, APO_IDECONF(sc));
+	/* APO_DATATIM(sc) includes APO_UDMA(sc) */
+	sc->sc_pm_reg[1] = Cardbus_conf_read(ct, csc->csc_tag, APO_DATATIM(sc));
+	sc->sc_pm_reg[2] = Cardbus_conf_read(ct, csc->csc_tag, APO_CTLMISC(sc));
+	sc->sc_pm_reg[3] = Cardbus_conf_read(ct, csc->csc_tag, APO_MISCTIM(sc));
+
+	splx(s);
+
+	return true;
+}
+
+static bool
+viaide_cardbus_resume(device_t dv, const pmf_qual_t *qual)
+{
+	struct viaide_cardbus_softc *csc = device_private(dv);
+	struct pciide_softc *sc = &csc->csc_sc;
+	struct cardbus_devfunc *ct = csc->csc_ct;
+	int s;
+
+	s = splvm();
+
+	Cardbus_conf_write(ct, csc->csc_tag, APO_IDECONF(sc), sc->sc_pm_reg[0]);
+	Cardbus_conf_write(ct, csc->csc_tag, APO_DATATIM(sc), sc->sc_pm_reg[1]);
+	Cardbus_conf_write(ct, csc->csc_tag, APO_CTLMISC(sc), sc->sc_pm_reg[2]);
+	Cardbus_conf_write(ct, csc->csc_tag, APO_MISCTIM(sc), sc->sc_pm_reg[3]);
+
+	splx(s);
+
+	return true;
+}
diff --git a/sys/dev/ic/vt6421.c b/sys/dev/ic/vt6421.c
new file mode 100644
index 000000000000..4da75497fdf2
--- /dev/null
+++ b/sys/dev/ic/vt6421.c
@@ -0,0 +1,191 @@
+/*	$NetBSD$	*/
+
+/*-
+ * Copyright (c) 2026 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+ 
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pciidereg.h>
+#include <dev/pci/pciidevar.h>
+#include <dev/pci/pciide_apollo_reg.h>
+
+#include "vt6421var.h"
+
+void
+vt6421_mapreg_dma(struct pciide_softc *sc, bus_dma_tag_t sc_dmat)
+{
+	struct pciide_channel *pc;
+	int chan, reg;
+	bus_size_t size;
+
+	sc->sc_dmat = sc_dmat;
+	if (sc->sc_dma_ok == 0) {
+		aprint_verbose(", but unused (couldn't map registers)");
+	} else {
+		sc->sc_wdcdev.dma_arg = sc;
+		sc->sc_wdcdev.dma_init = pciide_dma_init;
+		sc->sc_wdcdev.dma_start = pciide_dma_start;
+		sc->sc_wdcdev.dma_finish = pciide_dma_finish;
+	}
+
+	if (device_cfdata(sc->sc_wdcdev.sc_atac.atac_dev)->cf_flags &
+	    PCIIDE_OPTIONS_NODMA) {
+		aprint_verbose(
+		    ", but unused (forced off by config file)");
+		sc->sc_dma_ok = 0;
+	}
+
+	if (sc->sc_dma_ok == 0)
+		return;
+
+	for (chan = 0; chan < 4; chan++) {
+		pc = &sc->pciide_channels[chan];
+		for (reg = 0; reg < IDEDMA_NREGS; reg++) {
+			size = 4;
+			if (size > (IDEDMA_SCH_OFFSET - reg))
+				size = IDEDMA_SCH_OFFSET - reg;
+			if (bus_space_subregion(sc->sc_dma_iot, sc->sc_dma_ioh,
+			    IDEDMA_SCH_OFFSET * chan + reg, size,
+			    &pc->dma_iohs[reg]) != 0) {
+				sc->sc_dma_ok = 0;
+				aprint_verbose(", but can't subregion offset "
+				               "%d size %lu",
+					       reg, (u_long)size);
+				return;
+			}
+		}
+	}
+}
+
+static int
+via_vt6421_chansetup(struct pciide_softc *sc, int channel)
+{
+	struct pciide_channel *cp = &sc->pciide_channels[channel];
+
+	sc->wdc_chanarray[channel] = &cp->ata_channel;
+
+	cp->ata_channel.ch_channel = channel;
+	cp->ata_channel.ch_atac = &sc->sc_wdcdev.sc_atac;
+
+	return 1;
+}
+
+void
+vt6421_chip_map(struct pciide_softc *sc, struct vt6421_chan_handler *chan_handler)
+{
+	struct pciide_channel *cp;
+	struct ata_channel *wdc_cp;
+	struct wdc_regs *wdr;
+	int channel;
+	int i;
+
+	sc->sc_apo_regbase = APO_VIA_VT6421_REGBASE;
+
+	sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_DATA16 | ATAC_CAP_DATA32;
+	sc->sc_wdcdev.sc_atac.atac_pio_cap = 4;
+	if (sc->sc_dma_ok) {
+		sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_DMA | ATAC_CAP_UDMA;
+		sc->sc_wdcdev.irqack = pciide_irqack;
+		sc->sc_wdcdev.sc_atac.atac_dma_cap = 2;
+		sc->sc_wdcdev.sc_atac.atac_udma_cap = 6;
+	}
+	sc->sc_wdcdev.sc_atac.atac_set_modes = sata_setup_channel;
+
+	sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray;
+	sc->sc_wdcdev.sc_atac.atac_nchannels = VT6421_NCHANNELS;
+	sc->sc_wdcdev.wdc_maxdrives = 2;
+
+	wdc_allocate_regs(&sc->sc_wdcdev);
+
+	for (channel = 0; channel < sc->sc_wdcdev.sc_atac.atac_nchannels;
+	     channel++) {
+		cp = &sc->pciide_channels[channel];
+		if (via_vt6421_chansetup(sc, channel) == 0)
+			continue;
+		wdc_cp = &cp->ata_channel;
+		wdr = CHAN_TO_WDC_REGS(wdc_cp);
+
+		wdr->sata_iot = sc->sc_ba5_st;
+		wdr->sata_baseioh = sc->sc_ba5_sh;
+		if (bus_space_subregion(wdr->sata_iot, wdr->sata_baseioh,
+		    (wdc_cp->ch_channel << 6) + 0x0, 4,
+		    &wdr->sata_status) != 0) {
+			aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev,
+			    "couldn't map channel %d sata_status regs\n",
+			    wdc_cp->ch_channel);
+			continue;
+		}
+		if (bus_space_subregion(wdr->sata_iot, wdr->sata_baseioh,
+		    (wdc_cp->ch_channel << 6) + 0x4, 4,
+		    &wdr->sata_error) != 0) {
+			aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev,
+			    "couldn't map channel %d sata_error regs\n",
+			    wdc_cp->ch_channel);
+			continue;
+		}
+		if (bus_space_subregion(wdr->sata_iot, wdr->sata_baseioh,
+		    (wdc_cp->ch_channel << 6) + 0x8, 4,
+		    &wdr->sata_control) != 0) {
+			aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev,
+			    "couldn't map channel %d sata_control regs\n",
+			    wdc_cp->ch_channel);
+			continue;
+		}
+		
+
+		wdr->cmd_iot = chan_handler[channel].sc_cmd_st;
+		wdr->cmd_baseioh = chan_handler[channel].sc_cmd_sh;
+		wdr->cmd_ios = chan_handler[channel].sc_cmd_ios;
+
+		wdr->ctl_iot = wdr->cmd_iot;
+		for (i = 0; i < WDC_NREG; i++) {
+			if (bus_space_subregion(wdr->cmd_iot,
+			    wdr->cmd_baseioh, i, i == 0 ? 4 : 1,
+			    &wdr->cmd_iohs[i]) != 0) {
+				aprint_error_dev(
+				    sc->sc_wdcdev.sc_atac.atac_dev,
+				    "couldn't subregion channel %d "
+				    "cmd regs\n", channel);
+				return;
+			}
+		}
+		if (bus_space_subregion(wdr->cmd_iot, wdr->cmd_baseioh,
+		    WDC_NREG + 2, 1,  &wdr->ctl_ioh) != 0) {
+			aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev,
+			    "couldn't map channel %d ctl regs\n", channel);
+			return;
+		}
+		wdc_init_shadow_regs(wdr);
+		wdr->data32iot = wdr->cmd_iot;
+		wdr->data32ioh = wdr->cmd_iohs[wd_data];
+		wdcattach(wdc_cp);
+	}
+}
\ No newline at end of file
diff --git a/sys/dev/ic/vt6421var.h b/sys/dev/ic/vt6421var.h
new file mode 100644
index 000000000000..f33bd0523a6e
--- /dev/null
+++ b/sys/dev/ic/vt6421var.h
@@ -0,0 +1,46 @@
+/*	$NetBSD$	*/
+
+/*-
+ * Copyright (c) 2026 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+ 
+#ifndef _IC_VT6421_H_
+#define _IC_VT6421_H_
+
+#include <dev/pci/pciidevar.h>
+
+#define	VT6421_NCHANNELS	3
+
+struct vt6421_chan_handler {
+	bus_space_tag_t sc_cmd_st;
+	bus_space_handle_t sc_cmd_sh;
+	bus_size_t sc_cmd_ios;
+};
+
+void vt6421_mapreg_dma(struct pciide_softc *, bus_dma_tag_t);
+
+void vt6421_chip_map(struct pciide_softc *, struct vt6421_chan_handler *);
+
+#endif
\ No newline at end of file
diff --git a/sys/dev/pci/files.pci b/sys/dev/pci/files.pci
index d098b5c04783..e7e2cf1fb2ab 100644
--- a/sys/dev/pci/files.pci
+++ b/sys/dev/pci/files.pci
@@ -355,6 +355,7 @@ file	dev/pci/slide.c		slide
 device	viaide: ata, ata_dma, ata_udma, pciide_common, wdc_common, sata
 attach	viaide at pci
 file	dev/pci/viaide.c	viaide
+file	dev/ic/vt6421.c		viaide
 
 # STMicroelectronics STPC IDE controllers
 device	stpcide: ata, ata_dma, ata_udma, pciide_common, wdc_common
diff --git a/sys/dev/pci/viaide.c b/sys/dev/pci/viaide.c
index d5e0ccd4b95e..974ae5871696 100644
--- a/sys/dev/pci/viaide.c
+++ b/sys/dev/pci/viaide.c
@@ -37,6 +37,8 @@ __KERNEL_RCSID(0, "$NetBSD: viaide.c,v 1.108 2026/07/06 17:40:42 andvar Exp $");
 #include <dev/pci/pciidevar.h>
 #include <dev/pci/pciide_apollo_reg.h>
 
+#include <dev/ic/vt6421var.h>
+
 static int	via_pcib_match(const struct pci_attach_args *);
 static void	via_chip_map(struct pciide_softc *,
 		    const struct pci_attach_args *);
@@ -1130,80 +1132,16 @@ via_sata_chip_map_7(struct pciide_softc *sc, const struct pci_attach_args *pa)
 	via_sata_chip_map(sc, pa, 7);
 }
 
-static void
-via_vt6421_mapreg_dma(struct pciide_softc *sc, const struct pci_attach_args *pa)
-{
-	struct pciide_channel *pc;
-	int chan, reg;
-	bus_size_t size;
-
-	sc->sc_dma_ok = (pci_mapreg_map(pa, PCIIDE_REG_BUS_MASTER_DMA,
-	    PCI_MAPREG_TYPE_IO, 0, &sc->sc_dma_iot, &sc->sc_dma_ioh,
-	    NULL, &sc->sc_dma_ios) == 0);
-	sc->sc_dmat = pa->pa_dmat;
-	if (sc->sc_dma_ok == 0) {
-		aprint_verbose(", but unused (couldn't map registers)");
-	} else {
-		sc->sc_wdcdev.dma_arg = sc;
-		sc->sc_wdcdev.dma_init = pciide_dma_init;
-		sc->sc_wdcdev.dma_start = pciide_dma_start;
-		sc->sc_wdcdev.dma_finish = pciide_dma_finish;
-	}
-
-	if (device_cfdata(sc->sc_wdcdev.sc_atac.atac_dev)->cf_flags &
-	    PCIIDE_OPTIONS_NODMA) {
-		aprint_verbose(
-		    ", but unused (forced off by config file)");
-		sc->sc_dma_ok = 0;
-	}
-
-	if (sc->sc_dma_ok == 0)
-		return;
-
-	for (chan = 0; chan < 4; chan++) {
-		pc = &sc->pciide_channels[chan];
-		for (reg = 0; reg < IDEDMA_NREGS; reg++) {
-			size = 4;
-			if (size > (IDEDMA_SCH_OFFSET - reg))
-				size = IDEDMA_SCH_OFFSET - reg;
-			if (bus_space_subregion(sc->sc_dma_iot, sc->sc_dma_ioh,
-			    IDEDMA_SCH_OFFSET * chan + reg, size,
-			    &pc->dma_iohs[reg]) != 0) {
-				sc->sc_dma_ok = 0;
-				aprint_verbose(", but can't subregion offset "
-				               "%d size %lu",
-					       reg, (u_long)size);
-				return;
-			}
-		}
-	}
-}
-
-static int
-via_vt6421_chansetup(struct pciide_softc *sc, int channel)
-{
-	struct pciide_channel *cp = &sc->pciide_channels[channel];
-
-	sc->wdc_chanarray[channel] = &cp->ata_channel;
-
-	cp->ata_channel.ch_channel = channel;
-	cp->ata_channel.ch_atac = &sc->sc_wdcdev.sc_atac;
-
-	return 1;
-}
-
 static void
 via_sata_chip_map_new(struct pciide_softc *sc,
     const struct pci_attach_args *pa)
 {
-	struct pciide_channel *cp;
-	struct ata_channel *wdc_cp;
-	struct wdc_regs *wdr;
 	int channel;
 	pci_intr_handle_t intrhandle;
 	const char *intrstr;
-	int i;
 	char intrbuf[PCI_INTRSTR_LEN];
+	struct vt6421_chan_handler chan_handlers[VT6421_NCHANNELS];
+	struct vt6421_chan_handler *vch;
 
 	if (pciide_chipen(sc, pa) == 0)
 		return;
@@ -1216,31 +1154,15 @@ via_sata_chip_map_new(struct pciide_softc *sc,
 		    "couldn't map SATA regs\n");
 	}
 
+	sc->sc_dma_ok = (pci_mapreg_map(pa, PCIIDE_REG_BUS_MASTER_DMA,
+	    PCI_MAPREG_TYPE_IO, 0, &sc->sc_dma_iot, &sc->sc_dma_ioh,
+	    NULL, &sc->sc_dma_ios) == 0);
+
 	aprint_verbose_dev(sc->sc_wdcdev.sc_atac.atac_dev,
 	    "bus-master DMA support present");
-	via_vt6421_mapreg_dma(sc, pa);
+	vt6421_mapreg_dma(sc, pa->pa_dmat);
 	aprint_verbose("\n");
-
-	sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_DATA16 | ATAC_CAP_DATA32;
-	sc->sc_wdcdev.sc_atac.atac_pio_cap = 4;
-	if (sc->sc_dma_ok) {
-		sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_DMA | ATAC_CAP_UDMA;
-		sc->sc_wdcdev.irqack = pciide_irqack;
-		sc->sc_wdcdev.sc_atac.atac_dma_cap = 2;
-		sc->sc_wdcdev.sc_atac.atac_udma_cap = 6;
-	}
-	sc->sc_wdcdev.sc_atac.atac_set_modes = sata_setup_channel;
-
-	sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray;
-	sc->sc_wdcdev.sc_atac.atac_nchannels = 3;
-	sc->sc_wdcdev.wdc_maxdrives = 2;
-
-	if (PCI_CLASS(pa->pa_class) == PCI_CLASS_MASS_STORAGE &&
-	    PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_MASS_STORAGE_RAID)
-		sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_RAID;
-
-	wdc_allocate_regs(&sc->sc_wdcdev);
-
+	
 	if (pci_intr_map(pa, &intrhandle) != 0) {
 		aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev,
 		    "couldn't map native-PCI interrupt\n");
@@ -1258,72 +1180,17 @@ via_sata_chip_map_new(struct pciide_softc *sc,
 		aprint_error("\n");
 		return;
 	}
-	aprint_normal_dev(sc->sc_wdcdev.sc_atac.atac_dev,
-	    "using %s for native-PCI interrupt\n",
-	    intrstr ? intrstr : "unknown interrupt");
-
-	for (channel = 0; channel < sc->sc_wdcdev.sc_atac.atac_nchannels;
-	     channel++) {
-		cp = &sc->pciide_channels[channel];
-		if (via_vt6421_chansetup(sc, channel) == 0)
-			continue;
-		wdc_cp = &cp->ata_channel;
-		wdr = CHAN_TO_WDC_REGS(wdc_cp);
-
-		wdr->sata_iot = sc->sc_ba5_st;
-		wdr->sata_baseioh = sc->sc_ba5_sh;
-		if (bus_space_subregion(wdr->sata_iot, wdr->sata_baseioh,
-		    (wdc_cp->ch_channel << 6) + 0x0, 4,
-		    &wdr->sata_status) != 0) {
-			aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev,
-			    "couldn't map channel %d sata_status regs\n",
-			    wdc_cp->ch_channel);
-			continue;
-		}
-		if (bus_space_subregion(wdr->sata_iot, wdr->sata_baseioh,
-		    (wdc_cp->ch_channel << 6) + 0x4, 4,
-		    &wdr->sata_error) != 0) {
-			aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev,
-			    "couldn't map channel %d sata_error regs\n",
-			    wdc_cp->ch_channel);
-			continue;
-		}
-		if (bus_space_subregion(wdr->sata_iot, wdr->sata_baseioh,
-		    (wdc_cp->ch_channel << 6) + 0x8, 4,
-		    &wdr->sata_control) != 0) {
-			aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev,
-			    "couldn't map channel %d sata_control regs\n",
-			    wdc_cp->ch_channel);
-			continue;
-		}
+	
+	if (PCI_CLASS(pa->pa_class) == PCI_CLASS_MASS_STORAGE &&
+	    PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_MASS_STORAGE_RAID)
+		sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_RAID;
 
-		if (pci_mapreg_map(pa, PCI_BAR(wdc_cp->ch_channel),
-		    PCI_MAPREG_TYPE_IO, 0, &wdr->cmd_iot, &wdr->cmd_baseioh,
-		    NULL, &wdr->cmd_ios) != 0) {
+	for (channel = 0; channel < VT6421_NCHANNELS; channel++) {
+		vch = &chan_handlers[channel];
+		if (pci_mapreg_map(pa, PCI_BAR(channel), PCI_MAPREG_TYPE_IO, 0,
+		    &vch->sc_cmd_st, &vch->sc_cmd_sh, NULL, &vch->sc_cmd_ios) != 0)
 			aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev,
 			    "couldn't map channel %d regs\n", channel);
-		}
-		wdr->ctl_iot = wdr->cmd_iot;
-		for (i = 0; i < WDC_NREG; i++) {
-			if (bus_space_subregion(wdr->cmd_iot,
-			    wdr->cmd_baseioh, i, i == 0 ? 4 : 1,
-			    &wdr->cmd_iohs[i]) != 0) {
-				aprint_error_dev(
-				    sc->sc_wdcdev.sc_atac.atac_dev,
-				    "couldn't subregion channel %d "
-				    "cmd regs\n", channel);
-				return;
-			}
-		}
-		if (bus_space_subregion(wdr->cmd_iot, wdr->cmd_baseioh,
-		    WDC_NREG + 2, 1,  &wdr->ctl_ioh) != 0) {
-			aprint_error_dev(sc->sc_wdcdev.sc_atac.atac_dev,
-			    "couldn't map channel %d ctl regs\n", channel);
-			return;
-		}
-		wdc_init_shadow_regs(wdr);
-		wdr->data32iot = wdr->cmd_iot;
-		wdr->data32ioh = wdr->cmd_iohs[wd_data];
-		wdcattach(wdc_cp);
 	}
+	vt6421_chip_map(sc, chan_handlers);
 }


Home | Main Index | Thread Index | Old Index