Index: trunk/src/os2ahci/README
===================================================================
--- trunk/src/os2ahci/README	(revision 160)
+++ trunk/src/os2ahci/README	(revision 161)
@@ -386,4 +386,5 @@
   Removed unused IDC entry point.
   Some work on suspend/resume routines.
+  Suspend/resume is only supported on eCS systems with ACPI.
 
 v.1.27 23-Apr-2013 - David Azarewicz
Index: trunk/src/os2ahci/ahci.c
===================================================================
--- trunk/src/os2ahci/ahci.c	(revision 160)
+++ trunk/src/os2ahci/ahci.c	(revision 161)
@@ -122,4 +122,84 @@
 };
 
+void ahci_dump_host_regs(AD_INFO *ai, int bios_regs)
+{
+  #ifdef DEBUG
+  int i;
+  u32 version;
+
+  aprintf("AHCI global controller registers:\n");
+  for (i = 0; i <= HOST_CAP2; i += sizeof(u32)) {
+    u32 val;
+
+    if (bios_regs) val = ai->bios_config[i/sizeof(u32)];
+    else
+    {
+      /* HOST_CAP2 only exists for AHCI V1.2 and later */
+      if ((i == HOST_CAP2) && (version < 0x00010200L)) val = 0;
+      else val = readl(ai->mmio + i);
+    }
+    if (i == HOST_VERSION) version = val;
+
+    ntprintf(" %02x: %08lx", i, val);
+
+    if (i == HOST_CAP) {
+      ntprintf(" -");
+      if (val & HOST_CAP_64)         ntprintf(" 64bit");
+      if (val & HOST_CAP_NCQ)        ntprintf(" ncq");
+      if (val & HOST_CAP_SNTF)       ntprintf(" sntf");
+      if (val & HOST_CAP_MPS)        ntprintf(" mps");
+      if (val & HOST_CAP_SSS)        ntprintf(" sss");
+      if (val & HOST_CAP_ALPM)       ntprintf(" alpm");
+      if (val & HOST_CAP_LED)        ntprintf(" led");
+      if (val & HOST_CAP_CLO)        ntprintf(" clo");
+      if (val & HOST_CAP_ONLY)       ntprintf(" ahci_only");
+      if (val & HOST_CAP_PMP)        ntprintf(" pmp");
+      if (val & HOST_CAP_FBS)        ntprintf(" fbs");
+      if (val & HOST_CAP_PIO_MULTI)  ntprintf(" pio_multi");
+      if (val & HOST_CAP_SSC)        ntprintf(" ssc");
+      if (val & HOST_CAP_PART)       ntprintf(" part");
+      if (val & HOST_CAP_CCC)        ntprintf(" ccc");
+      if (val & HOST_CAP_EMS)        ntprintf(" ems");
+      if (val & HOST_CAP_SXS)        ntprintf(" sxs");
+      ntprintf(" cmd_slots:%d", (u16) ((val >> 8) & 0x1f) + 1);
+      ntprintf(" ports:%d",     (u16) (val & 0x1f) + 1);
+    } else if (i == HOST_CTL) {
+      ntprintf(" -");
+      if (val & HOST_AHCI_EN)        ntprintf(" ahci_enabled");
+      if (val & HOST_IRQ_EN)         ntprintf(" irq_enabled");
+      if (val & HOST_RESET)          ntprintf(" resetting");
+    } else if (i == HOST_CAP2) {
+      ntprintf(" -");
+      if (val & HOST_CAP2_BOH)       ntprintf(" boh");
+      if (val & HOST_CAP2_NVMHCI)    ntprintf(" nvmhci");
+      if (val & HOST_CAP2_APST)      ntprintf(" apst");
+    }
+    ntprintf("\n");
+  }
+  #endif
+}
+
+void ahci_dump_port_regs(AD_INFO *ai, int p)
+{
+  #ifdef DEBUG
+  u8 _far *port_mmio = port_base(ai, p);
+
+  aprintf("AHCI port %d registers:\n", p);
+  ntprintf(" PORT_CMD       = 0x%lx\n", readl(port_mmio + PORT_CMD));
+  ntprintf("command engine status:\n");
+  ntprintf(" PORT_SCR_ACT   = 0x%lx\n", readl(port_mmio + PORT_SCR_ACT));
+  ntprintf(" PORT_CMD_ISSUE = 0x%lx\n", readl(port_mmio + PORT_CMD_ISSUE));
+  ntprintf("link/device status:\n");
+  ntprintf(" PORT_SCR_STAT  = 0x%lx\n", readl(port_mmio + PORT_SCR_STAT));
+  ntprintf(" PORT_SCR_CTL   = 0x%lx\n", readl(port_mmio + PORT_SCR_CTL));
+  ntprintf(" PORT_SCR_ERR   = 0x%lx\n", readl(port_mmio + PORT_SCR_ERR));
+  ntprintf(" PORT_TFDATA    = 0x%lx\n", readl(port_mmio + PORT_TFDATA));
+  ntprintf("interrupt status:\n");
+  ntprintf(" PORT_IRQ_STAT  = 0x%lx\n", readl(port_mmio + PORT_IRQ_STAT));
+  ntprintf(" PORT_IRQ_MASK  = 0x%lx\n", readl(port_mmio + PORT_IRQ_MASK));
+  ntprintf(" HOST_IRQ_STAT  = 0x%lx\n", readl(ai->mmio + HOST_IRQ_STAT));
+  #endif
+}
+
 /******************************************************************************
  * Save BIOS configuration of AHCI adapter. As a side effect, this also saves
@@ -143,4 +223,11 @@
 
   ddprintf("ahci_save_bios_config: BIOS AHCI mode is %d\n", ai->bios_config[HOST_CTL / sizeof(u32)] & HOST_AHCI_EN);
+
+  /* HOST_CAP2 only exists for AHCI V1.2 and later */
+  if (ai->bios_config[HOST_VERSION / sizeof(u32)] >= 0x00010200L) {
+    ai->bios_config[HOST_CAP2 / sizeof(u32)] = readl(ai->mmio + HOST_CAP2);
+  } else {
+    ai->bios_config[HOST_CAP2 / sizeof(u32)] = 0;
+  }
 
 #if 0
