Index: trunk/src/os2ahci/README
===================================================================
--- trunk/src/os2ahci/README	(revision 164)
+++ trunk/src/os2ahci/README	(revision 165)
@@ -17,4 +17,5 @@
 Copyright (c) 2011 thi.guten Software Development
 Copyright (c) 2011-2013 Mensys B.V.
+Portions copyright (c) 2013 David Azarewicz
 
 Authors: Christian Mueller, Markus Thielen
@@ -81,4 +82,16 @@
 - Add the following line to CONFIG.SYS:
   BASEDEV=OS2AHCI.ADD
+
+
+Reporting Problems
+==================
+
+If you have problems with this driver, please read the Troubleshooting
+page at:
+
+  http://svn.ecomstation.nl/ahci/wiki/Troubleshooting
+
+You can open a ticket at:
+  http://svn.ecomstation.nl/ahci
 
 
@@ -151,5 +164,5 @@
 Option                 Description
 ------------------------------------------------------------------------------
-/s                     Enable SCSI emulation for ATAPI units (default = off)
+/s                     Enable SCSI emulation for ATAPI units (default = on)
                        SCSI emulation is required for tools like cdrecord.
 
@@ -346,16 +359,18 @@
 Starting with version 1.22, OS2AHCI supports the IOCTL interface required by
 existing SMART monitoring tools. Since those tools are hard-coded to open
-the character device named "IBMS506$", OS2AHCI will now register a device
-with this name, too.
+the character device named "IBMS506$", they will not work with OS2AHCI unless
+modified to open the OS2AHCI$ device. Previous versions of OS2AHCI used to
+register register a duplicate device with the IBMS506$ name, however since
+that caused so many unacceptable problems, that is no longer done. You must
+have a SMART utility that opens the OS2AHCI$ device to access the AHCI driver.
+
+A patched version of the smartctl.exe program is included in the OS2AHCI
+distribution. This patched version simply has the name "IBMS506$" changed
+to "OS2AHCI$" and is otherwise identical. This patched program has been
+renamed to smartahci.exe to distinguish it from the unpatched version.
+The patched smartahci.exe program is provided AS-IS and is completely
+UNSUPPORTED. Use of this program is at your own risk.
 
 NOTES:
-
- - If multiple drivers exporting this character device name are loaded at
-   the same time, the driver loaded last will receive all [SMART] requests.
-   This means that if both DANIS506 and OS2AHCI are loaded and SMART support
-   for OS2AHCI-controlled hard disks is desired, OS2AHCI will have to be
-   loaded after DANIS506. It also means that DANIS506 may have to be told
-   to ignore type 2 controllers (i.e. controllers supporting both SATA and
-   AHCI) using the command line options "/A:x /I".
 
  - The IOCTL interface for SMART is based on the idea of IDE controllers
@@ -381,4 +396,10 @@
 Change Log
 ==========
+
+v.1.30 29-Jun-2013 - David Azarewicz
+  Enhanced debug log output
+  Removed the IBMS506 header that was causing problems and shouldn't
+    be there anyway.
+  Fixed a defect in the SMART IOCtl.
 
 v.1.29 12-Jun-2013 - David Azarewicz
Index: trunk/src/os2ahci/ahci.c
===================================================================
--- trunk/src/os2ahci/ahci.c	(revision 164)
+++ trunk/src/os2ahci/ahci.c	(revision 165)
@@ -4,4 +4,5 @@
  * Copyright (c) 2011 thi.guten Software Development
  * Copyright (c) 2011 Mensys B.V.
+ * Portions copyright (c) 2013 David Azarewicz
  *
  * Authors: Christian Mueller, Markus Thielen
@@ -234,4 +235,7 @@
 
 #if 0
+  /* init_reset is set by default. This code is commented out to allow
+   * unsetting init_reset by a command line switch
+   */
   if ((ai->bios_config[HOST_CTL / sizeof(u32)] & HOST_AHCI_EN) == 0 &&
       ai->pci->vendor == PCI_VENDOR_ID_INTEL) {
@@ -1343,7 +1347,5 @@
     dprintf("flushing cache on %d.%d.%d\n", ad_no(ai), p, d);
     return(ahci_exec_polled_cmd(ai, p, d, 30000,
-                                ai->ports[p].devs[d].lba48 ? ATA_CMD_FLUSH_EXT
-                                                           : ATA_CMD_FLUSH,
-                                AP_END));
+           ai->ports[p].devs[d].lba48 ? ATA_CMD_FLUSH_EXT : ATA_CMD_FLUSH, AP_END));
   }
   return 0;
