Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 28 Mar 2009 19:09:30 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r190509 - in user/mav/ata/sys/dev/ata: . chipsets
Message-ID:  <200903281909.n2SJ9Uak010291@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mav
Date: Sat Mar 28 19:09:30 2009
New Revision: 190509
URL: http://svn.freebsd.org/changeset/base/190509

Log:
  Add ch_suspend/ch_resume methods for PCI controllers and implement them
  for AHCI. Refactor AHCI channel initialization according to it.
  
  Add minimal checks for PMP registers operations errors. Proper error
  handling is still required.
  
  Add delay after PMP port hardreset, to let it complete. Softreset issued
  without delay does not completes successfully. This is a temporary hack
  until I find how to make it right.

Modified:
  user/mav/ata/sys/dev/ata/ata-pci.c
  user/mav/ata/sys/dev/ata/ata-pci.h
  user/mav/ata/sys/dev/ata/ata-sata.c
  user/mav/ata/sys/dev/ata/chipsets/ata-ahci.c
  user/mav/ata/sys/dev/ata/chipsets/ata-jmicron.c

Modified: user/mav/ata/sys/dev/ata/ata-pci.c
==============================================================================
--- user/mav/ata/sys/dev/ata/ata-pci.c	Sat Mar 28 17:36:56 2009	(r190508)
+++ user/mav/ata/sys/dev/ata/ata-pci.c	Sat Mar 28 19:09:30 2009	(r190509)
@@ -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);
 }
 

Modified: user/mav/ata/sys/dev/ata/ata-pci.h
==============================================================================
--- user/mav/ata/sys/dev/ata/ata-pci.h	Sat Mar 28 17:36:56 2009	(r190508)
+++ user/mav/ata/sys/dev/ata/ata-pci.h	Sat Mar 28 19:09:30 2009	(r190509)
@@ -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);
@@ -454,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);

Modified: user/mav/ata/sys/dev/ata/ata-sata.c
==============================================================================
--- user/mav/ata/sys/dev/ata/ata-sata.c	Sat Mar 28 17:36:56 2009	(r190508)
+++ user/mav/ata/sys/dev/ata/ata-sata.c	Sat Mar 28 19:09:30 2009	(r190509)
@@ -130,7 +130,8 @@ ata_sata_connect(struct ata_channel *ch,
 
     /* wait up to 1 second for "connect well" */
     for (timeout = 0; timeout < 100 ; timeout++) {
-	ata_sata_scr_read(ch, port, ATA_SSTATUS, &status);
+	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;
@@ -172,27 +173,39 @@ ata_sata_phy_reset(device_t dev, int por
     uint32_t val;
 
     if (quick) {
-	ata_sata_scr_read(ch, port, ATA_SCONTROL, &val);
+	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_sata_scr_write(ch, port, ATA_SCONTROL, ATA_SC_DET_RESET);
+	    if (ata_sata_scr_write(ch, port, ATA_SCONTROL, ATA_SC_DET_RESET))
+		return (0);
 	    ata_udelay(100);
-	    ata_sata_scr_read(ch, port, ATA_SCONTROL, &val);
+	    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_sata_scr_write(ch, port, ATA_SCONTROL,
+	    if (ata_sata_scr_write(ch, port, ATA_SCONTROL,
 					ATA_SC_DET_IDLE |
 					ATA_SC_IPM_DIS_PARTIAL |
-					ATA_SC_IPM_DIS_SLUMBER);
+					ATA_SC_IPM_DIS_SLUMBER))
+		return (0);
 	    ata_udelay(100);
-	    ata_sata_scr_read(ch, port, ATA_SCONTROL, &val);
+	    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);
 	}
@@ -306,7 +319,9 @@ 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;
@@ -338,6 +353,13 @@ ata_pm_identify(device_t dev)
 	if (!ata_sata_phy_reset(dev, port, 1))
 	    continue;
 
+	/*
+	 * 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);
 
 	if (bootverbose)

Modified: user/mav/ata/sys/dev/ata/chipsets/ata-ahci.c
==============================================================================
--- user/mav/ata/sys/dev/ata/chipsets/ata-ahci.c	Sat Mar 28 17:36:56 2009	(r190508)
+++ user/mav/ata/sys/dev/ata/chipsets/ata-ahci.c	Sat Mar 28 19:09:30 2009	(r190509)
@@ -59,10 +59,16 @@ static int ata_ahci_begin_transaction(st
 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_re
 		 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
     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
 
     /* 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 por
     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, -1, 0)) {
+    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);

Modified: user/mav/ata/sys/dev/ata/chipsets/ata-jmicron.c
==============================================================================
--- user/mav/ata/sys/dev/ata/chipsets/ata-jmicron.c	Sat Mar 28 17:36:56 2009	(r190508)
+++ user/mav/ata/sys/dev/ata/chipsets/ata-jmicron.c	Sat Mar 28 19:09:30 2009	(r190509)
@@ -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)
 {



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200903281909.n2SJ9Uak010291>