Index: /trunk/src/os2ahci/ata.c
===================================================================
--- /trunk/src/os2ahci/ata.c	(revision 59)
+++ /trunk/src/os2ahci/ata.c	(revision 60)
@@ -627,5 +627,5 @@
 
   io->BlocksXferred += add_workspace(iorb)->blocks;
-  ddprintf("ata_read_pp(): blocks transferred = %d\n", (int) io->BlocksXferred);
+  ddprintf("ata(pi)_read_pp(): blocks transferred = %d\n", (int) io->BlocksXferred);
 
   if (io->BlocksXferred >= io->BlockCount) {
Index: /trunk/src/os2ahci/atapi.c
===================================================================
--- /trunk/src/os2ahci/atapi.c	(revision 59)
+++ /trunk/src/os2ahci/atapi.c	(revision 60)
@@ -23,4 +23,5 @@
 #include "os2ahci.h"
 #include "ata.h"
+#include "atapi.h"
 
 /* -------------------------- macros and constants ------------------------- */
@@ -29,4 +30,8 @@
 
 /* -------------------------- function prototypes -------------------------- */
+
+static void atapi_req_sense_pp      (IORBH _far *iorb);
+static void atapi_execute_cdb_pp    (IORBH _far *iorb);
+
 
 /* ------------------------ global/static variables ------------------------ */
@@ -49,4 +54,5 @@
 int atapi_unit_ready(IORBH _far *iorb, int slot)
 {
+  dprintf("atapi_unit_ready called\n");
   iorb_seterr(iorb, IOERR_CMD_NOT_SUPPORTED);
   return(-1);
@@ -58,7 +64,56 @@
 int atapi_read(IORBH _far *iorb, int slot)
 {
-  iorb_seterr(iorb, IOERR_CMD_NOT_SUPPORTED);
-  return(-1);
-}  
+  IORB_EXECUTEIO _far *io = (IORB_EXECUTEIO _far *) iorb;
+  ATAPI_CDB_12 cdb;
+  AD_INFO *ai = ad_infos + iorb_unit_adapter(iorb);
+  USHORT count = io->BlockCount - io->BlocksXferred;
+  USHORT sg_indx;
+  USHORT sg_cnt;
+  int p = iorb_unit_port(iorb);
+  int d = iorb_unit_device(iorb);
+  int rc;
+
+  /* translate read command to SCSI/ATAPI READ12 command.
+   * READ12 seems to be the most supported READ variant - according to MMC,
+   * and its enough even for BluRay.
+   */
+  memset(&cdb, 0x00, sizeof(cdb));
+  cdb.cmd = ATAPI_CMD_READ_12;
+  SET_CDB_32(cdb.lba, io->RBA + io->BlocksXferred);
+
+  do {
+    /* update sector count (might have been updated due to S/G limitations) */
+    SET_CDB_32(cdb.trans_len, (u32) count);
+
+    /* update S/G count and index */
+    sg_indx = ata_get_sg_indx(io);
+    sg_cnt = io->cSGList - sg_indx;
+
+    /* issue command */
+    rc = ata_cmd(ai, p, d, slot, ATA_CMD_PACKET,
+                 AP_ATAPI_CMD, (void _far *) &cdb, sizeof(cdb),
+                 AP_SGLIST,    io->pSGList + sg_indx, (u16) sg_cnt,
+                 AP_DEVICE,    0x4000,
+                 AP_END);
+
+    if (rc > 0) {
+      /* couldn't map all S/G elements */
+      ata_max_sg_cnt(io, sg_indx, (USHORT) rc, &sg_cnt, &count);
+    }
+  } while (rc > 0 && sg_cnt > 0);
+    
+  if (rc == 0) {
+    add_workspace(iorb)->blocks = count;
+    add_workspace(iorb)->ppfunc = ata_read_pp;
+
+  } else if (rc > 0) {
+    iorb_seterr(iorb, IOERR_CMD_SGLIST_BAD);
+
+  } else {
+    iorb_seterr(iorb, IOERR_CMD_ADD_SOFTWARE_FAILURE);
+  }
+
+  return(rc);
+}
 
 /******************************************************************************
@@ -67,4 +122,5 @@
 int atapi_verify(IORBH _far *iorb, int slot)
 {
+  dprintf("atapi_verify called\n");
   iorb_seterr(iorb, IOERR_CMD_NOT_SUPPORTED);
   return(-1);
@@ -76,4 +132,5 @@
 int atapi_write(IORBH _far *iorb, int slot)
 {
+  dprintf("atapi_write called\n");
   iorb_seterr(iorb, IOERR_CMD_NOT_SUPPORTED);
   return(-1);
@@ -85,6 +142,42 @@
 int atapi_execute_cdb(IORBH _far *iorb, int slot)
 {
-  iorb_seterr(iorb, IOERR_CMD_NOT_SUPPORTED);
-  return(-1);
+  IORB_ADAPTER_PASSTHRU _far *pt = (IORB_ADAPTER_PASSTHRU _far *) iorb;
+  int rc;
+
+  /* we do not perform the S/G limitation recovery loop here:
+   * "ADDs are not required to iterate commands through the CDB PassThru
+   * mechanism:" -- Storage Device Driver Reference, Scatter/Gather Lists
+   */
+  rc = ata_cmd(ad_infos + iorb_unit_adapter(iorb),
+               iorb_unit_port(iorb),
+               iorb_unit_device(iorb),
+               slot, ATA_CMD_PACKET,
+               AP_ATAPI_CMD, (void _far *) pt->pControllerCmd, 
+                             pt->ControllerCmdLen,
+               AP_SGLIST,    pt->pSGList, pt->cSGList,
+               AP_END);
+
+  if (rc == 0) {
+    add_workspace(iorb)->blocks = pt->cSGList;
+    add_workspace(iorb)->ppfunc = atapi_execute_cdb_pp;
+
+  } else if (rc > 0) {
+    iorb_seterr(iorb, IOERR_CMD_SGLIST_BAD);
+
+  } else {
+    iorb_seterr(iorb, IOERR_CMD_ADD_SOFTWARE_FAILURE);
+  }
+  
+  return(rc);
+}
+
+/******************************************************************************
+ * Post processing function for atapi_execute_cdb(); since we have no
+ * knowledge of the command itself, we just tell the IRQ handler that
+ * we're done.
+ */
+static void atapi_execute_cdb_pp(IORBH _far *iorb)
+{
+  add_workspace(iorb)->complete = 1;
 }
 
