Index: /trunk/src/os2ahci/ReadMe.txt
===================================================================
--- /trunk/src/os2ahci/ReadMe.txt	(revision 206)
+++ /trunk/src/os2ahci/ReadMe.txt	(revision 207)
@@ -1,3 +1,3 @@
-AHCI Driver for OS/2 v2.08
+AHCI Driver for OS/2
 
 Introduction
@@ -77,5 +77,5 @@
                        use this switch.
 
-/C:<n>                 Set debug COM port base address. Values for n can be:
+/COM:<n>               Set debug COM port base address. Values for n can be:
                          1 = COM1
                          2 = COM2
@@ -388,7 +388,9 @@
 Change Log
 ==========
-v.2.08 01-Jan-2021 - David Azarewicz
+v.2.08 20-Feb-2021 - David Azarewicz
   Corrected RM ADD handle and unit.
   Changed the internal implementation of /U to accomodate gpt filter.
+  Added support for 48/64 bit LBA operations.
+  Added test for non-aligned SG list element.
 
 v.2.07 19-May-2019 - David Azarewicz
Index: /trunk/src/os2ahci/ahci.c
===================================================================
--- /trunk/src/os2ahci/ahci.c	(revision 206)
+++ /trunk/src/os2ahci/ahci.c	(revision 207)
@@ -79,10 +79,11 @@
   u32 version;
 
-  DPRINTF(2,"AHCI global registers for adapter %d %d:%d:%d irq=%d addr=0x%x\n",
+  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);
 
