Index: trunk/src/os2ahci/Makefile
===================================================================
--- trunk/src/os2ahci/Makefile	(revision 209)
+++ trunk/src/os2ahci/Makefile	(revision 211)
@@ -17,4 +17,6 @@
 FDEBUG=0x0000
 
+FIXPACK=Test Build
+
 .ERASE
 .SUFFIXES
@@ -23,5 +25,5 @@
 # Define default build version if not specified in environment
 BLD_MAJOR=2
-BLD_MINOR=08 # must be 2 digits
+BLD_MINOR=09 # must be 2 digits
 BLD_REV=0 # not used at this time
 
@@ -90,5 +92,4 @@
 !endif
 
-#DAZ need to find which structures need pack(1) so we can reset this back to -zp4
 AFLAGS=-q -6p -bt=os2 -wx -d1
 CFLAGS =-q -bt=os2 -6s -olinar -s -ze -zl -zq -zfp -zgp -ms -wx -zp1 -ecs -ei -za99
@@ -142,5 +143,4 @@
   @%append $^&.lrf option map=$^*.map
   @%append $^&.lrf option stack=0
-  #  @%append $*.lnk option protmode
   @%append $^&.lrf sort global
   @%append $^&.lrf option osname='ArcaOS'
@@ -149,12 +149,4 @@
   @for %f in ($(OBJS)) do @%append $^&.lrf file %f
   @for %f in ($(LIBS)) do @%append $^&.lrf library %f
-  #  @%append $*.lnk segment type DATA SHARED
-  #  @%append $*.lnk segment type CODE IOPL
-  #  # Order segments by class
-  #  @%append $*.lnk order
-  #  @%append $*.lnk clname 'DATA'
-  #  @%append $*.lnk clname 'CONST'
-  #  @%append $*.lnk clname 'BSS'
-  #  @%append $*.lnk clname 'CODE'
   @wlink @$^&.lrf
   @%erase $^&.lrf
Index: trunk/src/os2ahci/ReadMe.txt
===================================================================
--- trunk/src/os2ahci/ReadMe.txt	(revision 209)
+++ trunk/src/os2ahci/ReadMe.txt	(revision 211)
@@ -16,5 +16,5 @@
 Copyright (c) 2011 thi.guten Software Development
 Copyright (c) 2011 Mensys B.V.
-Copyright (c) 2013-2021 David Azarewicz
+Copyright (c) 2013-2023 David Azarewicz
 
 Authors: Christian Mueller, Markus Thielen
@@ -72,7 +72,7 @@
                       (default = -1, all adapters)
 
-/F                    Force the use of the HW write cache when using NCQ
-                      commands; see "Native Command Queuing" below for
-                      further explanation (default = off)
+/F                    Ignore the request flag and force the use of the HW
+                      write cache when using NCQ commands; see "Native Command
+                      Queuing" below for further explanation (default=off)
 
 /G:<vendor>:<device>  Add generic PCI ID to list of supported AHCI adapters
@@ -94,8 +94,11 @@
                       turned off with /!T to perform only a PCI class scan
 
-/U                    Check for usable disks and mark disks that are not
-                      usable as unavailable for normal OS/2 operations.
-                      To be usable a disk must be an MBR disk or wiped.
-                      (default = on) Can be turned off with /!U.
+/U                    Check for usable disks and mark disks that are not usable
+                      as unavailable for normal OS/2 operations. To be usable a
+                      disk must be an MBR disk or wiped. (default=on) Can be
+                      turned off with /!U. Warning: Use /!U with caution and
+                      only temporarily if absolutely necessary to reconfigure a
+                      disk. Normal operation with /!U is not recommended and
+                      can lead to uncorrectable disk problems.
 
 /V                    Display informational messages during boot.
@@ -131,5 +134,5 @@
 
 /N                    Enable NCQ (Native Command Queuing) for hard disks
-                      (default = off)
+                      (default = on) Can be turned off with /!N.
 
 /LS                   Set link speed (default = 0):
@@ -145,7 +148,7 @@
                         3 = transitions to both partial and slumber states disabled
 
-/4                    Force track size to be 56 sectors regardless of the
-                      reported disk geometry to optimize partition boundaries
-                      for hard disks with 4096 byte sectors.
+/4                    Force reported track size to be 56 sectors regardless of the
+                      actual disk geometry. Intended to optimize partition boundaries
+                      for hard disks with 4096 byte sectors. May not work with LVM.
 
 Port-specific options depend on the currently active adapter
@@ -185,9 +188,4 @@
 database servers).
 
-While we believe NCQ will work with the majority of controllers and hard
-disks, it's currently turned off by default until we have more feedback
-from OS/2 users. In order to turn on NCQ, just add the command line
-option "/N" to OS2AHCI.ADD.
-
 NCQ and HW Caches
 -----------------
@@ -195,25 +193,9 @@
 In NCQ mode, OS2AHCI supports a request flag which allows upstream code
 (e.g. file systems) to force writes to go directly to the disk instead
-of being buffered in the HW disk cache. However, at least JFS doesn't
-support this flag properly which effectively disables the HW disk cache
-for write operations across the board, resulting in a substantial
-performance loss. In order to prevent OS2AHCI from disabling the HW
-cache when so requested by upstream code, please use the command line
-option "/F".
-
-This may, of course, result in data loss in case of power failures but
-apparently this was the situation with previous IDE drivers as well thus
-shouldn't make much difference in the field. The JFS code also seems to
-imply that this flag has never been widely supported by [IDE] drivers;
-otherwise, the JFS developers should have stumbled over the performance
-loss a long time ago and fixed the code.
-
-NOTES:
-
- - Without NCQ, OS2AHCI behaves like former IDE drivers, i.e. the HW
-   cache will always be enabled (on modern disks).
-
- - When suspending, rebooting or shutting down, OS2AHCI always flushes
-   the HW disk cache regardless of the "/F" or "/N" command line options.
+of being buffered in the HW disk cache. The command line option "/F"
+forces NCQ commands to use the hardware cache, ignoring the request flag.
+This may result in data loss in case of power failures. When rebooting
+or shutting down, the HW disk cache is always flushed regardless of any
+of the command line options.
 
 
@@ -262,6 +244,6 @@
  2. Drive HDD via OS2AHCI.ADD and CDROM via DANIS506.ADD
 
-OS2AHCI.ADD can't drive the CDROM because it's attached to a PATA
-IDE controller which doesn't support AHCI.
+OS2AHCI.ADD can't drive the CDROM because it's attached to an IDE controller
+which doesn't support AHCI.
 
  - If OS2AHCI.ADD comes first in CONFIG.SYS, it will take over the SATA/AHCI
@@ -270,55 +252,4 @@
  - If DANIS506.ADD comes first in CONFIG.SYS, it will take over both the
    SATA/AHCI and the PATA/IDE controller and OS2AHCI.ADD will silently exit.
-
-Advantages of AHCI
-------------------
-
-The interfaces provided by the various [Intel] controllers could be
-summarized like this (the term ATA as driver interface being a bit of our
-own invention):
-
- - Intel PIIX: IDE (I/O registers) and ATA (taskfile)
- - Intel ICH6: IDE (I/O registers), ATA (taskfile) and SATA
-   (FIS, vendor-specific)
- - Intel ICH7: IDE (I/O registers), ATA (taskfile), SATA
-   (FIS, vendor-specific) and AHCI (FIS)
- - Intel PCH: AHCI (FIS)
-
-Taskfiles are regions in memory with ATA commands which the IDE/ATA
-controller can read and process autonomously. FIS (Frame Information
-Structures) are pretty much the same but they are specific to the SATA
-communication protocol on the serial link. The most important FIS type
-for AHCI drivers is the H2D (host to device) FIS which basically contains
-the ATA command to be executed.
-
-The big advantage of AHCI controllers, apart from being vendor-neutral,
-is that they take care of a lot of things which previous-generation
-drivers like DANIS506 would have to do step by step. For example, in
-order to send an ATAPI command, DANIS506 would have to do the following:
-
-  * Send ATA "PACKET" command to device (via IDE registers, ATA taskfiles
-    or SATA FIS)
-  * Wait until device signals via interrupt it's ready for the ATAPI command
-  * Send ATAPI command to device via PIO
-  * Wait until device signals via interrupt it's ready to transfer data
-  * Send/Receive any data that might come along with the ATAPI command via
-    PIO, or wait for DMA transfer to complete
-  * Wait until device signals via interrupt that command and data transfer
-    have completed
-
-For OS2AHCI, the same operation looks like this:
-
-  * Fill in AHCI command header, FIS with ATA "PACKET" command and the ATAPI
-    command
-  * Tell port engine to process the command
-  * Wait until controller signals via interrupt that command and data
-    transfer have completed
-
-The AHCI controller automatically takes care of all underlying bits and
-pieces. OS2AHCI doesn't even have to know whether a particular message is
-sent via PIO or DMA because this is handled by the AHCI controller, too.
-And the whole concept of PIO and DMA is only relevant between AHCI controller
-and the device -- all transfers between OS2AHCI and the AHCI controller are
-always done via DMA.
 
 
@@ -384,4 +315,12 @@
 Change Log
 ==========
+
+v.2.09 24-Jun-2023 - David Azarewicz
+  Added workaround to help with VirtualBox issues.
+  Improved diagnostic messages.
+  Changed how timeouts are reset and how ctx hooks are triggered.
+  Added quirk for devices with issues executing some standard commands.
+  Changed to make /N the default.
+
 v.2.08 20-Feb-2021 - David Azarewicz
   Corrected RM ADD handle and unit.
Index: trunk/src/os2ahci/ahci.c
===================================================================
--- trunk/src/os2ahci/ahci.c	(revision 209)
+++ trunk/src/os2ahci/ahci.c	(revision 211)
@@ -4,5 +4,5 @@
  * Copyright (c) 2011 thi.guten Software Development
  * Copyright (c) 2011 Mensys B.V.
- * Copyright (c) 2013-2021 David Azarewicz <david@88watts.net>
+ * Copyright (c) 2013-2023 David Azarewicz <david@88watts.net>
  *
  * Authors: Christian Mueller, Markus Thielen
@@ -36,37 +36,4 @@
                               ? atapi_##func : ata_##func
 
-
-/* Initial driver status flags indexed by the board_* constants in os2ahci.h
- *
- * NOTE: The Linux AHCI driver uses a combination of board-specific quirk
- *       flags and overriding certain libata service functions to handle
- *       adapter flaws. However, there were only three overrides at the time
- *       os2ahci was written, one for hard adapter resets and two for port
- *       resets, and we can easily implement those within the corresponding
- *       reset handlers. If this becomes more complex, this array of flags
- *       should be converted into a structure array which contains function
- *       pointers to all handler functions which may need to be overridden.
- */
-u16 initial_flags[] =
-{
-  0,                                        /* board_ahci */
-  AHCI_HFLAG_NO_NCQ |                       /* board_ahci_vt8251 */
-    AHCI_HFLAG_NO_PMP,
-  AHCI_HFLAG_IGN_IRQ_IF_ERR,                /* board_ahci_ign_iferr */
-  AHCI_HFLAG_IGN_SERR_INTERNAL |            /* board_ahci_sb600 */
-    AHCI_HFLAG_NO_MSI |
-    AHCI_HFLAG_SECT255 |
-    AHCI_HFLAG_32BIT_ONLY,
-  AHCI_HFLAG_NO_NCQ |                       /* board_ahci_mv */
-    AHCI_HFLAG_NO_MSI |
-    AHCI_HFLAG_MV_PATA |
-    AHCI_HFLAG_NO_PMP,
-  AHCI_HFLAG_IGN_SERR_INTERNAL,             /* board_ahci_sb700 */
-  AHCI_HFLAG_YES_NCQ,                       /* board_ahci_mcp65 */
-  AHCI_HFLAG_NO_PMP,                        /* board_ahci_nopmp */
-  AHCI_HFLAG_YES_NCQ,                       /* board_ahci_yesncq */
-  AHCI_HFLAG_NO_SNTF,                       /* board_ahci_nosntf */
-};
-
 #define MAX_IRQ_HANDLERS 8 /* This is the maximum number of handlers that Dev32Help_SetIRQ can register */
 static u16 irq_used[MAX_IRQ_HANDLERS]; /* IRQ level for each used IRQ */
@@ -81,6 +48,6 @@
   dprintf(0,"AHCI global registers for adapter %d %d:%d:%d irq=%d addr=0x%x\n",
       ad_no(ai),
-      PCI_BUS_FROM_BDF(ai->bus_dev_func), PCI_DEV_FROM_BDF(ai->bus_dev_func),
-      PCI_FUNC_FROM_BDF(ai->bus_dev_func), ai->irq, ai->mmio_phys);
+      PCI_BUS_FROM_BDF(ai->BusDevFunc), PCI_DEV_FROM_BDF(ai->BusDevFunc),
+      PCI_FUNC_FROM_BDF(ai->BusDevFunc), ai->irq, ai->mmio_phys);
 
   for (i = 0; i <= HOST_CAP2; i += sizeof(u32))
@@ -180,13 +147,7 @@
   if (readl(ai->mmio + HOST_VERSION) >= 0x00010200L) ai->cap2 = readl(ai->mmio + HOST_CAP2);
 
-  if (ai->pci->board >= sizeof(initial_flags) / sizeof(*initial_flags))
-  {
-    dprintf(0,"error: invalid board index in PCI info\n");
-    return(-1);
-  }
-  ai->flags = initial_flags[ai->pci->board];
   ai->hw_ports = (ai->cap & 0x1f) + 1;
 