@@ -154,56 +241,7 @@
 #endif
 
-  /* HOST_CAP2 only exists for AHCI V1.2 and later */
-  if (ai->bios_config[HOST_VERSION / sizeof(u32)] >= 0x00010200L) {
-    ai->bios_config[HOST_CAP2 / sizeof(u32)] = readl(ai->mmio + HOST_CAP2);
-  } else {
-    ai->bios_config[HOST_CAP2 / sizeof(u32)] = 0;
-  }
-
+  #ifdef DEBUG
   /* print AHCI register debug information */
-  #ifdef DEBUG
-  if (debug) {
-    aprintf("AHCI global controller registers:\n");
-    for (i = 0; i <= HOST_CAP2 / sizeof(u32); i++) {
-      u32 val = ai->bios_config[i];
-      aprintf(" %02x: %08lx", i, val);
-
-      if (i == HOST_CAP) {
-        ntprintf(" -");
-        if (val & HOST_CAP_64)         ntprintf(" 64bit");
-        if (val & HOST_CAP_NCQ)        ntprintf(" ncq");
-        if (val & HOST_CAP_SNTF)       ntprintf(" sntf");
-        if (val & HOST_CAP_MPS)        ntprintf(" mps");
-        if (val & HOST_CAP_SSS)        ntprintf(" sss");
-        if (val & HOST_CAP_ALPM)       ntprintf(" alpm");
-        if (val & HOST_CAP_LED)        ntprintf(" led");
-        if (val & HOST_CAP_CLO)        ntprintf(" clo");
-        if (val & HOST_CAP_ONLY)       ntprintf(" ahci_only");
-        if (val & HOST_CAP_PMP)        ntprintf(" pmp");
-        if (val & HOST_CAP_FBS)        ntprintf(" fbs");
-        if (val & HOST_CAP_PIO_MULTI)  ntprintf(" pio_multi");
-        if (val & HOST_CAP_SSC)        ntprintf(" ssc");
-        if (val & HOST_CAP_PART)       ntprintf(" part");
-        if (val & HOST_CAP_CCC)        ntprintf(" ccc");
-        if (val & HOST_CAP_EMS)        ntprintf(" ems");
-        if (val & HOST_CAP_SXS)        ntprintf(" sxs");
-        ntprintf(" cmd_slots:%d", (u16) ((val >> 8) & 0x1f) + 1);
-        ntprintf(" ports:%d",     (u16) (val & 0x1f) + 1);
-
-      } else if (i == HOST_CTL) {
-        ntprintf(" -");
-        if (val & HOST_AHCI_EN)        ntprintf(" ahci_enabled");
-        if (val & HOST_IRQ_EN)         ntprintf(" irq_enabled");
-        if (val & HOST_RESET)          ntprintf(" resetting");
-
-      } else if (i == HOST_CAP2) {
-        ntprintf(" -");
-        if (val & HOST_CAP2_BOH)       ntprintf(" boh");
-        if (val & HOST_CAP2_NVMHCI)    ntprintf(" nvmhci");
-        if (val & HOST_CAP2_APST)      ntprintf(" apst");
-      }
-      ntprintf("\n");
-    }
-  }
+  if (debug) ahci_dump_host_regs(ai, 1);
   #endif
 