@@ -100,6 +193,96 @@
 int atapi_req_sense(IORBH _far *iorb, int slot)
 {
-  iorb_seterr(iorb, IOERR_CMD_NOT_SUPPORTED);
-  return(-1);
-}
-
+  ADD_WORKSPACE _far *aws = add_workspace(iorb);
+  ATAPI_CDB_REQ_SENSE cdb;
+  int rc;
+  
+  /* allocate sense buffer in ADD workspace */
+  aws->buf = malloc(ATAPI_SENSE_LEN);
+  if (aws->buf == NULL) {
+    iorb_seterr(iorb, IOERR_CMD_SW_RESOURCE);
+    return(-1);
+  }
+  memset(aws->buf, 0x00, ATAPI_SENSE_LEN);
+
+  /* prepare request sense command */
+  memset(&cdb, 0x00, sizeof(cdb));
+  cdb.cmd = ATAPI_CMD_REQUEST_SENSE;
+  aws->ppfunc = atapi_req_sense_pp;
+  rc = ata_cmd(ad_infos + iorb_unit_adapter(iorb),
+               iorb_unit_port(iorb),
+               iorb_unit_device(iorb),
+               slot,
+               ATA_CMD_PACKET,
+               AP_ATAPI_CMD, (void _far*) &cdb, sizeof(cdb),
+               AP_VADDR, (void _far *) aws->buf, ATAPI_SENSE_LEN,
+               AP_END);
+
+  if (rc > 0) {
+    /* should never happen - we got 64 bytes here */
+    iorb_seterr(iorb, IOERR_CMD_SGLIST_BAD);
+
+  } else {
+    /* we failed to get info about an error -> return
+     * non specific device error
+     */
+    iorb_seterr(iorb, IOERR_DEVICE_NONSPECIFIC);
+  }
+
+  return(rc);
+}
+
+/******************************************************************************
+ * Post processing function for ATAPI request sense; examines the sense
+ * data returned and maps sense info to IORB error info.
+ */
+static void atapi_req_sense_pp(IORBH _far *iorb)
+{
+  ADD_WORKSPACE _far *aws = add_workspace(iorb);
+  ATAPI_SENSE_DATA *psd = (ATAPI_SENSE_DATA *) aws->buf;
+
+  /* map sense data to some IOERR_ value */
+  switch (ATAPI_GET_SENSE(psd)) {
+
+  case ASENSE_NO_SENSE:
+  case ASENSE_RECOVERED_ERROR:
+    /* no error */
+    break;
+
+  case ASENSE_NOT_READY:
+    iorb_seterr(iorb, IOERR_UNIT_NOT_READY);
+    break;
+
+  case ASENSE_UNIT_ATTENTION:
+    iorb_seterr(iorb, IOERR_MEDIA_CHANGED);
+    break;
+
+  case ASENSE_MEDIUM_ERROR:
+    iorb_seterr(iorb, IOERR_MEDIA);
+    break;
+
+  case ASENSE_ILLEGAL_REQUEST:
+    iorb_seterr(iorb, IOERR_CMD_SYNTAX);
+    break;
+
+  case ASENSE_DATA_PROTECT:
+    iorb_seterr(iorb, IOERR_MEDIA_WRITE_PROTECT);
+    break;
+
+  case ASENSE_BLANK_CHECK:
+    iorb_seterr(iorb, IOERR_MEDIA_NOT_FORMATTED);
+    break;
+
+  case ASENSE_ABORTED_COMMAND:
+  case ASENSE_COPY_ABORTED:
+    iorb_seterr(iorb, IOERR_CMD_ABORTED);
+    break;
+  
+  default:
+    iorb_seterr(iorb, IOERR_DEVICE_NONSPECIFIC);
+    break;
+  }
+
+  /* free sense buffer */
+  aws_free(aws);
+
+}
Index: /trunk/src/os2ahci/atapi.h
===================================================================
--- /trunk/src/os2ahci/atapi.h	(revision 59)
+++ /trunk/src/os2ahci/atapi.h	(revision 60)
@@ -2,6 +2,7 @@
  * atapi.h - ATAPI structures and macros for os2ahci driver
  *