Index: trunk/src/os2ahci/apm.c
===================================================================
--- trunk/src/os2ahci/apm.c	(revision 164)
+++ trunk/src/os2ahci/apm.c	(revision 165)
@@ -4,4 +4,5 @@
  * Copyright (c) 2011 thi.guten Software Development
  * Copyright (c) 2011 Mensys B.V.
+ * Portions copyright (c) 2013 David Azarewicz
  *
  * Authors: Christian Mueller, Markus Thielen
@@ -123,6 +124,6 @@
       for (d = 0; d <= ai->ports[p].dev_max; d++) {
         if (ai->ports[p].devs[d].present) {
-	  ahci_flush_cache(ai, p, d);
-	}
+          ahci_flush_cache(ai, p, d);
+        }
       }
     }
@@ -241,4 +242,5 @@
 
       #if 0
+      /* cannot flush caches this way */
       ahci_start_port(ai, p, 0);
 
@@ -246,6 +248,6 @@
       for (d = 0; d <= ai->ports[p].dev_max; d++) {
         if (ai->ports[p].devs[d].present) {
-	  ahci_flush_cache(ai, p, d);
-	}
+          ahci_flush_cache(ai, p, d);
+        }
       }
       #endif
Index: trunk/src/os2ahci/ata.c
===================================================================
--- trunk/src/os2ahci/ata.c	(revision 164)
+++ trunk/src/os2ahci/ata.c	(revision 165)
@@ -4,4 +4,5 @@
  * Copyright (c) 2011 thi.guten Software Development
  * Copyright (c) 2011 Mensys B.V.
+ * Portions copyright (c) 2013 David Azarewicz
  *
  * Authors: Christian Mueller, Markus Thielen
Index: trunk/src/os2ahci/init.asm
===================================================================
--- trunk/src/os2ahci/init.asm	(revision 164)
+++ trunk/src/os2ahci/init.asm	(revision 165)
@@ -36,5 +36,5 @@
 
 DEVHDR          SEGMENT WORD PUBLIC 'DATA'
-_dev_hdr        dd      _next_hdr               ; next device header
+_dev_hdr        dd      -1                      ; next device header
                 dw      DEVLEV_3 + DEV_CHAR_DEV + DEV_IDC ; flags for ADD drivers
                 dw      OFFSET _asm_strat       ; strategy routine
@@ -44,20 +44,4 @@
                 dd      DEV_IOCTL2 + DEV_ADAPTER_DD + DEV_INITCOMPLETE + DEV_SAVERESTORE ; ADD flags
                 dw      0
-
-if 1
-; This is here to support old SMART tools which only look for IBMS506$. This is a
-; really bad thing to do as it will cause problems in the future. The SMART tools
-; should be fixed to be able to open OS2AHCI$ and this header should be removed.
-_next_hdr       dd      -1                      ; no headers after this one
-                dw      DEVLEV_3 + DEV_CHAR_DEV ; flags for ADD drivers
-                dw      OFFSET _asm_strat       ; strategy routine
-                dw      0                       ; IDC entry point
-                db      "IBMS506$"              ; name of character device
-                dq      0                       ; 8 reserved bytes
-                dd      0
-                dw      0
-else
-_next_hdr       equ -1
-endif
 
 DEVHDR          ENDS
Index: trunk/src/os2ahci/ioctl.c
===================================================================
--- trunk/src/os2ahci/ioctl.c	(revision 164)
+++ trunk/src/os2ahci/ioctl.c	(revision 165)
@@ -207,6 +207,5 @@
   ic->iorb.iorbh.UnitHandle       = iorb_unit(a, p, d);
   ic->iorb.iorbh.CommandCode      = IOCC_ADAPTER_PASSTHRU;