@@ -353,16 +391,74 @@
 
   /* restore saved BIOS configuration */
-  writel(ai->mmio + HOST_CCC,       ai->bios_config[HOST_CCC / sizeof(u32)]);
-  writel(ai->mmio + HOST_CCC_PORTS, ai->bios_config[HOST_CCC_PORTS / sizeof(u32)]);
-  writel(ai->mmio + HOST_EM_CTL,    ai->bios_config[HOST_EM_CTL / sizeof(u32)]);
-  writel(ai->mmio + HOST_CTL,       ai->bios_config[HOST_CTL / sizeof(u32)]);
+  //writel(ai->mmio + HOST_CCC,       ai->bios_config[HOST_CCC / sizeof(u32)]);
+  //writel(ai->mmio + HOST_CCC_PORTS, ai->bios_config[HOST_CCC_PORTS / sizeof(u32)]);
+  //writel(ai->mmio + HOST_EM_CTL,    ai->bios_config[HOST_EM_CTL / sizeof(u32)]);
+  //writel(ai->mmio + HOST_CTL,       ai->bios_config[HOST_CTL / sizeof(u32)]);
+
+  writel(ai->mmio + HOST_CAP, ai->bios_config[HOST_CAP / sizeof(u32)]);
+  if (ai->bios_config[HOST_CAP2 / sizeof(u32)])
+    writel(ai->mmio + HOST_CAP2, ai->bios_config[HOST_CAP2 / sizeof(u32)]);
+  writel(ai->mmio + HOST_PORTS_IMPL, ai->bios_config[HOST_PORTS_IMPL / sizeof(u32)]);
 
   /* flush PCI MMIO delayed write buffers */
-  readl(ai->mmio + HOST_CTL);
-
-  /* (re-)enable AHCI mode */
-  ahci_enable_ahci(ai);
+  readl(ai->mmio + HOST_PORTS_IMPL);
 
   return(0);
+}
+
+int ahci_reset_controller(AD_INFO *ai)
+{
+    u32 tmp;
+    TIMER Timer;
+
+    dprintf("controller reset starting on adapter %d\n", ad_no(ai));
+    /* we must be in AHCI mode, before using anything
+     * AHCI-specific, such as HOST_RESET.
+     */
+    ahci_enable_ahci(ai);
+
+    /* global controller reset */
+    tmp = readl(ai->mmio + HOST_CTL);
+    if ((tmp & HOST_RESET) == 0) {
+        writel(ai->mmio + HOST_CTL, tmp | HOST_RESET);
+        readl(ai->mmio + HOST_CTL); /* flush */
+    }
+
+    /*
+     * to perform host reset, OS should set HOST_RESET
+     * and poll until this bit is read to be "0".
+     * reset must complete within 1 second, or
+     * the hardware should be considered fried.
+     */
+    timer_init(&Timer, 1000);
+    while (((tmp = readl(ai->mmio + HOST_CTL)) & HOST_RESET) != 0) {
+      if (timer_check_and_block(&Timer)) {
+        dprintf("controller reset failed (0x%lx)\n", tmp);
+        return(-1);
+      }
+    }
+
+    /* turn on AHCI mode */
+    ahci_enable_ahci(ai);
+
+    /* Some registers might be cleared on reset.  Restore
+     * initial values.
+     */
+    ahci_restore_initial_config(ai);
+
+    if (ai->pci->vendor == PCI_VENDOR_ID_INTEL) {
+      u32 tmp16 = 0;
+
+      ddprintf("ahci_reset_controller: intel detected\n");
+      /* configure PCS */
+      pci_read_conf(ai->bus, ai->dev_func, 0x92, sizeof(u16), &tmp16);
+      if ((tmp16 & ai->port_map) != ai->port_map) {
+        ddprintf("ahci_reset_controller: updating PCS %x/%x\n", (u16)tmp16, ai->port_map);
+        tmp16 |= ai->port_map;
+        pci_write_conf(ai->bus, ai->dev_func, 0x92, sizeof(u16), tmp16);
+      }
+    }
+
+    return 0;
 }
 