-  for (i = 0; i <= HOST_CAP2; i += sizeof(u32)) {
+  for (i = 0; i <= HOST_CAP2; i += sizeof(u32))
+  {
     u32 val;
 
@@ -98,5 +99,6 @@
     dprintf(0," %02x: %08lx", i, val);
 
-    if (i == HOST_CAP) {
+    if (i == HOST_CAP)
+    {
       dprintf(0," -");
       if (val & HOST_CAP_64)         dprintf(0," 64bit");
@@ -119,10 +121,14 @@
       dprintf(0," cmd_slots:%d", ((val >> 8) & 0x1f) + 1);
       dprintf(0," ports:%d",     (val & 0x1f) + 1);
-    } else if (i == HOST_CTL) {
+    }
+    else if (i == HOST_CTL)
+    {
       dprintf(0," -");
       if (val & HOST_AHCI_EN)        dprintf(0," ahci_enabled");
       if (val & HOST_IRQ_EN)         dprintf(0," irq_enabled");
       if (val & HOST_RESET)          dprintf(0," resetting");
-    } else if (i == HOST_CAP2) {
+    }
+    else if (i == HOST_CAP2)
+    {
       dprintf(0," -");
       if (val & HOST_CAP2_BOH)       dprintf(0," boh");
@@ -278,5 +284,5 @@
   }
 
-  DUMP_HOST_REGS(2,ai,1);
+  DUMP_HOST_REGS(6,ai,1);
 
   return(0);
@@ -529,5 +535,5 @@
   int i;
 
-  DPRINTF(1,__func__": completing initialization of adapter #%d\n", ad_no(ai));
+  DPRINTF(2,__func__": completing initialization of adapter #%d\n", ad_no(ai));
 
   if (!ai->int_set)
@@ -609,5 +615,5 @@
   /* pci_enable_int(ai->bus, ai->dev_func); */
 
-  DPRINTF(1,__func__": done\n");
+  DPRINTF(2,__func__": done\n");
   return(0);
 }
@@ -834,5 +840,5 @@
     {
       /* this port seems to have a device attached and ready for commands */
-      DPRINTF(1,__func__": port %d seems to be attached to a device; probing...\n", p);
+      DPRINTF(2,__func__": port %d seems to be attached to a device; probing...\n", p);
 
       #ifdef DAZ_NEW_CODE
@@ -909,6 +915,6 @@
   TIMER Timer;
 
-  DPRINTF(2,__func__": resetting port %d.%d\n", ad_no(ai), p);
-  DUMP_PORT_REGS(2,ai,p);
+  DPRINTF(3,__func__": resetting port %d.%d\n", ad_no(ai), p);
+  DUMP_PORT_REGS(3,ai,p);
 
   /* stop port engines (we don't care whether there is an error doing so) */
@@ -944,5 +950,5 @@
 
   /* wait for communication to be re-established after port reset */
-  DPRINTF(2,"Wait for communication...\n");
+  DPRINTF(3,"Wait for communication...\n");
   TimerInit(&Timer, 500);
   while (((tmp = readl(port_mmio + PORT_SCR_STAT)) & 3) != 3)
@@ -950,5 +956,5 @@
     if (TimerCheckAndBlock(&Timer))
     {
-      DPRINTF(0,"no device present after resetting port #%d (PORT_SCR_STAT = 0x%x)\n", p, tmp);
+      DPRINTF(2,"no device present after resetting port #%d (PORT_SCR_STAT = 0x%x)\n", p, tmp);
       return(-1);
     }
@@ -960,5 +966,5 @@
 
   /* start port so we can receive the COMRESET FIS */
-  DPRINTF(2,__func__": starting port %d again\n", p);
+  DPRINTF(3,__func__": starting port %d again\n", p);
   ahci_start_port(ai, p, ei);
 
@@ -1794,5 +1800,12 @@
   }
 
-  dprintf(0,"port #%d interrupt error status: 0x%08lx; restarting port\n", p, irq_stat);
+  #ifdef DEBUG
+  dprintf(0,"port #%d interrupt error status: 0x%08x; restarting port\n", p, irq_stat);
+  #else
+  if (!ai->ports[p].devs[0].atapi || D32g_DbgLevel)
+  {
+    dprintf(0,"port #%d interrupt error status: 0x%08x; restarting port\n", p, irq_stat);
+  }
+  #endif
 
   /* Handle device-specific errors. Those errors typically involve restarting
Index: /trunk/src/os2ahci/ata.c
===================================================================
--- /trunk/src/os2ahci/ata.c	(revision 206)
+++ /trunk/src/os2ahci/ata.c	(revision 207)
@@ -26,16 +26,9 @@
  */
 
+#define INCL_LONGLONG
 #include "os2ahci.h"
 #include "ata.h"
 
-/* -------------------------- function prototypes -------------------------- */
-
-static int ata_cmd_read(IORBH *pIorb, AD_INFO *ai, int p, int d, int slot,
-                        ULONG sector, ULONG count, SCATGATENTRY *sg_list,
-                        ULONG sg_cnt);
-
-static int ata_cmd_write(IORBH *pIorb, AD_INFO *ai, int p, int d, int slot,
-                         ULONG sector, ULONG count, SCATGATENTRY *sg_list,
-                         ULONG sg_cnt, int write_through);
+#define MAKEULL(h,l) (((ULONGLONG)h<<32)|l)
 
 /******************************************************************************
@@ -256,8 +249,14 @@
     {
       u32 chunk = (sg_size > AHCI_MAX_SG_ELEMENT_LEN) ? AHCI_MAX_SG_ELEMENT_LEN : sg_size;
+
       if (n >= AHCI_MAX_SG)
       {
         /* couldn't store all S/G elements in our DMA buffer */
-        dprintf(0,"ata_cmd(): too many S/G elements\n");
+        if (sg_size)
+        {
+          dprintf(0, __func__": unaligned SG element\n");
+          return -1;
+        }
+        dprintf(0, __func__": too many S/G elements\n");
         return(i - 1);
       }
@@ -341,28 +340,4 @@
 
 /******************************************************************************
- * Get index in S/G list for the number of transferred sectors in the IORB.
- *
- * Returning io->cSGList indicates an error.
- *
- * NOTE: OS/2 makes sure S/G lists are set up such that entries at the HW
- *       limit will never cross sector boundaries. This means that splitting
- *       S/G lists into multiple commands can be done without editing the S/G
- *       lists.
- */
-u16 ata_get_sg_indx(IORB_EXECUTEIO *io)
-{
-  ULONG offset = io->BlocksXferred * io->BlockSize;
-  SCATGATENTRY *pSGList = (SCATGATENTRY*)Far16ToFlat(io->f16SGList);
-  USHORT i;
-
-  for (i = 0; i < io->cSGList && offset > 0; i++)
-  {
-    offset -= pSGList[i].XferBufLen;
-  }
-
-  return(i);
-}
-
-/******************************************************************************
  * Get max S/G count which will fit into our HW S/G buffers. This function is
  * called when the S/G list is too long and we need to split the IORB into
@@ -459,5 +434,5 @@
  * geometry to the last full cylinder.
  */
-int adjust_cylinders(GEOMETRY *geometry, ULONG TotalSectors)
+int adjust_cylinders(GEOMETRY64 *geometry, ULONG TotalSectors)
 {
   USHORT SecPerCyl;
@@ -487,5 +462,5 @@
 #define BIOS_MAX_NUMHEADS         255
 #define BIOS_MAX_SECTORSPERTRACK   63
-void log_geom_calculate_LBA_assist(GEOMETRY *geometry, ULONG TotalSectors)
+void log_geom_calculate_LBA_assist(GEOMETRY64 *geometry, ULONG TotalSectors)
 {
   UCHAR numSpT   = BIOS_MAX_SECTORSPERTRACK;
@@ -524,5 +499,5 @@
   DLA_Table_Sector *pDLA = (DLA_Table_Sector*)add_workspace(pIorb)->buf;
   AD_INFO *ai = ad_infos + iorb_unit_adapter(pIorb);
-  GEOMETRY *geometry = ((IORB_GEOMETRY*)pIorb)->f16Geometry;
+  GEOMETRY64 *geometry = (GEOMETRY64*)((IORB_GEOMETRY*)pIorb)->f16Geometry;
   int p = iorb_unit_port(pIorb);
   int rc;
@@ -544,5 +519,8 @@
     geometry->NumHeads = pDLA->Heads_Per_Cylinder;
     geometry->SectorsPerTrack = pDLA->Sectors_Per_Track;
-    geometry->TotalSectors = pDLA->Cylinders * pDLA->Heads_Per_Cylinder * pDLA->Sectors_Per_Track;
+    if (add_workspace(pIorb)->fIs64bit)
+      geometry->ullTotalSectors = pDLA->Cylinders * pDLA->Heads_Per_Cylinder * pDLA->Sectors_Per_Track;
+    else
+      geometry->TotalSectors = pDLA->Cylinders * pDLA->Heads_Per_Cylinder * pDLA->Sectors_Per_Track;
     return 1;
   }
@@ -589,6 +567,7 @@
 void ata_get_geometry_pp(IORBH FAR16DATA *vIorb, IORBH *pIorb)
 {
-  GEOMETRY *geometry = ((IORB_GEOMETRY*)pIorb)->f16Geometry;
+  GEOMETRY64 *geometry = (GEOMETRY64*)((IORB_GEOMETRY*)pIorb)->f16Geometry;
   USHORT geometry_len =  ((IORB_GEOMETRY *)pIorb)->GeometryLen;
+  ULONGLONG ullTotalSectors;
   u16 *id_buf = add_workspace(pIorb)->buf;
   int a = iorb_unit_adapter(pIorb);
@@ -627,5 +606,5 @@
    * can be unexpected and catastrophic.
    */
-  memset(geometry, 0x00, geometry_len);
+  memset(geometry, 0, geometry_len);
   geometry->BytesPerSector = ATA_SECTOR_SIZE;
 
@@ -634,5 +613,5 @@
   {
     /* 48-bit LBA supported */
-    if (ATA_CAPACITY48_H(id_buf) != 0)
+    if ((ATA_CAPACITY48_H(id_buf) != 0) && !add_workspace(pIorb)->fIs64bit)
     {
       /* more than 32 bits for number of sectors */
@@ -640,9 +619,9 @@
               iorb_unit_adapter(pIorb), iorb_unit_port(pIorb),
               iorb_unit_device(pIorb));
-      geometry->TotalSectors = 0xffffffffUL;
+      ullTotalSectors = 0xffffffff;
     }
     else
     {
-      geometry->TotalSectors = ATA_CAPACITY48_L(id_buf);
+      ullTotalSectors = MAKEULL(ATA_CAPACITY48_H(id_buf), ATA_CAPACITY48_L(id_buf));
     }
   }
@@ -650,5 +629,5 @@
   {
     /* 28-bit LBA */
-    geometry->TotalSectors = ATA_CAPACITY(id_buf) & 0x0fffffffUL;
+    ullTotalSectors = ATA_CAPACITY(id_buf) & 0x0fffffff;
   }
 
@@ -663,5 +642,5 @@
     geometry->NumHeads        = 255;
     geometry->SectorsPerTrack = track_size[a][p];
-    geometry->TotalCylinders  = geometry->TotalSectors / ((u32) geometry->NumHeads * (u32) geometry->SectorsPerTrack);
+    geometry->TotalCylinders  = ullTotalSectors / ((u32)geometry->NumHeads * (u32)geometry->SectorsPerTrack);
     Method = "Custom";
   }
@@ -688,5 +667,5 @@
     geometry->NumHeads        = 255;
     geometry->SectorsPerTrack = 63;
-    geometry->TotalCylinders  = geometry->TotalSectors / ((u32) geometry->NumHeads * (u32) geometry->SectorsPerTrack);
+    geometry->TotalCylinders  = ullTotalSectors / ((u32)geometry->NumHeads * (u32)geometry->SectorsPerTrack);
     Method = "SCSI";
   }
