summaryrefslogtreecommitdiffstats
path: root/sys/dev/ata/chipsets
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2010-10-18 11:30:13 +0000
committermav <mav@FreeBSD.org>2010-10-18 11:30:13 +0000
commitd5157b74694d4a37a03c0245b1681f20321cd062 (patch)
treefd926a601552c1bcf585c33dddb137654dc80a3f /sys/dev/ata/chipsets
parentc2ef20d77bba663f8ce180c864d82fee39cb3482 (diff)
downloadFreeBSD-src-d5157b74694d4a37a03c0245b1681f20321cd062.zip
FreeBSD-src-d5157b74694d4a37a03c0245b1681f20321cd062.tar.gz
Set of legacy mode SATA enchancements:
- Implement proper combined mode decoding for Intel controllers to properly identify SATA and PATA channels and associate ATA channels with SATA ports. This fixes wrong reporting and in some cases hard resets to wrong SATA ports. - Improve SATA registers support to handle hot-plug events and potentially interface errors. For ICH5/6300ESB chipsets these registers accessible via PCI config space. For later ones they may be accessible via PCI BAR(5). - For controllers not generating interrupts on hot-plug events, implement periodic status polling. Use it to detect hot-plug on Intel and VIA controllers. Same probably could also be used for Serverworks and SIS.
Diffstat (limited to 'sys/dev/ata/chipsets')
-rw-r--r--sys/dev/ata/chipsets/ata-ahci.c40
-rw-r--r--sys/dev/ata/chipsets/ata-intel.c406
-rw-r--r--sys/dev/ata/chipsets/ata-marvell.c2
-rw-r--r--sys/dev/ata/chipsets/ata-nvidia.c2
-rw-r--r--sys/dev/ata/chipsets/ata-promise.c38
-rw-r--r--sys/dev/ata/chipsets/ata-siliconimage.c42
-rw-r--r--sys/dev/ata/chipsets/ata-via.c15
7 files changed, 450 insertions, 95 deletions
diff --git a/sys/dev/ata/chipsets/ata-ahci.c b/sys/dev/ata/chipsets/ata-ahci.c
index 7496f6b..4a240d7 100644
--- a/sys/dev/ata/chipsets/ata-ahci.c
+++ b/sys/dev/ata/chipsets/ata-ahci.c
@@ -403,7 +403,7 @@ ata_ahci_status(device_t dev)
/* do we have any PHY events ? */
if (istatus & (ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC))
- ata_sata_phy_check_events(dev);
+ ata_sata_phy_check_events(dev, -1);
/* do we have a potentially hanging engine to take care of? */
/* XXX SOS what todo on NCQ */
@@ -623,6 +623,25 @@ ata_ahci_pm_read(device_t dev, int port, int reg, u_int32_t *result)
(struct ata_ahci_cmd_tab *)(ch->dma.work + ATA_AHCI_CT_OFFSET);
u_int8_t *fis = ch->dma.work + ATA_AHCI_FB_OFFSET + 0x40;
+ if (port < 0) {
+ *result = ATA_IDX_INL(ch, reg);
+ return (0);
+ }
+ if (port < ATA_PM) {
+ switch (reg) {
+ case ATA_SSTATUS:
+ reg = 0;
+ break;
+ case ATA_SERROR:
+ reg = 1;
+ break;
+ case ATA_SCONTROL:
+ reg = 2;
+ break;
+ default:
+ return (EINVAL);
+ }
+ }
bzero(ctp->cfis, 64);
ctp->cfis[0] = 0x27; /* host to device */
ctp->cfis[1] = 0x8f; /* command FIS to PM port */
@@ -649,6 +668,25 @@ ata_ahci_pm_write(device_t dev, int port, int reg, u_int32_t value)
(struct ata_ahci_cmd_tab *)(ch->dma.work + ATA_AHCI_CT_OFFSET);
int offset = ch->unit << 7;
+ if (port < 0) {
+ ATA_IDX_OUTL(ch, reg, value);
+ return (0);
+ }
+ if (port < ATA_PM) {
+ switch (reg) {
+ case ATA_SSTATUS:
+ reg = 0;
+ break;
+ case ATA_SERROR:
+ reg = 1;
+ break;
+ case ATA_SCONTROL:
+ reg = 2;
+ break;
+ default:
+ return (EINVAL);
+ }
+ }
bzero(ctp->cfis, 64);
ctp->cfis[0] = 0x27; /* host to device */
ctp->cfis[1] = 0x8f; /* command FIS to PM port */
diff --git a/sys/dev/ata/chipsets/ata-intel.c b/sys/dev/ata/chipsets/ata-intel.c
index 0f47bc7..ba602aa 100644
--- a/sys/dev/ata/chipsets/ata-intel.c
+++ b/sys/dev/ata/chipsets/ata-intel.c
@@ -59,6 +59,15 @@ static int ata_intel_old_setmode(device_t dev, int target, int mode);
static int ata_intel_new_setmode(device_t dev, int target, int mode);
static int ata_intel_sch_setmode(device_t dev, int target, int mode);
static int ata_intel_sata_getrev(device_t dev, int target);
+static int ata_intel_sata_status(device_t dev);
+static int ata_intel_sata_cscr_read(device_t dev, int port,
+ int reg, u_int32_t *result);
+static int ata_intel_sata_sidpr_read(device_t dev, int port,
+ int reg, u_int32_t *result);
+static int ata_intel_sata_cscr_write(device_t dev, int port,
+ int reg, u_int32_t result);
+static int ata_intel_sata_sidpr_write(device_t dev, int port,
+ int reg, u_int32_t result);
static int ata_intel_31244_ch_attach(device_t dev);
static int ata_intel_31244_ch_detach(device_t dev);
static int ata_intel_31244_status(device_t dev);
@@ -67,7 +76,9 @@ static void ata_intel_31244_reset(device_t dev);
/* misc defines */
#define INTEL_AHCI 1
-
+#define INTEL_ICH5 2
+#define INTEL_6CH 4
+#define INTEL_6CH2 8
/*
* Intel chipset support functions
@@ -92,74 +103,74 @@ ata_intel_probe(device_t dev)
{ 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_I82801EB_S1, 0, INTEL_ICH5, 2, ATA_SA150, "ICH5" },
+ { ATA_I82801EB_R1, 0, INTEL_ICH5, 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_I6300ESB_S1, 0, INTEL_ICH5, 2, ATA_SA150, "6300ESB" },
+ { ATA_I6300ESB_R1, 0, INTEL_ICH5, 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_S1, 0, 0, 0, ATA_SA300, "ICH7" },
+ { ATA_I82801GB_R1, 0, 0, 0, ATA_SA300, "ICH7" },
{ ATA_I82801GB_AH, 0, INTEL_AHCI, 0, ATA_SA300, "ICH7" },
- { ATA_I82801GBM_S1, 0, INTEL_AHCI, 0, ATA_SA150, "ICH7M" },
- { ATA_I82801GBM_R1, 0, INTEL_AHCI, 0, ATA_SA150, "ICH7M" },
+ { ATA_I82801GBM_S1, 0, 0, 0, ATA_SA150, "ICH7M" },
+ { ATA_I82801GBM_R1, 0, 0, 0, ATA_SA150, "ICH7M" },
{ ATA_I82801GBM_AH, 0, INTEL_AHCI, 0, ATA_SA150, "ICH7M" },
{ ATA_I63XXESB2, 0, 0, 1, ATA_UDMA5, "63XXESB2" },
- { ATA_I63XXESB2_S1, 0, INTEL_AHCI, 0, ATA_SA300, "63XXESB2" },
+ { ATA_I63XXESB2_S1, 0, 0, 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_S1, 0, INTEL_6CH, 0, ATA_SA300, "ICH8" },
+ { ATA_I82801HB_S2, 0, INTEL_6CH2, 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_S1, 0, INTEL_6CH, 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_S1, 0, INTEL_6CH, 0, ATA_SA300, "ICH9" },
+ { ATA_I82801IB_S2, 0, INTEL_6CH2, 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_S1, 0, INTEL_6CH, 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_I82801JIB_S2, 0, INTEL_6CH2, 0, ATA_SA300, "ICH10" },
+ { ATA_I82801JD_S1, 0, INTEL_6CH, 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_I82801JI_S1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" },
+ { ATA_I82801JD_S2, 0, INTEL_6CH2, 0, ATA_SA300, "ICH10" },
+ { ATA_I82801JI_S1, 0, INTEL_6CH, 0, ATA_SA300, "ICH10" },
{ ATA_I82801JI_AH, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" },
{ ATA_I82801JI_R1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" },
- { ATA_I82801JI_S2, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" },
- { ATA_5Series_S1, 0, INTEL_AHCI, 0, ATA_SA300, "5 Series/3400 Series PCH" },
- { ATA_5Series_S2, 0, INTEL_AHCI, 0, ATA_SA300, "5 Series/3400 Series PCH" },
+ { ATA_I82801JI_S2, 0, INTEL_6CH2, 0, ATA_SA300, "ICH10" },
+ { ATA_5Series_S1, 0, INTEL_6CH, 0, ATA_SA300, "5 Series/3400 Series PCH" },
+ { ATA_5Series_S2, 0, INTEL_6CH2, 0, ATA_SA300, "5 Series/3400 Series PCH" },
{ ATA_5Series_AH1, 0, INTEL_AHCI, 0, ATA_SA300, "5 Series/3400 Series PCH" },
{ ATA_5Series_AH2, 0, INTEL_AHCI, 0, ATA_SA300, "5 Series/3400 Series PCH" },
{ ATA_5Series_R1, 0, INTEL_AHCI, 0, ATA_SA300, "5 Series/3400 Series PCH" },
- { ATA_5Series_S3, 0, INTEL_AHCI, 0, ATA_SA300, "5 Series/3400 Series PCH" },
- { ATA_5Series_S4, 0, INTEL_AHCI, 0, ATA_SA300, "5 Series/3400 Series PCH" },
+ { ATA_5Series_S3, 0, INTEL_6CH2, 0, ATA_SA300, "5 Series/3400 Series PCH" },
+ { ATA_5Series_S4, 0, INTEL_6CH, 0, ATA_SA300, "5 Series/3400 Series PCH" },
{ ATA_5Series_AH3, 0, INTEL_AHCI, 0, ATA_SA300, "5 Series/3400 Series PCH" },
{ ATA_5Series_R2, 0, INTEL_AHCI, 0, ATA_SA300, "5 Series/3400 Series PCH" },
- { ATA_5Series_S5, 0, INTEL_AHCI, 0, ATA_SA300, "5 Series/3400 Series PCH" },
- { ATA_5Series_S6, 0, INTEL_AHCI, 0, ATA_SA300, "5 Series/3400 Series PCH" },
+ { ATA_5Series_S5, 0, INTEL_6CH2, 0, ATA_SA300, "5 Series/3400 Series PCH" },
+ { ATA_5Series_S6, 0, INTEL_6CH, 0, ATA_SA300, "5 Series/3400 Series PCH" },
{ ATA_5Series_AH4, 0, INTEL_AHCI, 0, ATA_SA300, "5 Series/3400 Series PCH" },
- { ATA_CPT_S1, 0, INTEL_AHCI, 0, ATA_SA300, "Cougar Point" },
- { ATA_CPT_S2, 0, INTEL_AHCI, 0, ATA_SA300, "Cougar Point" },
+ { ATA_CPT_S1, 0, INTEL_6CH, 0, ATA_SA300, "Cougar Point" },
+ { ATA_CPT_S2, 0, INTEL_6CH, 0, ATA_SA300, "Cougar Point" },
{ ATA_CPT_AH1, 0, INTEL_AHCI, 0, ATA_SA300, "Cougar Point" },
{ ATA_CPT_AH2, 0, INTEL_AHCI, 0, ATA_SA300, "Cougar Point" },
{ ATA_CPT_R1, 0, INTEL_AHCI, 0, ATA_SA300, "Cougar Point" },
{ ATA_CPT_R2, 0, INTEL_AHCI, 0, ATA_SA300, "Cougar Point" },
- { ATA_CPT_S3, 0, INTEL_AHCI, 0, ATA_SA300, "Cougar Point" },
- { ATA_CPT_S4, 0, INTEL_AHCI, 0, ATA_SA300, "Cougar Point" },
+ { ATA_CPT_S3, 0, INTEL_6CH2, 0, ATA_SA300, "Cougar Point" },
+ { ATA_CPT_S4, 0, INTEL_6CH2, 0, ATA_SA300, "Cougar Point" },
{ ATA_I31244, 0, 0, 2, ATA_SA150, "31244" },
{ ATA_ISCH, 0, 0, 1, ATA_UDMA5, "SCH" },
{ 0, 0, 0, 0, 0, 0}};
@@ -183,6 +194,8 @@ ata_intel_chipinit(device_t dev)
if (ata_setup_interrupt(dev, ata_generic_intr))
return ENXIO;
+ ctlr->chipset_data = NULL;
+
/* good old PIIX needs special treatment (not implemented) */
if (ctlr->chip->chipid == ATA_I82371FB) {
ctlr->setmode = ata_intel_old_setmode;
@@ -233,7 +246,7 @@ ata_intel_chipinit(device_t dev)
* if we have AHCI capability and AHCI or RAID mode enabled
* in BIOS we try for AHCI mode
*/
- if ((ctlr->chip->cfg1 == INTEL_AHCI) &&
+ if ((ctlr->chip->cfg1 & INTEL_AHCI) &&
(pci_read_config(dev, 0x90, 1) & 0xc0) &&
(ata_ahci_chipinit(dev) != ENXIO))
return 0;
@@ -242,7 +255,8 @@ ata_intel_chipinit(device_t dev)
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->r_rid2, RF_ACTIVE))
+ || (ctlr->chip->cfg1 & INTEL_ICH5))
ctlr->getrev = ata_intel_sata_getrev;
ctlr->setmode = ata_sata_setmode;
}
@@ -252,63 +266,142 @@ ata_intel_chipinit(device_t dev)
static int
ata_intel_ch_attach(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_ch_attach(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;
- }
+ struct ata_pci_controller *ctlr;
+ struct ata_channel *ch;
+ u_char *smap;
+ u_int map;
+
+ /* setup the usual register normal pci style */
+ if (ata_pci_ch_attach(dev))
+ return (ENXIO);
+
+ ctlr = device_get_softc(device_get_parent(dev));
+ ch = device_get_softc(dev);
+
+ /* 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;
- if (ctlr->chip->max_dma >= ATA_SA150) {
- if (ctlr->chip->cfg1 == 0 &&
- (pci_read_config(device_get_parent(dev), 0x90, 1) & 0x04) == 0)
- ch->flags |= ATA_NO_SLAVE;
- ch->flags |= ATA_SATA;
- } else if (ctlr->chip->chipid != ATA_ISCH)
- ch->flags |= ATA_CHECKS_CABLE;
- return 0;
+ ch->flags |= ATA_ALWAYS_DMASTAT;
+ if (ctlr->chip->max_dma >= ATA_SA150) {
+ smap = (u_char *)&ctlr->chipset_data + ch->unit * 2;
+ map = pci_read_config(device_get_parent(dev), 0x90, 1);
+ if (ctlr->chip->cfg1 & INTEL_ICH5) {
+ map &= 0x07;
+ if ((map & 0x04) == 0) {
+ ch->flags |= ATA_SATA;
+ ch->flags |= ATA_NO_SLAVE;
+ smap[0] = (map & 0x01) ^ ch->unit;
+ smap[1] = 0;
+ } else if ((map & 0x02) == 0 && ch->unit == 0) {
+ ch->flags |= ATA_SATA;
+ smap[0] = (map & 0x01) ? 1 : 0;
+ smap[1] = (map & 0x01) ? 0 : 1;
+ } else if ((map & 0x02) != 0 && ch->unit == 1) {
+ ch->flags |= ATA_SATA;
+ smap[0] = (map & 0x01) ? 1 : 0;
+ smap[1] = (map & 0x01) ? 0 : 1;
+ }
+ } else if (ctlr->chip->cfg1 & INTEL_6CH2) {
+ ch->flags |= ATA_SATA;
+ ch->flags |= ATA_NO_SLAVE;
+ smap[0] = (ch->unit == 0) ? 4 : 5;
+ smap[1] = 0;
+ } else {
+ map &= 0x03;
+ if (map == 0x00) {
+ ch->flags |= ATA_SATA;
+ smap[ch->unit] = (ch->unit == 0) ? 0x20 : 0x31;
+ smap[0] = (ch->unit == 0) ? 0 : 1;
+ smap[1] = (ch->unit == 0) ? 2 : 3;
+ } else if (map == 0x02 && ch->unit == 0) {
+ ch->flags |= ATA_SATA;
+ smap[0] = 0;
+ smap[1] = 2;
+ } else if (map == 0x01 && ch->unit == 1) {
+ ch->flags |= ATA_SATA;
+ smap[0] = 1;
+ smap[1] = 3;
+ }
+ }
+ if (ch->flags & ATA_SATA) {
+ if ((ctlr->chip->cfg1 & INTEL_ICH5)) {
+ ch->flags |= ATA_PERIODIC_POLL;
+ ch->hw.status = ata_intel_sata_status;
+ ch->hw.pm_read = ata_intel_sata_cscr_read;
+ ch->hw.pm_write = ata_intel_sata_cscr_write;
+ } else if (ctlr->r_res2) {
+ ch->flags |= ATA_PERIODIC_POLL;
+ ch->hw.status = ata_intel_sata_status;
+ ch->hw.pm_read = ata_intel_sata_sidpr_read;
+ ch->hw.pm_write = ata_intel_sata_sidpr_write;
+ }
+ if (ch->hw.pm_write != NULL) {
+ ata_sata_scr_write(ch, 0,
+ ATA_SERROR, 0xffffffff);
+ if ((ch->flags & ATA_NO_SLAVE) == 0) {
+ ata_sata_scr_write(ch, 1,
+ ATA_SERROR, 0xffffffff);
+ }
+ }
+ } else
+ ctlr->setmode = ata_intel_new_setmode;
+ } else if (ctlr->chip->chipid != ATA_ISCH)
+ ch->flags |= ATA_CHECKS_CABLE;
+ 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;
+ 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, pmask, timeout, devs;
+ u_char *smap;
+
+ /* In combined mode, skip SATA stuff for PATA channel. */
+ if ((ch->flags & ATA_SATA) == 0)
+ return (ata_generic_reset(dev));
+
+ /* Do hard-reset on respective SATA ports. */
+ smap = (u_char *)&ctlr->chipset_data + ch->unit * 2;
+ mask = 1 << smap[0];
+ if ((ch->flags & ATA_NO_SLAVE) == 0)
+ mask |= (1 << smap[1]);
+ 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". */
+ if (ctlr->chip->cfg1 & (INTEL_6CH | INTEL_6CH2))
+ pmask = mask << 8;
+ else
+ pmask = mask << 4;
+ for (timeout = 0; timeout < 100 ; timeout++) {
+ if (((pci_read_config(parent, 0x92, 2) & pmask) == pmask) &&
+ (ATA_IDX_INB(ch, ATA_STATUS) != 0xff))
+ break;
+ ata_udelay(10000);
+ }
- /* 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;
+ /* If any device found, do soft-reset. */
+ if (ch->hw.pm_read != NULL) {
+ devs = ata_sata_phy_reset(dev, 0, 2);
+ if ((ch->flags & ATA_NO_SLAVE) == 0)
+ devs += ata_sata_phy_reset(dev, 1, 2);
+ } else
+ devs = 1;
+ if (devs)
+ ata_generic_reset(dev);
else
- mask = (0x0001 << ch->unit);
- }
- 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);
+ ch->devices = 0;
}
static int
@@ -339,6 +432,10 @@ ata_intel_new_setmode(device_t dev, int target, int mode)
u_int8_t timings[] = { 0x00, 0x00, 0x10, 0x21, 0x23, 0x00, 0x21, 0x23 };
u_int8_t utimings[] = { 0x00, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02 };
+ /* In combined mode, skip PATA stuff for SATA channel. */
+ if (ch->flags & ATA_SATA)
+ return (ata_sata_setmode(dev, target, mode));
+
mode = min(mode, ctlr->chip->max_dma);
if (ata_dma_check_80pin && mode > ATA_UDMA2 &&
!(reg54 & (0x10 << devno))) {
@@ -421,12 +518,145 @@ static int
ata_intel_sata_getrev(device_t dev, int target)
{
struct ata_channel *ch = device_get_softc(dev);
- int devno = (ch->unit << 1) + target;
+ uint32_t status;
- /* set ATA_SSTATUS register offset */
- ATA_IDX_OUTL(ch, ATA_IDX_ADDR, devno * 0x100);
- /* query SATA STATUS for the speed */
- return ((ATA_IDX_INL(ch, ATA_IDX_DATA) & 0x0f0) >> 4);
+ if (ata_sata_scr_read(ch, target, ATA_SSTATUS, &status) == 0)
+ return ((status & 0x0f0) >> 4);
+ return (0xff);
+}
+
+static int
+ata_intel_sata_status(device_t dev)
+{
+ struct ata_channel *ch = device_get_softc(dev);
+
+ ata_sata_phy_check_events(dev, 0);
+ if ((ch->flags & ATA_NO_SLAVE) == 0)
+ ata_sata_phy_check_events(dev, 1);
+
+ return ata_pci_status(dev);
+}
+
+static int
+ata_intel_sata_cscr_read(device_t dev, int port, int reg, u_int32_t *result)
+{
+ struct ata_pci_controller *ctlr;
+ struct ata_channel *ch;
+ device_t parent;
+ u_char *smap;
+
+ parent = device_get_parent(dev);
+ ctlr = device_get_softc(parent);
+ ch = device_get_softc(dev);
+ smap = (u_char *)&ctlr->chipset_data + ch->unit * 2;
+ port = (port == 1) ? 1 : 0;
+ switch (reg) {
+ case ATA_SSTATUS:
+ reg = 0;
+ break;
+ case ATA_SERROR:
+ reg = 1;
+ break;
+ case ATA_SCONTROL:
+ reg = 2;
+ break;
+ default:
+ return (EINVAL);
+ }
+ pci_write_config(parent, 0xa0,
+ 0x50 + smap[port] * 0x10 + reg * 4, 4);
+ *result = pci_read_config(parent, 0xa4, 4);
+ return (0);
+}
+
+static int
+ata_intel_sata_sidpr_read(device_t dev, int port, int reg, u_int32_t *result)
+{
+ struct ata_pci_controller *ctlr;
+ struct ata_channel *ch;
+ device_t parent;
+
+ parent = device_get_parent(dev);
+ ctlr = device_get_softc(parent);
+ ch = device_get_softc(dev);
+ port = (port == 1) ? 1 : 0;
+ switch (reg) {
+ case ATA_SSTATUS:
+ reg = 0;
+ break;
+ case ATA_SCONTROL:
+ reg = 1;
+ break;
+ case ATA_SERROR:
+ reg = 2;
+ break;
+ default:
+ return (EINVAL);
+ }
+ ATA_IDX_OUTL(ch, ATA_IDX_ADDR, ((ch->unit * 2 + port) << 8) + reg);
+ *result = ATA_IDX_INL(ch, ATA_IDX_DATA);
+ return (0);
+}
+
+static int
+ata_intel_sata_cscr_write(device_t dev, int port, int reg, u_int32_t value)
+{
+ struct ata_pci_controller *ctlr;
+ struct ata_channel *ch;
+ device_t parent;
+ u_char *smap;
+
+ parent = device_get_parent(dev);
+ ctlr = device_get_softc(parent);
+ ch = device_get_softc(dev);
+ smap = (u_char *)&ctlr->chipset_data + ch->unit * 2;
+ port = (port == 1) ? 1 : 0;
+ switch (reg) {
+ case ATA_SSTATUS:
+ reg = 0;
+ break;
+ case ATA_SERROR:
+ reg = 1;
+ break;
+ case ATA_SCONTROL:
+ reg = 2;
+ break;
+ default:
+ return (EINVAL);
+ }
+ pci_write_config(parent, 0xa0,
+ 0x50 + smap[port] * 0x10 + reg * 4, 4);
+ pci_write_config(parent, 0xa4, value, 4);
+ return (0);
+}
+
+static int
+ata_intel_sata_sidpr_write(device_t dev, int port, int reg, u_int32_t value)
+{
+ struct ata_pci_controller *ctlr;
+ struct ata_channel *ch;
+ device_t parent;
+
+ parent = device_get_parent(dev);
+ ctlr = device_get_softc(parent);
+ ch = device_get_softc(dev);
+ port = (port == 1) ? 1 : 0;
+ switch (reg) {
+ case ATA_SSTATUS:
+ reg = 0;
+ break;
+ case ATA_SCONTROL:
+ reg = 1;
+ break;
+ case ATA_SERROR:
+ reg = 2;
+ break;
+ default:
+ return (EINVAL);
+ }
+ ATA_IDX_OUTL(ch, ATA_IDX_ADDR, ((ch->unit * 2 + port) << 8) + reg);
+ ATA_IDX_OUTL(ch, ATA_IDX_DATA, value);
+ return (0);
}
static int
@@ -492,7 +722,7 @@ static int
ata_intel_31244_status(device_t dev)
{
/* do we have any PHY events ? */
- ata_sata_phy_check_events(dev);
+ ata_sata_phy_check_events(dev, -1);
/* any drive action to take care of ? */
return ata_pci_status(dev);
diff --git a/sys/dev/ata/chipsets/ata-marvell.c b/sys/dev/ata/chipsets/ata-marvell.c
index 371d951..eb6414e 100644
--- a/sys/dev/ata/chipsets/ata-marvell.c
+++ b/sys/dev/ata/chipsets/ata-marvell.c
@@ -374,7 +374,7 @@ ata_marvell_edma_status(device_t dev)
ATA_OUTL(ctlr->r_res1, 0x02008 + ATA_MV_EDMA_BASE(ch), 0x0);
/* do we have any PHY events ? */
- ata_sata_phy_check_events(dev);
+ ata_sata_phy_check_events(dev, -1);
}
/* do we have any device action ? */
diff --git a/sys/dev/ata/chipsets/ata-nvidia.c b/sys/dev/ata/chipsets/ata-nvidia.c
index 344e5a4..b1da6f0 100644
--- a/sys/dev/ata/chipsets/ata-nvidia.c
+++ b/sys/dev/ata/chipsets/ata-nvidia.c
@@ -281,7 +281,7 @@ ata_nvidia_status(device_t dev)
/* do we have any PHY events ? */
if (istatus & (0x0c << shift))
- ata_sata_phy_check_events(dev);
+ ata_sata_phy_check_events(dev, -1);
/* clear interrupt(s) */
if (ctlr->chip->cfg1 & NVQ)
diff --git a/sys/dev/ata/chipsets/ata-promise.c b/sys/dev/ata/chipsets/ata-promise.c
index 8a7bceb..622352b 100644
--- a/sys/dev/ata/chipsets/ata-promise.c
+++ b/sys/dev/ata/chipsets/ata-promise.c
@@ -830,6 +830,25 @@ ata_promise_mio_pm_read(device_t dev, int port, int reg, u_int32_t *result)
struct ata_channel *ch = device_get_softc(dev);
int timeout = 0;
+ if (port < 0) {
+ *result = ATA_IDX_INL(ch, reg);
+ return (0);
+ }
+ if (port < ATA_PM) {
+ switch (reg) {
+ case ATA_SSTATUS:
+ reg = 0;
+ break;
+ case ATA_SERROR:
+ reg = 1;
+ break;
+ case ATA_SCONTROL:
+ reg = 2;
+ break;
+ default:
+ return (EINVAL);
+ }
+ }
/* set portmultiplier port */
ATA_OUTB(ctlr->r_res2, 0x4e8 + (ch->unit << 8), 0x0f);
@@ -862,6 +881,25 @@ ata_promise_mio_pm_write(device_t dev, int port, int reg, u_int32_t value)
struct ata_channel *ch = device_get_softc(dev);
int timeout = 0;
+ if (port < 0) {
+ ATA_IDX_OUTL(ch, reg, value);
+ return (0);
+ }
+ if (port < ATA_PM) {
+ switch (reg) {
+ case ATA_SSTATUS:
+ reg = 0;
+ break;
+ case ATA_SERROR:
+ reg = 1;
+ break;
+ case ATA_SCONTROL:
+ reg = 2;
+ break;
+ default:
+ return (EINVAL);
+ }
+ }
/* set portmultiplier port */
ATA_OUTB(ctlr->r_res2, 0x4e8 + (ch->unit << 8), 0x0f);
diff --git a/sys/dev/ata/chipsets/ata-siliconimage.c b/sys/dev/ata/chipsets/ata-siliconimage.c
index f9b90f6..fa7619c 100644
--- a/sys/dev/ata/chipsets/ata-siliconimage.c
+++ b/sys/dev/ata/chipsets/ata-siliconimage.c
@@ -354,7 +354,7 @@ ata_sii_status(device_t dev)
/* 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);
+ ata_sata_phy_check_events(dev, -1);
if (ATA_INL(ctlr->r_res2, 0xa0 + offset1) & 0x00000800)
return ata_pci_status(dev);
@@ -510,7 +510,7 @@ ata_siiprb_status(device_t dev)
u_int32_t istatus = ATA_INL(ctlr->r_res2, 0x1008 + offset);
/* do we have any PHY events ? */
- ata_sata_phy_check_events(dev);
+ ata_sata_phy_check_events(dev, -1);
/* clear interrupt(s) */
ATA_OUTL(ctlr->r_res2, 0x1008 + offset, istatus);
@@ -700,6 +700,25 @@ ata_siiprb_pm_read(device_t dev, int port, int reg, u_int32_t *result)
struct ata_siiprb_command *prb = (struct ata_siiprb_command *)ch->dma.work;
int offset = ch->unit * 0x2000;
+ if (port < 0) {
+ *result = ATA_IDX_INL(ch, reg);
+ return (0);
+ }
+ if (port < ATA_PM) {
+ switch (reg) {
+ case ATA_SSTATUS:
+ reg = 0;
+ break;
+ case ATA_SERROR:
+ reg = 1;
+ break;
+ case ATA_SCONTROL:
+ reg = 2;
+ break;
+ default:
+ return (EINVAL);
+ }
+ }
bzero(prb, sizeof(struct ata_siiprb_command));
prb->fis[0] = 0x27; /* host to device */
prb->fis[1] = 0x8f; /* command FIS to PM port */
@@ -724,6 +743,25 @@ ata_siiprb_pm_write(device_t dev, int port, int reg, u_int32_t value)
struct ata_siiprb_command *prb = (struct ata_siiprb_command *)ch->dma.work;
int offset = ch->unit * 0x2000;
+ if (port < 0) {
+ ATA_IDX_OUTL(ch, reg, value);
+ return (0);
+ }
+ if (port < ATA_PM) {
+ switch (reg) {
+ case ATA_SSTATUS:
+ reg = 0;
+ break;
+ case ATA_SERROR:
+ reg = 1;
+ break;
+ case ATA_SCONTROL:
+ reg = 2;
+ break;
+ default:
+ return (EINVAL);
+ }
+ }
bzero(prb, sizeof(struct ata_siiprb_command));
prb->fis[0] = 0x27; /* host to device */
prb->fis[1] = 0x8f; /* command FIS to PM port */
diff --git a/sys/dev/ata/chipsets/ata-via.c b/sys/dev/ata/chipsets/ata-via.c
index 8d87f31..284a892 100644
--- a/sys/dev/ata/chipsets/ata-via.c
+++ b/sys/dev/ata/chipsets/ata-via.c
@@ -56,6 +56,7 @@ static int ata_via_chipinit(device_t dev);
static int ata_via_ch_attach(device_t dev);
static int ata_via_ch_detach(device_t dev);
static void ata_via_reset(device_t dev);
+static int ata_via_status(device_t dev);
static int ata_via_old_setmode(device_t dev, int target, int mode);
static void ata_via_southbridge_fixup(device_t dev);
static int ata_via_new_setmode(device_t dev, int target, int mode);
@@ -249,11 +250,13 @@ ata_via_ch_attach(device_t dev)
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->hw.status = ata_via_status;
ch->flags |= ATA_NO_SLAVE;
ch->flags |= ATA_SATA;
+ ch->flags |= ATA_PERIODIC_POLL;
+
+ ata_sata_scr_write(ch, -1, ATA_SERROR, 0xffffffff);
- /* XXX SOS PHY hotplug handling missing in VIA chip ?? */
- /* XXX SOS unknown how to enable PHY state change interrupt */
return 0;
}
@@ -299,6 +302,14 @@ ata_via_reset(device_t dev)
}
static int
+ata_via_status(device_t dev)
+{
+
+ ata_sata_phy_check_events(dev, -1);
+ return (ata_pci_status(dev));
+}
+
+static int
ata_via_new_setmode(device_t dev, int target, int mode)
{
device_t parent = device_get_parent(dev);
OpenPOWER on IntegriCloud