@@ -633,5 +729,5 @@
 
   /* enable adapter-level interrupts */
-  writel(ai->mmio + HOST_CTL, HOST_IRQ_EN);
+  writel(ai->mmio + HOST_CTL, readl(ai->mmio + HOST_CTL) | HOST_IRQ_EN);
   readl(ai->mmio + HOST_CTL); /* flush */
 
@@ -661,19 +757,5 @@
 
   dprintf("ahci_reset_port: resetting port %d.%d\n", ad_no(ai), p);
-  if (debug > 1) {
-    aprintf(" PORT_CMD       = 0x%lx\n", readl(port_mmio + PORT_CMD));
-    aprintf("ahci_reset_port: command engine status:\n");
-    aprintf(" PORT_SCR_ACT   = 0x%lx\n", readl(port_mmio + PORT_SCR_ACT));
-    aprintf(" PORT_CMD_ISSUE = 0x%lx\n", readl(port_mmio + PORT_CMD_ISSUE));
-    aprintf("link/device status:\n");
-    aprintf(" PORT_SCR_STAT  = 0x%lx\n", readl(port_mmio + PORT_SCR_STAT));
-    aprintf(" PORT_SCR_CTL   = 0x%lx\n", readl(port_mmio + PORT_SCR_CTL));
-    aprintf(" PORT_SCR_ERR   = 0x%lx\n", readl(port_mmio + PORT_SCR_ERR));
-    aprintf(" PORT_TFDATA    = 0x%lx\n", readl(port_mmio + PORT_TFDATA));
-    aprintf("interrupt status:\n");
-    aprintf(" PORT_IRQ_STAT  = 0x%lx\n", readl(port_mmio + PORT_IRQ_STAT));
-    aprintf(" PORT_IRQ_MASK  = 0x%lx\n", readl(port_mmio + PORT_IRQ_MASK));
-    aprintf(" HOST_IRQ_STAT  = 0x%lx\n", readl(ai->mmio + HOST_IRQ_STAT));
-  }
+  if (debug > 1) ahci_dump_port_regs(ai, p);
 
   /* stop port engines (we don't care whether there is an error doing so) */
@@ -1367,9 +1449,7 @@
        */
       DevHelp_ArmCtxHook(0, engine_ctxhook_h);
-//      DevHelp_EOI(irq);
     } else {
       spin_lock(drv_lock);
       trigger_engine();
-//      DevHelp_EOI(irq);
       spin_unlock(drv_lock);
     }
Index: trunk/src/os2ahci/apm.c
===================================================================
--- trunk/src/os2ahci/apm.c	(revision 160)
+++ trunk/src/os2ahci/apm.c	(revision 161)
@@ -1,4 +1,4 @@
 /******************************************************************************
- * apm.c - Functions to interface with the APM driver.
+ * apm.c - Functions to interface with the legacy APM driver, and suspend / resume functions.
  *
  * Copyright (c) 2011 thi.guten Software Development
@@ -27,17 +27,11 @@
 #include "os2ahci.h"
 
+/* Legacy APM support is not needed on eCS systems with ACPI and is more
+ * reliable without it enabled.
+ */
+#ifdef LEGACY_APM
+
 #include <apmcalls.h>
-
-/* -------------------------- macros and constants ------------------------- */
-
-/* ------------------------ typedefs and structures ------------------------ */
-
-/* -------------------------- function prototypes -------------------------- */
-
-/* ------------------------ global/static variables ------------------------ */
-
 USHORT _far _cdecl apm_event    (APMEVENT _far *evt);
-
-/* ----------------------------- start of code ----------------------------- */
 
 /******************************************************************************
@@ -94,4 +88,5 @@
   return(0);
 }
+#endif /* LEGACY_APM */
 
 /******************************************************************************
@@ -143,11 +138,4 @@
   init_complete = 0;
 
-#if 0
-  /* restore BIOS configuration for each adapter and release the adapter */
-  for (a = 0; a < ad_info_cnt; a++) {
-    ahci_restore_bios_config(ad_infos + a);
-  }
-#endif
-
   /* TODO: put the device into the D3 state */
 