@@ -694,28 +673,40 @@
   DPRINTF(2,"Physical geometry: %d cylinders, %d heads, %d sectors per track (%dMB) (%s)\n",
       geometry->TotalCylinders, geometry->NumHeads, geometry->SectorsPerTrack,
-      (geometry->TotalSectors / 2048), Method);
-
-  /* Fixup the geometry in case the geometry reported by the BIOS is bad */
-  if (adjust_cylinders(geometry, geometry->TotalSectors))
-  { // cylinder overflow
-    log_geom_calculate_LBA_assist(geometry, geometry->TotalSectors);
-    geometry->TotalSectors = (USHORT)(geometry->NumHeads * geometry->SectorsPerTrack) * (ULONG)geometry->TotalCylinders;
-  }
-  adjust_cylinders(geometry, geometry->TotalSectors);
-
-  DPRINTF(2,"Logical geometry: %d cylinders, %d heads, %d sectors per track (%dMB) (%s)\n",
-      geometry->TotalCylinders, geometry->NumHeads, geometry->SectorsPerTrack,
-      (geometry->TotalSectors / 2048), Method);
-
-  if (is_lvm_geometry(pIorb)) Method = "LVM";
+      (ULONG)(ullTotalSectors / 2048), Method);
+
+  if (is_lvm_geometry(pIorb)) Method = "LVM";  /* Writes TotalSectors/ullTotalSectors */
+  else
+  {
+    if (add_workspace(pIorb)->fIs64bit)
+    {
+      geometry->NumHeads        = 255;
+      geometry->SectorsPerTrack = 255;
+      geometry->TotalCylinders  = ullTotalSectors / (255*255);
+      geometry->ullTotalSectors = ullTotalSectors;
+    }
+    else
+    {
+      /* Fixup the geometry in case the geometry reported by the BIOS is bad */
+      if (adjust_cylinders(geometry, ullTotalSectors))  /* Writes TotalSectors */
+      { // cylinder overflow
+        log_geom_calculate_LBA_assist(geometry, ullTotalSectors); /* Does not write TotalSectors */
+        ullTotalSectors = (USHORT)(geometry->NumHeads * geometry->SectorsPerTrack) * (ULONG)geometry->TotalCylinders;
+      }
+      adjust_cylinders(geometry, ullTotalSectors); /* Writes TotalSectors */
+    }
+  }
+  if (add_workspace(pIorb)->fIs64bit) ullTotalSectors = geometry->ullTotalSectors;
+  else ullTotalSectors = geometry->TotalSectors;
+
   ad_infos[a].ports[p].devs[0].dev_info.Cylinders = geometry->TotalCylinders;
   ad_infos[a].ports[p].devs[0].dev_info.HeadsPerCylinder = geometry->NumHeads;
   ad_infos[a].ports[p].devs[0].dev_info.SectorsPerTrack = geometry->SectorsPerTrack;
-  ad_infos[a].ports[p].devs[0].dev_info.TotalSectors = geometry->TotalSectors;
+  ad_infos[a].ports[p].devs[0].dev_info.TotalSectors = ullTotalSectors;
   ad_infos[a].ports[p].devs[0].dev_info.Method = Method;
 
