summaryrefslogtreecommitdiffstats
path: root/sys/dev/ata
diff options
context:
space:
mode:
authorsos <sos@FreeBSD.org>2008-10-09 12:56:57 +0000
committersos <sos@FreeBSD.org>2008-10-09 12:56:57 +0000
commit62bed477fa71057a850f515079a63e1892c9d0d4 (patch)
treeb090c7dee8dc1c6dcacd47c9e8757f41ec38a22a /sys/dev/ata
parentf39dcb8b690765dfcdf2a642c8a11e1ef70341cc (diff)
downloadFreeBSD-src-62bed477fa71057a850f515079a63e1892c9d0d4.zip
FreeBSD-src-62bed477fa71057a850f515079a63e1892c9d0d4.tar.gz
This is the roumored ATA modulerisation works, and it needs a little explanation.
If you just config KERNEL as usual there should be no apparent changes, you'll get all chipset support code compiled in. However there is now a way to only compile in code for chipsets needed on a pr vendor basis. ATA now has the following "device" entries: atacore: ATA core functionality, always needed for any ATA setup atacard: CARDBUS support atacbus: PC98 cbus support ataisa: ISA bus support atapci: PCI bus support only generic chipset support. ataahci: AHCI support, also pulled in by some vendor modules. ataacard, ataacerlabs, ataadaptec, ataamd, ataati, atacenatek, atacypress, atacyrix, atahighpoint, ataintel, ataite, atajmicron, atamarvell, atamicron, atanational, atanetcell, atanvidia, atapromise, ataserverworks, atasiliconimage, atasis, atavia; Vendor support, ie atavia for VIA chipsets atadisk: ATA disk driver ataraid: ATA softraid driver atapicd: ATAPI cd/dvd driver atapifd: ATAPI floppy/flashdisk driver atapist: ATAPI tape driver atausb: ATA<>USB bridge atapicam: ATA<>CAM bridge This makes it possible to config a kernel with just VIA chipset support by having the following ATA lines in the kernel config file: device atacore device atapci device atavia And then you need the atadisk, atapicd etc lines in there just as usual. If you use ATA as modules loaded at boot there is few changes except the rename of the "ata" module to "atacore", things looks just as usual. However under atapci you now have a whole bunch of vendor specific drivers, that you can kldload individually depending on you needs. Drivers have the same names as used in the kernel config explained above.
Diffstat (limited to 'sys/dev/ata')
-rw-r--r--sys/dev/ata/ata-all.c42
-rw-r--r--sys/dev/ata/ata-all.h1
-rw-r--r--sys/dev/ata/ata-chipset.c6548
-rw-r--r--sys/dev/ata/ata-dma.c2
-rw-r--r--sys/dev/ata/ata-pci.c368
-rw-r--r--sys/dev/ata/ata-pci.h153
-rw-r--r--sys/dev/ata/ata-sata.c357
-rw-r--r--sys/dev/ata/chipsets/ata-acard.c285
-rw-r--r--sys/dev/ata/chipsets/ata-acerlabs.c307
-rw-r--r--sys/dev/ata/chipsets/ata-adaptec.c82
-rw-r--r--sys/dev/ata/chipsets/ata-ahci.c744
-rw-r--r--sys/dev/ata/chipsets/ata-amd.c149
-rw-r--r--sys/dev/ata/chipsets/ata-ati.c197
-rw-r--r--sys/dev/ata/chipsets/ata-cenatek.c98
-rw-r--r--sys/dev/ata/chipsets/ata-cypress.c121
-rw-r--r--sys/dev/ata/chipsets/ata-cyrix.c131
-rw-r--r--sys/dev/ata/chipsets/ata-highpoint.c234
-rw-r--r--sys/dev/ata/chipsets/ata-intel.c515
-rw-r--r--sys/dev/ata/chipsets/ata-ite.c247
-rw-r--r--sys/dev/ata/chipsets/ata-jmicron.c204
-rw-r--r--sys/dev/ata/chipsets/ata-marvell.c542
-rw-r--r--sys/dev/ata/chipsets/ata-micron.c101
-rw-r--r--sys/dev/ata/chipsets/ata-national.c133
-rw-r--r--sys/dev/ata/chipsets/ata-netcell.c115
-rw-r--r--sys/dev/ata/chipsets/ata-nvidia.c264
-rw-r--r--sys/dev/ata/chipsets/ata-promise.c1250
-rw-r--r--sys/dev/ata/chipsets/ata-serverworks.c332
-rw-r--r--sys/dev/ata/chipsets/ata-siliconimage.c890
-rw-r--r--sys/dev/ata/chipsets/ata-sis.c314
-rw-r--r--sys/dev/ata/chipsets/ata-via.c351
30 files changed, 8254 insertions, 6823 deletions
diff --git a/sys/dev/ata/ata-all.c b/sys/dev/ata/ata-all.c
index 8da8a10..38538c8 100644
--- a/sys/dev/ata/ata-all.c
+++ b/sys/dev/ata/ata-all.c
@@ -616,7 +616,6 @@ ata_getparam(struct ata_device *atadev, int init)
if (!error && (isprint(atadev->param.model[0]) ||
isprint(atadev->param.model[1]))) {
struct ata_params *atacap = &atadev->param;
- char buffer[64];
int16_t *ptr;
for (ptr = (int16_t *)atacap;
@@ -648,6 +647,8 @@ ata_getparam(struct ata_device *atadev, int init)
(atacap->hwres & ATA_CABLE_ID) ? "80":"40");
if (init) {
+ char buffer[64];
+
sprintf(buffer, "%.40s/%.8s", atacap->model, atacap->revision);
device_set_desc_copy(atadev->dev, buffer);
if ((atadev->param.config & ATA_PROTO_ATAPI) &&
@@ -677,8 +678,8 @@ int
ata_identify(device_t dev)
{
struct ata_channel *ch = device_get_softc(dev);
- struct ata_device *devices[ATA_PM];
- device_t childdevs[ATA_PM];
+ struct ata_device *atadev;
+ device_t child;
int i;
if (bootverbose)
@@ -688,33 +689,26 @@ ata_identify(device_t dev)
if (ch->devices & (((ATA_ATA_MASTER | ATA_ATAPI_MASTER) << i))) {
int unit = -1;
- if (!(devices[i] = malloc(sizeof(struct ata_device),
- M_ATA, M_NOWAIT | M_ZERO))) {
+ if (!(atadev = malloc(sizeof(struct ata_device),
+ M_ATA, M_NOWAIT | M_ZERO))) {
device_printf(dev, "out of memory\n");
return ENOMEM;
}
- devices[i]->unit = i;
+ atadev->unit = i;
#ifdef ATA_STATIC_ID
if (ch->devices & ((ATA_ATA_MASTER << i)))
unit = (device_get_unit(dev) << 1) + i;
#endif
- if (!(childdevs[i] = ata_add_child(dev, devices[i], unit))) {
- free(devices[i], M_ATA);
- devices[i]=NULL;
- }
- else {
- if (ata_getparam(devices[i], 1)) {
- device_delete_child(dev, childdevs[i]);
- free(devices[i], M_ATA);
- childdevs[i] = NULL;
- devices[i] = NULL;
+ if ((child = ata_add_child(dev, atadev, unit))) {
+ if (ata_getparam(atadev, 1)) {
+ device_delete_child(dev, child);
+ free(atadev, M_ATA);
}
}
+ else
+ free(atadev, M_ATA);
}
- devices[i] = NULL;
- childdevs[i] = NULL;
}
-
bus_generic_probe(dev);
bus_generic_attach(dev);
return 0;
@@ -895,6 +889,16 @@ ata_mode2str(int mode)
}
int
+ata_atapi(device_t dev)
+{
+ struct ata_channel *ch = device_get_softc(device_get_parent(dev));
+ struct ata_device *atadev = device_get_softc(dev);
+
+ return ((atadev->unit == ATA_MASTER && ch->devices & ATA_ATAPI_MASTER) ||
+ (atadev->unit == ATA_SLAVE && ch->devices & ATA_ATAPI_SLAVE));
+}
+
+int
ata_pmode(struct ata_params *ap)
{
if (ap->atavalid & ATA_FLAG_64_70) {
diff --git a/sys/dev/ata/ata-all.h b/sys/dev/ata/ata-all.h
index b2283b9..e941433 100644
--- a/sys/dev/ata/ata-all.h
+++ b/sys/dev/ata/ata-all.h
@@ -563,6 +563,7 @@ void ata_modify_if_48bit(struct ata_request *request);
void ata_udelay(int interval);
char *ata_unit2str(struct ata_device *atadev);
char *ata_mode2str(int mode);
+int ata_atapi(device_t dev);
int ata_pmode(struct ata_params *ap);
int ata_wmode(struct ata_params *ap);
int ata_umode(struct ata_params *ap);
diff --git a/sys/dev/ata/ata-chipset.c b/sys/dev/ata/ata-chipset.c
deleted file mode 100644
index c8eb52c..0000000
--- a/sys/dev/ata/ata-chipset.c
+++ /dev/null
@@ -1,6548 +0,0 @@
-/*-
- * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org>
- * 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,
- * without modification, immediately at the beginning of the file.
- * 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 AUTHOR ``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 AUTHOR 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>
-__FBSDID("$FreeBSD$");
-
-#include "opt_ata.h"
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/kernel.h>
-#include <sys/ata.h>
-#include <sys/bus.h>
-#include <sys/endian.h>
-#include <sys/malloc.h>
-#include <sys/lock.h>
-#include <sys/mutex.h>
-#include <sys/sema.h>
-#include <sys/taskqueue.h>
-#include <vm/uma.h>
-#include <machine/stdarg.h>
-#include <machine/resource.h>
-#include <machine/bus.h>
-#include <sys/rman.h>
-#include <dev/pci/pcivar.h>
-#include <dev/pci/pcireg.h>
-#include <dev/ata/ata-all.h>
-#include <dev/ata/ata-pci.h>
-#include <ata_if.h>
-
-/* local prototypes */
-/* ata-chipset.c */
-static int ata_generic_chipinit(device_t dev);
-static void ata_generic_intr(void *data);
-static void ata_generic_setmode(device_t dev, int mode);
-static void ata_sata_phy_check_events(device_t dev);
-static void ata_sata_phy_event(void *context, int dummy);
-static int ata_sata_phy_reset(device_t dev);
-static int ata_sata_connect(struct ata_channel *ch);
-static void ata_sata_setmode(device_t dev, int mode);
-static int ata_request2fis_h2d(struct ata_request *request, u_int8_t *fis);
-static int ata_ahci_chipinit(device_t dev);
-static int ata_ahci_ctlr_reset(device_t dev);
-static int ata_ahci_suspend(device_t dev);
-static int ata_ahci_allocate(device_t dev);
-static int ata_ahci_status(device_t dev);
-static int ata_ahci_begin_transaction(struct ata_request *request);
-static int ata_ahci_end_transaction(struct ata_request *request);
-static int ata_ahci_pm_read(device_t dev, int port, int reg, u_int32_t *result);
-static int ata_ahci_pm_write(device_t dev, int port, int reg, u_int32_t result);
-static u_int32_t ata_ahci_softreset(device_t dev, int port);
-static void ata_ahci_reset(device_t dev);
-static void ata_ahci_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error);
-static void ata_ahci_dmainit(device_t dev);
-static int ata_ahci_setup_fis(struct ata_ahci_cmd_tab *ctp, struct ata_request *request);
-static int ata_acard_chipinit(device_t dev);
-static int ata_acard_allocate(device_t dev);
-static int ata_acard_status(device_t dev);
-static void ata_acard_850_setmode(device_t dev, int mode);
-static void ata_acard_86X_setmode(device_t dev, int mode);
-static int ata_ali_chipinit(device_t dev);
-static int ata_ali_allocate(device_t dev);
-static int ata_ali_sata_allocate(device_t dev);
-static void ata_ali_reset(device_t dev);
-static void ata_ali_setmode(device_t dev, int mode);
-static int ata_amd_chipinit(device_t dev);
-static int ata_ati_chipinit(device_t dev);
-static void ata_ati_setmode(device_t dev, int mode);
-static int ata_cyrix_chipinit(device_t dev);
-static void ata_cyrix_setmode(device_t dev, int mode);
-static int ata_cypress_chipinit(device_t dev);
-static void ata_cypress_setmode(device_t dev, int mode);
-static int ata_highpoint_chipinit(device_t dev);
-static int ata_highpoint_allocate(device_t dev);
-static void ata_highpoint_setmode(device_t dev, int mode);
-static int ata_highpoint_check_80pin(device_t dev, int mode);
-static int ata_intel_chipinit(device_t dev);
-static int ata_intel_allocate(device_t dev);
-static void ata_intel_reset(device_t dev);
-static void ata_intel_old_setmode(device_t dev, int mode);
-static void ata_intel_new_setmode(device_t dev, int mode);
-static void ata_intel_sata_setmode(device_t dev, int mode);
-static int ata_intel_31244_allocate(device_t dev);
-static int ata_intel_31244_status(device_t dev);
-static void ata_intel_31244_tf_write(struct ata_request *request);
-static void ata_intel_31244_reset(device_t dev);
-static int ata_ite_chipinit(device_t dev);
-static void ata_ite_8213_setmode(device_t dev, int mode);
-static void ata_ite_821x_setmode(device_t dev, int mode);
-static int ata_jmicron_chipinit(device_t dev);
-static int ata_jmicron_allocate(device_t dev);
-static void ata_jmicron_reset(device_t dev);
-static void ata_jmicron_dmainit(device_t dev);
-static void ata_jmicron_setmode(device_t dev, int mode);
-static int ata_marvell_pata_chipinit(device_t dev);
-static int ata_marvell_pata_allocate(device_t dev);
-static void ata_marvell_pata_setmode(device_t dev, int mode);
-static int ata_marvell_edma_chipinit(device_t dev);
-static int ata_marvell_edma_allocate(device_t dev);
-static int ata_marvell_edma_status(device_t dev);
-static int ata_marvell_edma_begin_transaction(struct ata_request *request);
-static int ata_marvell_edma_end_transaction(struct ata_request *request);
-static void ata_marvell_edma_reset(device_t dev);
-static void ata_marvell_edma_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error);
-static void ata_marvell_edma_dmainit(device_t dev);
-static int ata_national_chipinit(device_t dev);
-static void ata_national_setmode(device_t dev, int mode);
-static int ata_netcell_chipinit(device_t dev);
-static int ata_netcell_allocate(device_t dev);
-static int ata_nvidia_chipinit(device_t dev);
-static int ata_nvidia_allocate(device_t dev);
-static int ata_nvidia_status(device_t dev);
-static void ata_nvidia_reset(device_t dev);
-static int ata_promise_chipinit(device_t dev);
-static int ata_promise_allocate(device_t dev);
-static int ata_promise_status(device_t dev);
-static int ata_promise_dmastart(struct ata_request *request);
-static int ata_promise_dmastop(struct ata_request *request);
-static void ata_promise_dmareset(device_t dev);
-static void ata_promise_dmainit(device_t dev);
-static void ata_promise_setmode(device_t dev, int mode);
-static int ata_promise_tx2_allocate(device_t dev);
-static int ata_promise_tx2_status(device_t dev);
-static int ata_promise_mio_allocate(device_t dev);
-static void ata_promise_mio_intr(void *data);
-static int ata_promise_mio_status(device_t dev);
-static int ata_promise_mio_command(struct ata_request *request);
-static void ata_promise_mio_reset(device_t dev);
-static int ata_promise_mio_pm_read(device_t dev, int port, int reg, u_int32_t *result);
-static int ata_promise_mio_pm_write(device_t dev, int port, int reg, u_int32_t result);
-static u_int32_t ata_promise_mio_softreset(device_t dev, int port);
-static void ata_promise_mio_dmainit(device_t dev);
-static void ata_promise_mio_setprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error);
-static void ata_promise_mio_setmode(device_t dev, int mode);
-static void ata_promise_sx4_intr(void *data);
-static int ata_promise_sx4_command(struct ata_request *request);
-static int ata_promise_apkt(u_int8_t *bytep, struct ata_request *request);
-static void ata_promise_queue_hpkt(struct ata_pci_controller *ctlr, u_int32_t hpkt);
-static void ata_promise_next_hpkt(struct ata_pci_controller *ctlr);
-static int ata_serverworks_chipinit(device_t dev);
-static int ata_serverworks_allocate(device_t dev);
-static void ata_serverworks_tf_read(struct ata_request *request);
-static void ata_serverworks_tf_write(struct ata_request *request);
-static void ata_serverworks_setmode(device_t dev, int mode);
-static int ata_sii_chipinit(device_t dev);
-static int ata_cmd_allocate(device_t dev);
-static int ata_cmd_status(device_t dev);
-static void ata_cmd_setmode(device_t dev, int mode);
-static int ata_sii_allocate(device_t dev);
-static int ata_sii_status(device_t dev);
-static void ata_sii_reset(device_t dev);
-static void ata_sii_setmode(device_t dev, int mode);
-static int ata_siiprb_allocate(device_t dev);
-static int ata_siiprb_status(device_t dev);
-static int ata_siiprb_begin_transaction(struct ata_request *request);
-static int ata_siiprb_end_transaction(struct ata_request *request);
-static int ata_siiprb_pm_read(device_t dev, int port, int reg, u_int32_t *result);
-static int ata_siiprb_pm_write(device_t dev, int port, int reg, u_int32_t result);
-static u_int32_t ata_siiprb_softreset(device_t dev, int port);
-static void ata_siiprb_reset(device_t dev);
-static void ata_siiprb_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error);
-static void ata_siiprb_dmainit(device_t dev);
-static int ata_sis_chipinit(device_t dev);
-static int ata_sis_allocate(device_t dev);
-static void ata_sis_reset(device_t dev);
-static void ata_sis_setmode(device_t dev, int mode);
-static int ata_via_chipinit(device_t dev);
-static int ata_via_allocate(device_t dev);
-static void ata_via_reset(device_t dev);
-static void ata_via_setmode(device_t dev, int mode);
-static void ata_via_southbridge_fixup(device_t dev);
-static void ata_via_family_setmode(device_t dev, int mode);
-static void ata_set_desc(device_t dev);
-static struct ata_chip_id *ata_match_chip(device_t dev, struct ata_chip_id *index);
-static struct ata_chip_id *ata_find_chip(device_t dev, struct ata_chip_id *index, int slot);
-static int ata_setup_interrupt(device_t dev);
-static int ata_serialize(device_t dev, int flags);
-static void ata_print_cable(device_t dev, u_int8_t *who);
-static int ata_atapi(device_t dev);
-static int ata_check_80pin(device_t dev, int mode);
-static int ata_mode2idx(int mode);
-
-
-/*
- * generic ATA support functions
- */
-int
-ata_generic_ident(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
- char buffer[64];
-
- sprintf(buffer, "%s ATA controller", ata_pcivendor2str(dev));
- device_set_desc_copy(dev, buffer);
- ctlr->chipinit = ata_generic_chipinit;
- return 0;
-}
-
-static int
-ata_generic_chipinit(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
-
- if (ata_setup_interrupt(dev))
- return ENXIO;
- ctlr->setmode = ata_generic_setmode;
- return 0;
-}
-
-static void
-ata_generic_intr(void *data)
-{
- struct ata_pci_controller *ctlr = data;
- struct ata_channel *ch;
- int unit;
-
- for (unit = 0; unit < ctlr->channels; unit++) {
- if ((ch = ctlr->interrupt[unit].argument))
- ctlr->interrupt[unit].function(ch);
- }
-}
-
-static void
-ata_generic_setmode(device_t dev, int mode)
-{
- struct ata_device *atadev = device_get_softc(dev);
-
- mode = ata_limit_mode(dev, mode, ATA_UDMA2);
- mode = ata_check_80pin(dev, mode);
- if (!ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode))
- atadev->mode = mode;
-}
-
-
-/*
- * SATA support functions
- */
-static void
-ata_sata_phy_check_events(device_t dev)
-{
- struct ata_channel *ch = device_get_softc(dev);
- u_int32_t error = ATA_IDX_INL(ch, ATA_SERROR);
-
- /* clear error bits/interrupt */
- ATA_IDX_OUTL(ch, ATA_SERROR, error);
-
- /* do we have any events flagged ? */
- if (error) {
- struct ata_connect_task *tp;
- u_int32_t status = ATA_IDX_INL(ch, ATA_SSTATUS);
-
- /* if we have a connection event deal with it */
- if ((error & ATA_SE_PHY_CHANGED) &&
- (tp = (struct ata_connect_task *)
- malloc(sizeof(struct ata_connect_task),
- M_ATA, M_NOWAIT | M_ZERO))) {
-
- if (((status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN1) ||
- ((status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN2)) {
- if (bootverbose)
- device_printf(dev, "CONNECT requested\n");
- tp->action = ATA_C_ATTACH;
- }
- else {
- if (bootverbose)
- device_printf(dev, "DISCONNECT requested\n");
- tp->action = ATA_C_DETACH;
- }
- tp->dev = dev;
- TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp);
- taskqueue_enqueue(taskqueue_thread, &tp->task);
- }
- }
-}
-
-static void
-ata_sata_phy_event(void *context, int dummy)
-{
- struct ata_connect_task *tp = (struct ata_connect_task *)context;
- struct ata_channel *ch = device_get_softc(tp->dev);
- device_t *children;
- int nchildren, i;
-
- mtx_lock(&Giant); /* newbus suckage it needs Giant */
- if (tp->action == ATA_C_ATTACH) {
- if (bootverbose)
- device_printf(tp->dev, "CONNECTED\n");
- ATA_RESET(tp->dev);
- ata_identify(tp->dev);
- }
- if (tp->action == ATA_C_DETACH) {
- if (!device_get_children(tp->dev, &children, &nchildren)) {
- for (i = 0; i < nchildren; i++)
- if (children[i])
- device_delete_child(tp->dev, children[i]);
- free(children, M_TEMP);
- }
- mtx_lock(&ch->state_mtx);
- ch->state = ATA_IDLE;
- mtx_unlock(&ch->state_mtx);
- if (bootverbose)
- device_printf(tp->dev, "DISCONNECTED\n");
- }
- mtx_unlock(&Giant); /* suckage code dealt with, release Giant */
- free(tp, M_ATA);
-}
-
-static int
-ata_sata_phy_reset(device_t dev)
-{
- struct ata_channel *ch = device_get_softc(dev);
- int loop, retry;
-
- if ((ATA_IDX_INL(ch, ATA_SCONTROL) & ATA_SC_DET_MASK) == ATA_SC_DET_IDLE)
- return ata_sata_connect(ch);
-
- for (retry = 0; retry < 10; retry++) {
- for (loop = 0; loop < 10; loop++) {
- ATA_IDX_OUTL(ch, ATA_SCONTROL, ATA_SC_DET_RESET);
- ata_udelay(100);
- if ((ATA_IDX_INL(ch, ATA_SCONTROL) & ATA_SC_DET_MASK) ==
- ATA_SC_DET_RESET)
- break;
- }
- ata_udelay(5000);
- for (loop = 0; loop < 10; loop++) {
- ATA_IDX_OUTL(ch, ATA_SCONTROL, ATA_SC_DET_IDLE |
- ATA_SC_IPM_DIS_PARTIAL |
- ATA_SC_IPM_DIS_SLUMBER);
- ata_udelay(100);
- if ((ATA_IDX_INL(ch, ATA_SCONTROL) & ATA_SC_DET_MASK) == 0)
- return ata_sata_connect(ch);
- }
- }
- return 0;
-}
-
-static int
-ata_sata_connect(struct ata_channel *ch)
-{
- u_int32_t status;
- int timeout;
-
- /* wait up to 1 second for "connect well" */
- for (timeout = 0; timeout < 100 ; timeout++) {
- status = ATA_IDX_INL(ch, ATA_SSTATUS);
- if ((status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN1 ||
- (status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN2)
- break;
- ata_udelay(10000);
- }
- if (timeout >= 100) {
- if (bootverbose)
- device_printf(ch->dev, "SATA connect status=%08x\n", status);
- return 0;
- }
- if (bootverbose)
- device_printf(ch->dev, "SATA connect time=%dms\n", timeout * 10);
-
- /* clear SATA error register */
- ATA_IDX_OUTL(ch, ATA_SERROR, ATA_IDX_INL(ch, ATA_SERROR));
-
- return 1;
-}
-
-static void
-ata_sata_setmode(device_t dev, int mode)
-{
- struct ata_device *atadev = device_get_softc(dev);
-
- /*
- * if we detect that the device isn't a real SATA device we limit
- * the transfer mode to UDMA5/ATA100.
- * this works around the problems some devices has with the
- * Marvell 88SX8030 SATA->PATA converters and UDMA6/ATA133.
- */
- if (atadev->param.satacapabilities != 0x0000 &&
- atadev->param.satacapabilities != 0xffff) {
- struct ata_channel *ch = device_get_softc(device_get_parent(dev));
-
- /* on some drives we need to set the transfer mode */
- ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0,
- ata_limit_mode(dev, mode, ATA_UDMA6));
-
- /* query SATA STATUS for the speed */
- if (ch->r_io[ATA_SSTATUS].res &&
- ((ATA_IDX_INL(ch, ATA_SSTATUS) & ATA_SS_CONWELL_MASK) ==
- ATA_SS_CONWELL_GEN2))
- atadev->mode = ATA_SA300;
- else
- atadev->mode = ATA_SA150;
- }
- else {
- mode = ata_limit_mode(dev, mode, ATA_UDMA5);
- if (!ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode))
- atadev->mode = mode;
- }
-}
-
-static void
-ata_pm_identify(device_t dev)
-{
- struct ata_channel *ch = device_get_softc(dev);
- u_int32_t pm_chipid, pm_revision, pm_ports;
- int port;
-
- /* get PM vendor & product data */
- if (ch->hw.pm_read(dev, ATA_PM, 0, &pm_chipid)) {
- device_printf(dev, "error getting PM vendor data\n");
- return;
- }
-
- /* get PM revision data */
- if (ch->hw.pm_read(dev, ATA_PM, 1, &pm_revision)) {
- device_printf(dev, "error getting PM revison data\n");
- return;
- }
-
- /* get number of HW ports on the PM */
- if (ch->hw.pm_read(dev, ATA_PM, 2, &pm_ports)) {
- device_printf(dev, "error getting PM port info\n");
- return;
- }
- pm_ports &= 0x0000000f;
-
- /* chip specific quirks */
- switch (pm_chipid) {
- case 0x37261095:
- /* Some of these bogusly reports 6 ports */
- pm_ports = 5;
- device_printf(dev, "SiI 3726 r%x Portmultiplier with %d ports\n",
- pm_revision, pm_ports);
- break;
-
- default:
- device_printf(dev, "Portmultiplier (id=%08x rev=%x) with %d ports\n",
- pm_chipid, pm_revision, pm_ports);
- }
-
- /* inform dma.alloc() about needed DMA slots */
- ch->dma.dma_slots = pm_ports;
-
- /* reset all ports and register if anything connected */
- for (port=0; port < pm_ports; port++) {
- u_int32_t signature, status;
- int timeout;
-
- if (ch->hw.pm_write(dev, port, 2, ATA_SC_DET_RESET)) {
- device_printf(dev, "p%d: writing ATA_SC_DET_RESET failed\n", port);
- continue;
- }
-
- ata_udelay(5000);
-
- if (ch->hw.pm_write(dev, port, 2, ATA_SC_DET_IDLE)) {
- device_printf(dev, "p%d: writing ATA_SC_DET_idle failed\n", port);
- continue;
- }
-
- ata_udelay(5000);
-
- /* wait up to 1 second for "connect well" */
- for (timeout = 0; timeout < 100 ; timeout++) {
- ch->hw.pm_read(dev, port, 0, &status);
- if ((status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN1 ||
- (status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN2)
- break;
- ata_udelay(10000);
- }
- if (timeout >= 100) {
- if (bootverbose)
- device_printf(dev, "p%d: connect status=%08x\n", port, status);
- continue;
- }
- if (bootverbose)
- device_printf(dev, "p%d: connect time %dms\n", port, timeout * 10);
-
- /* clear SERROR register */
- ch->hw.pm_write(dev, port, 1, 0xffffffff);
-
- signature = ch->hw.softreset(dev, port);
-
- if (bootverbose)
- device_printf(dev, "p%d: SIGNATURE=%08x\n", port, signature);
-
- /* figure out whats there */
- switch (signature) {
- case 0x00000101:
- ch->devices |= (ATA_ATA_MASTER << port);
- continue;
- case 0xeb140101:
- ch->devices |= (ATA_ATAPI_MASTER << port);
- continue;
- }
- }
-}
-
-static int
-ata_request2fis_h2d(struct ata_request *request, u_int8_t *fis)
-{
- struct ata_device *atadev = device_get_softc(request->dev);
-
- if (request->flags & ATA_R_ATAPI) {
- fis[0] = 0x27; /* host to device */
- fis[1] = 0x80 | (atadev->unit & 0x0f);
- fis[2] = ATA_PACKET_CMD;
- if (request->flags & (ATA_R_READ | ATA_R_WRITE))
- fis[3] = ATA_F_DMA;
- else {
- fis[5] = request->transfersize;
- fis[6] = request->transfersize >> 8;
- }
- fis[7] = ATA_D_LBA;
- fis[15] = ATA_A_4BIT;
- return 20;
- }
- else {
- ata_modify_if_48bit(request);
- fis[0] = 0x27; /* host to device */
- fis[1] = 0x80 | (atadev->unit & 0x0f);
- fis[2] = request->u.ata.command;
- fis[3] = request->u.ata.feature;
- fis[4] = request->u.ata.lba;
- fis[5] = request->u.ata.lba >> 8;
- fis[6] = request->u.ata.lba >> 16;
- fis[7] = ATA_D_LBA;
- if (!(atadev->flags & ATA_D_48BIT_ACTIVE))
- fis[7] |= (ATA_D_IBM | (request->u.ata.lba >> 24 & 0x0f));
- fis[8] = request->u.ata.lba >> 24;
- fis[9] = request->u.ata.lba >> 32;
- fis[10] = request->u.ata.lba >> 40;
- fis[11] = request->u.ata.feature >> 8;
- fis[12] = request->u.ata.count;
- fis[13] = request->u.ata.count >> 8;
- fis[15] = ATA_A_4BIT;
- return 20;
- }
- return 0;
-}
-
-
-/*
- * AHCI v1.x compliant SATA chipset support functions
- */
-int
-ata_ahci_ident(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
- char buffer[64];
-
- /* is this PCI device flagged as an AHCI compliant chip ? */
- if (pci_read_config(dev, PCIR_PROGIF, 1) != PCIP_STORAGE_SATA_AHCI_1_0)
- return ENXIO;
-
- if (bootverbose)
- sprintf(buffer, "%s (ID=%08x) AHCI controller",
- ata_pcivendor2str(dev), pci_get_devid(dev));
- else
- sprintf(buffer, "%s AHCI controller", ata_pcivendor2str(dev));
- device_set_desc_copy(dev, buffer);
- ctlr->chipinit = ata_ahci_chipinit;
- return 0;
-}
-
-static int
-ata_ahci_chipinit(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
- u_int32_t version;
-
- /* if we have a memory BAR(5) we are likely on an AHCI part */
- ctlr->r_type2 = SYS_RES_MEMORY;
- ctlr->r_rid2 = PCIR_BAR(5);
- if (!(ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2,
- &ctlr->r_rid2, RF_ACTIVE)))
- return ENXIO;
-
- /* setup interrupt delivery if not done allready by a vendor driver */
- if (!ctlr->r_irq) {
- if (ata_setup_interrupt(dev))
- return ENXIO;
- }
- else
- device_printf(dev, "AHCI called from vendor specific driver\n");
-
- /* reset controller */
- ata_ahci_ctlr_reset(dev);
-
- /* get the number of HW channels */
- ctlr->channels =
- MAX(flsl(ATA_INL(ctlr->r_res2, ATA_AHCI_PI)),
- (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_NPMASK) + 1);
-
- ctlr->reset = ata_ahci_reset;
- ctlr->dmainit = ata_ahci_dmainit;
- ctlr->allocate = ata_ahci_allocate;
- ctlr->setmode = ata_sata_setmode;
- ctlr->suspend = ata_ahci_suspend;
- ctlr->resume = ata_ahci_ctlr_reset;
-
- /* enable PCI interrupt */
- pci_write_config(dev, PCIR_COMMAND,
- pci_read_config(dev, PCIR_COMMAND, 2) & ~0x0400, 2);
-
- /* announce we support the HW */
- version = ATA_INL(ctlr->r_res2, ATA_AHCI_VS);
- device_printf(dev,
- "AHCI Version %x%x.%x%x controller with %d ports PM %s\n",
- (version >> 24) & 0xff, (version >> 16) & 0xff,
- (version >> 8) & 0xff, version & 0xff,
- (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_NPMASK) + 1,
- (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_SPM) ?
- "supported" : "not supported");
- return 0;
-}
-
-static int
-ata_ahci_ctlr_reset(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
-
- /* enable AHCI mode */
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_AE);
-
- /* reset AHCI controller */
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_HR);
- DELAY(1000000);
- if (ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) & ATA_AHCI_GHC_HR) {
- bus_release_resource(dev, ctlr->r_type2, ctlr->r_rid2, ctlr->r_res2);
- device_printf(dev, "AHCI controller reset failure\n");
- return ENXIO;
- }
-
- /* reenable AHCI mode */
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_AE);
-
- /* clear interrupts */
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_IS, ATA_INL(ctlr->r_res2, ATA_AHCI_IS));
-
- /* enable AHCI interrupts */
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC,
- ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) | ATA_AHCI_GHC_IE);
-
- return 0;
-}
-
-static int
-ata_ahci_suspend(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
-
- /* disable interupts so the state change(s) doesn't trigger */
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC,
- ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) & (~ATA_AHCI_GHC_IE));
- return 0;
-}
-
-
-static int
-ata_ahci_allocate(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
- int offset = ch->unit << 7;
-
- /* set the SATA resources */
- ch->r_io[ATA_SSTATUS].res = ctlr->r_res2;
- ch->r_io[ATA_SSTATUS].offset = ATA_AHCI_P_SSTS + offset;
- ch->r_io[ATA_SERROR].res = ctlr->r_res2;
- ch->r_io[ATA_SERROR].offset = ATA_AHCI_P_SERR + offset;
- ch->r_io[ATA_SCONTROL].res = ctlr->r_res2;
- ch->r_io[ATA_SCONTROL].offset = ATA_AHCI_P_SCTL + offset;
- ch->r_io[ATA_SACTIVE].res = ctlr->r_res2;
- ch->r_io[ATA_SACTIVE].offset = ATA_AHCI_P_SACT + offset;
-
- ch->hw.status = ata_ahci_status;
- ch->hw.begin_transaction = ata_ahci_begin_transaction;
- ch->hw.end_transaction = ata_ahci_end_transaction;
- ch->hw.command = NULL; /* not used here */
- ch->hw.softreset = ata_ahci_softreset;
- ch->hw.pm_read = ata_ahci_pm_read;
- ch->hw.pm_write = ata_ahci_pm_write;
-
- return 0;
-}
-
-static int
-ata_ahci_status(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
- u_int32_t action = ATA_INL(ctlr->r_res2, ATA_AHCI_IS);
- int offset = ch->unit << 7;
-
-#define ATA_AHCI_STATBITS \
- (ATA_AHCI_P_IX_IF|ATA_AHCI_P_IX_HBD|ATA_AHCI_P_IX_HBF|ATA_AHCI_P_IX_TFE)
-
- if (action & (1 << ch->unit)) {
- u_int32_t istatus = ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset);
- u_int32_t cstatus = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CI + offset);
-
- /* clear interrupt(s) */
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IS + offset, istatus);
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_IS, action & (1 << ch->unit));
-
- /* do we have any PHY events ? */
- if (istatus & (ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC))
- ata_sata_phy_check_events(dev);
-
- /* do we have a potentially hanging engine to take care of? */
- /* XXX SOS what todo on NCQ */
- if ((istatus & ATA_AHCI_STATBITS) && (cstatus & 1)) {
-
- u_int32_t cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset);
- int timeout = 0;
-
- /* kill off all activity on this channel */
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
- cmd & ~(ATA_AHCI_P_CMD_FRE | ATA_AHCI_P_CMD_ST));
-
- /* XXX SOS this is not entirely wrong */
- do {
- DELAY(1000);
- if (timeout++ > 1000) {
- device_printf(dev, "stopping AHCI engine failed\n");
- break;
- }
- } while (ATA_INL(ctlr->r_res2,
- ATA_AHCI_P_CMD + offset) & ATA_AHCI_P_CMD_CR);
-
- /* start operations on this channel */
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
- cmd | (ATA_AHCI_P_CMD_FRE | ATA_AHCI_P_CMD_ST));
-
- return 1;
- }
- else
- /* XXX SOS what todo on NCQ */
- return (!(cstatus & 1));
- }
- return 0;
-}
-
-/* must be called with ATA channel locked and state_mtx held */
-static int
-ata_ahci_begin_transaction(struct ata_request *request)
-{
- struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev));
- struct ata_channel *ch = device_get_softc(request->parent);
- struct ata_device *atadev = device_get_softc(request->dev);
- struct ata_ahci_cmd_tab *ctp;
- struct ata_ahci_cmd_list *clp;
- int offset = ch->unit << 7;
- int port = atadev->unit & 0x0f;
- int entries = 0;
- int fis_size;
-
- /* get a piece of the workspace for this request */
- ctp = (struct ata_ahci_cmd_tab *)
- (ch->dma.work + ATA_AHCI_CT_OFFSET + (ATA_AHCI_CT_SIZE*request->tag));
-
- /* setup the FIS for this request */
- if (!(fis_size = ata_ahci_setup_fis(ctp, request))) {
- device_printf(request->dev, "setting up SATA FIS failed\n");
- request->result = EIO;
- return ATA_OP_FINISHED;
- }
-
- /* if request moves data setup and load SG list */
- if (request->flags & (ATA_R_READ | ATA_R_WRITE)) {
- if (ch->dma.load(request, ctp->prd_tab, &entries)) {
- device_printf(request->dev, "setting up DMA failed\n");
- request->result = EIO;
- return ATA_OP_FINISHED;
- }
- }
-
- /* setup the command list entry */
- clp = (struct ata_ahci_cmd_list *)
- (ch->dma.work + ATA_AHCI_CL_OFFSET + (ATA_AHCI_CL_SIZE*request->tag));
-
- clp->prd_length = entries;
- clp->cmd_flags = (request->flags & ATA_R_WRITE ? ATA_AHCI_CMD_WRITE : 0) |
- (request->flags & ATA_R_ATAPI ?
- (ATA_AHCI_CMD_ATAPI | ATA_AHCI_CMD_PREFETCH) : 0) |
- (fis_size / sizeof(u_int32_t)) |
- (port << 12);
- clp->bytecount = 0;
- clp->cmd_table_phys = htole64(ch->dma.work_bus + ATA_AHCI_CT_OFFSET +
- (ATA_AHCI_CT_SIZE * request->tag));
-
- /* clear eventual ACTIVE bit */
- ATA_IDX_OUTL(ch, ATA_SACTIVE,
- ATA_IDX_INL(ch, ATA_SACTIVE) & (1 << request->tag));
-
- /* set command type bit */
- if (request->flags & ATA_R_ATAPI)
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
- ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) |
- ATA_AHCI_P_CMD_ATAPI);
- else
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
- ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) &
- ~ATA_AHCI_P_CMD_ATAPI);
-
- /* set PM port to address */
- //ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FBS + offset, (port << 8) | 0x00000001);
-
- /* issue command to controller */
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CI + offset, (1 << request->tag));
-
- if (!(request->flags & ATA_R_ATAPI)) {
- /* device reset doesn't interrupt */
- if (request->u.ata.command == ATA_DEVICE_RESET) {
- u_int32_t tf_data;
- int timeout = 1000000;
-
- do {
- DELAY(10);
- tf_data = ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + (ch->unit<<7));
- } while ((tf_data & ATA_S_BUSY) && timeout--);
- if (bootverbose)
- device_printf(ch->dev, "device_reset timeout=%dus\n",
- (1000000-timeout)*10);
- request->status = tf_data;
- if (request->status & ATA_S_ERROR)
- request->error = tf_data >> 8;
- return ATA_OP_FINISHED;
- }
- }
-
- /* start the timeout */
- callout_reset(&request->callout, request->timeout * hz,
- (timeout_t*)ata_timeout, request);
- return ATA_OP_CONTINUES;
-}
-
-/* must be called with ATA channel locked and state_mtx held */
-static int
-ata_ahci_end_transaction(struct ata_request *request)
-{
- struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev));
- struct ata_channel *ch = device_get_softc(request->parent);
- struct ata_ahci_cmd_list *clp;
- u_int32_t tf_data;
- int offset = ch->unit << 7;
-
- /* kill the timeout */
- callout_stop(&request->callout);
-
- /* get status */
- tf_data = ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + offset);
- request->status = tf_data;
-
- /* if error status get details */
- if (request->status & ATA_S_ERROR)
- request->error = tf_data >> 8;
-
- /* on control commands read back registers to the request struct */
- if (request->flags & ATA_R_CONTROL) {
- struct ata_device *atadev = device_get_softc(request->dev);
- u_int8_t *fis = ch->dma.work + ATA_AHCI_FB_OFFSET + 0x40;
-
- request->u.ata.count = fis[12] | ((u_int16_t)fis[13] << 8);
- request->u.ata.lba = fis[4] | ((u_int64_t)fis[5] << 8) |
- ((u_int64_t)fis[6] << 16);
- if (atadev->flags & ATA_D_48BIT_ACTIVE)
- request->u.ata.lba |= ((u_int64_t)fis[8] << 24) |
- ((u_int64_t)fis[9] << 32) |
- ((u_int64_t)fis[10] << 40);
- else
- request->u.ata.lba |= ((u_int64_t)(fis[7] & 0x0f) << 24);
- }
-
- /* record how much data we actually moved */
- clp = (struct ata_ahci_cmd_list *)
- (ch->dma.work + ATA_AHCI_CL_OFFSET + (ATA_AHCI_CL_SIZE*request->tag));
- request->donecount = clp->bytecount;
-
- /* release SG list etc */
- ch->dma.unload(request);
-
- return ATA_OP_FINISHED;
-}
-
-static int
-ata_ahci_issue_cmd(device_t dev, u_int16_t flags, int timeout)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
- struct ata_ahci_cmd_list *clp =
- (struct ata_ahci_cmd_list *)(ch->dma.work + ATA_AHCI_CL_OFFSET);
- struct ata_ahci_cmd_tab *ctp =
- (struct ata_ahci_cmd_tab *)(ch->dma.work + ATA_AHCI_CT_OFFSET);
- u_int32_t status = 0;
- int offset = ch->unit << 7;
- int port = (ctp->cfis[1] & 0x0f);
- int count;
-
- clp->prd_length = 0;
- clp->cmd_flags = (20 / sizeof(u_int32_t)) | flags | (port << 12);
- clp->bytecount = 0;
- clp->cmd_table_phys = htole64(ch->dma.work_bus + ATA_AHCI_CT_OFFSET);
-
- /* set PM port */
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FBS + offset, (port << 8) | 0x00000001);
-
- /* issue command to controller */
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CI + offset, 1);
-
- /* poll for command finished */
- for (count = 0; count < timeout; count++) {
- DELAY(1000);
- if (!((status = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CI + offset)) & 1))
- break;
- }
-
- /* clear interrupts */
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IS + offset,
- ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset));
-
- if (bootverbose)
- device_printf(dev, "ahci_issue_cmd time=%dms cnt=%dms status=%08x\n",
- timeout, count, status);
- if (timeout && (count >= timeout))
- return EIO;
-
- return 0;
-}
-
-static int
-ata_ahci_pm_read(device_t dev, int port, int reg, u_int32_t *result)
-{
- struct ata_channel *ch = device_get_softc(dev);
- struct ata_ahci_cmd_tab *ctp =
- (struct ata_ahci_cmd_tab *)(ch->dma.work + ATA_AHCI_CT_OFFSET);
- u_int8_t *fis = ch->dma.work + ATA_AHCI_FB_OFFSET + 0x40;
-
- bzero(ctp->cfis, 64);
- ctp->cfis[0] = 0x27; /* host to device */
- ctp->cfis[1] = 0x8f; /* command FIS to PM port */
- ctp->cfis[2] = ATA_READ_PM;
- ctp->cfis[3] = reg;
- ctp->cfis[7] = port | ATA_D_LBA;
- ctp->cfis[15] = ATA_A_4BIT;
-
- if (ata_ahci_issue_cmd(dev, 0, 10)) {
- device_printf(dev, "error reading PM port\n");
- return EIO;
- }
-
- *result = fis[12] | (fis[4] << 8) | (fis[5] << 16) | (fis[6] << 24);
- return 0;
-}
-
-static int
-ata_ahci_pm_write(device_t dev, int port, int reg, u_int32_t value)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
- struct ata_ahci_cmd_tab *ctp =
- (struct ata_ahci_cmd_tab *)(ch->dma.work + ATA_AHCI_CT_OFFSET);
- int offset = ch->unit << 7;
-
- bzero(ctp->cfis, 64);
- ctp->cfis[0] = 0x27; /* host to device */
- ctp->cfis[1] = 0x8f; /* command FIS to PM port */
- ctp->cfis[2] = ATA_WRITE_PM;
- ctp->cfis[3] = reg;
- ctp->cfis[7] = port | ATA_D_LBA;
- ctp->cfis[12] = value & 0xff;
- ctp->cfis[4] = (value >> 8) & 0xff;;
- ctp->cfis[5] = (value >> 16) & 0xff;;
- ctp->cfis[6] = (value >> 24) & 0xff;;
- ctp->cfis[15] = ATA_A_4BIT;
-
- if (ata_ahci_issue_cmd(dev, 0, 100)) {
- device_printf(dev, "error writing PM port\n");
- return ATA_E_ABORT;
- }
-
- return (ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + offset) >> 8) & 0xff;
-}
-
-static void
-ata_ahci_restart(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
- u_int32_t cmd;
- int offset = ch->unit << 7;
- int timeout;
-
- /* kill off all activity on this channel */
- cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset);
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
- cmd & ~(ATA_AHCI_P_CMD_FRE | ATA_AHCI_P_CMD_ST));
-
- /* XXX SOS this is not entirely wrong */
- timeout = 0;
- do {
- DELAY(1000);
- if (timeout++ > 1000) {
- device_printf(dev, "stopping AHCI engine failed\n");
- break;
- }
- }
- while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) & ATA_AHCI_P_CMD_CR);
-
- /* issue Command List Override if supported */
- if (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_CLO) {
- cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset);
- cmd |= ATA_AHCI_P_CMD_CLO;
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, cmd);
- timeout = 0;
- do {
- DELAY(1000);
- if (timeout++ > 1000) {
- device_printf(dev, "executing CLO failed\n");
- break;
- }
- }
- while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD+offset)&ATA_AHCI_P_CMD_CLO);
- }
-
- /* clear SATA error register */
- ATA_IDX_OUTL(ch, ATA_SERROR, ATA_IDX_INL(ch, ATA_SERROR));
-
- /* clear any interrupts pending on this channel */
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IS + offset,
- ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset));
-
- /* start operations on this channel */
- cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset);
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
- cmd | (ATA_AHCI_P_CMD_FRE | ATA_AHCI_P_CMD_ST) |
- (ch->devices & ATA_PORTMULTIPLIER ? ATA_AHCI_P_CMD_PMA : 0));
-}
-
-static u_int32_t
-ata_ahci_softreset(device_t dev, int port)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
- int offset = ch->unit << 7;
- int timeout = 0;
-#ifdef AHCI_PM
- struct ata_ahci_cmd_tab *ctp =
- (struct ata_ahci_cmd_tab *)(ch->dma.work + ATA_AHCI_CT_OFFSET);
-
- /* kick controller into sane state if needed */
- ata_ahci_restart(dev);
-
- /* pull reset active */
- bzero(ctp->cfis, 64);
- ctp->cfis[0] = 0x27;
- ctp->cfis[1] = port & 0x0f;
- //ctp->cfis[7] = ATA_D_LBA | ATA_D_IBM;
- ctp->cfis[15] = (ATA_A_4BIT | ATA_A_RESET);
-
- if (ata_ahci_issue_cmd(dev, ATA_AHCI_CMD_RESET | ATA_AHCI_CMD_CLR_BUSY,100))
- device_printf(dev, "setting SRST failed ??\n");
- //return -1;
-
- ata_udelay(5000);
-
- /* pull reset inactive -> device softreset */
- bzero(ctp->cfis, 64);
- ctp->cfis[0] = 0x27;
- ctp->cfis[1] = port & 0x0f;
- //ctp->cfis[7] = ATA_D_LBA | ATA_D_IBM;
- ctp->cfis[15] = ATA_A_4BIT;
- if (ata_ahci_issue_cmd(dev, 0, 0))
- return -1;
-
- ata_udelay(150000);
-
-#endif
- do {
- DELAY(1000);
- if (timeout++ > 1000) {
- device_printf(dev, "still BUSY after softreset\n");
- break;
- }
- } while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + offset) & ATA_S_BUSY);
- if (bootverbose)
- device_printf(dev, "BUSY wait time=%dms\n", timeout);
-
- return ATA_INL(ctlr->r_res2, ATA_AHCI_P_SIG + offset);
-}
-
-static void
-ata_ahci_reset(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
- u_int64_t work;
- u_int32_t cmd, signature;
- int offset = ch->unit << 7;
-
- if (!(ATA_INL(ctlr->r_res2, ATA_AHCI_PI) & (1 << ch->unit))) {
- device_printf(dev, "port not implemented\n");
- return;
- }
-
- /* setup work areas */
- work = ch->dma.work_bus + ATA_AHCI_CL_OFFSET;
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CLB + offset, work & 0xffffffff);
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CLBU + offset, work >> 32);
-
- work = ch->dma.work_bus + ATA_AHCI_FB_OFFSET;
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FB + offset, work & 0xffffffff);
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FBU + offset, work >> 32);
-
- /* enable wanted port interrupts */
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IE + offset,
- (ATA_AHCI_P_IX_CPD | ATA_AHCI_P_IX_TFE | ATA_AHCI_P_IX_HBF |
- ATA_AHCI_P_IX_HBD | ATA_AHCI_P_IX_IF | ATA_AHCI_P_IX_OF |
- ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC | ATA_AHCI_P_IX_DP |
- ATA_AHCI_P_IX_UF | ATA_AHCI_P_IX_SDB | ATA_AHCI_P_IX_DS |
- ATA_AHCI_P_IX_PS | ATA_AHCI_P_IX_DHR));
-
- /* activate the channel and power/spin up device */
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
- (ATA_AHCI_P_CMD_ACTIVE | ATA_AHCI_P_CMD_POD | ATA_AHCI_P_CMD_SUD));
-
- ata_ahci_restart(dev);
-
- /* enable FIS based switching */
- //ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FBS + offset, 0x00000003);
-
- if (!ata_sata_phy_reset(dev)) {
- if (bootverbose)
- device_printf(dev, "phy reset found no device\n");
- ch->devices = 0;
-
- /* kill off all activity on this channel */
- cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset);
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
- cmd & ~(ATA_AHCI_P_CMD_FRE | ATA_AHCI_P_CMD_ST));
- return;
- }
-
- /* only probe for PortMultiplier if HW has support */
- if (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_SPM)
- signature = ata_ahci_softreset(dev, ATA_PM);
- else {
- signature = ata_ahci_softreset(dev, 0);
- }
- if (bootverbose)
- device_printf(dev, "SIGNATURE: %08x\n", signature);
-
- switch (signature) {
- case 0x00000101:
- ch->devices = ATA_ATA_MASTER;
- break;
- case 0x96690101:
- ch->devices = ATA_PORTMULTIPLIER;
- ata_pm_identify(dev);
- break;
- case 0xeb140101:
- ch->devices = ATA_ATAPI_MASTER;
- break;
- default: /* SOS XXX */
- if (bootverbose)
- device_printf(dev, "No signature, asuming disk device\n");
- ch->devices = ATA_ATA_MASTER;
- }
- if (bootverbose)
- device_printf(dev, "ahci_reset devices=%08x\n", ch->devices);
-}
-
-static void
-ata_ahci_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error)
-{
- struct ata_dmasetprd_args *args = xsc;
- struct ata_ahci_dma_prd *prd = args->dmatab;
- int i;
-
- if (!(args->error = error)) {
- for (i = 0; i < nsegs; i++) {
- prd[i].dba = htole64(segs[i].ds_addr);
- prd[i].dbc = htole32((segs[i].ds_len - 1) & ATA_AHCI_PRD_MASK);
- }
- }
-
- KASSERT(nsegs <= ATA_AHCI_DMA_ENTRIES, ("too many DMA segment entries\n"));
- args->nsegs = nsegs;
-}
-
-static void
-ata_ahci_dmainit(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
-
- ata_dmainit(dev);
- /* note start and stop are not used here */
- ch->dma.setprd = ata_ahci_dmasetprd;
- ch->dma.max_iosize = 8192 * DEV_BSIZE;
- if (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_64BIT)
- ch->dma.max_address = BUS_SPACE_MAXADDR;
-}
-
-static int
-ata_ahci_setup_fis(struct ata_ahci_cmd_tab *ctp, struct ata_request *request)
-{
- bzero(ctp->cfis, 64);
- if (request->flags & ATA_R_ATAPI) {
- bzero(ctp->acmd, 32);
- bcopy(request->u.atapi.ccb, ctp->acmd, 16);
- }
- return ata_request2fis_h2d(request, &ctp->cfis[0]);
-}
-
-
-/*
- * Acard chipset support functions
- */
-int
-ata_acard_ident(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
- static struct ata_chip_id ids[] =
- {{ ATA_ATP850R, 0, ATPOLD, 0x00, ATA_UDMA2, "ATP850" },
- { ATA_ATP860A, 0, 0, 0x00, ATA_UDMA4, "ATP860A" },
- { ATA_ATP860R, 0, 0, 0x00, ATA_UDMA4, "ATP860R" },
- { ATA_ATP865A, 0, 0, 0x00, ATA_UDMA6, "ATP865A" },
- { ATA_ATP865R, 0, 0, 0x00, ATA_UDMA6, "ATP865R" },
- { 0, 0, 0, 0, 0, 0}};
-
- if (!(ctlr->chip = ata_match_chip(dev, ids)))
- return ENXIO;
-
- ata_set_desc(dev);
- ctlr->chipinit = ata_acard_chipinit;
- return 0;
-}
-
-static int
-ata_acard_chipinit(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
-
- if (ata_setup_interrupt(dev))
- return ENXIO;
-
- ctlr->allocate = ata_acard_allocate;
- if (ctlr->chip->cfg1 == ATPOLD) {
- ctlr->setmode = ata_acard_850_setmode;
- ctlr->locking = ata_serialize;
- }
- else
- ctlr->setmode = ata_acard_86X_setmode;
- return 0;
-}
-
-static int
-ata_acard_allocate(device_t dev)
-{
- struct ata_channel *ch = device_get_softc(dev);
-
- /* setup the usual register normal pci style */
- if (ata_pci_allocate(dev))
- return ENXIO;
-
- ch->hw.status = ata_acard_status;
- return 0;
-}
-
-static int
-ata_acard_status(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
-
- if (ctlr->chip->cfg1 == ATPOLD &&
- ATA_LOCKING(dev, ATA_LF_WHICH) != ch->unit)
- return 0;
- if (ch->dma.flags & ATA_DMA_ACTIVE) {
- int bmstat = ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK;
-
- if ((bmstat & (ATA_BMSTAT_ACTIVE | ATA_BMSTAT_INTERRUPT)) !=
- ATA_BMSTAT_INTERRUPT)
- return 0;
- ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, bmstat & ~ATA_BMSTAT_ERROR);
- DELAY(1);
- ATA_IDX_OUTB(ch, ATA_BMCMD_PORT,
- ATA_IDX_INB(ch, ATA_BMCMD_PORT) & ~ATA_BMCMD_START_STOP);
- DELAY(1);
- }
- if (ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_BUSY) {
- DELAY(100);
- if (ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_BUSY)
- return 0;
- }
- return 1;
-}
-
-static void
-ata_acard_850_setmode(device_t dev, int mode)
-{
- device_t gparent = GRANDPARENT(dev);
- struct ata_pci_controller *ctlr = device_get_softc(gparent);
- struct ata_channel *ch = device_get_softc(device_get_parent(dev));
- struct ata_device *atadev = device_get_softc(dev);
- int devno = (ch->unit << 1) + atadev->unit;
- int error;
-
- mode = ata_limit_mode(dev, mode,
- ata_atapi(dev) ? ATA_PIO_MAX : ctlr->chip->max_dma);
-
- /* XXX SOS missing WDMA0+1 + PIO modes */
- if (mode >= ATA_WDMA2) {
- error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
- if (bootverbose)
- device_printf(dev, "%ssetting %s on %s chip\n",
- (error) ? "FAILURE " : "",
- ata_mode2str(mode), ctlr->chip->text);
- if (!error) {
- u_int8_t reg54 = pci_read_config(gparent, 0x54, 1);
-
- reg54 &= ~(0x03 << (devno << 1));
- if (mode >= ATA_UDMA0)
- reg54 |= (((mode & ATA_MODE_MASK) + 1) << (devno << 1));
- pci_write_config(gparent, 0x54, reg54, 1);
- pci_write_config(gparent, 0x4a, 0xa6, 1);
- pci_write_config(gparent, 0x40 + (devno << 1), 0x0301, 2);
- atadev->mode = mode;
- return;
- }
- }
- /* we could set PIO mode timings, but we assume the BIOS did that */
-}
-
-static void
-ata_acard_86X_setmode(device_t dev, int mode)
-{
- device_t gparent = GRANDPARENT(dev);
- struct ata_pci_controller *ctlr = device_get_softc(gparent);
- struct ata_channel *ch = device_get_softc(device_get_parent(dev));
- struct ata_device *atadev = device_get_softc(dev);
- int devno = (ch->unit << 1) + atadev->unit;
- int error;
-
-
- mode = ata_limit_mode(dev, mode,
- ata_atapi(dev) ? ATA_PIO_MAX : ctlr->chip->max_dma);
-
- mode = ata_check_80pin(dev, mode);
-
- /* XXX SOS missing WDMA0+1 + PIO modes */
- if (mode >= ATA_WDMA2) {
- error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
- if (bootverbose)
- device_printf(dev, "%ssetting %s on %s chip\n",
- (error) ? "FAILURE " : "",
- ata_mode2str(mode), ctlr->chip->text);
- if (!error) {
- u_int16_t reg44 = pci_read_config(gparent, 0x44, 2);
-
- reg44 &= ~(0x000f << (devno << 2));
- if (mode >= ATA_UDMA0)
- reg44 |= (((mode & ATA_MODE_MASK) + 1) << (devno << 2));
- pci_write_config(gparent, 0x44, reg44, 2);
- pci_write_config(gparent, 0x4a, 0xa6, 1);
- pci_write_config(gparent, 0x40 + devno, 0x31, 1);
- atadev->mode = mode;
- return;
- }
- }
- /* we could set PIO mode timings, but we assume the BIOS did that */
-}
-
-
-/*
- * Acer Labs Inc (ALI) chipset support functions
- */
-int
-ata_ali_ident(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
- static struct ata_chip_id ids[] =
- {{ ATA_ALI_5289, 0x00, 2, ALISATA, ATA_SA150, "M5289" },
- { ATA_ALI_5288, 0x00, 4, ALISATA, ATA_SA300, "M5288" },
- { ATA_ALI_5287, 0x00, 4, ALISATA, ATA_SA150, "M5287" },
- { ATA_ALI_5281, 0x00, 2, ALISATA, ATA_SA150, "M5281" },
- { ATA_ALI_5229, 0xc5, 0, ALINEW, ATA_UDMA6, "M5229" },
- { ATA_ALI_5229, 0xc4, 0, ALINEW, ATA_UDMA5, "M5229" },
- { ATA_ALI_5229, 0xc2, 0, ALINEW, ATA_UDMA4, "M5229" },
- { ATA_ALI_5229, 0x20, 0, ALIOLD, ATA_UDMA2, "M5229" },
- { ATA_ALI_5229, 0x00, 0, ALIOLD, ATA_WDMA2, "M5229" },
- { 0, 0, 0, 0, 0, 0}};
-
- if (!(ctlr->chip = ata_match_chip(dev, ids)))
- return ENXIO;
-
- ata_set_desc(dev);
- ctlr->chipinit = ata_ali_chipinit;
- return 0;
-}
-
-static int
-ata_ali_chipinit(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
-
- if (ata_setup_interrupt(dev))
- return ENXIO;
-
- switch (ctlr->chip->cfg2) {
- case ALISATA:
- ctlr->channels = ctlr->chip->cfg1;
- ctlr->allocate = ata_ali_sata_allocate;
- ctlr->setmode = ata_sata_setmode;
-
- /* AHCI mode is correctly supported only on the ALi 5288. */
- if ((ctlr->chip->chipid == ATA_ALI_5288) &&
- (ata_ahci_chipinit(dev) != ENXIO))
- return 0;
-
- /* enable PCI interrupt */
- pci_write_config(dev, PCIR_COMMAND,
- pci_read_config(dev, PCIR_COMMAND, 2) & ~0x0400, 2);
- break;
-
- case ALINEW:
- /* use device interrupt as byte count end */
- pci_write_config(dev, 0x4a, pci_read_config(dev, 0x4a, 1) | 0x20, 1);
-
- /* enable cable detection and UDMA support on newer chips */
- pci_write_config(dev, 0x4b, pci_read_config(dev, 0x4b, 1) | 0x09, 1);
-
- /* enable ATAPI UDMA mode */
- pci_write_config(dev, 0x53, pci_read_config(dev, 0x53, 1) | 0x01, 1);
-
- /* only chips with revision > 0xc4 can do 48bit DMA */
- if (ctlr->chip->chiprev <= 0xc4)
- device_printf(dev,
- "using PIO transfers above 137GB as workaround for "
- "48bit DMA access bug, expect reduced performance\n");
- ctlr->allocate = ata_ali_allocate;
- ctlr->reset = ata_ali_reset;
- ctlr->setmode = ata_ali_setmode;
- break;
-
- case ALIOLD:
- /* deactivate the ATAPI FIFO and enable ATAPI UDMA */
- pci_write_config(dev, 0x53, pci_read_config(dev, 0x53, 1) | 0x03, 1);
- ctlr->setmode = ata_ali_setmode;
- break;
- }
- return 0;
-}
-
-static int
-ata_ali_allocate(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
-
- /* setup the usual register normal pci style */
- if (ata_pci_allocate(dev))
- return ENXIO;
-
- /* older chips can't do 48bit DMA transfers */
- if (ctlr->chip->chiprev <= 0xc4)
- ch->flags |= ATA_NO_48BIT_DMA;
-
- return 0;
-}
-
-static int
-ata_ali_sata_allocate(device_t dev)
-{
- device_t parent = device_get_parent(dev);
- struct ata_pci_controller *ctlr = device_get_softc(parent);
- struct ata_channel *ch = device_get_softc(dev);
- struct resource *io = NULL, *ctlio = NULL;
- int unit01 = (ch->unit & 1), unit10 = (ch->unit & 2);
- int i, rid;
-
- rid = PCIR_BAR(0) + (unit01 ? 8 : 0);
- io = bus_alloc_resource_any(parent, SYS_RES_IOPORT, &rid, RF_ACTIVE);
- if (!io)
- return ENXIO;
-
- rid = PCIR_BAR(1) + (unit01 ? 8 : 0);
- ctlio = bus_alloc_resource_any(parent, SYS_RES_IOPORT, &rid, RF_ACTIVE);
- if (!ctlio) {
- bus_release_resource(dev, SYS_RES_IOPORT, ATA_IOADDR_RID, io);
- return ENXIO;
- }
-
- for (i = ATA_DATA; i <= ATA_COMMAND; i ++) {
- ch->r_io[i].res = io;
- ch->r_io[i].offset = i + (unit10 ? 8 : 0);
- }
- ch->r_io[ATA_CONTROL].res = ctlio;
- ch->r_io[ATA_CONTROL].offset = 2 + (unit10 ? 4 : 0);
- ch->r_io[ATA_IDX_ADDR].res = io;
- ata_default_registers(dev);
- if (ctlr->r_res1) {
- for (i = ATA_BMCMD_PORT; i <= ATA_BMDTP_PORT; i++) {
- ch->r_io[i].res = ctlr->r_res1;
- ch->r_io[i].offset = (i - ATA_BMCMD_PORT)+(ch->unit * ATA_BMIOSIZE);
- }
- }
- ch->flags |= ATA_NO_SLAVE;
-
- /* XXX SOS PHY handling awkward in ALI chip not supported yet */
- ata_pci_hw(dev);
- return 0;
-}
-
-static void
-ata_ali_reset(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
- device_t *children;
- int nchildren, i;
-
- ata_generic_reset(dev);
-
- /*
- * workaround for datacorruption bug found on at least SUN Blade-100
- * find the ISA function on the southbridge and disable then enable
- * the ATA channel tristate buffer
- */
- if (ctlr->chip->chiprev == 0xc3 || ctlr->chip->chiprev == 0xc2) {
- if (!device_get_children(GRANDPARENT(dev), &children, &nchildren)) {
- for (i = 0; i < nchildren; i++) {
- if (pci_get_devid(children[i]) == ATA_ALI_1533) {
- pci_write_config(children[i], 0x58,
- pci_read_config(children[i], 0x58, 1) &
- ~(0x04 << ch->unit), 1);
- pci_write_config(children[i], 0x58,
- pci_read_config(children[i], 0x58, 1) |
- (0x04 << ch->unit), 1);
- break;
- }
- }
- free(children, M_TEMP);
- }
- }
-}
-
-static void
-ata_ali_setmode(device_t dev, int mode)
-{
- device_t gparent = GRANDPARENT(dev);
- struct ata_pci_controller *ctlr = device_get_softc(gparent);
- struct ata_channel *ch = device_get_softc(device_get_parent(dev));
- struct ata_device *atadev = device_get_softc(dev);
- int devno = (ch->unit << 1) + atadev->unit;
- int error;
-
- mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma);
-
- if (ctlr->chip->cfg2 & ALINEW) {
- if (mode > ATA_UDMA2 &&
- pci_read_config(gparent, 0x4a, 1) & (1 << ch->unit)) {
- ata_print_cable(dev, "controller");
- mode = ATA_UDMA2;
- }
- }
- else
- mode = ata_check_80pin(dev, mode);
-
- if (ctlr->chip->cfg2 & ALIOLD) {
- /* doesn't support ATAPI DMA on write */
- ch->flags |= ATA_ATAPI_DMA_RO;
- if (ch->devices & ATA_ATAPI_MASTER && ch->devices & ATA_ATAPI_SLAVE) {
- /* doesn't support ATAPI DMA on two ATAPI devices */
- device_printf(dev, "two atapi devices on this channel, no DMA\n");
- mode = ata_limit_mode(dev, mode, ATA_PIO_MAX);
- }
- }
-
- error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
-
- if (bootverbose)
- device_printf(dev, "%ssetting %s on %s chip\n",
- (error) ? "FAILURE " : "",
- ata_mode2str(mode), ctlr->chip->text);
- if (!error) {
- if (mode >= ATA_UDMA0) {
- u_int8_t udma[] = {0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0d};
- u_int32_t word54 = pci_read_config(gparent, 0x54, 4);
-
- word54 &= ~(0x000f000f << (devno << 2));
- word54 |= (((udma[mode&ATA_MODE_MASK]<<16)|0x05)<<(devno<<2));
- pci_write_config(gparent, 0x54, word54, 4);
- pci_write_config(gparent, 0x58 + (ch->unit << 2),
- 0x00310001, 4);
- }
- else {
- u_int32_t piotimings[] =
- { 0x006d0003, 0x00580002, 0x00440001, 0x00330001,
- 0x00310001, 0x00440001, 0x00330001, 0x00310001};
-
- pci_write_config(gparent, 0x54, pci_read_config(gparent, 0x54, 4) &
- ~(0x0008000f << (devno << 2)), 4);
- pci_write_config(gparent, 0x58 + (ch->unit << 2),
- piotimings[ata_mode2idx(mode)], 4);
- }
- atadev->mode = mode;
- }
-}
-
-
-/*
- * American Micro Devices (AMD) chipset support functions
- */
-int
-ata_amd_ident(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
- static struct ata_chip_id ids[] =
- {{ ATA_AMD756, 0x00, AMDNVIDIA, 0x00, ATA_UDMA4, "756" },
- { ATA_AMD766, 0x00, AMDNVIDIA, AMDCABLE|AMDBUG, ATA_UDMA5, "766" },
- { ATA_AMD768, 0x00, AMDNVIDIA, AMDCABLE, ATA_UDMA5, "768" },
- { ATA_AMD8111, 0x00, AMDNVIDIA, AMDCABLE, ATA_UDMA6, "8111" },
- { ATA_AMD5536, 0x00, AMDNVIDIA, 0x00, ATA_UDMA5, "CS5536" },
- { 0, 0, 0, 0, 0, 0}};
-
- if (!(ctlr->chip = ata_match_chip(dev, ids)))
- return ENXIO;
-
- ata_set_desc(dev);
- ctlr->chipinit = ata_amd_chipinit;
- return 0;
-}
-
-static int
-ata_amd_chipinit(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
-
- if (ata_setup_interrupt(dev))
- return ENXIO;
-
- /* disable/set prefetch, postwrite */
- if (ctlr->chip->cfg2 & AMDBUG)
- pci_write_config(dev, 0x41, pci_read_config(dev, 0x41, 1) & 0x0f, 1);
- else
- pci_write_config(dev, 0x41, pci_read_config(dev, 0x41, 1) | 0xf0, 1);
-
- ctlr->setmode = ata_via_family_setmode;
- return 0;
-}
-
-
-/*
- * Adaptec chipset support functions
- */
-int
-ata_adaptec_ident(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
- static struct ata_chip_id ids[] =
- {{ ATA_ADAPTEC_1420, 0, 4, MV60XX, ATA_SA300, "1420SA" },
- { 0, 0, 0, 0, 0, 0}};
-
- if (!(ctlr->chip = ata_match_chip(dev, ids)))
- return ENXIO;
-
- ata_set_desc(dev);
- ctlr->chipinit = ata_marvell_edma_chipinit;
-
- return 0;
-}
-
-
-/*
- * ATI chipset support functions
- */
-int
-ata_ati_ident(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
- static struct ata_chip_id ids[] =
- {{ ATA_ATI_IXP200, 0x00, 0, ATIPATA, ATA_UDMA5, "IXP200" },
- { ATA_ATI_IXP300, 0x00, 0, ATIPATA, ATA_UDMA6, "IXP300" },
- { ATA_ATI_IXP300_S1, 0x00, 0, ATISATA, ATA_SA150, "IXP300" },
- { ATA_ATI_IXP400, 0x00, 0, ATIPATA, ATA_UDMA6, "IXP400" },
- { ATA_ATI_IXP400_S1, 0x00, 0, ATISATA, ATA_SA150, "IXP400" },
- { ATA_ATI_IXP400_S2, 0x00, 0, ATISATA, ATA_SA150, "IXP400" },
- { ATA_ATI_IXP600, 0x00, 0, ATIPATA, ATA_UDMA6, "IXP600" },
- { ATA_ATI_IXP600_S1, 0x00, 0, ATIAHCI, ATA_SA300, "IXP600" },
- { ATA_ATI_IXP700, 0x00, 0, ATIPATA, ATA_UDMA6, "IXP700" },
- { ATA_ATI_IXP700_S1, 0x00, 0, ATIAHCI, ATA_SA300, "IXP700" },
- { 0, 0, 0, 0, 0, 0}};
-
- if (!(ctlr->chip = ata_match_chip(dev, ids)))
- return ENXIO;
-
- ata_set_desc(dev);
-
- switch (ctlr->chip->cfg2) {
- case ATIPATA:
- ctlr->chipinit = ata_ati_chipinit;
- break;
- case ATISATA:
- /* the ATI SATA controller is actually a SiI 3112 controller */
- ctlr->chip->cfg1 = SIIMEMIO;
- ctlr->chipinit = ata_sii_chipinit;
- break;
- case ATIAHCI:
- ctlr->chipinit = ata_ahci_chipinit;
- break;
- }
- return 0;
-}
-
-static int
-ata_ati_chipinit(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
-
- if (ata_setup_interrupt(dev))
- return ENXIO;
-
- /* IXP600 & IXP700 only have 1 PATA channel */
- if ((ctlr->chip->chipid == ATA_ATI_IXP600) ||
- (ctlr->chip->chipid == ATA_ATI_IXP700))
- ctlr->channels = 1;
-
- ctlr->setmode = ata_ati_setmode;
- return 0;
-}
-
-static void
-ata_ati_setmode(device_t dev, int mode)
-{
- device_t gparent = GRANDPARENT(dev);
- struct ata_pci_controller *ctlr = device_get_softc(gparent);
- struct ata_channel *ch = device_get_softc(device_get_parent(dev));
- struct ata_device *atadev = device_get_softc(dev);
- int devno = (ch->unit << 1) + atadev->unit;
- int offset = (devno ^ 0x01) << 3;
- int error;
- u_int8_t piotimings[] = { 0x5d, 0x47, 0x34, 0x22, 0x20, 0x34, 0x22, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 };
- u_int8_t dmatimings[] = { 0x77, 0x21, 0x20 };
-
- mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma);
-
- mode = ata_check_80pin(dev, mode);
-
- error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
-
- if (bootverbose)
- device_printf(dev, "%ssetting %s on %s chip\n",
- (error) ? "FAILURE " : "",
- ata_mode2str(mode), ctlr->chip->text);
- if (!error) {
- if (mode >= ATA_UDMA0) {
- pci_write_config(gparent, 0x56,
- (pci_read_config(gparent, 0x56, 2) &
- ~(0xf << (devno << 2))) |
- ((mode & ATA_MODE_MASK) << (devno << 2)), 2);
- pci_write_config(gparent, 0x54,
- pci_read_config(gparent, 0x54, 1) |
- (0x01 << devno), 1);
- pci_write_config(gparent, 0x44,
- (pci_read_config(gparent, 0x44, 4) &
- ~(0xff << offset)) |
- (dmatimings[2] << offset), 4);
- }
- else if (mode >= ATA_WDMA0) {
- pci_write_config(gparent, 0x54,
- pci_read_config(gparent, 0x54, 1) &
- ~(0x01 << devno), 1);
- pci_write_config(gparent, 0x44,
- (pci_read_config(gparent, 0x44, 4) &
- ~(0xff << offset)) |
- (dmatimings[mode & ATA_MODE_MASK] << offset), 4);
- }
- else
- pci_write_config(gparent, 0x54,
- pci_read_config(gparent, 0x54, 1) &
- ~(0x01 << devno), 1);
-
- pci_write_config(gparent, 0x4a,
- (pci_read_config(gparent, 0x4a, 2) &
- ~(0xf << (devno << 2))) |
- (((mode - ATA_PIO0) & ATA_MODE_MASK) << (devno<<2)),2);
- pci_write_config(gparent, 0x40,
- (pci_read_config(gparent, 0x40, 4) &
- ~(0xff << offset)) |
- (piotimings[ata_mode2idx(mode)] << offset), 4);
- atadev->mode = mode;
- }
-}
-
-
-/*
- * Cyrix chipset support functions
- */
-int
-ata_cyrix_ident(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
-
- if (pci_get_devid(dev) == ATA_CYRIX_5530) {
- device_set_desc(dev, "Cyrix 5530 ATA33 controller");
- ctlr->chipinit = ata_cyrix_chipinit;
- return 0;
- }
- return ENXIO;
-}
-
-static int
-ata_cyrix_chipinit(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
-
- if (ata_setup_interrupt(dev))
- return ENXIO;
-
- if (ctlr->r_res1)
- ctlr->setmode = ata_cyrix_setmode;
- else
- ctlr->setmode = ata_generic_setmode;
- return 0;
-}
-
-static void
-ata_cyrix_setmode(device_t dev, int mode)
-{
- struct ata_channel *ch = device_get_softc(device_get_parent(dev));
- struct ata_device *atadev = device_get_softc(dev);
- int devno = (ch->unit << 1) + atadev->unit;
- u_int32_t piotiming[] =
- { 0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010 };
- u_int32_t dmatiming[] = { 0x00077771, 0x00012121, 0x00002020 };
- u_int32_t udmatiming[] = { 0x00921250, 0x00911140, 0x00911030 };
- int error;
-
- ch->dma.alignment = 16;
- ch->dma.max_iosize = 126 * DEV_BSIZE;
-
- mode = ata_limit_mode(dev, mode, ATA_UDMA2);
-
- error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
-
- if (bootverbose)
- device_printf(dev, "%ssetting %s on Cyrix chip\n",
- (error) ? "FAILURE " : "", ata_mode2str(mode));
- if (!error) {
- if (mode >= ATA_UDMA0) {
- ATA_OUTL(ch->r_io[ATA_BMCMD_PORT].res,
- 0x24 + (devno << 3), udmatiming[mode & ATA_MODE_MASK]);
- }
- else if (mode >= ATA_WDMA0) {
- ATA_OUTL(ch->r_io[ATA_BMCMD_PORT].res,
- 0x24 + (devno << 3), dmatiming[mode & ATA_MODE_MASK]);
- }
- else {
- ATA_OUTL(ch->r_io[ATA_BMCMD_PORT].res,
- 0x20 + (devno << 3), piotiming[mode & ATA_MODE_MASK]);
- }
- atadev->mode = mode;
- }
-}
-
-
-/*
- * Cypress chipset support functions
- */
-int
-ata_cypress_ident(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
-
- /*
- * the Cypress chip is a mess, it contains two ATA functions, but
- * both channels are visible on the first one.
- * simply ignore the second function for now, as the right
- * solution (ignoring the second channel on the first function)
- * doesn't work with the crappy ATA interrupt setup on the alpha.
- */
- if (pci_get_devid(dev) == ATA_CYPRESS_82C693 &&
- pci_get_function(dev) == 1 &&
- pci_get_subclass(dev) == PCIS_STORAGE_IDE) {
- device_set_desc(dev, "Cypress 82C693 ATA controller");
- ctlr->chipinit = ata_cypress_chipinit;
- return 0;
- }
- return ENXIO;
-}
-
-static int
-ata_cypress_chipinit(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
-
- if (ata_setup_interrupt(dev))
- return ENXIO;
-
- ctlr->setmode = ata_cypress_setmode;
- return 0;
-}
-
-static void
-ata_cypress_setmode(device_t dev, int mode)
-{
- device_t gparent = GRANDPARENT(dev);
- struct ata_channel *ch = device_get_softc(device_get_parent(dev));
- struct ata_device *atadev = device_get_softc(dev);
- int error;
-
- mode = ata_limit_mode(dev, mode, ATA_WDMA2);
-
- /* XXX SOS missing WDMA0+1 + PIO modes */
- if (mode == ATA_WDMA2) {
- error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
- if (bootverbose)
- device_printf(dev, "%ssetting WDMA2 on Cypress chip\n",
- error ? "FAILURE " : "");
- if (!error) {
- pci_write_config(gparent, ch->unit ? 0x4e : 0x4c, 0x2020, 2);
- atadev->mode = mode;
- return;
- }
- }
- /* we could set PIO mode timings, but we assume the BIOS did that */
-}
-
-
-/*
- * HighPoint chipset support functions
- */
-int
-ata_highpoint_ident(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
- struct ata_chip_id *idx;
- static struct ata_chip_id ids[] =
- {{ ATA_HPT374, 0x07, HPT374, 0x00, ATA_UDMA6, "HPT374" },
- { ATA_HPT372, 0x02, HPT372, 0x00, ATA_UDMA6, "HPT372N" },
- { ATA_HPT372, 0x01, HPT372, 0x00, ATA_UDMA6, "HPT372" },
- { ATA_HPT371, 0x01, HPT372, 0x00, ATA_UDMA6, "HPT371" },
- { ATA_HPT366, 0x05, HPT372, 0x00, ATA_UDMA6, "HPT372" },
- { ATA_HPT366, 0x03, HPT370, 0x00, ATA_UDMA5, "HPT370" },
- { ATA_HPT366, 0x02, HPT366, 0x00, ATA_UDMA4, "HPT368" },
- { ATA_HPT366, 0x00, HPT366, HPTOLD, ATA_UDMA4, "HPT366" },
- { ATA_HPT302, 0x01, HPT372, 0x00, ATA_UDMA6, "HPT302" },
- { 0, 0, 0, 0, 0, 0}};
- char buffer[64];
-
- if (!(idx = ata_match_chip(dev, ids)))
- return ENXIO;
-
- strcpy(buffer, "HighPoint ");
- strcat(buffer, idx->text);
- if (idx->cfg1 == HPT374) {
- if (pci_get_function(dev) == 0)
- strcat(buffer, " (channel 0+1)");
- if (pci_get_function(dev) == 1)
- strcat(buffer, " (channel 2+3)");
- }
- sprintf(buffer, "%s %s controller", buffer, ata_mode2str(idx->max_dma));
- device_set_desc_copy(dev, buffer);
- ctlr->chip = idx;
- ctlr->chipinit = ata_highpoint_chipinit;
- return 0;
-}
-
-static int
-ata_highpoint_chipinit(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
-
- if (ata_setup_interrupt(dev))
- return ENXIO;
-
- if (ctlr->chip->cfg2 == HPTOLD) {
- /* disable interrupt prediction */
- pci_write_config(dev, 0x51, (pci_read_config(dev, 0x51, 1) & ~0x80), 1);
- }
- else {
- /* disable interrupt prediction */
- pci_write_config(dev, 0x51, (pci_read_config(dev, 0x51, 1) & ~0x03), 1);
- pci_write_config(dev, 0x55, (pci_read_config(dev, 0x55, 1) & ~0x03), 1);
-
- /* enable interrupts */
- pci_write_config(dev, 0x5a, (pci_read_config(dev, 0x5a, 1) & ~0x10), 1);
-
- /* set clocks etc */
- if (ctlr->chip->cfg1 < HPT372)
- pci_write_config(dev, 0x5b, 0x22, 1);
- else
- pci_write_config(dev, 0x5b,
- (pci_read_config(dev, 0x5b, 1) & 0x01) | 0x20, 1);
- }
- ctlr->allocate = ata_highpoint_allocate;
- ctlr->setmode = ata_highpoint_setmode;
- return 0;
-}
-
-static int
-ata_highpoint_allocate(device_t dev)
-{
- struct ata_channel *ch = device_get_softc(dev);
-
- /* setup the usual register normal pci style */
- if (ata_pci_allocate(dev))
- return ENXIO;
-
- ch->flags |= ATA_ALWAYS_DMASTAT;
- return 0;
-}
-
-static void
-ata_highpoint_setmode(device_t dev, int mode)
-{
- device_t gparent = GRANDPARENT(dev);
- struct ata_pci_controller *ctlr = device_get_softc(gparent);
- struct ata_channel *ch = device_get_softc(device_get_parent(dev));
- struct ata_device *atadev = device_get_softc(dev);
- int devno = (ch->unit << 1) + atadev->unit;
- int error;
- u_int32_t timings33[][4] = {
- /* HPT366 HPT370 HPT372 HPT374 mode */
- { 0x40d0a7aa, 0x06914e57, 0x0d029d5e, 0x0ac1f48a }, /* PIO 0 */
- { 0x40d0a7a3, 0x06914e43, 0x0d029d26, 0x0ac1f465 }, /* PIO 1 */
- { 0x40d0a753, 0x06514e33, 0x0c829ca6, 0x0a81f454 }, /* PIO 2 */
- { 0x40c8a742, 0x06514e22, 0x0c829c84, 0x0a81f443 }, /* PIO 3 */
- { 0x40c8a731, 0x06514e21, 0x0c829c62, 0x0a81f442 }, /* PIO 4 */
- { 0x20c8a797, 0x26514e97, 0x2c82922e, 0x228082ea }, /* MWDMA 0 */
- { 0x20c8a732, 0x26514e33, 0x2c829266, 0x22808254 }, /* MWDMA 1 */
- { 0x20c8a731, 0x26514e21, 0x2c829262, 0x22808242 }, /* MWDMA 2 */
- { 0x10c8a731, 0x16514e31, 0x1c829c62, 0x121882ea }, /* UDMA 0 */
- { 0x10cba731, 0x164d4e31, 0x1c9a9c62, 0x12148254 }, /* UDMA 1 */
- { 0x10caa731, 0x16494e31, 0x1c929c62, 0x120c8242 }, /* UDMA 2 */
- { 0x10cfa731, 0x166d4e31, 0x1c8e9c62, 0x128c8242 }, /* UDMA 3 */
- { 0x10c9a731, 0x16454e31, 0x1c8a9c62, 0x12ac8242 }, /* UDMA 4 */
- { 0, 0x16454e31, 0x1c8a9c62, 0x12848242 }, /* UDMA 5 */
- { 0, 0, 0x1c869c62, 0x12808242 } /* UDMA 6 */
- };
-
- mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma);
-
- if (ctlr->chip->cfg1 == HPT366 && ata_atapi(dev))
- mode = ata_limit_mode(dev, mode, ATA_PIO_MAX);
-
- mode = ata_highpoint_check_80pin(dev, mode);
-
- /*
- * most if not all HPT chips cant really handle that the device is
- * running at ATA_UDMA6/ATA133 speed, so we cheat at set the device to
- * a max of ATA_UDMA5/ATA100 to guard against suboptimal performance
- */
- error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0,
- ata_limit_mode(dev, mode, ATA_UDMA5));
- if (bootverbose)
- device_printf(dev, "%ssetting %s on HighPoint chip\n",
- (error) ? "FAILURE " : "", ata_mode2str(mode));
- if (!error)
- pci_write_config(gparent, 0x40 + (devno << 2),
- timings33[ata_mode2idx(mode)][ctlr->chip->cfg1], 4);
- atadev->mode = mode;
-}
-
-static int
-ata_highpoint_check_80pin(device_t dev, int mode)
-{
- device_t gparent = GRANDPARENT(dev);
- struct ata_pci_controller *ctlr = device_get_softc(gparent);
- struct ata_channel *ch = device_get_softc(device_get_parent(dev));
- u_int8_t reg, val, res;
-
- if (ctlr->chip->cfg1 == HPT374 && pci_get_function(gparent) == 1) {
- reg = ch->unit ? 0x57 : 0x53;
- val = pci_read_config(gparent, reg, 1);
- pci_write_config(gparent, reg, val | 0x80, 1);
- }
- else {
- reg = 0x5b;
- val = pci_read_config(gparent, reg, 1);
- pci_write_config(gparent, reg, val & 0xfe, 1);
- }
- res = pci_read_config(gparent, 0x5a, 1) & (ch->unit ? 0x1:0x2);
- pci_write_config(gparent, reg, val, 1);
-
- if (mode > ATA_UDMA2 && res) {
- ata_print_cable(dev, "controller");
- mode = ATA_UDMA2;
- }
- return mode;
-}
-
-
-/*
- * Intel chipset support functions
- */
-int
-ata_intel_ident(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
- static struct ata_chip_id ids[] =
- {{ ATA_I82371FB, 0, 0, 2, ATA_WDMA2, "PIIX" },
- { ATA_I82371SB, 0, 0, 2, ATA_WDMA2, "PIIX3" },
- { ATA_I82371AB, 0, 0, 2, ATA_UDMA2, "PIIX4" },
- { ATA_I82443MX, 0, 0, 2, ATA_UDMA2, "PIIX4" },
- { ATA_I82451NX, 0, 0, 2, ATA_UDMA2, "PIIX4" },
- { ATA_I82801AB, 0, 0, 2, ATA_UDMA2, "ICH0" },
- { ATA_I82801AA, 0, 0, 2, ATA_UDMA4, "ICH" },
- { ATA_I82372FB, 0, 0, 2, ATA_UDMA4, "ICH" },
- { ATA_I82801BA, 0, 0, 2, ATA_UDMA5, "ICH2" },
- { ATA_I82801BA_1, 0, 0, 2, ATA_UDMA5, "ICH2" },
- { ATA_I82801CA, 0, 0, 2, ATA_UDMA5, "ICH3" },
- { ATA_I82801CA_1, 0, 0, 2, ATA_UDMA5, "ICH3" },
- { ATA_I82801DB, 0, 0, 2, ATA_UDMA5, "ICH4" },
- { ATA_I82801DB_1, 0, 0, 2, ATA_UDMA5, "ICH4" },
- { ATA_I82801EB, 0, 0, 2, ATA_UDMA5, "ICH5" },
- { ATA_I82801EB_S1, 0, 0, 2, ATA_SA150, "ICH5" },
- { ATA_I82801EB_R1, 0, 0, 2, ATA_SA150, "ICH5" },
- { ATA_I6300ESB, 0, 0, 2, ATA_UDMA5, "6300ESB" },
- { ATA_I6300ESB_S1, 0, 0, 2, ATA_SA150, "6300ESB" },
- { ATA_I6300ESB_R1, 0, 0, 2, ATA_SA150, "6300ESB" },
- { ATA_I82801FB, 0, 0, 2, ATA_UDMA5, "ICH6" },
- { ATA_I82801FB_S1, 0, AHCI, 0, ATA_SA150, "ICH6" },
- { ATA_I82801FB_R1, 0, AHCI, 0, ATA_SA150, "ICH6" },
- { ATA_I82801FBM, 0, AHCI, 0, ATA_SA150, "ICH6M" },
- { ATA_I82801GB, 0, 0, 1, ATA_UDMA5, "ICH7" },
- { ATA_I82801GB_S1, 0, AHCI, 0, ATA_SA300, "ICH7" },
- { ATA_I82801GB_R1, 0, AHCI, 0, ATA_SA300, "ICH7" },
- { ATA_I82801GB_AH, 0, AHCI, 0, ATA_SA300, "ICH7" },
- { ATA_I82801GBM_S1, 0, AHCI, 0, ATA_SA300, "ICH7M" },
- { ATA_I82801GBM_R1, 0, AHCI, 0, ATA_SA300, "ICH7M" },
- { ATA_I82801GBM_AH, 0, AHCI, 0, ATA_SA300, "ICH7M" },
- { ATA_I63XXESB2, 0, 0, 1, ATA_UDMA5, "63XXESB2" },
- { ATA_I63XXESB2_S1, 0, AHCI, 0, ATA_SA300, "63XXESB2" },
- { ATA_I63XXESB2_S2, 0, AHCI, 0, ATA_SA300, "63XXESB2" },
- { ATA_I63XXESB2_R1, 0, AHCI, 0, ATA_SA300, "63XXESB2" },
- { ATA_I63XXESB2_R2, 0, AHCI, 0, ATA_SA300, "63XXESB2" },
- { ATA_I82801HB_S1, 0, AHCI, 0, ATA_SA300, "ICH8" },
- { ATA_I82801HB_S2, 0, AHCI, 0, ATA_SA300, "ICH8" },
- { ATA_I82801HB_R1, 0, AHCI, 0, ATA_SA300, "ICH8" },
- { ATA_I82801HB_AH4, 0, AHCI, 0, ATA_SA300, "ICH8" },
- { ATA_I82801HB_AH6, 0, AHCI, 0, ATA_SA300, "ICH8" },
- { ATA_I82801HBM, 0, 0, 1, ATA_UDMA5, "ICH8M" },
- { ATA_I82801HBM_S1, 0, AHCI, 0, ATA_SA300, "ICH8M" },
- { ATA_I82801HBM_S2, 0, AHCI, 0, ATA_SA300, "ICH8M" },
- { ATA_I82801HBM_S3, 0, AHCI, 0, ATA_SA300, "ICH8M" },
- { ATA_I82801IB_S1, 0, AHCI, 0, ATA_SA300, "ICH9" },
- { ATA_I82801IB_S2, 0, AHCI, 0, ATA_SA300, "ICH9" },
- { ATA_I82801IB_AH2, 0, AHCI, 0, ATA_SA300, "ICH9" },
- { ATA_I82801IB_AH4, 0, AHCI, 0, ATA_SA300, "ICH9" },
- { ATA_I82801IB_AH6, 0, AHCI, 0, ATA_SA300, "ICH9" },
- { ATA_I82801IB_R1, 0, AHCI, 0, ATA_SA300, "ICH9" },
- { ATA_I82801JIB_S1, 0, AHCI, 0, ATA_SA300, "ICH10" },
- { ATA_I82801JIB_AH, 0, AHCI, 0, ATA_SA300, "ICH10" },
- { ATA_I82801JIB_R1, 0, AHCI, 0, ATA_SA300, "ICH10" },
- { ATA_I82801JIB_S2, 0, AHCI, 0, ATA_SA300, "ICH10" },
- { ATA_I82801JD_S1, 0, AHCI, 0, ATA_SA300, "ICH10" },
- { ATA_I82801JD_AH, 0, AHCI, 0, ATA_SA300, "ICH10" },
- { ATA_I82801JD_R1, 0, AHCI, 0, ATA_SA300, "ICH10" },
- { ATA_I82801JD_S2, 0, AHCI, 0, ATA_SA300, "ICH10" },
- { ATA_I31244, 0, 0, 2, ATA_SA150, "31244" },
- { 0, 0, 0, 0, 0, 0}};
-
- if (!(ctlr->chip = ata_match_chip(dev, ids)))
- return ENXIO;
-
- ata_set_desc(dev);
- ctlr->chipinit = ata_intel_chipinit;
- return 0;
-}
-
-static int
-ata_intel_chipinit(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
-
- if (ata_setup_interrupt(dev))
- return ENXIO;
-
- /* good old PIIX needs special treatment (not implemented) */
- if (ctlr->chip->chipid == ATA_I82371FB) {
- ctlr->setmode = ata_intel_old_setmode;
- }
-
- /* the intel 31244 needs special care if in DPA mode */
- else if (ctlr->chip->chipid == ATA_I31244) {
- if (pci_get_subclass(dev) != PCIS_STORAGE_IDE) {
- ctlr->r_type2 = SYS_RES_MEMORY;
- ctlr->r_rid2 = PCIR_BAR(0);
- if (!(ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2,
- &ctlr->r_rid2,
- RF_ACTIVE)))
- return ENXIO;
- ctlr->channels = 4;
- ctlr->allocate = ata_intel_31244_allocate;
- ctlr->reset = ata_intel_31244_reset;
- }
- ctlr->setmode = ata_sata_setmode;
- }
-
- /* non SATA intel chips goes here */
- else if (ctlr->chip->max_dma < ATA_SA150) {
- ctlr->channels = ctlr->chip->cfg2;
- ctlr->allocate = ata_intel_allocate;
- ctlr->setmode = ata_intel_new_setmode;
- }
-
- /* SATA parts can be either compat or AHCI */
- else {
- /* force all ports active "the legacy way" */
- pci_write_config(dev, 0x92, pci_read_config(dev, 0x92, 2) | 0x0f, 2);
-
- ctlr->allocate = ata_intel_allocate;
- ctlr->reset = ata_intel_reset;
-
- /*
- * if we have AHCI capability and AHCI or RAID mode enabled
- * in BIOS we try for AHCI mode
- */
- if ((ctlr->chip->cfg1 == AHCI) &&
- (pci_read_config(dev, 0x90, 1) & 0xc0) &&
- (ata_ahci_chipinit(dev) != ENXIO))
- return 0;
-
- /* if BAR(5) is IO it should point to SATA interface registers */
- ctlr->r_type2 = SYS_RES_IOPORT;
- ctlr->r_rid2 = PCIR_BAR(5);
- if ((ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2,
- &ctlr->r_rid2, RF_ACTIVE)))
- ctlr->setmode = ata_intel_sata_setmode;
- else
- ctlr->setmode = ata_sata_setmode;
-
- /* enable PCI interrupt */
- pci_write_config(dev, PCIR_COMMAND,
- pci_read_config(dev, PCIR_COMMAND, 2) & ~0x0400, 2);
- }
- return 0;
-}
-
-static int
-ata_intel_allocate(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
-
- /* setup the usual register normal pci style */
- if (ata_pci_allocate(dev))
- return ENXIO;
-
- /* if r_res2 is valid it points to SATA interface registers */
- if (ctlr->r_res2) {
- ch->r_io[ATA_IDX_ADDR].res = ctlr->r_res2;
- ch->r_io[ATA_IDX_ADDR].offset = 0x00;
- ch->r_io[ATA_IDX_DATA].res = ctlr->r_res2;
- ch->r_io[ATA_IDX_DATA].offset = 0x04;
- }
-
- ch->flags |= ATA_ALWAYS_DMASTAT;
- return 0;
-}
-
-static void
-ata_intel_reset(device_t dev)
-{
- device_t parent = device_get_parent(dev);
- struct ata_pci_controller *ctlr = device_get_softc(parent);
- struct ata_channel *ch = device_get_softc(dev);
- int mask, timeout;
-
- /* ICH6 & ICH7 in compat mode has 4 SATA ports as master/slave on 2 ch's */
- if (ctlr->chip->cfg1) {
- mask = (0x0005 << ch->unit);
- }
- else {
- /* ICH5 in compat mode has SATA ports as master/slave on 1 channel */
- if (pci_read_config(parent, 0x90, 1) & 0x04)
- mask = 0x0003;
- else {
- mask = (0x0001 << ch->unit);
- /* XXX SOS should be in intel_allocate if we grow it */
- ch->flags |= ATA_NO_SLAVE;
- }
- }
- pci_write_config(parent, 0x92, pci_read_config(parent, 0x92, 2) & ~mask, 2);
- DELAY(10);
- pci_write_config(parent, 0x92, pci_read_config(parent, 0x92, 2) | mask, 2);
-
- /* wait up to 1 sec for "connect well" */
- for (timeout = 0; timeout < 100 ; timeout++) {
- if (((pci_read_config(parent, 0x92, 2) & (mask << 4)) == (mask << 4)) &&
- (ATA_IDX_INB(ch, ATA_STATUS) != 0xff))
- break;
- ata_udelay(10000);
- }
- ata_generic_reset(dev);
-}
-
-static void
-ata_intel_old_setmode(device_t dev, int mode)
-{
- /* NOT YET */
-}
-
-static void
-ata_intel_new_setmode(device_t dev, int mode)
-{
- device_t gparent = GRANDPARENT(dev);
- struct ata_pci_controller *ctlr = device_get_softc(gparent);
- struct ata_channel *ch = device_get_softc(device_get_parent(dev));
- struct ata_device *atadev = device_get_softc(dev);
- int devno = (ch->unit << 1) + atadev->unit;
- u_int32_t reg40 = pci_read_config(gparent, 0x40, 4);
- u_int8_t reg44 = pci_read_config(gparent, 0x44, 1);
- u_int8_t reg48 = pci_read_config(gparent, 0x48, 1);
- u_int16_t reg4a = pci_read_config(gparent, 0x4a, 2);
- u_int16_t reg54 = pci_read_config(gparent, 0x54, 2);
- u_int32_t mask40 = 0, new40 = 0;
- u_int8_t mask44 = 0, new44 = 0;
- int error;
- u_int8_t timings[] = { 0x00, 0x00, 0x10, 0x21, 0x23, 0x10, 0x21, 0x23,
- 0x23, 0x23, 0x23, 0x23, 0x23, 0x23 };
-
- mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma);
-
- if ( mode > ATA_UDMA2 && !(reg54 & (0x10 << devno))) {
- ata_print_cable(dev, "controller");
- mode = ATA_UDMA2;
- }
-
- error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
-
- if (bootverbose)
- device_printf(dev, "%ssetting %s on %s chip\n",
- (error) ? "FAILURE " : "",
- ata_mode2str(mode), ctlr->chip->text);
- if (!error) {
- if (mode >= ATA_UDMA0) {
- u_int8_t utimings[] = { 0x00, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10 };
-
- pci_write_config(gparent, 0x48, reg48 | (0x0001 << devno), 2);
- pci_write_config(gparent, 0x4a,
- (reg4a & ~(0x3 << (devno << 2))) |
- (utimings[mode & ATA_MODE_MASK] << (devno<<2)), 2);
- }
- else {
- pci_write_config(gparent, 0x48, reg48 & ~(0x0001 << devno), 2);
- pci_write_config(gparent, 0x4a, (reg4a & ~(0x3 << (devno << 2))),2);
- }
- reg54 |= 0x0400;
- if (mode >= ATA_UDMA2)
- reg54 |= (0x1 << devno);
- else
- reg54 &= ~(0x1 << devno);
- if (mode >= ATA_UDMA5)
- reg54 |= (0x1000 << devno);
- else
- reg54 &= ~(0x1000 << devno);
-
- pci_write_config(gparent, 0x54, reg54, 2);
-
- reg40 &= ~0x00ff00ff;
- reg40 |= 0x40774077;
-
- if (atadev->unit == ATA_MASTER) {
- mask40 = 0x3300;
- new40 = timings[ata_mode2idx(mode)] << 8;
- }
- else {
- mask44 = 0x0f;
- new44 = ((timings[ata_mode2idx(mode)] & 0x30) >> 2) |
- (timings[ata_mode2idx(mode)] & 0x03);
- }
- if (ch->unit) {
- mask40 <<= 16;
- new40 <<= 16;
- mask44 <<= 4;
- new44 <<= 4;
- }
- pci_write_config(gparent, 0x40, (reg40 & ~mask40) | new40, 4);
- pci_write_config(gparent, 0x44, (reg44 & ~mask44) | new44, 1);
-
- atadev->mode = mode;
- }
-}
-
-static void
-ata_intel_sata_setmode(device_t dev, int mode)
-{
- struct ata_device *atadev = device_get_softc(dev);
-
- if (atadev->param.satacapabilities != 0x0000 &&
- atadev->param.satacapabilities != 0xffff) {
-
- struct ata_channel *ch = device_get_softc(device_get_parent(dev));
- int devno = (ch->unit << 1) + atadev->unit;
-
- /* on some drives we need to set the transfer mode */
- ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0,
- ata_limit_mode(dev, mode, ATA_UDMA6));
-
- /* set ATA_SSTATUS register offset */
- ATA_IDX_OUTL(ch, ATA_IDX_ADDR, devno * 0x100);
-
- /* query SATA STATUS for the speed */
- if ((ATA_IDX_INL(ch, ATA_IDX_DATA) & ATA_SS_CONWELL_MASK) ==
- ATA_SS_CONWELL_GEN2)
- atadev->mode = ATA_SA300;
- else
- atadev->mode = ATA_SA150;
- }
- else {
- mode = ata_limit_mode(dev, mode, ATA_UDMA5);
- if (!ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode))
- atadev->mode = mode;
- }
-}
-
-static int
-ata_intel_31244_allocate(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
- int i;
- int ch_offset;
-
- ch_offset = 0x200 + ch->unit * 0x200;
-
- for (i = ATA_DATA; i < ATA_MAX_RES; i++)
- ch->r_io[i].res = ctlr->r_res2;
-
- /* setup ATA registers */
- ch->r_io[ATA_DATA].offset = ch_offset + 0x00;
- ch->r_io[ATA_FEATURE].offset = ch_offset + 0x06;
- ch->r_io[ATA_COUNT].offset = ch_offset + 0x08;
- ch->r_io[ATA_SECTOR].offset = ch_offset + 0x0c;
- ch->r_io[ATA_CYL_LSB].offset = ch_offset + 0x10;
- ch->r_io[ATA_CYL_MSB].offset = ch_offset + 0x14;
- ch->r_io[ATA_DRIVE].offset = ch_offset + 0x18;
- ch->r_io[ATA_COMMAND].offset = ch_offset + 0x1d;
- ch->r_io[ATA_ERROR].offset = ch_offset + 0x04;
- ch->r_io[ATA_STATUS].offset = ch_offset + 0x1c;
- ch->r_io[ATA_ALTSTAT].offset = ch_offset + 0x28;
- ch->r_io[ATA_CONTROL].offset = ch_offset + 0x29;
-
- /* setup DMA registers */
- ch->r_io[ATA_SSTATUS].offset = ch_offset + 0x100;
- ch->r_io[ATA_SERROR].offset = ch_offset + 0x104;
- ch->r_io[ATA_SCONTROL].offset = ch_offset + 0x108;
-
- /* setup SATA registers */
- ch->r_io[ATA_BMCMD_PORT].offset = ch_offset + 0x70;
- ch->r_io[ATA_BMSTAT_PORT].offset = ch_offset + 0x72;
- ch->r_io[ATA_BMDTP_PORT].offset = ch_offset + 0x74;
-
- ch->flags |= ATA_NO_SLAVE;
- ata_pci_hw(dev);
- ch->hw.status = ata_intel_31244_status;
- ch->hw.tf_write = ata_intel_31244_tf_write;
-
- /* enable PHY state change interrupt */
- ATA_OUTL(ctlr->r_res2, 0x4,
- ATA_INL(ctlr->r_res2, 0x04) | (0x01 << (ch->unit << 3)));
- return 0;
-}
-
-static int
-ata_intel_31244_status(device_t dev)
-{
- /* do we have any PHY events ? */
- ata_sata_phy_check_events(dev);
-
- /* any drive action to take care of ? */
- return ata_pci_status(dev);
-}
-
-static void
-ata_intel_31244_tf_write(struct ata_request *request)
-{
- struct ata_channel *ch = device_get_softc(device_get_parent(request->dev));
- struct ata_device *atadev = device_get_softc(request->dev);
-
- if (atadev->flags & ATA_D_48BIT_ACTIVE) {
- ATA_IDX_OUTW(ch, ATA_FEATURE, request->u.ata.feature);
- ATA_IDX_OUTW(ch, ATA_COUNT, request->u.ata.count);
- ATA_IDX_OUTW(ch, ATA_SECTOR, ((request->u.ata.lba >> 16) & 0xff00) |
- (request->u.ata.lba & 0x00ff));
- ATA_IDX_OUTW(ch, ATA_CYL_LSB, ((request->u.ata.lba >> 24) & 0xff00) |
- ((request->u.ata.lba >> 8) & 0x00ff));
- ATA_IDX_OUTW(ch, ATA_CYL_MSB, ((request->u.ata.lba >> 32) & 0xff00) |
- ((request->u.ata.lba >> 16) & 0x00ff));
- ATA_IDX_OUTW(ch, ATA_DRIVE, ATA_D_LBA | ATA_DEV(atadev->unit));
- }
- else {
- ATA_IDX_OUTB(ch, ATA_FEATURE, request->u.ata.feature);
- ATA_IDX_OUTB(ch, ATA_COUNT, request->u.ata.count);
- if (atadev->flags & ATA_D_USE_CHS) {
- int heads, sectors;
-
- if (atadev->param.atavalid & ATA_FLAG_54_58) {
- heads = atadev->param.current_heads;
- sectors = atadev->param.current_sectors;
- }
- else {
- heads = atadev->param.heads;
- sectors = atadev->param.sectors;
- }
- ATA_IDX_OUTB(ch, ATA_SECTOR, (request->u.ata.lba % sectors)+1);
- ATA_IDX_OUTB(ch, ATA_CYL_LSB,
- (request->u.ata.lba / (sectors * heads)));
- ATA_IDX_OUTB(ch, ATA_CYL_MSB,
- (request->u.ata.lba / (sectors * heads)) >> 8);
- ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(atadev->unit) |
- (((request->u.ata.lba% (sectors * heads)) /
- sectors) & 0xf));
- }
- else {
- ATA_IDX_OUTB(ch, ATA_SECTOR, request->u.ata.lba);
- ATA_IDX_OUTB(ch, ATA_CYL_LSB, request->u.ata.lba >> 8);
- ATA_IDX_OUTB(ch, ATA_CYL_MSB, request->u.ata.lba >> 16);
- ATA_IDX_OUTB(ch, ATA_DRIVE,
- ATA_D_IBM | ATA_D_LBA | ATA_DEV(atadev->unit) |
- ((request->u.ata.lba >> 24) & 0x0f));
- }
- }
-}
-
-static void
-ata_intel_31244_reset(device_t dev)
-{
- if (ata_sata_phy_reset(dev))
- ata_generic_reset(dev);
-}
-
-
-/*
- * Integrated Technology Express Inc. (ITE) chipset support functions
- */
-int
-ata_ite_ident(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
- static struct ata_chip_id ids[] =
- {{ ATA_IT8213F, 0x00, 0x00, 0x00, ATA_UDMA6, "IT8213F" },
- { ATA_IT8212F, 0x00, 0x00, 0x00, ATA_UDMA6, "IT8212F" },
- { ATA_IT8211F, 0x00, 0x00, 0x00, ATA_UDMA6, "IT8211F" },
- { 0, 0, 0, 0, 0, 0}};
-
- if (!(ctlr->chip = ata_match_chip(dev, ids)))
- return ENXIO;
-
- ata_set_desc(dev);
- ctlr->chipinit = ata_ite_chipinit;
- return 0;
-}
-
-static int
-ata_ite_chipinit(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
-
- if (ata_setup_interrupt(dev))
- return ENXIO;
-
- if (ctlr->chip->chipid == ATA_IT8213F) {
- /* the ITE 8213F only has one channel */
- ctlr->channels = 1;
-
- ctlr->setmode = ata_ite_8213_setmode;
- }
- else {
- /* set PCI mode and 66Mhz reference clock */
- pci_write_config(dev, 0x50, pci_read_config(dev, 0x50, 1) & ~0x83, 1);
-
- /* set default active & recover timings */
- pci_write_config(dev, 0x54, 0x31, 1);
- pci_write_config(dev, 0x56, 0x31, 1);
-
- ctlr->setmode = ata_ite_821x_setmode;
- }
-
- return 0;
-}
-
-static void
-ata_ite_821x_setmode(device_t dev, int mode)
-{
- device_t gparent = GRANDPARENT(dev);
- struct ata_channel *ch = device_get_softc(device_get_parent(dev));
- struct ata_device *atadev = device_get_softc(dev);
- int devno = (ch->unit << 1) + atadev->unit;
- int error;
-
- /* correct the mode for what the HW supports */
- mode = ata_limit_mode(dev, mode, ATA_UDMA6);
-
- /* check the CBLID bits for 80 conductor cable detection */
- if (mode > ATA_UDMA2 && (pci_read_config(gparent, 0x40, 2) &
- (ch->unit ? (1<<3) : (1<<2)))) {
- ata_print_cable(dev, "controller");
- mode = ATA_UDMA2;
- }
-
- /* set the wanted mode on the device */
- error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
-
- if (bootverbose)
- device_printf(dev, "%s setting %s on ITE8212F chip\n",
- (error) ? "failed" : "success", ata_mode2str(mode));
-
- /* if the device accepted the mode change, setup the HW accordingly */
- if (!error) {
- if (mode >= ATA_UDMA0) {
- u_int8_t udmatiming[] =
- { 0x44, 0x42, 0x31, 0x21, 0x11, 0xa2, 0x91 };
-
- /* enable UDMA mode */
- pci_write_config(gparent, 0x50,
- pci_read_config(gparent, 0x50, 1) &
- ~(1 << (devno + 3)), 1);
-
- /* set UDMA timing */
- pci_write_config(gparent,
- 0x56 + (ch->unit << 2) + atadev->unit,
- udmatiming[mode & ATA_MODE_MASK], 1);
- }
- else {
- u_int8_t chtiming[] =
- { 0xaa, 0xa3, 0xa1, 0x33, 0x31, 0x88, 0x32, 0x31 };
-
- /* disable UDMA mode */
- pci_write_config(gparent, 0x50,
- pci_read_config(gparent, 0x50, 1) |
- (1 << (devno + 3)), 1);
-
- /* set active and recover timing (shared between master & slave) */
- if (pci_read_config(gparent, 0x54 + (ch->unit << 2), 1) <
- chtiming[ata_mode2idx(mode)])
- pci_write_config(gparent, 0x54 + (ch->unit << 2),
- chtiming[ata_mode2idx(mode)], 1);
- }
- atadev->mode = mode;
- }
-}
-
-static void
-ata_ite_8213_setmode(device_t dev, int mode)
-{
- device_t gparent = GRANDPARENT(dev);
- struct ata_pci_controller *ctlr = device_get_softc(gparent);
- struct ata_device *atadev = device_get_softc(dev);
- u_int16_t reg40 = pci_read_config(gparent, 0x40, 2);
- u_int8_t reg44 = pci_read_config(gparent, 0x44, 1);
- u_int8_t reg48 = pci_read_config(gparent, 0x48, 1);
- u_int16_t reg4a = pci_read_config(gparent, 0x4a, 2);
- u_int16_t reg54 = pci_read_config(gparent, 0x54, 2);
- u_int16_t mask40 = 0, new40 = 0;
- u_int8_t mask44 = 0, new44 = 0;
- int devno = atadev->unit;
- int error;
- u_int8_t timings[] = { 0x00, 0x00, 0x10, 0x21, 0x23, 0x10, 0x21, 0x23,
- 0x23, 0x23, 0x23, 0x23, 0x23, 0x23 };
-
- mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma);
-
- if (mode > ATA_UDMA2 && !(reg54 & (0x10 << devno))) {
- ata_print_cable(dev, "controller");
- mode = ATA_UDMA2;
- }
-
- error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
-
- if (bootverbose)
- device_printf(dev, "%ssetting %s on %s chip\n",
- (error) ? "FAILURE " : "",
- ata_mode2str(mode), ctlr->chip->text);
- if (!error) {
- if (mode >= ATA_UDMA0) {
- u_int8_t utimings[] = { 0x00, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10 };
-
- pci_write_config(gparent, 0x48, reg48 | (0x0001 << devno), 2);
- pci_write_config(gparent, 0x4a,
- (reg4a & ~(0x3 << (devno << 2))) |
- (utimings[mode & ATA_MODE_MASK] << (devno<<2)), 2);
- }
- else {
- pci_write_config(gparent, 0x48, reg48 & ~(0x0001 << devno), 2);
- pci_write_config(gparent, 0x4a, (reg4a & ~(0x3 << (devno << 2))),2);
- }
- if (mode >= ATA_UDMA2)
- reg54 |= (0x1 << devno);
- else
- reg54 &= ~(0x1 << devno);
- if (mode >= ATA_UDMA5)
- reg54 |= (0x1000 << devno);
- else
- reg54 &= ~(0x1000 << devno);
- pci_write_config(gparent, 0x54, reg54, 2);
-
- reg40 &= 0xff00;
- reg40 |= 0x4033;
- if (atadev->unit == ATA_MASTER) {
- reg40 |= (ata_atapi(dev) ? 0x04 : 0x00);
- mask40 = 0x3300;
- new40 = timings[ata_mode2idx(mode)] << 8;
- }
- else {
- reg40 |= (ata_atapi(dev) ? 0x40 : 0x00);
- mask44 = 0x0f;
- new44 = ((timings[ata_mode2idx(mode)] & 0x30) >> 2) |
- (timings[ata_mode2idx(mode)] & 0x03);
- }
- pci_write_config(gparent, 0x40, (reg40 & ~mask40) | new40, 4);
- pci_write_config(gparent, 0x44, (reg44 & ~mask44) | new44, 1);
-
- atadev->mode = mode;
- }
-}
-
-
-/*
- * JMicron chipset support functions
- */
-int
-ata_jmicron_ident(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
- struct ata_chip_id *idx;
- static struct ata_chip_id ids[] =
- {{ ATA_JMB360, 0, 1, 0, ATA_SA300, "JMB360" },
- { ATA_JMB361, 0, 1, 1, ATA_SA300, "JMB361" },
- { ATA_JMB363, 0, 2, 1, ATA_SA300, "JMB363" },
- { ATA_JMB365, 0, 1, 2, ATA_SA300, "JMB365" },
- { ATA_JMB366, 0, 2, 2, ATA_SA300, "JMB366" },
- { ATA_JMB368, 0, 0, 1, ATA_UDMA6, "JMB368" },
- { 0, 0, 0, 0, 0, 0}};
- char buffer[64];
-
- if (!(idx = ata_match_chip(dev, ids)))
- return ENXIO;
-
- if ((pci_read_config(dev, 0xdf, 1) & 0x40) &&
- (pci_get_function(dev) == (pci_read_config(dev, 0x40, 1) & 0x02 >> 1)))
- sprintf(buffer, "JMicron %s %s controller",
- idx->text, ata_mode2str(ATA_UDMA6));
- else
- sprintf(buffer, "JMicron %s %s controller",
- idx->text, ata_mode2str(idx->max_dma));
- device_set_desc_copy(dev, buffer);
- ctlr->chip = idx;
- ctlr->chipinit = ata_jmicron_chipinit;
- return 0;
-}
-
-static int
-ata_jmicron_chipinit(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
- int error;
-
- if (ata_setup_interrupt(dev))
- return ENXIO;
-
- /* do we have multiple PCI functions ? */
- if (pci_read_config(dev, 0xdf, 1) & 0x40) {
- /* are we on the AHCI part ? */
- if (ata_ahci_chipinit(dev) != ENXIO)
- return 0;
-
- /* otherwise we are on the PATA part */
- ctlr->allocate = ata_pci_allocate;
- ctlr->reset = ata_generic_reset;
- ctlr->dmainit = ata_pci_dmainit;
- ctlr->setmode = ata_jmicron_setmode;
- ctlr->channels = ctlr->chip->cfg2;
- }
- else {
- /* set controller configuration to a combined setup we support */
- pci_write_config(dev, 0x40, 0x80c0a131, 4);
- pci_write_config(dev, 0x80, 0x01200000, 4);
-
- if (ctlr->chip->cfg1 && (error = ata_ahci_chipinit(dev)))
- return error;
-
- ctlr->allocate = ata_jmicron_allocate;
- ctlr->reset = ata_jmicron_reset;
- ctlr->dmainit = ata_jmicron_dmainit;
- ctlr->setmode = ata_jmicron_setmode;
-
- /* set the number of HW channels */
- ctlr->channels = ctlr->chip->cfg1 + ctlr->chip->cfg2;
- }
- return 0;
-}
-
-static int
-ata_jmicron_allocate(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
- int error;
-
- if (ch->unit >= ctlr->chip->cfg1) {
- ch->unit -= ctlr->chip->cfg1;
- error = ata_pci_allocate(dev);
- ch->unit += ctlr->chip->cfg1;
- }
- else
- error = ata_ahci_allocate(dev);
- return error;
-}
-
-static void
-ata_jmicron_reset(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
-
- if (ch->unit >= ctlr->chip->cfg1)
- ata_generic_reset(dev);
- else
- ata_ahci_reset(dev);
-}
-
-static void
-ata_jmicron_dmainit(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
-
- if (ch->unit >= ctlr->chip->cfg1)
- ata_pci_dmainit(dev);
- else
- ata_ahci_dmainit(dev);
-}
-
-static void
-ata_jmicron_setmode(device_t dev, int mode)
-{
- struct ata_pci_controller *ctlr = device_get_softc(GRANDPARENT(dev));
- struct ata_channel *ch = device_get_softc(device_get_parent(dev));
-
- if (pci_read_config(dev, 0xdf, 1) & 0x40 || ch->unit >= ctlr->chip->cfg1) {
- struct ata_device *atadev = device_get_softc(dev);
-
- /* check for 80pin cable present */
- if (pci_read_config(dev, 0x40, 1) & 0x08)
- mode = ata_limit_mode(dev, mode, ATA_UDMA2);
- else
- mode = ata_limit_mode(dev, mode, ATA_UDMA6);
-
- if (!ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode))
- atadev->mode = mode;
- }
- else
- ata_sata_setmode(dev, mode);
-}
-
-
-/*
- * Marvell chipset support functions
- */
-#define ATA_MV_HOST_BASE(ch) \
- ((ch->unit & 3) * 0x0100) + (ch->unit > 3 ? 0x30000 : 0x20000)
-#define ATA_MV_EDMA_BASE(ch) \
- ((ch->unit & 3) * 0x2000) + (ch->unit > 3 ? 0x30000 : 0x20000)
-
-struct ata_marvell_response {
- u_int16_t tag;
- u_int8_t edma_status;
- u_int8_t dev_status;
- u_int32_t timestamp;
-};
-
-struct ata_marvell_dma_prdentry {
- u_int32_t addrlo;
- u_int32_t count;
- u_int32_t addrhi;
- u_int32_t reserved;
-};
-
-int
-ata_marvell_ident(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
- static struct ata_chip_id ids[] =
- {{ ATA_M88SX5040, 0, 4, MV50XX, ATA_SA150, "88SX5040" },
- { ATA_M88SX5041, 0, 4, MV50XX, ATA_SA150, "88SX5041" },
- { ATA_M88SX5080, 0, 8, MV50XX, ATA_SA150, "88SX5080" },
- { ATA_M88SX5081, 0, 8, MV50XX, ATA_SA150, "88SX5081" },
- { ATA_M88SX6041, 0, 4, MV60XX, ATA_SA300, "88SX6041" },
- { ATA_M88SX6081, 0, 8, MV60XX, ATA_SA300, "88SX6081" },
- { ATA_M88SX6101, 0, 1, MV61XX, ATA_UDMA6, "88SX6101" },
- { ATA_M88SX6145, 0, 2, MV61XX, ATA_UDMA6, "88SX6145" },
- { 0, 0, 0, 0, 0, 0}};
-
- if (!(ctlr->chip = ata_match_chip(dev, ids)))
- return ENXIO;
-
- ata_set_desc(dev);
-
- switch (ctlr->chip->cfg2) {
- case MV50XX:
- case MV60XX:
- ctlr->chipinit = ata_marvell_edma_chipinit;
- break;
- case MV61XX:
- ctlr->chipinit = ata_marvell_pata_chipinit;
- break;
- }
- return 0;
-}
-
-static int
-ata_marvell_pata_chipinit(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
-
- if (ata_setup_interrupt(dev))
- return ENXIO;
-
- ctlr->allocate = ata_marvell_pata_allocate;
- ctlr->setmode = ata_marvell_pata_setmode;
- ctlr->channels = ctlr->chip->cfg1;
- return 0;
-}
-
-static int
-ata_marvell_pata_allocate(device_t dev)
-{
- struct ata_channel *ch = device_get_softc(dev);
-
- /* setup the usual register normal pci style */
- if (ata_pci_allocate(dev))
- return ENXIO;
-
- /* dont use 32 bit PIO transfers */
- ch->flags |= ATA_USE_16BIT;
-
- return 0;
-}
-
-static void
-ata_marvell_pata_setmode(device_t dev, int mode)
-{
- device_t gparent = GRANDPARENT(dev);
- struct ata_pci_controller *ctlr = device_get_softc(gparent);
- struct ata_device *atadev = device_get_softc(dev);
-
- mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma);
- mode = ata_check_80pin(dev, mode);
- if (!ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode))
- atadev->mode = mode;
-}
-
-static int
-ata_marvell_edma_chipinit(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
-
- if (ata_setup_interrupt(dev))
- return ENXIO;
-
- ctlr->r_type1 = SYS_RES_MEMORY;
- ctlr->r_rid1 = PCIR_BAR(0);
- if (!(ctlr->r_res1 = bus_alloc_resource_any(dev, ctlr->r_type1,
- &ctlr->r_rid1, RF_ACTIVE)))
- return ENXIO;
-
- /* mask all host controller interrupts */
- ATA_OUTL(ctlr->r_res1, 0x01d64, 0x00000000);
-
- /* mask all PCI interrupts */
- ATA_OUTL(ctlr->r_res1, 0x01d5c, 0x00000000);
-
- ctlr->allocate = ata_marvell_edma_allocate;
- ctlr->reset = ata_marvell_edma_reset;
- ctlr->dmainit = ata_marvell_edma_dmainit;
- ctlr->setmode = ata_sata_setmode;
- ctlr->channels = ctlr->chip->cfg1;
-
- /* clear host controller interrupts */
- ATA_OUTL(ctlr->r_res1, 0x20014, 0x00000000);
- if (ctlr->chip->cfg1 > 4)
- ATA_OUTL(ctlr->r_res1, 0x30014, 0x00000000);
-
- /* clear PCI interrupts */
- ATA_OUTL(ctlr->r_res1, 0x01d58, 0x00000000);
-
- /* unmask PCI interrupts we want */
- ATA_OUTL(ctlr->r_res1, 0x01d5c, 0x007fffff);
-
- /* unmask host controller interrupts we want */
- ATA_OUTL(ctlr->r_res1, 0x01d64, 0x000000ff/*HC0*/ | 0x0001fe00/*HC1*/ |
- /*(1<<19) | (1<<20) | (1<<21) |*/(1<<22) | (1<<24) | (0x7f << 25));
-
- /* enable PCI interrupt */
- pci_write_config(dev, PCIR_COMMAND,
- pci_read_config(dev, PCIR_COMMAND, 2) & ~0x0400, 2);
- return 0;
-}
-
-static int
-ata_marvell_edma_allocate(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
- u_int64_t work = ch->dma.work_bus;
- int i;
-
- /* clear work area */
- bzero(ch->dma.work, 1024+256);
-
- /* set legacy ATA resources */
- for (i = ATA_DATA; i <= ATA_COMMAND; i++) {
- ch->r_io[i].res = ctlr->r_res1;
- ch->r_io[i].offset = 0x02100 + (i << 2) + ATA_MV_EDMA_BASE(ch);
- }
- ch->r_io[ATA_CONTROL].res = ctlr->r_res1;
- ch->r_io[ATA_CONTROL].offset = 0x02120 + ATA_MV_EDMA_BASE(ch);
- ch->r_io[ATA_IDX_ADDR].res = ctlr->r_res1;
- ata_default_registers(dev);
-
- /* set SATA resources */
- switch (ctlr->chip->cfg2) {
- case MV50XX:
- ch->r_io[ATA_SSTATUS].res = ctlr->r_res1;
- ch->r_io[ATA_SSTATUS].offset = 0x00100 + ATA_MV_HOST_BASE(ch);
- ch->r_io[ATA_SERROR].res = ctlr->r_res1;
- ch->r_io[ATA_SERROR].offset = 0x00104 + ATA_MV_HOST_BASE(ch);
- ch->r_io[ATA_SCONTROL].res = ctlr->r_res1;
- ch->r_io[ATA_SCONTROL].offset = 0x00108 + ATA_MV_HOST_BASE(ch);
- break;
- case MV60XX:
- ch->r_io[ATA_SSTATUS].res = ctlr->r_res1;
- ch->r_io[ATA_SSTATUS].offset = 0x02300 + ATA_MV_EDMA_BASE(ch);
- ch->r_io[ATA_SERROR].res = ctlr->r_res1;
- ch->r_io[ATA_SERROR].offset = 0x02304 + ATA_MV_EDMA_BASE(ch);
- ch->r_io[ATA_SCONTROL].res = ctlr->r_res1;
- ch->r_io[ATA_SCONTROL].offset = 0x02308 + ATA_MV_EDMA_BASE(ch);
- ch->r_io[ATA_SACTIVE].res = ctlr->r_res1;
- ch->r_io[ATA_SACTIVE].offset = 0x02350 + ATA_MV_EDMA_BASE(ch);
- break;
- }
-
- ch->flags |= ATA_NO_SLAVE;
- ch->flags |= ATA_USE_16BIT; /* XXX SOS needed ? */
- ata_generic_hw(dev);
- ch->hw.begin_transaction = ata_marvell_edma_begin_transaction;
- ch->hw.end_transaction = ata_marvell_edma_end_transaction;
- ch->hw.status = ata_marvell_edma_status;
-
- /* disable the EDMA machinery */
- ATA_OUTL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch), 0x00000002);
- DELAY(100000); /* SOS should poll for disabled */
-
- /* set configuration to non-queued 128b read transfers stop on error */
- ATA_OUTL(ctlr->r_res1, 0x02000 + ATA_MV_EDMA_BASE(ch), (1<<11) | (1<<13));
-
- /* request queue base high */
- ATA_OUTL(ctlr->r_res1, 0x02010 + ATA_MV_EDMA_BASE(ch), work >> 32);
-
- /* request queue in ptr */
- ATA_OUTL(ctlr->r_res1, 0x02014 + ATA_MV_EDMA_BASE(ch), work & 0xffffffff);
-
- /* request queue out ptr */
- ATA_OUTL(ctlr->r_res1, 0x02018 + ATA_MV_EDMA_BASE(ch), 0x0);
-
- /* response queue base high */
- work += 1024;
- ATA_OUTL(ctlr->r_res1, 0x0201c + ATA_MV_EDMA_BASE(ch), work >> 32);
-
- /* response queue in ptr */
- ATA_OUTL(ctlr->r_res1, 0x02020 + ATA_MV_EDMA_BASE(ch), 0x0);
-
- /* response queue out ptr */
- ATA_OUTL(ctlr->r_res1, 0x02024 + ATA_MV_EDMA_BASE(ch), work & 0xffffffff);
-
- /* clear SATA error register */
- ATA_IDX_OUTL(ch, ATA_SERROR, ATA_IDX_INL(ch, ATA_SERROR));
-
- /* clear any outstanding error interrupts */
- ATA_OUTL(ctlr->r_res1, 0x02008 + ATA_MV_EDMA_BASE(ch), 0x0);
-
- /* unmask all error interrupts */
- ATA_OUTL(ctlr->r_res1, 0x0200c + ATA_MV_EDMA_BASE(ch), ~0x0);
-
- /* enable EDMA machinery */
- ATA_OUTL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch), 0x00000001);
- return 0;
-}
-
-static int
-ata_marvell_edma_status(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
- u_int32_t cause = ATA_INL(ctlr->r_res1, 0x01d60);
- int shift = (ch->unit << 1) + (ch->unit > 3);
-
- if (cause & (1 << shift)) {
-
- /* clear interrupt(s) */
- ATA_OUTL(ctlr->r_res1, 0x02008 + ATA_MV_EDMA_BASE(ch), 0x0);
-
- /* do we have any PHY events ? */
- ata_sata_phy_check_events(dev);
- }
-
- /* do we have any device action ? */
- return (cause & (2 << shift));
-}
-
-/* must be called with ATA channel locked and state_mtx held */
-static int
-ata_marvell_edma_begin_transaction(struct ata_request *request)
-{
- struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev));
- struct ata_channel *ch = device_get_softc(request->parent);
- u_int32_t req_in;
- u_int8_t *bytep;
- u_int16_t *wordp;
- u_int32_t *quadp;
- int i;
- int error, slot;
-
- /* only DMA R/W goes through the EMDA machine */
- if (request->u.ata.command != ATA_READ_DMA &&
- request->u.ata.command != ATA_WRITE_DMA) {
-
- /* disable the EDMA machinery */
- if (ATA_INL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch)) & 0x00000001)
- ATA_OUTL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch), 0x00000002);
- return ata_begin_transaction(request);
- }
-
- /* check for 48 bit access and convert if needed */
- ata_modify_if_48bit(request);
-
- /* check sanity, setup SG list and DMA engine */
- if ((error = ch->dma.load(request, NULL, NULL))) {
- device_printf(request->dev, "setting up DMA failed\n");
- request->result = error;
- return ATA_OP_FINISHED;
- }
-
- /* get next free request queue slot */
- req_in = ATA_INL(ctlr->r_res1, 0x02014 + ATA_MV_EDMA_BASE(ch));
- slot = (((req_in & ~0xfffffc00) >> 5) + 0) & 0x1f;
- bytep = (u_int8_t *)(ch->dma.work);
- bytep += (slot << 5);
- wordp = (u_int16_t *)bytep;
- quadp = (u_int32_t *)bytep;
-
- /* fill in this request */
- quadp[0] = (long)request->dma->sg_bus & 0xffffffff;
- quadp[1] = (u_int64_t)request->dma->sg_bus >> 32;
- wordp[4] = (request->flags & ATA_R_READ ? 0x01 : 0x00) | (request->tag<<1);
-
- i = 10;
- bytep[i++] = (request->u.ata.count >> 8) & 0xff;
- bytep[i++] = 0x10 | ATA_COUNT;
- bytep[i++] = request->u.ata.count & 0xff;
- bytep[i++] = 0x10 | ATA_COUNT;
-
- bytep[i++] = (request->u.ata.lba >> 24) & 0xff;
- bytep[i++] = 0x10 | ATA_SECTOR;
- bytep[i++] = request->u.ata.lba & 0xff;
- bytep[i++] = 0x10 | ATA_SECTOR;
-
- bytep[i++] = (request->u.ata.lba >> 32) & 0xff;
- bytep[i++] = 0x10 | ATA_CYL_LSB;
- bytep[i++] = (request->u.ata.lba >> 8) & 0xff;
- bytep[i++] = 0x10 | ATA_CYL_LSB;
-
- bytep[i++] = (request->u.ata.lba >> 40) & 0xff;
- bytep[i++] = 0x10 | ATA_CYL_MSB;
- bytep[i++] = (request->u.ata.lba >> 16) & 0xff;
- bytep[i++] = 0x10 | ATA_CYL_MSB;
-
- bytep[i++] = ATA_D_LBA | ATA_D_IBM | ((request->u.ata.lba >> 24) & 0xf);
- bytep[i++] = 0x10 | ATA_DRIVE;
-
- bytep[i++] = request->u.ata.command;
- bytep[i++] = 0x90 | ATA_COMMAND;
-
- /* enable EDMA machinery if needed */
- if (!(ATA_INL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch)) & 0x00000001)) {
- ATA_OUTL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch), 0x00000001);
- while (!(ATA_INL(ctlr->r_res1,
- 0x02028 + ATA_MV_EDMA_BASE(ch)) & 0x00000001))
- DELAY(10);
- }
-
- /* tell EDMA it has a new request */
- slot = (((req_in & ~0xfffffc00) >> 5) + 1) & 0x1f;
- req_in &= 0xfffffc00;
- req_in += (slot << 5);
- ATA_OUTL(ctlr->r_res1, 0x02014 + ATA_MV_EDMA_BASE(ch), req_in);
-
- return ATA_OP_CONTINUES;
-}
-
-/* must be called with ATA channel locked and state_mtx held */
-static int
-ata_marvell_edma_end_transaction(struct ata_request *request)
-{
- struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev));
- struct ata_channel *ch = device_get_softc(request->parent);
- int offset = (ch->unit > 3 ? 0x30014 : 0x20014);
- u_int32_t icr = ATA_INL(ctlr->r_res1, offset);
- int res;
-
- /* EDMA interrupt */
- if ((icr & (0x0001 << (ch->unit & 3)))) {
- struct ata_marvell_response *response;
- u_int32_t rsp_in, rsp_out;
- int slot;
-
- /* stop timeout */
- callout_stop(&request->callout);
-
- /* get response ptr's */
- rsp_in = ATA_INL(ctlr->r_res1, 0x02020 + ATA_MV_EDMA_BASE(ch));
- rsp_out = ATA_INL(ctlr->r_res1, 0x02024 + ATA_MV_EDMA_BASE(ch));
- slot = (((rsp_in & ~0xffffff00) >> 3)) & 0x1f;
- rsp_out &= 0xffffff00;
- rsp_out += (slot << 3);
- response = (struct ata_marvell_response *)
- (ch->dma.work + 1024 + (slot << 3));
-
- /* record status for this request */
- request->status = response->dev_status;
- request->error = 0;
-
- /* ack response */
- ATA_OUTL(ctlr->r_res1, 0x02024 + ATA_MV_EDMA_BASE(ch), rsp_out);
-
- /* update progress */
- if (!(request->status & ATA_S_ERROR) &&
- !(request->flags & ATA_R_TIMEOUT))
- request->donecount = request->bytecount;
-
- /* unload SG list */
- ch->dma.unload(request);
-
- res = ATA_OP_FINISHED;
- }
-
- /* legacy ATA interrupt */
- else {
- res = ata_end_transaction(request);
- }
-
- /* ack interrupt */
- ATA_OUTL(ctlr->r_res1, offset, ~(icr & (0x0101 << (ch->unit & 3))));
- return res;
-}
-
-static void
-ata_marvell_edma_reset(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
-
- /* disable the EDMA machinery */
- ATA_OUTL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch), 0x00000002);
- while ((ATA_INL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch)) & 0x00000001))
- DELAY(10);
-
- /* clear SATA error register */
- ATA_IDX_OUTL(ch, ATA_SERROR, ATA_IDX_INL(ch, ATA_SERROR));
-
- /* clear any outstanding error interrupts */
- ATA_OUTL(ctlr->r_res1, 0x02008 + ATA_MV_EDMA_BASE(ch), 0x0);
-
- /* unmask all error interrupts */
- ATA_OUTL(ctlr->r_res1, 0x0200c + ATA_MV_EDMA_BASE(ch), ~0x0);
-
- /* enable channel and test for devices */
- if (ata_sata_phy_reset(dev))
- ata_generic_reset(dev);
-
- /* enable EDMA machinery */
- ATA_OUTL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch), 0x00000001);
-}
-
-static void
-ata_marvell_edma_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs,
- int error)
-{
- struct ata_dmasetprd_args *args = xsc;
- struct ata_marvell_dma_prdentry *prd = args->dmatab;
- int i;
-
- if ((args->error = error))
- return;
-
- for (i = 0; i < nsegs; i++) {
- prd[i].addrlo = htole32(segs[i].ds_addr);
- prd[i].count = htole32(segs[i].ds_len);
- prd[i].addrhi = htole32((u_int64_t)segs[i].ds_addr >> 32);
- }
- prd[i - 1].count |= htole32(ATA_DMA_EOT);
- KASSERT(nsegs <= ATA_DMA_ENTRIES, ("too many DMA segment entries\n"));
- args->nsegs = nsegs;
-}
-
-static void
-ata_marvell_edma_dmainit(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
-
- ata_dmainit(dev);
- /* note start and stop are not used here */
- ch->dma.setprd = ata_marvell_edma_dmasetprd;
-
- /* if 64bit support present adjust max address used */
- if (ATA_INL(ctlr->r_res1, 0x00d00) & 0x00000004)
- ch->dma.max_address = BUS_SPACE_MAXADDR;
-
- /* chip does not reliably do 64K DMA transfers */
- ch->dma.max_iosize = 126 * DEV_BSIZE;
-}
-
-
-/*
- * National chipset support functions
- */
-int
-ata_national_ident(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
-
- /* this chip is a clone of the Cyrix chip, bugs and all */
- if (pci_get_devid(dev) == ATA_SC1100) {
- device_set_desc(dev, "National Geode SC1100 ATA33 controller");
- ctlr->chipinit = ata_national_chipinit;
- return 0;
- }
- return ENXIO;
-}
-
-static int
-ata_national_chipinit(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
-
- if (ata_setup_interrupt(dev))
- return ENXIO;
-
- ctlr->setmode = ata_national_setmode;
- return 0;
-}
-
-static void
-ata_national_setmode(device_t dev, int mode)
-{
- device_t gparent = GRANDPARENT(dev);
- struct ata_channel *ch = device_get_softc(device_get_parent(dev));
- struct ata_device *atadev = device_get_softc(dev);
- int devno = (ch->unit << 1) + atadev->unit;
- u_int32_t piotiming[] =
- { 0x9172d132, 0x21717121, 0x00803020, 0x20102010, 0x00100010,
- 0x00803020, 0x20102010, 0x00100010,
- 0x00100010, 0x00100010, 0x00100010 };
- u_int32_t dmatiming[] = { 0x80077771, 0x80012121, 0x80002020 };
- u_int32_t udmatiming[] = { 0x80921250, 0x80911140, 0x80911030 };
- int error;
-
- ch->dma.alignment = 16;
- ch->dma.max_iosize = 126 * DEV_BSIZE;
-
- mode = ata_limit_mode(dev, mode, ATA_UDMA2);
-
- error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
-
- if (bootverbose)
- device_printf(dev, "%s setting %s on National chip\n",
- (error) ? "failed" : "success", ata_mode2str(mode));
- if (!error) {
- if (mode >= ATA_UDMA0) {
- pci_write_config(gparent, 0x44 + (devno << 3),
- udmatiming[mode & ATA_MODE_MASK], 4);
- }
- else if (mode >= ATA_WDMA0) {
- pci_write_config(gparent, 0x44 + (devno << 3),
- dmatiming[mode & ATA_MODE_MASK], 4);
- }
- else {
- pci_write_config(gparent, 0x44 + (devno << 3),
- pci_read_config(gparent, 0x44 + (devno << 3), 4) |
- 0x80000000, 4);
- }
- pci_write_config(gparent, 0x40 + (devno << 3),
- piotiming[ata_mode2idx(mode)], 4);
- atadev->mode = mode;
- }
-}
-
-
-/*
- * NetCell chipset support functions
- */
-int
-ata_netcell_ident(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
-
- if (pci_get_devid(dev) == ATA_NETCELL_SR) {
- device_set_desc(dev, "Netcell SyncRAID SR3000/5000 RAID Controller");
- ctlr->chipinit = ata_netcell_chipinit;
- return 0;
- }
- return ENXIO;
-}
-
-static int
-ata_netcell_chipinit(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
-
- if (ata_generic_chipinit(dev))
- return ENXIO;
-
- ctlr->allocate = ata_netcell_allocate;
- return 0;
-}
-
-static int
-ata_netcell_allocate(device_t dev)
-{
- struct ata_channel *ch = device_get_softc(dev);
-
- /* setup the usual register normal pci style */
- if (ata_pci_allocate(dev))
- return ENXIO;
-
- /* the NetCell only supports 16 bit PIO transfers */
- ch->flags |= ATA_USE_16BIT;
-
- return 0;
-}
-
-
-/*
- * nVidia chipset support functions
- */
-int
-ata_nvidia_ident(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
- static struct ata_chip_id ids[] =
- {{ ATA_NFORCE1, 0, AMDNVIDIA, NVIDIA, ATA_UDMA5, "nForce" },
- { ATA_NFORCE2, 0, AMDNVIDIA, NVIDIA, ATA_UDMA6, "nForce2" },
- { ATA_NFORCE2_PRO, 0, AMDNVIDIA, NVIDIA, ATA_UDMA6, "nForce2 Pro" },
- { ATA_NFORCE2_PRO_S1, 0, 0, 0, ATA_SA150, "nForce2 Pro" },
- { ATA_NFORCE3, 0, AMDNVIDIA, NVIDIA, ATA_UDMA6, "nForce3" },
- { ATA_NFORCE3_PRO, 0, AMDNVIDIA, NVIDIA, ATA_UDMA6, "nForce3 Pro" },
- { ATA_NFORCE3_PRO_S1, 0, 0, 0, ATA_SA150, "nForce3 Pro" },
- { ATA_NFORCE3_PRO_S2, 0, 0, 0, ATA_SA150, "nForce3 Pro" },
- { ATA_NFORCE_MCP04, 0, AMDNVIDIA, NVIDIA, ATA_UDMA6, "nForce MCP" },
- { ATA_NFORCE_MCP04_S1, 0, 0, NV4, ATA_SA150, "nForce MCP" },
- { ATA_NFORCE_MCP04_S2, 0, 0, NV4, ATA_SA150, "nForce MCP" },
- { ATA_NFORCE_CK804, 0, AMDNVIDIA, NVIDIA, ATA_UDMA6, "nForce CK804" },
- { ATA_NFORCE_CK804_S1, 0, 0, NV4, ATA_SA300, "nForce CK804" },
- { ATA_NFORCE_CK804_S2, 0, 0, NV4, ATA_SA300, "nForce CK804" },
- { ATA_NFORCE_MCP51, 0, AMDNVIDIA, NVIDIA, ATA_UDMA6, "nForce MCP51" },
- { ATA_NFORCE_MCP51_S1, 0, 0, NV4|NVQ, ATA_SA300, "nForce MCP51" },
- { ATA_NFORCE_MCP51_S2, 0, 0, NV4|NVQ, ATA_SA300, "nForce MCP51" },
- { ATA_NFORCE_MCP55, 0, AMDNVIDIA, NVIDIA, ATA_UDMA6, "nForce MCP55" },
- { ATA_NFORCE_MCP55_S1, 0, 0, NV4|NVQ, ATA_SA300, "nForce MCP55" },
- { ATA_NFORCE_MCP55_S2, 0, 0, NV4|NVQ, ATA_SA300, "nForce MCP55" },
- { ATA_NFORCE_MCP61, 0, AMDNVIDIA, NVIDIA, ATA_UDMA6, "nForce MCP61" },
- { ATA_NFORCE_MCP61_S1, 0, 0, NV4|NVQ, ATA_SA300, "nForce MCP61" },
- { ATA_NFORCE_MCP61_S2, 0, 0, NV4|NVQ, ATA_SA300, "nForce MCP61" },
- { ATA_NFORCE_MCP61_S3, 0, 0, NV4|NVQ, ATA_SA300, "nForce MCP61" },
- { ATA_NFORCE_MCP65, 0, AMDNVIDIA, NVIDIA, ATA_UDMA6, "nForce MCP65" },
- { ATA_NFORCE_MCP67, 0, AMDNVIDIA, NVIDIA, ATA_UDMA6, "nForce MCP67" },
- { ATA_NFORCE_MCP73, 0, AMDNVIDIA, NVIDIA, ATA_UDMA6, "nForce MCP73" },
- { ATA_NFORCE_MCP77, 0, AMDNVIDIA, NVIDIA, ATA_UDMA6, "nForce MCP77" },
- { 0, 0, 0, 0, 0, 0}} ;
-
- if (!(ctlr->chip = ata_match_chip(dev, ids)))
- return ENXIO;
-
- ata_set_desc(dev);
- ctlr->chipinit = ata_nvidia_chipinit;
- return 0;
-}
-
-static int
-ata_nvidia_chipinit(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
-
- if (ata_setup_interrupt(dev))
- return ENXIO;
-
- if (ctlr->chip->max_dma >= ATA_SA150) {
- if (pci_read_config(dev, PCIR_BAR(5), 1) & 1)
- ctlr->r_type2 = SYS_RES_IOPORT;
- else
- ctlr->r_type2 = SYS_RES_MEMORY;
- ctlr->r_rid2 = PCIR_BAR(5);
- if ((ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2,
- &ctlr->r_rid2, RF_ACTIVE))) {
- int offset = ctlr->chip->cfg2 & NV4 ? 0x0440 : 0x0010;
-
- ctlr->allocate = ata_nvidia_allocate;
- ctlr->reset = ata_nvidia_reset;
-
- /* enable control access */
- pci_write_config(dev, 0x50, pci_read_config(dev, 0x50, 1) | 0x04,1);
-
- if (ctlr->chip->cfg2 & NVQ) {
- /* clear interrupt status */
- ATA_OUTL(ctlr->r_res2, offset, 0x00ff00ff);
-
- /* enable device and PHY state change interrupts */
- ATA_OUTL(ctlr->r_res2, offset + 4, 0x000d000d);
-
- /* disable NCQ support */
- ATA_OUTL(ctlr->r_res2, 0x0400,
- ATA_INL(ctlr->r_res2, 0x0400) & 0xfffffff9);
- }
- else {
- /* clear interrupt status */
- ATA_OUTB(ctlr->r_res2, offset, 0xff);
-
- /* enable device and PHY state change interrupts */
- ATA_OUTB(ctlr->r_res2, offset + 1, 0xdd);
- }
-
- /* enable PCI interrupt */
- pci_write_config(dev, PCIR_COMMAND,
- pci_read_config(dev, PCIR_COMMAND, 2) & ~0x0400,2);
-
- }
- ctlr->setmode = ata_sata_setmode;
- }
- else {
- /* disable prefetch, postwrite */
- pci_write_config(dev, 0x51, pci_read_config(dev, 0x51, 1) & 0x0f, 1);
- ctlr->setmode = ata_via_family_setmode;
- }
- return 0;
-}
-
-static int
-ata_nvidia_allocate(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
-
- /* setup the usual register normal pci style */
- if (ata_pci_allocate(dev))
- return ENXIO;
-
- ch->r_io[ATA_SSTATUS].res = ctlr->r_res2;
- ch->r_io[ATA_SSTATUS].offset = (ch->unit << 6);
- ch->r_io[ATA_SERROR].res = ctlr->r_res2;
- ch->r_io[ATA_SERROR].offset = 0x04 + (ch->unit << 6);
- ch->r_io[ATA_SCONTROL].res = ctlr->r_res2;
- ch->r_io[ATA_SCONTROL].offset = 0x08 + (ch->unit << 6);
-
- ch->hw.status = ata_nvidia_status;
- ch->flags |= ATA_NO_SLAVE;
-
- return 0;
-}
-
-static int
-ata_nvidia_status(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
- int offset = ctlr->chip->cfg2 & NV4 ? 0x0440 : 0x0010;
- int shift = ch->unit << (ctlr->chip->cfg2 & NVQ ? 4 : 2);
- u_int32_t istatus;
-
- /* get interrupt status */
- if (ctlr->chip->cfg2 & NVQ)
- istatus = ATA_INL(ctlr->r_res2, offset);
- else
- istatus = ATA_INB(ctlr->r_res2, offset);
-
- /* do we have any PHY events ? */
- if (istatus & (0x0c << shift))
- ata_sata_phy_check_events(dev);
-
- /* clear interrupt(s) */
- if (ctlr->chip->cfg2 & NVQ)
- ATA_OUTL(ctlr->r_res2, offset, (0x0f << shift) | 0x00f000f0);
- else
- ATA_OUTB(ctlr->r_res2, offset, (0x0f << shift));
-
- /* do we have any device action ? */
- return (istatus & (0x01 << shift));
-}
-
-static void
-ata_nvidia_reset(device_t dev)
-{
- if (ata_sata_phy_reset(dev))
- ata_generic_reset(dev);
-}
-
-
-/*
- * Promise chipset support functions
- */
-#define ATA_PDC_APKT_OFFSET 0x00000010
-#define ATA_PDC_HPKT_OFFSET 0x00000040
-#define ATA_PDC_ASG_OFFSET 0x00000080
-#define ATA_PDC_LSG_OFFSET 0x000000c0
-#define ATA_PDC_HSG_OFFSET 0x00000100
-#define ATA_PDC_CHN_OFFSET 0x00000400
-#define ATA_PDC_BUF_BASE 0x00400000
-#define ATA_PDC_BUF_OFFSET 0x00100000
-#define ATA_PDC_MAX_HPKT 8
-#define ATA_PDC_WRITE_REG 0x00
-#define ATA_PDC_WRITE_CTL 0x0e
-#define ATA_PDC_WRITE_END 0x08
-#define ATA_PDC_WAIT_NBUSY 0x10
-#define ATA_PDC_WAIT_READY 0x18
-#define ATA_PDC_1B 0x20
-#define ATA_PDC_2B 0x40
-
-struct host_packet {
-u_int32_t addr;
- TAILQ_ENTRY(host_packet) chain;
-};
-
-struct ata_promise_sx4 {
- struct mtx mtx;
- TAILQ_HEAD(, host_packet) queue;
- int busy;
-};
-
-int
-ata_promise_ident(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
- struct ata_chip_id *idx;
- static struct ata_chip_id ids[] =
- {{ ATA_PDC20246, 0, PROLD, 0x00, ATA_UDMA2, "PDC20246" },
- { ATA_PDC20262, 0, PRNEW, 0x00, ATA_UDMA4, "PDC20262" },
- { ATA_PDC20263, 0, PRNEW, 0x00, ATA_UDMA4, "PDC20263" },
- { ATA_PDC20265, 0, PRNEW, 0x00, ATA_UDMA5, "PDC20265" },
- { ATA_PDC20267, 0, PRNEW, 0x00, ATA_UDMA5, "PDC20267" },
- { ATA_PDC20268, 0, PRTX, PRTX4, ATA_UDMA5, "PDC20268" },
- { ATA_PDC20269, 0, PRTX, 0x00, ATA_UDMA6, "PDC20269" },
- { ATA_PDC20270, 0, PRTX, PRTX4, ATA_UDMA5, "PDC20270" },
- { ATA_PDC20271, 0, PRTX, 0x00, ATA_UDMA6, "PDC20271" },
- { ATA_PDC20275, 0, PRTX, 0x00, ATA_UDMA6, "PDC20275" },
- { ATA_PDC20276, 0, PRTX, PRSX6K, ATA_UDMA6, "PDC20276" },
- { ATA_PDC20277, 0, PRTX, 0x00, ATA_UDMA6, "PDC20277" },
- { ATA_PDC20318, 0, PRMIO, PRSATA, ATA_SA150, "PDC20318" },
- { ATA_PDC20319, 0, PRMIO, PRSATA, ATA_SA150, "PDC20319" },
- { ATA_PDC20371, 0, PRMIO, PRCMBO, ATA_SA150, "PDC20371" },
- { ATA_PDC20375, 0, PRMIO, PRCMBO, ATA_SA150, "PDC20375" },
- { ATA_PDC20376, 0, PRMIO, PRCMBO, ATA_SA150, "PDC20376" },
- { ATA_PDC20377, 0, PRMIO, PRCMBO, ATA_SA150, "PDC20377" },
- { ATA_PDC20378, 0, PRMIO, PRCMBO, ATA_SA150, "PDC20378" },
- { ATA_PDC20379, 0, PRMIO, PRCMBO, ATA_SA150, "PDC20379" },
- { ATA_PDC20571, 0, PRMIO, PRCMBO2, ATA_SA150, "PDC20571" },
- { ATA_PDC20575, 0, PRMIO, PRCMBO2, ATA_SA150, "PDC20575" },
- { ATA_PDC20579, 0, PRMIO, PRCMBO2, ATA_SA150, "PDC20579" },
- { ATA_PDC20771, 0, PRMIO, PRCMBO2, ATA_SA300, "PDC20771" },
- { ATA_PDC40775, 0, PRMIO, PRCMBO2, ATA_SA300, "PDC40775" },
- { ATA_PDC20617, 0, PRMIO, PRPATA, ATA_UDMA6, "PDC20617" },
- { ATA_PDC20618, 0, PRMIO, PRPATA, ATA_UDMA6, "PDC20618" },
- { ATA_PDC20619, 0, PRMIO, PRPATA, ATA_UDMA6, "PDC20619" },
- { ATA_PDC20620, 0, PRMIO, PRPATA, ATA_UDMA6, "PDC20620" },
- { ATA_PDC20621, 0, PRMIO, PRSX4X, ATA_UDMA5, "PDC20621" },
- { ATA_PDC20622, 0, PRMIO, PRSX4X, ATA_SA150, "PDC20622" },
- { ATA_PDC40518, 0, PRMIO, PRSATA2, ATA_SA150, "PDC40518" },
- { ATA_PDC40519, 0, PRMIO, PRSATA2, ATA_SA150, "PDC40519" },
- { ATA_PDC40718, 0, PRMIO, PRSATA2, ATA_SA300, "PDC40718" },
- { ATA_PDC40719, 0, PRMIO, PRSATA2, ATA_SA300, "PDC40719" },
- { ATA_PDC40779, 0, PRMIO, PRSATA2, ATA_SA300, "PDC40779" },
- { 0, 0, 0, 0, 0, 0}};
- char buffer[64];
- uintptr_t devid = 0;
-
- if (!(idx = ata_match_chip(dev, ids)))
- return ENXIO;
-
- /* if we are on a SuperTrak SX6000 dont attach */
- if ((idx->cfg2 & PRSX6K) && pci_get_class(GRANDPARENT(dev))==PCIC_BRIDGE &&
- !BUS_READ_IVAR(device_get_parent(GRANDPARENT(dev)),
- GRANDPARENT(dev), PCI_IVAR_DEVID, &devid) &&
- devid == ATA_I960RM)
- return ENXIO;
-
- strcpy(buffer, "Promise ");
- strcat(buffer, idx->text);
-
- /* if we are on a FastTrak TX4, adjust the interrupt resource */
- if ((idx->cfg2 & PRTX4) && pci_get_class(GRANDPARENT(dev))==PCIC_BRIDGE &&
- !BUS_READ_IVAR(device_get_parent(GRANDPARENT(dev)),
- GRANDPARENT(dev), PCI_IVAR_DEVID, &devid) &&
- ((devid == ATA_DEC_21150) || (devid == ATA_DEC_21150_1))) {
- static long start = 0, end = 0;
-
- if (pci_get_slot(dev) == 1) {
- bus_get_resource(dev, SYS_RES_IRQ, 0, &start, &end);
- strcat(buffer, " (channel 0+1)");
- }
- else if (pci_get_slot(dev) == 2 && start && end) {
- bus_set_resource(dev, SYS_RES_IRQ, 0, start, end);
- strcat(buffer, " (channel 2+3)");
- }
- else {
- start = end = 0;
- }
- }
- sprintf(buffer, "%s %s controller", buffer, ata_mode2str(idx->max_dma));
- device_set_desc_copy(dev, buffer);
- ctlr->chip = idx;
- ctlr->chipinit = ata_promise_chipinit;
- return 0;
-}
-
-static int
-ata_promise_chipinit(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
- int fake_reg, stat_reg;
-
- if (ata_setup_interrupt(dev))
- return ENXIO;
-
- switch (ctlr->chip->cfg1) {
- case PRNEW:
- /* setup clocks */
- ATA_OUTB(ctlr->r_res1, 0x11, ATA_INB(ctlr->r_res1, 0x11) | 0x0a);
-
- ctlr->dmainit = ata_promise_dmainit;
- /* FALLTHROUGH */
-
- case PROLD:
- /* enable burst mode */
- ATA_OUTB(ctlr->r_res1, 0x1f, ATA_INB(ctlr->r_res1, 0x1f) | 0x01);
- ctlr->allocate = ata_promise_allocate;
- ctlr->setmode = ata_promise_setmode;
- return 0;
-
- case PRTX:
- ctlr->allocate = ata_promise_tx2_allocate;
- ctlr->setmode = ata_promise_setmode;
- return 0;
-
- case PRMIO:
- ctlr->r_type1 = SYS_RES_MEMORY;
- ctlr->r_rid1 = PCIR_BAR(4);
- if (!(ctlr->r_res1 = bus_alloc_resource_any(dev, ctlr->r_type1,
- &ctlr->r_rid1, RF_ACTIVE)))
- goto failnfree;
-
- ctlr->r_type2 = SYS_RES_MEMORY;
- ctlr->r_rid2 = PCIR_BAR(3);
- if (!(ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2,
- &ctlr->r_rid2, RF_ACTIVE)))
- goto failnfree;
-
- if (ctlr->chip->cfg2 == PRSX4X) {
- struct ata_promise_sx4 *hpkt;
- u_int32_t dimm = ATA_INL(ctlr->r_res2, 0x000c0080);
-
- if (bus_teardown_intr(dev, ctlr->r_irq, ctlr->handle) ||
- bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, NULL,
- ata_promise_sx4_intr, ctlr, &ctlr->handle)) {
- device_printf(dev, "unable to setup interrupt\n");
- goto failnfree;
- }
-
- /* print info about cache memory */
- device_printf(dev, "DIMM size %dMB @ 0x%08x%s\n",
- (((dimm >> 16) & 0xff)-((dimm >> 24) & 0xff)+1) << 4,
- ((dimm >> 24) & 0xff),
- ATA_INL(ctlr->r_res2, 0x000c0088) & (1<<16) ?
- " ECC enabled" : "" );
-
- /* adjust cache memory parameters */
- ATA_OUTL(ctlr->r_res2, 0x000c000c,
- (ATA_INL(ctlr->r_res2, 0x000c000c) & 0xffff0000));
-
- /* setup host packet controls */
- hpkt = malloc(sizeof(struct ata_promise_sx4),
- M_TEMP, M_NOWAIT | M_ZERO);
- mtx_init(&hpkt->mtx, "ATA promise HPKT lock", NULL, MTX_DEF);
- TAILQ_INIT(&hpkt->queue);
- hpkt->busy = 0;
- device_set_ivars(dev, hpkt);
- ctlr->allocate = ata_promise_mio_allocate;
- ctlr->reset = ata_promise_mio_reset;
- ctlr->dmainit = ata_promise_mio_dmainit;
- ctlr->setmode = ata_promise_setmode;
- ctlr->channels = 4;
- return 0;
- }
-
- /* mio type controllers need an interrupt intercept */
- if (bus_teardown_intr(dev, ctlr->r_irq, ctlr->handle) ||
- bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, NULL,
- ata_promise_mio_intr, ctlr, &ctlr->handle)) {
- device_printf(dev, "unable to setup interrupt\n");
- goto failnfree;
- }
-
- switch (ctlr->chip->cfg2) {
- case PRPATA:
- ctlr->channels = ((ATA_INL(ctlr->r_res2, 0x48) & 0x01) > 0) +
- ((ATA_INL(ctlr->r_res2, 0x48) & 0x02) > 0) + 2;
- goto sata150;
- case PRCMBO:
- ctlr->channels = 3;
- goto sata150;
- case PRSATA:
- ctlr->channels = 4;
-sata150:
- fake_reg = 0x60;
- stat_reg = 0x6c;
- break;
-
- case PRCMBO2:
- ctlr->channels = 3;
- goto sataii;
- case PRSATA2:
- default:
- ctlr->channels = 4;
-sataii:
- fake_reg = 0x54;
- stat_reg = 0x60;
- break;
- }
-
- /* prime fake interrupt register */
- ATA_OUTL(ctlr->r_res2, fake_reg, 0xffffffff);
-
- /* clear SATA status and unmask interrupts */
- ATA_OUTL(ctlr->r_res2, stat_reg, 0x000000ff);
-
- /* enable "long burst length" on gen2 chips */
- if ((ctlr->chip->cfg2 == PRSATA2) || (ctlr->chip->cfg2 == PRCMBO2))
- ATA_OUTL(ctlr->r_res2, 0x44, ATA_INL(ctlr->r_res2, 0x44) | 0x2000);
-
- ctlr->allocate = ata_promise_mio_allocate;
- ctlr->reset = ata_promise_mio_reset;
- ctlr->dmainit = ata_promise_mio_dmainit;
- ctlr->setmode = ata_promise_mio_setmode;
-
- return 0;
- }
-
-failnfree:
- if (ctlr->r_res2)
- bus_release_resource(dev, ctlr->r_type2, ctlr->r_rid2, ctlr->r_res2);
- if (ctlr->r_res1)
- bus_release_resource(dev, ctlr->r_type1, ctlr->r_rid1, ctlr->r_res1);
- return ENXIO;
-}
-
-static int
-ata_promise_allocate(device_t dev)
-{
- struct ata_channel *ch = device_get_softc(dev);
-
- if (ata_pci_allocate(dev))
- return ENXIO;
-
- ch->hw.status = ata_promise_status;
- return 0;
-}
-
-static int
-ata_promise_status(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
-
- if (ATA_INL(ctlr->r_res1, 0x1c) & (ch->unit ? 0x00004000 : 0x00000400)) {
- return ata_pci_status(dev);
- }
- return 0;
-}
-
-static int
-ata_promise_dmastart(struct ata_request *request)
-{
- struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev));
- struct ata_channel *ch = device_get_softc(request->parent);
- struct ata_device *atadev = device_get_softc(request->dev);
-
- if (atadev->flags & ATA_D_48BIT_ACTIVE) {
- ATA_OUTB(ctlr->r_res1, 0x11,
- ATA_INB(ctlr->r_res1, 0x11) | (ch->unit ? 0x08 : 0x02));
- ATA_OUTL(ctlr->r_res1, ch->unit ? 0x24 : 0x20,
- ((request->flags & ATA_R_READ) ? 0x05000000 : 0x06000000) |
- (request->bytecount >> 1));
- }
- ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, (ATA_IDX_INB(ch, ATA_BMSTAT_PORT) |
- (ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR)));
- ATA_IDX_OUTL(ch, ATA_BMDTP_PORT, request->dma->sg_bus);
- ATA_IDX_OUTB(ch, ATA_BMCMD_PORT,
- ((request->flags & ATA_R_READ) ? ATA_BMCMD_WRITE_READ : 0) |
- ATA_BMCMD_START_STOP);
- ch->dma.flags |= ATA_DMA_ACTIVE;
- return 0;
-}
-
-static int
-ata_promise_dmastop(struct ata_request *request)
-{
- struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev));
- struct ata_channel *ch = device_get_softc(request->parent);
- struct ata_device *atadev = device_get_softc(request->dev);
- int error;
-
- if (atadev->flags & ATA_D_48BIT_ACTIVE) {
- ATA_OUTB(ctlr->r_res1, 0x11,
- ATA_INB(ctlr->r_res1, 0x11) & ~(ch->unit ? 0x08 : 0x02));
- ATA_OUTL(ctlr->r_res1, ch->unit ? 0x24 : 0x20, 0);
- }
- error = ATA_IDX_INB(ch, ATA_BMSTAT_PORT);
- ATA_IDX_OUTB(ch, ATA_BMCMD_PORT,
- ATA_IDX_INB(ch, ATA_BMCMD_PORT) & ~ATA_BMCMD_START_STOP);
- ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR);
- ch->dma.flags &= ~ATA_DMA_ACTIVE;
- return error;
-}
-
-static void
-ata_promise_dmareset(device_t dev)
-{
- struct ata_channel *ch = device_get_softc(dev);
-
- ATA_IDX_OUTB(ch, ATA_BMCMD_PORT,
- ATA_IDX_INB(ch, ATA_BMCMD_PORT) & ~ATA_BMCMD_START_STOP);
- ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR);
- ch->flags &= ~ATA_DMA_ACTIVE;
-}
-
-static void
-ata_promise_dmainit(device_t dev)
-{
- struct ata_channel *ch = device_get_softc(dev);
-
- ata_dmainit(dev);
- ch->dma.start = ata_promise_dmastart;
- ch->dma.stop = ata_promise_dmastop;
- ch->dma.reset = ata_promise_dmareset;
-}
-
-static void
-ata_promise_setmode(device_t dev, int mode)
-{
- device_t gparent = GRANDPARENT(dev);
- struct ata_pci_controller *ctlr = device_get_softc(gparent);
- struct ata_channel *ch = device_get_softc(device_get_parent(dev));
- struct ata_device *atadev = device_get_softc(dev);
- int devno = (ch->unit << 1) + atadev->unit;
- int error;
- u_int32_t timings[][2] = {
- /* PROLD PRNEW mode */
- { 0x004ff329, 0x004fff2f }, /* PIO 0 */
- { 0x004fec25, 0x004ff82a }, /* PIO 1 */
- { 0x004fe823, 0x004ff026 }, /* PIO 2 */
- { 0x004fe622, 0x004fec24 }, /* PIO 3 */
- { 0x004fe421, 0x004fe822 }, /* PIO 4 */
- { 0x004567f3, 0x004acef6 }, /* MWDMA 0 */
- { 0x004467f3, 0x0048cef6 }, /* MWDMA 1 */
- { 0x004367f3, 0x0046cef6 }, /* MWDMA 2 */
- { 0x004367f3, 0x0046cef6 }, /* UDMA 0 */
- { 0x004247f3, 0x00448ef6 }, /* UDMA 1 */
- { 0x004127f3, 0x00436ef6 }, /* UDMA 2 */
- { 0, 0x00424ef6 }, /* UDMA 3 */
- { 0, 0x004127f3 }, /* UDMA 4 */
- { 0, 0x004127f3 } /* UDMA 5 */
- };
-
- mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma);
-
- switch (ctlr->chip->cfg1) {
- case PROLD:
- case PRNEW:
- if (mode > ATA_UDMA2 && (pci_read_config(gparent, 0x50, 2) &
- (ch->unit ? 1 << 11 : 1 << 10))) {
- ata_print_cable(dev, "controller");
- mode = ATA_UDMA2;
- }
- if (ata_atapi(dev) && mode > ATA_PIO_MAX)
- mode = ata_limit_mode(dev, mode, ATA_PIO_MAX);
- break;
-
- case PRTX:
- ATA_IDX_OUTB(ch, ATA_BMDEVSPEC_0, 0x0b);
- if (mode > ATA_UDMA2 &&
- ATA_IDX_INB(ch, ATA_BMDEVSPEC_1) & 0x04) {
- ata_print_cable(dev, "controller");
- mode = ATA_UDMA2;
- }
- break;
-
- case PRMIO:
- if (mode > ATA_UDMA2 &&
- (ATA_INL(ctlr->r_res2,
- (ctlr->chip->cfg2 & PRSX4X ? 0x000c0260 : 0x0260) +
- (ch->unit << 7)) & 0x01000000)) {
- ata_print_cable(dev, "controller");
- mode = ATA_UDMA2;
- }
- break;
- }
-
- error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
-
- if (bootverbose)
- device_printf(dev, "%ssetting %s on %s chip\n",
- (error) ? "FAILURE " : "",
- ata_mode2str(mode), ctlr->chip->text);
- if (!error) {
- if (ctlr->chip->cfg1 < PRTX)
- pci_write_config(gparent, 0x60 + (devno << 2),
- timings[ata_mode2idx(mode)][ctlr->chip->cfg1], 4);
- atadev->mode = mode;
- }
- return;
-}
-
-static int
-ata_promise_tx2_allocate(device_t dev)
-{
- struct ata_channel *ch = device_get_softc(dev);
-
- if (ata_pci_allocate(dev))
- return ENXIO;
-
- ch->hw.status = ata_promise_tx2_status;
- return 0;
-}
-
-static int
-ata_promise_tx2_status(device_t dev)
-{
- struct ata_channel *ch = device_get_softc(dev);
-
- ATA_IDX_OUTB(ch, ATA_BMDEVSPEC_0, 0x0b);
- if (ATA_IDX_INB(ch, ATA_BMDEVSPEC_1) & 0x20) {
- return ata_pci_status(dev);
- }
- return 0;
-}
-
-static int
-ata_promise_mio_allocate(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
- int offset = (ctlr->chip->cfg2 & PRSX4X) ? 0x000c0000 : 0;
- int i;
-
- for (i = ATA_DATA; i <= ATA_COMMAND; i++) {
- ch->r_io[i].res = ctlr->r_res2;
- ch->r_io[i].offset = offset + 0x0200 + (i << 2) + (ch->unit << 7);
- }
- ch->r_io[ATA_CONTROL].res = ctlr->r_res2;
- ch->r_io[ATA_CONTROL].offset = offset + 0x0238 + (ch->unit << 7);
- ch->r_io[ATA_IDX_ADDR].res = ctlr->r_res2;
- ata_default_registers(dev);
- if ((ctlr->chip->cfg2 & (PRSATA | PRSATA2)) ||
- ((ctlr->chip->cfg2 & (PRCMBO | PRCMBO2)) && ch->unit < 2)) {
- ch->r_io[ATA_SSTATUS].res = ctlr->r_res2;
- ch->r_io[ATA_SSTATUS].offset = 0x400 + (ch->unit << 8);
- ch->r_io[ATA_SERROR].res = ctlr->r_res2;
- ch->r_io[ATA_SERROR].offset = 0x404 + (ch->unit << 8);
- ch->r_io[ATA_SCONTROL].res = ctlr->r_res2;
- ch->r_io[ATA_SCONTROL].offset = 0x408 + (ch->unit << 8);
- ch->flags |= ATA_NO_SLAVE;
- }
- ch->flags |= ATA_USE_16BIT;
-
- ata_generic_hw(dev);
- if (ctlr->chip->cfg2 & PRSX4X) {
- ch->hw.command = ata_promise_sx4_command;
- }
- else {
- ch->hw.command = ata_promise_mio_command;
- ch->hw.status = ata_promise_mio_status;
- ch->hw.softreset = ata_promise_mio_softreset;
- ch->hw.pm_read = ata_promise_mio_pm_read;
- ch->hw.pm_write = ata_promise_mio_pm_write;
- }
- return 0;
-}
-
-static void
-ata_promise_mio_intr(void *data)
-{
- struct ata_pci_controller *ctlr = data;
- struct ata_channel *ch;
- u_int32_t vector;
- int unit, fake_reg;
-
- switch (ctlr->chip->cfg2) {
- case PRPATA:
- case PRCMBO:
- case PRSATA:
- fake_reg = 0x60;
- break;
- case PRCMBO2:
- case PRSATA2:
- default:
- fake_reg = 0x54;
- break;
- }
-
- /*
- * since reading interrupt status register on early "mio" chips
- * clears the status bits we cannot read it for each channel later on
- * in the generic interrupt routine.
- * store the bits in an unused register in the chip so we can read
- * it from there safely to get around this "feature".
- */
- vector = ATA_INL(ctlr->r_res2, 0x040);
- ATA_OUTL(ctlr->r_res2, 0x040, vector);
- ATA_OUTL(ctlr->r_res2, fake_reg, vector);
-
- for (unit = 0; unit < ctlr->channels; unit++) {
- if ((ch = ctlr->interrupt[unit].argument))
- ctlr->interrupt[unit].function(ch);
- }
-
- ATA_OUTL(ctlr->r_res2, fake_reg, 0xffffffff);
-}
-
-static int
-ata_promise_mio_status(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
- struct ata_connect_task *tp;
- u_int32_t fake_reg, stat_reg, vector, status;
-
- switch (ctlr->chip->cfg2) {
- case PRPATA:
- case PRCMBO:
- case PRSATA:
- fake_reg = 0x60;
- stat_reg = 0x6c;
- break;
- case PRCMBO2:
- case PRSATA2:
- default:
- fake_reg = 0x54;
- stat_reg = 0x60;
- break;
- }
-
- /* read and acknowledge interrupt */
- vector = ATA_INL(ctlr->r_res2, fake_reg);
-
- /* read and clear interface status */
- status = ATA_INL(ctlr->r_res2, stat_reg);
- ATA_OUTL(ctlr->r_res2, stat_reg, status & (0x00000011 << ch->unit));
-
- /* check for and handle disconnect events */
- if ((status & (0x00000001 << ch->unit)) &&
- (tp = (struct ata_connect_task *)
- malloc(sizeof(struct ata_connect_task),
- M_ATA, M_NOWAIT | M_ZERO))) {
-
- if (bootverbose)
- device_printf(dev, "DISCONNECT requested\n");
- tp->action = ATA_C_DETACH;
- tp->dev = dev;
- TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp);
- taskqueue_enqueue(taskqueue_thread, &tp->task);
- }
-
- /* check for and handle connect events */
- if ((status & (0x00000010 << ch->unit)) &&
- (tp = (struct ata_connect_task *)
- malloc(sizeof(struct ata_connect_task),
- M_ATA, M_NOWAIT | M_ZERO))) {
-
- if (bootverbose)
- device_printf(dev, "CONNECT requested\n");
- tp->action = ATA_C_ATTACH;
- tp->dev = dev;
- TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp);
- taskqueue_enqueue(taskqueue_thread, &tp->task);
- }
-
- /* do we have any device action ? */
- return (vector & (1 << (ch->unit + 1)));
-}
-
-static int
-ata_promise_mio_command(struct ata_request *request)
-{
- struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev));
- struct ata_channel *ch = device_get_softc(request->parent);
- struct ata_device *atadev = device_get_softc(request->dev);
-
- u_int32_t *wordp = (u_int32_t *)ch->dma.work;
-
- ATA_OUTL(ctlr->r_res2, (ch->unit + 1) << 2, 0x00000001);
-
- /* set portmultiplier port */
- ATA_OUTB(ctlr->r_res2, 0x4e8 + (ch->unit << 8), atadev->unit & 0x0f);
-
- /* XXX SOS add ATAPI commands support later */
- switch (request->u.ata.command) {
- default:
- return ata_generic_command(request);
-
- case ATA_READ_DMA:
- case ATA_READ_DMA48:
- wordp[0] = htole32(0x04 | ((ch->unit + 1) << 16) | (0x00 << 24));
- break;
-
- case ATA_WRITE_DMA:
- case ATA_WRITE_DMA48:
- wordp[0] = htole32(0x00 | ((ch->unit + 1) << 16) | (0x00 << 24));
- break;
- }
- wordp[1] = htole32(request->dma->sg_bus);
- wordp[2] = 0;
- ata_promise_apkt((u_int8_t*)wordp, request);
-
- ATA_OUTL(ctlr->r_res2, 0x0240 + (ch->unit << 7), ch->dma.work_bus);
- return 0;
-}
-
-static void
-ata_promise_mio_reset(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
- struct ata_promise_sx4 *hpktp;
-
- switch (ctlr->chip->cfg2) {
- case PRSX4X:
-
- /* softreset channel ATA module */
- hpktp = device_get_ivars(ctlr->dev);
- ATA_OUTL(ctlr->r_res2, 0xc0260 + (ch->unit << 7), ch->unit + 1);
- ata_udelay(1000);
- ATA_OUTL(ctlr->r_res2, 0xc0260 + (ch->unit << 7),
- (ATA_INL(ctlr->r_res2, 0xc0260 + (ch->unit << 7)) &
- ~0x00003f9f) | (ch->unit + 1));
-
- /* softreset HOST module */ /* XXX SOS what about other outstandings */
- mtx_lock(&hpktp->mtx);
- ATA_OUTL(ctlr->r_res2, 0xc012c,
- (ATA_INL(ctlr->r_res2, 0xc012c) & ~0x00000f9f) | (1 << 11));
- DELAY(10);
- ATA_OUTL(ctlr->r_res2, 0xc012c,
- (ATA_INL(ctlr->r_res2, 0xc012c) & ~0x00000f9f));
- hpktp->busy = 0;
- mtx_unlock(&hpktp->mtx);
- ata_generic_reset(dev);
- break;
-
- case PRPATA:
- case PRCMBO:
- case PRSATA:
- if ((ctlr->chip->cfg2 == PRSATA) ||
- ((ctlr->chip->cfg2 == PRCMBO) && (ch->unit < 2))) {
-
- /* mask plug/unplug intr */
- ATA_OUTL(ctlr->r_res2, 0x06c, (0x00110000 << ch->unit));
- }
-
- /* softreset channels ATA module */
- ATA_OUTL(ctlr->r_res2, 0x0260 + (ch->unit << 7), (1 << 11));
- ata_udelay(10000);
- ATA_OUTL(ctlr->r_res2, 0x0260 + (ch->unit << 7),
- (ATA_INL(ctlr->r_res2, 0x0260 + (ch->unit << 7)) &
- ~0x00003f9f) | (ch->unit + 1));
-
- if ((ctlr->chip->cfg2 == PRSATA) ||
- ((ctlr->chip->cfg2 == PRCMBO) && (ch->unit < 2))) {
-
- if (ata_sata_phy_reset(dev))
- ata_generic_reset(dev);
-
- /* reset and enable plug/unplug intr */
- ATA_OUTL(ctlr->r_res2, 0x06c, (0x00000011 << ch->unit));
- }
- else
- ata_generic_reset(dev);
- break;
-
- case PRCMBO2:
- case PRSATA2:
- if ((ctlr->chip->cfg2 == PRSATA2) ||
- ((ctlr->chip->cfg2 == PRCMBO2) && (ch->unit < 2))) {
- /* set portmultiplier port */
- //ATA_OUTL(ctlr->r_res2, 0x4e8 + (ch->unit << 8), 0x0f);
-
- /* mask plug/unplug intr */
- ATA_OUTL(ctlr->r_res2, 0x060, (0x00110000 << ch->unit));
- }
-
- /* softreset channels ATA module */
- ATA_OUTL(ctlr->r_res2, 0x0260 + (ch->unit << 7), (1 << 11));
- ata_udelay(10000);
- ATA_OUTL(ctlr->r_res2, 0x0260 + (ch->unit << 7),
- (ATA_INL(ctlr->r_res2, 0x0260 + (ch->unit << 7)) &
- ~0x00003f9f) | (ch->unit + 1));
-
- if ((ctlr->chip->cfg2 == PRSATA2) ||
- ((ctlr->chip->cfg2 == PRCMBO2) && (ch->unit < 2))) {
-
- /* set PHY mode to "improved" */
- ATA_OUTL(ctlr->r_res2, 0x414 + (ch->unit << 8),
- (ATA_INL(ctlr->r_res2, 0x414 + (ch->unit << 8)) &
- ~0x00000003) | 0x00000001);
-
- if (ata_sata_phy_reset(dev)) {
- u_int32_t signature = ch->hw.softreset(dev, ATA_PM);
-
- if (1 | bootverbose)
- device_printf(dev, "SIGNATURE: %08x\n", signature);
-
- switch (signature) {
- case 0x00000101:
- ch->devices = ATA_ATA_MASTER;
- break;
- case 0x96690101:
- ch->devices = ATA_PORTMULTIPLIER;
- ata_pm_identify(dev);
- break;
- case 0xeb140101:
- ch->devices = ATA_ATAPI_MASTER;
- break;
- default: /* SOS XXX */
- if (bootverbose)
- device_printf(dev,
- "No signature, asuming disk device\n");
- ch->devices = ATA_ATA_MASTER;
- }
- if (bootverbose)
- device_printf(dev, "promise_mio_reset devices=%08x\n",
- ch->devices);
-
- }
-
- /* reset and enable plug/unplug intr */
- ATA_OUTL(ctlr->r_res2, 0x060, (0x00000011 << ch->unit));
-
- ///* set portmultiplier port */
- ATA_OUTL(ctlr->r_res2, 0x4e8 + (ch->unit << 8), 0x00);
- }
- else
- ata_generic_reset(dev);
- break;
-
- }
-}
-
-static int
-ata_promise_mio_pm_read(device_t dev, int port, int reg, u_int32_t *result)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
- int timeout = 0;
-
- /* set portmultiplier port */
- ATA_OUTB(ctlr->r_res2, 0x4e8 + (ch->unit << 8), 0x0f);
-
- ATA_IDX_OUTB(ch, ATA_FEATURE, reg);
- ATA_IDX_OUTB(ch, ATA_DRIVE, port);
-
- ATA_IDX_OUTB(ch, ATA_COMMAND, ATA_READ_PM);
-
- while (timeout < 1000000) {
- u_int8_t status = ATA_IDX_INB(ch, ATA_STATUS);
- if (!(status & ATA_S_BUSY))
- break;
- timeout += 1000;
- DELAY(1000);
- }
- if (timeout >= 1000000)
- return ATA_E_ABORT;
-
- *result = ATA_IDX_INB(ch, ATA_COUNT) |
- (ATA_IDX_INB(ch, ATA_SECTOR) << 8) |
- (ATA_IDX_INB(ch, ATA_CYL_LSB) << 16) |
- (ATA_IDX_INB(ch, ATA_CYL_MSB) << 24);
- return 0;
-}
-
-static int
-ata_promise_mio_pm_write(device_t dev, int port, int reg, u_int32_t value)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
- int timeout = 0;
-
- /* set portmultiplier port */
- ATA_OUTB(ctlr->r_res2, 0x4e8 + (ch->unit << 8), 0x0f);
-
- ATA_IDX_OUTB(ch, ATA_FEATURE, reg);
- ATA_IDX_OUTB(ch, ATA_DRIVE, port);
- ATA_IDX_OUTB(ch, ATA_COUNT, value & 0xff);
- ATA_IDX_OUTB(ch, ATA_SECTOR, (value >> 8) & 0xff);
- ATA_IDX_OUTB(ch, ATA_CYL_LSB, (value >> 16) & 0xff);
- ATA_IDX_OUTB(ch, ATA_CYL_MSB, (value >> 24) & 0xff);
-
- ATA_IDX_OUTB(ch, ATA_COMMAND, ATA_WRITE_PM);
-
- while (timeout < 1000000) {
- u_int8_t status = ATA_IDX_INB(ch, ATA_STATUS);
- if (!(status & ATA_S_BUSY))
- break;
- timeout += 1000;
- DELAY(1000);
- }
- if (timeout >= 1000000)
- return ATA_E_ABORT;
-
- return ATA_IDX_INB(ch, ATA_ERROR);
-}
-
-/* must be called with ATA channel locked and state_mtx held */
-static u_int32_t
-ata_promise_mio_softreset(device_t dev, int port)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
- int timeout;
-
- /* set portmultiplier port */
- ATA_OUTB(ctlr->r_res2, 0x4e8 + (ch->unit << 8), port & 0x0f);
-
- /* softreset device on this channel */
- ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_DEV(ATA_MASTER));
- DELAY(10);
- ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_IDS | ATA_A_RESET);
- ata_udelay(10000);
- ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_IDS);
- ata_udelay(150000);
- ATA_IDX_INB(ch, ATA_ERROR);
-
- /* wait for BUSY to go inactive */
- for (timeout = 0; timeout < 100; timeout++) {
- u_int8_t err, stat;
-
- err = ATA_IDX_INB(ch, ATA_ERROR);
- stat = ATA_IDX_INB(ch, ATA_STATUS);
-
- //if (stat == err && timeout > (stat & ATA_S_BUSY ? 100 : 10))
- //break;
-
- if (!(stat & ATA_S_BUSY)) {
- //if ((err & 0x7f) == ATA_E_ILI) {
- return ATA_IDX_INB(ch, ATA_COUNT) |
- (ATA_IDX_INB(ch, ATA_SECTOR) << 8) |
- (ATA_IDX_INB(ch, ATA_CYL_LSB) << 16) |
- (ATA_IDX_INB(ch, ATA_CYL_MSB) << 24);
- //}
- //else if (stat & 0x0f) {
- //stat |= ATA_S_BUSY;
- //}
- }
-
- if (!(stat & ATA_S_BUSY) || (stat == 0xff && timeout > 10))
- break;
- ata_udelay(100000);
- }
- return -1;
-}
-
-static void
-ata_promise_mio_dmainit(device_t dev)
-{
- struct ata_channel *ch = device_get_softc(dev);
-
- ata_dmainit(dev);
- /* note start and stop are not used here */
- ch->dma.setprd = ata_promise_mio_setprd;
-}
-
-
-#define MAXLASTSGSIZE (32 * sizeof(u_int32_t))
-static void
-ata_promise_mio_setprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error)
-{
- struct ata_dmasetprd_args *args = xsc;
- struct ata_dma_prdentry *prd = args->dmatab;
- int i;
-
- if ((args->error = error))
- return;
-
- for (i = 0; i < nsegs; i++) {
- prd[i].addr = htole32(segs[i].ds_addr);
- prd[i].count = htole32(segs[i].ds_len);
- }
- if (segs[i - 1].ds_len > MAXLASTSGSIZE) {
- //printf("split last SG element of %u\n", segs[i - 1].ds_len);
- prd[i - 1].count = htole32(segs[i - 1].ds_len - MAXLASTSGSIZE);
- prd[i].count = htole32(MAXLASTSGSIZE);
- prd[i].addr = htole32(segs[i - 1].ds_addr +
- (segs[i - 1].ds_len - MAXLASTSGSIZE));
- nsegs++;
- i++;
- }
- prd[i - 1].count |= htole32(ATA_DMA_EOT);
- KASSERT(nsegs <= ATA_DMA_ENTRIES, ("too many DMA segment entries\n"));
- args->nsegs = nsegs;
-}
-
-static void
-ata_promise_mio_setmode(device_t dev, int mode)
-{
- device_t gparent = GRANDPARENT(dev);
- struct ata_pci_controller *ctlr = device_get_softc(gparent);
- struct ata_channel *ch = device_get_softc(device_get_parent(dev));
-
- if ( (ctlr->chip->cfg2 == PRSATA) ||
- ((ctlr->chip->cfg2 == PRCMBO) && (ch->unit < 2)) ||
- (ctlr->chip->cfg2 == PRSATA2) ||
- ((ctlr->chip->cfg2 == PRCMBO2) && (ch->unit < 2)))
- ata_sata_setmode(dev, mode);
- else
- ata_promise_setmode(dev, mode);
-}
-
-static void
-ata_promise_sx4_intr(void *data)
-{
- struct ata_pci_controller *ctlr = data;
- struct ata_channel *ch;
- u_int32_t vector = ATA_INL(ctlr->r_res2, 0x000c0480);
- int unit;
-
- for (unit = 0; unit < ctlr->channels; unit++) {
- if (vector & (1 << (unit + 1)))
- if ((ch = ctlr->interrupt[unit].argument))
- ctlr->interrupt[unit].function(ch);
- if (vector & (1 << (unit + 5)))
- if ((ch = ctlr->interrupt[unit].argument))
- ata_promise_queue_hpkt(ctlr,
- htole32((ch->unit * ATA_PDC_CHN_OFFSET) +
- ATA_PDC_HPKT_OFFSET));
- if (vector & (1 << (unit + 9))) {
- ata_promise_next_hpkt(ctlr);
- if ((ch = ctlr->interrupt[unit].argument))
- ctlr->interrupt[unit].function(ch);
- }
- if (vector & (1 << (unit + 13))) {
- ata_promise_next_hpkt(ctlr);
- if ((ch = ctlr->interrupt[unit].argument))
- ATA_OUTL(ctlr->r_res2, 0x000c0240 + (ch->unit << 7),
- htole32((ch->unit * ATA_PDC_CHN_OFFSET) +
- ATA_PDC_APKT_OFFSET));
- }
- }
-}
-
-static int
-ata_promise_sx4_command(struct ata_request *request)
-{
- device_t gparent = GRANDPARENT(request->dev);
- struct ata_pci_controller *ctlr = device_get_softc(gparent);
- struct ata_channel *ch = device_get_softc(request->parent);
- struct ata_dma_prdentry *prd = request->dma->sg;
- caddr_t window = rman_get_virtual(ctlr->r_res1);
- u_int32_t *wordp;
- int i, idx, length = 0;
-
- /* XXX SOS add ATAPI commands support later */
- switch (request->u.ata.command) {
-
- default:
- return -1;
-
- case ATA_ATA_IDENTIFY:
- case ATA_READ:
- case ATA_READ48:
- case ATA_READ_MUL:
- case ATA_READ_MUL48:
- case ATA_WRITE:
- case ATA_WRITE48:
- case ATA_WRITE_MUL:
- case ATA_WRITE_MUL48:
- ATA_OUTL(ctlr->r_res2, 0x000c0400 + ((ch->unit + 1) << 2), 0x00000001);
- return ata_generic_command(request);
-
- case ATA_SETFEATURES:
- case ATA_FLUSHCACHE:
- case ATA_FLUSHCACHE48:
- case ATA_SLEEP:
- case ATA_SET_MULTI:
- wordp = (u_int32_t *)
- (window + (ch->unit * ATA_PDC_CHN_OFFSET) + ATA_PDC_APKT_OFFSET);
- wordp[0] = htole32(0x08 | ((ch->unit + 1)<<16) | (0x00 << 24));
- wordp[1] = 0;
- wordp[2] = 0;
- ata_promise_apkt((u_int8_t *)wordp, request);
- ATA_OUTL(ctlr->r_res2, 0x000c0484, 0x00000001);
- ATA_OUTL(ctlr->r_res2, 0x000c0400 + ((ch->unit + 1) << 2), 0x00000001);
- ATA_OUTL(ctlr->r_res2, 0x000c0240 + (ch->unit << 7),
- htole32((ch->unit * ATA_PDC_CHN_OFFSET)+ATA_PDC_APKT_OFFSET));
- return 0;
-
- case ATA_READ_DMA:
- case ATA_READ_DMA48:
- case ATA_WRITE_DMA:
- case ATA_WRITE_DMA48:
- wordp = (u_int32_t *)
- (window + (ch->unit * ATA_PDC_CHN_OFFSET) + ATA_PDC_HSG_OFFSET);
- i = idx = 0;
- do {
- wordp[idx++] = prd[i].addr;
- wordp[idx++] = prd[i].count;
- length += (prd[i].count & ~ATA_DMA_EOT);
- } while (!(prd[i++].count & ATA_DMA_EOT));
-
- wordp = (u_int32_t *)
- (window + (ch->unit * ATA_PDC_CHN_OFFSET) + ATA_PDC_LSG_OFFSET);
- wordp[0] = htole32((ch->unit * ATA_PDC_BUF_OFFSET) + ATA_PDC_BUF_BASE);
- wordp[1] = htole32(request->bytecount | ATA_DMA_EOT);
-
- wordp = (u_int32_t *)
- (window + (ch->unit * ATA_PDC_CHN_OFFSET) + ATA_PDC_ASG_OFFSET);
- wordp[0] = htole32((ch->unit * ATA_PDC_BUF_OFFSET) + ATA_PDC_BUF_BASE);
- wordp[1] = htole32(request->bytecount | ATA_DMA_EOT);
-
- wordp = (u_int32_t *)
- (window + (ch->unit * ATA_PDC_CHN_OFFSET) + ATA_PDC_HPKT_OFFSET);
- if (request->flags & ATA_R_READ)
- wordp[0] = htole32(0x14 | ((ch->unit+9)<<16) | ((ch->unit+5)<<24));
- if (request->flags & ATA_R_WRITE)
- wordp[0] = htole32(0x00 | ((ch->unit+13)<<16) | (0x00<<24));
- wordp[1] = htole32((ch->unit * ATA_PDC_CHN_OFFSET)+ATA_PDC_HSG_OFFSET);
- wordp[2] = htole32((ch->unit * ATA_PDC_CHN_OFFSET)+ATA_PDC_LSG_OFFSET);
- wordp[3] = 0;
-
- wordp = (u_int32_t *)
- (window + (ch->unit * ATA_PDC_CHN_OFFSET) + ATA_PDC_APKT_OFFSET);
- if (request->flags & ATA_R_READ)
- wordp[0] = htole32(0x04 | ((ch->unit+5)<<16) | (0x00<<24));
- if (request->flags & ATA_R_WRITE)
- wordp[0] = htole32(0x10 | ((ch->unit+1)<<16) | ((ch->unit+13)<<24));
- wordp[1] = htole32((ch->unit * ATA_PDC_CHN_OFFSET)+ATA_PDC_ASG_OFFSET);
- wordp[2] = 0;
- ata_promise_apkt((u_int8_t *)wordp, request);
- ATA_OUTL(ctlr->r_res2, 0x000c0484, 0x00000001);
-
- if (request->flags & ATA_R_READ) {
- ATA_OUTL(ctlr->r_res2, 0x000c0400 + ((ch->unit+5)<<2), 0x00000001);
- ATA_OUTL(ctlr->r_res2, 0x000c0400 + ((ch->unit+9)<<2), 0x00000001);
- ATA_OUTL(ctlr->r_res2, 0x000c0240 + (ch->unit << 7),
- htole32((ch->unit * ATA_PDC_CHN_OFFSET) + ATA_PDC_APKT_OFFSET));
- }
- if (request->flags & ATA_R_WRITE) {
- ATA_OUTL(ctlr->r_res2, 0x000c0400 + ((ch->unit+1)<<2), 0x00000001);
- ATA_OUTL(ctlr->r_res2, 0x000c0400 + ((ch->unit+13)<<2), 0x00000001);
- ata_promise_queue_hpkt(ctlr,
- htole32((ch->unit * ATA_PDC_CHN_OFFSET) + ATA_PDC_HPKT_OFFSET));
- }
- return 0;
- }
-}
-
-static int
-ata_promise_apkt(u_int8_t *bytep, struct ata_request *request)
-{
- struct ata_device *atadev = device_get_softc(request->dev);
- int i = 12;
-
- bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_REG | ATA_PDC_WAIT_NBUSY|ATA_DRIVE;
- bytep[i++] = ATA_D_IBM | ATA_D_LBA | ATA_DEV(atadev->unit);
- bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_CTL;
- bytep[i++] = ATA_A_4BIT;
-
- if (atadev->flags & ATA_D_48BIT_ACTIVE) {
- bytep[i++] = ATA_PDC_2B | ATA_PDC_WRITE_REG | ATA_FEATURE;
- bytep[i++] = request->u.ata.feature >> 8;
- bytep[i++] = request->u.ata.feature;
- bytep[i++] = ATA_PDC_2B | ATA_PDC_WRITE_REG | ATA_COUNT;
- bytep[i++] = request->u.ata.count >> 8;
- bytep[i++] = request->u.ata.count;
- bytep[i++] = ATA_PDC_2B | ATA_PDC_WRITE_REG | ATA_SECTOR;
- bytep[i++] = request->u.ata.lba >> 24;
- bytep[i++] = request->u.ata.lba;
- bytep[i++] = ATA_PDC_2B | ATA_PDC_WRITE_REG | ATA_CYL_LSB;
- bytep[i++] = request->u.ata.lba >> 32;
- bytep[i++] = request->u.ata.lba >> 8;
- bytep[i++] = ATA_PDC_2B | ATA_PDC_WRITE_REG | ATA_CYL_MSB;
- bytep[i++] = request->u.ata.lba >> 40;
- bytep[i++] = request->u.ata.lba >> 16;
- bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_REG | ATA_DRIVE;
- bytep[i++] = ATA_D_LBA | ATA_DEV(atadev->unit);
- }
- else {
- bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_REG | ATA_FEATURE;
- bytep[i++] = request->u.ata.feature;
- bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_REG | ATA_COUNT;
- bytep[i++] = request->u.ata.count;
- bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_REG | ATA_SECTOR;
- bytep[i++] = request->u.ata.lba;
- bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_REG | ATA_CYL_LSB;
- bytep[i++] = request->u.ata.lba >> 8;
- bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_REG | ATA_CYL_MSB;
- bytep[i++] = request->u.ata.lba >> 16;
- bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_REG | ATA_DRIVE;
- bytep[i++] = (atadev->flags & ATA_D_USE_CHS ? 0 : ATA_D_LBA) |
- ATA_D_IBM | ATA_DEV(atadev->unit) |
- ((request->u.ata.lba >> 24)&0xf);
- }
- bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_END | ATA_COMMAND;
- bytep[i++] = request->u.ata.command;
- return i;
-}
-
-static void
-ata_promise_queue_hpkt(struct ata_pci_controller *ctlr, u_int32_t hpkt)
-{
- struct ata_promise_sx4 *hpktp = device_get_ivars(ctlr->dev);
-
- mtx_lock(&hpktp->mtx);
- if (hpktp->busy) {
- struct host_packet *hp =
- malloc(sizeof(struct host_packet), M_TEMP, M_NOWAIT | M_ZERO);
- hp->addr = hpkt;
- TAILQ_INSERT_TAIL(&hpktp->queue, hp, chain);
- }
- else {
- hpktp->busy = 1;
- ATA_OUTL(ctlr->r_res2, 0x000c0100, hpkt);
- }
- mtx_unlock(&hpktp->mtx);
-}
-
-static void
-ata_promise_next_hpkt(struct ata_pci_controller *ctlr)
-{
- struct ata_promise_sx4 *hpktp = device_get_ivars(ctlr->dev);
- struct host_packet *hp;
-
- mtx_lock(&hpktp->mtx);
- if ((hp = TAILQ_FIRST(&hpktp->queue))) {
- TAILQ_REMOVE(&hpktp->queue, hp, chain);
- ATA_OUTL(ctlr->r_res2, 0x000c0100, hp->addr);
- free(hp, M_TEMP);
- }
- else
- hpktp->busy = 0;
- mtx_unlock(&hpktp->mtx);
-}
-
-
-/*
- * ServerWorks chipset support functions
- */
-int
-ata_serverworks_ident(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
- static struct ata_chip_id ids[] =
- {{ ATA_ROSB4, 0x00, SWKS33, 0, ATA_UDMA2, "ROSB4" },
- { ATA_CSB5, 0x92, SWKS100, 0, ATA_UDMA5, "CSB5" },
- { ATA_CSB5, 0x00, SWKS66, 0, ATA_UDMA4, "CSB5" },
- { ATA_CSB6, 0x00, SWKS100, 0, ATA_UDMA5, "CSB6" },
- { ATA_CSB6_1, 0x00, SWKS66, 0, ATA_UDMA4, "CSB6" },
- { ATA_HT1000, 0x00, SWKS100, 0, ATA_UDMA5, "HT1000" },
- { ATA_HT1000_S1, 0x00, SWKS100, 4, ATA_SA150, "HT1000" },
- { ATA_HT1000_S2, 0x00, SWKSMIO, 4, ATA_SA150, "HT1000" },
- { ATA_K2, 0x00, SWKSMIO, 4, ATA_SA150, "K2" },
- { ATA_FRODO4, 0x00, SWKSMIO, 4, ATA_SA150, "Frodo4" },
- { ATA_FRODO8, 0x00, SWKSMIO, 8, ATA_SA150, "Frodo8" },
- { 0, 0, 0, 0, 0, 0}};
-
- if (!(ctlr->chip = ata_match_chip(dev, ids)))
- return ENXIO;
-
- ata_set_desc(dev);
- ctlr->chipinit = ata_serverworks_chipinit;
- return 0;
-}
-
-static int
-ata_serverworks_chipinit(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
-
- if (ata_setup_interrupt(dev))
- return ENXIO;
-
- if (ctlr->chip->cfg1 == SWKSMIO) {
- ctlr->r_type2 = SYS_RES_MEMORY;
- ctlr->r_rid2 = PCIR_BAR(5);
- if (!(ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2,
- &ctlr->r_rid2, RF_ACTIVE)))
- return ENXIO;
-
- ctlr->channels = ctlr->chip->cfg2;
- ctlr->allocate = ata_serverworks_allocate;
- ctlr->setmode = ata_sata_setmode;
- return 0;
- }
- else if (ctlr->chip->cfg1 == SWKS33) {
- device_t *children;
- int nchildren, i;
-
- /* locate the ISA part in the southbridge and enable UDMA33 */
- if (!device_get_children(device_get_parent(dev), &children,&nchildren)){
- for (i = 0; i < nchildren; i++) {
- if (pci_get_devid(children[i]) == ATA_ROSB4_ISA) {
- pci_write_config(children[i], 0x64,
- (pci_read_config(children[i], 0x64, 4) &
- ~0x00002000) | 0x00004000, 4);
- break;
- }
- }
- free(children, M_TEMP);
- }
- }
- else {
- pci_write_config(dev, 0x5a,
- (pci_read_config(dev, 0x5a, 1) & ~0x40) |
- (ctlr->chip->cfg1 == SWKS100) ? 0x03 : 0x02, 1);
- }
- ctlr->setmode = ata_serverworks_setmode;
- return 0;
-}
-
-static int
-ata_serverworks_allocate(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
- int ch_offset;
- int i;
-
- ch_offset = ch->unit * 0x100;
-
- for (i = ATA_DATA; i < ATA_MAX_RES; i++)
- ch->r_io[i].res = ctlr->r_res2;
-
- /* setup ATA registers */
- ch->r_io[ATA_DATA].offset = ch_offset + 0x00;
- ch->r_io[ATA_FEATURE].offset = ch_offset + 0x04;
- ch->r_io[ATA_COUNT].offset = ch_offset + 0x08;
- ch->r_io[ATA_SECTOR].offset = ch_offset + 0x0c;
- ch->r_io[ATA_CYL_LSB].offset = ch_offset + 0x10;
- ch->r_io[ATA_CYL_MSB].offset = ch_offset + 0x14;
- ch->r_io[ATA_DRIVE].offset = ch_offset + 0x18;
- ch->r_io[ATA_COMMAND].offset = ch_offset + 0x1c;
- ch->r_io[ATA_CONTROL].offset = ch_offset + 0x20;
- ata_default_registers(dev);
-
- /* setup DMA registers */
- ch->r_io[ATA_BMCMD_PORT].offset = ch_offset + 0x30;
- ch->r_io[ATA_BMSTAT_PORT].offset = ch_offset + 0x32;
- ch->r_io[ATA_BMDTP_PORT].offset = ch_offset + 0x34;
-
- /* setup SATA registers */
- ch->r_io[ATA_SSTATUS].offset = ch_offset + 0x40;
- ch->r_io[ATA_SERROR].offset = ch_offset + 0x44;
- ch->r_io[ATA_SCONTROL].offset = ch_offset + 0x48;
-
- ch->flags |= ATA_NO_SLAVE;
- ata_pci_hw(dev);
- ch->hw.tf_read = ata_serverworks_tf_read;
- ch->hw.tf_write = ata_serverworks_tf_write;
-
- /* chip does not reliably do 64K DMA transfers */
- ch->dma.max_iosize = 126 * DEV_BSIZE;
-
- return 0;
-}
-
-static void
-ata_serverworks_tf_read(struct ata_request *request)
-{
- struct ata_channel *ch = device_get_softc(request->parent);
- struct ata_device *atadev = device_get_softc(request->dev);
-
- if (atadev->flags & ATA_D_48BIT_ACTIVE) {
- u_int16_t temp;
-
- request->u.ata.count = ATA_IDX_INW(ch, ATA_COUNT);
- temp = ATA_IDX_INW(ch, ATA_SECTOR);
- request->u.ata.lba = (u_int64_t)(temp & 0x00ff) |
- ((u_int64_t)(temp & 0xff00) << 24);
- temp = ATA_IDX_INW(ch, ATA_CYL_LSB);
- request->u.ata.lba |= ((u_int64_t)(temp & 0x00ff) << 8) |
- ((u_int64_t)(temp & 0xff00) << 32);
- temp = ATA_IDX_INW(ch, ATA_CYL_MSB);
- request->u.ata.lba |= ((u_int64_t)(temp & 0x00ff) << 16) |
- ((u_int64_t)(temp & 0xff00) << 40);
- }
- else {
- request->u.ata.count = ATA_IDX_INW(ch, ATA_COUNT) & 0x00ff;
- request->u.ata.lba = (ATA_IDX_INW(ch, ATA_SECTOR) & 0x00ff) |
- ((ATA_IDX_INW(ch, ATA_CYL_LSB) & 0x00ff) << 8) |
- ((ATA_IDX_INW(ch, ATA_CYL_MSB) & 0x00ff) << 16) |
- ((ATA_IDX_INW(ch, ATA_DRIVE) & 0xf) << 24);
- }
-}
-
-static void
-ata_serverworks_tf_write(struct ata_request *request)
-{
- struct ata_channel *ch = device_get_softc(request->parent);
- struct ata_device *atadev = device_get_softc(request->dev);
-
- if (atadev->flags & ATA_D_48BIT_ACTIVE) {
- ATA_IDX_OUTW(ch, ATA_FEATURE, request->u.ata.feature);
- ATA_IDX_OUTW(ch, ATA_COUNT, request->u.ata.count);
- ATA_IDX_OUTW(ch, ATA_SECTOR, ((request->u.ata.lba >> 16) & 0xff00) |
- (request->u.ata.lba & 0x00ff));
- ATA_IDX_OUTW(ch, ATA_CYL_LSB, ((request->u.ata.lba >> 24) & 0xff00) |
- ((request->u.ata.lba >> 8) & 0x00ff));
- ATA_IDX_OUTW(ch, ATA_CYL_MSB, ((request->u.ata.lba >> 32) & 0xff00) |
- ((request->u.ata.lba >> 16) & 0x00ff));
- ATA_IDX_OUTW(ch, ATA_DRIVE, ATA_D_LBA | ATA_DEV(atadev->unit));
- }
- else {
- ATA_IDX_OUTW(ch, ATA_FEATURE, request->u.ata.feature);
- ATA_IDX_OUTW(ch, ATA_COUNT, request->u.ata.count);
- if (atadev->flags & ATA_D_USE_CHS) {
- int heads, sectors;
-
- if (atadev->param.atavalid & ATA_FLAG_54_58) {
- heads = atadev->param.current_heads;
- sectors = atadev->param.current_sectors;
- }
- else {
- heads = atadev->param.heads;
- sectors = atadev->param.sectors;
- }
- ATA_IDX_OUTW(ch, ATA_SECTOR, (request->u.ata.lba % sectors)+1);
- ATA_IDX_OUTW(ch, ATA_CYL_LSB,
- (request->u.ata.lba / (sectors * heads)));
- ATA_IDX_OUTW(ch, ATA_CYL_MSB,
- (request->u.ata.lba / (sectors * heads)) >> 8);
- ATA_IDX_OUTW(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(atadev->unit) |
- (((request->u.ata.lba% (sectors * heads)) /
- sectors) & 0xf));
- }
- else {
- ATA_IDX_OUTW(ch, ATA_SECTOR, request->u.ata.lba);
- ATA_IDX_OUTW(ch, ATA_CYL_LSB, request->u.ata.lba >> 8);
- ATA_IDX_OUTW(ch, ATA_CYL_MSB, request->u.ata.lba >> 16);
- ATA_IDX_OUTW(ch, ATA_DRIVE,
- ATA_D_IBM | ATA_D_LBA | ATA_DEV(atadev->unit) |
- ((request->u.ata.lba >> 24) & 0x0f));
- }
- }
-}
-
-static void
-ata_serverworks_setmode(device_t dev, int mode)
-{
- device_t gparent = GRANDPARENT(dev);
- struct ata_pci_controller *ctlr = device_get_softc(gparent);
- struct ata_channel *ch = device_get_softc(device_get_parent(dev));
- struct ata_device *atadev = device_get_softc(dev);
- int devno = (ch->unit << 1) + atadev->unit;
- int offset = (devno ^ 0x01) << 3;
- int error;
- u_int8_t piotimings[] = { 0x5d, 0x47, 0x34, 0x22, 0x20, 0x34, 0x22, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 };
- u_int8_t dmatimings[] = { 0x77, 0x21, 0x20 };
-
- mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma);
-
- mode = ata_check_80pin(dev, mode);
-
- error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
-
- if (bootverbose)
- device_printf(dev, "%ssetting %s on %s chip\n",
- (error) ? "FAILURE " : "",
- ata_mode2str(mode), ctlr->chip->text);
- if (!error) {
- if (mode >= ATA_UDMA0) {
- pci_write_config(gparent, 0x56,
- (pci_read_config(gparent, 0x56, 2) &
- ~(0xf << (devno << 2))) |
- ((mode & ATA_MODE_MASK) << (devno << 2)), 2);
- pci_write_config(gparent, 0x54,
- pci_read_config(gparent, 0x54, 1) |
- (0x01 << devno), 1);
- pci_write_config(gparent, 0x44,
- (pci_read_config(gparent, 0x44, 4) &
- ~(0xff << offset)) |
- (dmatimings[2] << offset), 4);
- }
- else if (mode >= ATA_WDMA0) {
- pci_write_config(gparent, 0x54,
- pci_read_config(gparent, 0x54, 1) &
- ~(0x01 << devno), 1);
- pci_write_config(gparent, 0x44,
- (pci_read_config(gparent, 0x44, 4) &
- ~(0xff << offset)) |
- (dmatimings[mode & ATA_MODE_MASK] << offset), 4);
- }
- else
- pci_write_config(gparent, 0x54,
- pci_read_config(gparent, 0x54, 1) &
- ~(0x01 << devno), 1);
-
- pci_write_config(gparent, 0x40,
- (pci_read_config(gparent, 0x40, 4) &
- ~(0xff << offset)) |
- (piotimings[ata_mode2idx(mode)] << offset), 4);
- atadev->mode = mode;
- }
-}
-
-
-/*
- * Silicon Image Inc. (SiI) (former CMD) chipset support functions
- */
-int
-ata_sii_ident(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
- static struct ata_chip_id ids[] =
- {{ ATA_SII3114, 0x00, SIIMEMIO, SII4CH, ATA_SA150, "3114" },
- { ATA_SII3512, 0x02, SIIMEMIO, 0, ATA_SA150, "3512" },
- { ATA_SII3112, 0x02, SIIMEMIO, 0, ATA_SA150, "3112" },
- { ATA_SII3112_1, 0x02, SIIMEMIO, 0, ATA_SA150, "3112" },
- { ATA_SII3512, 0x00, SIIMEMIO, SIIBUG, ATA_SA150, "3512" },
- { ATA_SII3112, 0x00, SIIMEMIO, SIIBUG, ATA_SA150, "3112" },
- { ATA_SII3112_1, 0x00, SIIMEMIO, SIIBUG, ATA_SA150, "3112" },
- { ATA_SII3124, 0x00, SIIPRBIO, SII4CH, ATA_SA300, "3124" },
- { ATA_SII3132, 0x00, SIIPRBIO, 0, ATA_SA300, "3132" },
- { ATA_SII3132_1, 0x00, SIIPRBIO, 0, ATA_SA300, "3132" },
- { ATA_SII0680, 0x00, SIIMEMIO, SIISETCLK, ATA_UDMA6, "680" },
- { ATA_CMD649, 0x00, 0, SIIINTR, ATA_UDMA5, "(CMD) 649" },
- { ATA_CMD648, 0x00, 0, SIIINTR, ATA_UDMA4, "(CMD) 648" },
- { ATA_CMD646, 0x07, 0, 0, ATA_UDMA2, "(CMD) 646U2" },
- { ATA_CMD646, 0x00, 0, 0, ATA_WDMA2, "(CMD) 646" },
- { 0, 0, 0, 0, 0, 0}};
-
- if (!(ctlr->chip = ata_match_chip(dev, ids)))
- return ENXIO;
-
- ata_set_desc(dev);
- ctlr->chipinit = ata_sii_chipinit;
- return 0;
-}
-
-static int
-ata_sii_chipinit(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
-
- if (ata_setup_interrupt(dev))
- return ENXIO;
-
- switch (ctlr->chip->cfg1) {
- case SIIPRBIO:
- ctlr->r_type1 = SYS_RES_MEMORY;
- ctlr->r_rid1 = PCIR_BAR(0);
- if (!(ctlr->r_res1 = bus_alloc_resource_any(dev, ctlr->r_type1,
- &ctlr->r_rid1, RF_ACTIVE)))
- return ENXIO;
-
- ctlr->r_rid2 = PCIR_BAR(2);
- ctlr->r_type2 = SYS_RES_MEMORY;
- if (!(ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2,
- &ctlr->r_rid2, RF_ACTIVE))){
- bus_release_resource(dev, ctlr->r_type1, ctlr->r_rid1,ctlr->r_res1);
- return ENXIO;
- }
- ctlr->allocate = ata_siiprb_allocate;
- ctlr->reset = ata_siiprb_reset;
- ctlr->dmainit = ata_siiprb_dmainit;
- ctlr->setmode = ata_sata_setmode;
- ctlr->channels = (ctlr->chip->cfg2 == SII4CH) ? 4 : 2;
-
- /* reset controller */
- ATA_OUTL(ctlr->r_res1, 0x0040, 0x80000000);
- DELAY(10000);
- ATA_OUTL(ctlr->r_res1, 0x0040, 0x0000000f);
-
- /* enable PCI interrupt */
- pci_write_config(dev, PCIR_COMMAND,
- pci_read_config(dev, PCIR_COMMAND, 2) & ~0x0400, 2);
- break;
-
- case SIIMEMIO:
- ctlr->r_type2 = SYS_RES_MEMORY;
- ctlr->r_rid2 = PCIR_BAR(5);
- if (!(ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2,
- &ctlr->r_rid2, RF_ACTIVE))){
- if (ctlr->chip->chipid != ATA_SII0680 ||
- (pci_read_config(dev, 0x8a, 1) & 1))
- return ENXIO;
- }
-
- if (ctlr->chip->cfg2 & SIISETCLK) {
- if ((pci_read_config(dev, 0x8a, 1) & 0x30) != 0x10)
- pci_write_config(dev, 0x8a,
- (pci_read_config(dev, 0x8a, 1) & 0xcf)|0x10,1);
- if ((pci_read_config(dev, 0x8a, 1) & 0x30) != 0x10)
- device_printf(dev, "%s could not set ATA133 clock\n",
- ctlr->chip->text);
- }
-
- /* if we have 4 channels enable the second set */
- if (ctlr->chip->cfg2 & SII4CH) {
- ATA_OUTL(ctlr->r_res2, 0x0200, 0x00000002);
- ctlr->channels = 4;
- }
-
- /* dont block interrupts from any channel */
- pci_write_config(dev, 0x48,
- (pci_read_config(dev, 0x48, 4) & ~0x03c00000), 4);
-
- /* enable PCI interrupt as BIOS might not */
- pci_write_config(dev, 0x8a, (pci_read_config(dev, 0x8a, 1) & 0x3f), 1);
-
- if (ctlr->r_res2)
- ctlr->allocate = ata_sii_allocate;
-
- if (ctlr->chip->max_dma >= ATA_SA150) {
- ctlr->reset = ata_sii_reset;
- ctlr->setmode = ata_sata_setmode;
- }
- else
- ctlr->setmode = ata_sii_setmode;
- break;
-
- default:
- if ((pci_read_config(dev, 0x51, 1) & 0x08) != 0x08) {
- device_printf(dev, "HW has secondary channel disabled\n");
- ctlr->channels = 1;
- }
-
- /* enable interrupt as BIOS might not */
- pci_write_config(dev, 0x71, 0x01, 1);
-
- ctlr->allocate = ata_cmd_allocate;
- ctlr->setmode = ata_cmd_setmode;
- break;
- }
- return 0;
-}
-
-static int
-ata_cmd_allocate(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
-
- /* setup the usual register normal pci style */
- if (ata_pci_allocate(dev))
- return ENXIO;
-
- if (ctlr->chip->cfg2 & SIIINTR)
- ch->hw.status = ata_cmd_status;
-
- return 0;
-}
-
-static int
-ata_cmd_status(device_t dev)
-{
- struct ata_channel *ch = device_get_softc(dev);
- u_int8_t reg71;
-
- if (((reg71 = pci_read_config(device_get_parent(dev), 0x71, 1)) &
- (ch->unit ? 0x08 : 0x04))) {
- pci_write_config(device_get_parent(dev), 0x71,
- reg71 & ~(ch->unit ? 0x04 : 0x08), 1);
- return ata_pci_status(dev);
- }
- return 0;
-}
-
-static void
-ata_cmd_setmode(device_t dev, int mode)
-{
- device_t gparent = GRANDPARENT(dev);
- struct ata_pci_controller *ctlr = device_get_softc(gparent);
- struct ata_channel *ch = device_get_softc(device_get_parent(dev));
- struct ata_device *atadev = device_get_softc(dev);
- int devno = (ch->unit << 1) + atadev->unit;
- int error;
-
- mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma);
-
- mode = ata_check_80pin(dev, mode);
-
- error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
-
- if (bootverbose)
- device_printf(dev, "%ssetting %s on %s chip\n",
- (error) ? "FAILURE " : "",
- ata_mode2str(mode), ctlr->chip->text);
- if (!error) {
- int treg = 0x54 + ((devno < 3) ? (devno << 1) : 7);
- int ureg = ch->unit ? 0x7b : 0x73;
-
- if (mode >= ATA_UDMA0) {
- int udmatimings[][2] = { { 0x31, 0xc2 }, { 0x21, 0x82 },
- { 0x11, 0x42 }, { 0x25, 0x8a },
- { 0x15, 0x4a }, { 0x05, 0x0a } };
-
- u_int8_t umode = pci_read_config(gparent, ureg, 1);
-
- umode &= ~(atadev->unit == ATA_MASTER ? 0x35 : 0xca);
- umode |= udmatimings[mode & ATA_MODE_MASK][atadev->unit];
- pci_write_config(gparent, ureg, umode, 1);
- }
- else if (mode >= ATA_WDMA0) {
- int dmatimings[] = { 0x87, 0x32, 0x3f };
-
- pci_write_config(gparent, treg, dmatimings[mode & ATA_MODE_MASK],1);
- pci_write_config(gparent, ureg,
- pci_read_config(gparent, ureg, 1) &
- ~(atadev->unit == ATA_MASTER ? 0x35 : 0xca), 1);
- }
- else {
- int piotimings[] = { 0xa9, 0x57, 0x44, 0x32, 0x3f };
- pci_write_config(gparent, treg,
- piotimings[(mode & ATA_MODE_MASK) - ATA_PIO0], 1);
- pci_write_config(gparent, ureg,
- pci_read_config(gparent, ureg, 1) &
- ~(atadev->unit == ATA_MASTER ? 0x35 : 0xca), 1);
- }
- atadev->mode = mode;
- }
-}
-
-static int
-ata_sii_allocate(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
- int unit01 = (ch->unit & 1), unit10 = (ch->unit & 2);
- int i;
-
- for (i = ATA_DATA; i <= ATA_COMMAND; i++) {
- ch->r_io[i].res = ctlr->r_res2;
- ch->r_io[i].offset = 0x80 + i + (unit01 << 6) + (unit10 << 8);
- }
- ch->r_io[ATA_CONTROL].res = ctlr->r_res2;
- ch->r_io[ATA_CONTROL].offset = 0x8a + (unit01 << 6) + (unit10 << 8);
- ch->r_io[ATA_IDX_ADDR].res = ctlr->r_res2;
- ata_default_registers(dev);
-
- ch->r_io[ATA_BMCMD_PORT].res = ctlr->r_res2;
- ch->r_io[ATA_BMCMD_PORT].offset = 0x00 + (unit01 << 3) + (unit10 << 8);
- ch->r_io[ATA_BMSTAT_PORT].res = ctlr->r_res2;
- ch->r_io[ATA_BMSTAT_PORT].offset = 0x02 + (unit01 << 3) + (unit10 << 8);
- ch->r_io[ATA_BMDTP_PORT].res = ctlr->r_res2;
- ch->r_io[ATA_BMDTP_PORT].offset = 0x04 + (unit01 << 3) + (unit10 << 8);
-
- if (ctlr->chip->max_dma >= ATA_SA150) {
- ch->r_io[ATA_SSTATUS].res = ctlr->r_res2;
- ch->r_io[ATA_SSTATUS].offset = 0x104 + (unit01 << 7) + (unit10 << 8);
- ch->r_io[ATA_SERROR].res = ctlr->r_res2;
- ch->r_io[ATA_SERROR].offset = 0x108 + (unit01 << 7) + (unit10 << 8);
- ch->r_io[ATA_SCONTROL].res = ctlr->r_res2;
- ch->r_io[ATA_SCONTROL].offset = 0x100 + (unit01 << 7) + (unit10 << 8);
- ch->flags |= ATA_NO_SLAVE;
-
- /* enable PHY state change interrupt */
- ATA_OUTL(ctlr->r_res2, 0x148 + (unit01 << 7) + (unit10 << 8),(1 << 16));
- }
-
- if (ctlr->chip->cfg2 & SIIBUG) {
- /* work around errata in early chips */
- ch->dma.boundary = 8192;
- ch->dma.segsize = 15 * DEV_BSIZE;
- }
-
- ata_pci_hw(dev);
- ch->hw.status = ata_sii_status;
- return 0;
-}
-
-static int
-ata_sii_status(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
- int offset0 = ((ch->unit & 1) << 3) + ((ch->unit & 2) << 8);
- int offset1 = ((ch->unit & 1) << 6) + ((ch->unit & 2) << 8);
-
- /* do we have any PHY events ? */
- if (ctlr->chip->max_dma >= ATA_SA150 &&
- (ATA_INL(ctlr->r_res2, 0x10 + offset0) & 0x00000010))
- ata_sata_phy_check_events(dev);
-
- if (ATA_INL(ctlr->r_res2, 0xa0 + offset1) & 0x00000800)
- return ata_pci_status(dev);
- else
- return 0;
-}
-
-static void
-ata_sii_reset(device_t dev)
-{
- if (ata_sata_phy_reset(dev))
- ata_generic_reset(dev);
-}
-
-static void
-ata_sii_setmode(device_t dev, int mode)
-{
- device_t gparent = GRANDPARENT(dev);
- struct ata_pci_controller *ctlr = device_get_softc(gparent);
- struct ata_channel *ch = device_get_softc(device_get_parent(dev));
- struct ata_device *atadev = device_get_softc(dev);
- int rego = (ch->unit << 4) + (atadev->unit << 1);
- int mreg = ch->unit ? 0x84 : 0x80;
- int mask = 0x03 << (atadev->unit << 2);
- int mval = pci_read_config(gparent, mreg, 1) & ~mask;
- int error;
-
- mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma);
-
- if (ctlr->chip->cfg2 & SIISETCLK) {
- if (mode > ATA_UDMA2 && (pci_read_config(gparent, 0x79, 1) &
- (ch->unit ? 0x02 : 0x01))) {
- ata_print_cable(dev, "controller");
- mode = ATA_UDMA2;
- }
- }
- else
- mode = ata_check_80pin(dev, mode);
-
- error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
-
- if (bootverbose)
- device_printf(dev, "%ssetting %s on %s chip\n",
- (error) ? "FAILURE " : "",
- ata_mode2str(mode), ctlr->chip->text);
- if (error)
- return;
-
- if (mode >= ATA_UDMA0) {
- u_int8_t udmatimings[] = { 0xf, 0xb, 0x7, 0x5, 0x3, 0x2, 0x1 };
- u_int8_t ureg = 0xac + rego;
-
- pci_write_config(gparent, mreg,
- mval | (0x03 << (atadev->unit << 2)), 1);
- pci_write_config(gparent, ureg,
- (pci_read_config(gparent, ureg, 1) & ~0x3f) |
- udmatimings[mode & ATA_MODE_MASK], 1);
-
- }
- else if (mode >= ATA_WDMA0) {
- u_int8_t dreg = 0xa8 + rego;
- u_int16_t dmatimings[] = { 0x2208, 0x10c2, 0x10c1 };
-
- pci_write_config(gparent, mreg,
- mval | (0x02 << (atadev->unit << 2)), 1);
- pci_write_config(gparent, dreg, dmatimings[mode & ATA_MODE_MASK], 2);
-
- }
- else {
- u_int8_t preg = 0xa4 + rego;
- u_int16_t piotimings[] = { 0x328a, 0x2283, 0x1104, 0x10c3, 0x10c1 };
-
- pci_write_config(gparent, mreg,
- mval | (0x01 << (atadev->unit << 2)), 1);
- pci_write_config(gparent, preg, piotimings[mode & ATA_MODE_MASK], 2);
- }
- atadev->mode = mode;
-}
-
-
-struct ata_siiprb_dma_prdentry {
- u_int64_t addr;
- u_int32_t count;
- u_int32_t control;
-} __packed;
-
-#define ATA_SIIPRB_DMA_ENTRIES 125
-struct ata_siiprb_ata_command {
- struct ata_siiprb_dma_prdentry prd[ATA_SIIPRB_DMA_ENTRIES];
-} __packed;
-
-struct ata_siiprb_atapi_command {
- u_int8_t ccb[16];
- struct ata_siiprb_dma_prdentry prd[ATA_SIIPRB_DMA_ENTRIES];
-} __packed;
-
-struct ata_siiprb_command {
- u_int16_t control;
- u_int16_t protocol_override;
- u_int32_t transfer_count;
- u_int8_t fis[24];
- union {
- struct ata_siiprb_ata_command ata;
- struct ata_siiprb_atapi_command atapi;
- } u;
-} __packed;
-
-static int
-ata_siiprb_allocate(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
- int offset = ch->unit * 0x2000;
-
- /* set the SATA resources */
- ch->r_io[ATA_SSTATUS].res = ctlr->r_res2;
- ch->r_io[ATA_SSTATUS].offset = 0x1f04 + offset;
- ch->r_io[ATA_SERROR].res = ctlr->r_res2;
- ch->r_io[ATA_SERROR].offset = 0x1f08 + offset;
- ch->r_io[ATA_SCONTROL].res = ctlr->r_res2;
- ch->r_io[ATA_SCONTROL].offset = 0x1f00 + offset;
- ch->r_io[ATA_SACTIVE].res = ctlr->r_res2;
- ch->r_io[ATA_SACTIVE].offset = 0x1f0c + offset;
-
- ch->hw.status = ata_siiprb_status;
- ch->hw.begin_transaction = ata_siiprb_begin_transaction;
- ch->hw.end_transaction = ata_siiprb_end_transaction;
- ch->hw.command = NULL; /* not used here */
- ch->hw.softreset = ata_siiprb_softreset;
- ch->hw.pm_read = ata_siiprb_pm_read;
- ch->hw.pm_write = ata_siiprb_pm_write;
-
- return 0;
-}
-
-static int
-ata_siiprb_status(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
- u_int32_t action = ATA_INL(ctlr->r_res1, 0x0044);
- int offset = ch->unit * 0x2000;
-
- if (action & (1 << ch->unit)) {
- u_int32_t istatus = ATA_INL(ctlr->r_res2, 0x1008 + offset);
-
- /* do we have any PHY events ? */
- ata_sata_phy_check_events(dev);
-
- /* clear interrupt(s) */
- ATA_OUTL(ctlr->r_res2, 0x1008 + offset, istatus);
-
- /* do we have any device action ? */
- return (istatus & 0x00000003);
- }
- return 0;
-}
-
-static int
-ata_siiprb_begin_transaction(struct ata_request *request)
-{
- struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev));
- struct ata_channel *ch = device_get_softc(request->parent);
- struct ata_siiprb_command *prb;
- struct ata_siiprb_dma_prdentry *prd;
- int offset = ch->unit * 0x2000;
- u_int64_t prb_bus;
-
- /* SOS XXX */
- if (request->u.ata.command == ATA_DEVICE_RESET) {
- request->result = 0;
- return ATA_OP_FINISHED;
- }
-
- /* get a piece of the workspace for this request */
- prb = (struct ata_siiprb_command *)
- (ch->dma.work + (sizeof(struct ata_siiprb_command) * request->tag));
-
- /* set basic prd options ata/atapi etc etc */
- bzero(prb, sizeof(struct ata_siiprb_command));
-
- /* setup the FIS for this request */
- if (!ata_request2fis_h2d(request, &prb->fis[0])) {
- device_printf(request->dev, "setting up SATA FIS failed\n");
- request->result = EIO;
- return ATA_OP_FINISHED;
- }
-
- /* setup transfer type */
- if (request->flags & ATA_R_ATAPI) {
- struct ata_device *atadev = device_get_softc(request->dev);
-
- bcopy(request->u.atapi.ccb, prb->u.atapi.ccb, 16);
- if ((atadev->param.config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_12)
- ATA_OUTL(ctlr->r_res2, 0x1004 + offset, 0x00000020);
- else
- ATA_OUTL(ctlr->r_res2, 0x1000 + offset, 0x00000020);
- if (request->flags & ATA_R_READ)
- prb->control = htole16(0x0010);
- if (request->flags & ATA_R_WRITE)
- prb->control = htole16(0x0020);
- prd = &prb->u.atapi.prd[0];
- }
- else
- prd = &prb->u.ata.prd[0];
-
- /* if request moves data setup and load SG list */
- if (request->flags & (ATA_R_READ | ATA_R_WRITE)) {
- if (ch->dma.load(request, prd, NULL)) {
- device_printf(request->dev, "setting up DMA failed\n");
- request->result = EIO;
- return ATA_OP_FINISHED;
- }
- }
-
- /* activate the prb */
- prb_bus = ch->dma.work_bus +
- (sizeof(struct ata_siiprb_command) * request->tag);
- ATA_OUTL(ctlr->r_res2,
- 0x1c00 + offset + (request->tag * sizeof(u_int64_t)), prb_bus);
- ATA_OUTL(ctlr->r_res2,
- 0x1c04 + offset + (request->tag * sizeof(u_int64_t)), prb_bus>>32);
-
- /* start the timeout */
- callout_reset(&request->callout, request->timeout * hz,
- (timeout_t*)ata_timeout, request);
- return ATA_OP_CONTINUES;
-}
-
-static int
-ata_siiprb_end_transaction(struct ata_request *request)
-{
- struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev));
- struct ata_channel *ch = device_get_softc(request->parent);
- struct ata_siiprb_command *prb;
- int offset = ch->unit * 0x2000;
- int error, timeout;
-
- /* kill the timeout */
- callout_stop(&request->callout);
-
- prb = (struct ata_siiprb_command *)
- ((u_int8_t *)rman_get_virtual(ctlr->r_res2)+(request->tag << 7)+offset);
-
- /* any controller errors flagged ? */
- if ((error = ATA_INL(ctlr->r_res2, 0x1024 + offset))) {
- if (bootverbose)
- printf("ata_siiprb_end_transaction %s error=%08x\n",
- ata_cmd2str(request), error);
-
- /* if device error status get details */
- if (error == 1 || error == 2) {
- request->status = prb->fis[2];
- if (request->status & ATA_S_ERROR)
- request->error = prb->fis[3];
- }
-
- /* SOS XXX handle other controller errors here */
-
- /* initialize port */
- ATA_OUTL(ctlr->r_res2, 0x1000 + offset, 0x00000004);
-
- /* poll for port ready */
- for (timeout = 0; timeout < 1000; timeout++) {
- DELAY(1000);
- if (ATA_INL(ctlr->r_res2, 0x1008 + offset) & 0x00040000)
- break;
- }
- if (bootverbose) {
- if (timeout >= 1000)
- device_printf(ch->dev, "port initialize timeout\n");
- else
- device_printf(ch->dev, "port initialize time=%dms\n", timeout);
- }
- }
-
- /* on control commands read back registers to the request struct */
- if (request->flags & ATA_R_CONTROL) {
- struct ata_device *atadev = device_get_softc(request->dev);
-
- request->u.ata.count = prb->fis[12] | ((u_int16_t)prb->fis[13] << 8);
- request->u.ata.lba = prb->fis[4] | ((u_int64_t)prb->fis[5] << 8) |
- ((u_int64_t)prb->fis[6] << 16);
- if (atadev->flags & ATA_D_48BIT_ACTIVE)
- request->u.ata.lba |= ((u_int64_t)prb->fis[8] << 24) |
- ((u_int64_t)prb->fis[9] << 32) |
- ((u_int64_t)prb->fis[10] << 40);
- else
- request->u.ata.lba |= ((u_int64_t)(prb->fis[7] & 0x0f) << 24);
- }
-
- /* update progress */
- if (!(request->status & ATA_S_ERROR) && !(request->flags & ATA_R_TIMEOUT)) {
- if (request->flags & ATA_R_READ)
- request->donecount = prb->transfer_count;
- else
- request->donecount = request->bytecount;
- }
-
- /* release SG list etc */
- ch->dma.unload(request);
-
- return ATA_OP_FINISHED;
-}
-
-static int
-ata_siiprb_issue_cmd(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
- u_int64_t prb_bus = ch->dma.work_bus;
- u_int32_t status;
- int offset = ch->unit * 0x2000;
- int timeout;
-
- /* issue command to chip */
- ATA_OUTL(ctlr->r_res2, 0x1c00 + offset, prb_bus);
- ATA_OUTL(ctlr->r_res2, 0x1c04 + offset, prb_bus >> 32);
-
- /* poll for command finished */
- for (timeout = 0; timeout < 10000; timeout++) {
- DELAY(1000);
- if ((status = ATA_INL(ctlr->r_res2, 0x1008 + offset)) & 0x00010000)
- break;
- }
- ATA_OUTL(ctlr->r_res2, 0x1008 + offset, 0x00010000);
-
- if (timeout >= 1000)
- return EIO;
-
- if (bootverbose)
- device_printf(dev, "siiprb_issue_cmd time=%dms status=%08x\n",
- timeout, status);
- return 0;
-}
-
-static int
-ata_siiprb_pm_read(device_t dev, int port, int reg, u_int32_t *result)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
- struct ata_siiprb_command *prb = (struct ata_siiprb_command *)ch->dma.work;
- int offset = ch->unit * 0x2000;
-
- bzero(prb, sizeof(struct ata_siiprb_command));
- prb->fis[0] = 0x27; /* host to device */
- prb->fis[1] = 0x8f; /* command FIS to PM port */
- prb->fis[2] = ATA_READ_PM;
- prb->fis[3] = reg;
- prb->fis[7] = port;
- if (ata_siiprb_issue_cmd(dev)) {
- device_printf(dev, "error reading PM port\n");
- return EIO;
- }
- prb = (struct ata_siiprb_command *)
- ((u_int8_t *)rman_get_virtual(ctlr->r_res2) + offset);
- *result = prb->fis[12]|(prb->fis[4]<<8)|(prb->fis[5]<<16)|(prb->fis[6]<<24);
- return 0;
-}
-
-static int
-ata_siiprb_pm_write(device_t dev, int port, int reg, u_int32_t value)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
- struct ata_siiprb_command *prb = (struct ata_siiprb_command *)ch->dma.work;
- int offset = ch->unit * 0x2000;
-
- bzero(prb, sizeof(struct ata_siiprb_command));
- prb->fis[0] = 0x27; /* host to device */
- prb->fis[1] = 0x8f; /* command FIS to PM port */
- prb->fis[2] = ATA_WRITE_PM;
- prb->fis[3] = reg;
- prb->fis[7] = port;
- prb->fis[12] = value & 0xff;
- prb->fis[4] = (value >> 8) & 0xff;;
- prb->fis[5] = (value >> 16) & 0xff;;
- prb->fis[6] = (value >> 24) & 0xff;;
- if (ata_siiprb_issue_cmd(dev)) {
- device_printf(dev, "error writing PM port\n");
- return ATA_E_ABORT;
- }
- prb = (struct ata_siiprb_command *)
- ((u_int8_t *)rman_get_virtual(ctlr->r_res2) + offset);
- return prb->fis[3];
-}
-
-static u_int32_t
-ata_siiprb_softreset(device_t dev, int port)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
- struct ata_siiprb_command *prb = (struct ata_siiprb_command *)ch->dma.work;
- int offset = ch->unit * 0x2000;
-
- /* setup the workspace for a soft reset command */
- bzero(prb, sizeof(struct ata_siiprb_command));
- prb->control = htole16(0x0080);
- prb->fis[1] = port & 0x0f;
-
- /* issue soft reset */
- if (ata_siiprb_issue_cmd(dev))
- return -1;
-
- ata_udelay(150000);
-
- /* return possible signature */
- prb = (struct ata_siiprb_command *)
- ((u_int8_t *)rman_get_virtual(ctlr->r_res2) + offset);
- return prb->fis[12]|(prb->fis[4]<<8)|(prb->fis[5]<<16)|(prb->fis[6]<<24);
-}
-
-static void
-ata_siiprb_reset(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
- int offset = ch->unit * 0x2000;
- u_int32_t status, signature;
- int timeout;
-
- /* reset channel HW */
- ATA_OUTL(ctlr->r_res2, 0x1000 + offset, 0x00000001);
- DELAY(1000);
- ATA_OUTL(ctlr->r_res2, 0x1004 + offset, 0x00000001);
- DELAY(10000);
-
- /* poll for channel ready */
- for (timeout = 0; timeout < 1000; timeout++) {
- if ((status = ATA_INL(ctlr->r_res2, 0x1008 + offset)) & 0x00040000)
- break;
- DELAY(1000);
- }
-
- if (bootverbose) {
- if (timeout >= 1000)
- device_printf(dev, "channel HW reset timeout\n");
- else
- device_printf(dev, "channel HW reset time=%dms\n", timeout);
- }
-
- /* reset phy */
- if (!ata_sata_phy_reset(dev)) {
- if (bootverbose)
- device_printf(dev, "phy reset found no device\n");
- ch->devices = 0;
- goto finish;
- }
-
- /* issue soft reset */
- signature = ata_siiprb_softreset(dev, ATA_PM);
- if (bootverbose)
- device_printf(dev, "SIGNATURE=%08x\n", signature);
-
- /* figure out whats there */
- switch (signature) {
- case 0x00000101:
- ch->devices = ATA_ATA_MASTER;
- break;
- case 0x96690101:
- ch->devices = ATA_PORTMULTIPLIER;
- ATA_OUTL(ctlr->r_res2, 0x1000 + offset, 0x2000); /* enable PM support */
- ata_pm_identify(dev);
- break;
- case 0xeb140101:
- ch->devices = ATA_ATAPI_MASTER;
- break;
- default:
- ch->devices = 0;
- }
- if (bootverbose)
- device_printf(dev, "siiprb_reset devices=%08x\n", ch->devices);
-
-finish:
- /* clear interrupt(s) */
- ATA_OUTL(ctlr->r_res2, 0x1008 + offset, 0x000008ff);
-
- /* require explicit interrupt ack */
- ATA_OUTL(ctlr->r_res2, 0x1000 + offset, 0x00000008);
-
- /* 64bit mode */
- ATA_OUTL(ctlr->r_res2, 0x1004 + offset, 0x00000400);
-
- /* enable interrupts wanted */
- ATA_OUTL(ctlr->r_res2, 0x1010 + offset, 0x000000ff);
-}
-
-static void
-ata_siiprb_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error)
-{
- struct ata_dmasetprd_args *args = xsc;
- struct ata_siiprb_dma_prdentry *prd = args->dmatab;
- int i;
-
- if ((args->error = error))
- return;
-
- for (i = 0; i < nsegs; i++) {
- prd[i].addr = htole64(segs[i].ds_addr);
- prd[i].count = htole32(segs[i].ds_len);
- }
- prd[i - 1].control = htole32(ATA_DMA_EOT);
- KASSERT(nsegs <= ATA_SIIPRB_DMA_ENTRIES,("too many DMA segment entries\n"));
- args->nsegs = nsegs;
-}
-
-static void
-ata_siiprb_dmainit(device_t dev)
-{
- struct ata_channel *ch = device_get_softc(dev);
-
- ata_dmainit(dev);
- /* note start and stop are not used here */
- ch->dma.setprd = ata_siiprb_dmasetprd;
- ch->dma.max_address = BUS_SPACE_MAXADDR;
-}
-
-
-/*
- * Silicon Integrated Systems Corp. (SiS) chipset support functions
- */
-int
-ata_sis_ident(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
- struct ata_chip_id *idx;
- static struct ata_chip_id ids[] =
- {{ ATA_SIS182, 0x00, SISSATA, 0, ATA_SA150, "182" }, /* south */
- { ATA_SIS181, 0x00, SISSATA, 0, ATA_SA150, "181" }, /* south */
- { ATA_SIS180, 0x00, SISSATA, 0, ATA_SA150, "180" }, /* south */
- { ATA_SIS965, 0x00, SIS133NEW, 0, ATA_UDMA6, "965" }, /* south */
- { ATA_SIS964, 0x00, SIS133NEW, 0, ATA_UDMA6, "964" }, /* south */
- { ATA_SIS963, 0x00, SIS133NEW, 0, ATA_UDMA6, "963" }, /* south */
- { ATA_SIS962, 0x00, SIS133NEW, 0, ATA_UDMA6, "962" }, /* south */
-
- { ATA_SIS745, 0x00, SIS100NEW, 0, ATA_UDMA5, "745" }, /* 1chip */
- { ATA_SIS735, 0x00, SIS100NEW, 0, ATA_UDMA5, "735" }, /* 1chip */
- { ATA_SIS733, 0x00, SIS100NEW, 0, ATA_UDMA5, "733" }, /* 1chip */
- { ATA_SIS730, 0x00, SIS100OLD, 0, ATA_UDMA5, "730" }, /* 1chip */
-
- { ATA_SIS635, 0x00, SIS100NEW, 0, ATA_UDMA5, "635" }, /* 1chip */
- { ATA_SIS633, 0x00, SIS100NEW, 0, ATA_UDMA5, "633" }, /* unknown */
- { ATA_SIS630, 0x30, SIS100OLD, 0, ATA_UDMA5, "630S"}, /* 1chip */
- { ATA_SIS630, 0x00, SIS66, 0, ATA_UDMA4, "630" }, /* 1chip */
- { ATA_SIS620, 0x00, SIS66, 0, ATA_UDMA4, "620" }, /* 1chip */
-
- { ATA_SIS550, 0x00, SIS66, 0, ATA_UDMA5, "550" },
- { ATA_SIS540, 0x00, SIS66, 0, ATA_UDMA4, "540" },
- { ATA_SIS530, 0x00, SIS66, 0, ATA_UDMA4, "530" },
-
- { ATA_SIS5513, 0xc2, SIS33, 1, ATA_UDMA2, "5513" },
- { ATA_SIS5513, 0x00, SIS33, 1, ATA_WDMA2, "5513" },
- { 0, 0, 0, 0, 0, 0 }};
- char buffer[64];
- int found = 0;
-
- if (!(idx = ata_find_chip(dev, ids, -pci_get_slot(dev))))
- return ENXIO;
-
- if (idx->cfg2 && !found) {
- u_int8_t reg57 = pci_read_config(dev, 0x57, 1);
-
- pci_write_config(dev, 0x57, (reg57 & 0x7f), 1);
- if (pci_read_config(dev, PCIR_DEVVENDOR, 4) == ATA_SIS5518) {
- found = 1;
- idx->cfg1 = SIS133NEW;
- idx->max_dma = ATA_UDMA6;
- sprintf(buffer, "SiS 962/963 %s controller",
- ata_mode2str(idx->max_dma));
- }
- pci_write_config(dev, 0x57, reg57, 1);
- }
- if (idx->cfg2 && !found) {
- u_int8_t reg4a = pci_read_config(dev, 0x4a, 1);
-
- pci_write_config(dev, 0x4a, (reg4a | 0x10), 1);
- if (pci_read_config(dev, PCIR_DEVVENDOR, 4) == ATA_SIS5517) {
- struct ata_chip_id id[] =
- {{ ATA_SISSOUTH, 0x10, 0, 0, 0, "" }, { 0, 0, 0, 0, 0, 0 }};
-
- found = 1;
- if (ata_find_chip(dev, id, pci_get_slot(dev))) {
- idx->cfg1 = SIS133OLD;
- idx->max_dma = ATA_UDMA6;
- }
- else {
- idx->cfg1 = SIS100NEW;
- idx->max_dma = ATA_UDMA5;
- }
- sprintf(buffer, "SiS 961 %s controller",ata_mode2str(idx->max_dma));
- }
- pci_write_config(dev, 0x4a, reg4a, 1);
- }
- if (!found)
- sprintf(buffer,"SiS %s %s controller",
- idx->text, ata_mode2str(idx->max_dma));
-
- device_set_desc_copy(dev, buffer);
- ctlr->chip = idx;
- ctlr->chipinit = ata_sis_chipinit;
- return 0;
-}
-
-static int
-ata_sis_chipinit(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
-
- if (ata_setup_interrupt(dev))
- return ENXIO;
-
- switch (ctlr->chip->cfg1) {
- case SIS33:
- break;
- case SIS66:
- case SIS100OLD:
- pci_write_config(dev, 0x52, pci_read_config(dev, 0x52, 1) & ~0x04, 1);
- break;
- case SIS100NEW:
- case SIS133OLD:
- pci_write_config(dev, 0x49, pci_read_config(dev, 0x49, 1) & ~0x01, 1);
- break;
- case SIS133NEW:
- pci_write_config(dev, 0x50, pci_read_config(dev, 0x50, 2) | 0x0008, 2);
- pci_write_config(dev, 0x52, pci_read_config(dev, 0x52, 2) | 0x0008, 2);
- break;
- case SISSATA:
- ctlr->r_type2 = SYS_RES_IOPORT;
- ctlr->r_rid2 = PCIR_BAR(5);
- if ((ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2,
- &ctlr->r_rid2, RF_ACTIVE))) {
- ctlr->allocate = ata_sis_allocate;
- ctlr->reset = ata_sis_reset;
-
- /* enable PCI interrupt */
- pci_write_config(dev, PCIR_COMMAND,
- pci_read_config(dev, PCIR_COMMAND, 2) & ~0x0400,2);
- }
- ctlr->setmode = ata_sata_setmode;
- return 0;
- default:
- return ENXIO;
- }
- ctlr->setmode = ata_sis_setmode;
- return 0;
-}
-
-static int
-ata_sis_allocate(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
- int offset = ch->unit << ((ctlr->chip->chipid == ATA_SIS182) ? 5 : 6);
-
- /* setup the usual register normal pci style */
- if (ata_pci_allocate(dev))
- return ENXIO;
-
- ch->r_io[ATA_SSTATUS].res = ctlr->r_res2;
- ch->r_io[ATA_SSTATUS].offset = 0x00 + offset;
- ch->r_io[ATA_SERROR].res = ctlr->r_res2;
- ch->r_io[ATA_SERROR].offset = 0x04 + offset;
- ch->r_io[ATA_SCONTROL].res = ctlr->r_res2;
- ch->r_io[ATA_SCONTROL].offset = 0x08 + offset;
- ch->flags |= ATA_NO_SLAVE;
-
- /* XXX SOS PHY hotplug handling missing in SiS chip ?? */
- /* XXX SOS unknown how to enable PHY state change interrupt */
- return 0;
-}
-
-static void
-ata_sis_reset(device_t dev)
-{
- if (ata_sata_phy_reset(dev))
- ata_generic_reset(dev);
-}
-
-static void
-ata_sis_setmode(device_t dev, int mode)
-{
- device_t gparent = GRANDPARENT(dev);
- struct ata_pci_controller *ctlr = device_get_softc(gparent);
- struct ata_channel *ch = device_get_softc(device_get_parent(dev));
- struct ata_device *atadev = device_get_softc(dev);
- int devno = (ch->unit << 1) + atadev->unit;
- int error;
-
- mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma);
-
- if (ctlr->chip->cfg1 == SIS133NEW) {
- if (mode > ATA_UDMA2 &&
- pci_read_config(gparent, ch->unit ? 0x52 : 0x50,2) & 0x8000) {
- ata_print_cable(dev, "controller");
- mode = ATA_UDMA2;
- }
- }
- else {
- if (mode > ATA_UDMA2 &&
- pci_read_config(gparent, 0x48, 1)&(ch->unit ? 0x20 : 0x10)) {
- ata_print_cable(dev, "controller");
- mode = ATA_UDMA2;
- }
- }
-
- error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
-
- if (bootverbose)
- device_printf(dev, "%ssetting %s on %s chip\n",
- (error) ? "FAILURE " : "",
- ata_mode2str(mode), ctlr->chip->text);
- if (!error) {
- switch (ctlr->chip->cfg1) {
- case SIS133NEW: {
- u_int32_t timings[] =
- { 0x28269008, 0x0c266008, 0x04263008, 0x0c0a3008, 0x05093008,
- 0x22196008, 0x0c0a3008, 0x05093008, 0x050939fc, 0x050936ac,
- 0x0509347c, 0x0509325c, 0x0509323c, 0x0509322c, 0x0509321c};
- u_int32_t reg;
-
- reg = (pci_read_config(gparent, 0x57, 1)&0x40?0x70:0x40)+(devno<<2);
- pci_write_config(gparent, reg, timings[ata_mode2idx(mode)], 4);
- break;
- }
- case SIS133OLD: {
- u_int16_t timings[] =
- { 0x00cb, 0x0067, 0x0044, 0x0033, 0x0031, 0x0044, 0x0033, 0x0031,
- 0x8f31, 0x8a31, 0x8731, 0x8531, 0x8331, 0x8231, 0x8131 };
-
- u_int16_t reg = 0x40 + (devno << 1);
-
- pci_write_config(gparent, reg, timings[ata_mode2idx(mode)], 2);
- break;
- }
- case SIS100NEW: {
- u_int16_t timings[] =
- { 0x00cb, 0x0067, 0x0044, 0x0033, 0x0031, 0x0044, 0x0033,
- 0x0031, 0x8b31, 0x8731, 0x8531, 0x8431, 0x8231, 0x8131 };
- u_int16_t reg = 0x40 + (devno << 1);
-
- pci_write_config(gparent, reg, timings[ata_mode2idx(mode)], 2);
- break;
- }
- case SIS100OLD:
- case SIS66:
- case SIS33: {
- u_int16_t timings[] =
- { 0x0c0b, 0x0607, 0x0404, 0x0303, 0x0301, 0x0404, 0x0303,
- 0x0301, 0xf301, 0xd301, 0xb301, 0xa301, 0x9301, 0x8301 };
- u_int16_t reg = 0x40 + (devno << 1);
-
- pci_write_config(gparent, reg, timings[ata_mode2idx(mode)], 2);
- break;
- }
- }
- atadev->mode = mode;
- }
-}
-
-
-/* VIA Technologies Inc. chipset support functions */
-int
-ata_via_ident(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
- static struct ata_chip_id ids[] =
- {{ ATA_VIA82C586, 0x02, VIA33, 0x00, ATA_UDMA2, "82C586B" },
- { ATA_VIA82C586, 0x00, VIA33, 0x00, ATA_WDMA2, "82C586" },
- { ATA_VIA82C596, 0x12, VIA66, VIACLK, ATA_UDMA4, "82C596B" },
- { ATA_VIA82C596, 0x00, VIA33, 0x00, ATA_UDMA2, "82C596" },
- { ATA_VIA82C686, 0x40, VIA100, VIABUG, ATA_UDMA5, "82C686B"},
- { ATA_VIA82C686, 0x10, VIA66, VIACLK, ATA_UDMA4, "82C686A" },
- { ATA_VIA82C686, 0x00, VIA33, 0x00, ATA_UDMA2, "82C686" },
- { ATA_VIA8231, 0x00, VIA100, VIABUG, ATA_UDMA5, "8231" },
- { ATA_VIA8233, 0x00, VIA100, 0x00, ATA_UDMA5, "8233" },
- { ATA_VIA8233C, 0x00, VIA100, 0x00, ATA_UDMA5, "8233C" },
- { ATA_VIA8233A, 0x00, VIA133, 0x00, ATA_UDMA6, "8233A" },
- { ATA_VIA8235, 0x00, VIA133, 0x00, ATA_UDMA6, "8235" },
- { ATA_VIA8237, 0x00, VIA133, 0x00, ATA_UDMA6, "8237" },
- { ATA_VIA8237A, 0x00, VIA133, 0x00, ATA_UDMA6, "8237A" },
- { ATA_VIA8237S, 0x00, VIA133, 0x00, ATA_UDMA6, "8237S" },
- { ATA_VIA8251, 0x00, VIA133, 0x00, ATA_UDMA6, "8251" },
- { 0, 0, 0, 0, 0, 0 }};
- static struct ata_chip_id new_ids[] =
- {{ ATA_VIA6410, 0x00, 0, 0x00, ATA_UDMA6, "6410" },
- { ATA_VIA6420, 0x00, 7, 0x00, ATA_SA150, "6420" },
- { ATA_VIA6421, 0x00, 6, VIABAR, ATA_SA150, "6421" },
- { ATA_VIA8237A, 0x00, 7, 0x00, ATA_SA150, "8237A" },
- { ATA_VIA8237S, 0x00, 7, 0x00, ATA_SA150, "8237S" },
- { ATA_VIA8251, 0x00, 0, VIAAHCI, ATA_SA300, "8251" },
- { 0, 0, 0, 0, 0, 0 }};
-
- if (pci_get_devid(dev) == ATA_VIA82C571) {
- if (!(ctlr->chip = ata_find_chip(dev, ids, -99)))
- return ENXIO;
- }
- else {
- if (!(ctlr->chip = ata_match_chip(dev, new_ids)))
- return ENXIO;
- }
-
- ata_set_desc(dev);
- ctlr->chipinit = ata_via_chipinit;
- return 0;
-}
-
-static int
-ata_via_chipinit(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
-
- if (ata_setup_interrupt(dev))
- return ENXIO;
-
- if (ctlr->chip->max_dma >= ATA_SA150) {
- /* do we have AHCI capability ? */
- if ((ctlr->chip->cfg2 == VIAAHCI) && ata_ahci_chipinit(dev) != ENXIO)
- return 0;
-
- ctlr->r_type2 = SYS_RES_IOPORT;
- ctlr->r_rid2 = PCIR_BAR(5);
- if ((ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2,
- &ctlr->r_rid2, RF_ACTIVE))) {
- ctlr->allocate = ata_via_allocate;
- ctlr->reset = ata_via_reset;
-
- /* enable PCI interrupt */
- pci_write_config(dev, PCIR_COMMAND,
- pci_read_config(dev, PCIR_COMMAND, 2) & ~0x0400,2);
- }
-
- if (ctlr->chip->cfg2 & VIABAR) {
- ctlr->channels = 3;
- ctlr->setmode = ata_via_setmode;
- }
- else
- ctlr->setmode = ata_sata_setmode;
- return 0;
- }
-
- /* prepare for ATA-66 on the 82C686a and 82C596b */
- if (ctlr->chip->cfg2 & VIACLK)
- pci_write_config(dev, 0x50, 0x030b030b, 4);
-
- /* the southbridge might need the data corruption fix */
- if (ctlr->chip->cfg2 & VIABUG)
- ata_via_southbridge_fixup(dev);
-
- /* set fifo configuration half'n'half */
- pci_write_config(dev, 0x43,
- (pci_read_config(dev, 0x43, 1) & 0x90) | 0x2a, 1);
-
- /* set status register read retry */
- pci_write_config(dev, 0x44, pci_read_config(dev, 0x44, 1) | 0x08, 1);
-
- /* set DMA read & end-of-sector fifo flush */
- pci_write_config(dev, 0x46,
- (pci_read_config(dev, 0x46, 1) & 0x0c) | 0xf0, 1);
-
- /* set sector size */
- pci_write_config(dev, 0x60, DEV_BSIZE, 2);
- pci_write_config(dev, 0x68, DEV_BSIZE, 2);
-
- ctlr->setmode = ata_via_family_setmode;
- return 0;
-}
-
-static int
-ata_via_allocate(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
-
- /* newer SATA chips has resources in one BAR for each channel */
- if (ctlr->chip->cfg2 & VIABAR) {
- struct resource *r_io;
- int i, rid;
-
- rid = PCIR_BAR(ch->unit);
- if (!(r_io = bus_alloc_resource_any(device_get_parent(dev),
- SYS_RES_IOPORT,
- &rid, RF_ACTIVE)))
- return ENXIO;
-
- for (i = ATA_DATA; i <= ATA_COMMAND; i ++) {
- ch->r_io[i].res = r_io;
- ch->r_io[i].offset = i;
- }
- ch->r_io[ATA_CONTROL].res = r_io;
- ch->r_io[ATA_CONTROL].offset = 2 + ATA_IOSIZE;
- ch->r_io[ATA_IDX_ADDR].res = r_io;
- ata_default_registers(dev);
- for (i = ATA_BMCMD_PORT; i <= ATA_BMDTP_PORT; i++) {
- ch->r_io[i].res = ctlr->r_res1;
- ch->r_io[i].offset = (i - ATA_BMCMD_PORT)+(ch->unit * ATA_BMIOSIZE);
- }
- ata_pci_hw(dev);
- if (ch->unit >= 2)
- return 0;
- }
- else {
- /* setup the usual register normal pci style */
- if (ata_pci_allocate(dev))
- return ENXIO;
- }
-
- ch->r_io[ATA_SSTATUS].res = ctlr->r_res2;
- ch->r_io[ATA_SSTATUS].offset = (ch->unit << ctlr->chip->cfg1);
- ch->r_io[ATA_SERROR].res = ctlr->r_res2;
- ch->r_io[ATA_SERROR].offset = 0x04 + (ch->unit << ctlr->chip->cfg1);
- ch->r_io[ATA_SCONTROL].res = ctlr->r_res2;
- ch->r_io[ATA_SCONTROL].offset = 0x08 + (ch->unit << ctlr->chip->cfg1);
- ch->flags |= ATA_NO_SLAVE;
-
- /* XXX SOS PHY hotplug handling missing in VIA chip ?? */
- /* XXX SOS unknown how to enable PHY state change interrupt */
- return 0;
-}
-
-static void
-ata_via_reset(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
-
- if ((ctlr->chip->cfg2 & VIABAR) && (ch->unit > 1))
- ata_generic_reset(dev);
- else
- if (ata_sata_phy_reset(dev))
- ata_generic_reset(dev);
-}
-
-static void
-ata_via_setmode(device_t dev, int mode)
-{
- device_t gparent = GRANDPARENT(dev);
- struct ata_pci_controller *ctlr = device_get_softc(gparent);
- struct ata_channel *ch = device_get_softc(device_get_parent(dev));
- struct ata_device *atadev = device_get_softc(dev);
- int error;
-
- if ((ctlr->chip->cfg2 & VIABAR) && (ch->unit > 1)) {
- u_int8_t pio_timings[] = { 0xa8, 0x65, 0x65, 0x32, 0x20,
- 0x65, 0x32, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 };
- u_int8_t dma_timings[] = { 0xee, 0xe8, 0xe6, 0xe4, 0xe2, 0xe1, 0xe0 };
-
- mode = ata_check_80pin(dev, ata_limit_mode(dev, mode, ATA_UDMA6));
- error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
- if (bootverbose)
- device_printf(dev, "%ssetting %s on %s chip\n",
- (error) ? "FAILURE " : "", ata_mode2str(mode),
- ctlr->chip->text);
- if (!error) {
- pci_write_config(gparent, 0xab, pio_timings[ata_mode2idx(mode)], 1);
- if (mode >= ATA_UDMA0)
- pci_write_config(gparent, 0xb3,
- dma_timings[mode & ATA_MODE_MASK], 1);
- atadev->mode = mode;
- }
- }
- else
- ata_sata_setmode(dev, mode);
-}
-
-static void
-ata_via_southbridge_fixup(device_t dev)
-{
- device_t *children;
- int nchildren, i;
-
- if (device_get_children(device_get_parent(dev), &children, &nchildren))
- return;
-
- for (i = 0; i < nchildren; i++) {
- if (pci_get_devid(children[i]) == ATA_VIA8363 ||
- pci_get_devid(children[i]) == ATA_VIA8371 ||
- pci_get_devid(children[i]) == ATA_VIA8662 ||
- pci_get_devid(children[i]) == ATA_VIA8361) {
- u_int8_t reg76 = pci_read_config(children[i], 0x76, 1);
-
- if ((reg76 & 0xf0) != 0xd0) {
- device_printf(dev,
- "Correcting VIA config for southbridge data corruption bug\n");
- pci_write_config(children[i], 0x75, 0x80, 1);
- pci_write_config(children[i], 0x76, (reg76 & 0x0f) | 0xd0, 1);
- }
- break;
- }
- }
- free(children, M_TEMP);
-}
-
-
-/* common code for VIA, AMD & nVidia */
-static void
-ata_via_family_setmode(device_t dev, int mode)
-{
- device_t gparent = GRANDPARENT(dev);
- struct ata_pci_controller *ctlr = device_get_softc(gparent);
- struct ata_channel *ch = device_get_softc(device_get_parent(dev));
- struct ata_device *atadev = device_get_softc(dev);
- u_int8_t timings[] = { 0xa8, 0x65, 0x42, 0x22, 0x20, 0x42, 0x22, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 };
- int modes[][7] = {
- { 0xc2, 0xc1, 0xc0, 0x00, 0x00, 0x00, 0x00 }, /* VIA ATA33 */
- { 0xee, 0xec, 0xea, 0xe9, 0xe8, 0x00, 0x00 }, /* VIA ATA66 */
- { 0xf7, 0xf6, 0xf4, 0xf2, 0xf1, 0xf0, 0x00 }, /* VIA ATA100 */
- { 0xf7, 0xf7, 0xf6, 0xf4, 0xf2, 0xf1, 0xf0 }, /* VIA ATA133 */
- { 0xc2, 0xc1, 0xc0, 0xc4, 0xc5, 0xc6, 0xc7 }}; /* AMD/nVIDIA */
- int devno = (ch->unit << 1) + atadev->unit;
- int reg = 0x53 - devno;
- int error;
-
- mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma);
-
- if (ctlr->chip->cfg2 & AMDCABLE) {
- if (mode > ATA_UDMA2 &&
- !(pci_read_config(gparent, 0x42, 1) & (1 << devno))) {
- ata_print_cable(dev, "controller");
- mode = ATA_UDMA2;
- }
- }
- else
- mode = ata_check_80pin(dev, mode);
-
- if (ctlr->chip->cfg2 & NVIDIA)
- reg += 0x10;
-
- if (ctlr->chip->cfg1 != VIA133)
- pci_write_config(gparent, reg - 0x08, timings[ata_mode2idx(mode)], 1);
-
- error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
-
- if (bootverbose)
- device_printf(dev, "%ssetting %s on %s chip\n",
- (error) ? "FAILURE " : "", ata_mode2str(mode),
- ctlr->chip->text);
- if (!error) {
- if (mode >= ATA_UDMA0)
- pci_write_config(gparent, reg,
- modes[ctlr->chip->cfg1][mode & ATA_MODE_MASK], 1);
- else
- pci_write_config(gparent, reg, 0x8b, 1);
- atadev->mode = mode;
- }
-}
-
-
-/* misc functions */
-static void
-ata_set_desc(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
- char buffer[128];
-
- sprintf(buffer, "%s %s %s controller",
- ata_pcivendor2str(dev), ctlr->chip->text,
- ata_mode2str(ctlr->chip->max_dma));
- device_set_desc_copy(dev, buffer);
-}
-
-static struct ata_chip_id *
-ata_match_chip(device_t dev, struct ata_chip_id *index)
-{
- while (index->chipid != 0) {
- if (pci_get_devid(dev) == index->chipid &&
- pci_get_revid(dev) >= index->chiprev)
- return index;
- index++;
- }
- return NULL;
-}
-
-static struct ata_chip_id *
-ata_find_chip(device_t dev, struct ata_chip_id *index, int slot)
-{
- device_t *children;
- int nchildren, i;
-
- if (device_get_children(device_get_parent(dev), &children, &nchildren))
- return 0;
-
- while (index->chipid != 0) {
- for (i = 0; i < nchildren; i++) {
- if (((slot >= 0 && pci_get_slot(children[i]) == slot) ||
- (slot < 0 && pci_get_slot(children[i]) <= -slot)) &&
- pci_get_devid(children[i]) == index->chipid &&
- pci_get_revid(children[i]) >= index->chiprev) {
- free(children, M_TEMP);
- return index;
- }
- }
- index++;
- }
- free(children, M_TEMP);
- return NULL;
-}
-
-static int
-ata_setup_interrupt(device_t dev)
-{
- struct ata_pci_controller *ctlr = device_get_softc(dev);
- int rid = ATA_IRQ_RID;
-
- if (!ata_legacy(dev)) {
- if (!(ctlr->r_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
- RF_SHAREABLE | RF_ACTIVE))) {
- device_printf(dev, "unable to map interrupt\n");
- return ENXIO;
- }
- if ((bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, NULL,
- ata_generic_intr, ctlr, &ctlr->handle))) {
- /* SOS XXX release r_irq */
- device_printf(dev, "unable to setup interrupt\n");
- return ENXIO;
- }
- }
- return 0;
-}
-
-struct ata_serialize {
- struct mtx locked_mtx;
- int locked_ch;
- int restart_ch;
-};
-
-static int
-ata_serialize(device_t dev, int flags)
-{
- struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
- struct ata_channel *ch = device_get_softc(dev);
- struct ata_serialize *serial;
- static int inited = 0;
- int res;
-
- if (!inited) {
- serial = malloc(sizeof(struct ata_serialize),
- M_TEMP, M_NOWAIT | M_ZERO);
- mtx_init(&serial->locked_mtx, "ATA serialize lock", NULL, MTX_DEF);
- serial->locked_ch = -1;
- serial->restart_ch = -1;
- device_set_ivars(ctlr->dev, serial);
- inited = 1;
- }
- else
- serial = device_get_ivars(ctlr->dev);
-
- mtx_lock(&serial->locked_mtx);
- switch (flags) {
- case ATA_LF_LOCK:
- if (serial->locked_ch == -1)
- serial->locked_ch = ch->unit;
- if (serial->locked_ch != ch->unit)
- serial->restart_ch = ch->unit;
- break;
-
- case ATA_LF_UNLOCK:
- if (serial->locked_ch == ch->unit) {
- serial->locked_ch = -1;
- if (serial->restart_ch != -1) {
- if ((ch = ctlr->interrupt[serial->restart_ch].argument)) {
- serial->restart_ch = -1;
- mtx_unlock(&serial->locked_mtx);
- ata_start(dev);
- return -1;
- }
- }
- }
- break;
-
- case ATA_LF_WHICH:
- break;
- }
- res = serial->locked_ch;
- mtx_unlock(&serial->locked_mtx);
- return res;
-}
-
-static void
-ata_print_cable(device_t dev, u_int8_t *who)
-{
- device_printf(dev,
- "DMA limited to UDMA33, %s found non-ATA66 cable\n", who);
-}
-
-static int
-ata_atapi(device_t dev)
-{
- struct ata_channel *ch = device_get_softc(device_get_parent(dev));
- struct ata_device *atadev = device_get_softc(dev);
-
- return ((atadev->unit == ATA_MASTER && ch->devices & ATA_ATAPI_MASTER) ||
- (atadev->unit == ATA_SLAVE && ch->devices & ATA_ATAPI_SLAVE));
-}
-
-static int
-ata_check_80pin(device_t dev, int mode)
-{
- struct ata_device *atadev = device_get_softc(dev);
-
- if (!ata_dma_check_80pin) {
- if (bootverbose)
- device_printf(dev, "Skipping 80pin cable check\n");
- return mode;
- }
-
- if (mode > ATA_UDMA2 && !(atadev->param.hwres & ATA_CABLE_ID)) {
- ata_print_cable(dev, "device");
- mode = ATA_UDMA2;
- }
- return mode;
-}
-
-static int
-ata_mode2idx(int mode)
-{
- if ((mode & ATA_DMA_MASK) == ATA_UDMA0)
- return (mode & ATA_MODE_MASK) + 8;
- if ((mode & ATA_DMA_MASK) == ATA_WDMA0)
- return (mode & ATA_MODE_MASK) + 5;
- return (mode & ATA_MODE_MASK) - ATA_PIO0;
-}
diff --git a/sys/dev/ata/ata-dma.c b/sys/dev/ata/ata-dma.c
index 4006724..5ef1a5e 100644
--- a/sys/dev/ata/ata-dma.c
+++ b/sys/dev/ata/ata-dma.c
@@ -81,7 +81,7 @@ ata_dmainit(device_t dev)
ch->dma.segsize = 63536;
ch->dma.max_iosize = 128 * DEV_BSIZE;
ch->dma.max_address = BUS_SPACE_MAXADDR_32BIT;
- ch->dma.dma_slots = 2;
+ ch->dma.dma_slots = 6;
if (bus_dma_tag_create(bus_get_dma_tag(dev), ch->dma.alignment, 0,
ch->dma.max_address, BUS_SPACE_MAXADDR,
diff --git a/sys/dev/ata/ata-pci.c b/sys/dev/ata/ata-pci.c
index e9dded4..855a1d0 100644
--- a/sys/dev/ata/ata-pci.c
+++ b/sys/dev/ata/ata-pci.c
@@ -54,140 +54,34 @@ static MALLOC_DEFINE(M_ATAPCI, "ata_pci", "ATA driver PCI");
/* misc defines */
#define IOMASK 0xfffffffc
-#define ATA_PROBE_OK -10
-int
-ata_legacy(device_t dev)
-{
- return (((pci_read_config(dev, PCIR_PROGIF, 1)&PCIP_STORAGE_IDE_MASTERDEV)&&
- ((pci_read_config(dev, PCIR_PROGIF, 1) &
- (PCIP_STORAGE_IDE_MODEPRIM | PCIP_STORAGE_IDE_MODESEC)) !=
- (PCIP_STORAGE_IDE_MODEPRIM | PCIP_STORAGE_IDE_MODESEC))) ||
- (!pci_read_config(dev, PCIR_BAR(0), 4) &&
- !pci_read_config(dev, PCIR_BAR(1), 4) &&
- !pci_read_config(dev, PCIR_BAR(2), 4) &&
- !pci_read_config(dev, PCIR_BAR(3), 4) &&
- !pci_read_config(dev, PCIR_BAR(5), 4)));
-}
+/* local prototypes */
+static int ata_generic_chipinit(device_t dev);
+static void ata_generic_setmode(device_t dev, int mode);
+/*
+ * generic PCI ATA device probe
+ */
int
ata_pci_probe(device_t dev)
{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+ char buffer[64];
+
+ /* is this a storage class device ? */
if (pci_get_class(dev) != PCIC_STORAGE)
return ENXIO;
- /* if this is an AHCI chipset grab it */
- if (pci_get_subclass(dev) == PCIS_STORAGE_SATA) {
- if (!ata_ahci_ident(dev))
- return ATA_PROBE_OK;
- }
-
- /* run through the vendor specific drivers */
- switch (pci_get_vendor(dev)) {
- case ATA_ACARD_ID:
- if (!ata_acard_ident(dev))
- return ATA_PROBE_OK;
- break;
- case ATA_ACER_LABS_ID:
- if (!ata_ali_ident(dev))
- return ATA_PROBE_OK;
- break;
- case ATA_AMD_ID:
- if (!ata_amd_ident(dev))
- return ATA_PROBE_OK;
- break;
- case ATA_ADAPTEC_ID:
- if (!ata_adaptec_ident(dev))
- return ATA_PROBE_OK;
- break;
- case ATA_ATI_ID:
- if (!ata_ati_ident(dev))
- return ATA_PROBE_OK;
- break;
- case ATA_CYRIX_ID:
- if (!ata_cyrix_ident(dev))
- return ATA_PROBE_OK;
- break;
- case ATA_CYPRESS_ID:
- if (!ata_cypress_ident(dev))
- return ATA_PROBE_OK;
- break;
- case ATA_HIGHPOINT_ID:
- if (!ata_highpoint_ident(dev))
- return ATA_PROBE_OK;
- break;
- case ATA_INTEL_ID:
- if (!ata_intel_ident(dev))
- return ATA_PROBE_OK;
- break;
- case ATA_ITE_ID:
- if (!ata_ite_ident(dev))
- return ATA_PROBE_OK;
- break;
- case ATA_JMICRON_ID:
- if (!ata_jmicron_ident(dev))
- return ATA_PROBE_OK;
- break;
- case ATA_MARVELL_ID:
- if (!ata_marvell_ident(dev))
- return ATA_PROBE_OK;
- break;
- case ATA_NATIONAL_ID:
- if (!ata_national_ident(dev))
- return ATA_PROBE_OK;
- break;
- case ATA_NETCELL_ID:
- if (!ata_netcell_ident(dev))
- return ATA_PROBE_OK;
- break;
- case ATA_NVIDIA_ID:
- if (!ata_nvidia_ident(dev))
- return ATA_PROBE_OK;
- break;
- case ATA_PROMISE_ID:
- if (!ata_promise_ident(dev))
- return ATA_PROBE_OK;
- break;
- case ATA_SERVERWORKS_ID:
- if (!ata_serverworks_ident(dev))
- return ATA_PROBE_OK;
- break;
- case ATA_SILICON_IMAGE_ID:
- if (!ata_sii_ident(dev))
- return ATA_PROBE_OK;
- break;
- case ATA_SIS_ID:
- if (!ata_sis_ident(dev))
- return ATA_PROBE_OK;
- break;
- case ATA_VIA_ID:
- if (!ata_via_ident(dev))
- return ATA_PROBE_OK;
- break;
- case ATA_CENATEK_ID:
- if (pci_get_devid(dev) == ATA_CENATEK_ROCKET) {
- ata_generic_ident(dev);
- device_set_desc(dev, "Cenatek Rocket Drive controller");
- return ATA_PROBE_OK;
- }
- break;
- case ATA_MICRON_ID:
- if (pci_get_devid(dev) == ATA_MICRON_RZ1000 ||
- pci_get_devid(dev) == ATA_MICRON_RZ1001) {
- ata_generic_ident(dev);
- device_set_desc(dev,
- "RZ 100? ATA controller !WARNING! data loss/corruption risk");
- return ATA_PROBE_OK;
- }
- break;
- }
+ /* is this an IDE/ATA type device ? */
+ if (pci_get_subclass(dev) != PCIS_STORAGE_IDE)
+ return ENXIO;
+
+ sprintf(buffer, "%s ATA controller", ata_pcivendor2str(dev));
+ device_set_desc_copy(dev, buffer);
+ ctlr->chipinit = ata_generic_chipinit;
- /* unknown chipset, try generic DMA if it seems possible */
- if (pci_get_subclass(dev) == PCIS_STORAGE_IDE) {
- if (!ata_generic_ident(dev))
- return ATA_PROBE_OK;
- }
- return ENXIO;
+ /* we are a low priority handler */
+ return -100;
}
int
@@ -286,7 +180,6 @@ ata_pci_resume(device_t dev)
return error;
}
-
struct resource *
ata_pci_alloc_resource(device_t dev, device_t child, int type, int *rid,
u_long start, u_long end, u_long count, u_int flags)
@@ -414,6 +307,28 @@ ata_pci_teardown_intr(device_t dev, device_t child, struct resource *irq,
}
}
+static void
+ata_generic_setmode(device_t dev, int mode)
+{
+ struct ata_device *atadev = device_get_softc(dev);
+
+ mode = ata_limit_mode(dev, mode, ATA_UDMA2);
+ mode = ata_check_80pin(dev, mode);
+ if (!ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode))
+ atadev->mode = mode;
+}
+
+static int
+ata_generic_chipinit(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+
+ if (ata_setup_interrupt(dev, ata_generic_intr))
+ return ENXIO;
+ ctlr->setmode = ata_generic_setmode;
+ return 0;
+}
+
int
ata_pci_allocate(device_t dev)
{
@@ -545,35 +460,6 @@ ata_pci_dmainit(device_t dev)
ch->dma.reset = ata_pci_dmareset;
}
-char *
-ata_pcivendor2str(device_t dev)
-{
- switch (pci_get_vendor(dev)) {
- case ATA_ACARD_ID: return "Acard";
- case ATA_ACER_LABS_ID: return "AcerLabs";
- case ATA_AMD_ID: return "AMD";
- case ATA_ADAPTEC_ID: return "Adaptec";
- case ATA_ATI_ID: return "ATI";
- case ATA_CYRIX_ID: return "Cyrix";
- case ATA_CYPRESS_ID: return "Cypress";
- case ATA_HIGHPOINT_ID: return "HighPoint";
- case ATA_INTEL_ID: return "Intel";
- case ATA_ITE_ID: return "ITE";
- case ATA_JMICRON_ID: return "JMicron";
- case ATA_MARVELL_ID: return "Marvell";
- case ATA_NATIONAL_ID: return "National";
- case ATA_NETCELL_ID: return "Netcell";
- case ATA_NVIDIA_ID: return "nVidia";
- case ATA_PROMISE_ID: return "Promise";
- case ATA_SERVERWORKS_ID: return "ServerWorks";
- case ATA_SILICON_IMAGE_ID: return "SiI";
- case ATA_SIS_ID: return "SiS";
- case ATA_VIA_ID: return "VIA";
- case ATA_CENATEK_ID: return "Cenatek";
- case ATA_MICRON_ID: return "Micron";
- default: return "Generic";
- }
-}
static device_method_t ata_pci_methods[] = {
/* device interface */
@@ -595,7 +481,7 @@ static device_method_t ata_pci_methods[] = {
{ 0, 0 }
};
-devclass_t atapci_devclass;
+devclass_t ata_pci_devclass;
static driver_t ata_pci_driver = {
"atapci",
@@ -603,7 +489,7 @@ static driver_t ata_pci_driver = {
sizeof(struct ata_pci_controller),
};
-DRIVER_MODULE(atapci, pci, ata_pci_driver, atapci_devclass, 0, 0);
+DRIVER_MODULE(atapci, pci, ata_pci_driver, ata_pci_devclass, 0, 0);
MODULE_VERSION(atapci, 1);
MODULE_DEPEND(atapci, ata, 1, 1, 1);
@@ -728,3 +614,171 @@ driver_t ata_pcichannel_driver = {
};
DRIVER_MODULE(ata, atapci, ata_pcichannel_driver, ata_devclass, 0, 0);
+
+
+/*
+ * misc support fucntions
+ */
+int
+ata_legacy(device_t dev)
+{
+ return (((pci_read_config(dev, PCIR_PROGIF, 1)&PCIP_STORAGE_IDE_MASTERDEV)&&
+ ((pci_read_config(dev, PCIR_PROGIF, 1) &
+ (PCIP_STORAGE_IDE_MODEPRIM | PCIP_STORAGE_IDE_MODESEC)) !=
+ (PCIP_STORAGE_IDE_MODEPRIM | PCIP_STORAGE_IDE_MODESEC))) ||
+ (!pci_read_config(dev, PCIR_BAR(0), 4) &&
+ !pci_read_config(dev, PCIR_BAR(1), 4) &&
+ !pci_read_config(dev, PCIR_BAR(2), 4) &&
+ !pci_read_config(dev, PCIR_BAR(3), 4) &&
+ !pci_read_config(dev, PCIR_BAR(5), 4)));
+}
+
+void
+ata_generic_intr(void *data)
+{
+ struct ata_pci_controller *ctlr = data;
+ struct ata_channel *ch;
+ int unit;
+
+ for (unit = 0; unit < ctlr->channels; unit++) {
+ if ((ch = ctlr->interrupt[unit].argument))
+ ctlr->interrupt[unit].function(ch);
+ }
+}
+
+int
+ata_setup_interrupt(device_t dev, void *intr_func)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+ int rid = ATA_IRQ_RID;
+
+ if (!ata_legacy(dev)) {
+ if (!(ctlr->r_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+ RF_SHAREABLE | RF_ACTIVE))) {
+ device_printf(dev, "unable to map interrupt\n");
+ return ENXIO;
+ }
+ if ((bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, NULL,
+ intr_func, ctlr, &ctlr->handle))) {
+ /* SOS XXX release r_irq */
+ device_printf(dev, "unable to setup interrupt\n");
+ return ENXIO;
+ }
+ }
+ return 0;
+}
+
+void
+ata_set_desc(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+ char buffer[128];
+
+ sprintf(buffer, "%s %s %s controller",
+ ata_pcivendor2str(dev), ctlr->chip->text,
+ ata_mode2str(ctlr->chip->max_dma));
+ device_set_desc_copy(dev, buffer);
+}
+
+struct ata_chip_id *
+ata_match_chip(device_t dev, struct ata_chip_id *index)
+{
+ while (index->chipid != 0) {
+ if (pci_get_devid(dev) == index->chipid &&
+ pci_get_revid(dev) >= index->chiprev)
+ return index;
+ index++;
+ }
+ return NULL;
+}
+
+struct ata_chip_id *
+ata_find_chip(device_t dev, struct ata_chip_id *index, int slot)
+{
+ device_t *children;
+ int nchildren, i;
+
+ if (device_get_children(device_get_parent(dev), &children, &nchildren))
+ return 0;
+
+ while (index->chipid != 0) {
+ for (i = 0; i < nchildren; i++) {
+ if (((slot >= 0 && pci_get_slot(children[i]) == slot) ||
+ (slot < 0 && pci_get_slot(children[i]) <= -slot)) &&
+ pci_get_devid(children[i]) == index->chipid &&
+ pci_get_revid(children[i]) >= index->chiprev) {
+ free(children, M_TEMP);
+ return index;
+ }
+ }
+ index++;
+ }
+ free(children, M_TEMP);
+ return NULL;
+}
+
+void
+ata_print_cable(device_t dev, u_int8_t *who)
+{
+ device_printf(dev,
+ "DMA limited to UDMA33, %s found non-ATA66 cable\n", who);
+}
+
+int
+ata_check_80pin(device_t dev, int mode)
+{
+ struct ata_device *atadev = device_get_softc(dev);
+
+ if (!ata_dma_check_80pin) {
+ if (bootverbose)
+ device_printf(dev, "Skipping 80pin cable check\n");
+ return mode;
+ }
+
+ if (mode > ATA_UDMA2 && !(atadev->param.hwres & ATA_CABLE_ID)) {
+ ata_print_cable(dev, "device");
+ mode = ATA_UDMA2;
+ }
+ return mode;
+}
+
+char *
+ata_pcivendor2str(device_t dev)
+{
+ switch (pci_get_vendor(dev)) {
+ case ATA_ACARD_ID: return "Acard";
+ case ATA_ACER_LABS_ID: return "AcerLabs";
+ case ATA_AMD_ID: return "AMD";
+ case ATA_ADAPTEC_ID: return "Adaptec";
+ case ATA_ATI_ID: return "ATI";
+ case ATA_CYRIX_ID: return "Cyrix";
+ case ATA_CYPRESS_ID: return "Cypress";
+ case ATA_HIGHPOINT_ID: return "HighPoint";
+ case ATA_INTEL_ID: return "Intel";
+ case ATA_ITE_ID: return "ITE";
+ case ATA_JMICRON_ID: return "JMicron";
+ case ATA_MARVELL_ID: return "Marvell";
+ case ATA_NATIONAL_ID: return "National";
+ case ATA_NETCELL_ID: return "Netcell";
+ case ATA_NVIDIA_ID: return "nVidia";
+ case ATA_PROMISE_ID: return "Promise";
+ case ATA_SERVERWORKS_ID: return "ServerWorks";
+ case ATA_SILICON_IMAGE_ID: return "SiI";
+ case ATA_SIS_ID: return "SiS";
+ case ATA_VIA_ID: return "VIA";
+ case ATA_CENATEK_ID: return "Cenatek";
+ case ATA_MICRON_ID: return "Micron";
+ default: return "Generic";
+ }
+}
+
+int
+ata_mode2idx(int mode)
+{
+ if ((mode & ATA_DMA_MASK) == ATA_UDMA0)
+ return (mode & ATA_MODE_MASK) + 8;
+ if ((mode & ATA_DMA_MASK) == ATA_WDMA0)
+ return (mode & ATA_MODE_MASK) + 5;
+ return (mode & ATA_MODE_MASK) - ATA_PIO0;
+}
+
diff --git a/sys/dev/ata/ata-pci.h b/sys/dev/ata/ata-pci.h
index bd00404..bdb14aa 100644
--- a/sys/dev/ata/ata-pci.h
+++ b/sys/dev/ata/ata-pci.h
@@ -395,79 +395,6 @@ struct ata_connect_task {
#define ATA_VIA6420 0x31491106
#define ATA_VIA6421 0x32491106
-/* chipset setup related defines */
-#define AHCI 1
-#define ATPOLD 1
-
-#define ALIOLD 0x01
-#define ALINEW 0x02
-#define ALISATA 0x04
-
-#define ATIPATA 0x01
-#define ATISATA 0x02
-#define ATIAHCI 0x04
-
-#define HPT366 0
-#define HPT370 1
-#define HPT372 2
-#define HPT374 3
-#define HPTOLD 0x01
-
-#define MV50XX 50
-#define MV60XX 60
-#define MV61XX 61
-
-#define PROLD 0
-#define PRNEW 1
-#define PRTX 2
-#define PRMIO 3
-#define PRTX4 0x01
-#define PRSX4X 0x02
-#define PRSX6K 0x04
-#define PRPATA 0x08
-#define PRCMBO 0x10
-#define PRCMBO2 0x20
-#define PRSATA 0x40
-#define PRSATA2 0x80
-
-#define SWKS33 0
-#define SWKS66 1
-#define SWKS100 2
-#define SWKSMIO 3
-
-#define SIIMEMIO 1
-#define SIIPRBIO 2
-#define SIIINTR 0x01
-#define SIISETCLK 0x02
-#define SIIBUG 0x04
-#define SII4CH 0x08
-
-#define SIS_SOUTH 1
-#define SISSATA 2
-#define SIS133NEW 3
-#define SIS133OLD 4
-#define SIS100NEW 5
-#define SIS100OLD 6
-#define SIS66 7
-#define SIS33 8
-
-#define VIA33 0
-#define VIA66 1
-#define VIA100 2
-#define VIA133 3
-#define AMDNVIDIA 4
-
-#define AMDCABLE 0x0001
-#define AMDBUG 0x0002
-#define NVIDIA 0x0004
-#define NV4 0x0010
-#define NVQ 0x0020
-#define VIACLK 0x0100
-#define VIABUG 0x0200
-#define VIABAR 0x0400
-#define VIAAHCI 0x0800
-
-
/* global prototypes ata-pci.c */
int ata_pci_probe(device_t dev);
int ata_pci_attach(device_t dev);
@@ -483,32 +410,62 @@ int ata_pci_status(device_t dev);
void ata_pci_hw(device_t dev);
void ata_pci_dmainit(device_t dev);
char *ata_pcivendor2str(device_t dev);
-
-
-/* global prototypes ata-chipset.c */
-int ata_generic_ident(device_t);
-int ata_ahci_ident(device_t);
-int ata_acard_ident(device_t);
-int ata_ali_ident(device_t);
-int ata_amd_ident(device_t);
-int ata_adaptec_ident(device_t);
-int ata_ati_ident(device_t);
-int ata_cyrix_ident(device_t);
-int ata_cypress_ident(device_t);
-int ata_highpoint_ident(device_t);
-int ata_intel_ident(device_t);
-int ata_ite_ident(device_t);
-int ata_jmicron_ident(device_t);
-int ata_marvell_ident(device_t);
-int ata_national_ident(device_t);
-int ata_nvidia_ident(device_t);
-int ata_netcell_ident(device_t);
-int ata_promise_ident(device_t);
-int ata_serverworks_ident(device_t);
-int ata_sii_ident(device_t);
-int ata_sis_ident(device_t);
-int ata_via_ident(device_t);
int ata_legacy(device_t);
+void ata_generic_intr(void *data);
+int ata_setup_interrupt(device_t dev, void *intr_func);
+void ata_set_desc(device_t dev);
+struct ata_chip_id *ata_match_chip(device_t dev, struct ata_chip_id *index);
+struct ata_chip_id *ata_find_chip(device_t dev, struct ata_chip_id *index, int slot);
+void ata_print_cable(device_t dev, u_int8_t *who);
+int ata_check_80pin(device_t dev, int mode);
+int ata_mode2idx(int mode);
+
+/* global prototypes ata-sata.c */
+void ata_sata_phy_event(void *context, int dummy);
+void ata_sata_phy_check_events(device_t dev);
+int ata_sata_phy_reset(device_t dev);
+void ata_sata_setmode(device_t dev, int mode);
+int ata_request2fis_h2d(struct ata_request *request, u_int8_t *fis);
+void ata_pm_identify(device_t dev);
+
+/* global prototypes from chipsets/ata-*.c */
+int ata_ahci_chipinit(device_t);
+int ata_ahci_allocate(device_t dev);
+void ata_ahci_reset(device_t dev);
+void ata_ahci_dmainit(device_t dev);
+int ata_marvell_edma_chipinit(device_t);
+int ata_sii_chipinit(device_t);
/* global prototypes ata-dma.c */
void ata_dmainit(device_t);
+
+/* externs */
+extern devclass_t ata_pci_devclass;
+
+/* macro for easy definition of all driver module stuff */
+#define ATA_DECLARE_DRIVER(dname) \
+static device_method_t __CONCAT(dname,_methods)[] = { \
+ DEVMETHOD(device_probe, __CONCAT(dname,_probe)), \
+ DEVMETHOD(device_attach, ata_pci_attach), \
+ DEVMETHOD(device_detach, ata_pci_detach), \
+ DEVMETHOD(device_suspend, bus_generic_suspend), \
+ DEVMETHOD(device_resume, bus_generic_resume), \
+ DEVMETHOD(device_shutdown, bus_generic_shutdown), \
+ DEVMETHOD(bus_alloc_resource, ata_pci_alloc_resource), \
+ DEVMETHOD(bus_release_resource, ata_pci_release_resource), \
+ DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), \
+ DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), \
+ DEVMETHOD(bus_setup_intr, ata_pci_setup_intr), \
+ DEVMETHOD(bus_teardown_intr, ata_pci_teardown_intr), \
+ { 0, 0 } \
+}; \
+static driver_t __CONCAT(dname,_driver) = { \
+ "atapci", \
+ __CONCAT(dname,_methods), \
+ sizeof(struct ata_pci_controller) \
+}; \
+DRIVER_MODULE(dname, pci, __CONCAT(dname,_driver), ata_pci_devclass, 0, 0); \
+MODULE_VERSION(dname, 1); \
+MODULE_DEPEND(dname, ata, 1, 1, 1); \
+MODULE_DEPEND(dname, atapci, 1, 1, 1);
+
diff --git a/sys/dev/ata/ata-sata.c b/sys/dev/ata/ata-sata.c
new file mode 100644
index 0000000..b65bd56
--- /dev/null
+++ b/sys/dev/ata/ata-sata.c
@@ -0,0 +1,357 @@
+/*-
+ * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org>
+ * 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,
+ * without modification, immediately at the beginning of the file.
+ * 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 AUTHOR ``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 AUTHOR 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>
+__FBSDID("$FreeBSD$");
+
+#include "opt_ata.h"
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/ata.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sema.h>
+#include <sys/taskqueue.h>
+#include <vm/uma.h>
+#include <machine/stdarg.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/ata/ata-all.h>
+#include <dev/ata/ata-pci.h>
+#include <ata_if.h>
+
+/*
+ * SATA support functions
+ */
+void
+ata_sata_phy_event(void *context, int dummy)
+{
+ struct ata_connect_task *tp = (struct ata_connect_task *)context;
+ struct ata_channel *ch = device_get_softc(tp->dev);
+ device_t *children;
+ int nchildren, i;
+
+ mtx_lock(&Giant); /* newbus suckage it needs Giant */
+ if (tp->action == ATA_C_ATTACH) {
+ if (bootverbose)
+ device_printf(tp->dev, "CONNECTED\n");
+ ATA_RESET(tp->dev);
+ ata_identify(tp->dev);
+ }
+ if (tp->action == ATA_C_DETACH) {
+ if (!device_get_children(tp->dev, &children, &nchildren)) {
+ for (i = 0; i < nchildren; i++)
+ if (children[i])
+ device_delete_child(tp->dev, children[i]);
+ free(children, M_TEMP);
+ }
+ mtx_lock(&ch->state_mtx);
+ ch->state = ATA_IDLE;
+ mtx_unlock(&ch->state_mtx);
+ if (bootverbose)
+ device_printf(tp->dev, "DISCONNECTED\n");
+ }
+ mtx_unlock(&Giant); /* suckage code dealt with, release Giant */
+ free(tp, M_ATA);
+}
+
+void
+ata_sata_phy_check_events(device_t dev)
+{
+ struct ata_channel *ch = device_get_softc(dev);
+ u_int32_t error = ATA_IDX_INL(ch, ATA_SERROR);
+
+ /* clear error bits/interrupt */
+ ATA_IDX_OUTL(ch, ATA_SERROR, error);
+
+ /* do we have any events flagged ? */
+ if (error) {
+ struct ata_connect_task *tp;
+ u_int32_t status = ATA_IDX_INL(ch, ATA_SSTATUS);
+
+ /* if we have a connection event deal with it */
+ if ((error & ATA_SE_PHY_CHANGED) &&
+ (tp = (struct ata_connect_task *)
+ malloc(sizeof(struct ata_connect_task),
+ M_ATA, M_NOWAIT | M_ZERO))) {
+
+ if (((status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN1) ||
+ ((status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN2)) {
+ if (bootverbose)
+ device_printf(dev, "CONNECT requested\n");
+ tp->action = ATA_C_ATTACH;
+ }
+ else {
+ if (bootverbose)
+ device_printf(dev, "DISCONNECT requested\n");
+ tp->action = ATA_C_DETACH;
+ }
+ tp->dev = dev;
+ TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp);
+ taskqueue_enqueue(taskqueue_thread, &tp->task);
+ }
+ }
+}
+
+static int
+ata_sata_connect(struct ata_channel *ch)
+{
+ u_int32_t status;
+ int timeout;
+
+ /* wait up to 1 second for "connect well" */
+ for (timeout = 0; timeout < 100 ; timeout++) {
+ status = ATA_IDX_INL(ch, ATA_SSTATUS);
+ if ((status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN1 ||
+ (status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN2)
+ break;
+ ata_udelay(10000);
+ }
+ if (timeout >= 100) {
+ if (bootverbose)
+ device_printf(ch->dev, "SATA connect status=%08x\n", status);
+ return 0;
+ }
+ if (bootverbose)
+ device_printf(ch->dev, "SATA connect time=%dms\n", timeout * 10);
+
+ /* clear SATA error register */
+ ATA_IDX_OUTL(ch, ATA_SERROR, ATA_IDX_INL(ch, ATA_SERROR));
+
+ return 1;
+}
+
+int
+ata_sata_phy_reset(device_t dev)
+{
+ struct ata_channel *ch = device_get_softc(dev);
+ int loop, retry;
+
+ if ((ATA_IDX_INL(ch, ATA_SCONTROL) & ATA_SC_DET_MASK) == ATA_SC_DET_IDLE)
+ return ata_sata_connect(ch);
+
+ for (retry = 0; retry < 10; retry++) {
+ for (loop = 0; loop < 10; loop++) {
+ ATA_IDX_OUTL(ch, ATA_SCONTROL, ATA_SC_DET_RESET);
+ ata_udelay(100);
+ if ((ATA_IDX_INL(ch, ATA_SCONTROL) & ATA_SC_DET_MASK) ==
+ ATA_SC_DET_RESET)
+ break;
+ }
+ ata_udelay(5000);
+ for (loop = 0; loop < 10; loop++) {
+ ATA_IDX_OUTL(ch, ATA_SCONTROL, ATA_SC_DET_IDLE |
+ ATA_SC_IPM_DIS_PARTIAL |
+ ATA_SC_IPM_DIS_SLUMBER);
+ ata_udelay(100);
+ if ((ATA_IDX_INL(ch, ATA_SCONTROL) & ATA_SC_DET_MASK) == 0)
+ return ata_sata_connect(ch);
+ }
+ }
+ return 0;
+}
+
+void
+ata_sata_setmode(device_t dev, int mode)
+{
+ struct ata_device *atadev = device_get_softc(dev);
+
+ /*
+ * if we detect that the device isn't a real SATA device we limit
+ * the transfer mode to UDMA5/ATA100.
+ * this works around the problems some devices has with the
+ * Marvell 88SX8030 SATA->PATA converters and UDMA6/ATA133.
+ */
+ if (atadev->param.satacapabilities != 0x0000 &&
+ atadev->param.satacapabilities != 0xffff) {
+ struct ata_channel *ch = device_get_softc(device_get_parent(dev));
+
+ /* on some drives we need to set the transfer mode */
+ ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0,
+ ata_limit_mode(dev, mode, ATA_UDMA6));
+
+ /* query SATA STATUS for the speed */
+ if (ch->r_io[ATA_SSTATUS].res &&
+ ((ATA_IDX_INL(ch, ATA_SSTATUS) & ATA_SS_CONWELL_MASK) ==
+ ATA_SS_CONWELL_GEN2))
+ atadev->mode = ATA_SA300;
+ else
+ atadev->mode = ATA_SA150;
+ }
+ else {
+ mode = ata_limit_mode(dev, mode, ATA_UDMA5);
+ if (!ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode))
+ atadev->mode = mode;
+ }
+}
+
+int
+ata_request2fis_h2d(struct ata_request *request, u_int8_t *fis)
+{
+ struct ata_device *atadev = device_get_softc(request->dev);
+
+ if (request->flags & ATA_R_ATAPI) {
+ fis[0] = 0x27; /* host to device */
+ fis[1] = 0x80 | (atadev->unit & 0x0f);
+ fis[2] = ATA_PACKET_CMD;
+ if (request->flags & (ATA_R_READ | ATA_R_WRITE))
+ fis[3] = ATA_F_DMA;
+ else {
+ fis[5] = request->transfersize;
+ fis[6] = request->transfersize >> 8;
+ }
+ fis[7] = ATA_D_LBA;
+ fis[15] = ATA_A_4BIT;
+ return 20;
+ }
+ else {
+ ata_modify_if_48bit(request);
+ fis[0] = 0x27; /* host to device */
+ fis[1] = 0x80 | (atadev->unit & 0x0f);
+ fis[2] = request->u.ata.command;
+ fis[3] = request->u.ata.feature;
+ fis[4] = request->u.ata.lba;
+ fis[5] = request->u.ata.lba >> 8;
+ fis[6] = request->u.ata.lba >> 16;
+ fis[7] = ATA_D_LBA;
+ if (!(atadev->flags & ATA_D_48BIT_ACTIVE))
+ fis[7] |= (ATA_D_IBM | (request->u.ata.lba >> 24 & 0x0f));
+ fis[8] = request->u.ata.lba >> 24;
+ fis[9] = request->u.ata.lba >> 32;
+ fis[10] = request->u.ata.lba >> 40;
+ fis[11] = request->u.ata.feature >> 8;
+ fis[12] = request->u.ata.count;
+ fis[13] = request->u.ata.count >> 8;
+ fis[15] = ATA_A_4BIT;
+ return 20;
+ }
+ return 0;
+}
+
+void
+ata_pm_identify(device_t dev)
+{
+ struct ata_channel *ch = device_get_softc(dev);
+ u_int32_t pm_chipid, pm_revision, pm_ports;
+ int port;
+
+ /* get PM vendor & product data */
+ if (ch->hw.pm_read(dev, ATA_PM, 0, &pm_chipid)) {
+ device_printf(dev, "error getting PM vendor data\n");
+ return;
+ }
+
+ /* get PM revision data */
+ if (ch->hw.pm_read(dev, ATA_PM, 1, &pm_revision)) {
+ device_printf(dev, "error getting PM revison data\n");
+ return;
+ }
+
+ /* get number of HW ports on the PM */
+ if (ch->hw.pm_read(dev, ATA_PM, 2, &pm_ports)) {
+ device_printf(dev, "error getting PM port info\n");
+ return;
+ }
+ pm_ports &= 0x0000000f;
+
+ /* chip specific quirks */
+ switch (pm_chipid) {
+ case 0x37261095:
+ /* Some of these bogusly reports 6 ports */
+ pm_ports = 5;
+ device_printf(dev, "SiI 3726 r%x Portmultiplier with %d ports\n",
+ pm_revision, pm_ports);
+ break;
+
+ default:
+ device_printf(dev, "Portmultiplier (id=%08x rev=%x) with %d ports\n",
+ pm_chipid, pm_revision, pm_ports);
+ }
+
+ /* realloc space for needed DMA slots */
+ ch->dma.dma_slots = pm_ports;
+
+ /* reset all ports and register if anything connected */
+ for (port=0; port < pm_ports; port++) {
+ u_int32_t signature, status;
+ int timeout;
+
+ if (ch->hw.pm_write(dev, port, 2, ATA_SC_DET_RESET)) {
+ device_printf(dev, "p%d: writing ATA_SC_DET_RESET failed\n", port);
+ continue;
+ }
+
+ ata_udelay(5000);
+
+ if (ch->hw.pm_write(dev, port, 2, ATA_SC_DET_IDLE)) {
+ device_printf(dev, "p%d: writing ATA_SC_DET_idle failed\n", port);
+ continue;
+ }
+
+ ata_udelay(5000);
+
+ /* wait up to 1 second for "connect well" */
+ for (timeout = 0; timeout < 100 ; timeout++) {
+ ch->hw.pm_read(dev, port, 0, &status);
+ if ((status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN1 ||
+ (status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN2)
+ break;
+ ata_udelay(10000);
+ }
+ if (timeout >= 100) {
+ if (bootverbose)
+ device_printf(dev, "p%d: connect status=%08x\n", port, status);
+ continue;
+ }
+ if (bootverbose)
+ device_printf(dev, "p%d: connect time %dms\n", port, timeout * 10);
+
+ /* clear SERROR register */
+ ch->hw.pm_write(dev, port, 1, 0xffffffff);
+
+ signature = ch->hw.softreset(dev, port);
+
+ if (bootverbose)
+ device_printf(dev, "p%d: SIGNATURE=%08x\n", port, signature);
+
+ /* figure out whats there */
+ switch (signature) {
+ case 0x00000101:
+ ch->devices |= (ATA_ATA_MASTER << port);
+ continue;
+ case 0xeb140101:
+ ch->devices |= (ATA_ATAPI_MASTER << port);
+ continue;
+ }
+ }
+}
diff --git a/sys/dev/ata/chipsets/ata-acard.c b/sys/dev/ata/chipsets/ata-acard.c
new file mode 100644
index 0000000..da4c14c
--- /dev/null
+++ b/sys/dev/ata/chipsets/ata-acard.c
@@ -0,0 +1,285 @@
+/*-
+ * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org>
+ * 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,
+ * without modification, immediately at the beginning of the file.
+ * 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 AUTHOR ``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 AUTHOR 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>
+__FBSDID("$FreeBSD$");
+
+#include "opt_ata.h"
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/ata.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sema.h>
+#include <sys/taskqueue.h>
+#include <vm/uma.h>
+#include <machine/stdarg.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/ata/ata-all.h>
+#include <dev/ata/ata-pci.h>
+#include <ata_if.h>
+
+/* local prototypes */
+static int ata_acard_chipinit(device_t dev);
+static int ata_acard_allocate(device_t dev);
+static int ata_acard_status(device_t dev);
+static void ata_acard_850_setmode(device_t dev, int mode);
+static void ata_acard_86X_setmode(device_t dev, int mode);
+static int ata_serialize(device_t dev, int flags);
+
+/* misc defines */
+#define ATP_OLD 1
+
+
+/*
+ * Acard chipset support functions
+ */
+static int
+ata_acard_probe(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+ static struct ata_chip_id ids[] =
+ {{ ATA_ATP850R, 0, ATP_OLD, 0x00, ATA_UDMA2, "ATP850" },
+ { ATA_ATP860A, 0, 0, 0x00, ATA_UDMA4, "ATP860A" },
+ { ATA_ATP860R, 0, 0, 0x00, ATA_UDMA4, "ATP860R" },
+ { ATA_ATP865A, 0, 0, 0x00, ATA_UDMA6, "ATP865A" },
+ { ATA_ATP865R, 0, 0, 0x00, ATA_UDMA6, "ATP865R" },
+ { 0, 0, 0, 0, 0, 0}};
+
+ if (pci_get_vendor(dev) != ATA_ACARD_ID)
+ return ENXIO;
+
+ if (!(ctlr->chip = ata_match_chip(dev, ids)))
+ return ENXIO;
+
+ ata_set_desc(dev);
+ ctlr->chipinit = ata_acard_chipinit;
+ return 0;
+}
+
+static int
+ata_acard_chipinit(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+
+ if (ata_setup_interrupt(dev, ata_generic_intr))
+ return ENXIO;
+
+ ctlr->allocate = ata_acard_allocate;
+ if (ctlr->chip->cfg1 == ATP_OLD) {
+ ctlr->setmode = ata_acard_850_setmode;
+ ctlr->locking = ata_serialize;
+ }
+ else
+ ctlr->setmode = ata_acard_86X_setmode;
+ return 0;
+}
+
+static int
+ata_acard_allocate(device_t dev)
+{
+ struct ata_channel *ch = device_get_softc(dev);
+
+ /* setup the usual register normal pci style */
+ if (ata_pci_allocate(dev))
+ return ENXIO;
+
+ ch->hw.status = ata_acard_status;
+ return 0;
+}
+
+static int
+ata_acard_status(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+
+ if (ctlr->chip->cfg1 == ATP_OLD &&
+ ATA_LOCKING(dev, ATA_LF_WHICH) != ch->unit)
+ return 0;
+ if (ch->dma.flags & ATA_DMA_ACTIVE) {
+ int bmstat = ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK;
+
+ if ((bmstat & (ATA_BMSTAT_ACTIVE | ATA_BMSTAT_INTERRUPT)) !=
+ ATA_BMSTAT_INTERRUPT)
+ return 0;
+ ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, bmstat & ~ATA_BMSTAT_ERROR);
+ DELAY(1);
+ ATA_IDX_OUTB(ch, ATA_BMCMD_PORT,
+ ATA_IDX_INB(ch, ATA_BMCMD_PORT) & ~ATA_BMCMD_START_STOP);
+ DELAY(1);
+ }
+ if (ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_BUSY) {
+ DELAY(100);
+ if (ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_BUSY)
+ return 0;
+ }
+ return 1;
+}
+
+static void
+ata_acard_850_setmode(device_t dev, int mode)
+{
+ device_t gparent = GRANDPARENT(dev);
+ struct ata_pci_controller *ctlr = device_get_softc(gparent);
+ struct ata_channel *ch = device_get_softc(device_get_parent(dev));
+ struct ata_device *atadev = device_get_softc(dev);
+ int devno = (ch->unit << 1) + atadev->unit;
+ int error;
+
+ mode = ata_limit_mode(dev, mode,
+ ata_atapi(dev) ? ATA_PIO_MAX : ctlr->chip->max_dma);
+
+ /* XXX SOS missing WDMA0+1 + PIO modes */
+ if (mode >= ATA_WDMA2) {
+ error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
+ if (bootverbose)
+ device_printf(dev, "%ssetting %s on %s chip\n",
+ (error) ? "FAILURE " : "",
+ ata_mode2str(mode), ctlr->chip->text);
+ if (!error) {
+ u_int8_t reg54 = pci_read_config(gparent, 0x54, 1);
+
+ reg54 &= ~(0x03 << (devno << 1));
+ if (mode >= ATA_UDMA0)
+ reg54 |= (((mode & ATA_MODE_MASK) + 1) << (devno << 1));
+ pci_write_config(gparent, 0x54, reg54, 1);
+ pci_write_config(gparent, 0x4a, 0xa6, 1);
+ pci_write_config(gparent, 0x40 + (devno << 1), 0x0301, 2);
+ atadev->mode = mode;
+ return;
+ }
+ }
+ /* we could set PIO mode timings, but we assume the BIOS did that */
+}
+
+static void
+ata_acard_86X_setmode(device_t dev, int mode)
+{
+ device_t gparent = GRANDPARENT(dev);
+ struct ata_pci_controller *ctlr = device_get_softc(gparent);
+ struct ata_channel *ch = device_get_softc(device_get_parent(dev));
+ struct ata_device *atadev = device_get_softc(dev);
+ int devno = (ch->unit << 1) + atadev->unit;
+ int error;
+
+
+ mode = ata_limit_mode(dev, mode,
+ ata_atapi(dev) ? ATA_PIO_MAX : ctlr->chip->max_dma);
+
+ mode = ata_check_80pin(dev, mode);
+
+ /* XXX SOS missing WDMA0+1 + PIO modes */
+ if (mode >= ATA_WDMA2) {
+ error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
+ if (bootverbose)
+ device_printf(dev, "%ssetting %s on %s chip\n",
+ (error) ? "FAILURE " : "",
+ ata_mode2str(mode), ctlr->chip->text);
+ if (!error) {
+ u_int16_t reg44 = pci_read_config(gparent, 0x44, 2);
+
+ reg44 &= ~(0x000f << (devno << 2));
+ if (mode >= ATA_UDMA0)
+ reg44 |= (((mode & ATA_MODE_MASK) + 1) << (devno << 2));
+ pci_write_config(gparent, 0x44, reg44, 2);
+ pci_write_config(gparent, 0x4a, 0xa6, 1);
+ pci_write_config(gparent, 0x40 + devno, 0x31, 1);
+ atadev->mode = mode;
+ return;
+ }
+ }
+ /* we could set PIO mode timings, but we assume the BIOS did that */
+}
+
+struct ata_serialize {
+ struct mtx locked_mtx;
+ int locked_ch;
+ int restart_ch;
+};
+
+static int
+ata_serialize(device_t dev, int flags)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ struct ata_serialize *serial;
+ static int inited = 0;
+ int res;
+
+ if (!inited) {
+ serial = malloc(sizeof(struct ata_serialize),
+ M_TEMP, M_NOWAIT | M_ZERO);
+ mtx_init(&serial->locked_mtx, "ATA serialize lock", NULL, MTX_DEF);
+ serial->locked_ch = -1;
+ serial->restart_ch = -1;
+ device_set_ivars(ctlr->dev, serial);
+ inited = 1;
+ }
+ else
+ serial = device_get_ivars(ctlr->dev);
+
+ mtx_lock(&serial->locked_mtx);
+ switch (flags) {
+ case ATA_LF_LOCK:
+ if (serial->locked_ch == -1)
+ serial->locked_ch = ch->unit;
+ if (serial->locked_ch != ch->unit)
+ serial->restart_ch = ch->unit;
+ break;
+
+ case ATA_LF_UNLOCK:
+ if (serial->locked_ch == ch->unit) {
+ serial->locked_ch = -1;
+ if (serial->restart_ch != -1) {
+ if ((ch = ctlr->interrupt[serial->restart_ch].argument)) {
+ serial->restart_ch = -1;
+ mtx_unlock(&serial->locked_mtx);
+ ata_start(dev);
+ return -1;
+ }
+ }
+ }
+ break;
+
+ case ATA_LF_WHICH:
+ break;
+ }
+ res = serial->locked_ch;
+ mtx_unlock(&serial->locked_mtx);
+ return res;
+}
+
+ATA_DECLARE_DRIVER(ata_acard);
diff --git a/sys/dev/ata/chipsets/ata-acerlabs.c b/sys/dev/ata/chipsets/ata-acerlabs.c
new file mode 100644
index 0000000..6e54bc4
--- /dev/null
+++ b/sys/dev/ata/chipsets/ata-acerlabs.c
@@ -0,0 +1,307 @@
+/*-
+ * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org>
+ * 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,
+ * without modification, immediately at the beginning of the file.
+ * 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 AUTHOR ``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 AUTHOR 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>
+__FBSDID("$FreeBSD$");
+
+#include "opt_ata.h"
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/ata.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sema.h>
+#include <sys/taskqueue.h>
+#include <vm/uma.h>
+#include <machine/stdarg.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/ata/ata-all.h>
+#include <dev/ata/ata-pci.h>
+#include <ata_if.h>
+
+/* local prototypes */
+static int ata_ali_chipinit(device_t dev);
+static int ata_ali_allocate(device_t dev);
+static int ata_ali_sata_allocate(device_t dev);
+static void ata_ali_reset(device_t dev);
+static void ata_ali_setmode(device_t dev, int mode);
+
+/* misc defines */
+#define ALI_OLD 0x01
+#define ALI_NEW 0x02
+#define ALI_SATA 0x04
+
+
+/*
+ * Acer Labs Inc (ALI) chipset support functions
+ */
+static int
+ata_ali_probe(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+ static struct ata_chip_id ids[] =
+ {{ ATA_ALI_5289, 0x00, 2, ALI_SATA, ATA_SA150, "M5289" },
+ { ATA_ALI_5288, 0x00, 4, ALI_SATA, ATA_SA300, "M5288" },
+ { ATA_ALI_5287, 0x00, 4, ALI_SATA, ATA_SA150, "M5287" },
+ { ATA_ALI_5281, 0x00, 2, ALI_SATA, ATA_SA150, "M5281" },
+ { ATA_ALI_5229, 0xc5, 0, ALI_NEW, ATA_UDMA6, "M5229" },
+ { ATA_ALI_5229, 0xc4, 0, ALI_NEW, ATA_UDMA5, "M5229" },
+ { ATA_ALI_5229, 0xc2, 0, ALI_NEW, ATA_UDMA4, "M5229" },
+ { ATA_ALI_5229, 0x20, 0, ALI_OLD, ATA_UDMA2, "M5229" },
+ { ATA_ALI_5229, 0x00, 0, ALI_OLD, ATA_WDMA2, "M5229" },
+ { 0, 0, 0, 0, 0, 0}};
+
+ if (pci_get_vendor(dev) != ATA_ACER_LABS_ID)
+ return ENXIO;
+
+ if (!(ctlr->chip = ata_match_chip(dev, ids)))
+ return ENXIO;
+
+ ata_set_desc(dev);
+ ctlr->chipinit = ata_ali_chipinit;
+ return 0;
+}
+
+static int
+ata_ali_chipinit(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+
+ if (ata_setup_interrupt(dev, ata_generic_intr))
+ return ENXIO;
+
+ switch (ctlr->chip->cfg2) {
+ case ALI_SATA:
+ ctlr->channels = ctlr->chip->cfg1;
+ ctlr->allocate = ata_ali_sata_allocate;
+ ctlr->setmode = ata_sata_setmode;
+
+ /* AHCI mode is correctly supported only on the ALi 5288. */
+ if ((ctlr->chip->chipid == ATA_ALI_5288) &&
+ (ata_ahci_chipinit(dev) != ENXIO))
+ return 0;
+
+ /* enable PCI interrupt */
+ pci_write_config(dev, PCIR_COMMAND,
+ pci_read_config(dev, PCIR_COMMAND, 2) & ~0x0400, 2);
+ break;
+
+ case ALI_NEW:
+ /* use device interrupt as byte count end */
+ pci_write_config(dev, 0x4a, pci_read_config(dev, 0x4a, 1) | 0x20, 1);
+
+ /* enable cable detection and UDMA support on newer chips */
+ pci_write_config(dev, 0x4b, pci_read_config(dev, 0x4b, 1) | 0x09, 1);
+
+ /* enable ATAPI UDMA mode */
+ pci_write_config(dev, 0x53, pci_read_config(dev, 0x53, 1) | 0x01, 1);
+
+ /* only chips with revision > 0xc4 can do 48bit DMA */
+ if (ctlr->chip->chiprev <= 0xc4)
+ device_printf(dev,
+ "using PIO transfers above 137GB as workaround for "
+ "48bit DMA access bug, expect reduced performance\n");
+ ctlr->allocate = ata_ali_allocate;
+ ctlr->reset = ata_ali_reset;
+ ctlr->setmode = ata_ali_setmode;
+ break;
+
+ case ALI_OLD:
+ /* deactivate the ATAPI FIFO and enable ATAPI UDMA */
+ pci_write_config(dev, 0x53, pci_read_config(dev, 0x53, 1) | 0x03, 1);
+ ctlr->setmode = ata_ali_setmode;
+ break;
+ }
+ return 0;
+}
+
+static int
+ata_ali_allocate(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+
+ /* setup the usual register normal pci style */
+ if (ata_pci_allocate(dev))
+ return ENXIO;
+
+ /* older chips can't do 48bit DMA transfers */
+ if (ctlr->chip->chiprev <= 0xc4)
+ ch->flags |= ATA_NO_48BIT_DMA;
+
+ return 0;
+}
+
+static int
+ata_ali_sata_allocate(device_t dev)
+{
+ device_t parent = device_get_parent(dev);
+ struct ata_pci_controller *ctlr = device_get_softc(parent);
+ struct ata_channel *ch = device_get_softc(dev);
+ struct resource *io = NULL, *ctlio = NULL;
+ int unit01 = (ch->unit & 1), unit10 = (ch->unit & 2);
+ int i, rid;
+
+ rid = PCIR_BAR(0) + (unit01 ? 8 : 0);
+ io = bus_alloc_resource_any(parent, SYS_RES_IOPORT, &rid, RF_ACTIVE);
+ if (!io)
+ return ENXIO;
+
+ rid = PCIR_BAR(1) + (unit01 ? 8 : 0);
+ ctlio = bus_alloc_resource_any(parent, SYS_RES_IOPORT, &rid, RF_ACTIVE);
+ if (!ctlio) {
+ bus_release_resource(dev, SYS_RES_IOPORT, ATA_IOADDR_RID, io);
+ return ENXIO;
+ }
+
+ for (i = ATA_DATA; i <= ATA_COMMAND; i ++) {
+ ch->r_io[i].res = io;
+ ch->r_io[i].offset = i + (unit10 ? 8 : 0);
+ }
+ ch->r_io[ATA_CONTROL].res = ctlio;
+ ch->r_io[ATA_CONTROL].offset = 2 + (unit10 ? 4 : 0);
+ ch->r_io[ATA_IDX_ADDR].res = io;
+ ata_default_registers(dev);
+ if (ctlr->r_res1) {
+ for (i = ATA_BMCMD_PORT; i <= ATA_BMDTP_PORT; i++) {
+ ch->r_io[i].res = ctlr->r_res1;
+ ch->r_io[i].offset = (i - ATA_BMCMD_PORT)+(ch->unit * ATA_BMIOSIZE);
+ }
+ }
+ ch->flags |= ATA_NO_SLAVE;
+
+ /* XXX SOS PHY handling awkward in ALI chip not supported yet */
+ ata_pci_hw(dev);
+ return 0;
+}
+
+static void
+ata_ali_reset(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ device_t *children;
+ int nchildren, i;
+
+ ata_generic_reset(dev);
+
+ /*
+ * workaround for datacorruption bug found on at least SUN Blade-100
+ * find the ISA function on the southbridge and disable then enable
+ * the ATA channel tristate buffer
+ */
+ if (ctlr->chip->chiprev == 0xc3 || ctlr->chip->chiprev == 0xc2) {
+ if (!device_get_children(GRANDPARENT(dev), &children, &nchildren)) {
+ for (i = 0; i < nchildren; i++) {
+ if (pci_get_devid(children[i]) == ATA_ALI_1533) {
+ pci_write_config(children[i], 0x58,
+ pci_read_config(children[i], 0x58, 1) &
+ ~(0x04 << ch->unit), 1);
+ pci_write_config(children[i], 0x58,
+ pci_read_config(children[i], 0x58, 1) |
+ (0x04 << ch->unit), 1);
+ break;
+ }
+ }
+ free(children, M_TEMP);
+ }
+ }
+}
+
+static void
+ata_ali_setmode(device_t dev, int mode)
+{
+ device_t gparent = GRANDPARENT(dev);
+ struct ata_pci_controller *ctlr = device_get_softc(gparent);
+ struct ata_channel *ch = device_get_softc(device_get_parent(dev));
+ struct ata_device *atadev = device_get_softc(dev);
+ int devno = (ch->unit << 1) + atadev->unit;
+ int error;
+
+ mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma);
+
+ if (ctlr->chip->cfg2 & ALI_NEW) {
+ if (mode > ATA_UDMA2 &&
+ pci_read_config(gparent, 0x4a, 1) & (1 << ch->unit)) {
+ ata_print_cable(dev, "controller");
+ mode = ATA_UDMA2;
+ }
+ }
+ else
+ mode = ata_check_80pin(dev, mode);
+
+ if (ctlr->chip->cfg2 & ALI_OLD) {
+ /* doesn't support ATAPI DMA on write */
+ ch->flags |= ATA_ATAPI_DMA_RO;
+ if (ch->devices & ATA_ATAPI_MASTER && ch->devices & ATA_ATAPI_SLAVE) {
+ /* doesn't support ATAPI DMA on two ATAPI devices */
+ device_printf(dev, "two atapi devices on this channel, no DMA\n");
+ mode = ata_limit_mode(dev, mode, ATA_PIO_MAX);
+ }
+ }
+
+ error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
+
+ if (bootverbose)
+ device_printf(dev, "%ssetting %s on %s chip\n",
+ (error) ? "FAILURE " : "",
+ ata_mode2str(mode), ctlr->chip->text);
+ if (!error) {
+ if (mode >= ATA_UDMA0) {
+ u_int8_t udma[] = {0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0d};
+ u_int32_t word54 = pci_read_config(gparent, 0x54, 4);
+
+ word54 &= ~(0x000f000f << (devno << 2));
+ word54 |= (((udma[mode&ATA_MODE_MASK]<<16)|0x05)<<(devno<<2));
+ pci_write_config(gparent, 0x54, word54, 4);
+ pci_write_config(gparent, 0x58 + (ch->unit << 2),
+ 0x00310001, 4);
+ }
+ else {
+ u_int32_t piotimings[] =
+ { 0x006d0003, 0x00580002, 0x00440001, 0x00330001,
+ 0x00310001, 0x00440001, 0x00330001, 0x00310001};
+
+ pci_write_config(gparent, 0x54, pci_read_config(gparent, 0x54, 4) &
+ ~(0x0008000f << (devno << 2)), 4);
+ pci_write_config(gparent, 0x58 + (ch->unit << 2),
+ piotimings[ata_mode2idx(mode)], 4);
+ }
+ atadev->mode = mode;
+ }
+}
+
+ATA_DECLARE_DRIVER(ata_ali);
+MODULE_DEPEND(ata_ali, ata_ahci, 1, 1, 1);
diff --git a/sys/dev/ata/chipsets/ata-adaptec.c b/sys/dev/ata/chipsets/ata-adaptec.c
new file mode 100644
index 0000000..11bb8be
--- /dev/null
+++ b/sys/dev/ata/chipsets/ata-adaptec.c
@@ -0,0 +1,82 @@
+/*-
+ * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org>
+ * 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,
+ * without modification, immediately at the beginning of the file.
+ * 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 AUTHOR ``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 AUTHOR 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>
+__FBSDID("$FreeBSD$");
+
+#include "opt_ata.h"
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/ata.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sema.h>
+#include <sys/taskqueue.h>
+#include <vm/uma.h>
+#include <machine/stdarg.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/ata/ata-all.h>
+#include <dev/ata/ata-pci.h>
+#include <ata_if.h>
+
+/* misc defines */
+#define MV_60XX 60 //must match ata_marvell.c's definition
+
+
+/*
+ * Adaptec chipset support functions
+ */
+static int
+ata_adaptec_probe(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+ static struct ata_chip_id ids[] =
+ {{ ATA_ADAPTEC_1420, 0, 4, MV_60XX, ATA_SA300, "1420SA" },
+ { 0, 0, 0, 0, 0, 0}};
+
+ if (pci_get_vendor(dev) != ATA_ADAPTEC_ID)
+ return ENXIO;
+
+ if (!(ctlr->chip = ata_match_chip(dev, ids)))
+ return ENXIO;
+
+ ata_set_desc(dev);
+ ctlr->chipinit = ata_marvell_edma_chipinit;
+
+ return 0;
+}
+
+ATA_DECLARE_DRIVER(ata_adaptec);
+MODULE_DEPEND(ata_adaptec, ata_marvell, 1, 1, 1);
diff --git a/sys/dev/ata/chipsets/ata-ahci.c b/sys/dev/ata/chipsets/ata-ahci.c
new file mode 100644
index 0000000..4481d9a
--- /dev/null
+++ b/sys/dev/ata/chipsets/ata-ahci.c
@@ -0,0 +1,744 @@
+/*-
+ * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org>
+ * 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,
+ * without modification, immediately at the beginning of the file.
+ * 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 AUTHOR ``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 AUTHOR 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>
+__FBSDID("$FreeBSD$");
+
+#include "opt_ata.h"
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/ata.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sema.h>
+#include <sys/taskqueue.h>
+#include <vm/uma.h>
+#include <machine/stdarg.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/ata/ata-all.h>
+#include <dev/ata/ata-pci.h>
+#include <ata_if.h>
+
+/* local prototypes */
+static int ata_ahci_ctlr_reset(device_t dev);
+static int ata_ahci_suspend(device_t dev);
+static int ata_ahci_status(device_t dev);
+static int ata_ahci_begin_transaction(struct ata_request *request);
+static int ata_ahci_end_transaction(struct ata_request *request);
+static int ata_ahci_pm_read(device_t dev, int port, int reg, u_int32_t *result);
+static int ata_ahci_pm_write(device_t dev, int port, int reg, u_int32_t result);
+static u_int32_t ata_ahci_softreset(device_t dev, int port);
+static void ata_ahci_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error);
+static int ata_ahci_setup_fis(struct ata_ahci_cmd_tab *ctp, struct ata_request *equest);
+
+/*
+ * AHCI v1.x compliant SATA chipset support functions
+ */
+static int
+ata_ahci_probe(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+ char buffer[64];
+
+ /* is this a possible AHCI candidate ? */
+ if (pci_get_subclass(dev) != PCIS_STORAGE_SATA)
+ return ENXIO;
+
+ /* is this PCI device flagged as an AHCI compliant chip ? */
+ if (pci_read_config(dev, PCIR_PROGIF, 1) != PCIP_STORAGE_SATA_AHCI_1_0)
+ return ENXIO;
+
+ if (bootverbose)
+ sprintf(buffer, "%s (ID=%08x) AHCI controller",
+ ata_pcivendor2str(dev), pci_get_devid(dev));
+ else
+ sprintf(buffer, "%s AHCI controller", ata_pcivendor2str(dev));
+ device_set_desc_copy(dev, buffer);
+ ctlr->chipinit = ata_ahci_chipinit;
+ return 0;
+}
+
+int
+ata_ahci_chipinit(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+ u_int32_t version;
+
+ /* if we have a memory BAR(5) we are likely on an AHCI part */
+ ctlr->r_type2 = SYS_RES_MEMORY;
+ ctlr->r_rid2 = PCIR_BAR(5);
+ if (!(ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2,
+ &ctlr->r_rid2, RF_ACTIVE)))
+ return ENXIO;
+
+ /* setup interrupt delivery if not done allready by a vendor driver */
+ if (!ctlr->r_irq) {
+ if (ata_setup_interrupt(dev, ata_generic_intr))
+ return ENXIO;
+ }
+ else
+ device_printf(dev, "AHCI called from vendor specific driver\n");
+
+ /* reset controller */
+ ata_ahci_ctlr_reset(dev);
+
+ /* get the number of HW channels */
+ ctlr->channels =
+ MAX(flsl(ATA_INL(ctlr->r_res2, ATA_AHCI_PI)),
+ (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_NPMASK) + 1);
+
+ ctlr->reset = ata_ahci_reset;
+ ctlr->dmainit = ata_ahci_dmainit;
+ ctlr->allocate = ata_ahci_allocate;
+ ctlr->setmode = ata_sata_setmode;
+ ctlr->suspend = ata_ahci_suspend;
+ ctlr->resume = ata_ahci_ctlr_reset;
+
+ /* enable PCI interrupt */
+ pci_write_config(dev, PCIR_COMMAND,
+ pci_read_config(dev, PCIR_COMMAND, 2) & ~0x0400, 2);
+
+ /* announce we support the HW */
+ version = ATA_INL(ctlr->r_res2, ATA_AHCI_VS);
+ device_printf(dev,
+ "AHCI Version %x%x.%x%x controller with %d ports PM %s\n",
+ (version >> 24) & 0xff, (version >> 16) & 0xff,
+ (version >> 8) & 0xff, version & 0xff,
+ (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_NPMASK) + 1,
+ (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_SPM) ?
+ "supported" : "not supported");
+ return 0;
+}
+
+static int
+ata_ahci_ctlr_reset(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+
+ /* enable AHCI mode */
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_AE);
+
+ /* reset AHCI controller */
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_HR);
+ DELAY(1000000);
+ if (ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) & ATA_AHCI_GHC_HR) {
+ bus_release_resource(dev, ctlr->r_type2, ctlr->r_rid2, ctlr->r_res2);
+ device_printf(dev, "AHCI controller reset failure\n");
+ return ENXIO;
+ }
+
+ /* reenable AHCI mode */
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_AE);
+
+ /* clear interrupts */
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_IS, ATA_INL(ctlr->r_res2, ATA_AHCI_IS));
+
+ /* enable AHCI interrupts */
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC,
+ ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) | ATA_AHCI_GHC_IE);
+
+ return 0;
+}
+
+static int
+ata_ahci_suspend(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+
+ /* disable interupts so the state change(s) doesn't trigger */
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC,
+ ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) & (~ATA_AHCI_GHC_IE));
+ return 0;
+}
+
+
+int
+ata_ahci_allocate(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ int offset = ch->unit << 7;
+
+ /* set the SATA resources */
+ ch->r_io[ATA_SSTATUS].res = ctlr->r_res2;
+ ch->r_io[ATA_SSTATUS].offset = ATA_AHCI_P_SSTS + offset;
+ ch->r_io[ATA_SERROR].res = ctlr->r_res2;
+ ch->r_io[ATA_SERROR].offset = ATA_AHCI_P_SERR + offset;
+ ch->r_io[ATA_SCONTROL].res = ctlr->r_res2;
+ ch->r_io[ATA_SCONTROL].offset = ATA_AHCI_P_SCTL + offset;
+ ch->r_io[ATA_SACTIVE].res = ctlr->r_res2;
+ ch->r_io[ATA_SACTIVE].offset = ATA_AHCI_P_SACT + offset;
+
+ ch->hw.status = ata_ahci_status;
+ ch->hw.begin_transaction = ata_ahci_begin_transaction;
+ ch->hw.end_transaction = ata_ahci_end_transaction;
+ ch->hw.command = NULL; /* not used here */
+ ch->hw.softreset = ata_ahci_softreset;
+ ch->hw.pm_read = ata_ahci_pm_read;
+ ch->hw.pm_write = ata_ahci_pm_write;
+
+ return 0;
+}
+
+static int
+ata_ahci_status(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ u_int32_t action = ATA_INL(ctlr->r_res2, ATA_AHCI_IS);
+ int offset = ch->unit << 7;
+
+#define ATA_AHCI_STATBITS \
+ (ATA_AHCI_P_IX_IF|ATA_AHCI_P_IX_HBD|ATA_AHCI_P_IX_HBF|ATA_AHCI_P_IX_TFE)
+
+ if (action & (1 << ch->unit)) {
+ u_int32_t istatus = ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset);
+ u_int32_t cstatus = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CI + offset);
+
+ /* clear interrupt(s) */
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IS + offset, istatus);
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_IS, action & (1 << ch->unit));
+
+ /* do we have any PHY events ? */
+ if (istatus & (ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC))
+ ata_sata_phy_check_events(dev);
+
+ /* do we have a potentially hanging engine to take care of? */
+ /* XXX SOS what todo on NCQ */
+ if ((istatus & ATA_AHCI_STATBITS) && (cstatus & 1)) {
+
+ u_int32_t cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset);
+ int timeout = 0;
+
+ /* kill off all activity on this channel */
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
+ cmd & ~(ATA_AHCI_P_CMD_FRE | ATA_AHCI_P_CMD_ST));
+
+ /* XXX SOS this is not entirely wrong */
+ do {
+ DELAY(1000);
+ if (timeout++ > 1000) {
+ device_printf(dev, "stopping AHCI engine failed\n");
+ break;
+ }
+ } while (ATA_INL(ctlr->r_res2,
+ ATA_AHCI_P_CMD + offset) & ATA_AHCI_P_CMD_CR);
+
+ /* start operations on this channel */
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
+ cmd | (ATA_AHCI_P_CMD_FRE | ATA_AHCI_P_CMD_ST));
+
+ return 1;
+ }
+ else
+ /* XXX SOS what todo on NCQ */
+ return (!(cstatus & 1));
+ }
+ return 0;
+}
+
+/* must be called with ATA channel locked and state_mtx held */
+static int
+ata_ahci_begin_transaction(struct ata_request *request)
+{
+ struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev));
+ struct ata_channel *ch = device_get_softc(request->parent);
+ struct ata_device *atadev = device_get_softc(request->dev);
+ struct ata_ahci_cmd_tab *ctp;
+ struct ata_ahci_cmd_list *clp;
+ int offset = ch->unit << 7;
+ int port = atadev->unit & 0x0f;
+ int entries = 0;
+ int fis_size;
+
+ /* get a piece of the workspace for this request */
+ ctp = (struct ata_ahci_cmd_tab *)
+ (ch->dma.work + ATA_AHCI_CT_OFFSET + (ATA_AHCI_CT_SIZE*request->tag));
+
+ /* setup the FIS for this request */
+ if (!(fis_size = ata_ahci_setup_fis(ctp, request))) {
+ device_printf(request->dev, "setting up SATA FIS failed\n");
+ request->result = EIO;
+ return ATA_OP_FINISHED;
+ }
+
+ /* if request moves data setup and load SG list */
+ if (request->flags & (ATA_R_READ | ATA_R_WRITE)) {
+ if (ch->dma.load(request, ctp->prd_tab, &entries)) {
+ device_printf(request->dev, "setting up DMA failed\n");
+ request->result = EIO;
+ return ATA_OP_FINISHED;
+ }
+ }
+
+ /* setup the command list entry */
+ clp = (struct ata_ahci_cmd_list *)
+ (ch->dma.work + ATA_AHCI_CL_OFFSET + (ATA_AHCI_CL_SIZE*request->tag));
+
+ clp->prd_length = entries;
+ clp->cmd_flags = (request->flags & ATA_R_WRITE ? ATA_AHCI_CMD_WRITE : 0) |
+ (request->flags & ATA_R_ATAPI ?
+ (ATA_AHCI_CMD_ATAPI | ATA_AHCI_CMD_PREFETCH) : 0) |
+ (fis_size / sizeof(u_int32_t)) |
+ (port << 12);
+ clp->bytecount = 0;
+ clp->cmd_table_phys = htole64(ch->dma.work_bus + ATA_AHCI_CT_OFFSET +
+ (ATA_AHCI_CT_SIZE * request->tag));
+
+ /* clear eventual ACTIVE bit */
+ ATA_IDX_OUTL(ch, ATA_SACTIVE,
+ ATA_IDX_INL(ch, ATA_SACTIVE) & (1 << request->tag));
+
+ /* set command type bit */
+ if (request->flags & ATA_R_ATAPI)
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
+ ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) |
+ ATA_AHCI_P_CMD_ATAPI);
+ else
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
+ ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) &
+ ~ATA_AHCI_P_CMD_ATAPI);
+
+ /* set PM port to address */
+ //ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FBS + offset, (port << 8) | 0x00000001);
+
+ /* issue command to controller */
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CI + offset, (1 << request->tag));
+
+ if (!(request->flags & ATA_R_ATAPI)) {
+ /* device reset doesn't interrupt */
+ if (request->u.ata.command == ATA_DEVICE_RESET) {
+ u_int32_t tf_data;
+ int timeout = 1000000;
+
+ do {
+ DELAY(10);
+ tf_data = ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + (ch->unit<<7));
+ } while ((tf_data & ATA_S_BUSY) && timeout--);
+ if (bootverbose)
+ device_printf(ch->dev, "device_reset timeout=%dus\n",
+ (1000000-timeout)*10);
+ request->status = tf_data;
+ if (request->status & ATA_S_ERROR)
+ request->error = tf_data >> 8;
+ return ATA_OP_FINISHED;
+ }
+ }
+
+ /* start the timeout */
+ callout_reset(&request->callout, request->timeout * hz,
+ (timeout_t*)ata_timeout, request);
+ return ATA_OP_CONTINUES;
+}
+
+/* must be called with ATA channel locked and state_mtx held */
+static int
+ata_ahci_end_transaction(struct ata_request *request)
+{
+ struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev));
+ struct ata_channel *ch = device_get_softc(request->parent);
+ struct ata_ahci_cmd_list *clp;
+ u_int32_t tf_data;
+ int offset = ch->unit << 7;
+
+ /* kill the timeout */
+ callout_stop(&request->callout);
+
+ /* get status */
+ tf_data = ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + offset);
+ request->status = tf_data;
+
+ /* if error status get details */
+ if (request->status & ATA_S_ERROR)
+ request->error = tf_data >> 8;
+
+ /* on control commands read back registers to the request struct */
+ if (request->flags & ATA_R_CONTROL) {
+ struct ata_device *atadev = device_get_softc(request->dev);
+ u_int8_t *fis = ch->dma.work + ATA_AHCI_FB_OFFSET + 0x40;
+
+ request->u.ata.count = fis[12] | ((u_int16_t)fis[13] << 8);
+ request->u.ata.lba = fis[4] | ((u_int64_t)fis[5] << 8) |
+ ((u_int64_t)fis[6] << 16);
+ if (atadev->flags & ATA_D_48BIT_ACTIVE)
+ request->u.ata.lba |= ((u_int64_t)fis[8] << 24) |
+ ((u_int64_t)fis[9] << 32) |
+ ((u_int64_t)fis[10] << 40);
+ else
+ request->u.ata.lba |= ((u_int64_t)(fis[7] & 0x0f) << 24);
+ }
+
+ /* record how much data we actually moved */
+ clp = (struct ata_ahci_cmd_list *)
+ (ch->dma.work + ATA_AHCI_CL_OFFSET + (ATA_AHCI_CL_SIZE*request->tag));
+ request->donecount = clp->bytecount;
+
+ /* release SG list etc */
+ ch->dma.unload(request);
+
+ return ATA_OP_FINISHED;
+}
+
+static int
+ata_ahci_issue_cmd(device_t dev, u_int16_t flags, int timeout)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ struct ata_ahci_cmd_list *clp =
+ (struct ata_ahci_cmd_list *)(ch->dma.work + ATA_AHCI_CL_OFFSET);
+ struct ata_ahci_cmd_tab *ctp =
+ (struct ata_ahci_cmd_tab *)(ch->dma.work + ATA_AHCI_CT_OFFSET);
+ u_int32_t status = 0;
+ int offset = ch->unit << 7;
+ int port = (ctp->cfis[1] & 0x0f);
+ int count;
+
+ clp->prd_length = 0;
+ clp->cmd_flags = (20 / sizeof(u_int32_t)) | flags | (port << 12);
+ clp->bytecount = 0;
+ clp->cmd_table_phys = htole64(ch->dma.work_bus + ATA_AHCI_CT_OFFSET);
+
+ /* set PM port */
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FBS + offset, (port << 8) | 0x00000001);
+
+ /* issue command to controller */
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CI + offset, 1);
+
+ /* poll for command finished */
+ for (count = 0; count < timeout; count++) {
+ DELAY(1000);
+ if (!((status = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CI + offset)) & 1))
+ break;
+ }
+
+ /* clear interrupts */
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IS + offset,
+ ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset));
+
+ if (bootverbose)
+ device_printf(dev, "ahci_issue_cmd time=%dms cnt=%dms status=%08x\n",
+ timeout, count, status);
+ if (timeout && (count >= timeout))
+ return EIO;
+
+ return 0;
+}
+
+static int
+ata_ahci_pm_read(device_t dev, int port, int reg, u_int32_t *result)
+{
+ struct ata_channel *ch = device_get_softc(dev);
+ struct ata_ahci_cmd_tab *ctp =
+ (struct ata_ahci_cmd_tab *)(ch->dma.work + ATA_AHCI_CT_OFFSET);
+ u_int8_t *fis = ch->dma.work + ATA_AHCI_FB_OFFSET + 0x40;
+
+ bzero(ctp->cfis, 64);
+ ctp->cfis[0] = 0x27; /* host to device */
+ ctp->cfis[1] = 0x8f; /* command FIS to PM port */
+ ctp->cfis[2] = ATA_READ_PM;
+ ctp->cfis[3] = reg;
+ ctp->cfis[7] = port | ATA_D_LBA;
+ ctp->cfis[15] = ATA_A_4BIT;
+
+ if (ata_ahci_issue_cmd(dev, 0, 10)) {
+ device_printf(dev, "error reading PM port\n");
+ return EIO;
+ }
+
+ *result = fis[12] | (fis[4] << 8) | (fis[5] << 16) | (fis[6] << 24);
+ return 0;
+}
+
+static int
+ata_ahci_pm_write(device_t dev, int port, int reg, u_int32_t value)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ struct ata_ahci_cmd_tab *ctp =
+ (struct ata_ahci_cmd_tab *)(ch->dma.work + ATA_AHCI_CT_OFFSET);
+ int offset = ch->unit << 7;
+
+ bzero(ctp->cfis, 64);
+ ctp->cfis[0] = 0x27; /* host to device */
+ ctp->cfis[1] = 0x8f; /* command FIS to PM port */
+ ctp->cfis[2] = ATA_WRITE_PM;
+ ctp->cfis[3] = reg;
+ ctp->cfis[7] = port | ATA_D_LBA;
+ ctp->cfis[12] = value & 0xff;
+ ctp->cfis[4] = (value >> 8) & 0xff;;
+ ctp->cfis[5] = (value >> 16) & 0xff;;
+ ctp->cfis[6] = (value >> 24) & 0xff;;
+ ctp->cfis[15] = ATA_A_4BIT;
+
+ if (ata_ahci_issue_cmd(dev, 0, 100)) {
+ device_printf(dev, "error writing PM port\n");
+ return ATA_E_ABORT;
+ }
+
+ return (ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + offset) >> 8) & 0xff;
+}
+
+static void
+ata_ahci_restart(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ u_int32_t cmd;
+ int offset = ch->unit << 7;
+ int timeout;
+
+ /* kill off all activity on this channel */
+ cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset);
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
+ cmd & ~(ATA_AHCI_P_CMD_FRE | ATA_AHCI_P_CMD_ST));
+
+ /* XXX SOS this is not entirely wrong */
+ timeout = 0;
+ do {
+ DELAY(1000);
+ if (timeout++ > 1000) {
+ device_printf(dev, "stopping AHCI engine failed\n");
+ break;
+ }
+ }
+ while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) & ATA_AHCI_P_CMD_CR);
+
+ /* issue Command List Override if supported */
+ if (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_CLO) {
+ cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset);
+ cmd |= ATA_AHCI_P_CMD_CLO;
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, cmd);
+ timeout = 0;
+ do {
+ DELAY(1000);
+ if (timeout++ > 1000) {
+ device_printf(dev, "executing CLO failed\n");
+ break;
+ }
+ }
+ while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD+offset)&ATA_AHCI_P_CMD_CLO);
+ }
+
+ /* clear SATA error register */
+ ATA_IDX_OUTL(ch, ATA_SERROR, ATA_IDX_INL(ch, ATA_SERROR));
+
+ /* clear any interrupts pending on this channel */
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IS + offset,
+ ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset));
+
+ /* start operations on this channel */
+ cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset);
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
+ cmd | (ATA_AHCI_P_CMD_FRE | ATA_AHCI_P_CMD_ST) |
+ (ch->devices & ATA_PORTMULTIPLIER ? ATA_AHCI_P_CMD_PMA : 0));
+}
+
+static u_int32_t
+ata_ahci_softreset(device_t dev, int port)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ int offset = ch->unit << 7;
+ int timeout = 0;
+#ifdef AHCI_PM
+ struct ata_ahci_cmd_tab *ctp =
+ (struct ata_ahci_cmd_tab *)(ch->dma.work + ATA_AHCI_CT_OFFSET);
+
+ /* kick controller into sane state if needed */
+ ata_ahci_restart(dev);
+
+ /* pull reset active */
+ bzero(ctp->cfis, 64);
+ ctp->cfis[0] = 0x27;
+ ctp->cfis[1] = port & 0x0f;
+ //ctp->cfis[7] = ATA_D_LBA | ATA_D_IBM;
+ ctp->cfis[15] = (ATA_A_4BIT | ATA_A_RESET);
+
+ if (ata_ahci_issue_cmd(dev, ATA_AHCI_CMD_RESET | ATA_AHCI_CMD_CLR_BUSY,100))
+ device_printf(dev, "setting SRST failed ??\n");
+ //return -1;
+
+ ata_udelay(5000);
+
+ /* pull reset inactive -> device softreset */
+ bzero(ctp->cfis, 64);
+ ctp->cfis[0] = 0x27;
+ ctp->cfis[1] = port & 0x0f;
+ //ctp->cfis[7] = ATA_D_LBA | ATA_D_IBM;
+ ctp->cfis[15] = ATA_A_4BIT;
+ if (ata_ahci_issue_cmd(dev, 0, 0))
+ return -1;
+
+ ata_udelay(150000);
+
+#endif
+ do {
+ DELAY(1000);
+ if (timeout++ > 1000) {
+ device_printf(dev, "still BUSY after softreset\n");
+ break;
+ }
+ } while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + offset) & ATA_S_BUSY);
+ if (bootverbose)
+ device_printf(dev, "BUSY wait time=%dms\n", timeout);
+
+ return ATA_INL(ctlr->r_res2, ATA_AHCI_P_SIG + offset);
+}
+
+void
+ata_ahci_reset(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ u_int64_t work;
+ u_int32_t cmd, signature;
+ int offset = ch->unit << 7;
+
+ if (!(ATA_INL(ctlr->r_res2, ATA_AHCI_PI) & (1 << ch->unit))) {
+ device_printf(dev, "port not implemented\n");
+ return;
+ }
+
+ /* setup work areas */
+ work = ch->dma.work_bus + ATA_AHCI_CL_OFFSET;
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CLB + offset, work & 0xffffffff);
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CLBU + offset, work >> 32);
+
+ work = ch->dma.work_bus + ATA_AHCI_FB_OFFSET;
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FB + offset, work & 0xffffffff);
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FBU + offset, work >> 32);
+
+ /* enable wanted port interrupts */
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IE + offset,
+ (ATA_AHCI_P_IX_CPD | ATA_AHCI_P_IX_TFE | ATA_AHCI_P_IX_HBF |
+ ATA_AHCI_P_IX_HBD | ATA_AHCI_P_IX_IF | ATA_AHCI_P_IX_OF |
+ ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC | ATA_AHCI_P_IX_DP |
+ ATA_AHCI_P_IX_UF | ATA_AHCI_P_IX_SDB | ATA_AHCI_P_IX_DS |
+ ATA_AHCI_P_IX_PS | ATA_AHCI_P_IX_DHR));
+
+ /* activate the channel and power/spin up device */
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
+ (ATA_AHCI_P_CMD_ACTIVE | ATA_AHCI_P_CMD_POD | ATA_AHCI_P_CMD_SUD));
+
+ ata_ahci_restart(dev);
+
+ /* enable FIS based switching */
+ //ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FBS + offset, 0x00000003);
+
+ if (!ata_sata_phy_reset(dev)) {
+ if (bootverbose)
+ device_printf(dev, "phy reset found no device\n");
+ ch->devices = 0;
+
+ /* kill off all activity on this channel */
+ cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset);
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
+ cmd & ~(ATA_AHCI_P_CMD_FRE | ATA_AHCI_P_CMD_ST));
+ return;
+ }
+
+ /* only probe for PortMultiplier if HW has support */
+ if (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_SPM)
+ signature = ata_ahci_softreset(dev, ATA_PM);
+ else {
+ signature = ata_ahci_softreset(dev, 0);
+ }
+ if (bootverbose)
+ device_printf(dev, "SIGNATURE: %08x\n", signature);
+
+ switch (signature) {
+ case 0x00000101:
+ ch->devices = ATA_ATA_MASTER;
+ break;
+ case 0x96690101:
+ ch->devices = ATA_PORTMULTIPLIER;
+ ata_pm_identify(dev);
+ break;
+ case 0xeb140101:
+ ch->devices = ATA_ATAPI_MASTER;
+ break;
+ default: /* SOS XXX */
+ if (bootverbose)
+ device_printf(dev, "No signature, asuming disk device\n");
+ ch->devices = ATA_ATA_MASTER;
+ }
+ if (bootverbose)
+ device_printf(dev, "ahci_reset devices=%08x\n", ch->devices);
+}
+
+static void
+ata_ahci_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error)
+{
+ struct ata_dmasetprd_args *args = xsc;
+ struct ata_ahci_dma_prd *prd = args->dmatab;
+ int i;
+
+ if (!(args->error = error)) {
+ for (i = 0; i < nsegs; i++) {
+ prd[i].dba = htole64(segs[i].ds_addr);
+ prd[i].dbc = htole32((segs[i].ds_len - 1) & ATA_AHCI_PRD_MASK);
+ }
+ }
+
+ KASSERT(nsegs <= ATA_AHCI_DMA_ENTRIES, ("too many DMA segment entries\n"));
+ args->nsegs = nsegs;
+}
+
+void
+ata_ahci_dmainit(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+
+ ata_dmainit(dev);
+ /* note start and stop are not used here */
+ ch->dma.setprd = ata_ahci_dmasetprd;
+ ch->dma.max_iosize = 8192 * DEV_BSIZE;
+ if (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_64BIT)
+ ch->dma.max_address = BUS_SPACE_MAXADDR;
+}
+
+static int
+ata_ahci_setup_fis(struct ata_ahci_cmd_tab *ctp, struct ata_request *request)
+{
+ bzero(ctp->cfis, 64);
+ if (request->flags & ATA_R_ATAPI) {
+ bzero(ctp->acmd, 32);
+ bcopy(request->u.atapi.ccb, ctp->acmd, 16);
+ }
+ return ata_request2fis_h2d(request, &ctp->cfis[0]);
+}
+
+ATA_DECLARE_DRIVER(ata_ahci);
diff --git a/sys/dev/ata/chipsets/ata-amd.c b/sys/dev/ata/chipsets/ata-amd.c
new file mode 100644
index 0000000..a376444
--- /dev/null
+++ b/sys/dev/ata/chipsets/ata-amd.c
@@ -0,0 +1,149 @@
+/*-
+ * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org>
+ * 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,
+ * without modification, immediately at the beginning of the file.
+ * 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 AUTHOR ``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 AUTHOR 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>
+__FBSDID("$FreeBSD$");
+
+#include "opt_ata.h"
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/ata.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sema.h>
+#include <sys/taskqueue.h>
+#include <vm/uma.h>
+#include <machine/stdarg.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/ata/ata-all.h>
+#include <dev/ata/ata-pci.h>
+#include <ata_if.h>
+
+/* local prototypes */
+static int ata_amd_chipinit(device_t dev);
+static void ata_amd_setmode(device_t dev, int mode);
+
+/* misc defines */
+#define AMD_BUG 0x01
+#define AMD_CABLE 0x02
+
+
+/*
+ * American Micro Devices (AMD) chipset support functions
+ */
+static int
+ata_amd_probe(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+ static struct ata_chip_id ids[] =
+ {{ ATA_AMD756, 0x00, 0x00, 0, ATA_UDMA4, "756" },
+ { ATA_AMD766, 0x00, AMD_CABLE|AMD_BUG, 0, ATA_UDMA5, "766" },
+ { ATA_AMD768, 0x00, AMD_CABLE, 0, ATA_UDMA5, "768" },
+ { ATA_AMD8111, 0x00, AMD_CABLE, 0, ATA_UDMA6, "8111" },
+ { ATA_AMD5536, 0x00, 0x00, 0, ATA_UDMA5, "CS5536" },
+ { 0, 0, 0, 0, 0, 0}};
+
+ if (pci_get_vendor(dev) != ATA_AMD_ID)
+ return ENXIO;
+
+ if (!(ctlr->chip = ata_match_chip(dev, ids)))
+ return ENXIO;
+
+ ata_set_desc(dev);
+ ctlr->chipinit = ata_amd_chipinit;
+ return 0;
+}
+
+static int
+ata_amd_chipinit(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+
+ if (ata_setup_interrupt(dev, ata_generic_intr))
+ return ENXIO;
+
+ /* disable/set prefetch, postwrite */
+ if (ctlr->chip->cfg1 & AMD_BUG)
+ pci_write_config(dev, 0x41, pci_read_config(dev, 0x41, 1) & 0x0f, 1);
+ else
+ pci_write_config(dev, 0x41, pci_read_config(dev, 0x41, 1) | 0xf0, 1);
+
+ ctlr->setmode = ata_amd_setmode;
+ return 0;
+}
+
+static void
+ata_amd_setmode(device_t dev, int mode)
+{
+ device_t gparent = GRANDPARENT(dev);
+ struct ata_pci_controller *ctlr = device_get_softc(gparent);
+ struct ata_channel *ch = device_get_softc(device_get_parent(dev));
+ struct ata_device *atadev = device_get_softc(dev);
+ u_int8_t timings[] = { 0xa8, 0x65, 0x42, 0x22, 0x20, 0x42, 0x22, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 };
+ int modes[7] = { 0xc2, 0xc1, 0xc0, 0xc4, 0xc5, 0xc6, 0xc7 };
+ int devno = (ch->unit << 1) + atadev->unit;
+ int reg = 0x53 - devno;
+ int error;
+
+ mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma);
+
+ if (ctlr->chip->cfg1 & AMD_CABLE) {
+ if (mode > ATA_UDMA2 &&
+ !(pci_read_config(gparent, 0x42, 1) & (1 << devno))) {
+ ata_print_cable(dev, "controller");
+ mode = ATA_UDMA2;
+ }
+ }
+ else
+ mode = ata_check_80pin(dev, mode);
+
+
+ error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
+ if (bootverbose)
+ device_printf(dev, "%ssetting %s on %s chip\n",
+ (error) ? "FAILURE " : "", ata_mode2str(mode),
+ ctlr->chip->text);
+ if (!error) {
+ pci_write_config(gparent, reg - 0x08, timings[ata_mode2idx(mode)], 1);
+ if (mode >= ATA_UDMA0)
+ pci_write_config(gparent, reg, modes[mode & ATA_MODE_MASK], 1);
+ else
+ pci_write_config(gparent, reg, 0x8b, 1);
+ atadev->mode = mode;
+ }
+}
+
+ATA_DECLARE_DRIVER(ata_amd);
diff --git a/sys/dev/ata/chipsets/ata-ati.c b/sys/dev/ata/chipsets/ata-ati.c
new file mode 100644
index 0000000..a777241
--- /dev/null
+++ b/sys/dev/ata/chipsets/ata-ati.c
@@ -0,0 +1,197 @@
+/*-
+ * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org>
+ * 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,
+ * without modification, immediately at the beginning of the file.
+ * 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 AUTHOR ``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 AUTHOR 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>
+__FBSDID("$FreeBSD$");
+
+#include "opt_ata.h"
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/ata.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sema.h>
+#include <sys/taskqueue.h>
+#include <vm/uma.h>
+#include <machine/stdarg.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/ata/ata-all.h>
+#include <dev/ata/ata-pci.h>
+#include <ata_if.h>
+
+/* local prototypes */
+static int ata_ati_chipinit(device_t dev);
+static void ata_ati_setmode(device_t dev, int mode);
+
+/* misc defines */
+#define ATI_PATA 0x01
+#define ATI_SATA 0x02
+#define ATI_AHCI 0x04
+#define SII_MEMIO 1
+#define SII_BUG 0x04
+
+
+/*
+ * ATI chipset support functions
+ */
+static int
+ata_ati_probe(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+ static struct ata_chip_id ids[] =
+ {{ ATA_ATI_IXP200, 0x00, ATI_PATA, 0, ATA_UDMA5, "IXP200" },
+ { ATA_ATI_IXP300, 0x00, ATI_PATA, 0, ATA_UDMA6, "IXP300" },
+ { ATA_ATI_IXP300_S1, 0x00, ATI_SATA, 0, ATA_SA150, "IXP300" },
+ { ATA_ATI_IXP400, 0x00, ATI_PATA, 0, ATA_UDMA6, "IXP400" },
+ { ATA_ATI_IXP400_S1, 0x00, ATI_SATA, 0, ATA_SA150, "IXP400" },
+ { ATA_ATI_IXP400_S2, 0x00, ATI_SATA, 0, ATA_SA150, "IXP400" },
+ { ATA_ATI_IXP600, 0x00, ATI_PATA, 0, ATA_UDMA6, "IXP600" },
+ { ATA_ATI_IXP600_S1, 0x00, ATI_AHCI, 0, ATA_SA300, "IXP600" },
+ { ATA_ATI_IXP700, 0x00, ATI_PATA, 0, ATA_UDMA6, "IXP700" },
+ { ATA_ATI_IXP700_S1, 0x00, ATI_AHCI, 0, ATA_SA300, "IXP700" },
+ { 0, 0, 0, 0, 0, 0}};
+
+ if (pci_get_vendor(dev) != ATA_ATI_ID)
+ return ENXIO;
+
+ if (!(ctlr->chip = ata_match_chip(dev, ids)))
+ return ENXIO;
+
+ ata_set_desc(dev);
+
+ switch (ctlr->chip->cfg1) {
+ case ATI_PATA:
+ ctlr->chipinit = ata_ati_chipinit;
+ break;
+ case ATI_SATA:
+ /*
+ * the ATI SATA controller is actually a SiI 3112 controller
+ * cfg values below much match those in ata-siliconimage.c
+ */
+ ctlr->chip->cfg1 = SII_MEMIO;
+ ctlr->chip->cfg2 = SII_BUG;
+ ctlr->chipinit = ata_sii_chipinit;
+ break;
+ case ATI_AHCI:
+ ctlr->chipinit = ata_ahci_chipinit;
+ break;
+ }
+ return 0;
+}
+
+static int
+ata_ati_chipinit(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+
+ if (ata_setup_interrupt(dev, ata_generic_intr))
+ return ENXIO;
+
+ /* IXP600 & IXP700 only have 1 PATA channel */
+ if ((ctlr->chip->chipid == ATA_ATI_IXP600) ||
+ (ctlr->chip->chipid == ATA_ATI_IXP700))
+ ctlr->channels = 1;
+
+ ctlr->setmode = ata_ati_setmode;
+ return 0;
+}
+
+static void
+ata_ati_setmode(device_t dev, int mode)
+{
+ device_t gparent = GRANDPARENT(dev);
+ struct ata_pci_controller *ctlr = device_get_softc(gparent);
+ struct ata_channel *ch = device_get_softc(device_get_parent(dev));
+ struct ata_device *atadev = device_get_softc(dev);
+ int devno = (ch->unit << 1) + atadev->unit;
+ int offset = (devno ^ 0x01) << 3;
+ int error;
+ u_int8_t piotimings[] = { 0x5d, 0x47, 0x34, 0x22, 0x20, 0x34, 0x22, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 };
+ u_int8_t dmatimings[] = { 0x77, 0x21, 0x20 };
+
+ mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma);
+
+ mode = ata_check_80pin(dev, mode);
+
+ error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
+
+ if (bootverbose)
+ device_printf(dev, "%ssetting %s on %s chip\n",
+ (error) ? "FAILURE " : "",
+ ata_mode2str(mode), ctlr->chip->text);
+ if (!error) {
+ if (mode >= ATA_UDMA0) {
+ pci_write_config(gparent, 0x56,
+ (pci_read_config(gparent, 0x56, 2) &
+ ~(0xf << (devno << 2))) |
+ ((mode & ATA_MODE_MASK) << (devno << 2)), 2);
+ pci_write_config(gparent, 0x54,
+ pci_read_config(gparent, 0x54, 1) |
+ (0x01 << devno), 1);
+ pci_write_config(gparent, 0x44,
+ (pci_read_config(gparent, 0x44, 4) &
+ ~(0xff << offset)) |
+ (dmatimings[2] << offset), 4);
+ }
+ else if (mode >= ATA_WDMA0) {
+ pci_write_config(gparent, 0x54,
+ pci_read_config(gparent, 0x54, 1) &
+ ~(0x01 << devno), 1);
+ pci_write_config(gparent, 0x44,
+ (pci_read_config(gparent, 0x44, 4) &
+ ~(0xff << offset)) |
+ (dmatimings[mode & ATA_MODE_MASK] << offset), 4);
+ }
+ else
+ pci_write_config(gparent, 0x54,
+ pci_read_config(gparent, 0x54, 1) &
+ ~(0x01 << devno), 1);
+
+ pci_write_config(gparent, 0x4a,
+ (pci_read_config(gparent, 0x4a, 2) &
+ ~(0xf << (devno << 2))) |
+ (((mode - ATA_PIO0) & ATA_MODE_MASK) << (devno<<2)),2);
+ pci_write_config(gparent, 0x40,
+ (pci_read_config(gparent, 0x40, 4) &
+ ~(0xff << offset)) |
+ (piotimings[ata_mode2idx(mode)] << offset), 4);
+ atadev->mode = mode;
+ }
+}
+
+ATA_DECLARE_DRIVER(ata_ati);
+MODULE_DEPEND(ata_ati, ata_ahci, 1, 1, 1);
+MODULE_DEPEND(ata_ati, ata_sii, 1, 1, 1);
diff --git a/sys/dev/ata/chipsets/ata-cenatek.c b/sys/dev/ata/chipsets/ata-cenatek.c
new file mode 100644
index 0000000..2fd4f08
--- /dev/null
+++ b/sys/dev/ata/chipsets/ata-cenatek.c
@@ -0,0 +1,98 @@
+/*-
+ * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org>
+ * 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,
+ * without modification, immediately at the beginning of the file.
+ * 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 AUTHOR ``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 AUTHOR 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>
+__FBSDID("$FreeBSD$");
+
+#include "opt_ata.h"
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/ata.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sema.h>
+#include <sys/taskqueue.h>
+#include <vm/uma.h>
+#include <machine/stdarg.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/ata/ata-all.h>
+#include <dev/ata/ata-pci.h>
+#include <ata_if.h>
+
+/* local prototypes */
+static int ata_cenatek_chipinit(device_t dev);
+static void ata_cenatek_setmode(device_t dev, int mode);
+
+
+/*
+ * Cenatek chipset support functions
+ */
+static int
+ata_cenatek_probe(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+
+ if (pci_get_devid(dev) != ATA_CENATEK_ROCKET)
+ return ENXIO;
+
+ ctlr->chipinit = ata_cenatek_chipinit;
+ device_set_desc(dev, "Cenatek Rocket Drive controller");
+ return 0;
+}
+
+static int
+ata_cenatek_chipinit(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+
+ if (ata_setup_interrupt(dev, ata_generic_intr))
+ return ENXIO;
+
+ ctlr->setmode = ata_cenatek_setmode;
+ return 0;
+}
+
+static void
+ata_cenatek_setmode(device_t dev, int mode)
+{
+ struct ata_device *atadev = device_get_softc(dev);
+
+ mode = ata_limit_mode(dev, mode, ATA_UDMA2);
+ mode = ata_check_80pin(dev, mode);
+ if (!ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode))
+ atadev->mode = mode;
+}
+
+ATA_DECLARE_DRIVER(ata_cenatek);
diff --git a/sys/dev/ata/chipsets/ata-cypress.c b/sys/dev/ata/chipsets/ata-cypress.c
new file mode 100644
index 0000000..a9e0b95
--- /dev/null
+++ b/sys/dev/ata/chipsets/ata-cypress.c
@@ -0,0 +1,121 @@
+/*-
+ * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org>
+ * 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,
+ * without modification, immediately at the beginning of the file.
+ * 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 AUTHOR ``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 AUTHOR 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>
+__FBSDID("$FreeBSD$");
+
+#include "opt_ata.h"
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/ata.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sema.h>
+#include <sys/taskqueue.h>
+#include <vm/uma.h>
+#include <machine/stdarg.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/ata/ata-all.h>
+#include <dev/ata/ata-pci.h>
+#include <ata_if.h>
+
+/* local prototypes */
+static int ata_cypress_chipinit(device_t dev);
+static void ata_cypress_setmode(device_t dev, int mode);
+
+
+/*
+ * Cypress chipset support functions
+ */
+static int
+ata_cypress_probe(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+
+ /*
+ * the Cypress chip is a mess, it contains two ATA functions, but
+ * both channels are visible on the first one.
+ * simply ignore the second function for now, as the right
+ * solution (ignoring the second channel on the first function)
+ * doesn't work with the crappy ATA interrupt setup on the alpha.
+ */
+ if (pci_get_devid(dev) == ATA_CYPRESS_82C693 &&
+ pci_get_function(dev) == 1 &&
+ pci_get_subclass(dev) == PCIS_STORAGE_IDE) {
+ device_set_desc(dev, "Cypress 82C693 ATA controller");
+ ctlr->chipinit = ata_cypress_chipinit;
+ return 0;
+ }
+ return ENXIO;
+}
+
+static int
+ata_cypress_chipinit(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+
+ if (ata_setup_interrupt(dev, ata_generic_intr))
+ return ENXIO;
+
+ ctlr->setmode = ata_cypress_setmode;
+ return 0;
+}
+
+static void
+ata_cypress_setmode(device_t dev, int mode)
+{
+ device_t gparent = GRANDPARENT(dev);
+ struct ata_channel *ch = device_get_softc(device_get_parent(dev));
+ struct ata_device *atadev = device_get_softc(dev);
+ int error;
+
+ mode = ata_limit_mode(dev, mode, ATA_WDMA2);
+
+ /* XXX SOS missing WDMA0+1 + PIO modes */
+ if (mode == ATA_WDMA2) {
+ error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
+ if (bootverbose)
+ device_printf(dev, "%ssetting WDMA2 on Cypress chip\n",
+ error ? "FAILURE " : "");
+ if (!error) {
+ pci_write_config(gparent, ch->unit ? 0x4e : 0x4c, 0x2020, 2);
+ atadev->mode = mode;
+ return;
+ }
+ }
+ /* we could set PIO mode timings, but we assume the BIOS did that */
+}
+
+ATA_DECLARE_DRIVER(ata_cypress);
diff --git a/sys/dev/ata/chipsets/ata-cyrix.c b/sys/dev/ata/chipsets/ata-cyrix.c
new file mode 100644
index 0000000..e7da18f
--- /dev/null
+++ b/sys/dev/ata/chipsets/ata-cyrix.c
@@ -0,0 +1,131 @@
+/*-
+ * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org>
+ * 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,
+ * without modification, immediately at the beginning of the file.
+ * 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 AUTHOR ``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 AUTHOR 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>
+__FBSDID("$FreeBSD$");
+
+#include "opt_ata.h"
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/ata.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sema.h>
+#include <sys/taskqueue.h>
+#include <vm/uma.h>
+#include <machine/stdarg.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/ata/ata-all.h>
+#include <dev/ata/ata-pci.h>
+#include <ata_if.h>
+
+/* local prototypes */
+static int ata_cyrix_chipinit(device_t dev);
+static void ata_cyrix_setmode(device_t dev, int mode);
+
+
+/*
+ * Cyrix chipset support functions
+ */
+static int
+ata_cyrix_probe(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+
+ if (pci_get_devid(dev) == ATA_CYRIX_5530) {
+ device_set_desc(dev, "Cyrix 5530 ATA33 controller");
+ ctlr->chipinit = ata_cyrix_chipinit;
+ return 0;
+ }
+ return ENXIO;
+}
+
+static int
+ata_cyrix_chipinit(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+
+ if (ata_setup_interrupt(dev, ata_generic_intr))
+ return ENXIO;
+
+ ctlr->setmode = ata_cyrix_setmode;
+ return 0;
+}
+
+static void
+ata_cyrix_setmode(device_t dev, int mode)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(GRANDPARENT(dev));
+ struct ata_channel *ch = device_get_softc(device_get_parent(dev));
+ struct ata_device *atadev = device_get_softc(dev);
+ int devno = (ch->unit << 1) + atadev->unit;
+ u_int32_t piotiming[] =
+ { 0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010 };
+ u_int32_t dmatiming[] = { 0x00077771, 0x00012121, 0x00002020 };
+ u_int32_t udmatiming[] = { 0x00921250, 0x00911140, 0x00911030 };
+ int error;
+
+ mode = ata_limit_mode(dev, mode, ATA_UDMA2);
+
+ error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
+
+ if (bootverbose)
+ device_printf(dev, "%ssetting %s on Cyrix chip\n",
+ (error) ? "FAILURE " : "", ata_mode2str(mode));
+
+ if (!error) {
+ /* dont try to set the mode if we dont have the resource */
+ if (ctlr->r_res1) {
+ ch->dma.alignment = 16;
+ ch->dma.max_iosize = 126 * DEV_BSIZE;
+
+ if (mode >= ATA_UDMA0) {
+ ATA_OUTL(ch->r_io[ATA_BMCMD_PORT].res,
+ 0x24 + (devno << 3), udmatiming[mode & ATA_MODE_MASK]);
+ }
+ else if (mode >= ATA_WDMA0) {
+ ATA_OUTL(ch->r_io[ATA_BMCMD_PORT].res,
+ 0x24 + (devno << 3), dmatiming[mode & ATA_MODE_MASK]);
+ }
+ else {
+ ATA_OUTL(ch->r_io[ATA_BMCMD_PORT].res,
+ 0x20 + (devno << 3), piotiming[mode & ATA_MODE_MASK]);
+ }
+ }
+ atadev->mode = mode;
+ }
+}
+
+ATA_DECLARE_DRIVER(ata_cyrix);
diff --git a/sys/dev/ata/chipsets/ata-highpoint.c b/sys/dev/ata/chipsets/ata-highpoint.c
new file mode 100644
index 0000000..b187f53
--- /dev/null
+++ b/sys/dev/ata/chipsets/ata-highpoint.c
@@ -0,0 +1,234 @@
+/*-
+ * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org>
+ * 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,
+ * without modification, immediately at the beginning of the file.
+ * 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 AUTHOR ``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 AUTHOR 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>
+__FBSDID("$FreeBSD$");
+
+#include "opt_ata.h"
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/ata.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sema.h>
+#include <sys/taskqueue.h>
+#include <vm/uma.h>
+#include <machine/stdarg.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/ata/ata-all.h>
+#include <dev/ata/ata-pci.h>
+#include <ata_if.h>
+
+/* local prototypes */
+static int ata_highpoint_chipinit(device_t dev);
+static int ata_highpoint_allocate(device_t dev);
+static void ata_highpoint_setmode(device_t dev, int mode);
+static int ata_highpoint_check_80pin(device_t dev, int mode);
+
+/* misc defines */
+#define HPT_366 0
+#define HPT_370 1
+#define HPT_372 2
+#define HPT_374 3
+#define HPT_OLD 1
+
+
+/*
+ * HighPoint chipset support functions
+ */
+static int
+ata_highpoint_probe(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+ struct ata_chip_id *idx;
+ static struct ata_chip_id ids[] =
+ {{ ATA_HPT374, 0x07, HPT_374, 0, ATA_UDMA6, "HPT374" },
+ { ATA_HPT372, 0x02, HPT_372, 0, ATA_UDMA6, "HPT372N" },
+ { ATA_HPT372, 0x01, HPT_372, 0, ATA_UDMA6, "HPT372" },
+ { ATA_HPT371, 0x01, HPT_372, 0, ATA_UDMA6, "HPT371" },
+ { ATA_HPT366, 0x05, HPT_372, 0, ATA_UDMA6, "HPT372" },
+ { ATA_HPT366, 0x03, HPT_370, 0, ATA_UDMA5, "HPT370" },
+ { ATA_HPT366, 0x02, HPT_366, 0, ATA_UDMA4, "HPT368" },
+ { ATA_HPT366, 0x00, HPT_366, HPT_OLD, ATA_UDMA4, "HPT366" },
+ { ATA_HPT302, 0x01, HPT_372, 0, ATA_UDMA6, "HPT302" },
+ { 0, 0, 0, 0, 0, 0}};
+ char buffer[64];
+
+ if (pci_get_vendor(dev) != ATA_HIGHPOINT_ID)
+ return ENXIO;
+
+ if (!(idx = ata_match_chip(dev, ids)))
+ return ENXIO;
+
+ strcpy(buffer, "HighPoint ");
+ strcat(buffer, idx->text);
+ if (idx->cfg1 == HPT_374) {
+ if (pci_get_function(dev) == 0)
+ strcat(buffer, " (channel 0+1)");
+ if (pci_get_function(dev) == 1)
+ strcat(buffer, " (channel 2+3)");
+ }
+ sprintf(buffer, "%s %s controller", buffer, ata_mode2str(idx->max_dma));
+ device_set_desc_copy(dev, buffer);
+ ctlr->chip = idx;
+ ctlr->chipinit = ata_highpoint_chipinit;
+ return 0;
+}
+
+static int
+ata_highpoint_chipinit(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+
+ if (ata_setup_interrupt(dev, ata_generic_intr))
+ return ENXIO;
+
+ if (ctlr->chip->cfg2 == HPT_OLD) {
+ /* disable interrupt prediction */
+ pci_write_config(dev, 0x51, (pci_read_config(dev, 0x51, 1) & ~0x80), 1);
+ }
+ else {
+ /* disable interrupt prediction */
+ pci_write_config(dev, 0x51, (pci_read_config(dev, 0x51, 1) & ~0x03), 1);
+ pci_write_config(dev, 0x55, (pci_read_config(dev, 0x55, 1) & ~0x03), 1);
+
+ /* enable interrupts */
+ pci_write_config(dev, 0x5a, (pci_read_config(dev, 0x5a, 1) & ~0x10), 1);
+
+ /* set clocks etc */
+ if (ctlr->chip->cfg1 < HPT_372)
+ pci_write_config(dev, 0x5b, 0x22, 1);
+ else
+ pci_write_config(dev, 0x5b,
+ (pci_read_config(dev, 0x5b, 1) & 0x01) | 0x20, 1);
+ }
+ ctlr->allocate = ata_highpoint_allocate;
+ ctlr->setmode = ata_highpoint_setmode;
+ return 0;
+}
+
+static int
+ata_highpoint_allocate(device_t dev)
+{
+ struct ata_channel *ch = device_get_softc(dev);
+
+ /* setup the usual register normal pci style */
+ if (ata_pci_allocate(dev))
+ return ENXIO;
+
+ ch->flags |= ATA_ALWAYS_DMASTAT;
+ return 0;
+}
+
+static void
+ata_highpoint_setmode(device_t dev, int mode)
+{
+ device_t gparent = GRANDPARENT(dev);
+ struct ata_pci_controller *ctlr = device_get_softc(gparent);
+ struct ata_channel *ch = device_get_softc(device_get_parent(dev));
+ struct ata_device *atadev = device_get_softc(dev);
+ int devno = (ch->unit << 1) + atadev->unit;
+ int error;
+ u_int32_t timings33[][4] = {
+ /* HPT366 HPT370 HPT372 HPT374 mode */
+ { 0x40d0a7aa, 0x06914e57, 0x0d029d5e, 0x0ac1f48a }, /* PIO 0 */
+ { 0x40d0a7a3, 0x06914e43, 0x0d029d26, 0x0ac1f465 }, /* PIO 1 */
+ { 0x40d0a753, 0x06514e33, 0x0c829ca6, 0x0a81f454 }, /* PIO 2 */
+ { 0x40c8a742, 0x06514e22, 0x0c829c84, 0x0a81f443 }, /* PIO 3 */
+ { 0x40c8a731, 0x06514e21, 0x0c829c62, 0x0a81f442 }, /* PIO 4 */
+ { 0x20c8a797, 0x26514e97, 0x2c82922e, 0x228082ea }, /* MWDMA 0 */
+ { 0x20c8a732, 0x26514e33, 0x2c829266, 0x22808254 }, /* MWDMA 1 */
+ { 0x20c8a731, 0x26514e21, 0x2c829262, 0x22808242 }, /* MWDMA 2 */
+ { 0x10c8a731, 0x16514e31, 0x1c829c62, 0x121882ea }, /* UDMA 0 */
+ { 0x10cba731, 0x164d4e31, 0x1c9a9c62, 0x12148254 }, /* UDMA 1 */
+ { 0x10caa731, 0x16494e31, 0x1c929c62, 0x120c8242 }, /* UDMA 2 */
+ { 0x10cfa731, 0x166d4e31, 0x1c8e9c62, 0x128c8242 }, /* UDMA 3 */
+ { 0x10c9a731, 0x16454e31, 0x1c8a9c62, 0x12ac8242 }, /* UDMA 4 */
+ { 0, 0x16454e31, 0x1c8a9c62, 0x12848242 }, /* UDMA 5 */
+ { 0, 0, 0x1c869c62, 0x12808242 } /* UDMA 6 */
+ };
+
+ mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma);
+
+ if (ctlr->chip->cfg1 == HPT_366 && ata_atapi(dev))
+ mode = ata_limit_mode(dev, mode, ATA_PIO_MAX);
+
+ mode = ata_highpoint_check_80pin(dev, mode);
+
+ /*
+ * most if not all HPT chips cant really handle that the device is
+ * running at ATA_UDMA6/ATA133 speed, so we cheat at set the device to
+ * a max of ATA_UDMA5/ATA100 to guard against suboptimal performance
+ */
+ error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0,
+ ata_limit_mode(dev, mode, ATA_UDMA5));
+ if (bootverbose)
+ device_printf(dev, "%ssetting %s on HighPoint chip\n",
+ (error) ? "FAILURE " : "", ata_mode2str(mode));
+ if (!error)
+ pci_write_config(gparent, 0x40 + (devno << 2),
+ timings33[ata_mode2idx(mode)][ctlr->chip->cfg1], 4);
+ atadev->mode = mode;
+}
+
+static int
+ata_highpoint_check_80pin(device_t dev, int mode)
+{
+ device_t gparent = GRANDPARENT(dev);
+ struct ata_pci_controller *ctlr = device_get_softc(gparent);
+ struct ata_channel *ch = device_get_softc(device_get_parent(dev));
+ u_int8_t reg, val, res;
+
+ if (ctlr->chip->cfg1 == HPT_374 && pci_get_function(gparent) == 1) {
+ reg = ch->unit ? 0x57 : 0x53;
+ val = pci_read_config(gparent, reg, 1);
+ pci_write_config(gparent, reg, val | 0x80, 1);
+ }
+ else {
+ reg = 0x5b;
+ val = pci_read_config(gparent, reg, 1);
+ pci_write_config(gparent, reg, val & 0xfe, 1);
+ }
+ res = pci_read_config(gparent, 0x5a, 1) & (ch->unit ? 0x1:0x2);
+ pci_write_config(gparent, reg, val, 1);
+
+ if (mode > ATA_UDMA2 && res) {
+ ata_print_cable(dev, "controller");
+ mode = ATA_UDMA2;
+ }
+ return mode;
+}
+
+ATA_DECLARE_DRIVER(ata_highpoint);
diff --git a/sys/dev/ata/chipsets/ata-intel.c b/sys/dev/ata/chipsets/ata-intel.c
new file mode 100644
index 0000000..03489d8
--- /dev/null
+++ b/sys/dev/ata/chipsets/ata-intel.c
@@ -0,0 +1,515 @@
+/*-
+ * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org>
+ * 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,
+ * without modification, immediately at the beginning of the file.
+ * 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 AUTHOR ``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 AUTHOR 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>
+__FBSDID("$FreeBSD$");
+
+#include "opt_ata.h"
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/ata.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sema.h>
+#include <sys/taskqueue.h>
+#include <vm/uma.h>
+#include <machine/stdarg.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/ata/ata-all.h>
+#include <dev/ata/ata-pci.h>
+#include <ata_if.h>
+
+/* local prototypes */
+static int ata_intel_chipinit(device_t dev);
+static int ata_intel_allocate(device_t dev);
+static void ata_intel_reset(device_t dev);
+static void ata_intel_old_setmode(device_t dev, int mode);
+static void ata_intel_new_setmode(device_t dev, int mode);
+static void ata_intel_sata_setmode(device_t dev, int mode);
+static int ata_intel_31244_allocate(device_t dev);
+static int ata_intel_31244_status(device_t dev);
+static void ata_intel_31244_tf_write(struct ata_request *request);
+static void ata_intel_31244_reset(device_t dev);
+
+/* misc defines */
+#define INTEL_AHCI 1
+
+
+/*
+ * Intel chipset support functions
+ */
+static int
+ata_intel_probe(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+ static struct ata_chip_id ids[] =
+ {{ ATA_I82371FB, 0, 0, 2, ATA_WDMA2, "PIIX" },
+ { ATA_I82371SB, 0, 0, 2, ATA_WDMA2, "PIIX3" },
+ { ATA_I82371AB, 0, 0, 2, ATA_UDMA2, "PIIX4" },
+ { ATA_I82443MX, 0, 0, 2, ATA_UDMA2, "PIIX4" },
+ { ATA_I82451NX, 0, 0, 2, ATA_UDMA2, "PIIX4" },
+ { ATA_I82801AB, 0, 0, 2, ATA_UDMA2, "ICH0" },
+ { ATA_I82801AA, 0, 0, 2, ATA_UDMA4, "ICH" },
+ { ATA_I82372FB, 0, 0, 2, ATA_UDMA4, "ICH" },
+ { ATA_I82801BA, 0, 0, 2, ATA_UDMA5, "ICH2" },
+ { ATA_I82801BA_1, 0, 0, 2, ATA_UDMA5, "ICH2" },
+ { ATA_I82801CA, 0, 0, 2, ATA_UDMA5, "ICH3" },
+ { ATA_I82801CA_1, 0, 0, 2, ATA_UDMA5, "ICH3" },
+ { ATA_I82801DB, 0, 0, 2, ATA_UDMA5, "ICH4" },
+ { ATA_I82801DB_1, 0, 0, 2, ATA_UDMA5, "ICH4" },
+ { ATA_I82801EB, 0, 0, 2, ATA_UDMA5, "ICH5" },
+ { ATA_I82801EB_S1, 0, 0, 2, ATA_SA150, "ICH5" },
+ { ATA_I82801EB_R1, 0, 0, 2, ATA_SA150, "ICH5" },
+ { ATA_I6300ESB, 0, 0, 2, ATA_UDMA5, "6300ESB" },
+ { ATA_I6300ESB_S1, 0, 0, 2, ATA_SA150, "6300ESB" },
+ { ATA_I6300ESB_R1, 0, 0, 2, ATA_SA150, "6300ESB" },
+ { ATA_I82801FB, 0, 0, 2, ATA_UDMA5, "ICH6" },
+ { ATA_I82801FB_S1, 0, INTEL_AHCI, 0, ATA_SA150, "ICH6" },
+ { ATA_I82801FB_R1, 0, INTEL_AHCI, 0, ATA_SA150, "ICH6" },
+ { ATA_I82801FBM, 0, INTEL_AHCI, 0, ATA_SA150, "ICH6M" },
+ { ATA_I82801GB, 0, 0, 1, ATA_UDMA5, "ICH7" },
+ { ATA_I82801GB_S1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH7" },
+ { ATA_I82801GB_R1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH7" },
+ { ATA_I82801GB_AH, 0, INTEL_AHCI, 0, ATA_SA300, "ICH7" },
+ { ATA_I82801GBM_S1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH7M" },
+ { ATA_I82801GBM_R1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH7M" },
+ { ATA_I82801GBM_AH, 0, INTEL_AHCI, 0, ATA_SA300, "ICH7M" },
+ { ATA_I63XXESB2, 0, 0, 1, ATA_UDMA5, "63XXESB2" },
+ { ATA_I63XXESB2_S1, 0, INTEL_AHCI, 0, ATA_SA300, "63XXESB2" },
+ { ATA_I63XXESB2_S2, 0, INTEL_AHCI, 0, ATA_SA300, "63XXESB2" },
+ { ATA_I63XXESB2_R1, 0, INTEL_AHCI, 0, ATA_SA300, "63XXESB2" },
+ { ATA_I63XXESB2_R2, 0, INTEL_AHCI, 0, ATA_SA300, "63XXESB2" },
+ { ATA_I82801HB_S1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH8" },
+ { ATA_I82801HB_S2, 0, INTEL_AHCI, 0, ATA_SA300, "ICH8" },
+ { ATA_I82801HB_R1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH8" },
+ { ATA_I82801HB_AH4, 0, INTEL_AHCI, 0, ATA_SA300, "ICH8" },
+ { ATA_I82801HB_AH6, 0, INTEL_AHCI, 0, ATA_SA300, "ICH8" },
+ { ATA_I82801HBM, 0, 0, 1, ATA_UDMA5, "ICH8M" },
+ { ATA_I82801HBM_S1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH8M" },
+ { ATA_I82801HBM_S2, 0, INTEL_AHCI, 0, ATA_SA300, "ICH8M" },
+ { ATA_I82801HBM_S3, 0, INTEL_AHCI, 0, ATA_SA300, "ICH8M" },
+ { ATA_I82801IB_S1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH9" },
+ { ATA_I82801IB_S2, 0, INTEL_AHCI, 0, ATA_SA300, "ICH9" },
+ { ATA_I82801IB_AH2, 0, INTEL_AHCI, 0, ATA_SA300, "ICH9" },
+ { ATA_I82801IB_AH4, 0, INTEL_AHCI, 0, ATA_SA300, "ICH9" },
+ { ATA_I82801IB_AH6, 0, INTEL_AHCI, 0, ATA_SA300, "ICH9" },
+ { ATA_I82801IB_R1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH9" },
+ { ATA_I82801JIB_S1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" },
+ { ATA_I82801JIB_AH, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" },
+ { ATA_I82801JIB_R1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" },
+ { ATA_I82801JIB_S2, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" },
+ { ATA_I82801JD_S1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" },
+ { ATA_I82801JD_AH, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" },
+ { ATA_I82801JD_R1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" },
+ { ATA_I82801JD_S2, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" },
+ { ATA_I31244, 0, 0, 2, ATA_SA150, "31244" },
+ { 0, 0, 0, 0, 0, 0}};
+
+ if (pci_get_vendor(dev) != ATA_INTEL_ID)
+ return ENXIO;
+
+ if (!(ctlr->chip = ata_match_chip(dev, ids)))
+ return ENXIO;
+
+ ata_set_desc(dev);
+ ctlr->chipinit = ata_intel_chipinit;
+ return 0;
+}
+
+static int
+ata_intel_chipinit(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+
+ if (ata_setup_interrupt(dev, ata_generic_intr))
+ return ENXIO;
+
+ /* good old PIIX needs special treatment (not implemented) */
+ if (ctlr->chip->chipid == ATA_I82371FB) {
+ ctlr->setmode = ata_intel_old_setmode;
+ }
+
+ /* the intel 31244 needs special care if in DPA mode */
+ else if (ctlr->chip->chipid == ATA_I31244) {
+ if (pci_get_subclass(dev) != PCIS_STORAGE_IDE) {
+ ctlr->r_type2 = SYS_RES_MEMORY;
+ ctlr->r_rid2 = PCIR_BAR(0);
+ if (!(ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2,
+ &ctlr->r_rid2,
+ RF_ACTIVE)))
+ return ENXIO;
+ ctlr->channels = 4;
+ ctlr->allocate = ata_intel_31244_allocate;
+ ctlr->reset = ata_intel_31244_reset;
+ }
+ ctlr->setmode = ata_sata_setmode;
+ }
+
+ /* non SATA intel chips goes here */
+ else if (ctlr->chip->max_dma < ATA_SA150) {
+ ctlr->channels = ctlr->chip->cfg2;
+ ctlr->allocate = ata_intel_allocate;
+ ctlr->setmode = ata_intel_new_setmode;
+ }
+
+ /* SATA parts can be either compat or AHCI */
+ else {
+ /* force all ports active "the legacy way" */
+ pci_write_config(dev, 0x92, pci_read_config(dev, 0x92, 2) | 0x0f, 2);
+
+ ctlr->allocate = ata_intel_allocate;
+ ctlr->reset = ata_intel_reset;
+
+ /*
+ * if we have AHCI capability and AHCI or RAID mode enabled
+ * in BIOS we try for AHCI mode
+ */
+ if ((ctlr->chip->cfg1 == INTEL_AHCI) &&
+ (pci_read_config(dev, 0x90, 1) & 0xc0) &&
+ (ata_ahci_chipinit(dev) != ENXIO))
+ return 0;
+
+ /* if BAR(5) is IO it should point to SATA interface registers */
+ ctlr->r_type2 = SYS_RES_IOPORT;
+ ctlr->r_rid2 = PCIR_BAR(5);
+ if ((ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2,
+ &ctlr->r_rid2, RF_ACTIVE)))
+ ctlr->setmode = ata_intel_sata_setmode;
+ else
+ ctlr->setmode = ata_sata_setmode;
+
+ /* enable PCI interrupt */
+ pci_write_config(dev, PCIR_COMMAND,
+ pci_read_config(dev, PCIR_COMMAND, 2) & ~0x0400, 2);
+ }
+ return 0;
+}
+
+static int
+ata_intel_allocate(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+
+ /* setup the usual register normal pci style */
+ if (ata_pci_allocate(dev))
+ return ENXIO;
+
+ /* if r_res2 is valid it points to SATA interface registers */
+ if (ctlr->r_res2) {
+ ch->r_io[ATA_IDX_ADDR].res = ctlr->r_res2;
+ ch->r_io[ATA_IDX_ADDR].offset = 0x00;
+ ch->r_io[ATA_IDX_DATA].res = ctlr->r_res2;
+ ch->r_io[ATA_IDX_DATA].offset = 0x04;
+ }
+
+ ch->flags |= ATA_ALWAYS_DMASTAT;
+ return 0;
+}
+
+static void
+ata_intel_reset(device_t dev)
+{
+ device_t parent = device_get_parent(dev);
+ struct ata_pci_controller *ctlr = device_get_softc(parent);
+ struct ata_channel *ch = device_get_softc(dev);
+ int mask, timeout;
+
+ /* ICH6 & ICH7 in compat mode has 4 SATA ports as master/slave on 2 ch's */
+ if (ctlr->chip->cfg1) {
+ mask = (0x0005 << ch->unit);
+ }
+ else {
+ /* ICH5 in compat mode has SATA ports as master/slave on 1 channel */
+ if (pci_read_config(parent, 0x90, 1) & 0x04)
+ mask = 0x0003;
+ else {
+ mask = (0x0001 << ch->unit);
+ /* XXX SOS should be in intel_allocate if we grow it */
+ ch->flags |= ATA_NO_SLAVE;
+ }
+ }
+ pci_write_config(parent, 0x92, pci_read_config(parent, 0x92, 2) & ~mask, 2);
+ DELAY(10);
+ pci_write_config(parent, 0x92, pci_read_config(parent, 0x92, 2) | mask, 2);
+
+ /* wait up to 1 sec for "connect well" */
+ for (timeout = 0; timeout < 100 ; timeout++) {
+ if (((pci_read_config(parent, 0x92, 2) & (mask << 4)) == (mask << 4)) &&
+ (ATA_IDX_INB(ch, ATA_STATUS) != 0xff))
+ break;
+ ata_udelay(10000);
+ }
+ ata_generic_reset(dev);
+}
+
+static void
+ata_intel_old_setmode(device_t dev, int mode)
+{
+ /* NOT YET */
+}
+
+static void
+ata_intel_new_setmode(device_t dev, int mode)
+{
+ device_t gparent = GRANDPARENT(dev);
+ struct ata_pci_controller *ctlr = device_get_softc(gparent);
+ struct ata_channel *ch = device_get_softc(device_get_parent(dev));
+ struct ata_device *atadev = device_get_softc(dev);
+ int devno = (ch->unit << 1) + atadev->unit;
+ u_int32_t reg40 = pci_read_config(gparent, 0x40, 4);
+ u_int8_t reg44 = pci_read_config(gparent, 0x44, 1);
+ u_int8_t reg48 = pci_read_config(gparent, 0x48, 1);
+ u_int16_t reg4a = pci_read_config(gparent, 0x4a, 2);
+ u_int16_t reg54 = pci_read_config(gparent, 0x54, 2);
+ u_int32_t mask40 = 0, new40 = 0;
+ u_int8_t mask44 = 0, new44 = 0;
+ int error;
+ u_int8_t timings[] = { 0x00, 0x00, 0x10, 0x21, 0x23, 0x10, 0x21, 0x23,
+ 0x23, 0x23, 0x23, 0x23, 0x23, 0x23 };
+
+ mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma);
+
+ if ( mode > ATA_UDMA2 && !(reg54 & (0x10 << devno))) {
+ ata_print_cable(dev, "controller");
+ mode = ATA_UDMA2;
+ }
+
+ error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
+
+ if (bootverbose)
+ device_printf(dev, "%ssetting %s on %s chip\n",
+ (error) ? "FAILURE " : "",
+ ata_mode2str(mode), ctlr->chip->text);
+ if (!error) {
+ if (mode >= ATA_UDMA0) {
+ u_int8_t utimings[] = { 0x00, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10 };
+
+ pci_write_config(gparent, 0x48, reg48 | (0x0001 << devno), 2);
+ pci_write_config(gparent, 0x4a,
+ (reg4a & ~(0x3 << (devno << 2))) |
+ (utimings[mode & ATA_MODE_MASK] << (devno<<2)), 2);
+ }
+ else {
+ pci_write_config(gparent, 0x48, reg48 & ~(0x0001 << devno), 2);
+ pci_write_config(gparent, 0x4a, (reg4a & ~(0x3 << (devno << 2))),2);
+ }
+ reg54 |= 0x0400;
+ if (mode >= ATA_UDMA2)
+ reg54 |= (0x1 << devno);
+ else
+ reg54 &= ~(0x1 << devno);
+ if (mode >= ATA_UDMA5)
+ reg54 |= (0x1000 << devno);
+ else
+ reg54 &= ~(0x1000 << devno);
+
+ pci_write_config(gparent, 0x54, reg54, 2);
+
+ reg40 &= ~0x00ff00ff;
+ reg40 |= 0x40774077;
+
+ if (atadev->unit == ATA_MASTER) {
+ mask40 = 0x3300;
+ new40 = timings[ata_mode2idx(mode)] << 8;
+ }
+ else {
+ mask44 = 0x0f;
+ new44 = ((timings[ata_mode2idx(mode)] & 0x30) >> 2) |
+ (timings[ata_mode2idx(mode)] & 0x03);
+ }
+ if (ch->unit) {
+ mask40 <<= 16;
+ new40 <<= 16;
+ mask44 <<= 4;
+ new44 <<= 4;
+ }
+ pci_write_config(gparent, 0x40, (reg40 & ~mask40) | new40, 4);
+ pci_write_config(gparent, 0x44, (reg44 & ~mask44) | new44, 1);
+
+ atadev->mode = mode;
+ }
+}
+
+static void
+ata_intel_sata_setmode(device_t dev, int mode)
+{
+ struct ata_device *atadev = device_get_softc(dev);
+
+ if (atadev->param.satacapabilities != 0x0000 &&
+ atadev->param.satacapabilities != 0xffff) {
+
+ struct ata_channel *ch = device_get_softc(device_get_parent(dev));
+ int devno = (ch->unit << 1) + atadev->unit;
+
+ /* on some drives we need to set the transfer mode */
+ ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0,
+ ata_limit_mode(dev, mode, ATA_UDMA6));
+
+ /* set ATA_SSTATUS register offset */
+ ATA_IDX_OUTL(ch, ATA_IDX_ADDR, devno * 0x100);
+
+ /* query SATA STATUS for the speed */
+ if ((ATA_IDX_INL(ch, ATA_IDX_DATA) & ATA_SS_CONWELL_MASK) ==
+ ATA_SS_CONWELL_GEN2)
+ atadev->mode = ATA_SA300;
+ else
+ atadev->mode = ATA_SA150;
+ }
+ else {
+ mode = ata_limit_mode(dev, mode, ATA_UDMA5);
+ if (!ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode))
+ atadev->mode = mode;
+ }
+}
+
+static int
+ata_intel_31244_allocate(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ int i;
+ int ch_offset;
+
+ ch_offset = 0x200 + ch->unit * 0x200;
+
+ for (i = ATA_DATA; i < ATA_MAX_RES; i++)
+ ch->r_io[i].res = ctlr->r_res2;
+
+ /* setup ATA registers */
+ ch->r_io[ATA_DATA].offset = ch_offset + 0x00;
+ ch->r_io[ATA_FEATURE].offset = ch_offset + 0x06;
+ ch->r_io[ATA_COUNT].offset = ch_offset + 0x08;
+ ch->r_io[ATA_SECTOR].offset = ch_offset + 0x0c;
+ ch->r_io[ATA_CYL_LSB].offset = ch_offset + 0x10;
+ ch->r_io[ATA_CYL_MSB].offset = ch_offset + 0x14;
+ ch->r_io[ATA_DRIVE].offset = ch_offset + 0x18;
+ ch->r_io[ATA_COMMAND].offset = ch_offset + 0x1d;
+ ch->r_io[ATA_ERROR].offset = ch_offset + 0x04;
+ ch->r_io[ATA_STATUS].offset = ch_offset + 0x1c;
+ ch->r_io[ATA_ALTSTAT].offset = ch_offset + 0x28;
+ ch->r_io[ATA_CONTROL].offset = ch_offset + 0x29;
+
+ /* setup DMA registers */
+ ch->r_io[ATA_SSTATUS].offset = ch_offset + 0x100;
+ ch->r_io[ATA_SERROR].offset = ch_offset + 0x104;
+ ch->r_io[ATA_SCONTROL].offset = ch_offset + 0x108;
+
+ /* setup SATA registers */
+ ch->r_io[ATA_BMCMD_PORT].offset = ch_offset + 0x70;
+ ch->r_io[ATA_BMSTAT_PORT].offset = ch_offset + 0x72;
+ ch->r_io[ATA_BMDTP_PORT].offset = ch_offset + 0x74;
+
+ ch->flags |= ATA_NO_SLAVE;
+ ata_pci_hw(dev);
+ ch->hw.status = ata_intel_31244_status;
+ ch->hw.tf_write = ata_intel_31244_tf_write;
+
+ /* enable PHY state change interrupt */
+ ATA_OUTL(ctlr->r_res2, 0x4,
+ ATA_INL(ctlr->r_res2, 0x04) | (0x01 << (ch->unit << 3)));
+ return 0;
+}
+
+static int
+ata_intel_31244_status(device_t dev)
+{
+ /* do we have any PHY events ? */
+ ata_sata_phy_check_events(dev);
+
+ /* any drive action to take care of ? */
+ return ata_pci_status(dev);
+}
+
+static void
+ata_intel_31244_tf_write(struct ata_request *request)
+{
+ struct ata_channel *ch = device_get_softc(device_get_parent(request->dev));
+ struct ata_device *atadev = device_get_softc(request->dev);
+
+ if (atadev->flags & ATA_D_48BIT_ACTIVE) {
+ ATA_IDX_OUTW(ch, ATA_FEATURE, request->u.ata.feature);
+ ATA_IDX_OUTW(ch, ATA_COUNT, request->u.ata.count);
+ ATA_IDX_OUTW(ch, ATA_SECTOR, ((request->u.ata.lba >> 16) & 0xff00) |
+ (request->u.ata.lba & 0x00ff));
+ ATA_IDX_OUTW(ch, ATA_CYL_LSB, ((request->u.ata.lba >> 24) & 0xff00) |
+ ((request->u.ata.lba >> 8) & 0x00ff));
+ ATA_IDX_OUTW(ch, ATA_CYL_MSB, ((request->u.ata.lba >> 32) & 0xff00) |
+ ((request->u.ata.lba >> 16) & 0x00ff));
+ ATA_IDX_OUTW(ch, ATA_DRIVE, ATA_D_LBA | ATA_DEV(atadev->unit));
+ }
+ else {
+ ATA_IDX_OUTB(ch, ATA_FEATURE, request->u.ata.feature);
+ ATA_IDX_OUTB(ch, ATA_COUNT, request->u.ata.count);
+ if (atadev->flags & ATA_D_USE_CHS) {
+ int heads, sectors;
+
+ if (atadev->param.atavalid & ATA_FLAG_54_58) {
+ heads = atadev->param.current_heads;
+ sectors = atadev->param.current_sectors;
+ }
+ else {
+ heads = atadev->param.heads;
+ sectors = atadev->param.sectors;
+ }
+ ATA_IDX_OUTB(ch, ATA_SECTOR, (request->u.ata.lba % sectors)+1);
+ ATA_IDX_OUTB(ch, ATA_CYL_LSB,
+ (request->u.ata.lba / (sectors * heads)));
+ ATA_IDX_OUTB(ch, ATA_CYL_MSB,
+ (request->u.ata.lba / (sectors * heads)) >> 8);
+ ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(atadev->unit) |
+ (((request->u.ata.lba% (sectors * heads)) /
+ sectors) & 0xf));
+ }
+ else {
+ ATA_IDX_OUTB(ch, ATA_SECTOR, request->u.ata.lba);
+ ATA_IDX_OUTB(ch, ATA_CYL_LSB, request->u.ata.lba >> 8);
+ ATA_IDX_OUTB(ch, ATA_CYL_MSB, request->u.ata.lba >> 16);
+ ATA_IDX_OUTB(ch, ATA_DRIVE,
+ ATA_D_IBM | ATA_D_LBA | ATA_DEV(atadev->unit) |
+ ((request->u.ata.lba >> 24) & 0x0f));
+ }
+ }
+}
+
+static void
+ata_intel_31244_reset(device_t dev)
+{
+ if (ata_sata_phy_reset(dev))
+ ata_generic_reset(dev);
+}
+
+ATA_DECLARE_DRIVER(ata_intel);
+MODULE_DEPEND(ata_intel, ata_ahci, 1, 1, 1);
diff --git a/sys/dev/ata/chipsets/ata-ite.c b/sys/dev/ata/chipsets/ata-ite.c
new file mode 100644
index 0000000..e3175ed
--- /dev/null
+++ b/sys/dev/ata/chipsets/ata-ite.c
@@ -0,0 +1,247 @@
+/*-
+ * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org>
+ * 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,
+ * without modification, immediately at the beginning of the file.
+ * 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 AUTHOR ``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 AUTHOR 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>
+__FBSDID("$FreeBSD$");
+
+#include "opt_ata.h"
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/ata.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sema.h>
+#include <sys/taskqueue.h>
+#include <vm/uma.h>
+#include <machine/stdarg.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/ata/ata-all.h>
+#include <dev/ata/ata-pci.h>
+#include <ata_if.h>
+
+/* local prototypes */
+static int ata_ite_chipinit(device_t dev);
+static void ata_ite_821x_setmode(device_t dev, int mode);
+static void ata_ite_8213_setmode(device_t dev, int mode);
+
+
+/*
+ * Integrated Technology Express Inc. (ITE) chipset support functions
+ */
+static int
+ata_ite_probe(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+ static struct ata_chip_id ids[] =
+ {{ ATA_IT8213F, 0x00, 0x00, 0x00, ATA_UDMA6, "IT8213F" },
+ { ATA_IT8212F, 0x00, 0x00, 0x00, ATA_UDMA6, "IT8212F" },
+ { ATA_IT8211F, 0x00, 0x00, 0x00, ATA_UDMA6, "IT8211F" },
+ { 0, 0, 0, 0, 0, 0}};
+
+ if (pci_get_vendor(dev) != ATA_ITE_ID)
+ return ENXIO;
+
+ if (!(ctlr->chip = ata_match_chip(dev, ids)))
+ return ENXIO;
+
+ ata_set_desc(dev);
+ ctlr->chipinit = ata_ite_chipinit;
+ return 0;
+}
+
+static int
+ata_ite_chipinit(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+
+ if (ata_setup_interrupt(dev, ata_generic_intr))
+ return ENXIO;
+
+ if (ctlr->chip->chipid == ATA_IT8213F) {
+ /* the ITE 8213F only has one channel */
+ ctlr->channels = 1;
+
+ ctlr->setmode = ata_ite_8213_setmode;
+ }
+ else {
+ /* set PCI mode and 66Mhz reference clock */
+ pci_write_config(dev, 0x50, pci_read_config(dev, 0x50, 1) & ~0x83, 1);
+
+ /* set default active & recover timings */
+ pci_write_config(dev, 0x54, 0x31, 1);
+ pci_write_config(dev, 0x56, 0x31, 1);
+
+ ctlr->setmode = ata_ite_821x_setmode;
+ }
+
+ return 0;
+}
+
+static void
+ata_ite_821x_setmode(device_t dev, int mode)
+{
+ device_t gparent = GRANDPARENT(dev);
+ struct ata_channel *ch = device_get_softc(device_get_parent(dev));
+ struct ata_device *atadev = device_get_softc(dev);
+ int devno = (ch->unit << 1) + atadev->unit;
+ int error;
+
+ /* correct the mode for what the HW supports */
+ mode = ata_limit_mode(dev, mode, ATA_UDMA6);
+
+ /* check the CBLID bits for 80 conductor cable detection */
+ if (mode > ATA_UDMA2 && (pci_read_config(gparent, 0x40, 2) &
+ (ch->unit ? (1<<3) : (1<<2)))) {
+ ata_print_cable(dev, "controller");
+ mode = ATA_UDMA2;
+ }
+
+ /* set the wanted mode on the device */
+ error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
+
+ if (bootverbose)
+ device_printf(dev, "%s setting %s on ITE8212F chip\n",
+ (error) ? "failed" : "success", ata_mode2str(mode));
+
+ /* if the device accepted the mode change, setup the HW accordingly */
+ if (!error) {
+ if (mode >= ATA_UDMA0) {
+ u_int8_t udmatiming[] =
+ { 0x44, 0x42, 0x31, 0x21, 0x11, 0xa2, 0x91 };
+
+ /* enable UDMA mode */
+ pci_write_config(gparent, 0x50,
+ pci_read_config(gparent, 0x50, 1) &
+ ~(1 << (devno + 3)), 1);
+
+ /* set UDMA timing */
+ pci_write_config(gparent,
+ 0x56 + (ch->unit << 2) + atadev->unit,
+ udmatiming[mode & ATA_MODE_MASK], 1);
+ }
+ else {
+ u_int8_t chtiming[] =
+ { 0xaa, 0xa3, 0xa1, 0x33, 0x31, 0x88, 0x32, 0x31 };
+
+ /* disable UDMA mode */
+ pci_write_config(gparent, 0x50,
+ pci_read_config(gparent, 0x50, 1) |
+ (1 << (devno + 3)), 1);
+
+ /* set active and recover timing (shared between master & slave) */
+ if (pci_read_config(gparent, 0x54 + (ch->unit << 2), 1) <
+ chtiming[ata_mode2idx(mode)])
+ pci_write_config(gparent, 0x54 + (ch->unit << 2),
+ chtiming[ata_mode2idx(mode)], 1);
+ }
+ atadev->mode = mode;
+ }
+}
+
+static void
+ata_ite_8213_setmode(device_t dev, int mode)
+{
+ device_t gparent = GRANDPARENT(dev);
+ struct ata_pci_controller *ctlr = device_get_softc(gparent);
+ struct ata_device *atadev = device_get_softc(dev);
+ u_int16_t reg40 = pci_read_config(gparent, 0x40, 2);
+ u_int8_t reg44 = pci_read_config(gparent, 0x44, 1);
+ u_int8_t reg48 = pci_read_config(gparent, 0x48, 1);
+ u_int16_t reg4a = pci_read_config(gparent, 0x4a, 2);
+ u_int16_t reg54 = pci_read_config(gparent, 0x54, 2);
+ u_int16_t mask40 = 0, new40 = 0;
+ u_int8_t mask44 = 0, new44 = 0;
+ int devno = atadev->unit;
+ int error;
+ u_int8_t timings[] = { 0x00, 0x00, 0x10, 0x21, 0x23, 0x10, 0x21, 0x23,
+ 0x23, 0x23, 0x23, 0x23, 0x23, 0x23 };
+
+ mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma);
+
+ if (mode > ATA_UDMA2 && !(reg54 & (0x10 << devno))) {
+ ata_print_cable(dev, "controller");
+ mode = ATA_UDMA2;
+ }
+
+ error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
+
+ if (bootverbose)
+ device_printf(dev, "%ssetting %s on %s chip\n",
+ (error) ? "FAILURE " : "",
+ ata_mode2str(mode), ctlr->chip->text);
+ if (!error) {
+ if (mode >= ATA_UDMA0) {
+ u_int8_t utimings[] = { 0x00, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10 };
+
+ pci_write_config(gparent, 0x48, reg48 | (0x0001 << devno), 2);
+ pci_write_config(gparent, 0x4a,
+ (reg4a & ~(0x3 << (devno << 2))) |
+ (utimings[mode & ATA_MODE_MASK] << (devno<<2)), 2);
+ }
+ else {
+ pci_write_config(gparent, 0x48, reg48 & ~(0x0001 << devno), 2);
+ pci_write_config(gparent, 0x4a, (reg4a & ~(0x3 << (devno << 2))),2);
+ }
+ if (mode >= ATA_UDMA2)
+ reg54 |= (0x1 << devno);
+ else
+ reg54 &= ~(0x1 << devno);
+ if (mode >= ATA_UDMA5)
+ reg54 |= (0x1000 << devno);
+ else
+ reg54 &= ~(0x1000 << devno);
+ pci_write_config(gparent, 0x54, reg54, 2);
+
+ reg40 &= 0xff00;
+ reg40 |= 0x4033;
+ if (atadev->unit == ATA_MASTER) {
+ reg40 |= (ata_atapi(dev) ? 0x04 : 0x00);
+ mask40 = 0x3300;
+ new40 = timings[ata_mode2idx(mode)] << 8;
+ }
+ else {
+ reg40 |= (ata_atapi(dev) ? 0x40 : 0x00);
+ mask44 = 0x0f;
+ new44 = ((timings[ata_mode2idx(mode)] & 0x30) >> 2) |
+ (timings[ata_mode2idx(mode)] & 0x03);
+ }
+ pci_write_config(gparent, 0x40, (reg40 & ~mask40) | new40, 4);
+ pci_write_config(gparent, 0x44, (reg44 & ~mask44) | new44, 1);
+
+ atadev->mode = mode;
+ }
+}
+
+ATA_DECLARE_DRIVER(ata_ite);
diff --git a/sys/dev/ata/chipsets/ata-jmicron.c b/sys/dev/ata/chipsets/ata-jmicron.c
new file mode 100644
index 0000000..32a9b57
--- /dev/null
+++ b/sys/dev/ata/chipsets/ata-jmicron.c
@@ -0,0 +1,204 @@
+/*-
+ * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org>
+ * 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,
+ * without modification, immediately at the beginning of the file.
+ * 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 AUTHOR ``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 AUTHOR 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>
+__FBSDID("$FreeBSD$");
+
+#include "opt_ata.h"
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/ata.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sema.h>
+#include <sys/taskqueue.h>
+#include <vm/uma.h>
+#include <machine/stdarg.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/ata/ata-all.h>
+#include <dev/ata/ata-pci.h>
+#include <ata_if.h>
+
+/* local prototypes */
+static int ata_jmicron_chipinit(device_t dev);
+static int ata_jmicron_allocate(device_t dev);
+static void ata_jmicron_reset(device_t dev);
+static void ata_jmicron_dmainit(device_t dev);
+static void ata_jmicron_setmode(device_t dev, int mode);
+
+
+/*
+ * JMicron chipset support functions
+ */
+static int
+ata_jmicron_probe(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+ struct ata_chip_id *idx;
+ static struct ata_chip_id ids[] =
+ {{ ATA_JMB360, 0, 1, 0, ATA_SA300, "JMB360" },
+ { ATA_JMB361, 0, 1, 1, ATA_SA300, "JMB361" },
+ { ATA_JMB363, 0, 2, 1, ATA_SA300, "JMB363" },
+ { ATA_JMB365, 0, 1, 2, ATA_SA300, "JMB365" },
+ { ATA_JMB366, 0, 2, 2, ATA_SA300, "JMB366" },
+ { ATA_JMB368, 0, 0, 1, ATA_UDMA6, "JMB368" },
+ { 0, 0, 0, 0, 0, 0}};
+ char buffer[64];
+
+ if (pci_get_vendor(dev) != ATA_JMICRON_ID)
+ return ENXIO;
+
+ if (!(idx = ata_match_chip(dev, ids)))
+ return ENXIO;
+
+ if ((pci_read_config(dev, 0xdf, 1) & 0x40) &&
+ (pci_get_function(dev) == (pci_read_config(dev, 0x40, 1) & 0x02 >> 1)))
+ sprintf(buffer, "JMicron %s %s controller",
+ idx->text, ata_mode2str(ATA_UDMA6));
+ else
+ sprintf(buffer, "JMicron %s %s controller",
+ idx->text, ata_mode2str(idx->max_dma));
+ device_set_desc_copy(dev, buffer);
+ ctlr->chip = idx;
+ ctlr->chipinit = ata_jmicron_chipinit;
+ return 0;
+}
+
+static int
+ata_jmicron_chipinit(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+ int error;
+
+ if (ata_setup_interrupt(dev, ata_generic_intr))
+ return ENXIO;
+
+ /* do we have multiple PCI functions ? */
+ if (pci_read_config(dev, 0xdf, 1) & 0x40) {
+ /* are we on the AHCI part ? */
+ if (ata_ahci_chipinit(dev) != ENXIO)
+ return 0;
+
+ /* otherwise we are on the PATA part */
+ ctlr->allocate = ata_pci_allocate;
+ ctlr->reset = ata_generic_reset;
+ ctlr->dmainit = ata_pci_dmainit;
+ ctlr->setmode = ata_jmicron_setmode;
+ ctlr->channels = ctlr->chip->cfg2;
+ }
+ else {
+ /* set controller configuration to a combined setup we support */
+ pci_write_config(dev, 0x40, 0x80c0a131, 4);
+ pci_write_config(dev, 0x80, 0x01200000, 4);
+
+ if (ctlr->chip->cfg1 && (error = ata_ahci_chipinit(dev)))
+ return error;
+
+ ctlr->allocate = ata_jmicron_allocate;
+ ctlr->reset = ata_jmicron_reset;
+ ctlr->dmainit = ata_jmicron_dmainit;
+ ctlr->setmode = ata_jmicron_setmode;
+
+ /* set the number of HW channels */
+ ctlr->channels = ctlr->chip->cfg1 + ctlr->chip->cfg2;
+ }
+ return 0;
+}
+
+static int
+ata_jmicron_allocate(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ int error;
+
+ if (ch->unit >= ctlr->chip->cfg1) {
+ ch->unit -= ctlr->chip->cfg1;
+ error = ata_pci_allocate(dev);
+ ch->unit += ctlr->chip->cfg1;
+ }
+ else
+ error = ata_ahci_allocate(dev);
+ return error;
+}
+
+static void
+ata_jmicron_reset(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+
+ if (ch->unit >= ctlr->chip->cfg1)
+ ata_generic_reset(dev);
+ else
+ ata_ahci_reset(dev);
+}
+
+static void
+ata_jmicron_dmainit(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+
+ if (ch->unit >= ctlr->chip->cfg1)
+ ata_pci_dmainit(dev);
+ else
+ ata_ahci_dmainit(dev);
+}
+
+static void
+ata_jmicron_setmode(device_t dev, int mode)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(GRANDPARENT(dev));
+ struct ata_channel *ch = device_get_softc(device_get_parent(dev));
+
+ if (pci_read_config(dev, 0xdf, 1) & 0x40 || ch->unit >= ctlr->chip->cfg1) {
+ struct ata_device *atadev = device_get_softc(dev);
+
+ /* check for 80pin cable present */
+ if (pci_read_config(dev, 0x40, 1) & 0x08)
+ mode = ata_limit_mode(dev, mode, ATA_UDMA2);
+ else
+ mode = ata_limit_mode(dev, mode, ATA_UDMA6);
+
+ if (!ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode))
+ atadev->mode = mode;
+ }
+ else
+ ata_sata_setmode(dev, mode);
+}
+
+ATA_DECLARE_DRIVER(ata_jmicron);
+MODULE_DEPEND(ata_jmicron, ata_ahci, 1, 1, 1);
diff --git a/sys/dev/ata/chipsets/ata-marvell.c b/sys/dev/ata/chipsets/ata-marvell.c
new file mode 100644
index 0000000..8f2d5cd
--- /dev/null
+++ b/sys/dev/ata/chipsets/ata-marvell.c
@@ -0,0 +1,542 @@
+/*-
+ * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org>
+ * 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,
+ * without modification, immediately at the beginning of the file.
+ * 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 AUTHOR ``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 AUTHOR 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>
+__FBSDID("$FreeBSD$");
+
+#include "opt_ata.h"
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/ata.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sema.h>
+#include <sys/taskqueue.h>
+#include <vm/uma.h>
+#include <machine/stdarg.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/ata/ata-all.h>
+#include <dev/ata/ata-pci.h>
+#include <ata_if.h>
+
+/* local prototypes */
+static int ata_marvell_pata_chipinit(device_t dev);
+static int ata_marvell_pata_allocate(device_t dev);
+static void ata_marvell_pata_setmode(device_t dev, int mode);
+static int ata_marvell_edma_allocate(device_t dev);
+static int ata_marvell_edma_status(device_t dev);
+static int ata_marvell_edma_begin_transaction(struct ata_request *request);
+static int ata_marvell_edma_end_transaction(struct ata_request *request);
+static void ata_marvell_edma_reset(device_t dev);
+static void ata_marvell_edma_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error);
+static void ata_marvell_edma_dmainit(device_t dev);
+
+/* misc defines */
+#define MV_50XX 50
+#define MV_60XX 60
+#define MV_61XX 61
+
+
+/*
+ * Marvell chipset support functions
+ */
+#define ATA_MV_HOST_BASE(ch) \
+ ((ch->unit & 3) * 0x0100) + (ch->unit > 3 ? 0x30000 : 0x20000)
+#define ATA_MV_EDMA_BASE(ch) \
+ ((ch->unit & 3) * 0x2000) + (ch->unit > 3 ? 0x30000 : 0x20000)
+
+struct ata_marvell_response {
+ u_int16_t tag;
+ u_int8_t edma_status;
+ u_int8_t dev_status;
+ u_int32_t timestamp;
+};
+
+struct ata_marvell_dma_prdentry {
+ u_int32_t addrlo;
+ u_int32_t count;
+ u_int32_t addrhi;
+ u_int32_t reserved;
+};
+
+static int
+ata_marvell_probe(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+ static struct ata_chip_id ids[] =
+ {{ ATA_M88SX5040, 0, 4, MV_50XX, ATA_SA150, "88SX5040" },
+ { ATA_M88SX5041, 0, 4, MV_50XX, ATA_SA150, "88SX5041" },
+ { ATA_M88SX5080, 0, 8, MV_50XX, ATA_SA150, "88SX5080" },
+ { ATA_M88SX5081, 0, 8, MV_50XX, ATA_SA150, "88SX5081" },
+ { ATA_M88SX6041, 0, 4, MV_60XX, ATA_SA300, "88SX6041" },
+ { ATA_M88SX6081, 0, 8, MV_60XX, ATA_SA300, "88SX6081" },
+ { ATA_M88SX6101, 0, 1, MV_61XX, ATA_UDMA6, "88SX6101" },
+ { ATA_M88SX6145, 0, 2, MV_61XX, ATA_UDMA6, "88SX6145" },
+ { 0, 0, 0, 0, 0, 0}};
+
+ if (pci_get_vendor(dev) != ATA_MARVELL_ID)
+ return ENXIO;
+
+ if (!(ctlr->chip = ata_match_chip(dev, ids)))
+ return ENXIO;
+
+ ata_set_desc(dev);
+
+ switch (ctlr->chip->cfg2) {
+ case MV_50XX:
+ case MV_60XX:
+ ctlr->chipinit = ata_marvell_edma_chipinit;
+ break;
+ case MV_61XX:
+ ctlr->chipinit = ata_marvell_pata_chipinit;
+ break;
+ }
+ return 0;
+}
+
+static int
+ata_marvell_pata_chipinit(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+
+ if (ata_setup_interrupt(dev, ata_generic_intr))
+ return ENXIO;
+
+ ctlr->allocate = ata_marvell_pata_allocate;
+ ctlr->setmode = ata_marvell_pata_setmode;
+ ctlr->channels = ctlr->chip->cfg1;
+ return 0;
+}
+
+static int
+ata_marvell_pata_allocate(device_t dev)
+{
+ struct ata_channel *ch = device_get_softc(dev);
+
+ /* setup the usual register normal pci style */
+ if (ata_pci_allocate(dev))
+ return ENXIO;
+
+ /* dont use 32 bit PIO transfers */
+ ch->flags |= ATA_USE_16BIT;
+
+ return 0;
+}
+
+static void
+ata_marvell_pata_setmode(device_t dev, int mode)
+{
+ device_t gparent = GRANDPARENT(dev);
+ struct ata_pci_controller *ctlr = device_get_softc(gparent);
+ struct ata_device *atadev = device_get_softc(dev);
+
+ mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma);
+ mode = ata_check_80pin(dev, mode);
+ if (!ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode))
+ atadev->mode = mode;
+}
+
+int
+ata_marvell_edma_chipinit(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+
+ if (ata_setup_interrupt(dev, ata_generic_intr))
+ return ENXIO;
+
+ ctlr->r_type1 = SYS_RES_MEMORY;
+ ctlr->r_rid1 = PCIR_BAR(0);
+ if (!(ctlr->r_res1 = bus_alloc_resource_any(dev, ctlr->r_type1,
+ &ctlr->r_rid1, RF_ACTIVE)))
+ return ENXIO;
+
+ /* mask all host controller interrupts */
+ ATA_OUTL(ctlr->r_res1, 0x01d64, 0x00000000);
+
+ /* mask all PCI interrupts */
+ ATA_OUTL(ctlr->r_res1, 0x01d5c, 0x00000000);
+
+ ctlr->allocate = ata_marvell_edma_allocate;
+ ctlr->reset = ata_marvell_edma_reset;
+ ctlr->dmainit = ata_marvell_edma_dmainit;
+ ctlr->setmode = ata_sata_setmode;
+ ctlr->channels = ctlr->chip->cfg1;
+
+ /* clear host controller interrupts */
+ ATA_OUTL(ctlr->r_res1, 0x20014, 0x00000000);
+ if (ctlr->chip->cfg1 > 4)
+ ATA_OUTL(ctlr->r_res1, 0x30014, 0x00000000);
+
+ /* clear PCI interrupts */
+ ATA_OUTL(ctlr->r_res1, 0x01d58, 0x00000000);
+
+ /* unmask PCI interrupts we want */
+ ATA_OUTL(ctlr->r_res1, 0x01d5c, 0x007fffff);
+
+ /* unmask host controller interrupts we want */
+ ATA_OUTL(ctlr->r_res1, 0x01d64, 0x000000ff/*HC0*/ | 0x0001fe00/*HC1*/ |
+ /*(1<<19) | (1<<20) | (1<<21) |*/(1<<22) | (1<<24) | (0x7f << 25));
+
+ /* enable PCI interrupt */
+ pci_write_config(dev, PCIR_COMMAND,
+ pci_read_config(dev, PCIR_COMMAND, 2) & ~0x0400, 2);
+ return 0;
+}
+
+static int
+ata_marvell_edma_allocate(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ u_int64_t work = ch->dma.work_bus;
+ int i;
+
+ /* clear work area */
+ bzero(ch->dma.work, 1024+256);
+
+ /* set legacy ATA resources */
+ for (i = ATA_DATA; i <= ATA_COMMAND; i++) {
+ ch->r_io[i].res = ctlr->r_res1;
+ ch->r_io[i].offset = 0x02100 + (i << 2) + ATA_MV_EDMA_BASE(ch);
+ }
+ ch->r_io[ATA_CONTROL].res = ctlr->r_res1;
+ ch->r_io[ATA_CONTROL].offset = 0x02120 + ATA_MV_EDMA_BASE(ch);
+ ch->r_io[ATA_IDX_ADDR].res = ctlr->r_res1;
+ ata_default_registers(dev);
+
+ /* set SATA resources */
+ switch (ctlr->chip->cfg2) {
+ case MV_50XX:
+ ch->r_io[ATA_SSTATUS].res = ctlr->r_res1;
+ ch->r_io[ATA_SSTATUS].offset = 0x00100 + ATA_MV_HOST_BASE(ch);
+ ch->r_io[ATA_SERROR].res = ctlr->r_res1;
+ ch->r_io[ATA_SERROR].offset = 0x00104 + ATA_MV_HOST_BASE(ch);
+ ch->r_io[ATA_SCONTROL].res = ctlr->r_res1;
+ ch->r_io[ATA_SCONTROL].offset = 0x00108 + ATA_MV_HOST_BASE(ch);
+ break;
+ case MV_60XX:
+ ch->r_io[ATA_SSTATUS].res = ctlr->r_res1;
+ ch->r_io[ATA_SSTATUS].offset = 0x02300 + ATA_MV_EDMA_BASE(ch);
+ ch->r_io[ATA_SERROR].res = ctlr->r_res1;
+ ch->r_io[ATA_SERROR].offset = 0x02304 + ATA_MV_EDMA_BASE(ch);
+ ch->r_io[ATA_SCONTROL].res = ctlr->r_res1;
+ ch->r_io[ATA_SCONTROL].offset = 0x02308 + ATA_MV_EDMA_BASE(ch);
+ ch->r_io[ATA_SACTIVE].res = ctlr->r_res1;
+ ch->r_io[ATA_SACTIVE].offset = 0x02350 + ATA_MV_EDMA_BASE(ch);
+ break;
+ }
+
+ ch->flags |= ATA_NO_SLAVE;
+ ch->flags |= ATA_USE_16BIT; /* XXX SOS needed ? */
+ ata_generic_hw(dev);
+ ch->hw.begin_transaction = ata_marvell_edma_begin_transaction;
+ ch->hw.end_transaction = ata_marvell_edma_end_transaction;
+ ch->hw.status = ata_marvell_edma_status;
+
+ /* disable the EDMA machinery */
+ ATA_OUTL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch), 0x00000002);
+ DELAY(100000); /* SOS should poll for disabled */
+
+ /* set configuration to non-queued 128b read transfers stop on error */
+ ATA_OUTL(ctlr->r_res1, 0x02000 + ATA_MV_EDMA_BASE(ch), (1<<11) | (1<<13));
+
+ /* request queue base high */
+ ATA_OUTL(ctlr->r_res1, 0x02010 + ATA_MV_EDMA_BASE(ch), work >> 32);
+
+ /* request queue in ptr */
+ ATA_OUTL(ctlr->r_res1, 0x02014 + ATA_MV_EDMA_BASE(ch), work & 0xffffffff);
+
+ /* request queue out ptr */
+ ATA_OUTL(ctlr->r_res1, 0x02018 + ATA_MV_EDMA_BASE(ch), 0x0);
+
+ /* response queue base high */
+ work += 1024;
+ ATA_OUTL(ctlr->r_res1, 0x0201c + ATA_MV_EDMA_BASE(ch), work >> 32);
+
+ /* response queue in ptr */
+ ATA_OUTL(ctlr->r_res1, 0x02020 + ATA_MV_EDMA_BASE(ch), 0x0);
+
+ /* response queue out ptr */
+ ATA_OUTL(ctlr->r_res1, 0x02024 + ATA_MV_EDMA_BASE(ch), work & 0xffffffff);
+
+ /* clear SATA error register */
+ ATA_IDX_OUTL(ch, ATA_SERROR, ATA_IDX_INL(ch, ATA_SERROR));
+
+ /* clear any outstanding error interrupts */
+ ATA_OUTL(ctlr->r_res1, 0x02008 + ATA_MV_EDMA_BASE(ch), 0x0);
+
+ /* unmask all error interrupts */
+ ATA_OUTL(ctlr->r_res1, 0x0200c + ATA_MV_EDMA_BASE(ch), ~0x0);
+
+ /* enable EDMA machinery */
+ ATA_OUTL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch), 0x00000001);
+ return 0;
+}
+
+static int
+ata_marvell_edma_status(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ u_int32_t cause = ATA_INL(ctlr->r_res1, 0x01d60);
+ int shift = (ch->unit << 1) + (ch->unit > 3);
+
+ if (cause & (1 << shift)) {
+
+ /* clear interrupt(s) */
+ ATA_OUTL(ctlr->r_res1, 0x02008 + ATA_MV_EDMA_BASE(ch), 0x0);
+
+ /* do we have any PHY events ? */
+ ata_sata_phy_check_events(dev);
+ }
+
+ /* do we have any device action ? */
+ return (cause & (2 << shift));
+}
+
+/* must be called with ATA channel locked and state_mtx held */
+static int
+ata_marvell_edma_begin_transaction(struct ata_request *request)
+{
+ struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev));
+ struct ata_channel *ch = device_get_softc(request->parent);
+ u_int32_t req_in;
+ u_int8_t *bytep;
+ u_int16_t *wordp;
+ u_int32_t *quadp;
+ int i;
+ int error, slot;
+
+ /* only DMA R/W goes through the EMDA machine */
+ if (request->u.ata.command != ATA_READ_DMA &&
+ request->u.ata.command != ATA_WRITE_DMA) {
+
+ /* disable the EDMA machinery */
+ if (ATA_INL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch)) & 0x00000001)
+ ATA_OUTL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch), 0x00000002);
+ return ata_begin_transaction(request);
+ }
+
+ /* check for 48 bit access and convert if needed */
+ ata_modify_if_48bit(request);
+
+ /* check sanity, setup SG list and DMA engine */
+ if ((error = ch->dma.load(request, NULL, NULL))) {
+ device_printf(request->dev, "setting up DMA failed\n");
+ request->result = error;
+ return ATA_OP_FINISHED;
+ }
+
+ /* get next free request queue slot */
+ req_in = ATA_INL(ctlr->r_res1, 0x02014 + ATA_MV_EDMA_BASE(ch));
+ slot = (((req_in & ~0xfffffc00) >> 5) + 0) & 0x1f;
+ bytep = (u_int8_t *)(ch->dma.work);
+ bytep += (slot << 5);
+ wordp = (u_int16_t *)bytep;
+ quadp = (u_int32_t *)bytep;
+
+ /* fill in this request */
+ quadp[0] = (long)request->dma->sg_bus & 0xffffffff;
+ quadp[1] = (u_int64_t)request->dma->sg_bus >> 32;
+ wordp[4] = (request->flags & ATA_R_READ ? 0x01 : 0x00) | (request->tag<<1);
+
+ i = 10;
+ bytep[i++] = (request->u.ata.count >> 8) & 0xff;
+ bytep[i++] = 0x10 | ATA_COUNT;
+ bytep[i++] = request->u.ata.count & 0xff;
+ bytep[i++] = 0x10 | ATA_COUNT;
+
+ bytep[i++] = (request->u.ata.lba >> 24) & 0xff;
+ bytep[i++] = 0x10 | ATA_SECTOR;
+ bytep[i++] = request->u.ata.lba & 0xff;
+ bytep[i++] = 0x10 | ATA_SECTOR;
+
+ bytep[i++] = (request->u.ata.lba >> 32) & 0xff;
+ bytep[i++] = 0x10 | ATA_CYL_LSB;
+ bytep[i++] = (request->u.ata.lba >> 8) & 0xff;
+ bytep[i++] = 0x10 | ATA_CYL_LSB;
+
+ bytep[i++] = (request->u.ata.lba >> 40) & 0xff;
+ bytep[i++] = 0x10 | ATA_CYL_MSB;
+ bytep[i++] = (request->u.ata.lba >> 16) & 0xff;
+ bytep[i++] = 0x10 | ATA_CYL_MSB;
+
+ bytep[i++] = ATA_D_LBA | ATA_D_IBM | ((request->u.ata.lba >> 24) & 0xf);
+ bytep[i++] = 0x10 | ATA_DRIVE;
+
+ bytep[i++] = request->u.ata.command;
+ bytep[i++] = 0x90 | ATA_COMMAND;
+
+ /* enable EDMA machinery if needed */
+ if (!(ATA_INL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch)) & 0x00000001)) {
+ ATA_OUTL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch), 0x00000001);
+ while (!(ATA_INL(ctlr->r_res1,
+ 0x02028 + ATA_MV_EDMA_BASE(ch)) & 0x00000001))
+ DELAY(10);
+ }
+
+ /* tell EDMA it has a new request */
+ slot = (((req_in & ~0xfffffc00) >> 5) + 1) & 0x1f;
+ req_in &= 0xfffffc00;
+ req_in += (slot << 5);
+ ATA_OUTL(ctlr->r_res1, 0x02014 + ATA_MV_EDMA_BASE(ch), req_in);
+
+ return ATA_OP_CONTINUES;
+}
+
+/* must be called with ATA channel locked and state_mtx held */
+static int
+ata_marvell_edma_end_transaction(struct ata_request *request)
+{
+ struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev));
+ struct ata_channel *ch = device_get_softc(request->parent);
+ int offset = (ch->unit > 3 ? 0x30014 : 0x20014);
+ u_int32_t icr = ATA_INL(ctlr->r_res1, offset);
+ int res;
+
+ /* EDMA interrupt */
+ if ((icr & (0x0001 << (ch->unit & 3)))) {
+ struct ata_marvell_response *response;
+ u_int32_t rsp_in, rsp_out;
+ int slot;
+
+ /* stop timeout */
+ callout_stop(&request->callout);
+
+ /* get response ptr's */
+ rsp_in = ATA_INL(ctlr->r_res1, 0x02020 + ATA_MV_EDMA_BASE(ch));
+ rsp_out = ATA_INL(ctlr->r_res1, 0x02024 + ATA_MV_EDMA_BASE(ch));
+ slot = (((rsp_in & ~0xffffff00) >> 3)) & 0x1f;
+ rsp_out &= 0xffffff00;
+ rsp_out += (slot << 3);
+ response = (struct ata_marvell_response *)
+ (ch->dma.work + 1024 + (slot << 3));
+
+ /* record status for this request */
+ request->status = response->dev_status;
+ request->error = 0;
+
+ /* ack response */
+ ATA_OUTL(ctlr->r_res1, 0x02024 + ATA_MV_EDMA_BASE(ch), rsp_out);
+
+ /* update progress */
+ if (!(request->status & ATA_S_ERROR) &&
+ !(request->flags & ATA_R_TIMEOUT))
+ request->donecount = request->bytecount;
+
+ /* unload SG list */
+ ch->dma.unload(request);
+
+ res = ATA_OP_FINISHED;
+ }
+
+ /* legacy ATA interrupt */
+ else {
+ res = ata_end_transaction(request);
+ }
+
+ /* ack interrupt */
+ ATA_OUTL(ctlr->r_res1, offset, ~(icr & (0x0101 << (ch->unit & 3))));
+ return res;
+}
+
+static void
+ata_marvell_edma_reset(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+
+ /* disable the EDMA machinery */
+ ATA_OUTL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch), 0x00000002);
+ while ((ATA_INL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch)) & 0x00000001))
+ DELAY(10);
+
+ /* clear SATA error register */
+ ATA_IDX_OUTL(ch, ATA_SERROR, ATA_IDX_INL(ch, ATA_SERROR));
+
+ /* clear any outstanding error interrupts */
+ ATA_OUTL(ctlr->r_res1, 0x02008 + ATA_MV_EDMA_BASE(ch), 0x0);
+
+ /* unmask all error interrupts */
+ ATA_OUTL(ctlr->r_res1, 0x0200c + ATA_MV_EDMA_BASE(ch), ~0x0);
+
+ /* enable channel and test for devices */
+ if (ata_sata_phy_reset(dev))
+ ata_generic_reset(dev);
+
+ /* enable EDMA machinery */
+ ATA_OUTL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch), 0x00000001);
+}
+
+static void
+ata_marvell_edma_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs,
+ int error)
+{
+ struct ata_dmasetprd_args *args = xsc;
+ struct ata_marvell_dma_prdentry *prd = args->dmatab;
+ int i;
+
+ if ((args->error = error))
+ return;
+
+ for (i = 0; i < nsegs; i++) {
+ prd[i].addrlo = htole32(segs[i].ds_addr);
+ prd[i].count = htole32(segs[i].ds_len);
+ prd[i].addrhi = htole32((u_int64_t)segs[i].ds_addr >> 32);
+ }
+ prd[i - 1].count |= htole32(ATA_DMA_EOT);
+ KASSERT(nsegs <= ATA_DMA_ENTRIES, ("too many DMA segment entries\n"));
+ args->nsegs = nsegs;
+}
+
+static void
+ata_marvell_edma_dmainit(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+
+ ata_dmainit(dev);
+ /* note start and stop are not used here */
+ ch->dma.setprd = ata_marvell_edma_dmasetprd;
+
+ /* if 64bit support present adjust max address used */
+ if (ATA_INL(ctlr->r_res1, 0x00d00) & 0x00000004)
+ ch->dma.max_address = BUS_SPACE_MAXADDR;
+
+ /* chip does not reliably do 64K DMA transfers */
+ ch->dma.max_iosize = 126 * DEV_BSIZE;
+}
+
+ATA_DECLARE_DRIVER(ata_marvell);
diff --git a/sys/dev/ata/chipsets/ata-micron.c b/sys/dev/ata/chipsets/ata-micron.c
new file mode 100644
index 0000000..1351f09
--- /dev/null
+++ b/sys/dev/ata/chipsets/ata-micron.c
@@ -0,0 +1,101 @@
+/*-
+ * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org>
+ * 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,
+ * without modification, immediately at the beginning of the file.
+ * 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 AUTHOR ``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 AUTHOR 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>
+__FBSDID("$FreeBSD$");
+
+#include "opt_ata.h"
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/ata.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sema.h>
+#include <sys/taskqueue.h>
+#include <vm/uma.h>
+#include <machine/stdarg.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/ata/ata-all.h>
+#include <dev/ata/ata-pci.h>
+#include <ata_if.h>
+
+/* local prototypes */
+static int ata_micron_chipinit(device_t dev);
+static void ata_micron_setmode(device_t dev, int mode);
+
+
+/*
+ * Cenatek chipset support functions
+ */
+static int
+ata_micron_probe(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+
+ if (pci_get_devid(dev) == ATA_MICRON_RZ1000 ||
+ pci_get_devid(dev) == ATA_MICRON_RZ1001) {
+ device_set_desc(dev,
+ "RZ 100? ATA controller !WARNING! data loss/corruption risk");
+ ctlr->chipinit = ata_micron_chipinit;
+ return 0;
+ }
+ else
+ return ENXIO;
+}
+
+static int
+ata_micron_chipinit(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+
+ if (ata_setup_interrupt(dev, ata_generic_intr))
+ return ENXIO;
+
+ ctlr->setmode = ata_micron_setmode;
+ return 0;
+}
+
+static void
+ata_micron_setmode(device_t dev, int mode)
+{
+ struct ata_device *atadev = device_get_softc(dev);
+
+ mode = ata_limit_mode(dev, mode, ATA_UDMA2);
+ mode = ata_check_80pin(dev, mode);
+ if (!ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode))
+ atadev->mode = mode;
+}
+
+ATA_DECLARE_DRIVER(ata_micron);
diff --git a/sys/dev/ata/chipsets/ata-national.c b/sys/dev/ata/chipsets/ata-national.c
new file mode 100644
index 0000000..8e80a10f
--- /dev/null
+++ b/sys/dev/ata/chipsets/ata-national.c
@@ -0,0 +1,133 @@
+/*-
+ * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org>
+ * 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,
+ * without modification, immediately at the beginning of the file.
+ * 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 AUTHOR ``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 AUTHOR 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>
+__FBSDID("$FreeBSD$");
+
+#include "opt_ata.h"
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/ata.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sema.h>
+#include <sys/taskqueue.h>
+#include <vm/uma.h>
+#include <machine/stdarg.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/ata/ata-all.h>
+#include <dev/ata/ata-pci.h>
+#include <ata_if.h>
+
+/* local prototypes */
+static int ata_national_chipinit(device_t dev);
+static void ata_national_setmode(device_t dev, int mode);
+
+
+/*
+ * National chipset support functions
+ */
+static int
+ata_national_probe(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+
+ /* this chip is a clone of the Cyrix chip, bugs and all */
+ if (pci_get_devid(dev) == ATA_SC1100) {
+ device_set_desc(dev, "National Geode SC1100 ATA33 controller");
+ ctlr->chipinit = ata_national_chipinit;
+ return 0;
+ }
+ return ENXIO;
+}
+
+static int
+ata_national_chipinit(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+
+ if (ata_setup_interrupt(dev, ata_generic_intr))
+ return ENXIO;
+
+ ctlr->setmode = ata_national_setmode;
+ return 0;
+}
+
+static void
+ata_national_setmode(device_t dev, int mode)
+{
+ device_t gparent = GRANDPARENT(dev);
+ struct ata_channel *ch = device_get_softc(device_get_parent(dev));
+ struct ata_device *atadev = device_get_softc(dev);
+ int devno = (ch->unit << 1) + atadev->unit;
+ u_int32_t piotiming[] =
+ { 0x9172d132, 0x21717121, 0x00803020, 0x20102010, 0x00100010,
+ 0x00803020, 0x20102010, 0x00100010,
+ 0x00100010, 0x00100010, 0x00100010 };
+ u_int32_t dmatiming[] = { 0x80077771, 0x80012121, 0x80002020 };
+ u_int32_t udmatiming[] = { 0x80921250, 0x80911140, 0x80911030 };
+ int error;
+
+ ch->dma.alignment = 16;
+ ch->dma.max_iosize = 126 * DEV_BSIZE;
+
+ mode = ata_limit_mode(dev, mode, ATA_UDMA2);
+
+ error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
+
+ if (bootverbose)
+ device_printf(dev, "%s setting %s on National chip\n",
+ (error) ? "failed" : "success", ata_mode2str(mode));
+ if (!error) {
+ if (mode >= ATA_UDMA0) {
+ pci_write_config(gparent, 0x44 + (devno << 3),
+ udmatiming[mode & ATA_MODE_MASK], 4);
+ }
+ else if (mode >= ATA_WDMA0) {
+ pci_write_config(gparent, 0x44 + (devno << 3),
+ dmatiming[mode & ATA_MODE_MASK], 4);
+ }
+ else {
+ pci_write_config(gparent, 0x44 + (devno << 3),
+ pci_read_config(gparent, 0x44 + (devno << 3), 4) |
+ 0x80000000, 4);
+ }
+ pci_write_config(gparent, 0x40 + (devno << 3),
+ piotiming[ata_mode2idx(mode)], 4);
+ atadev->mode = mode;
+ }
+}
+
+ATA_DECLARE_DRIVER(ata_national);
diff --git a/sys/dev/ata/chipsets/ata-netcell.c b/sys/dev/ata/chipsets/ata-netcell.c
new file mode 100644
index 0000000..7a446f1
--- /dev/null
+++ b/sys/dev/ata/chipsets/ata-netcell.c
@@ -0,0 +1,115 @@
+/*-
+ * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org>
+ * 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,
+ * without modification, immediately at the beginning of the file.
+ * 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 AUTHOR ``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 AUTHOR 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>
+__FBSDID("$FreeBSD$");
+
+#include "opt_ata.h"
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/ata.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sema.h>
+#include <sys/taskqueue.h>
+#include <vm/uma.h>
+#include <machine/stdarg.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/ata/ata-all.h>
+#include <dev/ata/ata-pci.h>
+#include <ata_if.h>
+
+/* local prototypes */
+static int ata_netcell_chipinit(device_t dev);
+static int ata_netcell_allocate(device_t dev);
+static void ata_netcell_setmode(device_t dev, int mode);
+
+
+/*
+ * NetCell chipset support functions
+ */
+static int
+ata_netcell_probe(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+
+ if (pci_get_devid(dev) == ATA_NETCELL_SR) {
+ device_set_desc(dev, "Netcell SyncRAID SR3000/5000 RAID Controller");
+ ctlr->chipinit = ata_netcell_chipinit;
+ return 0;
+ }
+ return ENXIO;
+}
+
+static int
+ata_netcell_chipinit(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+
+ if (ata_setup_interrupt(dev, ata_generic_intr))
+ return ENXIO;
+
+ ctlr->allocate = ata_netcell_allocate;
+ ctlr->setmode = ata_netcell_setmode;
+ return 0;
+}
+
+static int
+ata_netcell_allocate(device_t dev)
+{
+ struct ata_channel *ch = device_get_softc(dev);
+
+ /* setup the usual register normal pci style */
+ if (ata_pci_allocate(dev))
+ return ENXIO;
+
+ /* the NetCell only supports 16 bit PIO transfers */
+ ch->flags |= ATA_USE_16BIT;
+
+ return 0;
+}
+
+static void
+ata_netcell_setmode(device_t dev, int mode)
+{
+ struct ata_device *atadev = device_get_softc(dev);
+
+ mode = ata_limit_mode(dev, mode, ATA_UDMA2);
+ mode = ata_check_80pin(dev, mode);
+ if (!ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode))
+ atadev->mode = mode;
+}
+
+ATA_DECLARE_DRIVER(ata_netcell);
diff --git a/sys/dev/ata/chipsets/ata-nvidia.c b/sys/dev/ata/chipsets/ata-nvidia.c
new file mode 100644
index 0000000..6042e8d
--- /dev/null
+++ b/sys/dev/ata/chipsets/ata-nvidia.c
@@ -0,0 +1,264 @@
+/*-
+ * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org>
+ * 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,
+ * without modification, immediately at the beginning of the file.
+ * 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 AUTHOR ``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 AUTHOR 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>
+__FBSDID("$FreeBSD$");
+
+#include "opt_ata.h"
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/ata.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sema.h>
+#include <sys/taskqueue.h>
+#include <vm/uma.h>
+#include <machine/stdarg.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/ata/ata-all.h>
+#include <dev/ata/ata-pci.h>
+#include <ata_if.h>
+
+/* local prototypes */
+static int ata_nvidia_chipinit(device_t dev);
+static int ata_nvidia_allocate(device_t dev);
+static int ata_nvidia_status(device_t dev);
+static void ata_nvidia_reset(device_t dev);
+static void ata_nvidia_setmode(device_t dev, int mode);
+
+/* misc defines */
+#define NV4 0x01
+#define NVQ 0x02
+
+
+/*
+ * nVidia chipset support functions
+ */
+static int
+ata_nvidia_probe(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+ static struct ata_chip_id ids[] =
+ {{ ATA_NFORCE1, 0, 0, 0, ATA_UDMA5, "nForce" },
+ { ATA_NFORCE2, 0, 0, 0, ATA_UDMA6, "nForce2" },
+ { ATA_NFORCE2_PRO, 0, 0, 0, ATA_UDMA6, "nForce2 Pro" },
+ { ATA_NFORCE2_PRO_S1, 0, 0, 0, ATA_SA150, "nForce2 Pro" },
+ { ATA_NFORCE3, 0, 0, 0, ATA_UDMA6, "nForce3" },
+ { ATA_NFORCE3_PRO, 0, 0, 0, ATA_UDMA6, "nForce3 Pro" },
+ { ATA_NFORCE3_PRO_S1, 0, 0, 0, ATA_SA150, "nForce3 Pro" },
+ { ATA_NFORCE3_PRO_S2, 0, 0, 0, ATA_SA150, "nForce3 Pro" },
+ { ATA_NFORCE_MCP04, 0, 0, 0, ATA_UDMA6, "nForce MCP" },
+ { ATA_NFORCE_MCP04_S1, 0, NV4, 0, ATA_SA150, "nForce MCP" },
+ { ATA_NFORCE_MCP04_S2, 0, NV4, 0, ATA_SA150, "nForce MCP" },
+ { ATA_NFORCE_CK804, 0, 0, 0, ATA_UDMA6, "nForce CK804" },
+ { ATA_NFORCE_CK804_S1, 0, NV4, 0, ATA_SA300, "nForce CK804" },
+ { ATA_NFORCE_CK804_S2, 0, NV4, 0, ATA_SA300, "nForce CK804" },
+ { ATA_NFORCE_MCP51, 0, 0, 0, ATA_UDMA6, "nForce MCP51" },
+ { ATA_NFORCE_MCP51_S1, 0, NV4|NVQ, 0, ATA_SA300, "nForce MCP51" },
+ { ATA_NFORCE_MCP51_S2, 0, NV4|NVQ, 0, ATA_SA300, "nForce MCP51" },
+ { ATA_NFORCE_MCP55, 0, 0, 0, ATA_UDMA6, "nForce MCP55" },
+ { ATA_NFORCE_MCP55_S1, 0, NV4|NVQ, 0, ATA_SA300, "nForce MCP55" },
+ { ATA_NFORCE_MCP55_S2, 0, NV4|NVQ, 0, ATA_SA300, "nForce MCP55" },
+ { ATA_NFORCE_MCP61, 0, 0, 0, ATA_UDMA6, "nForce MCP61" },
+ { ATA_NFORCE_MCP61_S1, 0, NV4|NVQ, 0, ATA_SA300, "nForce MCP61" },
+ { ATA_NFORCE_MCP61_S2, 0, NV4|NVQ, 0, ATA_SA300, "nForce MCP61" },
+ { ATA_NFORCE_MCP61_S3, 0, NV4|NVQ, 0, ATA_SA300, "nForce MCP61" },
+ { ATA_NFORCE_MCP65, 0, 0, 0, ATA_UDMA6, "nForce MCP65" },
+ { ATA_NFORCE_MCP67, 0, 0, 0, ATA_UDMA6, "nForce MCP67" },
+ { ATA_NFORCE_MCP73, 0, 0, 0, ATA_UDMA6, "nForce MCP73" },
+ { ATA_NFORCE_MCP77, 0, 0, 0, ATA_UDMA6, "nForce MCP77" },
+ { 0, 0, 0, 0, 0, 0}} ;
+
+ if (pci_get_vendor(dev) != ATA_NVIDIA_ID)
+ return ENXIO;
+
+ if (!(ctlr->chip = ata_match_chip(dev, ids)))
+ return ENXIO;
+
+ ata_set_desc(dev);
+ ctlr->chipinit = ata_nvidia_chipinit;
+ return 0;
+}
+
+static int
+ata_nvidia_chipinit(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+
+ if (ata_setup_interrupt(dev, ata_generic_intr))
+ return ENXIO;
+
+ if (ctlr->chip->max_dma >= ATA_SA150) {
+ if (pci_read_config(dev, PCIR_BAR(5), 1) & 1)
+ ctlr->r_type2 = SYS_RES_IOPORT;
+ else
+ ctlr->r_type2 = SYS_RES_MEMORY;
+ ctlr->r_rid2 = PCIR_BAR(5);
+ if ((ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2,
+ &ctlr->r_rid2, RF_ACTIVE))) {
+ int offset = ctlr->chip->cfg1 & NV4 ? 0x0440 : 0x0010;
+
+ ctlr->allocate = ata_nvidia_allocate;
+ ctlr->reset = ata_nvidia_reset;
+
+ /* enable control access */
+ pci_write_config(dev, 0x50, pci_read_config(dev, 0x50, 1) | 0x04,1);
+
+ if (ctlr->chip->cfg1 & NVQ) {
+ /* clear interrupt status */
+ ATA_OUTL(ctlr->r_res2, offset, 0x00ff00ff);
+
+ /* enable device and PHY state change interrupts */
+ ATA_OUTL(ctlr->r_res2, offset + 4, 0x000d000d);
+
+ /* disable NCQ support */
+ ATA_OUTL(ctlr->r_res2, 0x0400,
+ ATA_INL(ctlr->r_res2, 0x0400) & 0xfffffff9);
+ }
+ else {
+ /* clear interrupt status */
+ ATA_OUTB(ctlr->r_res2, offset, 0xff);
+
+ /* enable device and PHY state change interrupts */
+ ATA_OUTB(ctlr->r_res2, offset + 1, 0xdd);
+ }
+
+ /* enable PCI interrupt */
+ pci_write_config(dev, PCIR_COMMAND,
+ pci_read_config(dev, PCIR_COMMAND, 2) & ~0x0400,2);
+
+ }
+ ctlr->setmode = ata_sata_setmode;
+ }
+ else {
+ /* disable prefetch, postwrite */
+ pci_write_config(dev, 0x51, pci_read_config(dev, 0x51, 1) & 0x0f, 1);
+ ctlr->setmode = ata_nvidia_setmode;
+ }
+ return 0;
+}
+
+static int
+ata_nvidia_allocate(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+
+ /* setup the usual register normal pci style */
+ if (ata_pci_allocate(dev))
+ return ENXIO;
+
+ ch->r_io[ATA_SSTATUS].res = ctlr->r_res2;
+ ch->r_io[ATA_SSTATUS].offset = (ch->unit << 6);
+ ch->r_io[ATA_SERROR].res = ctlr->r_res2;
+ ch->r_io[ATA_SERROR].offset = 0x04 + (ch->unit << 6);
+ ch->r_io[ATA_SCONTROL].res = ctlr->r_res2;
+ ch->r_io[ATA_SCONTROL].offset = 0x08 + (ch->unit << 6);
+
+ ch->hw.status = ata_nvidia_status;
+ ch->flags |= ATA_NO_SLAVE;
+
+ return 0;
+}
+
+static int
+ata_nvidia_status(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ int offset = ctlr->chip->cfg1 & NV4 ? 0x0440 : 0x0010;
+ int shift = ch->unit << (ctlr->chip->cfg1 & NVQ ? 4 : 2);
+ u_int32_t istatus;
+
+ /* get interrupt status */
+ if (ctlr->chip->cfg1 & NVQ)
+ istatus = ATA_INL(ctlr->r_res2, offset);
+ else
+ istatus = ATA_INB(ctlr->r_res2, offset);
+
+ /* do we have any PHY events ? */
+ if (istatus & (0x0c << shift))
+ ata_sata_phy_check_events(dev);
+
+ /* clear interrupt(s) */
+ if (ctlr->chip->cfg1 & NVQ)
+ ATA_OUTL(ctlr->r_res2, offset, (0x0f << shift) | 0x00f000f0);
+ else
+ ATA_OUTB(ctlr->r_res2, offset, (0x0f << shift));
+
+ /* do we have any device action ? */
+ return (istatus & (0x01 << shift));
+}
+
+static void
+ata_nvidia_reset(device_t dev)
+{
+ if (ata_sata_phy_reset(dev))
+ ata_generic_reset(dev);
+}
+
+static void
+ata_nvidia_setmode(device_t dev, int mode)
+{
+ device_t gparent = GRANDPARENT(dev);
+ struct ata_pci_controller *ctlr = device_get_softc(gparent);
+ struct ata_channel *ch = device_get_softc(device_get_parent(dev));
+ struct ata_device *atadev = device_get_softc(dev);
+ u_int8_t timings[] = { 0xa8, 0x65, 0x42, 0x22, 0x20, 0x42, 0x22, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 };
+ int modes[7] = { 0xc2, 0xc1, 0xc0, 0xc4, 0xc5, 0xc6, 0xc7 };
+ int devno = (ch->unit << 1) + atadev->unit;
+ int reg = 0x63 - devno;
+ int error;
+
+ mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma);
+ mode = ata_check_80pin(dev, mode);
+
+ error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
+ if (bootverbose)
+ device_printf(dev, "%ssetting %s on %s chip\n",
+ (error) ? "FAILURE " : "", ata_mode2str(mode),
+ ctlr->chip->text);
+ if (!error) {
+ pci_write_config(gparent, reg - 0x08, timings[ata_mode2idx(mode)], 1);
+ if (mode >= ATA_UDMA0)
+ pci_write_config(gparent, reg, modes[mode & ATA_MODE_MASK], 1);
+ else
+ pci_write_config(gparent, reg, 0x8b, 1);
+ atadev->mode = mode;
+ }
+}
+
+ATA_DECLARE_DRIVER(ata_nvidia);
diff --git a/sys/dev/ata/chipsets/ata-promise.c b/sys/dev/ata/chipsets/ata-promise.c
new file mode 100644
index 0000000..7d1ec21
--- /dev/null
+++ b/sys/dev/ata/chipsets/ata-promise.c
@@ -0,0 +1,1250 @@
+/*-
+ * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org>
+ * 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,
+ * without modification, immediately at the beginning of the file.
+ * 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 AUTHOR ``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 AUTHOR 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>
+__FBSDID("$FreeBSD$");
+
+#include "opt_ata.h"
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/ata.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sema.h>
+#include <sys/taskqueue.h>
+#include <vm/uma.h>
+#include <machine/stdarg.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/ata/ata-all.h>
+#include <dev/ata/ata-pci.h>
+#include <ata_if.h>
+
+/* local prototypes */
+static int ata_promise_chipinit(device_t dev);
+static int ata_promise_allocate(device_t dev);
+static int ata_promise_status(device_t dev);
+static int ata_promise_dmastart(struct ata_request *request);
+static int ata_promise_dmastop(struct ata_request *request);
+static void ata_promise_dmareset(device_t dev);
+static void ata_promise_dmainit(device_t dev);
+static void ata_promise_setmode(device_t dev, int mode);
+static int ata_promise_tx2_allocate(device_t dev);
+static int ata_promise_tx2_status(device_t dev);
+static int ata_promise_mio_allocate(device_t dev);
+static void ata_promise_mio_intr(void *data);
+static int ata_promise_mio_status(device_t dev);
+static int ata_promise_mio_command(struct ata_request *request);
+static void ata_promise_mio_reset(device_t dev);
+static int ata_promise_mio_pm_read(device_t dev, int port, int reg, u_int32_t *result);
+static int ata_promise_mio_pm_write(device_t dev, int port, int reg, u_int32_t result);
+static u_int32_t ata_promise_mio_softreset(device_t dev, int port);
+static void ata_promise_mio_dmainit(device_t dev);
+static void ata_promise_mio_setprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error);
+static void ata_promise_mio_setmode(device_t dev, int mode);
+static void ata_promise_sx4_intr(void *data);
+static int ata_promise_sx4_command(struct ata_request *request);
+static int ata_promise_apkt(u_int8_t *bytep, struct ata_request *request);
+static void ata_promise_queue_hpkt(struct ata_pci_controller *ctlr, u_int32_t hpkt);
+static void ata_promise_next_hpkt(struct ata_pci_controller *ctlr);
+
+/* misc defines */
+#define PR_OLD 0
+#define PR_NEW 1
+#define PR_TX 2
+#define PR_MIO 3
+#define PR_TX4 0x01
+#define PR_SX4X 0x02
+#define PR_SX6K 0x04
+#define PR_PATA 0x08
+#define PR_CMBO 0x10
+#define PR_CMBO2 0x20
+#define PR_SATA 0x40
+#define PR_SATA2 0x80
+
+
+/*
+ * Promise chipset support functions
+ */
+#define ATA_PDC_APKT_OFFSET 0x00000010
+#define ATA_PDC_HPKT_OFFSET 0x00000040
+#define ATA_PDC_ASG_OFFSET 0x00000080
+#define ATA_PDC_LSG_OFFSET 0x000000c0
+#define ATA_PDC_HSG_OFFSET 0x00000100
+#define ATA_PDC_CHN_OFFSET 0x00000400
+#define ATA_PDC_BUF_BASE 0x00400000
+#define ATA_PDC_BUF_OFFSET 0x00100000
+#define ATA_PDC_MAX_HPKT 8
+#define ATA_PDC_WRITE_REG 0x00
+#define ATA_PDC_WRITE_CTL 0x0e
+#define ATA_PDC_WRITE_END 0x08
+#define ATA_PDC_WAIT_NBUSY 0x10
+#define ATA_PDC_WAIT_READY 0x18
+#define ATA_PDC_1B 0x20
+#define ATA_PDC_2B 0x40
+
+struct host_packet {
+ u_int32_t addr;
+ TAILQ_ENTRY(host_packet) chain;
+};
+
+struct ata_promise_sx4 {
+ struct mtx mtx;
+ TAILQ_HEAD(, host_packet) queue;
+ int busy;
+};
+
+static int
+ata_promise_probe(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+ struct ata_chip_id *idx;
+ static struct ata_chip_id ids[] =
+ {{ ATA_PDC20246, 0, PR_OLD, 0x00, ATA_UDMA2, "PDC20246" },
+ { ATA_PDC20262, 0, PR_NEW, 0x00, ATA_UDMA4, "PDC20262" },
+ { ATA_PDC20263, 0, PR_NEW, 0x00, ATA_UDMA4, "PDC20263" },
+ { ATA_PDC20265, 0, PR_NEW, 0x00, ATA_UDMA5, "PDC20265" },
+ { ATA_PDC20267, 0, PR_NEW, 0x00, ATA_UDMA5, "PDC20267" },
+ { ATA_PDC20268, 0, PR_TX, PR_TX4, ATA_UDMA5, "PDC20268" },
+ { ATA_PDC20269, 0, PR_TX, 0x00, ATA_UDMA6, "PDC20269" },
+ { ATA_PDC20270, 0, PR_TX, PR_TX4, ATA_UDMA5, "PDC20270" },
+ { ATA_PDC20271, 0, PR_TX, 0x00, ATA_UDMA6, "PDC20271" },
+ { ATA_PDC20275, 0, PR_TX, 0x00, ATA_UDMA6, "PDC20275" },
+ { ATA_PDC20276, 0, PR_TX, PR_SX6K, ATA_UDMA6, "PDC20276" },
+ { ATA_PDC20277, 0, PR_TX, 0x00, ATA_UDMA6, "PDC20277" },
+ { ATA_PDC20318, 0, PR_MIO, PR_SATA, ATA_SA150, "PDC20318" },
+ { ATA_PDC20319, 0, PR_MIO, PR_SATA, ATA_SA150, "PDC20319" },
+ { ATA_PDC20371, 0, PR_MIO, PR_CMBO, ATA_SA150, "PDC20371" },
+ { ATA_PDC20375, 0, PR_MIO, PR_CMBO, ATA_SA150, "PDC20375" },
+ { ATA_PDC20376, 0, PR_MIO, PR_CMBO, ATA_SA150, "PDC20376" },
+ { ATA_PDC20377, 0, PR_MIO, PR_CMBO, ATA_SA150, "PDC20377" },
+ { ATA_PDC20378, 0, PR_MIO, PR_CMBO, ATA_SA150, "PDC20378" },
+ { ATA_PDC20379, 0, PR_MIO, PR_CMBO, ATA_SA150, "PDC20379" },
+ { ATA_PDC20571, 0, PR_MIO, PR_CMBO2, ATA_SA150, "PDC20571" },
+ { ATA_PDC20575, 0, PR_MIO, PR_CMBO2, ATA_SA150, "PDC20575" },
+ { ATA_PDC20579, 0, PR_MIO, PR_CMBO2, ATA_SA150, "PDC20579" },
+ { ATA_PDC20771, 0, PR_MIO, PR_CMBO2, ATA_SA300, "PDC20771" },
+ { ATA_PDC40775, 0, PR_MIO, PR_CMBO2, ATA_SA300, "PDC40775" },
+ { ATA_PDC20617, 0, PR_MIO, PR_PATA, ATA_UDMA6, "PDC20617" },
+ { ATA_PDC20618, 0, PR_MIO, PR_PATA, ATA_UDMA6, "PDC20618" },
+ { ATA_PDC20619, 0, PR_MIO, PR_PATA, ATA_UDMA6, "PDC20619" },
+ { ATA_PDC20620, 0, PR_MIO, PR_PATA, ATA_UDMA6, "PDC20620" },
+ { ATA_PDC20621, 0, PR_MIO, PR_SX4X, ATA_UDMA5, "PDC20621" },
+ { ATA_PDC20622, 0, PR_MIO, PR_SX4X, ATA_SA150, "PDC20622" },
+ { ATA_PDC40518, 0, PR_MIO, PR_SATA2, ATA_SA150, "PDC40518" },
+ { ATA_PDC40519, 0, PR_MIO, PR_SATA2, ATA_SA150, "PDC40519" },
+ { ATA_PDC40718, 0, PR_MIO, PR_SATA2, ATA_SA300, "PDC40718" },
+ { ATA_PDC40719, 0, PR_MIO, PR_SATA2, ATA_SA300, "PDC40719" },
+ { ATA_PDC40779, 0, PR_MIO, PR_SATA2, ATA_SA300, "PDC40779" },
+ { 0, 0, 0, 0, 0, 0}};
+ char buffer[64];
+ uintptr_t devid = 0;
+
+ if (pci_get_vendor(dev) != ATA_PROMISE_ID)
+ return ENXIO;
+
+ if (!(idx = ata_match_chip(dev, ids)))
+ return ENXIO;
+
+ /* if we are on a SuperTrak SX6000 dont attach */
+ if ((idx->cfg2 & PR_SX6K) && pci_get_class(GRANDPARENT(dev))==PCIC_BRIDGE &&
+ !BUS_READ_IVAR(device_get_parent(GRANDPARENT(dev)),
+ GRANDPARENT(dev), PCI_IVAR_DEVID, &devid) &&
+ devid == ATA_I960RM)
+ return ENXIO;
+
+ strcpy(buffer, "Promise ");
+ strcat(buffer, idx->text);
+
+ /* if we are on a FastTrak TX4, adjust the interrupt resource */
+ if ((idx->cfg2 & PR_TX4) && pci_get_class(GRANDPARENT(dev))==PCIC_BRIDGE &&
+ !BUS_READ_IVAR(device_get_parent(GRANDPARENT(dev)),
+ GRANDPARENT(dev), PCI_IVAR_DEVID, &devid) &&
+ ((devid == ATA_DEC_21150) || (devid == ATA_DEC_21150_1))) {
+ static long start = 0, end = 0;
+
+ if (pci_get_slot(dev) == 1) {
+ bus_get_resource(dev, SYS_RES_IRQ, 0, &start, &end);
+ strcat(buffer, " (channel 0+1)");
+ }
+ else if (pci_get_slot(dev) == 2 && start && end) {
+ bus_set_resource(dev, SYS_RES_IRQ, 0, start, end);
+ strcat(buffer, " (channel 2+3)");
+ }
+ else {
+ start = end = 0;
+ }
+ }
+ sprintf(buffer, "%s %s controller", buffer, ata_mode2str(idx->max_dma));
+ device_set_desc_copy(dev, buffer);
+ ctlr->chip = idx;
+ ctlr->chipinit = ata_promise_chipinit;
+ return 0;
+}
+
+static int
+ata_promise_chipinit(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+ int fake_reg, stat_reg;
+
+ if (ata_setup_interrupt(dev, ata_generic_intr))
+ return ENXIO;
+
+ switch (ctlr->chip->cfg1) {
+ case PR_NEW:
+ /* setup clocks */
+ ATA_OUTB(ctlr->r_res1, 0x11, ATA_INB(ctlr->r_res1, 0x11) | 0x0a);
+
+ ctlr->dmainit = ata_promise_dmainit;
+ /* FALLTHROUGH */
+
+ case PR_OLD:
+ /* enable burst mode */
+ ATA_OUTB(ctlr->r_res1, 0x1f, ATA_INB(ctlr->r_res1, 0x1f) | 0x01);
+ ctlr->allocate = ata_promise_allocate;
+ ctlr->setmode = ata_promise_setmode;
+ return 0;
+
+ case PR_TX:
+ ctlr->allocate = ata_promise_tx2_allocate;
+ ctlr->setmode = ata_promise_setmode;
+ return 0;
+
+ case PR_MIO:
+ ctlr->r_type1 = SYS_RES_MEMORY;
+ ctlr->r_rid1 = PCIR_BAR(4);
+ if (!(ctlr->r_res1 = bus_alloc_resource_any(dev, ctlr->r_type1,
+ &ctlr->r_rid1, RF_ACTIVE)))
+ goto failnfree;
+
+ ctlr->r_type2 = SYS_RES_MEMORY;
+ ctlr->r_rid2 = PCIR_BAR(3);
+ if (!(ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2,
+ &ctlr->r_rid2, RF_ACTIVE)))
+ goto failnfree;
+
+ if (ctlr->chip->cfg2 == PR_SX4X) {
+ struct ata_promise_sx4 *hpkt;
+ u_int32_t dimm = ATA_INL(ctlr->r_res2, 0x000c0080);
+
+ if (bus_teardown_intr(dev, ctlr->r_irq, ctlr->handle) ||
+ bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, NULL,
+ ata_promise_sx4_intr, ctlr, &ctlr->handle)) {
+ device_printf(dev, "unable to setup interrupt\n");
+ goto failnfree;
+ }
+
+ /* print info about cache memory */
+ device_printf(dev, "DIMM size %dMB @ 0x%08x%s\n",
+ (((dimm >> 16) & 0xff)-((dimm >> 24) & 0xff)+1) << 4,
+ ((dimm >> 24) & 0xff),
+ ATA_INL(ctlr->r_res2, 0x000c0088) & (1<<16) ?
+ " ECC enabled" : "" );
+
+ /* adjust cache memory parameters */
+ ATA_OUTL(ctlr->r_res2, 0x000c000c,
+ (ATA_INL(ctlr->r_res2, 0x000c000c) & 0xffff0000));
+
+ /* setup host packet controls */
+ hpkt = malloc(sizeof(struct ata_promise_sx4),
+ M_TEMP, M_NOWAIT | M_ZERO);
+ mtx_init(&hpkt->mtx, "ATA promise HPKT lock", NULL, MTX_DEF);
+ TAILQ_INIT(&hpkt->queue);
+ hpkt->busy = 0;
+ device_set_ivars(dev, hpkt);
+ ctlr->allocate = ata_promise_mio_allocate;
+ ctlr->reset = ata_promise_mio_reset;
+ ctlr->dmainit = ata_promise_mio_dmainit;
+ ctlr->setmode = ata_promise_setmode;
+ ctlr->channels = 4;
+ return 0;
+ }
+
+ /* mio type controllers need an interrupt intercept */
+ if (bus_teardown_intr(dev, ctlr->r_irq, ctlr->handle) ||
+ bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, NULL,
+ ata_promise_mio_intr, ctlr, &ctlr->handle)) {
+ device_printf(dev, "unable to setup interrupt\n");
+ goto failnfree;
+ }
+
+ switch (ctlr->chip->cfg2) {
+ case PR_PATA:
+ ctlr->channels = ((ATA_INL(ctlr->r_res2, 0x48) & 0x01) > 0) +
+ ((ATA_INL(ctlr->r_res2, 0x48) & 0x02) > 0) + 2;
+ goto sata150;
+ case PR_CMBO:
+ ctlr->channels = 3;
+ goto sata150;
+ case PR_SATA:
+ ctlr->channels = 4;
+sata150:
+ fake_reg = 0x60;
+ stat_reg = 0x6c;
+ break;
+
+ case PR_CMBO2:
+ ctlr->channels = 3;
+ goto sataii;
+ case PR_SATA2:
+ default:
+ ctlr->channels = 4;
+sataii:
+ fake_reg = 0x54;
+ stat_reg = 0x60;
+ break;
+ }
+
+ /* prime fake interrupt register */
+ ATA_OUTL(ctlr->r_res2, fake_reg, 0xffffffff);
+
+ /* clear SATA status and unmask interrupts */
+ ATA_OUTL(ctlr->r_res2, stat_reg, 0x000000ff);
+
+ /* enable "long burst length" on gen2 chips */
+ if ((ctlr->chip->cfg2 == PR_SATA2) || (ctlr->chip->cfg2 == PR_CMBO2))
+ ATA_OUTL(ctlr->r_res2, 0x44, ATA_INL(ctlr->r_res2, 0x44) | 0x2000);
+
+ ctlr->allocate = ata_promise_mio_allocate;
+ ctlr->reset = ata_promise_mio_reset;
+ ctlr->dmainit = ata_promise_mio_dmainit;
+ ctlr->setmode = ata_promise_mio_setmode;
+
+ return 0;
+ }
+
+failnfree:
+ if (ctlr->r_res2)
+ bus_release_resource(dev, ctlr->r_type2, ctlr->r_rid2, ctlr->r_res2);
+ if (ctlr->r_res1)
+ bus_release_resource(dev, ctlr->r_type1, ctlr->r_rid1, ctlr->r_res1);
+ return ENXIO;
+}
+
+static int
+ata_promise_allocate(device_t dev)
+{
+ struct ata_channel *ch = device_get_softc(dev);
+
+ if (ata_pci_allocate(dev))
+ return ENXIO;
+
+ ch->hw.status = ata_promise_status;
+ return 0;
+}
+
+static int
+ata_promise_status(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+
+ if (ATA_INL(ctlr->r_res1, 0x1c) & (ch->unit ? 0x00004000 : 0x00000400)) {
+ return ata_pci_status(dev);
+ }
+ return 0;
+}
+
+static int
+ata_promise_dmastart(struct ata_request *request)
+{
+ struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev));
+ struct ata_channel *ch = device_get_softc(request->parent);
+ struct ata_device *atadev = device_get_softc(request->dev);
+
+ if (atadev->flags & ATA_D_48BIT_ACTIVE) {
+ ATA_OUTB(ctlr->r_res1, 0x11,
+ ATA_INB(ctlr->r_res1, 0x11) | (ch->unit ? 0x08 : 0x02));
+ ATA_OUTL(ctlr->r_res1, ch->unit ? 0x24 : 0x20,
+ ((request->flags & ATA_R_READ) ? 0x05000000 : 0x06000000) |
+ (request->bytecount >> 1));
+ }
+ ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, (ATA_IDX_INB(ch, ATA_BMSTAT_PORT) |
+ (ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR)));
+ ATA_IDX_OUTL(ch, ATA_BMDTP_PORT, request->dma->sg_bus);
+ ATA_IDX_OUTB(ch, ATA_BMCMD_PORT,
+ ((request->flags & ATA_R_READ) ? ATA_BMCMD_WRITE_READ : 0) |
+ ATA_BMCMD_START_STOP);
+ ch->dma.flags |= ATA_DMA_ACTIVE;
+ return 0;
+}
+
+static int
+ata_promise_dmastop(struct ata_request *request)
+{
+ struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev));
+ struct ata_channel *ch = device_get_softc(request->parent);
+ struct ata_device *atadev = device_get_softc(request->dev);
+ int error;
+
+ if (atadev->flags & ATA_D_48BIT_ACTIVE) {
+ ATA_OUTB(ctlr->r_res1, 0x11,
+ ATA_INB(ctlr->r_res1, 0x11) & ~(ch->unit ? 0x08 : 0x02));
+ ATA_OUTL(ctlr->r_res1, ch->unit ? 0x24 : 0x20, 0);
+ }
+ error = ATA_IDX_INB(ch, ATA_BMSTAT_PORT);
+ ATA_IDX_OUTB(ch, ATA_BMCMD_PORT,
+ ATA_IDX_INB(ch, ATA_BMCMD_PORT) & ~ATA_BMCMD_START_STOP);
+ ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR);
+ ch->dma.flags &= ~ATA_DMA_ACTIVE;
+ return error;
+}
+
+static void
+ata_promise_dmareset(device_t dev)
+{
+ struct ata_channel *ch = device_get_softc(dev);
+
+ ATA_IDX_OUTB(ch, ATA_BMCMD_PORT,
+ ATA_IDX_INB(ch, ATA_BMCMD_PORT) & ~ATA_BMCMD_START_STOP);
+ ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR);
+ ch->flags &= ~ATA_DMA_ACTIVE;
+}
+
+static void
+ata_promise_dmainit(device_t dev)
+{
+ struct ata_channel *ch = device_get_softc(dev);
+
+ ata_dmainit(dev);
+ ch->dma.start = ata_promise_dmastart;
+ ch->dma.stop = ata_promise_dmastop;
+ ch->dma.reset = ata_promise_dmareset;
+}
+
+static void
+ata_promise_setmode(device_t dev, int mode)
+{
+ device_t gparent = GRANDPARENT(dev);
+ struct ata_pci_controller *ctlr = device_get_softc(gparent);
+ struct ata_channel *ch = device_get_softc(device_get_parent(dev));
+ struct ata_device *atadev = device_get_softc(dev);
+ int devno = (ch->unit << 1) + atadev->unit;
+ int error;
+ u_int32_t timings[][2] = {
+ /* PR_OLD PR_NEW mode */
+ { 0x004ff329, 0x004fff2f }, /* PIO 0 */
+ { 0x004fec25, 0x004ff82a }, /* PIO 1 */
+ { 0x004fe823, 0x004ff026 }, /* PIO 2 */
+ { 0x004fe622, 0x004fec24 }, /* PIO 3 */
+ { 0x004fe421, 0x004fe822 }, /* PIO 4 */
+ { 0x004567f3, 0x004acef6 }, /* MWDMA 0 */
+ { 0x004467f3, 0x0048cef6 }, /* MWDMA 1 */
+ { 0x004367f3, 0x0046cef6 }, /* MWDMA 2 */
+ { 0x004367f3, 0x0046cef6 }, /* UDMA 0 */
+ { 0x004247f3, 0x00448ef6 }, /* UDMA 1 */
+ { 0x004127f3, 0x00436ef6 }, /* UDMA 2 */
+ { 0, 0x00424ef6 }, /* UDMA 3 */
+ { 0, 0x004127f3 }, /* UDMA 4 */
+ { 0, 0x004127f3 } /* UDMA 5 */
+ };
+
+ mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma);
+
+ switch (ctlr->chip->cfg1) {
+ case PR_OLD:
+ case PR_NEW:
+ if (mode > ATA_UDMA2 && (pci_read_config(gparent, 0x50, 2) &
+ (ch->unit ? 1 << 11 : 1 << 10))) {
+ ata_print_cable(dev, "controller");
+ mode = ATA_UDMA2;
+ }
+ if (ata_atapi(dev) && mode > ATA_PIO_MAX)
+ mode = ata_limit_mode(dev, mode, ATA_PIO_MAX);
+ break;
+
+ case PR_TX:
+ ATA_IDX_OUTB(ch, ATA_BMDEVSPEC_0, 0x0b);
+ if (mode > ATA_UDMA2 &&
+ ATA_IDX_INB(ch, ATA_BMDEVSPEC_1) & 0x04) {
+ ata_print_cable(dev, "controller");
+ mode = ATA_UDMA2;
+ }
+ break;
+
+ case PR_MIO:
+ if (mode > ATA_UDMA2 &&
+ (ATA_INL(ctlr->r_res2,
+ (ctlr->chip->cfg2 & PR_SX4X ? 0x000c0260 : 0x0260) +
+ (ch->unit << 7)) & 0x01000000)) {
+ ata_print_cable(dev, "controller");
+ mode = ATA_UDMA2;
+ }
+ break;
+ }
+
+ error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
+
+ if (bootverbose)
+ device_printf(dev, "%ssetting %s on %s chip\n",
+ (error) ? "FAILURE " : "",
+ ata_mode2str(mode), ctlr->chip->text);
+ if (!error) {
+ if (ctlr->chip->cfg1 < PR_TX)
+ pci_write_config(gparent, 0x60 + (devno << 2),
+ timings[ata_mode2idx(mode)][ctlr->chip->cfg1], 4);
+ atadev->mode = mode;
+ }
+ return;
+}
+
+static int
+ata_promise_tx2_allocate(device_t dev)
+{
+ struct ata_channel *ch = device_get_softc(dev);
+
+ if (ata_pci_allocate(dev))
+ return ENXIO;
+
+ ch->hw.status = ata_promise_tx2_status;
+ return 0;
+}
+
+static int
+ata_promise_tx2_status(device_t dev)
+{
+ struct ata_channel *ch = device_get_softc(dev);
+
+ ATA_IDX_OUTB(ch, ATA_BMDEVSPEC_0, 0x0b);
+ if (ATA_IDX_INB(ch, ATA_BMDEVSPEC_1) & 0x20) {
+ return ata_pci_status(dev);
+ }
+ return 0;
+}
+
+static int
+ata_promise_mio_allocate(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ int offset = (ctlr->chip->cfg2 & PR_SX4X) ? 0x000c0000 : 0;
+ int i;
+
+ for (i = ATA_DATA; i <= ATA_COMMAND; i++) {
+ ch->r_io[i].res = ctlr->r_res2;
+ ch->r_io[i].offset = offset + 0x0200 + (i << 2) + (ch->unit << 7);
+ }
+ ch->r_io[ATA_CONTROL].res = ctlr->r_res2;
+ ch->r_io[ATA_CONTROL].offset = offset + 0x0238 + (ch->unit << 7);
+ ch->r_io[ATA_IDX_ADDR].res = ctlr->r_res2;
+ ata_default_registers(dev);
+ if ((ctlr->chip->cfg2 & (PR_SATA | PR_SATA2)) ||
+ ((ctlr->chip->cfg2 & (PR_CMBO | PR_CMBO2)) && ch->unit < 2)) {
+ ch->r_io[ATA_SSTATUS].res = ctlr->r_res2;
+ ch->r_io[ATA_SSTATUS].offset = 0x400 + (ch->unit << 8);
+ ch->r_io[ATA_SERROR].res = ctlr->r_res2;
+ ch->r_io[ATA_SERROR].offset = 0x404 + (ch->unit << 8);
+ ch->r_io[ATA_SCONTROL].res = ctlr->r_res2;
+ ch->r_io[ATA_SCONTROL].offset = 0x408 + (ch->unit << 8);
+ ch->flags |= ATA_NO_SLAVE;
+ }
+ ch->flags |= ATA_USE_16BIT;
+
+ ata_generic_hw(dev);
+ if (ctlr->chip->cfg2 & PR_SX4X) {
+ ch->hw.command = ata_promise_sx4_command;
+ }
+ else {
+ ch->hw.command = ata_promise_mio_command;
+ ch->hw.status = ata_promise_mio_status;
+ ch->hw.softreset = ata_promise_mio_softreset;
+ ch->hw.pm_read = ata_promise_mio_pm_read;
+ ch->hw.pm_write = ata_promise_mio_pm_write;
+ }
+ return 0;
+}
+
+static void
+ata_promise_mio_intr(void *data)
+{
+ struct ata_pci_controller *ctlr = data;
+ struct ata_channel *ch;
+ u_int32_t vector;
+ int unit, fake_reg;
+
+ switch (ctlr->chip->cfg2) {
+ case PR_PATA:
+ case PR_CMBO:
+ case PR_SATA:
+ fake_reg = 0x60;
+ break;
+ case PR_CMBO2:
+ case PR_SATA2:
+ default:
+ fake_reg = 0x54;
+ break;
+ }
+
+ /*
+ * since reading interrupt status register on early "mio" chips
+ * clears the status bits we cannot read it for each channel later on
+ * in the generic interrupt routine.
+ * store the bits in an unused register in the chip so we can read
+ * it from there safely to get around this "feature".
+ */
+ vector = ATA_INL(ctlr->r_res2, 0x040);
+ ATA_OUTL(ctlr->r_res2, 0x040, vector);
+ ATA_OUTL(ctlr->r_res2, fake_reg, vector);
+
+ for (unit = 0; unit < ctlr->channels; unit++) {
+ if ((ch = ctlr->interrupt[unit].argument))
+ ctlr->interrupt[unit].function(ch);
+ }
+
+ ATA_OUTL(ctlr->r_res2, fake_reg, 0xffffffff);
+}
+
+static int
+ata_promise_mio_status(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ struct ata_connect_task *tp;
+ u_int32_t fake_reg, stat_reg, vector, status;
+
+ switch (ctlr->chip->cfg2) {
+ case PR_PATA:
+ case PR_CMBO:
+ case PR_SATA:
+ fake_reg = 0x60;
+ stat_reg = 0x6c;
+ break;
+ case PR_CMBO2:
+ case PR_SATA2:
+ default:
+ fake_reg = 0x54;
+ stat_reg = 0x60;
+ break;
+ }
+
+ /* read and acknowledge interrupt */
+ vector = ATA_INL(ctlr->r_res2, fake_reg);
+
+ /* read and clear interface status */
+ status = ATA_INL(ctlr->r_res2, stat_reg);
+ ATA_OUTL(ctlr->r_res2, stat_reg, status & (0x00000011 << ch->unit));
+
+ /* check for and handle disconnect events */
+ if ((status & (0x00000001 << ch->unit)) &&
+ (tp = (struct ata_connect_task *)
+ malloc(sizeof(struct ata_connect_task),
+ M_ATA, M_NOWAIT | M_ZERO))) {
+
+ if (bootverbose)
+ device_printf(dev, "DISCONNECT requested\n");
+ tp->action = ATA_C_DETACH;
+ tp->dev = dev;
+ TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp);
+ taskqueue_enqueue(taskqueue_thread, &tp->task);
+ }
+
+ /* check for and handle connect events */
+ if ((status & (0x00000010 << ch->unit)) &&
+ (tp = (struct ata_connect_task *)
+ malloc(sizeof(struct ata_connect_task),
+ M_ATA, M_NOWAIT | M_ZERO))) {
+
+ if (bootverbose)
+ device_printf(dev, "CONNECT requested\n");
+ tp->action = ATA_C_ATTACH;
+ tp->dev = dev;
+ TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp);
+ taskqueue_enqueue(taskqueue_thread, &tp->task);
+ }
+
+ /* do we have any device action ? */
+ return (vector & (1 << (ch->unit + 1)));
+}
+
+static int
+ata_promise_mio_command(struct ata_request *request)
+{
+ struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev));
+ struct ata_channel *ch = device_get_softc(request->parent);
+ struct ata_device *atadev = device_get_softc(request->dev);
+
+ u_int32_t *wordp = (u_int32_t *)ch->dma.work;
+
+ ATA_OUTL(ctlr->r_res2, (ch->unit + 1) << 2, 0x00000001);
+
+ /* set portmultiplier port */
+ ATA_OUTB(ctlr->r_res2, 0x4e8 + (ch->unit << 8), atadev->unit & 0x0f);
+
+ /* XXX SOS add ATAPI commands support later */
+ switch (request->u.ata.command) {
+ default:
+ return ata_generic_command(request);
+
+ case ATA_READ_DMA:
+ case ATA_READ_DMA48:
+ wordp[0] = htole32(0x04 | ((ch->unit + 1) << 16) | (0x00 << 24));
+ break;
+
+ case ATA_WRITE_DMA:
+ case ATA_WRITE_DMA48:
+ wordp[0] = htole32(0x00 | ((ch->unit + 1) << 16) | (0x00 << 24));
+ break;
+ }
+ wordp[1] = htole32(request->dma->sg_bus);
+ wordp[2] = 0;
+ ata_promise_apkt((u_int8_t*)wordp, request);
+
+ ATA_OUTL(ctlr->r_res2, 0x0240 + (ch->unit << 7), ch->dma.work_bus);
+ return 0;
+}
+
+static void
+ata_promise_mio_reset(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ struct ata_promise_sx4 *hpktp;
+
+ switch (ctlr->chip->cfg2) {
+ case PR_SX4X:
+
+ /* softreset channel ATA module */
+ hpktp = device_get_ivars(ctlr->dev);
+ ATA_OUTL(ctlr->r_res2, 0xc0260 + (ch->unit << 7), ch->unit + 1);
+ ata_udelay(1000);
+ ATA_OUTL(ctlr->r_res2, 0xc0260 + (ch->unit << 7),
+ (ATA_INL(ctlr->r_res2, 0xc0260 + (ch->unit << 7)) &
+ ~0x00003f9f) | (ch->unit + 1));
+
+ /* softreset HOST module */ /* XXX SOS what about other outstandings */
+ mtx_lock(&hpktp->mtx);
+ ATA_OUTL(ctlr->r_res2, 0xc012c,
+ (ATA_INL(ctlr->r_res2, 0xc012c) & ~0x00000f9f) | (1 << 11));
+ DELAY(10);
+ ATA_OUTL(ctlr->r_res2, 0xc012c,
+ (ATA_INL(ctlr->r_res2, 0xc012c) & ~0x00000f9f));
+ hpktp->busy = 0;
+ mtx_unlock(&hpktp->mtx);
+ ata_generic_reset(dev);
+ break;
+
+ case PR_PATA:
+ case PR_CMBO:
+ case PR_SATA:
+ if ((ctlr->chip->cfg2 == PR_SATA) ||
+ ((ctlr->chip->cfg2 == PR_CMBO) && (ch->unit < 2))) {
+
+ /* mask plug/unplug intr */
+ ATA_OUTL(ctlr->r_res2, 0x06c, (0x00110000 << ch->unit));
+ }
+
+ /* softreset channels ATA module */
+ ATA_OUTL(ctlr->r_res2, 0x0260 + (ch->unit << 7), (1 << 11));
+ ata_udelay(10000);
+ ATA_OUTL(ctlr->r_res2, 0x0260 + (ch->unit << 7),
+ (ATA_INL(ctlr->r_res2, 0x0260 + (ch->unit << 7)) &
+ ~0x00003f9f) | (ch->unit + 1));
+
+ if ((ctlr->chip->cfg2 == PR_SATA) ||
+ ((ctlr->chip->cfg2 == PR_CMBO) && (ch->unit < 2))) {
+
+ if (ata_sata_phy_reset(dev))
+ ata_generic_reset(dev);
+
+ /* reset and enable plug/unplug intr */
+ ATA_OUTL(ctlr->r_res2, 0x06c, (0x00000011 << ch->unit));
+ }
+ else
+ ata_generic_reset(dev);
+ break;
+
+ case PR_CMBO2:
+ case PR_SATA2:
+ if ((ctlr->chip->cfg2 == PR_SATA2) ||
+ ((ctlr->chip->cfg2 == PR_CMBO2) && (ch->unit < 2))) {
+ /* set portmultiplier port */
+ //ATA_OUTL(ctlr->r_res2, 0x4e8 + (ch->unit << 8), 0x0f);
+
+ /* mask plug/unplug intr */
+ ATA_OUTL(ctlr->r_res2, 0x060, (0x00110000 << ch->unit));
+ }
+
+ /* softreset channels ATA module */
+ ATA_OUTL(ctlr->r_res2, 0x0260 + (ch->unit << 7), (1 << 11));
+ ata_udelay(10000);
+ ATA_OUTL(ctlr->r_res2, 0x0260 + (ch->unit << 7),
+ (ATA_INL(ctlr->r_res2, 0x0260 + (ch->unit << 7)) &
+ ~0x00003f9f) | (ch->unit + 1));
+
+ if ((ctlr->chip->cfg2 == PR_SATA2) ||
+ ((ctlr->chip->cfg2 == PR_CMBO2) && (ch->unit < 2))) {
+
+ /* set PHY mode to "improved" */
+ ATA_OUTL(ctlr->r_res2, 0x414 + (ch->unit << 8),
+ (ATA_INL(ctlr->r_res2, 0x414 + (ch->unit << 8)) &
+ ~0x00000003) | 0x00000001);
+
+ if (ata_sata_phy_reset(dev)) {
+ u_int32_t signature = ch->hw.softreset(dev, ATA_PM);
+
+ if (1 | bootverbose)
+ device_printf(dev, "SIGNATURE: %08x\n", signature);
+
+ switch (signature) {
+ case 0x00000101:
+ ch->devices = ATA_ATA_MASTER;
+ break;
+ case 0x96690101:
+ ch->devices = ATA_PORTMULTIPLIER;
+ ata_pm_identify(dev);
+ break;
+ case 0xeb140101:
+ ch->devices = ATA_ATAPI_MASTER;
+ break;
+ default: /* SOS XXX */
+ if (bootverbose)
+ device_printf(dev,
+ "No signature, asuming disk device\n");
+ ch->devices = ATA_ATA_MASTER;
+ }
+ if (bootverbose)
+ device_printf(dev, "promise_mio_reset devices=%08x\n",
+ ch->devices);
+
+ }
+
+ /* reset and enable plug/unplug intr */
+ ATA_OUTL(ctlr->r_res2, 0x060, (0x00000011 << ch->unit));
+
+ ///* set portmultiplier port */
+ ATA_OUTL(ctlr->r_res2, 0x4e8 + (ch->unit << 8), 0x00);
+ }
+ else
+ ata_generic_reset(dev);
+ break;
+
+ }
+}
+
+static int
+ata_promise_mio_pm_read(device_t dev, int port, int reg, u_int32_t *result)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ int timeout = 0;
+
+ /* set portmultiplier port */
+ ATA_OUTB(ctlr->r_res2, 0x4e8 + (ch->unit << 8), 0x0f);
+
+ ATA_IDX_OUTB(ch, ATA_FEATURE, reg);
+ ATA_IDX_OUTB(ch, ATA_DRIVE, port);
+
+ ATA_IDX_OUTB(ch, ATA_COMMAND, ATA_READ_PM);
+
+ while (timeout < 1000000) {
+ u_int8_t status = ATA_IDX_INB(ch, ATA_STATUS);
+ if (!(status & ATA_S_BUSY))
+ break;
+ timeout += 1000;
+ DELAY(1000);
+ }
+ if (timeout >= 1000000)
+ return ATA_E_ABORT;
+
+ *result = ATA_IDX_INB(ch, ATA_COUNT) |
+ (ATA_IDX_INB(ch, ATA_SECTOR) << 8) |
+ (ATA_IDX_INB(ch, ATA_CYL_LSB) << 16) |
+ (ATA_IDX_INB(ch, ATA_CYL_MSB) << 24);
+ return 0;
+}
+
+static int
+ata_promise_mio_pm_write(device_t dev, int port, int reg, u_int32_t value)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ int timeout = 0;
+
+ /* set portmultiplier port */
+ ATA_OUTB(ctlr->r_res2, 0x4e8 + (ch->unit << 8), 0x0f);
+
+ ATA_IDX_OUTB(ch, ATA_FEATURE, reg);
+ ATA_IDX_OUTB(ch, ATA_DRIVE, port);
+ ATA_IDX_OUTB(ch, ATA_COUNT, value & 0xff);
+ ATA_IDX_OUTB(ch, ATA_SECTOR, (value >> 8) & 0xff);
+ ATA_IDX_OUTB(ch, ATA_CYL_LSB, (value >> 16) & 0xff);
+ ATA_IDX_OUTB(ch, ATA_CYL_MSB, (value >> 24) & 0xff);
+
+ ATA_IDX_OUTB(ch, ATA_COMMAND, ATA_WRITE_PM);
+
+ while (timeout < 1000000) {
+ u_int8_t status = ATA_IDX_INB(ch, ATA_STATUS);
+ if (!(status & ATA_S_BUSY))
+ break;
+ timeout += 1000;
+ DELAY(1000);
+ }
+ if (timeout >= 1000000)
+ return ATA_E_ABORT;
+
+ return ATA_IDX_INB(ch, ATA_ERROR);
+}
+
+/* must be called with ATA channel locked and state_mtx held */
+static u_int32_t
+ata_promise_mio_softreset(device_t dev, int port)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ int timeout;
+
+ /* set portmultiplier port */
+ ATA_OUTB(ctlr->r_res2, 0x4e8 + (ch->unit << 8), port & 0x0f);
+
+ /* softreset device on this channel */
+ ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_DEV(ATA_MASTER));
+ DELAY(10);
+ ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_IDS | ATA_A_RESET);
+ ata_udelay(10000);
+ ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_IDS);
+ ata_udelay(150000);
+ ATA_IDX_INB(ch, ATA_ERROR);
+
+ /* wait for BUSY to go inactive */
+ for (timeout = 0; timeout < 100; timeout++) {
+ u_int8_t err, stat;
+
+ err = ATA_IDX_INB(ch, ATA_ERROR);
+ stat = ATA_IDX_INB(ch, ATA_STATUS);
+
+ //if (stat == err && timeout > (stat & ATA_S_BUSY ? 100 : 10))
+ //break;
+
+ if (!(stat & ATA_S_BUSY)) {
+ //if ((err & 0x7f) == ATA_E_ILI) {
+ return ATA_IDX_INB(ch, ATA_COUNT) |
+ (ATA_IDX_INB(ch, ATA_SECTOR) << 8) |
+ (ATA_IDX_INB(ch, ATA_CYL_LSB) << 16) |
+ (ATA_IDX_INB(ch, ATA_CYL_MSB) << 24);
+ //}
+ //else if (stat & 0x0f) {
+ //stat |= ATA_S_BUSY;
+ //}
+ }
+
+ if (!(stat & ATA_S_BUSY) || (stat == 0xff && timeout > 10))
+ break;
+ ata_udelay(100000);
+ }
+ return -1;
+}
+
+static void
+ata_promise_mio_dmainit(device_t dev)
+{
+ struct ata_channel *ch = device_get_softc(dev);
+
+ ata_dmainit(dev);
+ /* note start and stop are not used here */
+ ch->dma.setprd = ata_promise_mio_setprd;
+}
+
+
+#define MAXLASTSGSIZE (32 * sizeof(u_int32_t))
+static void
+ata_promise_mio_setprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error)
+{
+ struct ata_dmasetprd_args *args = xsc;
+ struct ata_dma_prdentry *prd = args->dmatab;
+ int i;
+
+ if ((args->error = error))
+ return;
+
+ for (i = 0; i < nsegs; i++) {
+ prd[i].addr = htole32(segs[i].ds_addr);
+ prd[i].count = htole32(segs[i].ds_len);
+ }
+ if (segs[i - 1].ds_len > MAXLASTSGSIZE) {
+ //printf("split last SG element of %u\n", segs[i - 1].ds_len);
+ prd[i - 1].count = htole32(segs[i - 1].ds_len - MAXLASTSGSIZE);
+ prd[i].count = htole32(MAXLASTSGSIZE);
+ prd[i].addr = htole32(segs[i - 1].ds_addr +
+ (segs[i - 1].ds_len - MAXLASTSGSIZE));
+ nsegs++;
+ i++;
+ }
+ prd[i - 1].count |= htole32(ATA_DMA_EOT);
+ KASSERT(nsegs <= ATA_DMA_ENTRIES, ("too many DMA segment entries\n"));
+ args->nsegs = nsegs;
+}
+
+static void
+ata_promise_mio_setmode(device_t dev, int mode)
+{
+ device_t gparent = GRANDPARENT(dev);
+ struct ata_pci_controller *ctlr = device_get_softc(gparent);
+ struct ata_channel *ch = device_get_softc(device_get_parent(dev));
+
+ if ( (ctlr->chip->cfg2 == PR_SATA) ||
+ ((ctlr->chip->cfg2 == PR_CMBO) && (ch->unit < 2)) ||
+ (ctlr->chip->cfg2 == PR_SATA2) ||
+ ((ctlr->chip->cfg2 == PR_CMBO2) && (ch->unit < 2)))
+ ata_sata_setmode(dev, mode);
+ else
+ ata_promise_setmode(dev, mode);
+}
+
+static void
+ata_promise_sx4_intr(void *data)
+{
+ struct ata_pci_controller *ctlr = data;
+ struct ata_channel *ch;
+ u_int32_t vector = ATA_INL(ctlr->r_res2, 0x000c0480);
+ int unit;
+
+ for (unit = 0; unit < ctlr->channels; unit++) {
+ if (vector & (1 << (unit + 1)))
+ if ((ch = ctlr->interrupt[unit].argument))
+ ctlr->interrupt[unit].function(ch);
+ if (vector & (1 << (unit + 5)))
+ if ((ch = ctlr->interrupt[unit].argument))
+ ata_promise_queue_hpkt(ctlr,
+ htole32((ch->unit * ATA_PDC_CHN_OFFSET) +
+ ATA_PDC_HPKT_OFFSET));
+ if (vector & (1 << (unit + 9))) {
+ ata_promise_next_hpkt(ctlr);
+ if ((ch = ctlr->interrupt[unit].argument))
+ ctlr->interrupt[unit].function(ch);
+ }
+ if (vector & (1 << (unit + 13))) {
+ ata_promise_next_hpkt(ctlr);
+ if ((ch = ctlr->interrupt[unit].argument))
+ ATA_OUTL(ctlr->r_res2, 0x000c0240 + (ch->unit << 7),
+ htole32((ch->unit * ATA_PDC_CHN_OFFSET) +
+ ATA_PDC_APKT_OFFSET));
+ }
+ }
+}
+
+static int
+ata_promise_sx4_command(struct ata_request *request)
+{
+ device_t gparent = GRANDPARENT(request->dev);
+ struct ata_pci_controller *ctlr = device_get_softc(gparent);
+ struct ata_channel *ch = device_get_softc(request->parent);
+ struct ata_dma_prdentry *prd = request->dma->sg;
+ caddr_t window = rman_get_virtual(ctlr->r_res1);
+ u_int32_t *wordp;
+ int i, idx, length = 0;
+
+ /* XXX SOS add ATAPI commands support later */
+ switch (request->u.ata.command) {
+
+ default:
+ return -1;
+
+ case ATA_ATA_IDENTIFY:
+ case ATA_READ:
+ case ATA_READ48:
+ case ATA_READ_MUL:
+ case ATA_READ_MUL48:
+ case ATA_WRITE:
+ case ATA_WRITE48:
+ case ATA_WRITE_MUL:
+ case ATA_WRITE_MUL48:
+ ATA_OUTL(ctlr->r_res2, 0x000c0400 + ((ch->unit + 1) << 2), 0x00000001);
+ return ata_generic_command(request);
+
+ case ATA_SETFEATURES:
+ case ATA_FLUSHCACHE:
+ case ATA_FLUSHCACHE48:
+ case ATA_SLEEP:
+ case ATA_SET_MULTI:
+ wordp = (u_int32_t *)
+ (window + (ch->unit * ATA_PDC_CHN_OFFSET) + ATA_PDC_APKT_OFFSET);
+ wordp[0] = htole32(0x08 | ((ch->unit + 1)<<16) | (0x00 << 24));
+ wordp[1] = 0;
+ wordp[2] = 0;
+ ata_promise_apkt((u_int8_t *)wordp, request);
+ ATA_OUTL(ctlr->r_res2, 0x000c0484, 0x00000001);
+ ATA_OUTL(ctlr->r_res2, 0x000c0400 + ((ch->unit + 1) << 2), 0x00000001);
+ ATA_OUTL(ctlr->r_res2, 0x000c0240 + (ch->unit << 7),
+ htole32((ch->unit * ATA_PDC_CHN_OFFSET)+ATA_PDC_APKT_OFFSET));
+ return 0;
+
+ case ATA_READ_DMA:
+ case ATA_READ_DMA48:
+ case ATA_WRITE_DMA:
+ case ATA_WRITE_DMA48:
+ wordp = (u_int32_t *)
+ (window + (ch->unit * ATA_PDC_CHN_OFFSET) + ATA_PDC_HSG_OFFSET);
+ i = idx = 0;
+ do {
+ wordp[idx++] = prd[i].addr;
+ wordp[idx++] = prd[i].count;
+ length += (prd[i].count & ~ATA_DMA_EOT);
+ } while (!(prd[i++].count & ATA_DMA_EOT));
+
+ wordp = (u_int32_t *)
+ (window + (ch->unit * ATA_PDC_CHN_OFFSET) + ATA_PDC_LSG_OFFSET);
+ wordp[0] = htole32((ch->unit * ATA_PDC_BUF_OFFSET) + ATA_PDC_BUF_BASE);
+ wordp[1] = htole32(request->bytecount | ATA_DMA_EOT);
+
+ wordp = (u_int32_t *)
+ (window + (ch->unit * ATA_PDC_CHN_OFFSET) + ATA_PDC_ASG_OFFSET);
+ wordp[0] = htole32((ch->unit * ATA_PDC_BUF_OFFSET) + ATA_PDC_BUF_BASE);
+ wordp[1] = htole32(request->bytecount | ATA_DMA_EOT);
+
+ wordp = (u_int32_t *)
+ (window + (ch->unit * ATA_PDC_CHN_OFFSET) + ATA_PDC_HPKT_OFFSET);
+ if (request->flags & ATA_R_READ)
+ wordp[0] = htole32(0x14 | ((ch->unit+9)<<16) | ((ch->unit+5)<<24));
+ if (request->flags & ATA_R_WRITE)
+ wordp[0] = htole32(0x00 | ((ch->unit+13)<<16) | (0x00<<24));
+ wordp[1] = htole32((ch->unit * ATA_PDC_CHN_OFFSET)+ATA_PDC_HSG_OFFSET);
+ wordp[2] = htole32((ch->unit * ATA_PDC_CHN_OFFSET)+ATA_PDC_LSG_OFFSET);
+ wordp[3] = 0;
+
+ wordp = (u_int32_t *)
+ (window + (ch->unit * ATA_PDC_CHN_OFFSET) + ATA_PDC_APKT_OFFSET);
+ if (request->flags & ATA_R_READ)
+ wordp[0] = htole32(0x04 | ((ch->unit+5)<<16) | (0x00<<24));
+ if (request->flags & ATA_R_WRITE)
+ wordp[0] = htole32(0x10 | ((ch->unit+1)<<16) | ((ch->unit+13)<<24));
+ wordp[1] = htole32((ch->unit * ATA_PDC_CHN_OFFSET)+ATA_PDC_ASG_OFFSET);
+ wordp[2] = 0;
+ ata_promise_apkt((u_int8_t *)wordp, request);
+ ATA_OUTL(ctlr->r_res2, 0x000c0484, 0x00000001);
+
+ if (request->flags & ATA_R_READ) {
+ ATA_OUTL(ctlr->r_res2, 0x000c0400 + ((ch->unit+5)<<2), 0x00000001);
+ ATA_OUTL(ctlr->r_res2, 0x000c0400 + ((ch->unit+9)<<2), 0x00000001);
+ ATA_OUTL(ctlr->r_res2, 0x000c0240 + (ch->unit << 7),
+ htole32((ch->unit * ATA_PDC_CHN_OFFSET) + ATA_PDC_APKT_OFFSET));
+ }
+ if (request->flags & ATA_R_WRITE) {
+ ATA_OUTL(ctlr->r_res2, 0x000c0400 + ((ch->unit+1)<<2), 0x00000001);
+ ATA_OUTL(ctlr->r_res2, 0x000c0400 + ((ch->unit+13)<<2), 0x00000001);
+ ata_promise_queue_hpkt(ctlr,
+ htole32((ch->unit * ATA_PDC_CHN_OFFSET) + ATA_PDC_HPKT_OFFSET));
+ }
+ return 0;
+ }
+}
+
+static int
+ata_promise_apkt(u_int8_t *bytep, struct ata_request *request)
+{
+ struct ata_device *atadev = device_get_softc(request->dev);
+ int i = 12;
+
+ bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_REG | ATA_PDC_WAIT_NBUSY|ATA_DRIVE;
+ bytep[i++] = ATA_D_IBM | ATA_D_LBA | ATA_DEV(atadev->unit);
+ bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_CTL;
+ bytep[i++] = ATA_A_4BIT;
+
+ if (atadev->flags & ATA_D_48BIT_ACTIVE) {
+ bytep[i++] = ATA_PDC_2B | ATA_PDC_WRITE_REG | ATA_FEATURE;
+ bytep[i++] = request->u.ata.feature >> 8;
+ bytep[i++] = request->u.ata.feature;
+ bytep[i++] = ATA_PDC_2B | ATA_PDC_WRITE_REG | ATA_COUNT;
+ bytep[i++] = request->u.ata.count >> 8;
+ bytep[i++] = request->u.ata.count;
+ bytep[i++] = ATA_PDC_2B | ATA_PDC_WRITE_REG | ATA_SECTOR;
+ bytep[i++] = request->u.ata.lba >> 24;
+ bytep[i++] = request->u.ata.lba;
+ bytep[i++] = ATA_PDC_2B | ATA_PDC_WRITE_REG | ATA_CYL_LSB;
+ bytep[i++] = request->u.ata.lba >> 32;
+ bytep[i++] = request->u.ata.lba >> 8;
+ bytep[i++] = ATA_PDC_2B | ATA_PDC_WRITE_REG | ATA_CYL_MSB;
+ bytep[i++] = request->u.ata.lba >> 40;
+ bytep[i++] = request->u.ata.lba >> 16;
+ bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_REG | ATA_DRIVE;
+ bytep[i++] = ATA_D_LBA | ATA_DEV(atadev->unit);
+ }
+ else {
+ bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_REG | ATA_FEATURE;
+ bytep[i++] = request->u.ata.feature;
+ bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_REG | ATA_COUNT;
+ bytep[i++] = request->u.ata.count;
+ bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_REG | ATA_SECTOR;
+ bytep[i++] = request->u.ata.lba;
+ bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_REG | ATA_CYL_LSB;
+ bytep[i++] = request->u.ata.lba >> 8;
+ bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_REG | ATA_CYL_MSB;
+ bytep[i++] = request->u.ata.lba >> 16;
+ bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_REG | ATA_DRIVE;
+ bytep[i++] = (atadev->flags & ATA_D_USE_CHS ? 0 : ATA_D_LBA) |
+ ATA_D_IBM | ATA_DEV(atadev->unit) |
+ ((request->u.ata.lba >> 24)&0xf);
+ }
+ bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_END | ATA_COMMAND;
+ bytep[i++] = request->u.ata.command;
+ return i;
+}
+
+static void
+ata_promise_queue_hpkt(struct ata_pci_controller *ctlr, u_int32_t hpkt)
+{
+ struct ata_promise_sx4 *hpktp = device_get_ivars(ctlr->dev);
+
+ mtx_lock(&hpktp->mtx);
+ if (hpktp->busy) {
+ struct host_packet *hp =
+ malloc(sizeof(struct host_packet), M_TEMP, M_NOWAIT | M_ZERO);
+ hp->addr = hpkt;
+ TAILQ_INSERT_TAIL(&hpktp->queue, hp, chain);
+ }
+ else {
+ hpktp->busy = 1;
+ ATA_OUTL(ctlr->r_res2, 0x000c0100, hpkt);
+ }
+ mtx_unlock(&hpktp->mtx);
+}
+
+static void
+ata_promise_next_hpkt(struct ata_pci_controller *ctlr)
+{
+ struct ata_promise_sx4 *hpktp = device_get_ivars(ctlr->dev);
+ struct host_packet *hp;
+
+ mtx_lock(&hpktp->mtx);
+ if ((hp = TAILQ_FIRST(&hpktp->queue))) {
+ TAILQ_REMOVE(&hpktp->queue, hp, chain);
+ ATA_OUTL(ctlr->r_res2, 0x000c0100, hp->addr);
+ free(hp, M_TEMP);
+ }
+ else
+ hpktp->busy = 0;
+ mtx_unlock(&hpktp->mtx);
+}
+
+ATA_DECLARE_DRIVER(ata_promise);
diff --git a/sys/dev/ata/chipsets/ata-serverworks.c b/sys/dev/ata/chipsets/ata-serverworks.c
new file mode 100644
index 0000000..997bf73
--- /dev/null
+++ b/sys/dev/ata/chipsets/ata-serverworks.c
@@ -0,0 +1,332 @@
+/*-
+ * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org>
+ * 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,
+ * without modification, immediately at the beginning of the file.
+ * 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 AUTHOR ``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 AUTHOR 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>
+__FBSDID("$FreeBSD$");
+
+#include "opt_ata.h"
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/ata.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sema.h>
+#include <sys/taskqueue.h>
+#include <vm/uma.h>
+#include <machine/stdarg.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/ata/ata-all.h>
+#include <dev/ata/ata-pci.h>
+#include <ata_if.h>
+
+/* local prototypes */
+static int ata_serverworks_chipinit(device_t dev);
+static int ata_serverworks_allocate(device_t dev);
+static void ata_serverworks_tf_read(struct ata_request *request);
+static void ata_serverworks_tf_write(struct ata_request *request);
+static void ata_serverworks_setmode(device_t dev, int mode);
+
+/* misc defines */
+#define SWKS_33 0
+#define SWKS_66 1
+#define SWKS_100 2
+#define SWKS_MIO 3
+
+
+/*
+ * ServerWorks chipset support functions
+ */
+static int
+ata_serverworks_probe(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+ static struct ata_chip_id ids[] =
+ {{ ATA_ROSB4, 0x00, SWKS_33, 0, ATA_UDMA2, "ROSB4" },
+ { ATA_CSB5, 0x92, SWKS_100, 0, ATA_UDMA5, "CSB5" },
+ { ATA_CSB5, 0x00, SWKS_66, 0, ATA_UDMA4, "CSB5" },
+ { ATA_CSB6, 0x00, SWKS_100, 0, ATA_UDMA5, "CSB6" },
+ { ATA_CSB6_1, 0x00, SWKS_66, 0, ATA_UDMA4, "CSB6" },
+ { ATA_HT1000, 0x00, SWKS_100, 0, ATA_UDMA5, "HT1000" },
+ { ATA_HT1000_S1, 0x00, SWKS_100, 4, ATA_SA150, "HT1000" },
+ { ATA_HT1000_S2, 0x00, SWKS_MIO, 4, ATA_SA150, "HT1000" },
+ { ATA_K2, 0x00, SWKS_MIO, 4, ATA_SA150, "K2" },
+ { ATA_FRODO4, 0x00, SWKS_MIO, 4, ATA_SA150, "Frodo4" },
+ { ATA_FRODO8, 0x00, SWKS_MIO, 8, ATA_SA150, "Frodo8" },
+ { 0, 0, 0, 0, 0, 0}};
+
+ if (pci_get_vendor(dev) != ATA_SERVERWORKS_ID)
+ return ENXIO;
+
+ if (!(ctlr->chip = ata_match_chip(dev, ids)))
+ return ENXIO;
+
+ ata_set_desc(dev);
+ ctlr->chipinit = ata_serverworks_chipinit;
+ return 0;
+}
+
+static int
+ata_serverworks_chipinit(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+
+ if (ata_setup_interrupt(dev, ata_generic_intr))
+ return ENXIO;
+
+ if (ctlr->chip->cfg1 == SWKS_MIO) {
+ ctlr->r_type2 = SYS_RES_MEMORY;
+ ctlr->r_rid2 = PCIR_BAR(5);
+ if (!(ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2,
+ &ctlr->r_rid2, RF_ACTIVE)))
+ return ENXIO;
+
+ ctlr->channels = ctlr->chip->cfg2;
+ ctlr->allocate = ata_serverworks_allocate;
+ ctlr->setmode = ata_sata_setmode;
+ return 0;
+ }
+ else if (ctlr->chip->cfg1 == SWKS_33) {
+ device_t *children;
+ int nchildren, i;
+
+ /* locate the ISA part in the southbridge and enable UDMA33 */
+ if (!device_get_children(device_get_parent(dev), &children,&nchildren)){
+ for (i = 0; i < nchildren; i++) {
+ if (pci_get_devid(children[i]) == ATA_ROSB4_ISA) {
+ pci_write_config(children[i], 0x64,
+ (pci_read_config(children[i], 0x64, 4) &
+ ~0x00002000) | 0x00004000, 4);
+ break;
+ }
+ }
+ free(children, M_TEMP);
+ }
+ }
+ else {
+ pci_write_config(dev, 0x5a,
+ (pci_read_config(dev, 0x5a, 1) & ~0x40) |
+ (ctlr->chip->cfg1 == SWKS_100) ? 0x03 : 0x02, 1);
+ }
+ ctlr->setmode = ata_serverworks_setmode;
+ return 0;
+}
+
+static int
+ata_serverworks_allocate(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ int ch_offset;
+ int i;
+
+ ch_offset = ch->unit * 0x100;
+
+ for (i = ATA_DATA; i < ATA_MAX_RES; i++)
+ ch->r_io[i].res = ctlr->r_res2;
+
+ /* setup ATA registers */
+ ch->r_io[ATA_DATA].offset = ch_offset + 0x00;
+ ch->r_io[ATA_FEATURE].offset = ch_offset + 0x04;
+ ch->r_io[ATA_COUNT].offset = ch_offset + 0x08;
+ ch->r_io[ATA_SECTOR].offset = ch_offset + 0x0c;
+ ch->r_io[ATA_CYL_LSB].offset = ch_offset + 0x10;
+ ch->r_io[ATA_CYL_MSB].offset = ch_offset + 0x14;
+ ch->r_io[ATA_DRIVE].offset = ch_offset + 0x18;
+ ch->r_io[ATA_COMMAND].offset = ch_offset + 0x1c;
+ ch->r_io[ATA_CONTROL].offset = ch_offset + 0x20;
+ ata_default_registers(dev);
+
+ /* setup DMA registers */
+ ch->r_io[ATA_BMCMD_PORT].offset = ch_offset + 0x30;
+ ch->r_io[ATA_BMSTAT_PORT].offset = ch_offset + 0x32;
+ ch->r_io[ATA_BMDTP_PORT].offset = ch_offset + 0x34;
+
+ /* setup SATA registers */
+ ch->r_io[ATA_SSTATUS].offset = ch_offset + 0x40;
+ ch->r_io[ATA_SERROR].offset = ch_offset + 0x44;
+ ch->r_io[ATA_SCONTROL].offset = ch_offset + 0x48;
+
+ ch->flags |= ATA_NO_SLAVE;
+ ata_pci_hw(dev);
+ ch->hw.tf_read = ata_serverworks_tf_read;
+ ch->hw.tf_write = ata_serverworks_tf_write;
+
+ /* chip does not reliably do 64K DMA transfers */
+ ch->dma.max_iosize = 126 * DEV_BSIZE;
+
+ return 0;
+}
+
+static void
+ata_serverworks_tf_read(struct ata_request *request)
+{
+ struct ata_channel *ch = device_get_softc(request->parent);
+ struct ata_device *atadev = device_get_softc(request->dev);
+
+ if (atadev->flags & ATA_D_48BIT_ACTIVE) {
+ u_int16_t temp;
+
+ request->u.ata.count = ATA_IDX_INW(ch, ATA_COUNT);
+ temp = ATA_IDX_INW(ch, ATA_SECTOR);
+ request->u.ata.lba = (u_int64_t)(temp & 0x00ff) |
+ ((u_int64_t)(temp & 0xff00) << 24);
+ temp = ATA_IDX_INW(ch, ATA_CYL_LSB);
+ request->u.ata.lba |= ((u_int64_t)(temp & 0x00ff) << 8) |
+ ((u_int64_t)(temp & 0xff00) << 32);
+ temp = ATA_IDX_INW(ch, ATA_CYL_MSB);
+ request->u.ata.lba |= ((u_int64_t)(temp & 0x00ff) << 16) |
+ ((u_int64_t)(temp & 0xff00) << 40);
+ }
+ else {
+ request->u.ata.count = ATA_IDX_INW(ch, ATA_COUNT) & 0x00ff;
+ request->u.ata.lba = (ATA_IDX_INW(ch, ATA_SECTOR) & 0x00ff) |
+ ((ATA_IDX_INW(ch, ATA_CYL_LSB) & 0x00ff) << 8) |
+ ((ATA_IDX_INW(ch, ATA_CYL_MSB) & 0x00ff) << 16) |
+ ((ATA_IDX_INW(ch, ATA_DRIVE) & 0xf) << 24);
+ }
+}
+
+static void
+ata_serverworks_tf_write(struct ata_request *request)
+{
+ struct ata_channel *ch = device_get_softc(request->parent);
+ struct ata_device *atadev = device_get_softc(request->dev);
+
+ if (atadev->flags & ATA_D_48BIT_ACTIVE) {
+ ATA_IDX_OUTW(ch, ATA_FEATURE, request->u.ata.feature);
+ ATA_IDX_OUTW(ch, ATA_COUNT, request->u.ata.count);
+ ATA_IDX_OUTW(ch, ATA_SECTOR, ((request->u.ata.lba >> 16) & 0xff00) |
+ (request->u.ata.lba & 0x00ff));
+ ATA_IDX_OUTW(ch, ATA_CYL_LSB, ((request->u.ata.lba >> 24) & 0xff00) |
+ ((request->u.ata.lba >> 8) & 0x00ff));
+ ATA_IDX_OUTW(ch, ATA_CYL_MSB, ((request->u.ata.lba >> 32) & 0xff00) |
+ ((request->u.ata.lba >> 16) & 0x00ff));
+ ATA_IDX_OUTW(ch, ATA_DRIVE, ATA_D_LBA | ATA_DEV(atadev->unit));
+ }
+ else {
+ ATA_IDX_OUTW(ch, ATA_FEATURE, request->u.ata.feature);
+ ATA_IDX_OUTW(ch, ATA_COUNT, request->u.ata.count);
+ if (atadev->flags & ATA_D_USE_CHS) {
+ int heads, sectors;
+
+ if (atadev->param.atavalid & ATA_FLAG_54_58) {
+ heads = atadev->param.current_heads;
+ sectors = atadev->param.current_sectors;
+ }
+ else {
+ heads = atadev->param.heads;
+ sectors = atadev->param.sectors;
+ }
+ ATA_IDX_OUTW(ch, ATA_SECTOR, (request->u.ata.lba % sectors)+1);
+ ATA_IDX_OUTW(ch, ATA_CYL_LSB,
+ (request->u.ata.lba / (sectors * heads)));
+ ATA_IDX_OUTW(ch, ATA_CYL_MSB,
+ (request->u.ata.lba / (sectors * heads)) >> 8);
+ ATA_IDX_OUTW(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(atadev->unit) |
+ (((request->u.ata.lba% (sectors * heads)) /
+ sectors) & 0xf));
+ }
+ else {
+ ATA_IDX_OUTW(ch, ATA_SECTOR, request->u.ata.lba);
+ ATA_IDX_OUTW(ch, ATA_CYL_LSB, request->u.ata.lba >> 8);
+ ATA_IDX_OUTW(ch, ATA_CYL_MSB, request->u.ata.lba >> 16);
+ ATA_IDX_OUTW(ch, ATA_DRIVE,
+ ATA_D_IBM | ATA_D_LBA | ATA_DEV(atadev->unit) |
+ ((request->u.ata.lba >> 24) & 0x0f));
+ }
+ }
+}
+
+static void
+ata_serverworks_setmode(device_t dev, int mode)
+{
+ device_t gparent = GRANDPARENT(dev);
+ struct ata_pci_controller *ctlr = device_get_softc(gparent);
+ struct ata_channel *ch = device_get_softc(device_get_parent(dev));
+ struct ata_device *atadev = device_get_softc(dev);
+ int devno = (ch->unit << 1) + atadev->unit;
+ int offset = (devno ^ 0x01) << 3;
+ int error;
+ u_int8_t piotimings[] = { 0x5d, 0x47, 0x34, 0x22, 0x20, 0x34, 0x22, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 };
+ u_int8_t dmatimings[] = { 0x77, 0x21, 0x20 };
+
+ mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma);
+
+ mode = ata_check_80pin(dev, mode);
+
+ error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
+
+ if (bootverbose)
+ device_printf(dev, "%ssetting %s on %s chip\n",
+ (error) ? "FAILURE " : "",
+ ata_mode2str(mode), ctlr->chip->text);
+ if (!error) {
+ if (mode >= ATA_UDMA0) {
+ pci_write_config(gparent, 0x56,
+ (pci_read_config(gparent, 0x56, 2) &
+ ~(0xf << (devno << 2))) |
+ ((mode & ATA_MODE_MASK) << (devno << 2)), 2);
+ pci_write_config(gparent, 0x54,
+ pci_read_config(gparent, 0x54, 1) |
+ (0x01 << devno), 1);
+ pci_write_config(gparent, 0x44,
+ (pci_read_config(gparent, 0x44, 4) &
+ ~(0xff << offset)) |
+ (dmatimings[2] << offset), 4);
+ }
+ else if (mode >= ATA_WDMA0) {
+ pci_write_config(gparent, 0x54,
+ pci_read_config(gparent, 0x54, 1) &
+ ~(0x01 << devno), 1);
+ pci_write_config(gparent, 0x44,
+ (pci_read_config(gparent, 0x44, 4) &
+ ~(0xff << offset)) |
+ (dmatimings[mode & ATA_MODE_MASK] << offset), 4);
+ }
+ else
+ pci_write_config(gparent, 0x54,
+ pci_read_config(gparent, 0x54, 1) &
+ ~(0x01 << devno), 1);
+
+ pci_write_config(gparent, 0x40,
+ (pci_read_config(gparent, 0x40, 4) &
+ ~(0xff << offset)) |
+ (piotimings[ata_mode2idx(mode)] << offset), 4);
+ atadev->mode = mode;
+ }
+}
+
+ATA_DECLARE_DRIVER(ata_serverworks);
diff --git a/sys/dev/ata/chipsets/ata-siliconimage.c b/sys/dev/ata/chipsets/ata-siliconimage.c
new file mode 100644
index 0000000..b3e8358
--- /dev/null
+++ b/sys/dev/ata/chipsets/ata-siliconimage.c
@@ -0,0 +1,890 @@
+/*-
+ * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org>
+ * 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,
+ * without modification, immediately at the beginning of the file.
+ * 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 AUTHOR ``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 AUTHOR 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>
+__FBSDID("$FreeBSD$");
+
+#include "opt_ata.h"
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/ata.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sema.h>
+#include <sys/taskqueue.h>
+#include <vm/uma.h>
+#include <machine/stdarg.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/ata/ata-all.h>
+#include <dev/ata/ata-pci.h>
+#include <ata_if.h>
+
+/* local prototypes */
+static int ata_cmd_allocate(device_t dev);
+static int ata_cmd_status(device_t dev);
+static void ata_cmd_setmode(device_t dev, int mode);
+static int ata_sii_allocate(device_t dev);
+static int ata_sii_status(device_t dev);
+static void ata_sii_reset(device_t dev);
+static void ata_sii_setmode(device_t dev, int mode);
+static int ata_siiprb_allocate(device_t dev);
+static int ata_siiprb_status(device_t dev);
+static int ata_siiprb_begin_transaction(struct ata_request *request);
+static int ata_siiprb_end_transaction(struct ata_request *request);
+static int ata_siiprb_pm_read(device_t dev, int port, int reg, u_int32_t *result);
+static int ata_siiprb_pm_write(device_t dev, int port, int reg, u_int32_t result);
+static u_int32_t ata_siiprb_softreset(device_t dev, int port);
+static void ata_siiprb_reset(device_t dev);
+static void ata_siiprb_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error);
+static void ata_siiprb_dmainit(device_t dev);
+
+/* misc defines */
+#define SII_MEMIO 1
+#define SII_PRBIO 2
+#define SII_INTR 0x01
+#define SII_SETCLK 0x02
+#define SII_BUG 0x04
+#define SII_4CH 0x08
+
+
+/*
+ * Silicon Image Inc. (SiI) (former CMD) chipset support functions
+ */
+static int
+ata_sii_probe(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+ static struct ata_chip_id ids[] =
+ {{ ATA_SII3114, 0x00, SII_MEMIO, SII_4CH, ATA_SA150, "3114" },
+ { ATA_SII3512, 0x02, SII_MEMIO, 0, ATA_SA150, "3512" },
+ { ATA_SII3112, 0x02, SII_MEMIO, 0, ATA_SA150, "3112" },
+ { ATA_SII3112_1, 0x02, SII_MEMIO, 0, ATA_SA150, "3112" },
+ { ATA_SII3512, 0x00, SII_MEMIO, SII_BUG, ATA_SA150, "3512" },
+ { ATA_SII3112, 0x00, SII_MEMIO, SII_BUG, ATA_SA150, "3112" },
+ { ATA_SII3112_1, 0x00, SII_MEMIO, SII_BUG, ATA_SA150, "3112" },
+ { ATA_SII3124, 0x00, SII_PRBIO, SII_4CH, ATA_SA300, "3124" },
+ { ATA_SII3132, 0x00, SII_PRBIO, 0, ATA_SA300, "3132" },
+ { ATA_SII3132_1, 0x00, SII_PRBIO, 0, ATA_SA300, "3132" },
+ { ATA_SII0680, 0x00, SII_MEMIO, SII_SETCLK, ATA_UDMA6, "680" },
+ { ATA_CMD649, 0x00, 0, SII_INTR, ATA_UDMA5, "(CMD) 649" },
+ { ATA_CMD648, 0x00, 0, SII_INTR, ATA_UDMA4, "(CMD) 648" },
+ { ATA_CMD646, 0x07, 0, 0, ATA_UDMA2, "(CMD) 646U2" },
+ { ATA_CMD646, 0x00, 0, 0, ATA_WDMA2, "(CMD) 646" },
+ { 0, 0, 0, 0, 0, 0}};
+
+ if (pci_get_vendor(dev) != ATA_SILICON_IMAGE_ID)
+ return ENXIO;
+
+ if (!(ctlr->chip = ata_match_chip(dev, ids)))
+ return ENXIO;
+
+ ata_set_desc(dev);
+ ctlr->chipinit = ata_sii_chipinit;
+ return 0;
+}
+
+int
+ata_sii_chipinit(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+
+ if (ata_setup_interrupt(dev, ata_generic_intr))
+ return ENXIO;
+
+ switch (ctlr->chip->cfg1) {
+ case SII_PRBIO:
+ ctlr->r_type1 = SYS_RES_MEMORY;
+ ctlr->r_rid1 = PCIR_BAR(0);
+ if (!(ctlr->r_res1 = bus_alloc_resource_any(dev, ctlr->r_type1,
+ &ctlr->r_rid1, RF_ACTIVE)))
+ return ENXIO;
+
+ ctlr->r_rid2 = PCIR_BAR(2);
+ ctlr->r_type2 = SYS_RES_MEMORY;
+ if (!(ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2,
+ &ctlr->r_rid2, RF_ACTIVE))){
+ bus_release_resource(dev, ctlr->r_type1, ctlr->r_rid1,ctlr->r_res1);
+ return ENXIO;
+ }
+ ctlr->allocate = ata_siiprb_allocate;
+ ctlr->reset = ata_siiprb_reset;
+ ctlr->dmainit = ata_siiprb_dmainit;
+ ctlr->setmode = ata_sata_setmode;
+ ctlr->channels = (ctlr->chip->cfg2 == SII_4CH) ? 4 : 2;
+
+ /* reset controller */
+ ATA_OUTL(ctlr->r_res1, 0x0040, 0x80000000);
+ DELAY(10000);
+ ATA_OUTL(ctlr->r_res1, 0x0040, 0x0000000f);
+
+ /* enable PCI interrupt */
+ pci_write_config(dev, PCIR_COMMAND,
+ pci_read_config(dev, PCIR_COMMAND, 2) & ~0x0400, 2);
+ break;
+
+ case SII_MEMIO:
+ ctlr->r_type2 = SYS_RES_MEMORY;
+ ctlr->r_rid2 = PCIR_BAR(5);
+ if (!(ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2,
+ &ctlr->r_rid2, RF_ACTIVE))){
+ if (ctlr->chip->chipid != ATA_SII0680 ||
+ (pci_read_config(dev, 0x8a, 1) & 1))
+ return ENXIO;
+ }
+
+ if (ctlr->chip->cfg2 & SII_SETCLK) {
+ if ((pci_read_config(dev, 0x8a, 1) & 0x30) != 0x10)
+ pci_write_config(dev, 0x8a,
+ (pci_read_config(dev, 0x8a, 1) & 0xcf)|0x10,1);
+ if ((pci_read_config(dev, 0x8a, 1) & 0x30) != 0x10)
+ device_printf(dev, "%s could not set ATA133 clock\n",
+ ctlr->chip->text);
+ }
+
+ /* if we have 4 channels enable the second set */
+ if (ctlr->chip->cfg2 & SII_4CH) {
+ ATA_OUTL(ctlr->r_res2, 0x0200, 0x00000002);
+ ctlr->channels = 4;
+ }
+
+ /* dont block interrupts from any channel */
+ pci_write_config(dev, 0x48,
+ (pci_read_config(dev, 0x48, 4) & ~0x03c00000), 4);
+
+ /* enable PCI interrupt as BIOS might not */
+ pci_write_config(dev, 0x8a, (pci_read_config(dev, 0x8a, 1) & 0x3f), 1);
+
+ if (ctlr->r_res2)
+ ctlr->allocate = ata_sii_allocate;
+
+ if (ctlr->chip->max_dma >= ATA_SA150) {
+ ctlr->reset = ata_sii_reset;
+ ctlr->setmode = ata_sata_setmode;
+ }
+ else
+ ctlr->setmode = ata_sii_setmode;
+ break;
+
+ default:
+ if ((pci_read_config(dev, 0x51, 1) & 0x08) != 0x08) {
+ device_printf(dev, "HW has secondary channel disabled\n");
+ ctlr->channels = 1;
+ }
+
+ /* enable interrupt as BIOS might not */
+ pci_write_config(dev, 0x71, 0x01, 1);
+
+ ctlr->allocate = ata_cmd_allocate;
+ ctlr->setmode = ata_cmd_setmode;
+ break;
+ }
+ return 0;
+}
+
+static int
+ata_cmd_allocate(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+
+ /* setup the usual register normal pci style */
+ if (ata_pci_allocate(dev))
+ return ENXIO;
+
+ if (ctlr->chip->cfg2 & SII_INTR)
+ ch->hw.status = ata_cmd_status;
+
+ return 0;
+}
+
+static int
+ata_cmd_status(device_t dev)
+{
+ struct ata_channel *ch = device_get_softc(dev);
+ u_int8_t reg71;
+
+ if (((reg71 = pci_read_config(device_get_parent(dev), 0x71, 1)) &
+ (ch->unit ? 0x08 : 0x04))) {
+ pci_write_config(device_get_parent(dev), 0x71,
+ reg71 & ~(ch->unit ? 0x04 : 0x08), 1);
+ return ata_pci_status(dev);
+ }
+ return 0;
+}
+
+static void
+ata_cmd_setmode(device_t dev, int mode)
+{
+ device_t gparent = GRANDPARENT(dev);
+ struct ata_pci_controller *ctlr = device_get_softc(gparent);
+ struct ata_channel *ch = device_get_softc(device_get_parent(dev));
+ struct ata_device *atadev = device_get_softc(dev);
+ int devno = (ch->unit << 1) + atadev->unit;
+ int error;
+
+ mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma);
+
+ mode = ata_check_80pin(dev, mode);
+
+ error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
+
+ if (bootverbose)
+ device_printf(dev, "%ssetting %s on %s chip\n",
+ (error) ? "FAILURE " : "",
+ ata_mode2str(mode), ctlr->chip->text);
+ if (!error) {
+ int treg = 0x54 + ((devno < 3) ? (devno << 1) : 7);
+ int ureg = ch->unit ? 0x7b : 0x73;
+
+ if (mode >= ATA_UDMA0) {
+ int udmatimings[][2] = { { 0x31, 0xc2 }, { 0x21, 0x82 },
+ { 0x11, 0x42 }, { 0x25, 0x8a },
+ { 0x15, 0x4a }, { 0x05, 0x0a } };
+
+ u_int8_t umode = pci_read_config(gparent, ureg, 1);
+
+ umode &= ~(atadev->unit == ATA_MASTER ? 0x35 : 0xca);
+ umode |= udmatimings[mode & ATA_MODE_MASK][atadev->unit];
+ pci_write_config(gparent, ureg, umode, 1);
+ }
+ else if (mode >= ATA_WDMA0) {
+ int dmatimings[] = { 0x87, 0x32, 0x3f };
+
+ pci_write_config(gparent, treg, dmatimings[mode & ATA_MODE_MASK],1);
+ pci_write_config(gparent, ureg,
+ pci_read_config(gparent, ureg, 1) &
+ ~(atadev->unit == ATA_MASTER ? 0x35 : 0xca), 1);
+ }
+ else {
+ int piotimings[] = { 0xa9, 0x57, 0x44, 0x32, 0x3f };
+ pci_write_config(gparent, treg,
+ piotimings[(mode & ATA_MODE_MASK) - ATA_PIO0], 1);
+ pci_write_config(gparent, ureg,
+ pci_read_config(gparent, ureg, 1) &
+ ~(atadev->unit == ATA_MASTER ? 0x35 : 0xca), 1);
+ }
+ atadev->mode = mode;
+ }
+}
+
+static int
+ata_sii_allocate(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ int unit01 = (ch->unit & 1), unit10 = (ch->unit & 2);
+ int i;
+
+ for (i = ATA_DATA; i <= ATA_COMMAND; i++) {
+ ch->r_io[i].res = ctlr->r_res2;
+ ch->r_io[i].offset = 0x80 + i + (unit01 << 6) + (unit10 << 8);
+ }
+ ch->r_io[ATA_CONTROL].res = ctlr->r_res2;
+ ch->r_io[ATA_CONTROL].offset = 0x8a + (unit01 << 6) + (unit10 << 8);
+ ch->r_io[ATA_IDX_ADDR].res = ctlr->r_res2;
+ ata_default_registers(dev);
+
+ ch->r_io[ATA_BMCMD_PORT].res = ctlr->r_res2;
+ ch->r_io[ATA_BMCMD_PORT].offset = 0x00 + (unit01 << 3) + (unit10 << 8);
+ ch->r_io[ATA_BMSTAT_PORT].res = ctlr->r_res2;
+ ch->r_io[ATA_BMSTAT_PORT].offset = 0x02 + (unit01 << 3) + (unit10 << 8);
+ ch->r_io[ATA_BMDTP_PORT].res = ctlr->r_res2;
+ ch->r_io[ATA_BMDTP_PORT].offset = 0x04 + (unit01 << 3) + (unit10 << 8);
+
+ if (ctlr->chip->max_dma >= ATA_SA150) {
+ ch->r_io[ATA_SSTATUS].res = ctlr->r_res2;
+ ch->r_io[ATA_SSTATUS].offset = 0x104 + (unit01 << 7) + (unit10 << 8);
+ ch->r_io[ATA_SERROR].res = ctlr->r_res2;
+ ch->r_io[ATA_SERROR].offset = 0x108 + (unit01 << 7) + (unit10 << 8);
+ ch->r_io[ATA_SCONTROL].res = ctlr->r_res2;
+ ch->r_io[ATA_SCONTROL].offset = 0x100 + (unit01 << 7) + (unit10 << 8);
+ ch->flags |= ATA_NO_SLAVE;
+
+ /* enable PHY state change interrupt */
+ ATA_OUTL(ctlr->r_res2, 0x148 + (unit01 << 7) + (unit10 << 8),(1 << 16));
+ }
+
+ if (ctlr->chip->cfg2 & SII_BUG) {
+ /* work around errata in early chips */
+ ch->dma.boundary = 8192;
+ ch->dma.segsize = 15 * DEV_BSIZE;
+ }
+
+ ata_pci_hw(dev);
+ ch->hw.status = ata_sii_status;
+ return 0;
+}
+
+static int
+ata_sii_status(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ int offset0 = ((ch->unit & 1) << 3) + ((ch->unit & 2) << 8);
+ int offset1 = ((ch->unit & 1) << 6) + ((ch->unit & 2) << 8);
+
+ /* do we have any PHY events ? */
+ if (ctlr->chip->max_dma >= ATA_SA150 &&
+ (ATA_INL(ctlr->r_res2, 0x10 + offset0) & 0x00000010))
+ ata_sata_phy_check_events(dev);
+
+ if (ATA_INL(ctlr->r_res2, 0xa0 + offset1) & 0x00000800)
+ return ata_pci_status(dev);
+ else
+ return 0;
+}
+
+static void
+ata_sii_reset(device_t dev)
+{
+ if (ata_sata_phy_reset(dev))
+ ata_generic_reset(dev);
+}
+
+static void
+ata_sii_setmode(device_t dev, int mode)
+{
+ device_t gparent = GRANDPARENT(dev);
+ struct ata_pci_controller *ctlr = device_get_softc(gparent);
+ struct ata_channel *ch = device_get_softc(device_get_parent(dev));
+ struct ata_device *atadev = device_get_softc(dev);
+ int rego = (ch->unit << 4) + (atadev->unit << 1);
+ int mreg = ch->unit ? 0x84 : 0x80;
+ int mask = 0x03 << (atadev->unit << 2);
+ int mval = pci_read_config(gparent, mreg, 1) & ~mask;
+ int error;
+
+ mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma);
+
+ if (ctlr->chip->cfg2 & SII_SETCLK) {
+ if (mode > ATA_UDMA2 && (pci_read_config(gparent, 0x79, 1) &
+ (ch->unit ? 0x02 : 0x01))) {
+ ata_print_cable(dev, "controller");
+ mode = ATA_UDMA2;
+ }
+ }
+ else
+ mode = ata_check_80pin(dev, mode);
+
+ error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
+
+ if (bootverbose)
+ device_printf(dev, "%ssetting %s on %s chip\n",
+ (error) ? "FAILURE " : "",
+ ata_mode2str(mode), ctlr->chip->text);
+ if (error)
+ return;
+
+ if (mode >= ATA_UDMA0) {
+ u_int8_t udmatimings[] = { 0xf, 0xb, 0x7, 0x5, 0x3, 0x2, 0x1 };
+ u_int8_t ureg = 0xac + rego;
+
+ pci_write_config(gparent, mreg,
+ mval | (0x03 << (atadev->unit << 2)), 1);
+ pci_write_config(gparent, ureg,
+ (pci_read_config(gparent, ureg, 1) & ~0x3f) |
+ udmatimings[mode & ATA_MODE_MASK], 1);
+
+ }
+ else if (mode >= ATA_WDMA0) {
+ u_int8_t dreg = 0xa8 + rego;
+ u_int16_t dmatimings[] = { 0x2208, 0x10c2, 0x10c1 };
+
+ pci_write_config(gparent, mreg,
+ mval | (0x02 << (atadev->unit << 2)), 1);
+ pci_write_config(gparent, dreg, dmatimings[mode & ATA_MODE_MASK], 2);
+
+ }
+ else {
+ u_int8_t preg = 0xa4 + rego;
+ u_int16_t piotimings[] = { 0x328a, 0x2283, 0x1104, 0x10c3, 0x10c1 };
+
+ pci_write_config(gparent, mreg,
+ mval | (0x01 << (atadev->unit << 2)), 1);
+ pci_write_config(gparent, preg, piotimings[mode & ATA_MODE_MASK], 2);
+ }
+ atadev->mode = mode;
+}
+
+
+struct ata_siiprb_dma_prdentry {
+ u_int64_t addr;
+ u_int32_t count;
+ u_int32_t control;
+} __packed;
+
+#define ATA_SIIPRB_DMA_ENTRIES 125
+struct ata_siiprb_ata_command {
+ struct ata_siiprb_dma_prdentry prd[ATA_SIIPRB_DMA_ENTRIES];
+} __packed;
+
+struct ata_siiprb_atapi_command {
+ u_int8_t ccb[16];
+ struct ata_siiprb_dma_prdentry prd[ATA_SIIPRB_DMA_ENTRIES];
+} __packed;
+
+struct ata_siiprb_command {
+ u_int16_t control;
+ u_int16_t protocol_override;
+ u_int32_t transfer_count;
+ u_int8_t fis[24];
+ union {
+ struct ata_siiprb_ata_command ata;
+ struct ata_siiprb_atapi_command atapi;
+ } u;
+} __packed;
+
+static int
+ata_siiprb_allocate(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ int offset = ch->unit * 0x2000;
+
+ /* set the SATA resources */
+ ch->r_io[ATA_SSTATUS].res = ctlr->r_res2;
+ ch->r_io[ATA_SSTATUS].offset = 0x1f04 + offset;
+ ch->r_io[ATA_SERROR].res = ctlr->r_res2;
+ ch->r_io[ATA_SERROR].offset = 0x1f08 + offset;
+ ch->r_io[ATA_SCONTROL].res = ctlr->r_res2;
+ ch->r_io[ATA_SCONTROL].offset = 0x1f00 + offset;
+ ch->r_io[ATA_SACTIVE].res = ctlr->r_res2;
+ ch->r_io[ATA_SACTIVE].offset = 0x1f0c + offset;
+
+ ch->hw.status = ata_siiprb_status;
+ ch->hw.begin_transaction = ata_siiprb_begin_transaction;
+ ch->hw.end_transaction = ata_siiprb_end_transaction;
+ ch->hw.command = NULL; /* not used here */
+ ch->hw.softreset = ata_siiprb_softreset;
+ ch->hw.pm_read = ata_siiprb_pm_read;
+ ch->hw.pm_write = ata_siiprb_pm_write;
+
+ return 0;
+}
+
+static int
+ata_siiprb_status(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ u_int32_t action = ATA_INL(ctlr->r_res1, 0x0044);
+ int offset = ch->unit * 0x2000;
+
+ if (action & (1 << ch->unit)) {
+ u_int32_t istatus = ATA_INL(ctlr->r_res2, 0x1008 + offset);
+
+ /* do we have any PHY events ? */
+ ata_sata_phy_check_events(dev);
+
+ /* clear interrupt(s) */
+ ATA_OUTL(ctlr->r_res2, 0x1008 + offset, istatus);
+
+ /* do we have any device action ? */
+ return (istatus & 0x00000003);
+ }
+ return 0;
+}
+
+static int
+ata_siiprb_begin_transaction(struct ata_request *request)
+{
+ struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev));
+ struct ata_channel *ch = device_get_softc(request->parent);
+ struct ata_siiprb_command *prb;
+ struct ata_siiprb_dma_prdentry *prd;
+ int offset = ch->unit * 0x2000;
+ u_int64_t prb_bus;
+
+ /* SOS XXX */
+ if (request->u.ata.command == ATA_DEVICE_RESET) {
+ request->result = 0;
+ return ATA_OP_FINISHED;
+ }
+
+ /* get a piece of the workspace for this request */
+ prb = (struct ata_siiprb_command *)
+ (ch->dma.work + (sizeof(struct ata_siiprb_command) * request->tag));
+
+ /* clear the prb structure */
+ bzero(prb, sizeof(struct ata_siiprb_command));
+
+ /* setup the FIS for this request */
+ if (!ata_request2fis_h2d(request, &prb->fis[0])) {
+ device_printf(request->dev, "setting up SATA FIS failed\n");
+ request->result = EIO;
+ return ATA_OP_FINISHED;
+ }
+
+ /* setup transfer type */
+ if (request->flags & ATA_R_ATAPI) {
+ struct ata_device *atadev = device_get_softc(request->dev);
+
+ bcopy(request->u.atapi.ccb, prb->u.atapi.ccb, 16);
+ if ((atadev->param.config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_12)
+ ATA_OUTL(ctlr->r_res2, 0x1004 + offset, 0x00000020);
+ else
+ ATA_OUTL(ctlr->r_res2, 0x1000 + offset, 0x00000020);
+ if (request->flags & ATA_R_READ)
+ prb->control = htole16(0x0010);
+ if (request->flags & ATA_R_WRITE)
+ prb->control = htole16(0x0020);
+ prd = &prb->u.atapi.prd[0];
+ }
+ else
+ prd = &prb->u.ata.prd[0];
+
+ /* if request moves data setup and load SG list */
+ if (request->flags & (ATA_R_READ | ATA_R_WRITE)) {
+ if (ch->dma.load(request, prd, NULL)) {
+ device_printf(request->dev, "setting up DMA failed\n");
+ request->result = EIO;
+ return ATA_OP_FINISHED;
+ }
+ }
+
+ /* activate the prb */
+ prb_bus = ch->dma.work_bus +
+ (sizeof(struct ata_siiprb_command) * request->tag);
+ ATA_OUTL(ctlr->r_res2,
+ 0x1c00 + offset + (request->tag * sizeof(u_int64_t)), prb_bus);
+ ATA_OUTL(ctlr->r_res2,
+ 0x1c04 + offset + (request->tag * sizeof(u_int64_t)), prb_bus>>32);
+
+ /* start the timeout */
+ callout_reset(&request->callout, request->timeout * hz,
+ (timeout_t*)ata_timeout, request);
+ return ATA_OP_CONTINUES;
+}
+
+static int
+ata_siiprb_end_transaction(struct ata_request *request)
+{
+ struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev));
+ struct ata_channel *ch = device_get_softc(request->parent);
+ struct ata_siiprb_command *prb;
+ int offset = ch->unit * 0x2000;
+ int error, timeout;
+
+ /* kill the timeout */
+ callout_stop(&request->callout);
+
+ prb = (struct ata_siiprb_command *)
+ ((u_int8_t *)rman_get_virtual(ctlr->r_res2)+(request->tag << 7)+offset);
+
+ /* any controller errors flagged ? */
+ if ((error = ATA_INL(ctlr->r_res2, 0x1024 + offset))) {
+ if (bootverbose)
+ printf("ata_siiprb_end_transaction %s error=%08x\n",
+ ata_cmd2str(request), error);
+
+ /* if device error status get details */
+ if (error == 1 || error == 2) {
+ request->status = prb->fis[2];
+ if (request->status & ATA_S_ERROR)
+ request->error = prb->fis[3];
+ }
+
+ /* SOS XXX handle other controller errors here */
+
+ /* initialize port */
+ ATA_OUTL(ctlr->r_res2, 0x1000 + offset, 0x00000004);
+
+ /* poll for port ready */
+ for (timeout = 0; timeout < 1000; timeout++) {
+ DELAY(1000);
+ if (ATA_INL(ctlr->r_res2, 0x1008 + offset) & 0x00040000)
+ break;
+ }
+ if (bootverbose) {
+ if (timeout >= 1000)
+ device_printf(ch->dev, "port initialize timeout\n");
+ else
+ device_printf(ch->dev, "port initialize time=%dms\n", timeout);
+ }
+ }
+
+ /* on control commands read back registers to the request struct */
+ if (request->flags & ATA_R_CONTROL) {
+ struct ata_device *atadev = device_get_softc(request->dev);
+
+ request->u.ata.count = prb->fis[12] | ((u_int16_t)prb->fis[13] << 8);
+ request->u.ata.lba = prb->fis[4] | ((u_int64_t)prb->fis[5] << 8) |
+ ((u_int64_t)prb->fis[6] << 16);
+ if (atadev->flags & ATA_D_48BIT_ACTIVE)
+ request->u.ata.lba |= ((u_int64_t)prb->fis[8] << 24) |
+ ((u_int64_t)prb->fis[9] << 32) |
+ ((u_int64_t)prb->fis[10] << 40);
+ else
+ request->u.ata.lba |= ((u_int64_t)(prb->fis[7] & 0x0f) << 24);
+ }
+
+ /* update progress */
+ if (!(request->status & ATA_S_ERROR) && !(request->flags & ATA_R_TIMEOUT)) {
+ if (request->flags & ATA_R_READ)
+ request->donecount = prb->transfer_count;
+ else
+ request->donecount = request->bytecount;
+ }
+
+ /* release SG list etc */
+ ch->dma.unload(request);
+
+ return ATA_OP_FINISHED;
+}
+
+static int
+ata_siiprb_issue_cmd(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ u_int64_t prb_bus = ch->dma.work_bus;
+ u_int32_t status;
+ int offset = ch->unit * 0x2000;
+ int timeout;
+
+ /* issue command to chip */
+ ATA_OUTL(ctlr->r_res2, 0x1c00 + offset, prb_bus);
+ ATA_OUTL(ctlr->r_res2, 0x1c04 + offset, prb_bus >> 32);
+
+ /* poll for command finished */
+ for (timeout = 0; timeout < 10000; timeout++) {
+ DELAY(1000);
+ if ((status = ATA_INL(ctlr->r_res2, 0x1008 + offset)) & 0x00010000)
+ break;
+ }
+ // SOS XXX ATA_OUTL(ctlr->r_res2, 0x1008 + offset, 0x00010000);
+ ATA_OUTL(ctlr->r_res2, 0x1008 + offset, 0x08ff08ff);
+
+ if (timeout >= 1000)
+ return EIO;
+
+ if (bootverbose)
+ device_printf(dev, "siiprb_issue_cmd time=%dms status=%08x\n",
+ timeout, status);
+ return 0;
+}
+
+static int
+ata_siiprb_pm_read(device_t dev, int port, int reg, u_int32_t *result)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ struct ata_siiprb_command *prb = (struct ata_siiprb_command *)ch->dma.work;
+ int offset = ch->unit * 0x2000;
+
+ bzero(prb, sizeof(struct ata_siiprb_command));
+ prb->fis[0] = 0x27; /* host to device */
+ prb->fis[1] = 0x8f; /* command FIS to PM port */
+ prb->fis[2] = ATA_READ_PM;
+ prb->fis[3] = reg;
+ prb->fis[7] = port;
+ if (ata_siiprb_issue_cmd(dev)) {
+ device_printf(dev, "error reading PM port\n");
+ return EIO;
+ }
+ prb = (struct ata_siiprb_command *)
+ ((u_int8_t *)rman_get_virtual(ctlr->r_res2) + offset);
+ *result = prb->fis[12]|(prb->fis[4]<<8)|(prb->fis[5]<<16)|(prb->fis[6]<<24);
+ return 0;
+}
+
+static int
+ata_siiprb_pm_write(device_t dev, int port, int reg, u_int32_t value)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ struct ata_siiprb_command *prb = (struct ata_siiprb_command *)ch->dma.work;
+ int offset = ch->unit * 0x2000;
+
+ bzero(prb, sizeof(struct ata_siiprb_command));
+ prb->fis[0] = 0x27; /* host to device */
+ prb->fis[1] = 0x8f; /* command FIS to PM port */
+ prb->fis[2] = ATA_WRITE_PM;
+ prb->fis[3] = reg;
+ prb->fis[7] = port;
+ prb->fis[12] = value & 0xff;
+ prb->fis[4] = (value >> 8) & 0xff;;
+ prb->fis[5] = (value >> 16) & 0xff;;
+ prb->fis[6] = (value >> 24) & 0xff;;
+ if (ata_siiprb_issue_cmd(dev)) {
+ device_printf(dev, "error writing PM port\n");
+ return ATA_E_ABORT;
+ }
+ prb = (struct ata_siiprb_command *)
+ ((u_int8_t *)rman_get_virtual(ctlr->r_res2) + offset);
+ return prb->fis[3];
+}
+
+static u_int32_t
+ata_siiprb_softreset(device_t dev, int port)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ struct ata_siiprb_command *prb = (struct ata_siiprb_command *)ch->dma.work;
+ u_int32_t signature;
+ int offset = ch->unit * 0x2000;
+
+ /* setup the workspace for a soft reset command */
+ bzero(prb, sizeof(struct ata_siiprb_command));
+ prb->control = htole16(0x0080);
+ prb->fis[1] = port & 0x0f;
+
+ /* issue soft reset */
+ if (ata_siiprb_issue_cmd(dev))
+ return -1;
+
+ ata_udelay(150000);
+
+ /* get possible signature */
+ prb = (struct ata_siiprb_command *)
+ ((u_int8_t *)rman_get_virtual(ctlr->r_res2) + offset);
+ signature=prb->fis[12]|(prb->fis[4]<<8)|(prb->fis[5]<<16)|(prb->fis[6]<<24);
+
+ /* clear error bits/interrupt */
+ ATA_IDX_OUTL(ch, ATA_SERROR, 0xffffffff);
+
+ return signature;
+}
+
+static void
+ata_siiprb_reset(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ int offset = ch->unit * 0x2000;
+ u_int32_t status, signature;
+ int timeout;
+
+ /* disable interrupts */
+ ATA_OUTL(ctlr->r_res2, 0x1014 + offset, 0x000000ff);
+
+ /* reset channel HW */
+ ATA_OUTL(ctlr->r_res2, 0x1000 + offset, 0x00000001);
+ DELAY(1000);
+ ATA_OUTL(ctlr->r_res2, 0x1004 + offset, 0x00000001);
+ DELAY(10000);
+
+ /* poll for channel ready */
+ for (timeout = 0; timeout < 1000; timeout++) {
+ if ((status = ATA_INL(ctlr->r_res2, 0x1008 + offset)) & 0x00040000)
+ break;
+ DELAY(1000);
+ }
+
+ if (bootverbose) {
+ if (timeout >= 1000)
+ device_printf(dev, "channel HW reset timeout\n");
+ else
+ device_printf(dev, "channel HW reset time=%dms\n", timeout);
+ }
+
+ /* reset phy */
+ if (!ata_sata_phy_reset(dev)) {
+ if (bootverbose)
+ device_printf(dev, "phy reset found no device\n");
+ ch->devices = 0;
+ goto finish;
+ }
+
+ /* issue soft reset */
+ signature = ata_siiprb_softreset(dev, ATA_PM);
+ if (bootverbose)
+ device_printf(dev, "SIGNATURE=%08x\n", signature);
+
+ /* figure out whats there */
+ switch (signature) {
+ case 0x00000101:
+ ch->devices = ATA_ATA_MASTER;
+ break;
+ case 0x96690101:
+ ch->devices = ATA_PORTMULTIPLIER;
+ ATA_OUTL(ctlr->r_res2, 0x1000 + offset, 0x2000); /* enable PM support */
+ //SOS XXX need to clear all PM status and interrupts!!!!
+ ata_pm_identify(dev);
+ break;
+ case 0xeb140101:
+ ch->devices = ATA_ATAPI_MASTER;
+ break;
+ default:
+ ch->devices = 0;
+ }
+ if (bootverbose)
+ device_printf(dev, "siiprb_reset devices=%08x\n", ch->devices);
+
+finish:
+ /* clear interrupt(s) */
+ ATA_OUTL(ctlr->r_res2, 0x1008 + offset, 0x000008ff);
+
+ /* require explicit interrupt ack */
+ ATA_OUTL(ctlr->r_res2, 0x1000 + offset, 0x00000008);
+
+ /* 64bit mode */
+ ATA_OUTL(ctlr->r_res2, 0x1004 + offset, 0x00000400);
+
+ /* enable interrupts wanted */
+ ATA_OUTL(ctlr->r_res2, 0x1010 + offset, 0x000000ff);
+}
+
+static void
+ata_siiprb_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error)
+{
+ struct ata_dmasetprd_args *args = xsc;
+ struct ata_siiprb_dma_prdentry *prd = args->dmatab;
+ int i;
+
+ if ((args->error = error))
+ return;
+
+ for (i = 0; i < nsegs; i++) {
+ prd[i].addr = htole64(segs[i].ds_addr);
+ prd[i].count = htole32(segs[i].ds_len);
+ }
+ prd[i - 1].control = htole32(ATA_DMA_EOT);
+ KASSERT(nsegs <= ATA_SIIPRB_DMA_ENTRIES,("too many DMA segment entries\n"));
+ args->nsegs = nsegs;
+}
+
+static void
+ata_siiprb_dmainit(device_t dev)
+{
+ struct ata_channel *ch = device_get_softc(dev);
+
+ ata_dmainit(dev);
+ /* note start and stop are not used here */
+ ch->dma.setprd = ata_siiprb_dmasetprd;
+ ch->dma.max_address = BUS_SPACE_MAXADDR;
+}
+
+ATA_DECLARE_DRIVER(ata_sii);
diff --git a/sys/dev/ata/chipsets/ata-sis.c b/sys/dev/ata/chipsets/ata-sis.c
new file mode 100644
index 0000000..e94bef5
--- /dev/null
+++ b/sys/dev/ata/chipsets/ata-sis.c
@@ -0,0 +1,314 @@
+/*-
+ * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org>
+ * 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,
+ * without modification, immediately at the beginning of the file.
+ * 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 AUTHOR ``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 AUTHOR 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>
+__FBSDID("$FreeBSD$");
+
+#include "opt_ata.h"
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/ata.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sema.h>
+#include <sys/taskqueue.h>
+#include <vm/uma.h>
+#include <machine/stdarg.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/ata/ata-all.h>
+#include <dev/ata/ata-pci.h>
+#include <ata_if.h>
+
+/* local prototypes */
+static int ata_sis_chipinit(device_t dev);
+static int ata_sis_allocate(device_t dev);
+static void ata_sis_reset(device_t dev);
+static void ata_sis_setmode(device_t dev, int mode);
+
+/* misc defines */
+#define SIS_33 1
+#define SIS_66 2
+#define SIS_100NEW 3
+#define SIS_100OLD 4
+#define SIS_133NEW 5
+#define SIS_133OLD 6
+#define SIS_SATA 7
+
+
+/*
+ * Silicon Integrated Systems Corp. (SiS) chipset support functions
+ */
+static int
+ata_sis_probe(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+ struct ata_chip_id *idx;
+ static struct ata_chip_id ids[] =
+ {{ ATA_SIS182, 0x00, SIS_SATA, 0, ATA_SA150, "182" }, /* south */
+ { ATA_SIS181, 0x00, SIS_SATA, 0, ATA_SA150, "181" }, /* south */
+ { ATA_SIS180, 0x00, SIS_SATA, 0, ATA_SA150, "180" }, /* south */
+ { ATA_SIS965, 0x00, SIS_133NEW, 0, ATA_UDMA6, "965" }, /* south */
+ { ATA_SIS964, 0x00, SIS_133NEW, 0, ATA_UDMA6, "964" }, /* south */
+ { ATA_SIS963, 0x00, SIS_133NEW, 0, ATA_UDMA6, "963" }, /* south */
+ { ATA_SIS962, 0x00, SIS_133NEW, 0, ATA_UDMA6, "962" }, /* south */
+
+ { ATA_SIS745, 0x00, SIS_100NEW, 0, ATA_UDMA5, "745" }, /* 1chip */
+ { ATA_SIS735, 0x00, SIS_100NEW, 0, ATA_UDMA5, "735" }, /* 1chip */
+ { ATA_SIS733, 0x00, SIS_100NEW, 0, ATA_UDMA5, "733" }, /* 1chip */
+ { ATA_SIS730, 0x00, SIS_100OLD, 0, ATA_UDMA5, "730" }, /* 1chip */
+
+ { ATA_SIS635, 0x00, SIS_100NEW, 0, ATA_UDMA5, "635" }, /* 1chip */
+ { ATA_SIS633, 0x00, SIS_100NEW, 0, ATA_UDMA5, "633" }, /* unknown */
+ { ATA_SIS630, 0x30, SIS_100OLD, 0, ATA_UDMA5, "630S"}, /* 1chip */
+ { ATA_SIS630, 0x00, SIS_66, 0, ATA_UDMA4, "630" }, /* 1chip */
+ { ATA_SIS620, 0x00, SIS_66, 0, ATA_UDMA4, "620" }, /* 1chip */
+
+ { ATA_SIS550, 0x00, SIS_66, 0, ATA_UDMA5, "550" },
+ { ATA_SIS540, 0x00, SIS_66, 0, ATA_UDMA4, "540" },
+ { ATA_SIS530, 0x00, SIS_66, 0, ATA_UDMA4, "530" },
+
+ { ATA_SIS5513, 0xc2, SIS_33, 1, ATA_UDMA2, "5513" },
+ { ATA_SIS5513, 0x00, SIS_33, 1, ATA_WDMA2, "5513" },
+ { 0, 0, 0, 0, 0, 0 }};
+ char buffer[64];
+ int found = 0;
+
+ if (pci_get_vendor(dev) != ATA_SIS_ID)
+ return ENXIO;
+
+ if (!(idx = ata_find_chip(dev, ids, -pci_get_slot(dev))))
+ return ENXIO;
+
+ if (idx->cfg2 && !found) {
+ u_int8_t reg57 = pci_read_config(dev, 0x57, 1);
+
+ pci_write_config(dev, 0x57, (reg57 & 0x7f), 1);
+ if (pci_read_config(dev, PCIR_DEVVENDOR, 4) == ATA_SIS5518) {
+ found = 1;
+ idx->cfg1 = SIS_133NEW;
+ idx->max_dma = ATA_UDMA6;
+ sprintf(buffer, "SiS 962/963 %s controller",
+ ata_mode2str(idx->max_dma));
+ }
+ pci_write_config(dev, 0x57, reg57, 1);
+ }
+ if (idx->cfg2 && !found) {
+ u_int8_t reg4a = pci_read_config(dev, 0x4a, 1);
+
+ pci_write_config(dev, 0x4a, (reg4a | 0x10), 1);
+ if (pci_read_config(dev, PCIR_DEVVENDOR, 4) == ATA_SIS5517) {
+ struct ata_chip_id id[] =
+ {{ ATA_SISSOUTH, 0x10, 0, 0, 0, "" }, { 0, 0, 0, 0, 0, 0 }};
+
+ found = 1;
+ if (ata_find_chip(dev, id, pci_get_slot(dev))) {
+ idx->cfg1 = SIS_133OLD;
+ idx->max_dma = ATA_UDMA6;
+ }
+ else {
+ idx->cfg1 = SIS_100NEW;
+ idx->max_dma = ATA_UDMA5;
+ }
+ sprintf(buffer, "SiS 961 %s controller",ata_mode2str(idx->max_dma));
+ }
+ pci_write_config(dev, 0x4a, reg4a, 1);
+ }
+ if (!found)
+ sprintf(buffer,"SiS %s %s controller",
+ idx->text, ata_mode2str(idx->max_dma));
+
+ device_set_desc_copy(dev, buffer);
+ ctlr->chip = idx;
+ ctlr->chipinit = ata_sis_chipinit;
+ return 0;
+}
+
+static int
+ata_sis_chipinit(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+
+ if (ata_setup_interrupt(dev, ata_generic_intr))
+ return ENXIO;
+
+ switch (ctlr->chip->cfg1) {
+ case SIS_33:
+ break;
+ case SIS_66:
+ case SIS_100OLD:
+ pci_write_config(dev, 0x52, pci_read_config(dev, 0x52, 1) & ~0x04, 1);
+ break;
+ case SIS_100NEW:
+ case SIS_133OLD:
+ pci_write_config(dev, 0x49, pci_read_config(dev, 0x49, 1) & ~0x01, 1);
+ break;
+ case SIS_133NEW:
+ pci_write_config(dev, 0x50, pci_read_config(dev, 0x50, 2) | 0x0008, 2);
+ pci_write_config(dev, 0x52, pci_read_config(dev, 0x52, 2) | 0x0008, 2);
+ break;
+ case SIS_SATA:
+ ctlr->r_type2 = SYS_RES_IOPORT;
+ ctlr->r_rid2 = PCIR_BAR(5);
+ if ((ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2,
+ &ctlr->r_rid2, RF_ACTIVE))) {
+ ctlr->allocate = ata_sis_allocate;
+ ctlr->reset = ata_sis_reset;
+
+ /* enable PCI interrupt */
+ pci_write_config(dev, PCIR_COMMAND,
+ pci_read_config(dev, PCIR_COMMAND, 2) & ~0x0400,2);
+ }
+ ctlr->setmode = ata_sata_setmode;
+ return 0;
+ default:
+ return ENXIO;
+ }
+ ctlr->setmode = ata_sis_setmode;
+ return 0;
+}
+
+static int
+ata_sis_allocate(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ int offset = ch->unit << ((ctlr->chip->chipid == ATA_SIS182) ? 5 : 6);
+
+ /* setup the usual register normal pci style */
+ if (ata_pci_allocate(dev))
+ return ENXIO;
+
+ ch->r_io[ATA_SSTATUS].res = ctlr->r_res2;
+ ch->r_io[ATA_SSTATUS].offset = 0x00 + offset;
+ ch->r_io[ATA_SERROR].res = ctlr->r_res2;
+ ch->r_io[ATA_SERROR].offset = 0x04 + offset;
+ ch->r_io[ATA_SCONTROL].res = ctlr->r_res2;
+ ch->r_io[ATA_SCONTROL].offset = 0x08 + offset;
+ ch->flags |= ATA_NO_SLAVE;
+
+ /* XXX SOS PHY hotplug handling missing in SiS chip ?? */
+ /* XXX SOS unknown how to enable PHY state change interrupt */
+ return 0;
+}
+
+static void
+ata_sis_reset(device_t dev)
+{
+ if (ata_sata_phy_reset(dev))
+ ata_generic_reset(dev);
+}
+
+static void
+ata_sis_setmode(device_t dev, int mode)
+{
+ device_t gparent = GRANDPARENT(dev);
+ struct ata_pci_controller *ctlr = device_get_softc(gparent);
+ struct ata_channel *ch = device_get_softc(device_get_parent(dev));
+ struct ata_device *atadev = device_get_softc(dev);
+ int devno = (ch->unit << 1) + atadev->unit;
+ int error;
+
+ mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma);
+
+ if (ctlr->chip->cfg1 == SIS_133NEW) {
+ if (mode > ATA_UDMA2 &&
+ pci_read_config(gparent, ch->unit ? 0x52 : 0x50,2) & 0x8000) {
+ ata_print_cable(dev, "controller");
+ mode = ATA_UDMA2;
+ }
+ }
+ else {
+ if (mode > ATA_UDMA2 &&
+ pci_read_config(gparent, 0x48, 1)&(ch->unit ? 0x20 : 0x10)) {
+ ata_print_cable(dev, "controller");
+ mode = ATA_UDMA2;
+ }
+ }
+
+ error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
+
+ if (bootverbose)
+ device_printf(dev, "%ssetting %s on %s chip\n",
+ (error) ? "FAILURE " : "",
+ ata_mode2str(mode), ctlr->chip->text);
+ if (!error) {
+ switch (ctlr->chip->cfg1) {
+ case SIS_133NEW: {
+ u_int32_t timings[] =
+ { 0x28269008, 0x0c266008, 0x04263008, 0x0c0a3008, 0x05093008,
+ 0x22196008, 0x0c0a3008, 0x05093008, 0x050939fc, 0x050936ac,
+ 0x0509347c, 0x0509325c, 0x0509323c, 0x0509322c, 0x0509321c};
+ u_int32_t reg;
+
+ reg = (pci_read_config(gparent, 0x57, 1)&0x40?0x70:0x40)+(devno<<2);
+ pci_write_config(gparent, reg, timings[ata_mode2idx(mode)], 4);
+ break;
+ }
+ case SIS_133OLD: {
+ u_int16_t timings[] =
+ { 0x00cb, 0x0067, 0x0044, 0x0033, 0x0031, 0x0044, 0x0033, 0x0031,
+ 0x8f31, 0x8a31, 0x8731, 0x8531, 0x8331, 0x8231, 0x8131 };
+
+ u_int16_t reg = 0x40 + (devno << 1);
+
+ pci_write_config(gparent, reg, timings[ata_mode2idx(mode)], 2);
+ break;
+ }
+ case SIS_100NEW: {
+ u_int16_t timings[] =
+ { 0x00cb, 0x0067, 0x0044, 0x0033, 0x0031, 0x0044, 0x0033,
+ 0x0031, 0x8b31, 0x8731, 0x8531, 0x8431, 0x8231, 0x8131 };
+ u_int16_t reg = 0x40 + (devno << 1);
+
+ pci_write_config(gparent, reg, timings[ata_mode2idx(mode)], 2);
+ break;
+ }
+ case SIS_100OLD:
+ case SIS_66:
+ case SIS_33: {
+ u_int16_t timings[] =
+ { 0x0c0b, 0x0607, 0x0404, 0x0303, 0x0301, 0x0404, 0x0303,
+ 0x0301, 0xf301, 0xd301, 0xb301, 0xa301, 0x9301, 0x8301 };
+ u_int16_t reg = 0x40 + (devno << 1);
+
+ pci_write_config(gparent, reg, timings[ata_mode2idx(mode)], 2);
+ break;
+ }
+ }
+ atadev->mode = mode;
+ }
+}
+
+ATA_DECLARE_DRIVER(ata_sis);
diff --git a/sys/dev/ata/chipsets/ata-via.c b/sys/dev/ata/chipsets/ata-via.c
new file mode 100644
index 0000000..04d9904
--- /dev/null
+++ b/sys/dev/ata/chipsets/ata-via.c
@@ -0,0 +1,351 @@
+/*-
+ * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org>
+ * 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,
+ * without modification, immediately at the beginning of the file.
+ * 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 AUTHOR ``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 AUTHOR 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>
+__FBSDID("$FreeBSD$");
+
+#include "opt_ata.h"
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/ata.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sema.h>
+#include <sys/taskqueue.h>
+#include <vm/uma.h>
+#include <machine/stdarg.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/ata/ata-all.h>
+#include <dev/ata/ata-pci.h>
+#include <ata_if.h>
+
+/* local prototypes */
+static int ata_via_chipinit(device_t dev);
+static int ata_via_allocate(device_t dev);
+static void ata_via_reset(device_t dev);
+static void ata_via_old_setmode(device_t dev, int mode);
+static void ata_via_southbridge_fixup(device_t dev);
+static void ata_via_new_setmode(device_t dev, int mode);
+
+/* misc defines */
+#define VIA33 0
+#define VIA66 1
+#define VIA100 2
+#define VIA133 3
+
+#define VIACLK 0x01
+#define VIABUG 0x02
+#define VIABAR 0x04
+#define VIAAHCI 0x08
+
+
+/*
+ * VIA Technologies Inc. chipset support functions
+ */
+static int
+ata_via_probe(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+ static struct ata_chip_id ids[] =
+ {{ ATA_VIA82C586, 0x02, VIA33, 0x00, ATA_UDMA2, "82C586B" },
+ { ATA_VIA82C586, 0x00, VIA33, 0x00, ATA_WDMA2, "82C586" },
+ { ATA_VIA82C596, 0x12, VIA66, VIACLK, ATA_UDMA4, "82C596B" },
+ { ATA_VIA82C596, 0x00, VIA33, 0x00, ATA_UDMA2, "82C596" },
+ { ATA_VIA82C686, 0x40, VIA100, VIABUG, ATA_UDMA5, "82C686B"},
+ { ATA_VIA82C686, 0x10, VIA66, VIACLK, ATA_UDMA4, "82C686A" },
+ { ATA_VIA82C686, 0x00, VIA33, 0x00, ATA_UDMA2, "82C686" },
+ { ATA_VIA8231, 0x00, VIA100, VIABUG, ATA_UDMA5, "8231" },
+ { ATA_VIA8233, 0x00, VIA100, 0x00, ATA_UDMA5, "8233" },
+ { ATA_VIA8233C, 0x00, VIA100, 0x00, ATA_UDMA5, "8233C" },
+ { ATA_VIA8233A, 0x00, VIA133, 0x00, ATA_UDMA6, "8233A" },
+ { ATA_VIA8235, 0x00, VIA133, 0x00, ATA_UDMA6, "8235" },
+ { ATA_VIA8237, 0x00, VIA133, 0x00, ATA_UDMA6, "8237" },
+ { ATA_VIA8237A, 0x00, VIA133, 0x00, ATA_UDMA6, "8237A" },
+ { ATA_VIA8237S, 0x00, VIA133, 0x00, ATA_UDMA6, "8237S" },
+ { ATA_VIA8251, 0x00, VIA133, 0x00, ATA_UDMA6, "8251" },
+ { 0, 0, 0, 0, 0, 0 }};
+ static struct ata_chip_id new_ids[] =
+ {{ ATA_VIA6410, 0x00, 0, 0x00, ATA_UDMA6, "6410" },
+ { ATA_VIA6420, 0x00, 7, 0x00, ATA_SA150, "6420" },
+ { ATA_VIA6421, 0x00, 6, VIABAR, ATA_SA150, "6421" },
+ { ATA_VIA8237A, 0x00, 7, 0x00, ATA_SA150, "8237A" },
+ { ATA_VIA8237S, 0x00, 7, 0x00, ATA_SA150, "8237S" },
+ { ATA_VIA8251, 0x00, 0, VIAAHCI, ATA_SA300, "8251" },
+ { 0, 0, 0, 0, 0, 0 }};
+
+ if (pci_get_vendor(dev) != ATA_VIA_ID)
+ return ENXIO;
+
+ if (pci_get_devid(dev) == ATA_VIA82C571) {
+ if (!(ctlr->chip = ata_find_chip(dev, ids, -99)))
+ return ENXIO;
+ }
+ else {
+ if (!(ctlr->chip = ata_match_chip(dev, new_ids)))
+ return ENXIO;
+ }
+
+ ata_set_desc(dev);
+ ctlr->chipinit = ata_via_chipinit;
+ return 0;
+}
+
+static int
+ata_via_chipinit(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+
+ if (ata_setup_interrupt(dev, ata_generic_intr))
+ return ENXIO;
+
+ if (ctlr->chip->max_dma >= ATA_SA150) {
+ /* do we have AHCI capability ? */
+ if ((ctlr->chip->cfg2 == VIAAHCI) && ata_ahci_chipinit(dev) != ENXIO)
+ return 0;
+
+ ctlr->r_type2 = SYS_RES_IOPORT;
+ ctlr->r_rid2 = PCIR_BAR(5);
+ if ((ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2,
+ &ctlr->r_rid2, RF_ACTIVE))) {
+ ctlr->allocate = ata_via_allocate;
+ ctlr->reset = ata_via_reset;
+
+ /* enable PCI interrupt */
+ pci_write_config(dev, PCIR_COMMAND,
+ pci_read_config(dev, PCIR_COMMAND, 2) & ~0x0400,2);
+ }
+
+ if (ctlr->chip->cfg2 & VIABAR) {
+ ctlr->channels = 3;
+ ctlr->setmode = ata_via_new_setmode;
+ }
+ else
+ ctlr->setmode = ata_sata_setmode;
+ return 0;
+ }
+
+ /* prepare for ATA-66 on the 82C686a and 82C596b */
+ if (ctlr->chip->cfg2 & VIACLK)
+ pci_write_config(dev, 0x50, 0x030b030b, 4);
+
+ /* the southbridge might need the data corruption fix */
+ if (ctlr->chip->cfg2 & VIABUG)
+ ata_via_southbridge_fixup(dev);
+
+ /* set fifo configuration half'n'half */
+ pci_write_config(dev, 0x43,
+ (pci_read_config(dev, 0x43, 1) & 0x90) | 0x2a, 1);
+
+ /* set status register read retry */
+ pci_write_config(dev, 0x44, pci_read_config(dev, 0x44, 1) | 0x08, 1);
+
+ /* set DMA read & end-of-sector fifo flush */
+ pci_write_config(dev, 0x46,
+ (pci_read_config(dev, 0x46, 1) & 0x0c) | 0xf0, 1);
+
+ /* set sector size */
+ pci_write_config(dev, 0x60, DEV_BSIZE, 2);
+ pci_write_config(dev, 0x68, DEV_BSIZE, 2);
+
+ ctlr->setmode = ata_via_old_setmode;
+ return 0;
+}
+
+static int
+ata_via_allocate(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+
+ /* newer SATA chips has resources in one BAR for each channel */
+ if (ctlr->chip->cfg2 & VIABAR) {
+ struct resource *r_io;
+ int i, rid;
+
+ rid = PCIR_BAR(ch->unit);
+ if (!(r_io = bus_alloc_resource_any(device_get_parent(dev),
+ SYS_RES_IOPORT,
+ &rid, RF_ACTIVE)))
+ return ENXIO;
+
+ for (i = ATA_DATA; i <= ATA_COMMAND; i ++) {
+ ch->r_io[i].res = r_io;
+ ch->r_io[i].offset = i;
+ }
+ ch->r_io[ATA_CONTROL].res = r_io;
+ ch->r_io[ATA_CONTROL].offset = 2 + ATA_IOSIZE;
+ ch->r_io[ATA_IDX_ADDR].res = r_io;
+ ata_default_registers(dev);
+ for (i = ATA_BMCMD_PORT; i <= ATA_BMDTP_PORT; i++) {
+ ch->r_io[i].res = ctlr->r_res1;
+ ch->r_io[i].offset = (i - ATA_BMCMD_PORT)+(ch->unit * ATA_BMIOSIZE);
+ }
+ ata_pci_hw(dev);
+ if (ch->unit >= 2)
+ return 0;
+ }
+ else {
+ /* setup the usual register normal pci style */
+ if (ata_pci_allocate(dev))
+ return ENXIO;
+ }
+
+ ch->r_io[ATA_SSTATUS].res = ctlr->r_res2;
+ ch->r_io[ATA_SSTATUS].offset = (ch->unit << ctlr->chip->cfg1);
+ ch->r_io[ATA_SERROR].res = ctlr->r_res2;
+ ch->r_io[ATA_SERROR].offset = 0x04 + (ch->unit << ctlr->chip->cfg1);
+ ch->r_io[ATA_SCONTROL].res = ctlr->r_res2;
+ ch->r_io[ATA_SCONTROL].offset = 0x08 + (ch->unit << ctlr->chip->cfg1);
+ ch->flags |= ATA_NO_SLAVE;
+
+ /* XXX SOS PHY hotplug handling missing in VIA chip ?? */
+ /* XXX SOS unknown how to enable PHY state change interrupt */
+ return 0;
+}
+
+static void
+ata_via_reset(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+
+ if ((ctlr->chip->cfg2 & VIABAR) && (ch->unit > 1))
+ ata_generic_reset(dev);
+ else
+ if (ata_sata_phy_reset(dev))
+ ata_generic_reset(dev);
+}
+
+static void
+ata_via_new_setmode(device_t dev, int mode)
+{
+ device_t gparent = GRANDPARENT(dev);
+ struct ata_pci_controller *ctlr = device_get_softc(gparent);
+ struct ata_channel *ch = device_get_softc(device_get_parent(dev));
+ struct ata_device *atadev = device_get_softc(dev);
+ int error;
+
+ if ((ctlr->chip->cfg2 & VIABAR) && (ch->unit > 1)) {
+ u_int8_t pio_timings[] = { 0xa8, 0x65, 0x65, 0x32, 0x20,
+ 0x65, 0x32, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 };
+ u_int8_t dma_timings[] = { 0xee, 0xe8, 0xe6, 0xe4, 0xe2, 0xe1, 0xe0 };
+
+ mode = ata_check_80pin(dev, ata_limit_mode(dev, mode, ATA_UDMA6));
+ error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
+ if (bootverbose)
+ device_printf(dev, "%ssetting %s on %s chip\n",
+ (error) ? "FAILURE " : "", ata_mode2str(mode),
+ ctlr->chip->text);
+ if (!error) {
+ pci_write_config(gparent, 0xab, pio_timings[ata_mode2idx(mode)], 1);
+ if (mode >= ATA_UDMA0)
+ pci_write_config(gparent, 0xb3,
+ dma_timings[mode & ATA_MODE_MASK], 1);
+ atadev->mode = mode;
+ }
+ }
+ else
+ ata_sata_setmode(dev, mode);
+}
+
+static void
+ata_via_old_setmode(device_t dev, int mode)
+{
+ device_t gparent = GRANDPARENT(dev);
+ struct ata_pci_controller *ctlr = device_get_softc(gparent);
+ struct ata_channel *ch = device_get_softc(device_get_parent(dev));
+ struct ata_device *atadev = device_get_softc(dev);
+ u_int8_t timings[] = { 0xa8, 0x65, 0x42, 0x22, 0x20, 0x42, 0x22, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 };
+ int modes[][7] = {
+ { 0xc2, 0xc1, 0xc0, 0x00, 0x00, 0x00, 0x00 }, /* VIA ATA33 */
+ { 0xee, 0xec, 0xea, 0xe9, 0xe8, 0x00, 0x00 }, /* VIA ATA66 */
+ { 0xf7, 0xf6, 0xf4, 0xf2, 0xf1, 0xf0, 0x00 }, /* VIA ATA100 */
+ { 0xf7, 0xf7, 0xf6, 0xf4, 0xf2, 0xf1, 0xf0 } }; /* VIA ATA133 */
+ int devno = (ch->unit << 1) + atadev->unit;
+ int reg = 0x53 - devno;
+ int error;
+
+ mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma);
+ mode = ata_check_80pin(dev, mode);
+
+ error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
+ if (bootverbose)
+ device_printf(dev, "%ssetting %s on %s chip\n",
+ (error) ? "FAILURE " : "", ata_mode2str(mode),
+ ctlr->chip->text);
+ if (!error) {
+ if (ctlr->chip->cfg1 != VIA133)
+ pci_write_config(gparent, reg - 0x08,timings[ata_mode2idx(mode)],1);
+ if (mode >= ATA_UDMA0)
+ pci_write_config(gparent, reg,
+ modes[ctlr->chip->cfg1][mode & ATA_MODE_MASK], 1);
+ else
+ pci_write_config(gparent, reg, 0x8b, 1);
+ atadev->mode = mode;
+ }
+}
+
+static void
+ata_via_southbridge_fixup(device_t dev)
+{
+ device_t *children;
+ int nchildren, i;
+
+ if (device_get_children(device_get_parent(dev), &children, &nchildren))
+ return;
+
+ for (i = 0; i < nchildren; i++) {
+ if (pci_get_devid(children[i]) == ATA_VIA8363 ||
+ pci_get_devid(children[i]) == ATA_VIA8371 ||
+ pci_get_devid(children[i]) == ATA_VIA8662 ||
+ pci_get_devid(children[i]) == ATA_VIA8361) {
+ u_int8_t reg76 = pci_read_config(children[i], 0x76, 1);
+
+ if ((reg76 & 0xf0) != 0xd0) {
+ device_printf(dev,
+ "Correcting VIA config for southbridge data corruption bug\n");
+ pci_write_config(children[i], 0x75, 0x80, 1);
+ pci_write_config(children[i], 0x76, (reg76 & 0x0f) | 0xd0, 1);
+ }
+ break;
+ }
+ }
+ free(children, M_TEMP);
+}
+
+ATA_DECLARE_DRIVER(ata_via);
+MODULE_DEPEND(ata_via, ata_ahci, 1, 1, 1);
OpenPOWER on IntegriCloud