@@ -171,4 +159,6 @@
   for (a = 0; a < ad_info_cnt; a++) {
     AD_INFO *ai = ad_infos + a;
+
+    //ahci_reset_controller(ai);
 
     /* Complete initialization of this adapter; this will restart the ports
@@ -184,8 +174,14 @@
   /* unlock all adapters now that we have set the init_complete flag */
   for (a = 0; a < ad_info_cnt; a++) {
-    unlock_adapter(ad_infos + a);
+    AD_INFO *ai = ad_infos + a;
+    unlock_adapter(ai);
   }
 
   suspended = 0;
+
+  /* restart engine to resume IORB processing */
+  resume_sleep_flag = 5000;
+  DevHelp_ArmCtxHook(0, engine_ctxhook_h);
+
   dprintf("resume() finished\n");
 }
Index: trunk/src/os2ahci/ctxhook.c
===================================================================
--- trunk/src/os2ahci/ctxhook.c	(revision 160)
+++ trunk/src/os2ahci/ctxhook.c	(revision 161)
@@ -217,5 +217,5 @@
             if (req_sense(problem_iorb, 0) == 0) {
               /* execute request sense on slot #0 before anything else comes along */
-              ADD_StartTimerMS(&aws->timer, 5000, (PFN) timeout_callback, 
+              ADD_StartTimerMS(&aws->timer, 5000, (PFN) timeout_callback,
                                problem_iorb, 0);
               aws->cmd_slot = 0;
@@ -430,4 +430,8 @@
 
   dprintf("engine_ctxhook() started\n");
+  if (resume_sleep_flag) {
+    msleep(resume_sleep_flag);
+    resume_sleep_flag = 0;
+  }
 
   spin_lock(drv_lock);
Index: trunk/src/os2ahci/os2ahci.c
===================================================================
--- trunk/src/os2ahci/os2ahci.c	(revision 160)
+++ trunk/src/os2ahci/os2ahci.c	(revision 161)
@@ -135,4 +135,5 @@
 int             init_complete;     /* if != 0, initialization has completed */
 int             suspended;
+int             resume_sleep_flag;
 
 /* apapter/port-specific options saved when parsing the command line */
@@ -222,4 +223,5 @@
   init_drv_called = 1;
   suspended = 0;
+  resume_sleep_flag = 0;
 
   /* set device helper entry point */
@@ -513,5 +515,5 @@
  * Device driver exit handler. This handler is called when OS/2 shuts down and
  * flushes the write caches of all attached devices. Since this is effectively
- * the same we do when suspending, we'll call out to the corresponding APM
+ * the same we do when suspending, we'll call out to the corresponding suspend
  * function.
  *
@@ -619,5 +621,5 @@
  * all IORBs have been sent.
  *
- * NOTE: While initialization has not completed (or during APM suspend/resume
+ * NOTE: While initialization has not completed (or during suspend/resume
  *       operations), this function will loop indefinitely because we can't
  *       rely on interrupt handlers or context hooks and complex IORBs
@@ -742,5 +744,4 @@
    * IORB.
    */
-  while (suspended) DevHelp_ProcBlock((ULONG)&send_iorb, 1, WAIT_IS_INTERRUPTABLE);
   add_workspace(iorb)->processing = 1;
   spin_unlock(drv_lock);
@@ -817,6 +818,8 @@
       }
 
+      #ifdef LEGACY_APM
       /* register APM hook */
       apm_init();
+      #endif
 
       if (!TRACE_ACTIVE) build_user_info();
Index: trunk/src/os2ahci/os2ahci.h
===================================================================
--- trunk/src/os2ahci/os2ahci.h	(revision 160)
+++ trunk/src/os2ahci/os2ahci.h	(revision 161)
@@ -34,5 +34,12 @@
  */
 
+/* Global feature defines
+ * DEBUG = enable debug logging routines to be compled in.
+ * LEGACY_APM = enable the legacy APM interface to be compiled in.
+ *   Legacy APM support is not needed on eCS systems with ACPI and is more reliable without it enabled.
+ */
 #define DEBUG
+//#define LEGACY_APM
+
 #define INCL_NOPMAPI
 #define INCL_DOSINFOSEG
@@ -517,4 +524,7 @@
 extern void    ahci_execute_cdb             (IORBH _far *iorb);
 extern void    ahci_execute_ata             (IORBH _far *iorb);
+extern void ahci_dump_host_regs(AD_INFO *ai, int bios_regs);
+extern void ahci_dump_port_regs(AD_INFO *ai, int p);
+extern int ahci_reset_controller(AD_INFO *ai);
 
 /* libc.c */
@@ -612,4 +622,5 @@
 extern int           init_complete; /* if != 0, initialization has completed */
 extern int           suspended;     /* indicates if the driver is suspended */
+extern int           resume_sleep_flag;
 
 extern u16           com_base;      /* debug COM port base address */