-  DPRINTF(2,"Reported geometry: %d cylinders, %d heads, %d sectors per track (%dMB) (%s)\n",
+  //DAZ DPRINTF(2,"Reported geometry: %d cylinders, %d heads, %d sectors per track (%dMB) (%s)\n",
+  DPRINTF(0,"Reported geometry: %d cylinders, %d heads, %d sectors per track (%dMB) (%s)\n",
       geometry->TotalCylinders, geometry->NumHeads, geometry->SectorsPerTrack,
-      (geometry->TotalSectors / 2048), Method);
+      (ULONG)(ullTotalSectors / 2048), Method);
 
   /* tell interrupt handler that this IORB is complete */
@@ -737,4 +728,57 @@
 
 /******************************************************************************
+ * Fabricate ATA READ command based on the capabilities of the corresponding
+ * device and the paramters set from above (NCQ, etc).
+ */
+static int ata_cmd_read(IORBH *pIorb, AD_INFO *ai, int p, int d, int slot,
+                        ULONGLONG ullLba, ULONG count, SCATGATENTRY *sg_list,
+                        ULONG sg_cnt)
+{
+  int rc;
+
+  if (ullLba >= (1UL << 28) || count > 256 || add_workspace(pIorb)->is_ncq)
+  {
+    /* need LBA48 for this command */
+    if (!ai->ports[p].devs[d].lba48)
+    {
+      iorb_seterr(pIorb, IOERR_RBA_LIMIT);
+      return(-1);
+    }
+    if (add_workspace(pIorb)->is_ncq)
+    {
+      /* use NCQ read; count goes into feature register, tag into count! */
+      rc = ata_cmd(ai, p, d, slot, ATA_CMD_FPDMA_READ,
+                   AP_SECTOR_48, ullLba,
+                   AP_FEATURES,  count,
+                   AP_COUNT,     (slot << 3), /* tag == slot */
+                   AP_SGLIST,    sg_list, sg_cnt,
+                   AP_DEVICE,    0x40,
+                   AP_END);
+    }
+    else
+    {
+      rc = ata_cmd(ai, p, d, slot, ATA_CMD_READ_EXT,
+                   AP_SECTOR_48, ullLba,
+                   AP_COUNT,     count,
+                   AP_SGLIST,    sg_list, sg_cnt,
+                   AP_DEVICE,    0x40,
+                   AP_END);
+    }
+
+  }
+  else
+  {
+    rc = ata_cmd(ai, p, d, slot, ATA_CMD_READ,
+                 AP_SECTOR_28, (ULONG)ullLba,
+                 AP_COUNT,     count & 0xffU,
+                 AP_SGLIST,    sg_list, sg_cnt,
+                 AP_DEVICE,    0x40,
+                 AP_END);
+  }
+
+  return(rc);
+}
+
+/******************************************************************************
  * Read sectors from AHCI device.
  */
@@ -744,5 +788,5 @@
   SCATGATENTRY *pSGList = (SCATGATENTRY*)Far16ToFlat(io->f16SGList);
   AD_INFO *ai = ad_infos + iorb_unit_adapter(pIorb);
-  ULONG sector = io->RBA + io->BlocksXferred;
+  ULONGLONG ullLba = io->RBA + io->BlocksXferred;
   USHORT count = io->BlockCount - io->BlocksXferred;
   USHORT sg_indx;
@@ -762,4 +806,9 @@
     /* unaligned S/G addresses present; need to use double buffers */
     return(ata_read_unaligned(pIorb, slot));
+  }
+
+  if (add_workspace(pIorb)->fIs64bit)
+  {
+    ullLba = ((IORB_EXECUTEIO64*)pIorb)->ullRBA + io->BlocksXferred;
   }
 