-  ic->iorb.iorbh.CommandModifier  = (req->flags & PT_ATAPI) ? IOCM_EXECUTE_CDB
-                                                            : IOCM_EXECUTE_ATA;
+  ic->iorb.iorbh.CommandModifier  = (req->flags & PT_ATAPI) ? IOCM_EXECUTE_CDB : IOCM_EXECUTE_ATA;
   ic->iorb.iorbh.RequestControl   = IORB_ASYNC_POST;
   ic->iorb.iorbh.Timeout          = req->timeout;
@@ -234,25 +233,8 @@
   add_entry(&ic->iorb.iorbh);
 
-  /* Wait for IORB completion. On SMP kernels, ProcBlock will release
-   * all spinlocks currently held, in addition to re-enabling interrupts,
-   * so we can use spinlocks to protect the time between checking the
-   * IORB_DONE flag and calling ProcBlock.
-   *
-   * However, if OS2AHCI_SMP is not defined, we're emulating spinlocks
-   * via disabling interrupts and there's a sanity check in the emulation
-   * code to catch recursive spinlocks, thus we need to reset the emulated
-   * spinlock status before calling ProcBlock. Otherwise, the driver will
-   * will get caught in the sanity checks when processing the next IORB or
-   * interrupt while we're waiting.
-   */
+  /* Wait for IORB completion. */
   spin_lock(drv_lock);
   while (!(ic->iorb.iorbh.Status & IORB_DONE)) {
-
-#   ifndef OS2AHCI_SMP
-      drv_lock = 0;
-#   endif
-
     DevHelp_ProcBlock((ULONG) (void _far *) &ic->iorb.iorbh, 30000, 1);
-    spin_lock(drv_lock);
   }
   spin_unlock(drv_lock);
@@ -355,5 +337,5 @@
   USHORT d;
   UCHAR unit;
