summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/ata/ata-pci.c15
-rw-r--r--sys/dev/ata/ata-pci.h8
-rw-r--r--sys/dev/ata/ata-sata.c177
-rw-r--r--sys/dev/ata/chipsets/ata-ahci.c159
-rw-r--r--sys/dev/ata/chipsets/ata-intel.c2
-rw-r--r--sys/dev/ata/chipsets/ata-jmicron.c28
-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.c4
-rw-r--r--sys/dev/ata/chipsets/ata-siliconimage.c4
-rw-r--r--sys/dev/ata/chipsets/ata-sis.c2
-rw-r--r--sys/dev/ata/chipsets/ata-via.c2
12 files changed, 300 insertions, 105 deletions
diff --git a/sys/dev/ata/ata-pci.c b/sys/dev/ata/ata-pci.c
index 97261d2..5fe26a8 100644
--- a/sys/dev/ata/ata-pci.c
+++ b/sys/dev/ata/ata-pci.c
@@ -584,22 +584,35 @@ ata_pcichannel_detach(device_t dev)
static int
ata_pcichannel_suspend(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->attached)
return (0);
- return ata_suspend(dev);
+ if ((error = ata_suspend(dev)))
+ return (error);
+
+ if (ctlr->ch_suspend != NULL && (error = ctlr->ch_suspend(dev)))
+ return (error);
+
+ return (0);
}
static int
ata_pcichannel_resume(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->attached)
return (0);
+ if (ctlr->ch_resume != NULL && (error = ctlr->ch_resume(dev)))
+ return (error);
+
return ata_resume(dev);
}
diff --git a/sys/dev/ata/ata-pci.h b/sys/dev/ata/ata-pci.h
index 27a341e..9e31bc7 100644
--- a/sys/dev/ata/ata-pci.h
+++ b/sys/dev/ata/ata-pci.h
@@ -57,6 +57,8 @@ struct ata_pci_controller {
int (*resume)(device_t);
int (*ch_attach)(device_t);
int (*ch_detach)(device_t);
+ int (*ch_suspend)(device_t);
+ int (*ch_resume)(device_t);
int (*locking)(device_t, int);
void (*reset)(device_t);
void (*setmode)(device_t, int);
@@ -443,7 +445,9 @@ int ata_mode2idx(int mode);
/* global prototypes ata-sata.c */
void ata_sata_phy_check_events(device_t dev);
-int ata_sata_phy_reset(device_t dev);
+int ata_sata_scr_read(struct ata_channel *ch, int port, int reg, uint32_t *val);
+int ata_sata_scr_write(struct ata_channel *ch, int port, int reg, uint32_t val);
+int ata_sata_phy_reset(device_t dev, int port, int quick);
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);
@@ -452,6 +456,8 @@ void ata_pm_identify(device_t dev);
int ata_ahci_chipinit(device_t);
int ata_ahci_ch_attach(device_t dev);
int ata_ahci_ch_detach(device_t dev);
+int ata_ahci_ch_suspend(device_t dev);
+int ata_ahci_ch_resume(device_t dev);
void ata_ahci_reset(device_t dev);
int ata_marvell_edma_chipinit(device_t);
int ata_sii_chipinit(device_t);
diff --git a/sys/dev/ata/ata-sata.c b/sys/dev/ata/ata-sata.c
index 642a94e..1151ca1 100644
--- a/sys/dev/ata/ata-sata.c
+++ b/sys/dev/ata/ata-sata.c
@@ -73,59 +73,141 @@ ata_sata_phy_check_events(device_t dev)
}
}
+int
+ata_sata_scr_read(struct ata_channel *ch, int port, int reg, uint32_t *val)
+{
+ int r;
+
+ if (port < 0) {
+ *val = ATA_IDX_INL(ch, reg);
+ return (0);
+ } else {
+ switch (reg) {
+ case ATA_SSTATUS:
+ r = 0;
+ break;
+ case ATA_SERROR:
+ r = 1;
+ break;
+ case ATA_SCONTROL:
+ r = 2;
+ break;
+ default:
+ return (EINVAL);
+ }
+ return (ch->hw.pm_read(ch->dev, port, r, val));
+ }
+}
+
+int
+ata_sata_scr_write(struct ata_channel *ch, int port, int reg, uint32_t val)
+{
+ int r;
+
+ if (port < 0) {
+ ATA_IDX_OUTL(ch, reg, val);
+ return (0);
+ } else {
+ switch (reg) {
+ case ATA_SERROR:
+ r = 1;
+ break;
+ case ATA_SCONTROL:
+ r = 2;
+ break;
+ default:
+ return (EINVAL);
+ }
+ return (ch->hw.pm_write(ch->dev, port, r, val));
+ }
+}
+
static int
-ata_sata_connect(struct ata_channel *ch)
+ata_sata_connect(struct ata_channel *ch, int port)
{
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 (ata_sata_scr_read(ch, port, ATA_SSTATUS, &status))
+ return (0);
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);
+ if (bootverbose) {
+ if (port < 0) {
+ device_printf(ch->dev, "SATA connect timeout status=%08x\n",
+ status);
+ } else {
+ device_printf(ch->dev, "p%d: SATA connect timeout status=%08x\n",
+ port, status);
+ }
+ }
return 0;
}
- if (bootverbose)
- device_printf(ch->dev, "SATA connect time=%dms\n", timeout * 10);
+ if (bootverbose) {
+ if (port < 0) {
+ device_printf(ch->dev, "SATA connect time=%dms status=%08x\n",
+ timeout * 10, status);
+ } else {
+ device_printf(ch->dev, "p%d: SATA connect time=%dms status=%08x\n",
+ port, timeout * 10, status);
+ }
+ }
/* clear SATA error register */
- ATA_IDX_OUTL(ch, ATA_SERROR, ATA_IDX_INL(ch, ATA_SERROR));
+ ata_sata_scr_write(ch, port, ATA_SERROR, 0xffffffff);
return 1;
}
int
-ata_sata_phy_reset(device_t dev)
+ata_sata_phy_reset(device_t dev, int port, int quick)
{
struct ata_channel *ch = device_get_softc(dev);
int loop, retry;
+ uint32_t val;
- if ((ATA_IDX_INL(ch, ATA_SCONTROL) & ATA_SC_DET_MASK) == ATA_SC_DET_IDLE)
- return ata_sata_connect(ch);
+ if (quick) {
+ if (ata_sata_scr_read(ch, port, ATA_SCONTROL, &val))
+ return (0);
+ if ((val & ATA_SC_DET_MASK) == ATA_SC_DET_IDLE)
+ return ata_sata_connect(ch, port);
+ }
+ if (bootverbose) {
+ if (port < 0) {
+ device_printf(dev, "hardware reset ...\n");
+ } else {
+ device_printf(dev, "p%d: hardware reset ...\n", port);
+ }
+ }
for (retry = 0; retry < 10; retry++) {
for (loop = 0; loop < 10; loop++) {
- ATA_IDX_OUTL(ch, ATA_SCONTROL, ATA_SC_DET_RESET);
+ if (ata_sata_scr_write(ch, port, ATA_SCONTROL, ATA_SC_DET_RESET))
+ return (0);
ata_udelay(100);
- if ((ATA_IDX_INL(ch, ATA_SCONTROL) & ATA_SC_DET_MASK) ==
- ATA_SC_DET_RESET)
+ if (ata_sata_scr_read(ch, port, ATA_SCONTROL, &val))
+ return (0);
+ if ((val & 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);
+ if (ata_sata_scr_write(ch, port, ATA_SCONTROL,
+ ATA_SC_DET_IDLE |
+ ATA_SC_IPM_DIS_PARTIAL |
+ ATA_SC_IPM_DIS_SLUMBER))
+ return (0);
ata_udelay(100);
- if ((ATA_IDX_INL(ch, ATA_SCONTROL) & ATA_SC_DET_MASK) == 0)
- return ata_sata_connect(ch);
+ if (ata_sata_scr_read(ch, port, ATA_SCONTROL, &val))
+ return (0);
+ if ((val & ATA_SC_DET_MASK) == 0)
+ return ata_sata_connect(ch, port);
}
}
return 0;
@@ -237,14 +319,27 @@ ata_pm_identify(device_t dev)
/* chip specific quirks */
switch (pm_chipid) {
case 0x37261095:
- /* Some of these bogusly reports 6 ports */
+ /* This PM declares 6 ports, while only 5 of them are real.
+ * Port 5 is enclosure management bridge port, which has implementation
+ * problems, causing probe faults. Hide it for now. */
+ device_printf(dev, "SiI 3726 (rev=%x) Port Multiplier with %d (5) ports\n",
+ pm_revision, pm_ports);
pm_ports = 5;
- device_printf(dev, "SiI 3726 r%x Portmultiplier with %d ports\n",
+ break;
+
+ case 0x47261095:
+ /* This PM declares 7 ports, while only 5 of them are real.
+ * Port 5 is some fake "Config Disk" with 640 sectors size,
+ * port 6 is enclosure management bridge port.
+ * Both fake ports has implementation problems, causing
+ * probe faults. Hide them for now. */
+ device_printf(dev, "SiI 4726 (rev=%x) Port Multiplier with %d (5) ports\n",
pm_revision, pm_ports);
+ pm_ports = 5;
break;
default:
- device_printf(dev, "Portmultiplier (id=%08x rev=%x) with %d ports\n",
+ device_printf(dev, "Port Multiplier (id=%08x rev=%x) with %d ports\n",
pm_chipid, pm_revision, pm_ports);
}
@@ -253,41 +348,17 @@ ata_pm_identify(device_t dev)
/* reset all ports and register if anything connected */
for (port=0; port < pm_ports; port++) {
- u_int32_t signature, status;
- int timeout;
+ u_int32_t signature;
- 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);
+ if (!ata_sata_phy_reset(dev, port, 1))
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);
+ /*
+ * XXX: I have no idea how to properly wait for PMP port hardreset
+ * completion. Without this delay soft reset does not completes
+ * successfully.
+ */
+ DELAY(1000000);
signature = ch->hw.softreset(dev, port);
diff --git a/sys/dev/ata/chipsets/ata-ahci.c b/sys/dev/ata/chipsets/ata-ahci.c
index 991d2ad..9e78132 100644
--- a/sys/dev/ata/chipsets/ata-ahci.c
+++ b/sys/dev/ata/chipsets/ata-ahci.c
@@ -59,10 +59,16 @@ 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 int ata_ahci_hardreset(device_t dev, int port, uint32_t *signature);
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);
static void ata_ahci_dmainit(device_t dev);
+static void ata_ahci_start(device_t dev);
+static void ata_ahci_stop(device_t dev);
+static void ata_ahci_clo(device_t dev);
+static void ata_ahci_start_fr(device_t dev);
+static void ata_ahci_stop_fr(device_t dev);
/*
* AHCI v1.x compliant SATA chipset support functions
@@ -131,6 +137,8 @@ ata_ahci_chipinit(device_t dev)
ctlr->reset = ata_ahci_reset;
ctlr->ch_attach = ata_ahci_ch_attach;
ctlr->ch_detach = ata_ahci_ch_detach;
+ ctlr->ch_suspend = ata_ahci_ch_suspend;
+ ctlr->ch_resume = ata_ahci_ch_resume;
ctlr->setmode = ata_sata_setmode;
ctlr->suspend = ata_ahci_suspend;
ctlr->resume = ata_ahci_ctlr_reset;
@@ -192,7 +200,6 @@ ata_ahci_suspend(device_t dev)
return 0;
}
-
int
ata_ahci_ch_attach(device_t dev)
{
@@ -220,12 +227,22 @@ ata_ahci_ch_attach(device_t dev)
ch->hw.pm_read = ata_ahci_pm_read;
ch->hw.pm_write = ata_ahci_pm_write;
+ ata_ahci_ch_resume(dev);
return 0;
}
int
ata_ahci_ch_detach(device_t dev)
{
+
+ ata_ahci_ch_suspend(dev);
+ ata_dmafini(dev);
+ return (0);
+}
+
+int
+ata_ahci_ch_suspend(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;
@@ -233,6 +250,8 @@ ata_ahci_ch_detach(device_t dev)
/* Disable port interrupts. */
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IE + offset, 0);
/* Reset command register. */
+ ata_ahci_stop(dev);
+ ata_ahci_stop_fr(dev);
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, 0);
/* Allow everything including partial and slumber modes. */
@@ -243,7 +262,35 @@ ata_ahci_ch_detach(device_t dev)
/* Disable PHY. */
ATA_IDX_OUTL(ch, ATA_SCONTROL, ATA_SC_DET_DISABLE);
- ata_dmafini(dev);
+ return (0);
+}
+
+int
+ata_ahci_ch_resume(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ uint64_t work;
+ int offset = ch->unit << 7;
+
+ /* Disable port interrupts */
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IE + offset, 0);
+
+ /* 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);
+
+ /* 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_start_fr(dev);
+ ata_ahci_start(dev);
+
return (0);
}
@@ -366,9 +413,6 @@ ata_ahci_begin_transaction(struct ata_request *request)
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));
@@ -465,9 +509,6 @@ ata_ahci_issue_cmd(device_t dev, u_int16_t flags, int timeout)
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);
@@ -480,7 +521,7 @@ ata_ahci_issue_cmd(device_t dev, u_int16_t flags, int timeout)
/* clear interrupts */
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IS + offset,
- ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset));
+ ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset));
if (timeout && (count >= timeout)) {
if (bootverbose) {
@@ -559,7 +600,7 @@ ata_ahci_stop(device_t dev)
/* 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));
+ cmd & ~ATA_AHCI_P_CMD_ST);
/* XXX SOS this is not entirely wrong */
timeout = 0;
@@ -617,10 +658,47 @@ ata_ahci_start(device_t dev)
/* 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) |
+ cmd | ATA_AHCI_P_CMD_ST |
(ch->devices & ATA_PORTMULTIPLIER ? ATA_AHCI_P_CMD_PMA : 0));
}
+static void
+ata_ahci_stop_fr(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);
+
+ timeout = 0;
+ do {
+ DELAY(1000);
+ if (timeout++ > 1000) {
+ device_printf(dev, "stopping AHCI FR engine failed\n");
+ break;
+ }
+ }
+ while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) & ATA_AHCI_P_CMD_FR);
+}
+
+static void
+ata_ahci_start_fr(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;
+
+ /* start FIS reception 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);
+}
+
static int
ata_ahci_wait_ready(device_t dev, int t)
{
@@ -628,13 +706,14 @@ ata_ahci_wait_ready(device_t dev, int t)
struct ata_channel *ch = device_get_softc(dev);
int offset = ch->unit << 7;
int timeout = 0;
+ uint32_t val;
- while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + offset) &
+ while ((val = ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + offset)) &
(ATA_S_BUSY | ATA_S_DRQ)) {
DELAY(1000);
if (timeout++ > t) {
- device_printf(dev, "port is not ready (timeout %dms)\n", t);
- return (-1);
+ device_printf(dev, "port is not ready (timeout %dms) tfd = %08x\n", t, val);
+ return (EBUSY);
}
}
if (bootverbose)
@@ -642,6 +721,28 @@ ata_ahci_wait_ready(device_t dev, int t)
return (0);
}
+static int
+ata_ahci_hardreset(device_t dev, int port, uint32_t *signature)
+{
+ 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;
+
+ *signature = 0xffffffff;
+ ata_ahci_stop(dev);
+ /* Reset port */
+ if (!ata_sata_phy_reset(dev, port, 0))
+ return (ENOENT);
+ /* Wait for clearing busy status. */
+ if (ata_ahci_wait_ready(dev, 10000)) {
+ device_printf(dev, "hardware reset timeout\n");
+ return (EBUSY);
+ }
+ *signature = ATA_INL(ctlr->r_res2, ATA_AHCI_P_SIG + offset);
+ ata_ahci_start(dev);
+ return (0);
+}
+
static u_int32_t
ata_ahci_softreset(device_t dev, int port)
{
@@ -679,9 +780,9 @@ ata_ahci_softreset(device_t dev, int port)
ctp->cfis[1] = port & 0x0f;
//ctp->cfis[7] = ATA_D_LBA | ATA_D_IBM;
ctp->cfis[15] = ATA_A_4BIT;
- ata_ahci_issue_cmd(dev, 0, 1000);
+ ata_ahci_issue_cmd(dev, 0, 3000);
- if (ata_ahci_wait_ready(dev, 1000)) {
+ if (ata_ahci_wait_ready(dev, 0)) {
device_printf(dev, "software reset clear timeout\n");
return (-1);
}
@@ -694,7 +795,6 @@ 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 signature;
int offset = ch->unit << 7;
@@ -704,25 +804,7 @@ ata_ahci_reset(device_t dev)
/* Disable port interrupts */
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IE + offset, 0);
- /* 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);
-
- /* 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_stop(dev);
-
- /* enable FIS based switching */
- //ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FBS + offset, 0x00000003);
-
- if (!ata_sata_phy_reset(dev)) {
+ if (ata_ahci_hardreset(dev, -1, &signature)) {
if (bootverbose)
device_printf(dev, "AHCI reset done: phy reset found no device\n");
ch->devices = 0;
@@ -733,8 +815,6 @@ ata_ahci_reset(device_t dev)
return;
}
- ata_ahci_start(dev);
-
/* 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 |
@@ -743,9 +823,6 @@ ata_ahci_reset(device_t dev)
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));
- /* Wait for initial TFD from device. */
- ata_ahci_wait_ready(dev, 10000);
-
/* 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);
diff --git a/sys/dev/ata/chipsets/ata-intel.c b/sys/dev/ata/chipsets/ata-intel.c
index 8bd2f03..cae1778 100644
--- a/sys/dev/ata/chipsets/ata-intel.c
+++ b/sys/dev/ata/chipsets/ata-intel.c
@@ -517,7 +517,7 @@ ata_intel_31244_tf_write(struct ata_request *request)
static void
ata_intel_31244_reset(device_t dev)
{
- if (ata_sata_phy_reset(dev))
+ if (ata_sata_phy_reset(dev, -1, 1))
ata_generic_reset(dev);
}
diff --git a/sys/dev/ata/chipsets/ata-jmicron.c b/sys/dev/ata/chipsets/ata-jmicron.c
index 301b99b..b1e7aef 100644
--- a/sys/dev/ata/chipsets/ata-jmicron.c
+++ b/sys/dev/ata/chipsets/ata-jmicron.c
@@ -55,6 +55,8 @@ __FBSDID("$FreeBSD$");
static int ata_jmicron_chipinit(device_t dev);
static int ata_jmicron_ch_attach(device_t dev);
static int ata_jmicron_ch_detach(device_t dev);
+static int ata_jmicron_ch_suspend(device_t dev);
+static int ata_jmicron_ch_resume(device_t dev);
static void ata_jmicron_reset(device_t dev);
static void ata_jmicron_setmode(device_t dev, int mode);
@@ -127,6 +129,8 @@ ata_jmicron_chipinit(device_t dev)
ctlr->ch_attach = ata_jmicron_ch_attach;
ctlr->ch_detach = ata_jmicron_ch_detach;
+ ctlr->ch_suspend = ata_jmicron_ch_suspend;
+ ctlr->ch_resume = ata_jmicron_ch_resume;
ctlr->reset = ata_jmicron_reset;
ctlr->setmode = ata_jmicron_setmode;
@@ -173,6 +177,30 @@ ata_jmicron_ch_detach(device_t dev)
return (error);
}
+static int
+ata_jmicron_ch_suspend(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 = 0;
+
+ if (ch->unit < ctlr->chip->cfg1)
+ error = ata_ahci_ch_suspend(dev);
+ return error;
+}
+
+static int
+ata_jmicron_ch_resume(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 = 0;
+
+ if (ch->unit < ctlr->chip->cfg1)
+ error = ata_ahci_ch_resume(dev);
+ return (error);
+}
+
static void
ata_jmicron_reset(device_t dev)
{
diff --git a/sys/dev/ata/chipsets/ata-marvell.c b/sys/dev/ata/chipsets/ata-marvell.c
index a0fa485..361bc5b 100644
--- a/sys/dev/ata/chipsets/ata-marvell.c
+++ b/sys/dev/ata/chipsets/ata-marvell.c
@@ -503,7 +503,7 @@ ata_marvell_edma_reset(device_t dev)
ATA_OUTL(ctlr->r_res1, 0x0200c + ATA_MV_EDMA_BASE(ch), ~0x0);
/* enable channel and test for devices */
- if (ata_sata_phy_reset(dev))
+ if (ata_sata_phy_reset(dev, -1, 1))
ata_generic_reset(dev);
/* enable EDMA machinery */
diff --git a/sys/dev/ata/chipsets/ata-nvidia.c b/sys/dev/ata/chipsets/ata-nvidia.c
index 7e03afa..9e1de81 100644
--- a/sys/dev/ata/chipsets/ata-nvidia.c
+++ b/sys/dev/ata/chipsets/ata-nvidia.c
@@ -249,7 +249,7 @@ ata_nvidia_status(device_t dev)
static void
ata_nvidia_reset(device_t dev)
{
- if (ata_sata_phy_reset(dev))
+ if (ata_sata_phy_reset(dev, -1, 1))
ata_generic_reset(dev);
}
diff --git a/sys/dev/ata/chipsets/ata-promise.c b/sys/dev/ata/chipsets/ata-promise.c
index 3856535..6b34596 100644
--- a/sys/dev/ata/chipsets/ata-promise.c
+++ b/sys/dev/ata/chipsets/ata-promise.c
@@ -769,7 +769,7 @@ ata_promise_mio_reset(device_t dev)
if ((ctlr->chip->cfg2 == PR_SATA) ||
((ctlr->chip->cfg2 == PR_CMBO) && (ch->unit < 2))) {
- if (ata_sata_phy_reset(dev))
+ if (ata_sata_phy_reset(dev, -1, 1))
ata_generic_reset(dev);
/* reset and enable plug/unplug intr */
@@ -805,7 +805,7 @@ ata_promise_mio_reset(device_t dev)
(ATA_INL(ctlr->r_res2, 0x414 + (ch->unit << 8)) &
~0x00000003) | 0x00000001);
- if (ata_sata_phy_reset(dev)) {
+ if (ata_sata_phy_reset(dev, -1, 1)) {
u_int32_t signature = ch->hw.softreset(dev, ATA_PM);
if (1 | bootverbose)
diff --git a/sys/dev/ata/chipsets/ata-siliconimage.c b/sys/dev/ata/chipsets/ata-siliconimage.c
index f5093c7..b163276 100644
--- a/sys/dev/ata/chipsets/ata-siliconimage.c
+++ b/sys/dev/ata/chipsets/ata-siliconimage.c
@@ -380,7 +380,7 @@ ata_sii_status(device_t dev)
static void
ata_sii_reset(device_t dev)
{
- if (ata_sata_phy_reset(dev))
+ if (ata_sata_phy_reset(dev, -1, 1))
ata_generic_reset(dev);
}
@@ -832,7 +832,7 @@ ata_siiprb_reset(device_t dev)
}
/* reset phy */
- if (!ata_sata_phy_reset(dev)) {
+ if (!ata_sata_phy_reset(dev, -1, 1)) {
if (bootverbose)
device_printf(dev, "phy reset found no device\n");
ch->devices = 0;
diff --git a/sys/dev/ata/chipsets/ata-sis.c b/sys/dev/ata/chipsets/ata-sis.c
index 1d9dac7..8e02ee9 100644
--- a/sys/dev/ata/chipsets/ata-sis.c
+++ b/sys/dev/ata/chipsets/ata-sis.c
@@ -226,7 +226,7 @@ ata_sis_ch_attach(device_t dev)
static void
ata_sis_reset(device_t dev)
{
- if (ata_sata_phy_reset(dev))
+ if (ata_sata_phy_reset(dev, -1, 1))
ata_generic_reset(dev);
}
diff --git a/sys/dev/ata/chipsets/ata-via.c b/sys/dev/ata/chipsets/ata-via.c
index 4530adf..525ca2f 100644
--- a/sys/dev/ata/chipsets/ata-via.c
+++ b/sys/dev/ata/chipsets/ata-via.c
@@ -269,7 +269,7 @@ ata_via_reset(device_t dev)
if ((ctlr->chip->cfg2 & VIABAR) && (ch->unit > 1))
ata_generic_reset(dev);
else
- if (ata_sata_phy_reset(dev))
+ if (ata_sata_phy_reset(dev, -1, 1))
ata_generic_reset(dev);
}
OpenPOWER on IntegriCloud