diff options
62 files changed, 8673 insertions, 6838 deletions
diff --git a/sys/conf/files b/sys/conf/files index 2ff8204..09b0697 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -459,23 +459,49 @@ dev/an/if_an_isa.c optional an isa dev/an/if_an_pccard.c optional an pccard dev/an/if_an_pci.c optional an pci dev/asr/asr.c optional asr pci -dev/ata/ata_if.m optional ata -dev/ata/ata-all.c optional ata -dev/ata/ata-card.c optional ata pccard -dev/ata/ata-cbus.c optional ata pc98 -dev/ata/ata-chipset.c optional ata pci +# +dev/ata/ata_if.m optional ata | atacore +dev/ata/ata-all.c optional ata | atacore +dev/ata/ata-lowlevel.c optional ata | atacore +dev/ata/ata-queue.c optional ata | atacore +dev/ata/ata-card.c optional ata pccard | atapccard +dev/ata/ata-cbus.c optional ata pc98 | atapc98 +dev/ata/ata-isa.c optional ata isa | ataisa +dev/ata/ata-pci.c optional ata pci | atapci +dev/ata/ata-dma.c optional ata pci | atapci +dev/ata/ata-sata.c optional ata pci | atapci +dev/ata/chipsets/ata-ahci.c optional ata pci | ataahci | ataacerlabs | \ + ataati | ataintel | atajmicron | atavia +dev/ata/chipsets/ata-acard.c optional ata pci | ataacard +dev/ata/chipsets/ata-acerlabs.c optional ata pci | ataacerlabs +dev/ata/chipsets/ata-adaptec.c optional ata pci | ataadaptec +dev/ata/chipsets/ata-amd.c optional ata pci | ataamd +dev/ata/chipsets/ata-ati.c optional ata pci | ataati +dev/ata/chipsets/ata-cenatek.c optional ata pci | atacenatek +dev/ata/chipsets/ata-cypress.c optional ata pci | atacypress +dev/ata/chipsets/ata-cyrix.c optional ata pci | atacyrix +dev/ata/chipsets/ata-highpoint.c optional ata pci | atahighpoint +dev/ata/chipsets/ata-intel.c optional ata pci | ataintel +dev/ata/chipsets/ata-ite.c optional ata pci | ataite +dev/ata/chipsets/ata-jmicron.c optional ata pci | atajmicron +dev/ata/chipsets/ata-marvell.c optional ata pci | atamarvell +dev/ata/chipsets/ata-micron.c optional ata pci | atamicron +dev/ata/chipsets/ata-national.c optional ata pci | atanational +dev/ata/chipsets/ata-netcell.c optional ata pci | atanetcell +dev/ata/chipsets/ata-nvidia.c optional ata pci | atanvidia +dev/ata/chipsets/ata-promise.c optional ata pci | atapromise +dev/ata/chipsets/ata-serverworks.c optional ata pci | ataserverworks +dev/ata/chipsets/ata-siliconimage.c optional ata pci | atasiliconimage +dev/ata/chipsets/ata-sis.c optional ata pci | atasis +dev/ata/chipsets/ata-via.c optional ata pci | atavia dev/ata/ata-disk.c optional atadisk -dev/ata/ata-dma.c optional ata pci -dev/ata/ata-isa.c optional ata isa -dev/ata/ata-lowlevel.c optional ata -dev/ata/ata-pci.c optional ata pci -dev/ata/ata-queue.c optional ata dev/ata/ata-raid.c optional ataraid dev/ata/ata-usb.c optional atausb -dev/ata/atapi-cam.c optional atapicam dev/ata/atapi-cd.c optional atapicd dev/ata/atapi-fd.c optional atapifd dev/ata/atapi-tape.c optional atapist +dev/ata/atapi-cam.c optional atapicam +# dev/ath/ah_osdep.c optional ath_hal \ compile-with "${NORMAL_C} -I$S/dev/ath" dev/ath/ath_rate/amrr/amrr.c optional ath_rate_amrr \ 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); diff --git a/sys/modules/ata/Makefile b/sys/modules/ata/Makefile index c67ade9..0e79b1e 100644 --- a/sys/modules/ata/Makefile +++ b/sys/modules/ata/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -SUBDIR = ata +SUBDIR = atacore SUBDIR += atacard .if ${MACHINE} == "pc98" SUBDIR += atacbus diff --git a/sys/modules/ata/ata/Makefile b/sys/modules/ata/atacore/Makefile index 262984e..7b8d9e2 100644 --- a/sys/modules/ata/ata/Makefile +++ b/sys/modules/ata/atacore/Makefile @@ -3,8 +3,7 @@ .PATH: ${.CURDIR}/../../../dev/ata KMOD= ata -SRCS= ata-all.c ata-queue.c ata-lowlevel.c ata_if.c -# ata-pci.c ata-dma.c ata-chipset.c +SRCS= ata-all.c ata-lowlevel.c ata-queue.c ata_if.c SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h .include <bsd.kmod.mk> diff --git a/sys/modules/ata/atadevel/Makefile b/sys/modules/ata/atadevel/Makefile new file mode 100644 index 0000000..d87c84f --- /dev/null +++ b/sys/modules/ata/atadevel/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../../dev/ata + +KMOD= atadevel +SRCS= ata-devel.c +SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h pci_if.h +CFLAGS+=-g + +.include <bsd.kmod.mk> diff --git a/sys/modules/ata/atadevel/ata-devel.c b/sys/modules/ata/atadevel/ata-devel.c new file mode 100644 index 0000000..dbbbab2 --- /dev/null +++ b/sys/modules/ata/atadevel/ata-devel.c @@ -0,0 +1,125 @@ +/*- + * Copyright (c) 2008 S\xf8ren 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 <sys/param.h> +#include <sys/module.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/ata.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/sema.h> +#include <sys/taskqueue.h> +#include <sys/errno.h> +#include <sys/kernel.h> +#include <sys/conf.h> +#include <sys/uio.h> +#include <sys/malloc.h> +#include <sys/bus.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> + +/* prototypes */ +static int ata_devel_chipinit(device_t dev); +static int ata_devel_allocate(device_t dev); +static void ata_devel_setmode(device_t dev, int mode); + + +static int +ata_devel_probe(device_t dev) +{ + struct ata_pci_controller *ctlr = device_get_softc(dev); + + device_printf(dev, "ata_devel_probe(): PCIID=0x%08x\n", pci_get_devid(dev)); + if (pci_get_devid(dev) == 0x12345678) { + printf("test probe successful!\n"); + device_set_desc(dev, "ATA DEVEL controller"); + ctlr->chipinit = ata_devel_chipinit; + return 0; + } + return ENXIO; +} + +static int +ata_devel_chipinit(device_t dev) +{ + struct ata_pci_controller *ctlr = device_get_softc(dev); + + /* setup interrupt delivery */ + if (ata_setup_interrupt(dev, ata_generic_intr)) + return ENXIO; + + /* perform any chipset specific setups here */ + + /* setup function ptr's, in this case allocate and setmode */ + ctlr->allocate = ata_devel_allocate; + ctlr->setmode = ata_devel_setmode; + + return 0; +} + +static int +ata_devel_allocate(device_t dev) +{ + if (ata_pci_allocate(dev)) + return ENXIO; + + /* setup channel specifics here like offsets to registers etc */ + + return 0; +} + +static void +ata_devel_setmode(device_t dev, int mode) +{ + struct ata_device *atadev = device_get_softc(dev); + int error; + + 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 DEVEL chip\n", + (error) ? "FAILURE " : "", ata_mode2str(mode)); + if (!error) + atadev->mode = mode; +} + +ATA_DECLARE_DRIVER(ata_devel); diff --git a/sys/modules/ata/atapci/Makefile b/sys/modules/ata/atapci/Makefile index 00d188b..6ce854e 100644 --- a/sys/modules/ata/atapci/Makefile +++ b/sys/modules/ata/atapci/Makefile @@ -1,9 +1,12 @@ # $FreeBSD$ +SUBDIR += chipsets + .PATH: ${.CURDIR}/../../../dev/ata KMOD= atapci -SRCS= ata-pci.c ata-dma.c ata-chipset.c +SRCS= ata-pci.c ata-dma.c ata-sata.c SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h pci_if.h .include <bsd.kmod.mk> + diff --git a/sys/modules/ata/atapci/Makefile.inc b/sys/modules/ata/atapci/Makefile.inc new file mode 100644 index 0000000..265f86d --- /dev/null +++ b/sys/modules/ata/atapci/Makefile.inc @@ -0,0 +1,3 @@ +# $FreeBSD$ + +.include "../Makefile.inc" diff --git a/sys/modules/ata/atapci/chipsets/Makefile b/sys/modules/ata/atapci/chipsets/Makefile new file mode 100644 index 0000000..5468359 --- /dev/null +++ b/sys/modules/ata/atapci/chipsets/Makefile @@ -0,0 +1,5 @@ +# $FreeBSD$ + +SUBDIR += ataacard ataacerlabs ataadaptec ataahci ataamd ataati atacenatek atacypress atacyrix atahighpoint ataintel ataite atajmicron atamarvell atamicron atanational atanetcell atanvidia atapromise ataserverworks atasiliconimage atasis atavia + +.include <bsd.subdir.mk> diff --git a/sys/modules/ata/atapci/chipsets/Makefile.inc b/sys/modules/ata/atapci/chipsets/Makefile.inc new file mode 100644 index 0000000..265f86d --- /dev/null +++ b/sys/modules/ata/atapci/chipsets/Makefile.inc @@ -0,0 +1,3 @@ +# $FreeBSD$ + +.include "../Makefile.inc" diff --git a/sys/modules/ata/atapci/chipsets/ataacard/Makefile b/sys/modules/ata/atapci/chipsets/ataacard/Makefile new file mode 100644 index 0000000..28da0f2 --- /dev/null +++ b/sys/modules/ata/atapci/chipsets/ataacard/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../../../../dev/ata/chipsets + +KMOD= ataacard +SRCS= ata-acard.c +SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h pci_if.h + +.include <bsd.kmod.mk> + diff --git a/sys/modules/ata/atapci/chipsets/ataacerlabs/Makefile b/sys/modules/ata/atapci/chipsets/ataacerlabs/Makefile new file mode 100644 index 0000000..8c36db1 --- /dev/null +++ b/sys/modules/ata/atapci/chipsets/ataacerlabs/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../../../../dev/ata/chipsets + +KMOD= ataacerlabs +SRCS= ata-acerlabs.c +SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h pci_if.h + +.include <bsd.kmod.mk> + diff --git a/sys/modules/ata/atapci/chipsets/ataadaptec/Makefile b/sys/modules/ata/atapci/chipsets/ataadaptec/Makefile new file mode 100644 index 0000000..a6e22b9 --- /dev/null +++ b/sys/modules/ata/atapci/chipsets/ataadaptec/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../../../../dev/ata/chipsets + +KMOD= ataadaptec +SRCS= ata-adaptec.c +SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h pci_if.h + +.include <bsd.kmod.mk> + diff --git a/sys/modules/ata/atapci/chipsets/ataahci/Makefile b/sys/modules/ata/atapci/chipsets/ataahci/Makefile new file mode 100644 index 0000000..c21bf19 --- /dev/null +++ b/sys/modules/ata/atapci/chipsets/ataahci/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../../../../dev/ata/chipsets + +KMOD= ataahci +SRCS= ata-ahci.c +SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h pci_if.h + +.include <bsd.kmod.mk> + diff --git a/sys/modules/ata/atapci/chipsets/ataamd/Makefile b/sys/modules/ata/atapci/chipsets/ataamd/Makefile new file mode 100644 index 0000000..f1c6c02 --- /dev/null +++ b/sys/modules/ata/atapci/chipsets/ataamd/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../../../../dev/ata/chipsets + +KMOD= ataamd +SRCS= ata-amd.c +SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h pci_if.h + +.include <bsd.kmod.mk> + diff --git a/sys/modules/ata/atapci/chipsets/ataati/Makefile b/sys/modules/ata/atapci/chipsets/ataati/Makefile new file mode 100644 index 0000000..5c96e5c --- /dev/null +++ b/sys/modules/ata/atapci/chipsets/ataati/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../../../../dev/ata/chipsets + +KMOD= ataati +SRCS= ata-ati.c +SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h pci_if.h + +.include <bsd.kmod.mk> + diff --git a/sys/modules/ata/atapci/chipsets/atacenatek/Makefile b/sys/modules/ata/atapci/chipsets/atacenatek/Makefile new file mode 100644 index 0000000..90eae7a --- /dev/null +++ b/sys/modules/ata/atapci/chipsets/atacenatek/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../../../../dev/ata/chipsets + +KMOD= atacenatek +SRCS= ata-cenatek.c +SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h pci_if.h + +.include <bsd.kmod.mk> + diff --git a/sys/modules/ata/atapci/chipsets/atacypress/Makefile b/sys/modules/ata/atapci/chipsets/atacypress/Makefile new file mode 100644 index 0000000..e356ea0 --- /dev/null +++ b/sys/modules/ata/atapci/chipsets/atacypress/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../../../../dev/ata/chipsets + +KMOD= atacypress +SRCS= ata-cypress.c +SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h pci_if.h + +.include <bsd.kmod.mk> + diff --git a/sys/modules/ata/atapci/chipsets/atacyrix/Makefile b/sys/modules/ata/atapci/chipsets/atacyrix/Makefile new file mode 100644 index 0000000..405e8cf --- /dev/null +++ b/sys/modules/ata/atapci/chipsets/atacyrix/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../../../../dev/ata/chipsets + +KMOD= atacyrix +SRCS= ata-cyrix.c +SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h pci_if.h + +.include <bsd.kmod.mk> + diff --git a/sys/modules/ata/atapci/chipsets/atahighpoint/Makefile b/sys/modules/ata/atapci/chipsets/atahighpoint/Makefile new file mode 100644 index 0000000..728829c --- /dev/null +++ b/sys/modules/ata/atapci/chipsets/atahighpoint/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../../../../dev/ata/chipsets + +KMOD= atahighpoint +SRCS= ata-highpoint.c +SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h pci_if.h + +.include <bsd.kmod.mk> + diff --git a/sys/modules/ata/atapci/chipsets/ataintel/Makefile b/sys/modules/ata/atapci/chipsets/ataintel/Makefile new file mode 100644 index 0000000..676ad74 --- /dev/null +++ b/sys/modules/ata/atapci/chipsets/ataintel/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../../../../dev/ata/chipsets + +KMOD= ataintel +SRCS= ata-intel.c +SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h pci_if.h + +.include <bsd.kmod.mk> + diff --git a/sys/modules/ata/atapci/chipsets/ataite/Makefile b/sys/modules/ata/atapci/chipsets/ataite/Makefile new file mode 100644 index 0000000..f93eea4 --- /dev/null +++ b/sys/modules/ata/atapci/chipsets/ataite/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../../../../dev/ata/chipsets + +KMOD= ataite +SRCS= ata-ite.c +SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h pci_if.h + +.include <bsd.kmod.mk> + diff --git a/sys/modules/ata/atapci/chipsets/atajmicron/Makefile b/sys/modules/ata/atapci/chipsets/atajmicron/Makefile new file mode 100644 index 0000000..94b6178 --- /dev/null +++ b/sys/modules/ata/atapci/chipsets/atajmicron/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../../../../dev/ata/chipsets + +KMOD= atajmicron +SRCS= ata-jmicron.c +SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h pci_if.h + +.include <bsd.kmod.mk> + diff --git a/sys/modules/ata/atapci/chipsets/atamarvell/Makefile b/sys/modules/ata/atapci/chipsets/atamarvell/Makefile new file mode 100644 index 0000000..c828313 --- /dev/null +++ b/sys/modules/ata/atapci/chipsets/atamarvell/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../../../../dev/ata/chipsets + +KMOD= atamarvell +SRCS= ata-marvell.c +SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h pci_if.h + +.include <bsd.kmod.mk> + diff --git a/sys/modules/ata/atapci/chipsets/atamicron/Makefile b/sys/modules/ata/atapci/chipsets/atamicron/Makefile new file mode 100644 index 0000000..b002a0b --- /dev/null +++ b/sys/modules/ata/atapci/chipsets/atamicron/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../../../../dev/ata/chipsets + +KMOD= atamicron +SRCS= ata-micron.c +SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h pci_if.h + +.include <bsd.kmod.mk> + diff --git a/sys/modules/ata/atapci/chipsets/atanational/Makefile b/sys/modules/ata/atapci/chipsets/atanational/Makefile new file mode 100644 index 0000000..52cae4c --- /dev/null +++ b/sys/modules/ata/atapci/chipsets/atanational/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../../../../dev/ata/chipsets + +KMOD= atanational +SRCS= ata-national.c +SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h pci_if.h + +.include <bsd.kmod.mk> + diff --git a/sys/modules/ata/atapci/chipsets/atanetcell/Makefile b/sys/modules/ata/atapci/chipsets/atanetcell/Makefile new file mode 100644 index 0000000..dae87a0 --- /dev/null +++ b/sys/modules/ata/atapci/chipsets/atanetcell/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../../../../dev/ata/chipsets + +KMOD= atanetcell +SRCS= ata-netcell.c +SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h pci_if.h + +.include <bsd.kmod.mk> + diff --git a/sys/modules/ata/atapci/chipsets/atanvidia/Makefile b/sys/modules/ata/atapci/chipsets/atanvidia/Makefile new file mode 100644 index 0000000..452bf22 --- /dev/null +++ b/sys/modules/ata/atapci/chipsets/atanvidia/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../../../../dev/ata/chipsets + +KMOD= atanvidia +SRCS= ata-nvidia.c +SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h pci_if.h + +.include <bsd.kmod.mk> + diff --git a/sys/modules/ata/atapci/chipsets/atapromise/Makefile b/sys/modules/ata/atapci/chipsets/atapromise/Makefile new file mode 100644 index 0000000..70d46e1 --- /dev/null +++ b/sys/modules/ata/atapci/chipsets/atapromise/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../../../../dev/ata/chipsets + +KMOD= atapromise +SRCS= ata-promise.c +SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h pci_if.h + +.include <bsd.kmod.mk> + diff --git a/sys/modules/ata/atapci/chipsets/ataserverworks/Makefile b/sys/modules/ata/atapci/chipsets/ataserverworks/Makefile new file mode 100644 index 0000000..2b789a5 --- /dev/null +++ b/sys/modules/ata/atapci/chipsets/ataserverworks/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../../../../dev/ata/chipsets + +KMOD= ataserverworks +SRCS= ata-serverworks.c +SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h pci_if.h + +.include <bsd.kmod.mk> + diff --git a/sys/modules/ata/atapci/chipsets/atasiliconimage/Makefile b/sys/modules/ata/atapci/chipsets/atasiliconimage/Makefile new file mode 100644 index 0000000..ea7aca3 --- /dev/null +++ b/sys/modules/ata/atapci/chipsets/atasiliconimage/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../../../../dev/ata/chipsets + +KMOD= atasiliconimage +SRCS= ata-siliconimage.c +SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h pci_if.h + +.include <bsd.kmod.mk> + diff --git a/sys/modules/ata/atapci/chipsets/atasis/Makefile b/sys/modules/ata/atapci/chipsets/atasis/Makefile new file mode 100644 index 0000000..b601452 --- /dev/null +++ b/sys/modules/ata/atapci/chipsets/atasis/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../../../../dev/ata/chipsets + +KMOD= atasis +SRCS= ata-sis.c +SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h pci_if.h + +.include <bsd.kmod.mk> + diff --git a/sys/modules/ata/atapci/chipsets/atavia/Makefile b/sys/modules/ata/atapci/chipsets/atavia/Makefile new file mode 100644 index 0000000..75e66b0 --- /dev/null +++ b/sys/modules/ata/atapci/chipsets/atavia/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../../../../dev/ata/chipsets + +KMOD= atavia +SRCS= ata-via.c +SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h pci_if.h + +.include <bsd.kmod.mk> + |