-  if ((ai->cap & HOST_CAP_64) && (ai->flags & AHCI_HFLAG_32BIT_ONLY))
+  if ((ai->cap & HOST_CAP_64) && (ai->quirks & AHCI_HFLAG_32BIT_ONLY))
   {
     /* disable 64-bit support for faulty controllers; OS/2 can't do 64 bits at
@@ -200,5 +161,5 @@
    * around quirks and faulty hardware is hard to come by...
    */
-  if ((ai->cap & HOST_CAP_NCQ) && (ai->flags & AHCI_HFLAG_NO_NCQ))
+  if ((ai->cap & HOST_CAP_NCQ) && (ai->quirks & AHCI_HFLAG_NO_NCQ))
   {
     DPRINTF(DBG_INIT, DBG_PREFIX": controller can't do NCQ, turning off CAP_NCQ\n");
@@ -206,5 +167,5 @@
   }
 
-  if (!(ai->cap & HOST_CAP_NCQ) && (ai->flags & AHCI_HFLAG_YES_NCQ))
+  if (!(ai->cap & HOST_CAP_NCQ) && (ai->quirks & AHCI_HFLAG_YES_NCQ))
   {
     DPRINTF(DBG_INIT, DBG_PREFIX": controller can do NCQ, turning on CAP_NCQ\n");
@@ -212,5 +173,5 @@
   }
 
-  if ((ai->cap & HOST_CAP_PMP) && (ai->flags & AHCI_HFLAG_NO_PMP))
+  if ((ai->cap & HOST_CAP_PMP) && (ai->quirks & AHCI_HFLAG_NO_PMP))
   {
     DPRINTF(DBG_INIT, DBG_PREFIX": controller can't do PMP, turning off CAP_PMP\n");
@@ -218,5 +179,5 @@
   }
 
-  if ((ai->cap & HOST_CAP_SNTF) && (ai->flags & AHCI_HFLAG_NO_SNTF))
+  if ((ai->cap & HOST_CAP_SNTF) && (ai->quirks & AHCI_HFLAG_NO_SNTF))
   {
     DPRINTF(DBG_INIT, DBG_PREFIX": controller can't do SNTF, turning off CAP_SNTF\n");
@@ -224,5 +185,5 @@
   }
 
-  if (ai->pci_vendor == PCI_VENDOR_ID_JMICRON && ai->pci_device == 0x2361 && ai->port_map != 1)
+  if (ai->PciVendor == PCI_VENDOR_ID_JMICRON && ai->PciDevice == 0x2361 && ai->port_map != 1)
   {
     DPRINTF(DBG_INIT, DBG_PREFIX": JMB361 has only one port, port_map 0x%x -> 0x%x\n", ai->port_map, 1);
@@ -276,5 +237,5 @@
   DPRINTF(DBG_DETAILED, DBG_PREFIX": BIOS AHCI mode is %d\n", ai->bios_config[HOST_CTL / sizeof(u32)] & HOST_AHCI_EN);
 
-  if ((ai->bios_config[HOST_CTL / sizeof(u32)] & HOST_AHCI_EN) == 0 && ai->pci_vendor == PCI_VENDOR_ID_INTEL)
+  if ((ai->bios_config[HOST_CTL / sizeof(u32)] & HOST_AHCI_EN) == 0 && ai->PciVendor == PCI_VENDOR_ID_INTEL)
   {
     /* Adapter is not in AHCI mode and the spec says a COMRESET is
@@ -309,5 +270,5 @@
   readl(ai->mmio + HOST_CTL);
 
-  if ((ai->bios_config[HOST_CTL / sizeof(u32)] & HOST_AHCI_EN) == 0 && ai->pci_vendor == PCI_VENDOR_ID_INTEL)
+  if ((ai->bios_config[HOST_CTL / sizeof(u32)] & HOST_AHCI_EN) == 0 && ai->PciVendor == PCI_VENDOR_ID_INTEL)
   {
     /* This BIOS apparently accesses the controller via SATA registers and
@@ -400,5 +361,5 @@
     while (((tmp = readl(ai->mmio + HOST_CTL)) & HOST_RESET) != 0) {
       if (TimerCheckAndBlock(&Timer)) {
-        dprintf(0,"controller reset failed (0x%x)\n", tmp);
+        dprintf(0, DBG_PREFIX": controller reset failed (0x%x)\n", tmp);
         return(-1);
       }
@@ -411,5 +372,5 @@
     ahci_restore_initial_config(ai);
 
-    if (ai->pci_vendor == PCI_VENDOR_ID_INTEL) {
+    if (ai->PciVendor == PCI_VENDOR_ID_INTEL) {
       u32 tmp16 = 0;
 
@@ -498,5 +459,5 @@
   }
 
-  if (ai->pci_vendor == PCI_VENDOR_ID_INTEL)
+  if (ai->PciVendor == PCI_VENDOR_ID_INTEL)
   {
     /* Adapter is not in AHCI mode and the spec says a COMRESET is
@@ -520,5 +481,5 @@
 
   /* couldn't enable AHCI mode */
-  dprintf(0,"failed to enable AHCI mode on adapter %d\n", ad_no(ai));
+  dprintf(0, DBG_PREFIX": failed to enable AHCI mode on adapter %d\n", ad_no(ai));
   return(1);
 }
@@ -541,7 +502,7 @@
     /* register IRQ handler; each IRQ level is registered only once */
     p = 1; /* int count */
-    if (!(ai->flags & AHCI_HFLAG_NO_MSI))
-    {
-      if (PsdMsiAlloc(ai->bus_dev_func, &p, &ai->irq)) p = 1; /* shared flag */
+    if (!(ai->quirks & AHCI_HFLAG_NO_MSI))
+    {
+      if (PsdMsiAlloc(ai->BusDevFunc, &p, &ai->irq)) p = 1; /* shared flag */
       else
       {
@@ -569,5 +530,5 @@
       if (rc)
       {
-        dprintf(0,"failed to register interrupt %d\n", ai->irq);
+        dprintf(0, DBG_PREFIX": failed to register interrupt %d\n", ai->irq);
         return(-1);
       }
@@ -612,7 +573,4 @@
   readl(ai->mmio + HOST_CTL); /* flush */
 
-  /* enable interrupts on PCI-level (PCI 2.3 added a feature to disable INTs) */
-  /* pci_enable_int(ai->bus, ai->dev_func); */
-
   DPRINTF(DBG_INIT|DBG_FUNCEND, DBG_PREFIX": END\n");
   return(0);
@@ -686,5 +644,5 @@
   if (ai->port_max < p) ai->port_max = p;
   if (ai->ports[p].dev_max < d) ai->ports[p].dev_max = d;
-  memset(ai->ports[p].devs + d, 0x00, sizeof(*ai->ports[p].devs));
+  memset(ai->ports[p].devs + d, 0, sizeof(*ai->ports[p].devs));
 
   /* set generic device information (assuming an ATA disk device for now) */
@@ -699,6 +657,6 @@
     /* this is an ATAPI device; augment device information */
     ai->ports[p].devs[d].atapi     = 1;
-    ai->ports[p].devs[d].atapi_16  = (id_buf[ATA_ID_CONFIG] & 0x0001U) != 0;
-    ai->ports[p].devs[d].dev_type  = (id_buf[ATA_ID_CONFIG] & 0x1f00U) >> 8;
+    ai->ports[p].devs[d].atapi_16  = (id_buf[ATA_ID_CONFIG] & 0x0001) != 0;
+    ai->ports[p].devs[d].dev_type  = (id_buf[ATA_ID_CONFIG] & 0x1f00) >> 8;
     ai->ports[p].devs[d].ncq_max   = 1;
 
@@ -709,5 +667,5 @@
     if (enable_ncq[ad_no(ai)][p])
     {
-      ai->ports[p].devs[d].ncq_max = id_buf[ATA_ID_QUEUE_DEPTH] & 0x001fU;
+      ai->ports[p].devs[d].ncq_max = id_buf[ATA_ID_QUEUE_DEPTH] & 0x001f;
     }
     if (ai->ports[p].devs[d].ncq_max < 1)
@@ -716,7 +674,7 @@
       ai->ports[p].devs[d].ncq_max = 1;
     }
-    if (id_buf[ATA_ID_CFS_ENABLE_2] & 0x0400U)
-    {
-      ai->ports[p].devs[d].lba48   = 1;
+    if (id_buf[ATA_ID_CFS_ENABLE_2] & 0x0400)
+    {
+      ai->ports[p].devs[d].lba48 = 1;
     }
   }
@@ -760,5 +718,5 @@
 
   /* try to detect virtualbox environment to enable a hack for IRQ routing */
-  if (ai == ad_infos && ai->pci_vendor == 0x8086 && ai->pci_device == 0x2829 &&
+  if (ai == ad_infos && ai->PciVendor == 0x8086 && ai->PciDevice == 0x2829 &&
       !memcmp(pDevName, "VBOX HARDDISK", 13))
   {
@@ -933,5 +891,5 @@
   /* set link speed and power management options */
   DPRINTF(DBG_DETAILED, DBG_PREFIX": setting link speed and power management options\n");
-  tmp = readl(port_mmio + PORT_SCR_CTL) & ~0x00000fffUL;
+  tmp = readl(port_mmio + PORT_SCR_CTL) & ~0x00000fff;
   tmp |= (link_speed[ad_no(ai)][p] & 0x0f) << 4;
   tmp |= (link_power[ad_no(ai)][p] & 0x0f) << 8;
@@ -1098,5 +1056,5 @@
   if ((rc = ahci_stop_fis_rx(ai, p)) != 0)
   {
-    dprintf(0,__func__": failed to stop FIS receive (%d)\n", rc);
+    dprintf(0, DBG_PREFIX": failed to stop FIS receive (%d)\n", rc);
     return(rc);
   }
@@ -1105,5 +1063,5 @@
   if ((rc = ahci_stop_engine(ai, p)) != 0)
   {
-    dprintf(0,__func__": failed to stop port HW engine (%d)\n", rc);
+    dprintf(0, DBG_PREFIX": failed to stop port HW engine (%d)\n", rc);
     return(rc);
   }
@@ -1408,4 +1366,5 @@
     writel(port_mmio + PORT_CMD_ISSUE, 1);
     TimerInit(&Timer, timeout);
+    rc = 0;
     while (readl(port_mmio + PORT_CMD_ISSUE) & 1)
     {
@@ -1417,5 +1376,5 @@
     if (rc)
     {
-      DPRINTF(DBG_DETAILED, " timeout for IORB %x port=%x", vIorb, p);
+      DPRINTF(DBG_DETAILED, " timeout %x for IORB %x port=%x", timeout, vIorb, p);
       iorb_seterr(pIorb, IOERR_ADAPTER_TIMEOUT);
     }
@@ -1731,4 +1690,6 @@
         iorb_queue_del(&ai->ports[p].iorb_queue, vIorb);
         iorb_queue_add(&done_queue, vIorb, pIorb);
+        /* If we failed a NCQ command and then succeeded with a standard command, disable NCQ for this port */
+        if (add_workspace(pIorb)->no_ncq) ai->ports[p].devs[iorb_unit_device(pIorb)].ncq_max = 1;
         aws_free(add_workspace(pIorb));
       }
@@ -1775,5 +1736,5 @@
     #ifdef DEBUG
     u32 *unk = (u32 *) (port_dma_base(ai, p)->rx_fis + RX_FIS_UNK);
-    dprintf(0,"warning: unknown FIS %08lx %08lx %08lx %08lx\n", unk[0], unk[1], unk[2], unk[3]);
+    dprintf(0, DBG_PREFIX": warning: unknown FIS %08lx %08lx %08x %08x\n", unk[0], unk[1], unk[2], unk[3]);
     #endif
     reset_port = 1;
@@ -1781,10 +1742,10 @@
   if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR))
   {
-    dprintf(0,"warning: host bus [data] error for port #%d\n", p);
+    dprintf(0, DBG_PREFIX": warning: host bus [data] error port=%d\n", p);
     reset_port = 1;
   }
-  if (irq_stat & PORT_IRQ_IF_ERR && !(ai->flags & AHCI_HFLAG_IGN_IRQ_IF_ERR))
-  {
-    dprintf(0,"warning: interface fatal error for port #%d\n", p);
+  if (irq_stat & PORT_IRQ_IF_ERR && !(ai->quirks & AHCI_HFLAG_IGN_IRQ_IF_ERR))
+  {
+    dprintf(0, DBG_PREFIX": warning: interface fatal error port=%d\n", p);
     reset_port = 1;
   }
@@ -1794,5 +1755,5 @@
 
     ports_to_reset[ad_no(ai)] |= 1UL << p;
-    KernArmHook(reset_ctxhook_h, 0, 0);
+    SafeArmCtxHook(ResetCtxHook_h, 0);
 
     /* no point analyzing device errors after a reset... */
@@ -1800,12 +1761,10 @@
   }
 
-  #ifdef DEBUG
-  dprintf(0,"port #%d interrupt error status: 0x%08x; restarting port\n", p, irq_stat);
-  #else
+  #ifndef DEBUG
   if (!ai->ports[p].devs[0].atapi)
-  {
-    dprintf(0,"port #%d interrupt error status: 0x%08x; restarting port\n", p, irq_stat);
-  }
   #endif
+  {
+    dprintf(0,DBG_PREFIX": Port=%d status=%08x; restarting port\n", p, irq_stat);
+  }
 
   /* Handle device-specific errors. Those errors typically involve restarting
@@ -1814,5 +1773,5 @@
    */
   ports_to_restart[ad_no(ai)] |= 1UL << p;
-  KernArmHook(restart_ctxhook_h, 0, 0);
+  SafeArmCtxHook(RestartCtxHook_h, 0);
 }
 
Index: trunk/src/os2ahci/ahci.h
===================================================================
--- trunk/src/os2ahci/ahci.h	(revision 209)
+++ trunk/src/os2ahci/ahci.h	(revision 211)
@@ -77,15 +77,4 @@
 #define RX_FIS_SDB              0x58 /* offset of SDB FIS data */
 #define RX_FIS_UNK              0x60 /* offset of Unknown FIS data */
-
-#define board_ahci              0
-#define board_ahci_vt8251       1
-#define board_ahci_ign_iferr    2
-#define board_ahci_sb600        3
-#define board_ahci_mv           4
-#define board_ahci_sb700        5 /* for SB700 and SB800 */
-#define board_ahci_mcp65        6
-#define board_ahci_nopmp        7
-#define board_ahci_yesncq       8
-#define board_ahci_nosntf       9
 
 /* global controller registers */
@@ -156,21 +145,21 @@
 
 /* PORT_IRQ_{STAT,MASK} bits */
-#define PORT_IRQ_COLD_PRES      (1UL << 31) /* cold presence detect */
-#define PORT_IRQ_TF_ERR         (1UL << 30) /* task file error */
-#define PORT_IRQ_HBUS_ERR       (1UL << 29) /* host bus fatal error */
-#define PORT_IRQ_HBUS_DATA_ERR  (1UL << 28) /* host bus data error */
-#define PORT_IRQ_IF_ERR         (1UL << 27) /* interface fatal error */
-#define PORT_IRQ_IF_NONFATAL    (1UL << 26) /* interface non-fatal error */
-#define PORT_IRQ_OVERFLOW       (1UL << 24) /* xfer exhausted available S/G */
-#define PORT_IRQ_BAD_PMP        (1UL << 23) /* incorrect port multiplier */
-#define PORT_IRQ_PHYRDY         (1UL << 22) /* PhyRdy changed */
-#define PORT_IRQ_DEV_ILCK       (1UL << 7)  /* device interlock */
-#define PORT_IRQ_CONNECT        (1UL << 6)  /* port connect change status */
-#define PORT_IRQ_SG_DONE        (1UL << 5)  /* descriptor processed */
-#define PORT_IRQ_UNK_FIS        (1UL << 4)  /* unknown FIS rx'd */
-#define PORT_IRQ_SDB_FIS        (1UL << 3)  /* Set Device Bits FIS rx'd */
-#define PORT_IRQ_DMAS_FIS       (1UL << 2)  /* DMA Setup FIS rx'd */
-#define PORT_IRQ_PIOS_FIS       (1UL << 1)  /* PIO Setup FIS rx'd */
-#define PORT_IRQ_D2H_REG_FIS    (1UL << 0)  /* D2H Register FIS rx'd */
+#define PORT_IRQ_COLD_PRES      (1UL << 31) /* 80000000 cold presence detect */
+#define PORT_IRQ_TF_ERR         (1UL << 30) /* 40000000 task file error */
+#define PORT_IRQ_HBUS_ERR       (1UL << 29) /* 20000000 host bus fatal error */
+#define PORT_IRQ_HBUS_DATA_ERR  (1UL << 28) /* 10000000 host bus data error */
+#define PORT_IRQ_IF_ERR         (1UL << 27) /* 08000000 interface fatal error */
+#define PORT_IRQ_IF_NONFATAL    (1UL << 26) /* 04000000 interface non-fatal error */
+#define PORT_IRQ_OVERFLOW       (1UL << 24) /* 01000000 xfer exhausted available S/G */
+#define PORT_IRQ_BAD_PMP        (1UL << 23) /* 00800000 incorrect port multiplier */
+#define PORT_IRQ_PHYRDY         (1UL << 22) /* 00400000 PhyRdy changed */
+#define PORT_IRQ_DEV_ILCK       (1UL << 7)  /* 00000080 device interlock */
+#define PORT_IRQ_CONNECT        (1UL << 6)  /* 00000040 port connect change status */
+#define PORT_IRQ_SG_DONE        (1UL << 5)  /* 00000020 descriptor processed */
+#define PORT_IRQ_UNK_FIS        (1UL << 4)  /* 00000010 unknown FIS rx'd */
+#define PORT_IRQ_SDB_FIS        (1UL << 3)  /* 00000008 Set Device Bits FIS rx'd */
+#define PORT_IRQ_DMAS_FIS       (1UL << 2)  /* 00000004 DMA Setup FIS rx'd */
+#define PORT_IRQ_PIOS_FIS       (1UL << 1)  /* 00000002 PIO Setup FIS rx'd */
+#define PORT_IRQ_D2H_REG_FIS    (1UL << 0)  /* 00000001 D2H Register FIS rx'd */
 #define PORT_IRQ_FREEZE         (PORT_IRQ_HBUS_ERR | PORT_IRQ_IF_ERR   | \
                                  PORT_IRQ_CONNECT  | PORT_IRQ_PHYRDY   | \
Index: trunk/src/os2ahci/apm.c
===================================================================
--- trunk/src/os2ahci/apm.c	(revision 209)
+++ trunk/src/os2ahci/apm.c	(revision 211)
@@ -4,5 +4,5 @@
  * Copyright (c) 2011 thi.guten Software Development
  * Copyright (c) 2011 Mensys B.V.
- * Copyright (c) 2013-2021 David Azarewicz <david@88watts.net>
+ * Copyright (c) 2013-2023 David Azarewicz <david@88watts.net>
  *
  * Authors: Christian Mueller, Markus Thielen
Index: trunk/src/os2ahci/ata.c
===================================================================
--- trunk/src/os2ahci/ata.c	(revision 209)
+++ trunk/src/os2ahci/ata.c	(revision 211)
@@ -4,5 +4,5 @@
  * Copyright (c) 2011 thi.guten Software Development
  * Copyright (c) 2011 Mensys B.V.
- * Copyright (c) 2013-2021 David Azarewicz <david@88watts.net>
+ * Copyright (c) 2013-2023 David Azarewicz <david@88watts.net>
  *
  * Authors: Christian Mueller, Markus Thielen
@@ -121,5 +121,5 @@
       if (ata_cmd.lba_l & 0xf0000000UL)
       {
-        dprintf(0,"error: LBA-28 address %d has more than 28 bits\n", ata_cmd.lba_l);
+        dprintf(0, DBG_PREFIX": error: LBA-28 address %d has more than 28 bits\n", ata_cmd.lba_l);
         return(ATA_CMD_INVALID_PARM);
       }
@@ -172,5 +172,5 @@
 
     default:
-      dprintf(0,"error: v_ata_cmd() called with invalid parameter type (%d)\n", (int) ap);
+      dprintf(0, DBG_PREFIX": error: called with invalid parameter type (%d)\n", (int) ap);
       return(ATA_CMD_INVALID_PARM);
     }
@@ -255,13 +255,13 @@
         if (sg_size)
         {
-          dprintf(0, __func__": unaligned SG element\n");
+          dprintf(0, DBG_PREFIX": unaligned SG element\n");
           return -1;
         }
-        dprintf(0, __func__": too many S/G elements\n");
+        dprintf(0, DBG_PREFIX": too many S/G elements\n");
         return(i - 1);
       }
       if ((sg_addr & 1) || (chunk & 1))
       {
-        DPRINTF(0, DBG_PREFIX": warning: ata_cmd() called with unaligned S/G element(s)\n");
+        DPRINTF(0, DBG_PREFIX": warning: called with unaligned S/G element(s)\n");
         return(ATA_CMD_UNALIGNED_ADDR);
       }
@@ -278,5 +278,5 @@
 
   #if DEBUG & DBG_DETAILED
-  dprintf(0,"ATA command for %d.%d.%d, slot %d:\n", ad_no(ai), p, d, slot);
+  dprintf(0, DBG_PREFIX": ATA command for %d.%d.%d, slot %d:\n", ad_no(ai), p, d, slot);
   dHexDump(0,cmd_hdr, offsetof(AHCI_CMD_HDR, reserved), "cmd_hdr: ");
   dHexDump(0,&ata_cmd, sizeof(ata_cmd), "ata_cmd: ");
@@ -549,5 +549,5 @@
     {
       /* more than 32 bits for number of sectors */
-      dprintf(0,"warning: limiting disk %d.%d.%d to 2TB\n",
+      dprintf(0, DBG_PREFIX": warning: limiting disk %d.%d.%d to 2TB\n",
               iorb_unit_adapter(pIorb), iorb_unit_port(pIorb),
               iorb_unit_device(pIorb));
@@ -651,5 +651,5 @@
   int rc;
 
-  if (ullLba >= (1UL << 28) || count > 256 || add_workspace(pIorb)->is_ncq)
+  if (add_workspace(pIorb)->is_ncq || ullLba >= (1 << 28) || count > 256 || (ullLba+count) >= (1 << 28))
   {
     /* need LBA48 for this command */
Index: trunk/src/os2ahci/ata.h
===================================================================
--- trunk/src/os2ahci/ata.h	(revision 209)
+++ trunk/src/os2ahci/ata.h	(revision 211)
@@ -4,5 +4,5 @@
  * Copyright (c) 2011 thi.guten Software Development
  * Copyright (c) 2011 Mensys B.V.
- * Copyright (c) 2013-2021 David Azarewicz <david@88watts.net>
+ * Copyright (c) 2013-2023 David Azarewicz <david@88watts.net>
  *
  * Authors: Christian Mueller, Markus Thielen
Index: trunk/src/os2ahci/atapi.c
===================================================================
--- trunk/src/os2ahci/atapi.c	(revision 209)
+++ trunk/src/os2ahci/atapi.c	(revision 211)
@@ -4,5 +4,5 @@
  * Copyright (c) 2011 thi.guten Software Development
  * Copyright (c) 2011 Mensys B.V.
- * Copyright (c) 2013-2021 David Azarewicz <david@88watts.net>
+ * Copyright (c) 2013-2023 David Azarewicz <david@88watts.net>
  *
  * Authors: Christian Mueller, Markus Thielen
Index: trunk/src/os2ahci/atapi.h
===================================================================
--- trunk/src/os2ahci/atapi.h	(revision 209)
+++ trunk/src/os2ahci/atapi.h	(revision 211)
@@ -4,5 +4,5 @@
  * Copyright (c) 2011 thi.guten Software Development
  * Copyright (c) 2011 Mensys B.V.
- * Copyright (c) 2013-2021 David Azarewicz <david@88watts.net>
+ * Copyright (c) 2013-2023 David Azarewicz <david@88watts.net>
  *
  * Authors: Christian Mueller, Markus Thielen
Index: trunk/src/os2ahci/ctxhook.c
===================================================================
--- trunk/src/os2ahci/ctxhook.c	(revision 209)
+++ trunk/src/os2ahci/ctxhook.c	(revision 211)
@@ -4,5 +4,5 @@
  * Copyright (c) 2011 thi.guten Software Development
  * Copyright (c) 2011 Mensys B.V.
- * Copyright (c) 2013-2021 David Azarewicz <david@88watts.net>
+ * Copyright (c) 2013-2023 David Azarewicz <david@88watts.net>
  *
  * Authors: Christian Mueller, Markus Thielen
@@ -31,10 +31,10 @@
 
 /* port restart context hook and input data */
-ULONG           restart_ctxhook_h;
+ULONG           RestartCtxHook_h;
 volatile u32    ports_to_restart[MAX_AD];
 
 /* port reset context hook and input data */
-ULONG           reset_ctxhook_h;
-ULONG           th_reset_watchdog;
+ULONG           ResetCtxHook_h;
+ULONG           th_watchdog;
 volatile u32    ports_to_reset[MAX_AD];
 IORB_QUEUE      abort_queue;
@@ -42,4 +42,53 @@
 /* trigger engine context hook and input data */
 ULONG           engine_ctxhook_h;
+
+#define QUEUEDEPTH 8
+static struct _ctxq_
+{
+  ULONG ulHandle;
+  ULONG ulArg;
+} CtxQueue[QUEUEDEPTH] = {0};
+static ULONG ulCtxStatusFlag = 0;
+
+void SafeArmCtxHook(ULONG ulHandle, ULONG armData)
+{
+  USHORT i;
+
+  i = LockInc(&ulCtxStatusFlag);
+
+  if (i)
+  {
+    i--;
+    if (i < QUEUEDEPTH)
+    {
+      CtxQueue[i].ulHandle = ulHandle;
+      CtxQueue[i].ulArg = armData;
+    }
+  }
+  else
+  {
+    KernArmHook(ulHandle, armData, 0);
+  }
+}
+
+void ClearThreadStatus(ULONG ulHandle)
+{
+  USHORT i;
+
+  i = LockDec(&ulCtxStatusFlag);
+
+  if (i)
+  {
+    i--;
+    if (i < QUEUEDEPTH)
+    {
+      KernArmHook(CtxQueue[i].ulHandle, CtxQueue[i].ulArg, 0);
+    }
+    else
+    {
+      KernArmHook(ulHandle, 0, 0);
+    }
+  }
+}
 
 /******************************************************************************
@@ -78,5 +127,5 @@
  * in the interrupt and error handlers.
  */
-void _Syscall restart_ctxhook(ULONG parm)
+void _Syscall RestartCtxHook(ULONG parm)
 {
   IORB_QUEUE done_queue;
@@ -85,4 +134,6 @@
   IORBH FAR16DATA *vIorb;
   IORBH FAR16DATA *vNext;
+  IORBH *pIorb;
+  ADD_WORKSPACE *aws;
   u8 *port_mmio;
   int rearm_ctx_hook;
@@ -97,8 +148,16 @@
   rearm_ctx_hook = 0;
 
-  DPRINTF(DBG_FUNCBEG, DBG_PREFIX": restart_ctxhook() started\n");
+  AhciStats.ulSoftErrorCount++;
+  DPRINTF(0, DBG_PREFIX": BEG\n");
   memset(&done_queue, 0x00, sizeof(done_queue));
 
   spin_lock(drv_lock);
+
+  if (th_watchdog != 0)
+  {
+    /* watchdog timer still active -- just reset it */
+    Timer_CancelTimer(th_watchdog);
+    th_watchdog = 0;
+  }
 
   for (a = 0; a < ad_info_cnt; a++)
@@ -124,18 +183,24 @@
         need_reset = 0;
 
-        DPRINTF(DBG_DETAILED, DBG_PREFIX": port %d, TF_DATA: 0x%x\n", p, readl(port_mmio + PORT_TFDATA));
+        DPRINTF(DBG_DETAILED, DBG_PREFIX": port=%d TF_DATA=0x%x\n", p, readl(port_mmio + PORT_TFDATA));
 
         /* get "current command slot"; only valid if there are no NCQ cmds */
         ccs = (int) ((readl(port_mmio + PORT_CMD) >> 8) & 0x1f);
-        DPRINTF(DBG_DETAILED, DBG_PREFIX": PORT_CMD      = 0x%x\n", ccs);
+        DPRINTF(DBG_DETAILED, DBG_PREFIX": PORT_CMD=0x%x\n", ccs);
 
         for (vIorb = ai->ports[p].iorb_queue.vRoot; vIorb != FAR16NULL; vIorb = vNext)
         {
-          IORBH *pIorb = Far16ToFlat(vIorb);
-          ADD_WORKSPACE *aws = add_workspace(pIorb);
+          pIorb = Far16ToFlat(vIorb);
+          aws = add_workspace(pIorb);
           vNext = pIorb->f16NxtIORB;
 
           if (aws->queued_hw)
           {
+            if (aws->timer != 0)
+            {
+              Timer_CancelTimer(aws->timer);
+              aws->timer = 0;
+            }
+
             if (ai->ports[p].ncq_cmds & (1UL << aws->cmd_slot))
             {
@@ -144,4 +209,8 @@
               aws->no_ncq = 1;
               need_reset = 1;
+              DPRINTF(0, DBG_PREFIX": failing IORB: %x NCQ slot=%x\n", vIorb, aws->cmd_slot);
+              #ifdef DEBUG
+              DumpIorb(pIorb, vIorb);
+              #endif
             }
             else
@@ -152,5 +221,8 @@
               {
                 /* this is the non-NCQ command that failed */
-                DPRINTF(0, DBG_PREFIX": failing IORB: %x\n", vIorb);
+                DPRINTF(0, DBG_PREFIX": failing IORB: %x slot=%x\n", vIorb, aws->cmd_slot);
+                #ifdef DEBUG
+                DumpIorb(pIorb, vIorb);
+                #endif
                 vProblemIorb = vIorb;
               }
@@ -179,5 +251,5 @@
         if (ai->ports[p].ncq_cmds != 0 || ai->ports[p].reg_cmds != 0)
         {
-          DPRINTF(0, DBG_PREFIX": warning: commands issued not 0 (%08lx/%08lx); resetting...\n",
+          DPRINTF(0, DBG_PREFIX": warning: commands issued not 0 (%08x/%08x); resetting...\n",
                   ai->ports[p].ncq_cmds, ai->ports[p].reg_cmds);
           need_reset = 1;
@@ -260,8 +332,9 @@
   spin_unlock(drv_lock);
 
+  DPRINTF(0, DBG_PREFIX": Resuming\n");
   /* call notification routine on all IORBs which have completed */
   for (vIorb = done_queue.vRoot; vIorb != FAR16NULL; vIorb = vNext)
   {
-    IORBH *pIorb = Far16ToFlat(vIorb);
+    pIorb = Far16ToFlat(vIorb);
     vNext = pIorb->f16NxtIORB;
 
@@ -278,5 +351,5 @@
   spin_unlock(drv_lock);
 
-  DPRINTF(DBG_FUNCEND, DBG_PREFIX": restart_ctxhook() completed\n");
+  DPRINTF(0, DBG_PREFIX": END Rearm=%x\n", rearm_ctx_hook);
 
   /* Check whether we have to rearm ourselves because some adapters were busy
@@ -285,7 +358,12 @@
   if (rearm_ctx_hook)
   {
-    msleep(250);
-    KernArmHook(restart_ctxhook_h, 0, 0);
-  }
+    /* we cannot rearm ourself because we will execute immediately leaving
+     * no time to process and clear the reason we need to rearm. Therefore
+     * we set the timer again.
+     */
+    Timer_StartTimerMS(&th_watchdog, 250, WatchdogTimer, RestartCtxHook_h);
+  }
+
+  ClearThreadStatus(RestartCtxHook_h);
   KernThunkStackTo16();
 }
@@ -317,5 +395,5 @@
  * the upstream code might reuse the IORBs before we're done with them.
  */
-void _Syscall reset_ctxhook(ULONG parm)
+void _Syscall ResetCtxHook(ULONG ulArg)
 {
   IORB_QUEUE done_queue;
@@ -323,4 +401,6 @@
   IORBH FAR16DATA *vIorb;
   IORBH FAR16DATA *vNext;
+  IORBH *pIorb;
+  ADD_WORKSPACE *aws;
   int rearm_ctx_hook;
   int a;
@@ -332,14 +412,35 @@
   rearm_ctx_hook = 0;
 
-  DPRINTF(DBG_FUNCBEG, DBG_PREFIX": reset_ctxhook() started\n");
+  AhciStats.ulHardErrorCount++;
+  DPRINTF(0, DBG_PREFIX": BEG Arg=%x\n", ulArg);
   memset(&done_queue, 0x00, sizeof(done_queue));
 
+  if (th_watchdog != 0)
+  {
+    /* watchdog timer still active -- just reset it */
+    Timer_CancelTimer(th_watchdog);
+    th_watchdog = 0;
+  }
+
   spin_lock(drv_lock);
 
-  if (th_reset_watchdog != 0)
-  {
-    /* watchdog timer still active -- just reset it */
-    Timer_CancelTimer(th_reset_watchdog);
-    th_reset_watchdog = 0;
+  if (ulArg)
+  {
+    /* Move the timed-out IORB to the abort queue. Since it's possible that the
+     * IORB has completed after the timeout has expired but before we got to
+     * this line of code, we'll check the return code of iorb_queue_del(): If it
+     * returns an error, the IORB must have completed a few microseconds ago and
+     * there is no timeout.
+     */
+    vIorb = (IORBH FAR16DATA *)CastULONGToFar16(ulArg);
+    pIorb = Far16ToFlat(vIorb);
+    a = iorb_unit_adapter(pIorb);
+    p = iorb_unit_port(pIorb);
+    if (iorb_queue_del(&ad_infos[a].ports[p].iorb_queue, vIorb) == 0)
+    {
+      pIorb = Far16ToFlat(vIorb);
+      iorb_queue_add(&abort_queue, vIorb, pIorb);
+      pIorb->ErrorCode = IOERR_ADAPTER_TIMEOUT;
+    }
   }
 
@@ -347,9 +448,10 @@
   for (vIorb = abort_queue.vRoot; vIorb != FAR16NULL; vIorb = vNext)
   {
-    IORBH *pIorb = Far16ToFlat(vIorb);
+    pIorb = Far16ToFlat(vIorb);
     vNext = pIorb->f16NxtIORB;
     a = iorb_unit_adapter(pIorb);
     p = iorb_unit_port(pIorb);
     ai = ad_infos + a;
+    aws = add_workspace(pIorb);
 
     if (ai->busy)
@@ -365,6 +467,12 @@
 
     /* reset port if the IORB has already been queued to hardware */
-    if (add_workspace(pIorb)->queued_hw)
-    {
+    if (aws->queued_hw)
+    {
+      if (aws->timer != 0)
+      {
+        Timer_CancelTimer(aws->timer);
+        aws->timer = 0;
+      }
+
       /* prepare port reset */
       ports_to_reset[a] |= (1UL << p);
@@ -411,6 +519,7 @@
         {
           IORBH *pIorb = Far16ToFlat(vIorb);
-          ADD_WORKSPACE *aws = add_workspace(pIorb);
           vNext = pIorb->f16NxtIORB;
+
+          aws = add_workspace(pIorb);
 
           if (aws->queued_hw)
@@ -421,5 +530,4 @@
               /* we can retry this IORB */
               iorb_requeue(pIorb);
-
             }
             else
@@ -438,8 +546,10 @@
   spin_unlock(drv_lock);
 
+  DPRINTF(0, DBG_PREFIX": Resuming\n");
+
   /* complete all aborted IORBs */
   for (vIorb = done_queue.vRoot; vIorb != FAR16NULL; vIorb = vNext)
   {
-    IORBH *pIorb = Far16ToFlat(vIorb);
+    pIorb = Far16ToFlat(vIorb);
     vNext = pIorb->f16NxtIORB;
 
@@ -457,5 +567,5 @@
   spin_unlock(drv_lock);
 
-  DPRINTF(DBG_FUNCEND, DBG_PREFIX": reset_ctxhook() completed\n");
+  DPRINTF(0, DBG_PREFIX": END Rearm=%x\n", rearm_ctx_hook);
 
   /* Check whether we have to rearm ourselves because some adapters were busy
@@ -468,9 +578,8 @@
      * we set the timer again.
      */
-    //msleep(250);
-    //KernArmHook(reset_ctxhook_h, 0, 0);
-    Timer_StartTimerMS(&th_reset_watchdog, 250, reset_watchdog, 0);
-  }
-
+    Timer_StartTimerMS(&th_watchdog, 250, WatchdogTimer, ResetCtxHook_h);
+  }
+
+  ClearThreadStatus(ResetCtxHook_h);
   KernThunkStackTo16();
 }
Index: trunk/src/os2ahci/ioctl.c
===================================================================
--- trunk/src/os2ahci/ioctl.c	(revision 209)
+++ trunk/src/os2ahci/ioctl.c	(revision 211)
@@ -4,5 +4,5 @@
  * Copyright (c) 2011 thi.guten Software Development
  * Copyright (c) 2011 Mensys B.V.
- * Copyright (c) 2013-2021 David Azarewicz <david@88watts.net>
+ * Copyright (c) 2013-2023 David Azarewicz <david@88watts.net>
  *
  * Authors: Christian Mueller, Markus Thielen
Index: trunk/src/os2ahci/ioctl.h
===================================================================
--- trunk/src/os2ahci/ioctl.h	(revision 209)
+++ trunk/src/os2ahci/ioctl.h	(revision 211)
@@ -4,5 +4,5 @@
  * Copyright (c) 2011 thi.guten Software Development
  * Copyright (c) 2011 Mensys B.V.
- * Copyright (c) 2013-2021 David Azarewicz <david@88watts.net>
+ * Copyright (c) 2013-2023 David Azarewicz <david@88watts.net>
  *
  * Authors: Christian Mueller, Markus Thielen
@@ -30,4 +30,5 @@
 #define OS2AHCI_IOCTL_GET_DEVLIST      0x01
 #define OS2AHCI_IOCTL_PASSTHROUGH      0x02
+#define OS2AHCI_IOCTL_DEBUG            0xd1
 
 /* IOCTL definitions from s506oem.h (primarily required for SMART calls) */
@@ -199,5 +200,4 @@
 } UnitInformationData;
 
-
 #pragma pack()
 
Index: trunk/src/os2ahci/os2ahci.c
===================================================================
--- trunk/src/os2ahci/os2ahci.c	(revision 209)
+++ trunk/src/os2ahci/os2ahci.c	(revision 211)
@@ -4,5 +4,5 @@
  * Copyright (c) 2011 thi.guten Software Development
  * Copyright (c) 2011 Mensys B.V.
- * Copyright (c) 2013-2021 David Azarewicz <david@88watts.net>
+ * Copyright (c) 2013-2023 David Azarewicz <david@88watts.net>
  *
  * Authors: Christian Mueller, Markus Thielen
@@ -26,4 +26,5 @@
  */
 
+#define INCL_LONGLONG
 #include "os2ahci.h"
 #include "ioctl.h"
@@ -58,5 +59,5 @@
 int thorough_scan = 1; /* if != 0, perform thorough PCI scan */
 int init_reset = 1;    /* if != 0, reset ports during init */
-int force_write_cache; /* if != 0, force write cache */
+int force_write_cache = 0; /* if != 0, force write cache */
 int iVerbose = 0;     /* default is quiet. 1=show sign on banner, >1=show adapter info during boot */
 int use_mbr_test = 1;
@@ -190,4 +191,5 @@
   memset(ad_infos, 0, sizeof(ad_infos));
   memset(emulate_scsi, 1, sizeof(emulate_scsi)); /* set default enabled */
+  memset(enable_ncq, 1, sizeof(enable_ncq)); /* set default enabled */
   UtSetDriverName("OS2AHCI$");
   Header.ulCaps |= DEV_ADAPTER_DD; /* DAZ This flag is not really needed. */
@@ -423,5 +425,5 @@
   if (iVerbose) iprintf("OS2AHCI.ADD: driver version %d.%02d", DMAJOR, DMINOR);
 
-  #ifdef TESTVER
+  #if defined(TESTVER) && defined(DEBUG)
   #include "testver.c"
   #endif
@@ -443,6 +445,6 @@
 
     /* allocate context hooks */
-    KernAllocateContextHook(restart_ctxhook, 0, &restart_ctxhook_h);
-    KernAllocateContextHook(reset_ctxhook, 0, &reset_ctxhook_h);
+    KernAllocateContextHook(RestartCtxHook, 0, &RestartCtxHook_h);
+    KernAllocateContextHook(ResetCtxHook, 0, &ResetCtxHook_h);
     KernAllocateContextHook(engine_ctxhook, 0, &engine_ctxhook_h);
 
@@ -481,5 +483,4 @@
 {
   DPRINTF(DBG_FUNCBEG, DBG_PREFIX": IOCTL 0x%x/0x%x\n", ioctl->ioctl.bCategory, ioctl->ioctl.bFunction);
-  AhciStats.ulTestCount2++;
 
   switch (ioctl->ioctl.bCategory)
@@ -599,7 +600,7 @@
     memset(&pIorb->ADDWorkSpace, 0x00, sizeof(ADD_WORKSPACE));
 
-    #ifdef DEBUG
-    DumpIorb(pIorb); /* DAZ TESTING */
-    #endif
+    //#ifdef DEBUG
+    //DumpIorb(pIorb); /* DAZ TESTING */
+    //#endif
 
     if (iorb_driver_level(pIorb))
@@ -622,5 +623,5 @@
       {
         /* unit handle outside of the allowed range */
-        dprintf(0,"warning: IORB for %d.%d.%d out of range\n", a, p, d);
+        dprintf(0, DBG_PREFIX": ERROR: IORB for %d.%d.%d is out of range\n", a, p, d);
         pIorb->Status = IORB_ERROR;
         pIorb->ErrorCode = IOERR_CMD_SYNTAX;
@@ -920,5 +921,5 @@
 
     /* trigger reset context hook which will finish the abort processing */
-    KernArmHook(reset_ctxhook_h, 0, 0);
+    SafeArmCtxHook(ResetCtxHook_h, 0);
     break;
 
@@ -1071,5 +1072,5 @@
     if ((u32)(pPtr + 1) - (u32)pDt > pIorb_conf->DeviceTableLen)
     {
-      dprintf(0,"error: device table provided by DASD too small\n");
+      dprintf(0, DBG_PREFIX": error: device table provided by DASD too small\n");
       iorb_seterr(pIorb, IOERR_CMD_SW_RESOURCE);
       goto iocm_device_table_done;
@@ -1100,5 +1101,5 @@
         if (ad_info->busy)
         {
-          dprintf(0,"error: port scan requested while adapter was busy\n");
+          dprintf(0, DBG_PREFIX": error: port scan requested while adapter was busy\n");
           iorb_seterr(pIorb, IOERR_CMD_SW_RESOURCE);
           goto iocm_device_table_done;
@@ -1112,5 +1113,5 @@
         if (rc != 0)
         {
-          dprintf(0,"error: port scan failed on adapter #%d\n", dta);
+          dprintf(0, DBG_PREFIX": error: port scan failed on adapter #%d\n", dta);
           iorb_seterr(pIorb, IOERR_CMD_SW_RESOURCE);
           goto iocm_device_table_done;
@@ -1533,7 +1534,7 @@
  * separate function which is invoked via a context hook.
  */
-void __syscall timeout_callback(ULONG timer_handle, ULONG p1)
-{
-  IORBH FAR16DATA *vIorb = (IORBH FAR16DATA *)CastULONGToFar16(p1);
+void __syscall timeout_callback(ULONG timer_handle, ULONG ulArg)
+{
+  IORBH FAR16DATA *vIorb = (IORBH FAR16DATA *)CastULONGToFar16(ulArg);
   IORBH *pIorb = Far16ToFlat(vIorb);
   int a = iorb_unit_adapter(pIorb);
@@ -1541,19 +1542,5 @@
 
   Timer_CancelTimer(timer_handle);
-  dprintf(0,"timeout for IORB %x port=%x\n", vIorb, p);
-
-  /* Move the timed-out IORB to the abort queue. Since it's possible that the
-   * IORB has completed after the timeout has expired but before we got to
-   * this line of code, we'll check the return code of iorb_queue_del(): If it
-   * returns an error, the IORB must have completed a few microseconds ago and
-   * there is no timeout.
-   */
-  spin_lock(drv_lock);
-  if (iorb_queue_del(&ad_infos[a].ports[p].iorb_queue, vIorb) == 0)
-  {
-    iorb_queue_add(&abort_queue, vIorb, pIorb);
-    pIorb->ErrorCode = IOERR_ADAPTER_TIMEOUT;
-  }
-  spin_unlock(drv_lock);
+  dprintf(0, DBG_PREFIX": timeout for IORB %x port=%x.%x\n", ulArg, a, p);
 
   /* Trigger abort processing function. We don't really care whether this
@@ -1568,13 +1555,5 @@
    *    will process our IORB as well.
    */
-  KernArmHook(reset_ctxhook_h, 0, 0);
-
-  /* Set up a watchdog timer which calls the context hook manually in case
-   * some kernel thread is looping around the IORB_COMPLETE status bit
-   * without yielding the CPU (kernel threads don't preempt). This shouldn't
-   * happen per design because kernel threads are supposed to yield but it
-   * does in the early boot phase.
-   */
-  Timer_StartTimerMS(&th_reset_watchdog, 5000, reset_watchdog, 0);
+  SafeArmCtxHook(ResetCtxHook_h, ulArg);
 }
 
@@ -1590,19 +1569,15 @@
  * problems during the early boot phase.
  */
-void __syscall reset_watchdog(ULONG timer_handle, ULONG p1)
+void __syscall WatchdogTimer(ULONG timer_handle, ULONG ulArg)
 {
   /* reset watchdog timer */
   Timer_CancelTimer(timer_handle);
-  th_reset_watchdog = 0;
-  dprintf(0,"reset watchdog invoked\n");
-
-  /* You cannot call the reset_ctxhook directly because it does things
+  th_watchdog = 0;
+  dprintf(0, DBG_PREFIX": BEG %s\n", ulArg==ResetCtxHook_h?"Reset":"Restart");
+
+  /* The ctxhook cannot be called directly because it does things
    * that are illegal in an interrupt handler.
    */
-
-  KernArmHook(reset_ctxhook_h, 0, 0);
-
-  /* call context hook manually */
-  //reset_ctxhook(0);
+  SafeArmCtxHook(ulArg, 0);
 }
 
@@ -1634,5 +1609,5 @@
   if ((u32)(pUi + 1) - (u32)pDt > pIorb_conf->DeviceTableLen)
   {
-    dprintf(0,"error: device table provided by DASD too small\n");
+    dprintf(0, DBG_PREFIX": error: device table provided by DASD too small\n");
     iorb_seterr(&pIorb_conf->iorbh, IOERR_CMD_SW_RESOURCE);
     return(-1);
Index: trunk/src/os2ahci/os2ahci.h
===================================================================
--- trunk/src/os2ahci/os2ahci.h	(revision 209)
+++ trunk/src/os2ahci/os2ahci.h	(revision 211)
@@ -4,5 +4,5 @@
  * Copyright (c) 2011 thi.guten Software Development
  * Copyright (c) 2011 Mensys B.V.
- * Copyright (c) 2013-2021 David Azarewicz <david@88watts.net>
+ * Copyright (c) 2013-2023 David Azarewicz <david@88watts.net>
  *
  * Authors: Christian Mueller, Markus Thielen
@@ -107,4 +107,17 @@
   parm nomemory [eax] [bx] value [eax] modify nomemory exact [eax];
 
+ULONG LockInc(ULONG *ulCounter);
+#pragma aux LockInc = \
+  "mov eax, 1" \
+  "lock xadd [ebx],eax" \
+  parm [ebx] value [eax] modify exact [eax];
+
+ULONG LockDec(ULONG *ulCounter);
+#pragma aux LockDec = \
+  "mov eax, -1" \
+  "lock xadd [ebx],eax" \
+  "dec eax" \
+  parm [ebx] value [eax] modify exact [eax];
+
 /* stdarg.h macros with explicit far pointers */
 typedef char *va_list;
@@ -112,7 +125,4 @@
 #define va_arg(va, type)      ((type *) (va += sizeof(type)))[-1]
 #define va_end(va)            va = 0
-
-/* stddef macros */
-#define offsetof(s, e) ((u32)&((s *)0)->e)
 
 /* shortcut macros */
@@ -222,6 +232,6 @@
   u32   class;           /* PCI device class */
   u32   class_mask;      /* bits to match when scanning for 'class' */
-  u32   board;           /* AHCI controller board type (board_* constants) */
-  char  *chipname;       /* human readable chip ID string */
+  char  *pChipName;      /* human readable chip ID string */
+  u32   quirks;          /* AHCI controller quirks */
 } PCI_ID;
 
@@ -275,36 +285,34 @@
 /* adapter information structure */
 typedef struct {
-  PCI_ID       *pci;                   /* 00 pointer to corresponding PCI ID */
-
-  unsigned      port_max : 5;          /* 04 maximum port number (0..AHCI_MAX_PORTS-1) */
+  u16           BusDevFunc;            /* 00 PCI bus number PCI device and function number */
+  u16           PciVendor;             /* 02 */
+  u16           PciDevice;             /* 04 */
+  u8            irq;                   /* 06 interrupt number */
+  u8            irq_pin;               /* 07 irq pin */
+
+  u32           cap;                   /* 08 working copy of CAP register */
+  u32           cap2;                  /* 0c working copy of CAP2 register */
+  HRESOURCE     rm_bars[6];            /* 10 resource handle for MMIO and I/O BARs */
+  HRESOURCE     rm_adh;                /* 28 resource handle for adapter */
+  char          *pChipName;            /* 2c pointer to chip name */
+  u32           quirks;                /* 30 adapter quirks */
+
+  unsigned      port_max : 5;          /* 34 maximum port number (0..AHCI_MAX_PORTS-1) */
   unsigned      cmd_max : 5;           /*    maximum cmd slot number (0-31) */
   unsigned      port_scan_done : 1;    /*    if != 0, port scan already done */
   unsigned      busy : 1;              /*    if != 0, adapter is busy */
   unsigned      hw_ports : 6;          /*    number of ports as reported by the hardware */
-  unsigned      int_set:1;             /* interrupt has been set */
-
-  u32           port_map;              /* 08   bitmap of active ports */
-  u16           pci_vendor;            /* 0c */
-  u16           pci_device;            /* 0e */
+  unsigned      int_set:1;             /*    interrupt has been set */
+
+  u32           port_map;              /* 38 bitmap of active ports */
 
   /* initial adapter configuration from BIOS */
-  u32           bios_config[HOST_CAP2 / sizeof(u32) + 1];  /* 10  0x24 / 4 + 1 = 0x0a dwords = 0x28 bytes*/
-
-  u32           cap;                   /* 38 working copy of CAP register */
-  u32           cap2;                  /* 3c working copy of CAP2 register */
-  u32           flags;                 /* 40 adapter flags */
-
-  HRESOURCE     rm_adh;                /* 44 resource handle for adapter */
-  HRESOURCE     rm_bars[6];            /* 48 resource handle for MMIO and I/O BARs */
-
-  u16           bus_dev_func;          /* 64 PCI bus number PCI device and function number */
-  u8            irq;                   /* 66 interrupt number */
-  u8            irq_pin;               /* 67 irq pin */
-
-  u32           mmio_phys;             /* 68 physical address of MMIO region */
-  u32           mmio_size;             /* 6c size of MMIO region */
-  u8           *mmio;                  /* 70 pointer to this adapter's MMIO region */
-
-  P_INFO        ports[AHCI_MAX_PORTS]; /* 74 SATA ports on this adapter */
+  u32           bios_config[HOST_CAP2 / sizeof(u32) + 1];  /* 3c  0x24 / 4 + 1 = 0x0a dwords = 0x28 bytes*/
+
+  u32           mmio_phys;             /* 64 physical address of MMIO region */
+  u32           mmio_size;             /* 68 size of MMIO region */
+  u8           *mmio;                  /* 6c pointer to this adapter's MMIO region */
+
+  P_INFO        ports[AHCI_MAX_PORTS]; /* 70 SATA ports on this adapter */
 } AD_INFO;
 
@@ -364,6 +372,6 @@
   ULONG ulSize;
   ULONG ulVersion;
-  ULONG ulTestCount3;
-  ULONG ulTestCount2;
+  ULONG ulHardErrorCount;
+  ULONG ulSoftErrorCount;
   ULONG ulTestCount1;
 } AHCISTATS;
@@ -409,5 +417,5 @@
 extern void unlock_adapter(AD_INFO *ai);
 extern void __syscall timeout_callback(ULONG timer_handle, ULONG p1);
-extern void __syscall reset_watchdog(ULONG timer_handle, ULONG p1);
+extern void __syscall WatchdogTimer(ULONG timer_handle, ULONG p1);
 
 /* ahci.c */
@@ -459,13 +467,12 @@
 extern int add_pci_id(u16 vendor, u16 device);
 extern void scan_pci_bus(void);
-extern int pci_enable_int(USHORT BusDevFunc);
 extern void pci_hack_virtualbox(void);
 extern char *vendor_from_id(u16 vendor);
-extern char *device_from_id(u16 device);
 
 /* ctxhook.c */
-extern void _Syscall restart_ctxhook(ULONG parm);
-extern void _Syscall reset_ctxhook(ULONG parm);
+extern void _Syscall RestartCtxHook(ULONG parm);
+extern void _Syscall ResetCtxHook(ULONG parm);
 extern void _Syscall engine_ctxhook(ULONG parm);
+extern void SafeArmCtxHook(ULONG ulHandle, ULONG armData);
 
 /* apm.c */
@@ -477,4 +484,5 @@
 extern USHORT ioctl_get_devlist(REQPACKET *ioctl);
 extern USHORT ioctl_passthrough(REQPACKET *ioctl);
+extern USHORT ioctl_debug(REQPACKET *ioctl);
 extern USHORT ioctl_gen_dsk(REQPACKET *ioctl);
 extern USHORT ioctl_smart(REQPACKET *ioctl);
@@ -504,10 +512,10 @@
 
 /* port restart context hook and input data */
-extern ULONG restart_ctxhook_h;
+extern ULONG RestartCtxHook_h;
 extern volatile u32 ports_to_restart[MAX_AD];
 
 /* port reset context hook and input data */
-extern ULONG reset_ctxhook_h;
-extern ULONG th_reset_watchdog;
+extern ULONG ResetCtxHook_h;
+extern ULONG th_watchdog;
 extern volatile u32 ports_to_reset[MAX_AD];
 extern IORB_QUEUE abort_queue;
@@ -525,5 +533,5 @@
 
 #ifdef DEBUG
-extern void DumpIorb(IORBH *pIorb);
+extern void DumpIorb(IORBH *pIorb, IORBH FAR16DATA *vIorb);
 #endif
 
Index: trunk/src/os2ahci/pci.c
===================================================================
--- trunk/src/os2ahci/pci.c	(revision 209)
+++ trunk/src/os2ahci/pci.c	(revision 211)
@@ -4,5 +4,5 @@
  * Copyright (c) 2011 thi.guten Software Development
  * Copyright (c) 2011 Mensys B.V.
- * Copyright (c) 2013-2021 David Azarewicz <david@88watts.net>
+ * Copyright (c) 2013-2023 David Azarewicz <david@88watts.net>
  *
  * Authors: Christian Mueller, Markus Thielen
@@ -27,4 +27,5 @@
 
 #include "os2ahci.h"
+#include "pci_regs.h"
 
 /* offset of PCI base address register (BAR) in the PCI config space */
@@ -36,30 +37,4 @@
 
 /******************************************************************************
- * chipset/controller name strings
- */
-static char chip_esb2[]    = "ESB2";
-static char chip_ich8[]    = "ICH8";
-static char chip_ich8m[]   = "ICH8M";
-static char chip_ich9[]    = "ICH9";
-static char chip_ich9m[]   = "ICH9M";
-static char chip_ich10[]   = "ICH10";
-static char chip_pchahci[] = "PCH AHCI";
-static char chip_pchraid[] = "PCH RAID";
-static char chip_tolapai[] = "Tolapai";
-static char chip_sb600[]   = "SB600";
-static char chip_sb700[]   = "SB700/800";
-static char chip_vt8251[]  = "VT8251";
-static char chip_mcp65[]   = "MCP65";
-static char chip_mcp67[]   = "MCP67";
-static char chip_mcp73[]   = "MCP73";
-static char chip_mcp77[]   = "MCP77";
-static char chip_mcp79[]   = "MCP79";
-static char chip_mcp89[]   = "MCP689";
-static char chip_sis968[]  = "968";
-
-static char s_generic[]    = "Generic";
-
-
-/******************************************************************************
  * PCI vendor and device IDs for known AHCI adapters. Copied from the Linux
  * AHCI driver.
@@ -69,170 +44,169 @@
 {
   /* Intel
-   * NOTE: ICH5 controller does NOT support AHCI, so we do
-   *       not add it here! */
-  { PCI_VDEVICE(INTEL, 0x2652), board_ahci,            "ICH6"       }, /* ICH6 */
-  { PCI_VDEVICE(INTEL, 0x2653), board_ahci,            "ICH6M"      }, /* ICH6M */
-  { PCI_VDEVICE(INTEL, 0x27c1), board_ahci,            "ICH7"       }, /* ICH7 */
-  { PCI_VDEVICE(INTEL, 0x27c5), board_ahci,            "ICH7M"      }, /* ICH7M */
-  { PCI_VDEVICE(INTEL, 0x27c3), board_ahci,            "ICH7R"      }, /* ICH7R */
-  { PCI_VDEVICE(AL,    0x5288), board_ahci_ign_iferr,  "ULiM5288"   }, /* ULi M5288 */
-  { PCI_VDEVICE(INTEL, 0x2681), board_ahci,            chip_esb2    }, /* ESB2 */
-  { PCI_VDEVICE(INTEL, 0x2682), board_ahci,            chip_esb2    }, /* ESB2 */
-  { PCI_VDEVICE(INTEL, 0x2683), board_ahci,            chip_esb2    }, /* ESB2 */
-  { PCI_VDEVICE(INTEL, 0x27c6), board_ahci,            "ICH7MDH"    }, /* ICH7-M DH */
-  { PCI_VDEVICE(INTEL, 0x2821), board_ahci,            chip_ich8    }, /* ICH8 */
-  { PCI_VDEVICE(INTEL, 0x2822), board_ahci_nosntf,     chip_ich8    }, /* ICH8 */
-  { PCI_VDEVICE(INTEL, 0x2824), board_ahci,            chip_ich8    }, /* ICH8 */
-  { PCI_VDEVICE(INTEL, 0x2829), board_ahci,            chip_ich8m   }, /* ICH8M */
-  { PCI_VDEVICE(INTEL, 0x282a), board_ahci,            chip_ich8m   }, /* ICH8M */
-  { PCI_VDEVICE(INTEL, 0x2922), board_ahci,            chip_ich9    }, /* ICH9 */
-  { PCI_VDEVICE(INTEL, 0x2923), board_ahci,            chip_ich9    }, /* ICH9 */
-  { PCI_VDEVICE(INTEL, 0x2924), board_ahci,            chip_ich9    }, /* ICH9 */
-  { PCI_VDEVICE(INTEL, 0x2925), board_ahci,            chip_ich9    }, /* ICH9 */
-  { PCI_VDEVICE(INTEL, 0x2927), board_ahci,            chip_ich9    }, /* ICH9 */
-  { PCI_VDEVICE(INTEL, 0x2929), board_ahci,            chip_ich9m   }, /* ICH9M */
-  { PCI_VDEVICE(INTEL, 0x292a), board_ahci,            chip_ich9m   }, /* ICH9M */
-  { PCI_VDEVICE(INTEL, 0x292b), board_ahci,            chip_ich9m   }, /* ICH9M */
-  { PCI_VDEVICE(INTEL, 0x292c), board_ahci,            chip_ich9m   }, /* ICH9M */
-  { PCI_VDEVICE(INTEL, 0x292f), board_ahci,            chip_ich9m   }, /* ICH9M */
-  { PCI_VDEVICE(INTEL, 0x294d), board_ahci,            chip_ich9    }, /* ICH9 */
-  { PCI_VDEVICE(INTEL, 0x294e), board_ahci,            chip_ich9m   }, /* ICH9M */
-  { PCI_VDEVICE(INTEL, 0x502a), board_ahci,            chip_tolapai }, /* Tolapai */
-  { PCI_VDEVICE(INTEL, 0x502b), board_ahci,            chip_tolapai }, /* Tolapai */
-  { PCI_VDEVICE(INTEL, 0x3a05), board_ahci,            chip_ich10   }, /* ICH10 */
-  { PCI_VDEVICE(INTEL, 0x3a22), board_ahci,            chip_ich10   }, /* ICH10 */
-  { PCI_VDEVICE(INTEL, 0x3a25), board_ahci,            chip_ich10   }, /* ICH10 */
-  { PCI_VDEVICE(INTEL, 0x3b22), board_ahci,            chip_pchahci }, /* PCH AHCI */
-  { PCI_VDEVICE(INTEL, 0x3b23), board_ahci,            chip_pchahci }, /* PCH AHCI */
-  { PCI_VDEVICE(INTEL, 0x3b24), board_ahci,            chip_pchraid }, /* PCH RAID */
-  { PCI_VDEVICE(INTEL, 0x3b25), board_ahci,            chip_pchraid }, /* PCH RAID */
-  { PCI_VDEVICE(INTEL, 0x3b29), board_ahci,            chip_pchahci }, /* PCH AHCI */
-  { PCI_VDEVICE(INTEL, 0x3b2b), board_ahci,            chip_pchraid }, /* PCH RAID */
-  { PCI_VDEVICE(INTEL, 0x3b2c), board_ahci,            chip_pchraid }, /* PCH RAID */
-  { PCI_VDEVICE(INTEL, 0x3b2f), board_ahci,            chip_pchahci }, /* PCH AHCI */
+   * NOTE: ICH5 controller does NOT support AHCI, so we do not add it here! */
+  { PCI_VDEVICE(INTEL, 0x2652), "ICH6" , 0 }, /* ICH6 */
+  { PCI_VDEVICE(INTEL, 0x2653), "ICH6M", 0 }, /* ICH6M */
+  { PCI_VDEVICE(INTEL, 0x27c1), "ICH7" , 0 }, /* ICH7 */
+  { PCI_VDEVICE(INTEL, 0x27c5), "ICH7M", 0 }, /* ICH7M */
+  { PCI_VDEVICE(INTEL, 0x27c3), "ICH7R", 0 }, /* ICH7R */
+  { PCI_VDEVICE(AL,    0x5288), "ULiM5288", AHCI_HFLAG_IGN_IRQ_IF_ERR }, /* ULi M5288 */
+  { PCI_VDEVICE(INTEL, 0x2681), "ESB2"   , 0 }, /* ESB2 */
+  { PCI_VDEVICE(INTEL, 0x2682), "ESB2"   , 0 }, /* ESB2 */
+  { PCI_VDEVICE(INTEL, 0x2683), "ESB2"   , 0 }, /* ESB2 */
+  { PCI_VDEVICE(INTEL, 0x27c6), "ICH7MDH", 0 }, /* ICH7-M DH */
+  { PCI_VDEVICE(INTEL, 0x2821), "ICH8"   , 0 }, /* ICH8 */
+  { PCI_VDEVICE(INTEL, 0x2822), "ICH8", AHCI_HFLAG_NO_SNTF }, /* ICH8 */
+  { PCI_VDEVICE(INTEL, 0x2824), "ICH8"    , 0 }, /* ICH8 */
+  { PCI_VDEVICE(INTEL, 0x2829), "ICH8M"   , 0 }, /* ICH8M */
+  { PCI_VDEVICE(INTEL, 0x282a), "ICH8M"   , 0 }, /* ICH8M */
+  { PCI_VDEVICE(INTEL, 0x2922), "ICH9"    , 0 }, /* ICH9 */
+  { PCI_VDEVICE(INTEL, 0x2923), "ICH9"    , 0 }, /* ICH9 */
+  { PCI_VDEVICE(INTEL, 0x2924), "ICH9"    , 0 }, /* ICH9 */
+  { PCI_VDEVICE(INTEL, 0x2925), "ICH9"    , 0 }, /* ICH9 */
+  { PCI_VDEVICE(INTEL, 0x2927), "ICH9"    , 0 }, /* ICH9 */
+  { PCI_VDEVICE(INTEL, 0x2929), "ICH9M"   , 0 }, /* ICH9M */
+  { PCI_VDEVICE(INTEL, 0x292a), "ICH9M"   , 0 }, /* ICH9M */
+  { PCI_VDEVICE(INTEL, 0x292b), "ICH9M"   , 0 }, /* ICH9M */
+  { PCI_VDEVICE(INTEL, 0x292c), "ICH9M"   , 0 }, /* ICH9M */
+  { PCI_VDEVICE(INTEL, 0x292f), "ICH9M"   , 0 }, /* ICH9M */
+  { PCI_VDEVICE(INTEL, 0x294d), "ICH9"    , 0 }, /* ICH9 */
+  { PCI_VDEVICE(INTEL, 0x294e), "ICH9M"   , 0 }, /* ICH9M */
+  { PCI_VDEVICE(INTEL, 0x502a), "Tolapai" , 0 }, /* Tolapai */
+  { PCI_VDEVICE(INTEL, 0x502b), "Tolapai" , 0 }, /* Tolapai */
+  { PCI_VDEVICE(INTEL, 0x3a05), "ICH10"   , 0 }, /* ICH10 */
+  { PCI_VDEVICE(INTEL, 0x3a22), "ICH10"   , 0 }, /* ICH10 */
+  { PCI_VDEVICE(INTEL, 0x3a25), "ICH10"   , 0 }, /* ICH10 */
+  { PCI_VDEVICE(INTEL, 0x3b22), "PCH AHCI", 0 }, /* PCH AHCI */
+  { PCI_VDEVICE(INTEL, 0x3b23), "PCH AHCI", 0 }, /* PCH AHCI */
+  { PCI_VDEVICE(INTEL, 0x3b24), "PCH RAID", 0 }, /* PCH RAID */
+  { PCI_VDEVICE(INTEL, 0x3b25), "PCH RAID", 0 }, /* PCH RAID */
+  { PCI_VDEVICE(INTEL, 0x3b29), "PCH AHCI", 0 }, /* PCH AHCI */
+  { PCI_VDEVICE(INTEL, 0x3b2b), "PCH RAID", 0 }, /* PCH RAID */
+  { PCI_VDEVICE(INTEL, 0x3b2c), "PCH RAID", 0 }, /* PCH RAID */
+  { PCI_VDEVICE(INTEL, 0x3b2f), "PCH AHCI", 0 }, /* PCH AHCI */
 
   /* JMicron 360/1/3/5/6, match class to avoid IDE function */
   { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
-    PCI_CLASS_STORAGE_SATA_AHCI, 0xffffffL, board_ahci_ign_iferr, "360" },
+    PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, "360", AHCI_HFLAG_IGN_IRQ_IF_ERR },
 
   /* ATI */
-  { PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600,        chip_sb600   }, /* ATI SB600 */
-  { PCI_VDEVICE(ATI, 0x4390), board_ahci_sb700,        chip_sb700   }, /* ATI SB700/800 */
-  { PCI_VDEVICE(ATI, 0x4391), board_ahci_sb700,        chip_sb700   }, /* ATI SB700/800 */
-  { PCI_VDEVICE(ATI, 0x4392), board_ahci_sb700,        chip_sb700   }, /* ATI SB700/800 */
-  { PCI_VDEVICE(ATI, 0x4393), board_ahci_sb700,        chip_sb700   }, /* ATI SB700/800 */
-  { PCI_VDEVICE(ATI, 0x4394), board_ahci_sb700,        chip_sb700   }, /* ATI SB700/800 */
-  { PCI_VDEVICE(ATI, 0x4395), board_ahci_sb700,        chip_sb700   }, /* ATI SB700/800 */
+  { PCI_VDEVICE(ATI, 0x4380), "SB600", AHCI_HFLAG_IGN_SERR_INTERNAL | AHCI_HFLAG_NO_MSI | AHCI_HFLAG_SECT255 | AHCI_HFLAG_32BIT_ONLY }, /* ATI SB600 */
+  { PCI_VDEVICE(ATI, 0x4390), "SB700/800", AHCI_HFLAG_IGN_SERR_INTERNAL }, /* ATI SB700/800 */
+  { PCI_VDEVICE(ATI, 0x4391), "SB700/800", AHCI_HFLAG_IGN_SERR_INTERNAL }, /* ATI SB700/800 */
+  { PCI_VDEVICE(ATI, 0x4392), "SB700/800", AHCI_HFLAG_IGN_SERR_INTERNAL }, /* ATI SB700/800 */
+  { PCI_VDEVICE(ATI, 0x4393), "SB700/800", AHCI_HFLAG_IGN_SERR_INTERNAL }, /* ATI SB700/800 */
+  { PCI_VDEVICE(ATI, 0x4394), "SB700/800", AHCI_HFLAG_IGN_SERR_INTERNAL }, /* ATI SB700/800 */
+  { PCI_VDEVICE(ATI, 0x4395), "SB700/800", AHCI_HFLAG_IGN_SERR_INTERNAL }, /* ATI SB700/800 */
 
   /* AMD */
-  { PCI_VDEVICE(AMD, 0x7800), board_ahci }, /* AMD Hudson-2 */
+  { PCI_VDEVICE(AMD, 0x7800), "Hudson-2", 0 }, /* AMD Hudson-2 */
   /* AMD is using RAID class only for ahci controllers */
   { PCI_VENDOR_ID_AMD, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
-    PCI_CLASS_STORAGE_RAID << 8, 0xffffffL, board_ahci, "Hudson2" },
+    PCI_CLASS_STORAGE_RAID << 8, 0xffffff, "Hudson2", 0 },
 
   /* VIA */
-  { PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251,       chip_vt8251  }, /* VIA VT8251 */
-  { PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251,       chip_vt8251  }, /* VIA VT8251 */
+  { PCI_VDEVICE(VIA, 0x3349), "VT8251", AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP }, /* VIA VT8251 */
+  { PCI_VDEVICE(VIA, 0x6287), "VT8251", AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP }, /* VIA VT8251 */
 
   /* NVIDIA */
-  { PCI_VDEVICE(NVIDIA, 0x044c), board_ahci_mcp65,     chip_mcp65   }, /* MCP65 */
-  { PCI_VDEVICE(NVIDIA, 0x044d), board_ahci_mcp65,     chip_mcp65   }, /* MCP65 */
-  { PCI_VDEVICE(NVIDIA, 0x044e), board_ahci_mcp65,     chip_mcp65   }, /* MCP65 */
-  { PCI_VDEVICE(NVIDIA, 0x044f), board_ahci_mcp65,     chip_mcp65   }, /* MCP65 */
-  { PCI_VDEVICE(NVIDIA, 0x045c), board_ahci_mcp65,     chip_mcp65   }, /* MCP65 */
-  { PCI_VDEVICE(NVIDIA, 0x045d), board_ahci_mcp65,     chip_mcp65   }, /* MCP65 */
-  { PCI_VDEVICE(NVIDIA, 0x045e), board_ahci_mcp65,     chip_mcp65   }, /* MCP65 */
-  { PCI_VDEVICE(NVIDIA, 0x045f), board_ahci_mcp65,     chip_mcp65   }, /* MCP65 */
-  { PCI_VDEVICE(NVIDIA, 0x0550), board_ahci_yesncq,    chip_mcp67   }, /* MCP67 */
-  { PCI_VDEVICE(NVIDIA, 0x0551), board_ahci_yesncq,    chip_mcp67   }, /* MCP67 */
-  { PCI_VDEVICE(NVIDIA, 0x0552), board_ahci_yesncq,    chip_mcp67   }, /* MCP67 */
-  { PCI_VDEVICE(NVIDIA, 0x0553), board_ahci_yesncq,    chip_mcp67   }, /* MCP67 */
-  { PCI_VDEVICE(NVIDIA, 0x0554), board_ahci_yesncq,    chip_mcp67   }, /* MCP67 */
-  { PCI_VDEVICE(NVIDIA, 0x0555), board_ahci_yesncq,    chip_mcp67   }, /* MCP67 */
-  { PCI_VDEVICE(NVIDIA, 0x0556), board_ahci_yesncq,    chip_mcp67   }, /* MCP67 */
-  { PCI_VDEVICE(NVIDIA, 0x0557), board_ahci_yesncq,    chip_mcp67   }, /* MCP67 */
-  { PCI_VDEVICE(NVIDIA, 0x0558), board_ahci_yesncq,    chip_mcp67   }, /* MCP67 */
-  { PCI_VDEVICE(NVIDIA, 0x0559), board_ahci_yesncq,    chip_mcp67   }, /* MCP67 */
-  { PCI_VDEVICE(NVIDIA, 0x055a), board_ahci_yesncq,    chip_mcp67   }, /* MCP67 */
-  { PCI_VDEVICE(NVIDIA, 0x055b), board_ahci_yesncq,    chip_mcp67   }, /* MCP67 */
-  { PCI_VDEVICE(NVIDIA, 0x0580), board_ahci_yesncq,    chip_mcp67   }, /* Linux ID */
-  { PCI_VDEVICE(NVIDIA, 0x07f0), board_ahci_yesncq,    chip_mcp73   }, /* MCP73 */
-  { PCI_VDEVICE(NVIDIA, 0x07f1), board_ahci_yesncq,    chip_mcp73   }, /* MCP73 */
-  { PCI_VDEVICE(NVIDIA, 0x07f2), board_ahci_yesncq,    chip_mcp73   }, /* MCP73 */
-  { PCI_VDEVICE(NVIDIA, 0x07f3), board_ahci_yesncq,    chip_mcp73   }, /* MCP73 */
-  { PCI_VDEVICE(NVIDIA, 0x07f4), board_ahci_yesncq,    chip_mcp73   }, /* MCP73 */
-  { PCI_VDEVICE(NVIDIA, 0x07f5), board_ahci_yesncq,    chip_mcp73   }, /* MCP73 */
-  { PCI_VDEVICE(NVIDIA, 0x07f6), board_ahci_yesncq,    chip_mcp73   }, /* MCP73 */
-  { PCI_VDEVICE(NVIDIA, 0x07f7), board_ahci_yesncq,    chip_mcp73   }, /* MCP73 */
-  { PCI_VDEVICE(NVIDIA, 0x07f8), board_ahci_yesncq,    chip_mcp73   }, /* MCP73 */
-  { PCI_VDEVICE(NVIDIA, 0x07f9), board_ahci_yesncq,    chip_mcp73   }, /* MCP73 */
-  { PCI_VDEVICE(NVIDIA, 0x07fa), board_ahci_yesncq,    chip_mcp73   }, /* MCP73 */
-  { PCI_VDEVICE(NVIDIA, 0x07fb), board_ahci_yesncq,    chip_mcp73   }, /* MCP73 */
-  { PCI_VDEVICE(NVIDIA, 0x0ad0), board_ahci,           chip_mcp77   }, /* MCP77 */
-  { PCI_VDEVICE(NVIDIA, 0x0ad1), board_ahci,           chip_mcp77   }, /* MCP77 */
-  { PCI_VDEVICE(NVIDIA, 0x0ad2), board_ahci,           chip_mcp77   }, /* MCP77 */
-  { PCI_VDEVICE(NVIDIA, 0x0ad3), board_ahci,           chip_mcp77   }, /* MCP77 */
-  { PCI_VDEVICE(NVIDIA, 0x0ad4), board_ahci,           chip_mcp77   }, /* MCP77 */
-  { PCI_VDEVICE(NVIDIA, 0x0ad5), board_ahci,           chip_mcp77   }, /* MCP77 */
-  { PCI_VDEVICE(NVIDIA, 0x0ad6), board_ahci,           chip_mcp77   }, /* MCP77 */
-  { PCI_VDEVICE(NVIDIA, 0x0ad7), board_ahci,           chip_mcp77   }, /* MCP77 */
-  { PCI_VDEVICE(NVIDIA, 0x0ad8), board_ahci,           chip_mcp77   }, /* MCP77 */
-  { PCI_VDEVICE(NVIDIA, 0x0ad9), board_ahci,           chip_mcp77   }, /* MCP77 */
-  { PCI_VDEVICE(NVIDIA, 0x0ada), board_ahci,           chip_mcp77   }, /* MCP77 */
-  { PCI_VDEVICE(NVIDIA, 0x0adb), board_ahci,           chip_mcp77   }, /* MCP77 */
-  { PCI_VDEVICE(NVIDIA, 0x0ab4), board_ahci,           chip_mcp79   }, /* MCP79 */
-  { PCI_VDEVICE(NVIDIA, 0x0ab5), board_ahci,           chip_mcp79   }, /* MCP79 */
-  { PCI_VDEVICE(NVIDIA, 0x0ab6), board_ahci,           chip_mcp79   }, /* MCP79 */
-  { PCI_VDEVICE(NVIDIA, 0x0ab7), board_ahci,           chip_mcp79   }, /* MCP79 */
-  { PCI_VDEVICE(NVIDIA, 0x0ab8), board_ahci,           chip_mcp79   }, /* MCP79 */
-  { PCI_VDEVICE(NVIDIA, 0x0ab9), board_ahci,           chip_mcp79   }, /* MCP79 */
-  { PCI_VDEVICE(NVIDIA, 0x0aba), board_ahci,           chip_mcp79   }, /* MCP79 */
-  { PCI_VDEVICE(NVIDIA, 0x0abb), board_ahci,           chip_mcp79   }, /* MCP79 */
-  { PCI_VDEVICE(NVIDIA, 0x0abc), board_ahci,           chip_mcp79   }, /* MCP79 */
-  { PCI_VDEVICE(NVIDIA, 0x0abd), board_ahci,           chip_mcp79   }, /* MCP79 */
-  { PCI_VDEVICE(NVIDIA, 0x0abe), board_ahci,           chip_mcp79   }, /* MCP79 */
-  { PCI_VDEVICE(NVIDIA, 0x0abf), board_ahci,           chip_mcp79   }, /* MCP79 */
-  { PCI_VDEVICE(NVIDIA, 0x0d84), board_ahci,           chip_mcp89   }, /* MCP89 */
-  { PCI_VDEVICE(NVIDIA, 0x0d85), board_ahci,           chip_mcp89   }, /* MCP89 */
-  { PCI_VDEVICE(NVIDIA, 0x0d86), board_ahci,           chip_mcp89   }, /* MCP89 */
-  { PCI_VDEVICE(NVIDIA, 0x0d87), board_ahci,           chip_mcp89   }, /* MCP89 */
-  { PCI_VDEVICE(NVIDIA, 0x0d88), board_ahci,           chip_mcp89   }, /* MCP89 */
-  { PCI_VDEVICE(NVIDIA, 0x0d89), board_ahci,           chip_mcp89   }, /* MCP89 */
-  { PCI_VDEVICE(NVIDIA, 0x0d8a), board_ahci,           chip_mcp89   }, /* MCP89 */
-  { PCI_VDEVICE(NVIDIA, 0x0d8b), board_ahci,           chip_mcp89   }, /* MCP89 */
-  { PCI_VDEVICE(NVIDIA, 0x0d8c), board_ahci,           chip_mcp89   }, /* MCP89 */
-  { PCI_VDEVICE(NVIDIA, 0x0d8d), board_ahci,           chip_mcp89   }, /* MCP89 */
-  { PCI_VDEVICE(NVIDIA, 0x0d8e), board_ahci,           chip_mcp89   }, /* MCP89 */
-  { PCI_VDEVICE(NVIDIA, 0x0d8f), board_ahci,           chip_mcp89   }, /* MCP89 */
+  { PCI_VDEVICE(NVIDIA, 0x044c), "MCP65", AHCI_HFLAG_YES_NCQ  }, /* MCP65 */
+  { PCI_VDEVICE(NVIDIA, 0x044d), "MCB65", AHCI_HFLAG_YES_NCQ  }, /* MCP65 */
+  { PCI_VDEVICE(NVIDIA, 0x044e), "MCP65", AHCI_HFLAG_YES_NCQ  }, /* MCP65 */
+  { PCI_VDEVICE(NVIDIA, 0x044f), "MCP65", AHCI_HFLAG_YES_NCQ  }, /* MCP65 */
+  { PCI_VDEVICE(NVIDIA, 0x045c), "MCP65", AHCI_HFLAG_YES_NCQ  }, /* MCP65 */
+  { PCI_VDEVICE(NVIDIA, 0x045d), "MCP65", AHCI_HFLAG_YES_NCQ  }, /* MCP65 */
+  { PCI_VDEVICE(NVIDIA, 0x045e), "MCP65", AHCI_HFLAG_YES_NCQ  }, /* MCP65 */
+  { PCI_VDEVICE(NVIDIA, 0x045f), "MCP65", AHCI_HFLAG_YES_NCQ  }, /* MCP65 */
+  { PCI_VDEVICE(NVIDIA, 0x0550), "MCP67" , AHCI_HFLAG_YES_NCQ }, /* MCP67 */
+  { PCI_VDEVICE(NVIDIA, 0x0551), "MCP67" , AHCI_HFLAG_YES_NCQ }, /* MCP67 */
+  { PCI_VDEVICE(NVIDIA, 0x0552), "MCP67" , AHCI_HFLAG_YES_NCQ }, /* MCP67 */
+  { PCI_VDEVICE(NVIDIA, 0x0553), "MCP67" , AHCI_HFLAG_YES_NCQ }, /* MCP67 */
+  { PCI_VDEVICE(NVIDIA, 0x0554), "MCP67" , AHCI_HFLAG_YES_NCQ }, /* MCP67 */
+  { PCI_VDEVICE(NVIDIA, 0x0555), "MCP67" , AHCI_HFLAG_YES_NCQ }, /* MCP67 */
+  { PCI_VDEVICE(NVIDIA, 0x0556), "MCP67" , AHCI_HFLAG_YES_NCQ }, /* MCP67 */
+  { PCI_VDEVICE(NVIDIA, 0x0557), "MCP67" , AHCI_HFLAG_YES_NCQ }, /* MCP67 */
+  { PCI_VDEVICE(NVIDIA, 0x0558), "MCP67" , AHCI_HFLAG_YES_NCQ }, /* MCP67 */
+  { PCI_VDEVICE(NVIDIA, 0x0559), "MCP67" , AHCI_HFLAG_YES_NCQ }, /* MCP67 */
+  { PCI_VDEVICE(NVIDIA, 0x055a), "MCP67" , AHCI_HFLAG_YES_NCQ }, /* MCP67 */
+  { PCI_VDEVICE(NVIDIA, 0x055b), "MCP67" , AHCI_HFLAG_YES_NCQ }, /* MCP67 */
+  { PCI_VDEVICE(NVIDIA, 0x0580), "MCP67" , AHCI_HFLAG_YES_NCQ }, /* Linux ID */
+  { PCI_VDEVICE(NVIDIA, 0x07f0), "MCP73" , AHCI_HFLAG_YES_NCQ }, /* MCP73 */
+  { PCI_VDEVICE(NVIDIA, 0x07f1), "MCP73" , AHCI_HFLAG_YES_NCQ }, /* MCP73 */
+  { PCI_VDEVICE(NVIDIA, 0x07f2), "MCP73" , AHCI_HFLAG_YES_NCQ }, /* MCP73 */
+  { PCI_VDEVICE(NVIDIA, 0x07f3), "MCP73" , AHCI_HFLAG_YES_NCQ }, /* MCP73 */
+  { PCI_VDEVICE(NVIDIA, 0x07f4), "MCP73" , AHCI_HFLAG_YES_NCQ }, /* MCP73 */
+  { PCI_VDEVICE(NVIDIA, 0x07f5), "MCP73" , AHCI_HFLAG_YES_NCQ }, /* MCP73 */
+  { PCI_VDEVICE(NVIDIA, 0x07f6), "MCP73" , AHCI_HFLAG_YES_NCQ }, /* MCP73 */
+  { PCI_VDEVICE(NVIDIA, 0x07f7), "MCP73" , AHCI_HFLAG_YES_NCQ }, /* MCP73 */
+  { PCI_VDEVICE(NVIDIA, 0x07f8), "MCP73" , AHCI_HFLAG_YES_NCQ }, /* MCP73 */
+  { PCI_VDEVICE(NVIDIA, 0x07f9), "MCP73" , AHCI_HFLAG_YES_NCQ }, /* MCP73 */
+  { PCI_VDEVICE(NVIDIA, 0x07fa), "MCP73" , AHCI_HFLAG_YES_NCQ }, /* MCP73 */
+  { PCI_VDEVICE(NVIDIA, 0x07fb), "MCP73" , AHCI_HFLAG_YES_NCQ }, /* MCP73 */
+  { PCI_VDEVICE(NVIDIA, 0x0ad0), "MCP77", 0 }, /* MCP77 */
+  { PCI_VDEVICE(NVIDIA, 0x0ad1), "MCP77", 0 }, /* MCP77 */
+  { PCI_VDEVICE(NVIDIA, 0x0ad2), "MCP77", 0 }, /* MCP77 */
+  { PCI_VDEVICE(NVIDIA, 0x0ad3), "MCP77", 0 }, /* MCP77 */
+  { PCI_VDEVICE(NVIDIA, 0x0ad4), "MCP77", 0 }, /* MCP77 */
+  { PCI_VDEVICE(NVIDIA, 0x0ad5), "MCP77", 0 }, /* MCP77 */
+  { PCI_VDEVICE(NVIDIA, 0x0ad6), "MCP77", 0 }, /* MCP77 */
+  { PCI_VDEVICE(NVIDIA, 0x0ad7), "MCP77", 0 }, /* MCP77 */
+  { PCI_VDEVICE(NVIDIA, 0x0ad8), "MCP77", 0 }, /* MCP77 */
+  { PCI_VDEVICE(NVIDIA, 0x0ad9), "MCP77", 0 }, /* MCP77 */
+  { PCI_VDEVICE(NVIDIA, 0x0ada), "MCP77", 0 }, /* MCP77 */
+  { PCI_VDEVICE(NVIDIA, 0x0adb), "MCP77", 0 }, /* MCP77 */
+  { PCI_VDEVICE(NVIDIA, 0x0ab4), "MCP79", 0 }, /* MCP79 */
+  { PCI_VDEVICE(NVIDIA, 0x0ab5), "MCP79", 0 }, /* MCP79 */
+  { PCI_VDEVICE(NVIDIA, 0x0ab6), "MCP79", 0 }, /* MCP79 */
+  { PCI_VDEVICE(NVIDIA, 0x0ab7), "MCP79", 0 }, /* MCP79 */
+  { PCI_VDEVICE(NVIDIA, 0x0ab8), "MCP79", 0 }, /* MCP79 */
+  { PCI_VDEVICE(NVIDIA, 0x0ab9), "MCP79", 0 }, /* MCP79 */
+  { PCI_VDEVICE(NVIDIA, 0x0aba), "MCP79", 0 }, /* MCP79 */
+  { PCI_VDEVICE(NVIDIA, 0x0abb), "MCP79", 0 }, /* MCP79 */
+  { PCI_VDEVICE(NVIDIA, 0x0abc), "MCP79", 0 }, /* MCP79 */
+  { PCI_VDEVICE(NVIDIA, 0x0abd), "MCP79", 0 }, /* MCP79 */
+  { PCI_VDEVICE(NVIDIA, 0x0abe), "MCP79", 0 }, /* MCP79 */
+  { PCI_VDEVICE(NVIDIA, 0x0abf), "MCP79", 0 }, /* MCP79 */
+  { PCI_VDEVICE(NVIDIA, 0x0d84), "MCP89", 0 }, /* MCP89 */
+  { PCI_VDEVICE(NVIDIA, 0x0d85), "MCP89", 0 }, /* MCP89 */
+  { PCI_VDEVICE(NVIDIA, 0x0d86), "MCP89", 0 }, /* MCP89 */
+  { PCI_VDEVICE(NVIDIA, 0x0d87), "MCP89", 0 }, /* MCP89 */
+  { PCI_VDEVICE(NVIDIA, 0x0d88), "MCP89", 0 }, /* MCP89 */
+  { PCI_VDEVICE(NVIDIA, 0x0d89), "MCP89", 0 }, /* MCP89 */
+  { PCI_VDEVICE(NVIDIA, 0x0d8a), "MCP89", 0 }, /* MCP89 */
+  { PCI_VDEVICE(NVIDIA, 0x0d8b), "MCP89", 0 }, /* MCP89 */
+  { PCI_VDEVICE(NVIDIA, 0x0d8c), "MCP89", 0 }, /* MCP89 */
+  { PCI_VDEVICE(NVIDIA, 0x0d8d), "MCP89", 0 }, /* MCP89 */
+  { PCI_VDEVICE(NVIDIA, 0x0d8e), "MCP89", 0 }, /* MCP89 */
+  { PCI_VDEVICE(NVIDIA, 0x0d8f), "MCP89", 0 }, /* MCP89 */
 
   /* SiS */
-  { PCI_VDEVICE(SI, 0x1184), board_ahci,               "966"        }, /* SiS 966 */
-  { PCI_VDEVICE(SI, 0x1185), board_ahci,               chip_sis968  }, /* SiS 968 */
-  { PCI_VDEVICE(SI, 0x0186), board_ahci,               chip_sis968  }, /* SiS 968 */
+  { PCI_VDEVICE(SI, 0x1184), "966", 0 }, /* SiS 966 */
+  { PCI_VDEVICE(SI, 0x1185), "968", 0 }, /* SiS 968 */
+  { PCI_VDEVICE(SI, 0x0186), "968", 0 }, /* SiS 968 */
 
   /* Marvell */
-  { PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv,       "6145"       }, /* 6145 */
-  { PCI_VDEVICE(MARVELL, 0x6121), board_ahci_mv,       "6121"       }, /* 6121 */
+  { PCI_VDEVICE(MARVELL, 0x6145), "6145", AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI | AHCI_HFLAG_MV_PATA | AHCI_HFLAG_NO_PMP }, /* 6145 */
+  { PCI_VDEVICE(MARVELL, 0x6121), "6121", AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI | AHCI_HFLAG_MV_PATA | AHCI_HFLAG_NO_PMP }, /* 6121 */
 
   /* Promise */
-  { PCI_VDEVICE(PROMISE, 0x3f20), board_ahci,          "PDC42819"   }, /* PDC42819 */
+  { PCI_VDEVICE(PROMISE, 0x3f20), "PDC42819", 0 }, /* PDC42819 */
 
   /* Generic, PCI class code for AHCI */
   { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
-    PCI_CLASS_STORAGE_SATA_AHCI, 0xffffffL, board_ahci, s_generic   },
+    PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, "Generic", 0 },
 
   /* end of list, including a few slots to define custom adapters (10) */
-  { 0, 0, 0, 0, 0, 0, 0, NULL },
-  { 0, 0, 0, 0, 0, 0, 0, NULL },
-  { 0, 0, 0, 0, 0, 0, 0, NULL },
-  { 0, 0, 0, 0, 0, 0, 0, NULL },
-  { 0, 0, 0, 0, 0, 0, 0, NULL },
-  { 0, 0, 0, 0, 0, 0, 0, NULL },
-  { 0, 0, 0, 0, 0, 0, 0, NULL },
-  { 0, 0, 0, 0, 0, 0, 0, NULL },
-  { 0, 0, 0, 0, 0, 0, 0, NULL },
-  { 0, 0, 0, 0, 0, 0, 0, NULL },
-
-  { 0, 0, 0, 0, 0, 0, 0, NULL }
+  { 0, 0, 0, 0, 0, 0, NULL, 0 },
+  { 0, 0, 0, 0, 0, 0, NULL, 0 },
+  { 0, 0, 0, 0, 0, 0, NULL, 0 },
+  { 0, 0, 0, 0, 0, 0, NULL, 0 },
+  { 0, 0, 0, 0, 0, 0, NULL, 0 },
+  { 0, 0, 0, 0, 0, 0, NULL, 0 },
+  { 0, 0, 0, 0, 0, 0, NULL, 0 },
+  { 0, 0, 0, 0, 0, 0, NULL, 0 },
+  { 0, 0, 0, 0, 0, 0, NULL, 0 },
+  { 0, 0, 0, 0, 0, 0, NULL, 0 },
+
+  { 0, 0, 0, 0, 0, 0, NULL, 0 }
 };
 
@@ -255,6 +229,6 @@
   pci_ids[i].vendor = vendor;
   pci_ids[i].device = device;
-  pci_ids[i].board = board_ahci;
-  pci_ids[i].chipname = s_generic;
+  pci_ids[i].pChipName = "Specified";
+  pci_ids[i].quirks = 0;
   return(0);
 }
@@ -321,5 +295,5 @@
         for (n = 0; n < ad_info_cnt; n++)
         {
-          if (ad_infos[n].bus_dev_func == BusDevFunc)
+          if (ad_infos[n].BusDevFunc == BusDevFunc)
           {
             /* this device has already been found (e.g. via thorough scan) */
@@ -343,21 +317,4 @@
     } while (BusDevFunc != 0xffff);
   }
-}
-
-/******************************************************************************
- * Enable interrupt generation. PCI 2.3 added a bit which allows disabling
- * interrupt generation for a device. This function clears the corresponding
- * bit in the configuration space command register.
- */
-int pci_enable_int(USHORT BusDevFunc)
-{
-  ULONG tmp;
-
-  if (PciReadConfig(BusDevFunc, 4, sizeof(tmp), &tmp) ||
-      PciWriteConfig(BusDevFunc, 4, sizeof(tmp), tmp & ~(1UL << 10)))
-  {
-    return(-1);
-  }
-  return(0);
 }
 
@@ -559,8 +516,9 @@
    * itself with the OS/2 resource manager
    */
-  ad_info->pci = pci_id;
-  ad_info->pci_vendor = vendor;
-  ad_info->pci_device = device;
-  ad_info->bus_dev_func = BusDevFunc;
+  ad_info->pChipName = pci_id->pChipName;
+  ad_info->quirks = pci_id->quirks;
+  ad_info->PciVendor = vendor;
+  ad_info->PciDevice = device;
+  ad_info->BusDevFunc = BusDevFunc;
   ad_info->irq = irq;
   ad_info->irq_pin = pin;
@@ -594,4 +552,10 @@
   }
 
+  if (!PciReadConfig(BusDevFunc, PCI_COMMAND, 2, &val))
+  {
+    val |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+    val &= ~PCI_COMMAND_INTX_DISABLE;
+    PciWriteConfig(BusDevFunc, PCI_COMMAND, 2, val);
+  }
   if (ahci_config_caps(ad_info)) goto add_pci_fail;
 
@@ -738,24 +702,5 @@
     }
 
-  return "Generic";
-}
-
-/******************************************************************************
- * return a device name for a PCI device id
- * NOTE: this is as simple as can be, so don't call it twice in one statement.
- */
-char *device_from_id(u16 device)
-{
-  int i;
-
-  for (i = 0; pci_ids[i].vendor != 0; i++)
-  {
-    if (pci_ids[i].device == device)
-    {
-      return pci_ids[i].chipname;
-    }
-  }
-
-  return s_generic;
+  return "";
 }
 
Index: trunk/src/os2ahci/thunk.asm
===================================================================
--- trunk/src/os2ahci/thunk.asm	(revision 209)
+++ trunk/src/os2ahci/thunk.asm	(revision 211)
@@ -1,4 +1,4 @@
 ; Thunking for ahci32 driver
-; Copyright (c) 2018-2021 David Azarewicz
+; Copyright (c) 2018-2023 David Azarewicz
 ; Author: David Azarewicz <david@88watts.net>
 
Index: trunk/src/os2ahci/trace.c
===================================================================
--- trunk/src/os2ahci/trace.c	(revision 209)
+++ trunk/src/os2ahci/trace.c	(revision 211)
@@ -1,5 +1,5 @@
 /**
  *
- * Copyright (c) 2013-2021 David Azarewicz <david@88watts.net>
+ * Copyright (c) 2013-2023 David Azarewicz <david@88watts.net>
  *
  */
@@ -22,8 +22,8 @@
     AD_INFO *ai = ad_infos + a;
 
-    dprintf(0,"Adapter %d: PCI=%d:%d:%d ID=%04x:%04x %s %s irq=%d addr=0x%x version=%x\n", a,
-      PCI_BUS_FROM_BDF(ai->bus_dev_func), PCI_DEV_FROM_BDF(ai->bus_dev_func),
-      PCI_FUNC_FROM_BDF(ai->bus_dev_func),
-      ai->pci_vendor, ai->pci_device, vendor_from_id(ai->pci_vendor), ai->pci->chipname,
+    dprintf(0,"Adapter %d: %d:%d:%d ID=%04x:%04x %s %s irq=%d adr=%x version=%x\n", a,
+      PCI_BUS_FROM_BDF(ai->BusDevFunc), PCI_DEV_FROM_BDF(ai->BusDevFunc),
+      PCI_FUNC_FROM_BDF(ai->BusDevFunc),
+      ai->PciVendor, ai->PciDevice, vendor_from_id(ai->PciVendor), ai->pChipName,
       ai->irq, ai->mmio_phys,
       ai->bios_config[HOST_VERSION / sizeof(u32)]);
@@ -63,11 +63,11 @@
 
 #ifdef DEBUG
-void DumpIorb(IORBH *pIorb)
+void DumpIorb(IORBH *pIorb, IORBH FAR16DATA *vIorb)
 {
-  if (!(D32g_DbgLevel & DBG_DETAILED)) return;
-  if (!ad_infos[iorb_unit_adapter(pIorb)].ports[iorb_unit_port(pIorb)].devs[iorb_unit_device(pIorb)].atapi) return;
+  //if (!(D32g_DbgLevel & DBG_DETAILED)) return;
+  if (ad_infos[iorb_unit_adapter(pIorb)].ports[iorb_unit_port(pIorb)].devs[iorb_unit_device(pIorb)].atapi) return;
 
   dprintf(0,"IORB %x: Size=%x Len=%x Handle=%x CmdCode=%x\n",
-      pIorb, sizeof(IORBH), pIorb->Length, pIorb->UnitHandle, pIorb->CommandCode);
+      vIorb, sizeof(IORBH), pIorb->Length, pIorb->UnitHandle, pIorb->CommandCode);
   dprintf(0,"  CmdMod=%x ReqCtrl=%x Status=%x ErrorCode=%x\n",
       pIorb->CommandModifier, pIorb->RequestControl, pIorb->Status, pIorb->ErrorCode);
@@ -75,4 +75,16 @@
       pIorb->Timeout, pIorb->StatusBlockLen, pIorb->pStatusBlock, pIorb->Reserved_1,
       pIorb->f16NxtIORB);
+
+  if (pIorb->CommandCode == IOCC_EXECUTE_IO || pIorb->CommandCode == IOCC_EXECUTE_IO_64)
+  {
+    IORB_EXECUTEIO64 *pIo = (IORB_EXECUTEIO64*)pIorb;
+    ULONGLONG ullLba;
+
+    ullLba = pIo->RBA;
+    if (pIorb->CommandCode == IOCC_EXECUTE_IO_64) ullLba = pIo->ullRBA;
+
+    dprintf(0,"  I/O: Block=%llx Count=%x Xferred=%x Size=%x Flags=%x\n",
+      ullLba, pIo->BlockCount, pIo->BlocksXferred, pIo->BlockSize, pIo->Flags);
+  }
 }
 #endif