-  
+
   /* verify addressability of parm buffer (DSKSP_CommandParameters) */
   if (DevHelp_VerifyAccess((SEL) ((ULONG) cp >> 16),
@@ -499,12 +481,9 @@
 
   case DSKSP_SMART_ONOFF:
-    ret = do_smart(unit, (BYTE) ((parm) ? ATA_SMART_ENABLE
-                                        : ATA_SMART_DISABLE),
-                   0, 0, NULL);
+    ret = do_smart(unit, (BYTE) ((parm) ? ATA_SMART_ENABLE : ATA_SMART_DISABLE), 0, 0, NULL);
     break;
 
   case DSKSP_SMART_AUTOSAVE_ONOFF:
-    ret = do_smart(unit, ATA_SMART_AUTOSAVE,
-                   (BYTE) ((parm) ? (BYTE) 0xf1 : 0), 0, NULL);
+    ret = do_smart(unit, ATA_SMART_AUTOSAVE, (BYTE) ((parm) ? (BYTE) 0xf1 : 0), 0, NULL);
     break;
 
@@ -547,6 +526,5 @@
  * Perform SMART request. The code has been more or less copied from DANIS506.
  */
-static USHORT do_smart(BYTE unit, BYTE sub_func, BYTE cnt, BYTE lba_l,
-                       void _far *buf)
+static USHORT do_smart(BYTE unit, BYTE sub_func, BYTE cnt, BYTE lba_l, void _far *buf)
 {
   OS2AHCI_PASSTHROUGH pt;
@@ -584,6 +562,5 @@
   }
 
-  if (((ret = gen_ioctl(&ioctl)) & STERR) == 0 &&
-      sub_func == ATA_SMART_STATUS) {
+  if (((ret = gen_ioctl(&ioctl)) & STERR) == 0 && sub_func == ATA_SMART_STATUS) {
 
     /* ATA_SMART_STATUS doesn't transfer anything but instead relies on the
Index: trunk/src/os2ahci/libc.c
===================================================================
--- trunk/src/os2ahci/libc.c	(revision 164)
+++ trunk/src/os2ahci/libc.c	(revision 165)
@@ -4,4 +4,5 @@
  * Copyright (c) 2011 thi.guten Software Development
  * Copyright (c) 2011 Mensys B.V.
+ * Portions copyright (c) 2013 David Azarewicz
  *
  * Authors: Christian Mueller, Markus Thielen
@@ -38,26 +39,7 @@
 #define HEAP_UNIT_CNT         (HEAP_SIZE / HEAP_UNIT)
 
-/* ------------------------ typedefs and structures ------------------------ */
-
-#ifdef NOT_USED
-/* mdelay() calibration status */
-typedef enum {
-  MD_NOT_CALIBRATED,                  /* delay loop not calibrated */
-  MD_CALIBRATION_START,               /* calibration run started */
-  MD_CALIBRATION_END,                 /* calibration run ended */
-  MD_CALIBRATION_DONE                 /* calibration complete */
-} MDCAL;
-static void _cdecl _far mdelay_timer_callback  (ULONG timer_handle,
-                                                ULONG parm1,
-                                                ULONG parm2);
-static int              mdelay_cal_end         (void);
-#endif
-
 /* -------------------------- function prototypes -------------------------- */
 
-static void             long_to_asc            (long val,
-                                                char _far *buf,
-                                                int base,
-                                                int zero, int flen);
+static void long_to_asc(long val, char _far *buf, int base, int zero, int flen);
 
 /* ------------------------ global/static variables ------------------------ */
@@ -94,10 +76,4 @@
 };
 
-#ifdef NOT_USED
-/* delay loop calibration data */
-volatile MDCAL mdelay_cal_status = 0;     /* delay loop calibration status */
-volatile u32   mdelay_loops_per_ms = 0;   /* delay loop counter */
-#endif
-
 /* very small heap for dynamic memory management */
 static u8 heap_buf[HEAP_SIZE];
@@ -688,87 +664,4 @@
 }
 
-#ifdef NOT_USED
-/******************************************************************************
- * Calibrate 'mdelay()' loop. This is done by setting up a 1 second timer
- * with a callback that sets 'mdelay_done' to MD_CALIBRATION_END. Then it
- * calls mdelay() with a large milliseond value as initial delay loop counter.
- * When the timer triggers, 'mdelay()' will stop and update the delay loop
- * counter.
- *
- * This function needs to be called at device driver init time. Since it uses
- * ADD timers, it must be called with interrupts enabled. All this is not very
- * precise (we should wait for a clock tick before starting, ...) but we don't
- * really need precise timers.
- */
-void mdelay_cal(void)
-{
-  ULONG timer_handle;
-
-  dprintf("calibrating delay loop... ");
-
-  mdelay_loops_per_ms = 100000;
-  mdelay_cal_status = MD_CALIBRATION_START;
-
-  ADD_StartTimerMS(&timer_handle, 1000, (PFN) mdelay_timer_callback, 0, 0);
-  mdelay(999999999);
-  ADD_CancelTimer(timer_handle);
-
-  dprintf("done (loops per ms = %ld)\n", mdelay_loops_per_ms);
-}
-
-/******************************************************************************
- * Wait specified number of milliseconds. This is implemented using a busy
- * loop and is only good for delays in the millisecond range but never for more
- * than a few milliseconds and only in situations where a proper timer won't do.
- * As a rule of thumb, don't call this function and use ADD timers, instead.
- *
- * NOTES:
- *
- *  - Timers are problematic on x86 platforms because there's no reliable
- *    hardware timer on all architectures and the CPU clock speed may change
- *    while executing delay loops (AMD Cool&Quiet and Intel SpeedStep), thus
- *    calibration routines won't really be sufficient. But this usually only
- *    extends the delay and we don't really need a high precision timer. The
- *    exception are things like notebooks that are clocked slower when on
- *    battery and which got booted while on battery. Should still be OK,
- *    though, because our requirements are not that strict.
- *
- *  - The code in this function is inefficient by design to make sure it
- *    will work with future CPUs which might otherwise be too fast for
- *    our loop counters. Part of this design is using volatile variables to
- *    force memory operations.
- *
- *  - Before using this function, call mdelay_calibrate() to determine the
- *    number of inner loops required per millisecond.
- */
-void mdelay(u32 millies)
-{
-  volatile u32 i;
-  volatile u32 n;
-
-  for (i = 0; i < millies; i++) {
-    for (n = 0; n < mdelay_loops_per_ms; n++) {
-      if (mdelay_cal_end()) {
-        /* this is a calibration run that just ended */
-        goto complete_calibration;
-      }
-    }
-  }
-  return;
-
-complete_calibration:
-  /* complete calibration cycle */
-  if (i < 1000) {
-    /* Initial value for delay loop was too high; interpolate results for
-     * an assumed initial delay loop divided by 1000.
-     */
-    i = i * 1000 + mdelay_loops_per_ms % 1000;
-    mdelay_loops_per_ms /= 1000;
-  }
-  mdelay_loops_per_ms = (mdelay_loops_per_ms * i) / 1000;
-  mdelay_cal_status = MD_CALIBRATION_DONE;
-}
-#endif
-
 /******************************************************************************
  * Setup the millisecond timer. This is implemented by blocking (yielding the
@@ -898,23 +791,2 @@
 }
 
-#ifdef NOT_USED
-/******************************************************************************
- * Timer callback handler for 'mdelay_calibrate()'
- */
-static void _cdecl _far mdelay_timer_callback(ULONG timer_handle,
-                                              ULONG parm1,
-                                              ULONG parm2)
-{
-  mdelay_cal_status = MD_CALIBRATION_END;
-}
-
-/******************************************************************************
- * Determine whether an mdelay calibration run has just ended. This is in a
- * function to prevent overzealous optimizers from removing the whole delay
- * loop in mdelay().
- */
-static int mdelay_cal_end(void)
-{
-  return(mdelay_cal_status == MD_CALIBRATION_END);
-}
-#endif
Index: trunk/src/os2ahci/os2ahci.c
===================================================================
--- trunk/src/os2ahci/os2ahci.c	(revision 164)
+++ trunk/src/os2ahci/os2ahci.c	(revision 165)
@@ -4,4 +4,5 @@
  * Copyright (c) 2011 thi.guten Software Development
  * Copyright (c) 2011 Mensys B.V.
+ * Portions copyright (c) 2013 David Azarewicz
  *
  * Authors: Christian Mueller, Markus Thielen
@@ -825,5 +826,5 @@
       #endif
 
-      if (!TRACE_ACTIVE) build_user_info();
+      build_user_info();
     }
     iorb_done(iorb);
Index: trunk/src/os2ahci/os2ahci.h
===================================================================
--- trunk/src/os2ahci/os2ahci.h	(revision 164)
+++ trunk/src/os2ahci/os2ahci.h	(revision 165)
@@ -175,5 +175,5 @@
 
 /* SMP spinlock compatibility macros for older DDKs using CLI/STI */
-#ifndef OS2AHCI_SMP
+#ifdef SPINLOCK_EMULATION
 #define DevHelp_CreateSpinLock(p_sph)  *(p_sph) = 0
 #define DevHelp_FreeSpinLock(sph)      0
Index: trunk/src/os2ahci/trace.c
===================================================================
--- trunk/src/os2ahci/trace.c	(revision 164)
+++ trunk/src/os2ahci/trace.c	(revision 165)
@@ -4,4 +4,5 @@
  * Copyright (c) 2011 thi.guten Software Development
  * Copyright (c) 2011 Mensys B.V.
+ * Portions copyright (c) 2013 David Azarewicz
  *
  * Authors: Christian Mueller, Markus Thielen
@@ -188,20 +189,4 @@
 
   spin_lock(com_lock);
-  #ifdef NOT_USED
-  /* block process until data is available in the trace buffer. */
-  while (ahci_trace_buf.writep == ahci_trace_buf.readp ) { /* buffer is empty */
-    spin_lock(com_lock);
-      #ifndef OS2AHCI_SMP
-      com_lock = 0;
-      #endif
-      if (DevHelp_ProcBlock((ULONG) ahci_trace_buf.phys_addr,
-                            (ULONG) -1, 0) == WAIT_INTERRUPTED) {
-        /* user pressed Ctrl+C or whatever */
-        rwrb->NumSectors = 0;
-        return STDON;
-      }
-    spin_lock(com_lock);
-  }
-  #endif
 
   /* get pointer to caller's buffer */
@@ -235,6 +220,7 @@
     AD_INFO *ai = ad_infos + a;
 
-    ntprintf("Adapter %d: %d:%d:%d irq=%d addr=0x%lx version=%lx\n", a,
+    ntprintf("Adapter %d: PCI=%d:%d:%d ID=%x:%x irq=%d addr=0x%lx version=%lx\n", a,
       ai->bus, ai->dev_func>>3, ai->dev_func&7,
+      ai->pci->vendor, ai->pci->device,
       ai->irq, ai->mmio_phys,
       ai->bios_config[HOST_VERSION / sizeof(u32)]);