- * Copyright (c) 2010 Christian Mueller. Parts copied from/inspired by the
- * Linux AHCI driver; those parts are (c) Linux AHCI/ATA maintainers
+ * Copyright (c) 2010 Christian Mueller, Markus Thielen. 
+ * Parts copied from/inspired by the  Linux AHCI driver; 
+ * those parts are (c) Linux AHCI/ATA maintainers
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -22,5 +23,132 @@
 /* -------------------------- macros and constants ------------------------- */
 
+/******************************************************************************
+ * macros to fill in ATAPI CDB values
+ */
+#define SET_CDB_16(_t, _v)  (_t)[0] = (u8) ((_v) >> 8);       \
+                            (_t)[1] = (u8)  (_v)
+#define SET_CDB_24(_t, _v)  (_t)[0] = (u8) ((_v) >> 16);      \
+                            (_t)[1] = (u8) ((_v) >> 8);       \
+                            (_t)[2] = (u8)  (_v)
+#define SET_CDB_32(_t, _v)  (_t)[0] = (u8) ((_v) >> 24);      \
+                            (_t)[1] = (u8) ((_v) >> 16);      \
+                            (_t)[2] = (u8) ((_v) >> 8);       \
+                            (_t)[3] = (u8)  (_v)
+
+#define GET_CDB_16(_f)      ((u16) (_f)[0] << 8  |            \
+                             (u16) (_f)[1])
+#define GET_CDB_24(_f)      ((u32) (_f)[0] << 16 |            \
+                             (u32) (_f)[1] << 8   |           \
+                             (u32) (_f)[2])
+#define GET_CDB_32(_f)      ((u32) (_f)[0] << 24  |           \
+			     (u32) (_f)[1] << 16  |           \
+                             (u32) (_f)[2] << 24  |           \
+                             (u32) (_f)[3])
+
+
+/******************************************************************************
+ * ATAPI/MMC command codes (as far as relevant for us)
+ */
+#define ATAPI_CMD_READ_6           0x08
+#define ATAPI_CMD_READ_10          0x28
+#define ATAPI_CMD_READ_12          0xa8
+#define ATAPI_CMD_READ_16          0x88
+#define ATAPI_CMD_WRITE_6          0x0a
+#define ATAPI_CMD_WRITE_10         0x2a
+#define ATAPI_CMD_WRITE_12         0xaa
+#define ATAPI_CMD_WRITE_16         0x8a
+#define ATAPI_CMD_REQUEST_SENSE    0x03
+
+/******************************************************************************
+ * ATAPI command flag bits
+ */
+#define ATAPI_FLAG_FUA             0x80
+#define ATAPI_FLAG_DPO             0x10
+
+/******************************************************************************
+ * ATAPI sense data
+ */
+#define ATAPI_SENSE_LEN            64
+
+#define ASENSE_NO_SENSE            0x00  /* no sense -> success */
+#define ASENSE_RECOVERED_ERROR     0x01  /* recovered error -> success */
+#define ASENSE_NOT_READY           0x02  /* device not ready */
+#define ASENSE_MEDIUM_ERROR        0x03  /* medium/CRC error */
+#define ASENSE_HARDWARE_ERROR      0x04  /* device error */
+#define ASENSE_ILLEGAL_REQUEST     0x05  /* invalid command/parameters issued */
+#define ASENSE_UNIT_ATTENTION      0x06  /* new medium */
+#define ASENSE_DATA_PROTECT        0x07  /* protected LBA */
+#define ASENSE_BLANK_CHECK         0x08  /* unformatted or write protected */
+#define ASENSE_VENDOR_SPECIFIC     0x09  /* vendor specific sense data */
+#define ASENSE_COPY_ABORTED        0x0a  /* copy, ...command aborted */
+#define ASENSE_ABORTED_COMMAND     0x0b  /* command has been aborted */
+#define ASENSE_EQUAL               0x0c
+#define ASENSE_VOLUME_OVERFLOW     0x0d  /* out of space */
+#define ASENSE_MISCOMPARE          0x0e  /* verification failed */
+#define ASENSE_RESERVED            0x0f
+
+/******************************************************************************
+ * macro to get sense key from ATAPI_SENSE_DATA pointer
+ */
+#define ATAPI_GET_SENSE(p_) (u8)(p_->sense.sense_key & 0x0f)
+
 /* ------------------------ typedefs and structures ------------------------ */