@@ -778,8 +827,8 @@
   do
   {
-    sg_indx = ata_get_sg_indx(io);
+    sg_indx = SgIndexFromOffset(pSGList, io->cSGList, io->BlocksXferred * io->BlockSize);
     sg_cnt = io->cSGList - sg_indx;
-    if ((rc = ata_cmd_read(pIorb, ai, p, d, slot, sector, count,
-                           pSGList + sg_indx, sg_cnt)) > 0)
+    rc = ata_cmd_read(pIorb, ai, p, d, slot, ullLba, count, pSGList + sg_indx, sg_cnt);
+    if (rc > 0)
     {
       /* couldn't map all S/G elements */
@@ -802,5 +851,4 @@
     add_workspace(pIorb)->unaligned = 1;
     return(ata_read_unaligned(pIorb, slot));
-
   }
   else
@@ -823,5 +871,5 @@
   ADD_WORKSPACE *aws = add_workspace(pIorb);
   AD_INFO *ai = ad_infos + iorb_unit_adapter(pIorb);
-  ULONG sector = io->RBA + io->BlocksXferred;
+  ULONGLONG ullLba = io->RBA + io->BlocksXferred;
   SCATGATENTRY sg_single;
   int p = iorb_unit_port(pIorb);
@@ -829,5 +877,10 @@
   int rc;
 
-  DPRINTF(7,"ata_read_unaligned(%d.%d.%d, %d)\n", ad_no(ai), p, d, sector);
+  if (add_workspace(pIorb)->fIs64bit)
+  {
+    ullLba = ((IORB_EXECUTEIO64*)pIorb)->ullRBA + io->BlocksXferred;
+  }
+
+  DPRINTF(7,"ata_read_unaligned(%d.%d.%d, %lld)\n", ad_no(ai), p, d, ullLba);
   ai->ports[p].unaligned_read_count++;
 
@@ -842,5 +895,5 @@
   sg_single.ppXferBuf = MemPhysAdr(aws->buf);
   sg_single.XferBufLen = io->BlockSize;
-  rc = ata_cmd_read(pIorb, ai, p, d, slot, sector, 1, &sg_single, 1);
+  rc = ata_cmd_read(pIorb, ai, p, d, slot, ullLba, 1, &sg_single, 1);
 
   if (rc == 0) {
@@ -873,7 +926,6 @@
   {
     /* copy transfer buffer to corresponding physical address in S/G list */
-    sg_memcpy(pSGList, io->cSGList,
-              (ULONG) io->BlocksXferred * (ULONG) io->BlockSize,
-              aws->buf, io->BlockSize, BUF_TO_SG);
+    CopySgBuf(pSGList, io->cSGList, (ULONG)io->BlocksXferred * (ULONG)io->BlockSize,
+              aws->buf, io->BlockSize, BUF_TO_SGL);
   }
 
@@ -902,4 +954,5 @@
   int p = iorb_unit_port(pIorb);
   int d = iorb_unit_device(pIorb);
+  ULONGLONG ullLba = io->RBA;
   int rc;
 
@@ -910,6 +963,11 @@
   }
 
+  if (add_workspace(pIorb)->fIs64bit)
+  {
+    ullLba = ((IORB_EXECUTEIO64*)pIorb)->ullRBA;
+  }
+
   /* prepare verify command */
-  if (io->RBA >= (1UL << 28) || io->BlockCount > 256)
+  if (ullLba >= (1UL << 28) || io->BlockCount > 256)
   {
     /* need LBA48 for this command */
@@ -919,5 +977,5 @@
     }
     rc = ata_cmd(ai, p, d, slot, ATA_CMD_VERIFY_EXT,
-                 AP_SECTOR_48, io->RBA, 0,
+                 AP_SECTOR_48, ullLba,
                  AP_COUNT,     io->BlockCount,
                  AP_DEVICE,    0x40,
@@ -925,5 +983,5 @@
   } else {
     rc = ata_cmd(ai, p, d, slot, ATA_CMD_VERIFY,
-                 AP_SECTOR_28, io->RBA,
+                 AP_SECTOR_28, (ULONG)ullLba,
                  AP_COUNT,     io->BlockCount & 0xffU,
                  AP_DEVICE,    0x40,
@@ -935,4 +993,62 @@
 
 /******************************************************************************
+ * Fabricate ATA WRITE command based on the capabilities of the corresponding
+ * device and the paramters set from above (NCQ, etc)
+ */
+static int ata_cmd_write(IORBH *pIorb, AD_INFO *ai, int p, int d, int slot,
+                         ULONGLONG ullLba, ULONG count, SCATGATENTRY *sg_list,
+                         ULONG sg_cnt, int write_through)
+{
+  int rc;
+
+  if (ullLba >= (1UL << 28) || count > 256 || add_workspace(pIorb)->is_ncq)
+  {
+    /* need LBA48 for this command */
+    if (!ai->ports[p].devs[d].lba48)
+    {
+      iorb_seterr(pIorb, IOERR_RBA_LIMIT);
+      return(-1);
+    }
+    if (add_workspace(pIorb)->is_ncq)
+    {
+      /* use NCQ write; count goes into feature register, tag into count! */
+      rc = ata_cmd(ai, p, d, slot, ATA_CMD_FPDMA_WRITE,
+                   AP_SECTOR_48, ullLba,
+                   AP_FEATURES,  count,
+                   /* tag = slot */
+                   AP_COUNT,     (slot << 3),
+                   AP_SGLIST,    sg_list, sg_cnt,
+                   AP_DEVICE,    0x40,
+                   /* force unit access */
+                   AP_DEVICE,    (write_through && !force_write_cache) ? 0x80 : 0,
+                   AP_WRITE,     1,
+                   AP_END);
+    }
+    else
+    {
+      rc = ata_cmd(ai, p, d, slot, ATA_CMD_WRITE_EXT,
+                   AP_SECTOR_48, ullLba,
+                   AP_COUNT,     count,
+                   AP_SGLIST,    sg_list, sg_cnt,
+                   AP_DEVICE,    0x40,
+                   AP_WRITE,     1,
+                   AP_END);
+    }
+  }
+  else
+  {
+    rc = ata_cmd(ai, p, d, slot, ATA_CMD_WRITE,
+                 AP_SECTOR_28, (ULONG)ullLba,
+                 AP_COUNT,     count & 0xffU,
+                 AP_SGLIST,    sg_list, sg_cnt,
+                 AP_DEVICE,    0x40,
+                 AP_WRITE,     1,
+                 AP_END);
+  }
+
+  return(rc);
+}
+
+/******************************************************************************
  * Write sectors to AHCI device.
  */
@@ -942,5 +1058,5 @@
   SCATGATENTRY *pSGList = (SCATGATENTRY*)Far16ToFlat(io->f16SGList);
   AD_INFO *ai = ad_infos + iorb_unit_adapter(pIorb);
-  ULONG sector = io->RBA + io->BlocksXferred;
+  ULONGLONG ullLba = io->RBA + io->BlocksXferred;
   USHORT count = io->BlockCount - io->BlocksXferred;
   USHORT sg_indx;
@@ -962,14 +1078,19 @@
   }
 
+  if (add_workspace(pIorb)->fIs64bit)
+  {
+    ullLba = ((IORB_EXECUTEIO64*)pIorb)->ullRBA + io->BlocksXferred;
+  }
+
   /* prepare write command while keeping an eye on S/G count limitations */
   do {
-    sg_indx = ata_get_sg_indx(io);
+    sg_indx = SgIndexFromOffset(pSGList, io->cSGList, io->BlocksXferred * io->BlockSize);
     sg_cnt = io->cSGList - sg_indx;
-    if ((rc = ata_cmd_write(pIorb, ai, p, d, slot, sector, count,
+    if ((rc = ata_cmd_write(pIorb, ai, p, d, slot, ullLba, count,
                             pSGList + sg_indx, sg_cnt,
                             io->Flags & XIO_DISABLE_HW_WRITE_CACHE)) > 0)
     {
       /* couldn't map all S/G elements */
-      ata_max_sg_cnt(io, sg_indx, (USHORT) rc, &sg_cnt, &count);
+      ata_max_sg_cnt(io, sg_indx, (USHORT)rc, &sg_cnt, &count);
     }
   } while (rc > 0 && sg_cnt > 0);
@@ -1010,5 +1131,5 @@
   ADD_WORKSPACE *aws = add_workspace(pIorb);
   AD_INFO *ai = ad_infos + iorb_unit_adapter(pIorb);
-  ULONG sector = io->RBA + io->BlocksXferred;
+  ULONGLONG ullLba = io->RBA + io->BlocksXferred;
   SCATGATENTRY sg_single;
   int p = iorb_unit_port(pIorb);
@@ -1016,5 +1137,10 @@
   int rc;
 
-  DPRINTF(7,"ata_write_unaligned(%d.%d.%d, %d)\n", ad_no(ai), p, d, sector);
+  if (add_workspace(pIorb)->fIs64bit)
+  {
+    ullLba = ((IORB_EXECUTEIO64*)pIorb)->ullRBA + io->BlocksXferred;
+  }
+
+  DPRINTF(7,"ata_write_unaligned(%d.%d.%d, %lld)\n", ad_no(ai), p, d, ullLba);
 
   /* allocate transfer buffer */
@@ -1026,12 +1152,11 @@
 
   /* copy next sector from S/G list to transfer buffer */
-  sg_memcpy(pSGList, io->cSGList,
-            (ULONG) io->BlocksXferred * (ULONG) io->BlockSize,
-            aws->buf, io->BlockSize, SG_TO_BUF);
+  CopySgBuf(pSGList, io->cSGList, (ULONG)io->BlocksXferred * (ULONG)io->BlockSize,
+            aws->buf, io->BlockSize, SGL_TO_BUF);
 
   /* prepare write command using transfer buffer */
   sg_single.ppXferBuf = MemPhysAdr(aws->buf);
   sg_single.XferBufLen = io->BlockSize;
-  rc = ata_cmd_write(pIorb, ai, p, d, slot, sector, 1, &sg_single, 1,
+  rc = ata_cmd_write(pIorb, ai, p, d, slot, ullLba, 1, &sg_single, 1,
                      io->Flags & XIO_DISABLE_HW_WRITE_CACHE);
 
@@ -1250,160 +1375,4 @@
 
 /******************************************************************************
- * Fabricate ATA READ command based on the capabilities of the corresponding
- * device and the paramters set from above (NCQ, etc).
- */
-static int ata_cmd_read(IORBH *pIorb, AD_INFO *ai, int p, int d, int slot,
-                        ULONG sector, ULONG count, SCATGATENTRY *sg_list,
-                        ULONG sg_cnt)
-{
-  int rc;
-
-  if (sector >= (1UL << 28) || count > 256 || add_workspace(pIorb)->is_ncq)
-  {
-    /* need LBA48 for this command */
-    if (!ai->ports[p].devs[d].lba48)
-    {
-      iorb_seterr(pIorb, IOERR_RBA_LIMIT);
-      return(-1);
-    }
-    if (add_workspace(pIorb)->is_ncq)
-    {
-      /* use NCQ read; count goes into feature register, tag into count! */
-      rc = ata_cmd(ai, p, d, slot, ATA_CMD_FPDMA_READ,
-                   AP_SECTOR_48, sector, 0,
-                   AP_FEATURES,  count,
-                   AP_COUNT,     (slot << 3), /* tag == slot */
-                   AP_SGLIST,    sg_list, sg_cnt,
-                   AP_DEVICE,    0x40,
-                   AP_END);
-    }
-    else
-    {
-      rc = ata_cmd(ai, p, d, slot, ATA_CMD_READ_EXT,
-                   AP_SECTOR_48, sector, 0,
-                   AP_COUNT,     count,
-                   AP_SGLIST,    sg_list, sg_cnt,
-                   AP_DEVICE,    0x40,
-                   AP_END);
-    }
-
-  }
-  else
-  {
-    rc = ata_cmd(ai, p, d, slot, ATA_CMD_READ,
-                 AP_SECTOR_28, sector,
-                 AP_COUNT,     count & 0xffU,
-                 AP_SGLIST,    sg_list, sg_cnt,
-                 AP_DEVICE,    0x40,
-                 AP_END);
-  }
-
-  return(rc);
-}
-
-/******************************************************************************
- * Fabricate ATA WRITE command based on the capabilities of the corresponding
- * device and the paramters set from above (NCQ, etc)
- */
-static int ata_cmd_write(IORBH *pIorb, AD_INFO *ai, int p, int d, int slot,
-                         ULONG sector, ULONG count, SCATGATENTRY *sg_list,
-                         ULONG sg_cnt, int write_through)
-{
-  int rc;
-
-  if (sector >= (1UL << 28) || count > 256 || add_workspace(pIorb)->is_ncq)
-  {
-    /* need LBA48 for this command */
-    if (!ai->ports[p].devs[d].lba48)
-    {
-      iorb_seterr(pIorb, IOERR_RBA_LIMIT);
-      return(-1);
-    }
-    if (add_workspace(pIorb)->is_ncq)
-    {
-      /* use NCQ write; count goes into feature register, tag into count! */
-      rc = ata_cmd(ai, p, d, slot, ATA_CMD_FPDMA_WRITE,
-                   AP_SECTOR_48, sector, 0,
-                   AP_FEATURES,  count,
-                   /* tag = slot */
-                   AP_COUNT,     (slot << 3),
-                   AP_SGLIST,    sg_list, sg_cnt,
-                   AP_DEVICE,    0x40,
-                   /* force unit access */
-                   AP_DEVICE,    (write_through && !force_write_cache) ? 0x80 : 0,
-                   AP_WRITE,     1,
-                   AP_END);
-    }
-    else
-    {
-      rc = ata_cmd(ai, p, d, slot, ATA_CMD_WRITE_EXT,
-                   AP_SECTOR_48, sector, 0,
-                   AP_COUNT,     count,
-                   AP_SGLIST,    sg_list, sg_cnt,
-                   AP_DEVICE,    0x40,
-                   AP_WRITE,     1,
-                   AP_END);
-    }
-  }
-  else
-  {
-    rc = ata_cmd(ai, p, d, slot, ATA_CMD_WRITE,
-                 AP_SECTOR_28, sector,
-                 AP_COUNT,     count & 0xffU,
-                 AP_SGLIST,    sg_list, sg_cnt,
-                 AP_DEVICE,    0x40,
-                 AP_WRITE,     1,
-                 AP_END);
-  }
-
-  return(rc);
-}
-
-/******************************************************************************
- * Copy block from S/G list to virtual address or vice versa.
- */
-void sg_memcpy(SCATGATENTRY *sg_list, USHORT sg_cnt, ULONG sg_off,
-               void *buf, USHORT len, SG_MEMCPY_DIRECTION dir)
-{
-  USHORT i;
-  USHORT l;
-  ULONG phys_addr;
-  ULONG pos = 0;
-  char *p;
-
-  /* walk through S/G list to find the elements involved in the operation */
-  for (i = 0; i < sg_cnt && len > 0; i++)
-  {
-    if (pos <= sg_off && pos + sg_list[i].XferBufLen > sg_off)
-    {
-      /* this S/G element intersects with the block to be copied */
-      phys_addr = sg_list[i].ppXferBuf + (sg_off - pos);
-      if ((l = sg_list[i].XferBufLen - (sg_off - pos)) > len)
-      {
-        l = len;
-      }
-
-      if (Dev32Help_PhysToLin(phys_addr, l, (PVOID) &p))
-      {
-        panic(__func__": DevHelp_PhysToLin() failed");
-      }
-      if (dir == SG_TO_BUF)
-      {
-        memcpy(buf, p, l);
-      }
-      else
-      {
-        memcpy(p, buf, l);
-      }
-      sg_off += l;
-      buf = (char *) buf + l;
-      len -= l;
-    }
-
-    pos += sg_list[i].XferBufLen;
-  }
-}
-
-/******************************************************************************
  * Halt processing by submitting an internal error. This is a last resort and
  * should only be called when the system state is corrupt.
Index: /trunk/src/os2ahci/ata.h
===================================================================
--- /trunk/src/os2ahci/ata.h	(revision 206)
+++ /trunk/src/os2ahci/ata.h	(revision 207)
@@ -492,7 +492,5 @@
 extern int v_ata_cmd(AD_INFO *ai, int port, int device, int slot, int cmd, va_list va);
 extern void ata_cmd_to_fis(u8 *fis, ATA_CMD *cmd, int device);
-extern USHORT ata_get_sg_indx(IORB_EXECUTEIO *io);
 extern void ata_max_sg_cnt(IORB_EXECUTEIO *io, USHORT sg_indx, USHORT sg_max, USHORT *sg_cnt, USHORT *sector_cnt);
-
 extern int ata_get_geometry(IORBH FAR16DATA *iorb, IORBH *pIorb, int slot);
 extern void ata_get_geometry_pp(IORBH FAR16DATA *vIorb, IORBH *pIorb);
@@ -508,5 +506,4 @@
 extern void ata_execute_ata_pp(IORBH FAR16DATA *vIorb, IORBH *pIorb);
 extern int ata_req_sense(IORBH FAR16DATA *vIorb, IORBH *pIorb, int slot);
-
 extern char *ata_dev_name(u16 *id_buf);
 
Index: /trunk/src/os2ahci/atapi.c
===================================================================
--- /trunk/src/os2ahci/atapi.c	(revision 206)
+++ /trunk/src/os2ahci/atapi.c	(revision 207)
@@ -99,5 +99,5 @@
 
     /* update S/G count and index */
-    sg_indx = ata_get_sg_indx(io);
+    sg_indx = SgIndexFromOffset(pSGList, io->cSGList, io->BlocksXferred * io->BlockSize);
     sg_cnt = io->cSGList - sg_indx;
 
Index: /trunk/src/os2ahci/os2ahci.c
===================================================================
--- /trunk/src/os2ahci/os2ahci.c	(revision 206)
+++ /trunk/src/os2ahci/os2ahci.c	(revision 207)
@@ -89,4 +89,5 @@
 int suspended;
 int resume_sleep_flag;
+AHCISTATS AhciStats;
 
 /* apapter/port-specific options saved when parsing the command line */
@@ -189,4 +190,7 @@
   UtSetDriverName("OS2AHCI$");
   Header.ulCaps |= DEV_ADAPTER_DD; /* DAZ This flag is not really needed. */
+  memset(&AhciStats, 0, sizeof(AhciStats));
+  AhciStats.ulSize = sizeof(AhciStats);
+  AhciStats.ulVersion = 0x101;
 
   /* create driver-level spinlock */
@@ -219,7 +223,7 @@
     }
 
-    if (ArgCmp(pszCmdLine, "C:"))
-    {
-      pszCmdLine += 2;
+    if (ArgCmp(pszCmdLine, "COM:"))
+    {
+      pszCmdLine += 4;
       /* set COM port base address for debug messages */
       D32g_ComBase = strtol(pszCmdLine, &pszCmdLine, 0);
@@ -483,4 +487,5 @@
 {
   DPRINTF(2,"IOCTL 0x%x/0x%x\n", ioctl->ioctl.bCategory, ioctl->ioctl.bFunction);
+  AhciStats.ulTestCount2++;
 
   switch (ioctl->ioctl.bCategory)
@@ -803,8 +808,14 @@
     break;
 
+  case IOCC_GEOMETRY_64:
+    add_workspace(pIorb)->fIs64bit = 1;
+    /* fall thru */
   case IOCC_GEOMETRY:
     iocc_geometry(vIorb, pIorb);
     break;
 
+  case IOCC_EXECUTE_IO_64:
+    add_workspace(pIorb)->fIs64bit = 1;
+    /* fall thru */
   case IOCC_EXECUTE_IO:
     iocc_execute_io(vIorb, pIorb);
@@ -816,4 +827,5 @@
 
   case IOCC_ADAPTER_PASSTHRU:
+    AhciStats.ulTestCount1++;
     iocc_adapter_passthru(vIorb, pIorb);
     break;
@@ -1215,8 +1227,4 @@
 
   case IOCM_WRITE:
-    add_workspace(pIorb)->idempotent = 1;
-    ahci_write(vIorb, pIorb);
-    break;
-
   case IOCM_WRITE_VERIFY:
     add_workspace(pIorb)->idempotent = 1;
Index: /trunk/src/os2ahci/os2ahci.h
===================================================================
--- /trunk/src/os2ahci/os2ahci.h	(revision 206)
+++ /trunk/src/os2ahci/os2ahci.h	(revision 207)
@@ -230,8 +230,8 @@
 
 typedef struct {
-    USHORT Cylinders;
+    ULONG Cylinders;
     USHORT HeadsPerCylinder;
     USHORT SectorsPerTrack;
-    ULONG  TotalSectors;
+    ULONGLONG  TotalSectors;
     char *Method;
 } DEV_INFO;
@@ -248,4 +248,7 @@
   u32           dma_buf_phys;          /* 14 physical address of DMA scratch buffer */
   u8           *dma_buf;               /* 18 DMA scatch buffers */
+  u32 unaligned_read_count;
+  u32 error_count;
+  u32 ulResetCount; /* added in 2.07 */
 
   struct {                             /* 1c */
@@ -263,8 +266,4 @@
     char dev_name[AHCI_DEV_NAME_LEN];
   } devs[AHCI_MAX_DEVS];
-
-  u32 unaligned_read_count;
-  u32 error_count;
-  u32 ulResetCount; /* added in 2.07 */
 } P_INFO;
 
@@ -313,4 +312,5 @@
   unsigned short processing    :1;     /* 0e IORB is being processd */
   unsigned short idempotent    :1;     /*    IORB is idempotent (can be retried) */
+  unsigned short fIs64bit      :1;     /* Transaction is a 64 bit operation */
   unsigned short queued_hw     :1;     /*    IORB has been queued to hardware */
   unsigned short no_ncq        :1;     /*    must not use native command queuing */
@@ -354,4 +354,13 @@
                                    /* These are the four entries which correspond to the entries in the partition table. */
 } DLA_Table_Sector, *PDLA_Table_Sector;
+
+typedef struct _ahcistats_
+{
+  ULONG ulSize;
+  ULONG ulVersion;
+  ULONG ulTestCount3;
+  ULONG ulTestCount2;
+  ULONG ulTestCount1;
+} AHCISTATS;
 
 static inline unsigned long readl(void *a)
@@ -487,4 +496,5 @@
 extern int suspended; /* indicates if the driver is suspended */
 extern int resume_sleep_flag;
+extern AHCISTATS AhciStats;
 
 /* port restart context hook and input data */
Index: /trunk/src/os2ahci/trace.c
===================================================================
--- /trunk/src/os2ahci/trace.c	(revision 206)
+++ /trunk/src/os2ahci/trace.c	(revision 207)
@@ -5,4 +5,5 @@
  */
 
+#define INCL_LONGLONG
 #include "os2ahci.h"
 
@@ -37,7 +38,6 @@
         if (pi->devs[d].present)
         {
-          if (iFlag) dprintf(0,"  Port %d:\n", p);
+          if (iFlag) dprintf(0,"  Port %d:", p);
           iFlag = 0;
-          dprintf(0,"    Drive %d:", d);
           if (pi->devs[d].atapi) dprintf(0," atapi");
           if (pi->devs[d].removable) dprintf(0," removable");
@@ -46,15 +46,13 @@
             dprintf(0," %d cylinders, %d heads, %d sectors per track (%dMB) (%s)",
               pi->devs[d].dev_info.Cylinders, pi->devs[d].dev_info.HeadsPerCylinder, pi->devs[d].dev_info.SectorsPerTrack,
-              pi->devs[d].dev_info.TotalSectors/2048, pi->devs[d].dev_info.Method);
+              (ULONG)(pi->devs[d].dev_info.TotalSectors/2048), pi->devs[d].dev_info.Method);
           }
-          if (pi->devs[d].ignored) dprintf(0," Not a usable disk");
+          if (pi->devs[d].ignored) dprintf(0," Unusable");
           dprintf(0,"\n");
-          dprintf(0,"             Model: %s\n", pi->devs[d].dev_name);
+          dprintf(0,"          Model: %s\n", pi->devs[d].dev_name);
         }
         else if (verbosity > 0)
         {
-          if (iFlag) dprintf(0,"  Port %d:\n", p);
-          iFlag = 0;
-          dprintf(0,"    No drive present\n");
+          if (iFlag) dprintf(0,"  Port %d: No drive present\n", p);
         } /* if */
       } /* for d */
