Index: /trunk/src/lbatest/lbatest.c
===================================================================
--- /trunk/src/lbatest/lbatest.c	(revision 44)
+++ /trunk/src/lbatest/lbatest.c	(revision 44)
@@ -0,0 +1,247 @@
+/******************************************************************************
+
+  lbatest.c - simple test program for os2ahci
+
+  Writes the actual LBA to each sector on a hard disk. The purpose is to
+  find out if the sector mapping of os2ahci.add is correct.
+
+  To run the test, attach a HD to an AHCI controller with os2ahci.add loaded
+  and run the test in write mode, then attach the disk to an IDE adapter with
+  with an S506 driver and run lbdatest in read mode.
+
+  Author: Markus Thielen
+
+  Compilation (Watcom): wcl386 -bt=os2 lbatest.c
+
+  Copyright (c) 2010 by thi.guten Software development, www.thiguten.de
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+******************************************************************************/
+
+/*---- includes -------------------------------------------------------------*/
+
+#define INCL_DOS
+#define INCL_ERRORS
+#define INCL_DOSDEVICES
+#define INCL_DOSDEVIOCTL
+#include <os2.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <ctype.h>
+#include <string.h>
+
+#define SECTOR_SIZE   512
+
+/*--- function prototypes ---------------------------------------------------*/
+
+void          usage            (void);
+
+int           write_test       (const char *drv);
+
+int           read_test        (const char *drv);
+
+
+/*--- start of code ---------------------------------------------------------*/
+
+/******************************************************************************
+ * main()
+ */
+int main(int argc, char **argv)
+{
+  char *drv;
+  char mode;
+  HFILE hf;
+
+  if (argc < 3) {
+    usage();
+    return -1;
+  }
+
+  /* get arguments */
+  drv = argv[1];
+  mode = toupper(argv[2][0]);
+  if (mode != 'W' && mode != 'R') {
+    usage();
+    return -1;
+  }
+
+  if (drv[1] != ':' && drv[2] != '\0') {
+    /* we want a drive letter, which is a letter and a colon */
+    usage();
+    return -1;
+  }
+
+  if (mode == 'W') {
+    return write_test(drv);
+  }
+  if (mode == 'R') {
+    return read_test(drv);
+  }
+
+  return 0;
+}
+
+/******************************************************************************
+ * write_test() - write each sector's address to the sector itself
+ */
+int write_test(const char *drv)
+{
+  unsigned long lba;
+  unsigned long ret;
+  HFILE hf_disk;
+  unsigned long action;
+  unsigned long cb_written;
+  char buf[SECTOR_SIZE];
+  int rc = 0;
+  float gbf = 1024.0 * 1024.0 * 1024.0 / 512.0;
+
+  /* ask for confirmation, we destroy the drive's contents */
+  printf("I'm going to destroy ALL DATA on drive %s now.\n"
+	 "type 'DESTROY' to continue, anything else to bail out.\n", drv);
+  if (gets(buf) == NULL || strcmp(buf, "DESTROY")) {
+    return -1;
+  }
+
+  /* open drive */
+  ret = DosOpen(drv, &hf_disk, &action, 0, 0, OPEN_ACTION_OPEN_IF_EXISTS,
+		OPEN_FLAGS_DASD | OPEN_FLAGS_FAIL_ON_ERROR |
+		OPEN_FLAGS_WRITE_THROUGH | OPEN_FLAGS_NO_CACHE |
+		OPEN_FLAGS_SEQUENTIAL | OPEN_SHARE_DENYREADWRITE |
+		OPEN_ACCESS_WRITEONLY,
+		NULL);
+  if (ret != NO_ERROR) {
+    fprintf(stderr, "Failed to open disk %s for writing: %d\n", drv, ret);
+    return -1;
+  }
+
+  /* lock disk */
+  ret = DosDevIOCtl(hf_disk, IOCTL_DISK, DSK_LOCKDRIVE, NULL, 0,
+		    &action, NULL, 0, &cb_written);
+  if (ret != NO_ERROR) {
+    fprintf(stderr, "Failed to lock drive, code %d\n", ret);
+    rc = -1;
+    goto cleanup;
+  }
+
+  /* go... */
+  memset(buf, 0x00, sizeof(buf));
+  for (lba = 0; ; lba++) {
+    memcpy(buf, &lba, sizeof(lba));
+    ret = DosWrite(hf_disk, buf, SECTOR_SIZE, &cb_written);
+    if (ret != NO_ERROR) {
+      fprintf(stderr, "\nFailed to write to disk %s, code %d\n", drv, ret);
+      rc = -1;
+      goto cleanup;
+    }
+
+    /* write progress */
+    if (lba % 100 == 0) {
+      printf("\r%dk sectors written (%0.02f GB)", lba / 1000, (float)lba / gbf);
+    }
+  }
+
+cleanup:
+  /* unlock drive */
+  DosDevIOCtl(hf_disk, IOCTL_DISK, DSK_UNLOCKDRIVE, NULL, 0, &action,
+              NULL, 0, &cb_written);
+
+  DosClose(hf_disk);
+  return rc;
+
+}
+
+/******************************************************************************
+ * read_test() - read each sector's first 4 bytes and compare to its LBA
+ */
+int read_test(const char *drv)
+{
+  unsigned long lba;
+  unsigned long ret;
+  HFILE hf_disk;
+  unsigned long action;
+  unsigned long cb_read;
+  char buf[SECTOR_SIZE];
+  int rc = 0;
+  unsigned long err_cnt = 0;
+  float gbf = 1024.0 * 1024.0 * 1024.0 / 512.0;
+
+  /* open drive */
+  ret = DosOpen(drv, &hf_disk, &action, 0, 0, OPEN_ACTION_OPEN_IF_EXISTS,
+		OPEN_FLAGS_DASD | OPEN_FLAGS_FAIL_ON_ERROR |
+		OPEN_FLAGS_WRITE_THROUGH | OPEN_FLAGS_NO_CACHE |
+		OPEN_FLAGS_SEQUENTIAL | OPEN_SHARE_DENYREADWRITE |
+		OPEN_ACCESS_READONLY,
+		NULL);
+  if (ret != NO_ERROR) {
+    fprintf(stderr, "Failed to open disk %s for reading: %d\n", drv, ret);
+    return -1;
+  }
+
+  /* lock disk */
+  ret = DosDevIOCtl(hf_disk, IOCTL_DISK, DSK_LOCKDRIVE, NULL, 0,
+		    &action, NULL, 0, &cb_read);
+  if (ret != NO_ERROR) {
+    fprintf(stderr, "Failed to lock drive, code %d\n", ret);
+    rc = -1;
+    goto cleanup;
+  }
+
+  /* go... */
+  memset(buf, 0x00, sizeof(buf));
+  for (lba = 0; ; lba++) {
+    ret = DosRead(hf_disk, buf, SECTOR_SIZE, &cb_read);
+    if (ret != NO_ERROR) {
+      fprintf(stderr, "\nFailed to read from disk %s, code %d\n", drv, ret);
+      rc = -1;
+      goto cleanup;
+    }
+
+    if (*((unsigned long*)buf) != lba) {
+      fprintf(stderr, "\nFailure: read %d from sector %d\n",
+	      *((unsigned long*)buf), lba);
+      err_cnt++;
+    }
+
+    /* progress */
+    if (lba % 100 == 0) {
+      printf("\r%dk sectors read (%0.02f GB)", lba / 1000, (float)lba / gbf);
+    }
+  }
+
+cleanup:
+  /* unlock drive */
+  DosDevIOCtl(hf_disk, IOCTL_DISK, DSK_UNLOCKDRIVE, NULL, 0, &action,
+              NULL, 0, &cb_read);
+
+  DosClose(hf_disk);
+
+  printf("Found %d logical errors (wrong values)\n", err_cnt);
+  return rc;
+}
+
+/******************************************************************************
+ * usage() - print usage summary to STDOUT
+ */
+void usage(void)
+{
+  printf("lbatest for os2ahci.add\n"
+	 "Usage:\n\n"
+	 "lbatest <drive letter> <mode>\n\n"
+	 "where mode is either W for writing or R for reading.\n\n"
+	 "In write mode, this program COMPLETELY DESTROYS ALL DATA on the specified\n"
+	 "disc. It writes the address of each sector to the sector itself.\n\n"
+	 "In read mode, each sector is read and its address verified.\n");
+}
Index: /trunk/src/os2ahci/ahci.h
===================================================================
--- /trunk/src/os2ahci/ahci.h	(revision 43)
+++ /trunk/src/os2ahci/ahci.h	(revision 44)
@@ -94,4 +94,5 @@
 #define HOST_EM_CTL             0x20 /* Enclosure Management Control */
 #define HOST_CAP2               0x24 /* host capabilities, extended */
+#define HOST_BOHC               0x28 /* BIOS hand off control and status */
 
 /* HOST_CTL bits */
@@ -123,4 +124,11 @@
 #define HOST_CAP2_NVMHCI        (1UL << 1)  /* NVMHCI supported */
 #define HOST_CAP2_APST          (1UL << 2)  /* Automatic partial to slumber */
+
+/* HOST_BOHC bits */
+#define HOST_BOHC_BOS           (1UL << 0)  /* BIOS owned (semaphore bit) */
+#define HOST_BOHC_OOS           (1UL << 1)  /* OS owned (semaphore bit) */
+#define HOST_BOHC_SOOE          (1UL << 2)  /* SMI on ownership change enable */
+#define HOST_BOHC_OOC           (1UL << 3)  /* OS ownership change */
+#define HOST_BOHC_BB            (1UL << 4)  /* BIOS is busy changing ownership */
 
 /* registers for each SATA port */