+
+/******************************************************************************
+ * ATAPI_SENSE_DATA - define layout of ATAPI sense data
+ */
+typedef union _ATAPI_SENSE_DATA {
+  struct {
+    u8 valid_respc;      /* valid bit (bit 7), response code (bits 6:0) */
+    u8 segment;          /* segment number (obsolete) */
+    u8 sense_key;        /* some flags (bits 7:4), sense key (bits 3:0) */
+    u8 info[4];          /* information (?) */
+    u8 adl_len;          /* additional sense info length */
+    u8 cmd_specific[4];  /* command specific stuff (ignored) */
+    u8 asc;              /* additional sense code */
+    u8 ascq;             /* additional sense code qualifier */
+    u8 fruc;             /* field replaceable unit code */
+    u8 flags;            /* vendor-specific flags */
+    u8 field_off[2];     /* offset to invalid field in parm list */
+  } sense;
+
+  u8 padding[ATAPI_SENSE_LEN]; /* pad to 64 bytes */
+
+} ATAPI_SENSE_DATA;
+
+/******************************************************************************
+ * ATAPI_CDB_10 - describes layout of generic 10 byte ATAPI command
+ */
+typedef struct _ATAPI_CMD_10 {
+  u8   cmd;            /* SCSI/ATAPI command code */
+  u8   flags;          /* flags (DPO, FUA) */
+  u8   lba[4];         /* logical block address */
+  u8   trans_len[2];   /* number of blocks to transfer */
+  u8   control;        /* (nothing much) */
+} ATAPI_CDB_10;
+
+/******************************************************************************
+ * ATAPI_CDB_12 - describes layout of generic 12 byte ATAPI command
+ */
+typedef struct _ATAPI_CMD_12 {
+  u8   cmd;            /* SCSI/ATAPI command code */
+  u8   flags;          /* flags (DPO, FUA) */
+  u8   lba[4];         /* logical block address */
+  u8   trans_len[4];   /* number of blocks to transfer */
+  u8   reserved;
+  u8   control;        /* (nothing much) */
+} ATAPI_CDB_12;
+
+/******************************************************************************Ã
+ * ATAPI_CDB_REQ_SENSE - describes request sense command
+ */
+typedef struct _ATAPI_CMD_REQ_SENSE {
+  u8   cmd;            /* command code (0x03) */
+  u8   lun:3;          /* SCSI lun (ignored) */
+  u8   resvd:5;
+  u8   buffer_len;     /* sense buffer length */
+  u8   control;
+} ATAPI_CDB_REQ_SENSE;
+
 
 /* ---------------------------- global variables --------------------------- */
Index: /trunk/src/os2ahci/os2ahci.def
===================================================================
--- /trunk/src/os2ahci/os2ahci.def	(revision 59)
+++ /trunk/src/os2ahci/os2ahci.def	(revision 60)
@@ -1,4 +1,4 @@
 library os2ahci
-Description '$@#thi.guten (www.thiguten.de):1.00.20101215#@OS/2 AHCI Adapter Device Driver'
+Description '$@#thi.guten (www.thiguten.de):1.00.20101216#@OS/2 AHCI Adapter Device Driver'
 protmode
 
Index: /trunk/tools/bldlvl.cmd
===================================================================
--- /trunk/tools/bldlvl.cmd	(revision 59)
+++ /trunk/tools/bldlvl.cmd	(revision 60)
@@ -267,2 +267,3 @@
     Return 0
 
+
