]> xenbits.xen.org Git - xenclient/ioemu-pq.git/commitdiff
Atapi pass through using SG_IO to allow concurrent access by multiple VMs.
authorAndrew McNeil <andrewmcn@bob.uk.xensource.com>
Fri, 28 Aug 2009 19:42:48 +0000 (20:42 +0100)
committerJean Guyader <jean.guyader@eu.citrix.com>
Sun, 30 Aug 2009 13:56:36 +0000 (14:56 +0100)
All VMS get notifications on CD insertion and extraction.
CD writing is currently broken.

master/atapi-pass-through

index 9acc7b4ed0bfab37e423aceba61c01e1e93e5118..c79f08a88542b48d5a2ca240429d96baa46e670b 100644 (file)
@@ -14,7 +14,7 @@ index 5f4f4cf..42da5b6 100644
  cscope:
        rm -f ./cscope.*
 diff --git a/block-raw-posix.c b/block-raw-posix.c
-index 9a02d4f..775a1d1 100644
+index 9a02d4f..6898d6e 100644
 --- a/block-raw-posix.c
 +++ b/block-raw-posix.c
 @@ -97,20 +97,7 @@
@@ -39,6 +39,14 @@ index 9a02d4f..775a1d1 100644
  
  static int posix_aio_init(void);
  
+@@ -979,6 +966,7 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
+     s->type = FTYPE_FILE;
+ #if defined(__linux__)
++    printf("**** hdev_open(%s)\n", filename);
+     if (strstart(filename, "/dev/cd", NULL)) {
+         /* open will not fail even if no CD is inserted */
+         open_flags |= O_NONBLOCK;
 diff --git a/block.c b/block.c
 index 36f5eb9..ae71513 100644
 --- a/block.c
@@ -97,10 +105,12 @@ index 0000000..f9bdee9
 +#endif /* !BLOCK_RAW_POSIX_H */
 diff --git a/hw/atapi-pt.c b/hw/atapi-pt.c
 new file mode 100644
-index 0000000..2f63492
+index 0000000..413cc47
 --- /dev/null
 +++ b/hw/atapi-pt.c
-@@ -0,0 +1,970 @@
+@@ -0,0 +1,1427 @@
++#include <sys/stat.h>
++
 +#define DEBUG_IDE_ATAPI_PT
 +
 +#define MSF_TO_FRAMES(M, S, F) (((M) * CD_SECS + (S)) * CD_FRAMES + (F))
@@ -119,6 +129,11 @@ index 0000000..2f63492
 +# define CHECK_SAME_VALUE(Val1, Val2)
 +#endif /* DEBUG_IDE_ATAPI_PT */
 +
++
++#define IDE_ATAPI_PT_NEW_CD_FILE   "/var/lock/xen-cd-new"
++#define IDE_ATAPI_PT_EJECT_CD_FILE "/var/lock/xen-cd-eject"
++
++
 +/* The generic packet command opcodes for CD/DVD Logical Units,
 + * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
 +static const struct {
@@ -211,158 +226,371 @@ index 0000000..2f63492
 +    "(reserved)",
 +};
 +
-+/* From Table 304 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
++
++
++/* From Table 459 of the SFF8090 Ver. 4 (Mt. Fuji) draft standard.
++ * Code is (key << 16) | (asc << 8) | ascq
++ * Mask is a bit mask, since some codes span ranges of values.
++ */
 +static const struct {
-+    unsigned long asc_ascq;
++    unsigned long code;
++    unsigned long mask;
 +    const char * const text;
 +} sense_data_texts[] = {
-+    { 0x000000, "No additional sense information" },
-+    { 0x000011, "Play operation in progress" },
-+    { 0x000012, "Play operation paused" },
-+    { 0x000013, "Play operation successfully completed" },
-+    { 0x000014, "Play operation stopped due to error" },
-+    { 0x000015, "No current audio status to return" },
-+    { 0x010c0a, "Write error - padding blocks added" },
-+    { 0x011700, "Recovered data with no error correction applied" },
-+    { 0x011701, "Recovered data with retries" },
-+    { 0x011702, "Recovered data with positive head offset" },
-+    { 0x011703, "Recovered data with negative head offset" },
-+    { 0x011704, "Recovered data with retries and/or CIRC applied" },
-+    { 0x011705, "Recovered data using previous sector ID" },
-+    { 0x011800, "Recovered data with error correction applied" },
-+    { 0x011801, "Recovered data with error correction and retries applied"},
-+    { 0x011802, "Recovered data - the data was auto-reallocated" },
-+    { 0x011803, "Recovered data with CIRC" },
-+    { 0x011804, "Recovered data with L-EC" },
-+    { 0x015d00, "Failure prediction threshold exceeded"
-+      " - Predicted logical unit failure" },
-+    { 0x015d01, "Failure prediction threshold exceeded"
-+      " - Predicted media failure" },
-+    { 0x015dff, "Failure prediction threshold exceeded - False" },
-+    { 0x017301, "Power calibration area almost full" },
-+    { 0x020400, "Logical unit not ready - cause not reportable" },
-+    /* Following is misspelled in ATAPI 2.6, _and_ in Mt. Fuji */
-+    { 0x020401, "Logical unit not ready"
-+      " - in progress [sic] of becoming ready" },
-+    { 0x020402, "Logical unit not ready - initializing command required" },
-+    { 0x020403, "Logical unit not ready - manual intervention required" },
-+    { 0x020404, "Logical unit not ready - format in progress" },
-+    { 0x020407, "Logical unit not ready - operation in progress" },
-+    { 0x020408, "Logical unit not ready - long write in progress" },
-+    { 0x020600, "No reference position found (media may be upside down)" },
-+    { 0x023000, "Incompatible medium installed" },
-+    { 0x023a00, "Medium not present" },
-+    { 0x025300, "Media load or eject failed" },
-+    { 0x025700, "Unable to recover table of contents" },
-+    { 0x030300, "Peripheral device write fault" },
-+    { 0x030301, "No write current" },
-+    { 0x030302, "Excessive write errors" },
-+    { 0x030c00, "Write error" },
-+    { 0x030c01, "Write error - Recovered with auto reallocation" },
-+    { 0x030c02, "Write error - auto reallocation failed" },
-+    { 0x030c03, "Write error - recommend reassignment" },
-+    { 0x030c04, "Compression check miscompare error" },
-+    { 0x030c05, "Data expansion occurred during compress" },
-+    { 0x030c06, "Block not compressible" },
-+    { 0x030c07, "Write error - recovery needed" },
-+    { 0x030c08, "Write error - recovery failed" },
-+    { 0x030c09, "Write error - loss of streaming" },
-+    { 0x031100, "Unrecovered read error" },
-+    { 0x031106, "CIRC unrecovered error" },
-+    { 0x033101, "Format command failed" },
-+    { 0x033200, "No defect spare location available" },
-+    { 0x033201, "Defect list update failure" },
-+    { 0x035100, "Erase failure" },
-+    { 0x037200, "Session fixation error" },
-+    { 0x037201, "Session fixation error writin lead-in" },
-+    { 0x037202, "Session fixation error writin lead-out" },
-+    { 0x037300, "CD control error" },
-+    { 0x037302, "Power calibration area is full" },
-+    { 0x037303, "Power calibration area error" },
-+    { 0x037304, "Program memory area / RMA update failure" },
-+    { 0x037305, "Program memory area / RMA is full" },
-+    { 0x037306, "Program memory area / RMA is (almost) full" },
-+    { 0x040200, "No seek complete" },
-+    { 0x040300, "Write fault" },
-+    { 0x040900, "Track following error" },
-+    { 0x040901, "Tracking servo failure" },
-+    { 0x040902, "Focus servo failure" },
-+    { 0x040903, "Spindle servo failure" },
-+    { 0x041500, "Random positioning error" },
-+    { 0x041501, "Mechanical positioning or changer error" },
-+    { 0x041502, "Positioning error detected by read of medium" },
-+    { 0x043c00, "Mechanical positioning or changer error" },
-+    { 0x044000, "Diagnostic failure on component (ASCQ)" },
-+    { 0x044400, "Internal CD/DVD logical unit failure" },
-+    { 0x04b600, "Media load mechanism failed" },
-+    { 0x051a00, "Parameter list length error" },
-+    { 0x052000, "Invalid command operation code" },
-+    { 0x052100, "Logical block address out of range" },
-+    { 0x052102, "Invalid address for write" },
-+    { 0x052400, "Invalid field in command packet" },
-+    { 0x052600, "Invalid field in parameter list" },
-+    { 0x052601, "Parameter not supported" },
-+    { 0x052602, "Parameter value invalid" },
-+    { 0x052700, "Write protected media" },
-+    { 0x052c00, "Command sequence error" },
-+    { 0x052c03, "Current program area is not empty" },
-+    { 0x052c04, "Current program area is empty" },
-+    { 0x053001, "Cannot read medium - unknown format" },
-+    { 0x053002, "Cannot read medium - incompatible format" },
-+    { 0x053900, "Saving parameters not supported" },
-+    { 0x054e00, "Overlapped commands attempted" },
-+    { 0x055302, "Medium removal prevented" },
-+    { 0x055500, "System resource failure" },
-+    { 0x056300, "End of user area encountered on this track" },
-+    { 0x056400, "Illegal mode for this track or incompatible medium" },
-+    { 0x056f00, "Copy protection key exchange failure"
-+      " - Authentication failure" },
-+    { 0x056f01, "Copy protection key exchange failure - Key not present" },
-+    { 0x056f02, "Copy protection key exchange failure"
-+      " - Key not established" },
-+    { 0x056f03, "Read of scrambled sector without authentication" },
-+    { 0x056f04, "Media region code is mismatched to logical unit" },
-+    { 0x056f05, "Drive region must be permanent"
-+      " / region reset count error" },
-+    { 0x057203, "Session fixation error - incomplete track in session" },
-+    { 0x057204, "Empty or partially written reserved track" },
-+    { 0x057205, "No more RZONE reservations are allowed" },
-+    { 0x05bf00, "Loss of streaming" },
-+    { 0x062800, "Not ready to ready transition, medium may have changed" },
-+    { 0x062900, "Power on, reset or hardware reset occurred" },
-+    { 0x062a00, "Parameters changed" },
-+    { 0x062a01, "Mode parameters changed" },
-+    { 0x062e00, "Insufficient time for operation" },
-+    { 0x063f00, "Logical unit operating conditions have changed" },
-+    { 0x063f01, "Microcode has been changed" },
-+    { 0x065a00, "Operator request or state change input (unspecified)" },
-+    { 0x065a01, "Operator medium removal request" },
-+    { 0x0bb900, "Play operation aborted" },
-+    /* Here we use 0xff for the key (not a valid key) to signify
-+     * that these can have _any_ key value associated with them... */
-+    { 0xff0401, "Logical unit is in process of becoming ready" },
-+    { 0xff0400, "Logical unit not ready, cause not reportable" },
-+    { 0xff0402, "Logical unit not ready, initializing command required" },
-+    { 0xff0403, "Logical unit not ready, manual intervention required" },
-+    { 0xff0500, "Logical unit does not respond to selection" },
-+    { 0xff0800, "Logical unit communication failure" },
-+    { 0xff0802, "Logical unit communication parity error" },
-+    { 0xff0801, "Logical unit communication time-out" },
-+    { 0xff2500, "Logical unit not supported" },
-+    { 0xff4c00, "Logical unit failed self-configuration" },
-+    { 0xff3e00, "Logical unit has not self-configured yet" },
++    { 0x080000, 0xFF0000, "BLANK CHECK"},
++    { 0x000000, 0xFFFFFF, "NO ADDITIONAL SENSE INFORMATION"},
++    { 0x000001, 0xFFFFFF, "FILEMARK DETECTED"},
++    { 0x000002, 0xFFFFFF, "END-OF-PARTITION/MEDIUM DETECTED"},
++    { 0x000003, 0xFFFFFF, "SETMARK DETECTED"},
++    { 0x000004, 0xFFFFFF, "BEGINNING-OF-PARTITION/MEDIUM DETECTED"},
++    { 0x000005, 0xFFFFFF, "END-OF-DATA DETECTED"},
++    { 0x0B0006, 0xFFFFFF, "I/O PROCESS TERMINATED, PLAY OPERATION ABORTED"},
++    { 0x000011, 0xFFFFFF, "AUDIO PLAY OPERATION IN PROGRESS"},
++    { 0x000012, 0xFFFFFF, "AUDIO PLAY OPERATION PAUSED"},
++    { 0x000013, 0xFFFFFF, "AUDIO PLAY OPERATION SUCCESSFULLY COMPLETED"},
++    { 0x000014, 0xFFFFFF, "AUDIO PLAY OPERATION STOPPED DUE TO ERROR"},
++    { 0x000015, 0xFFFFFF, "NO CURRENT AUDIO STATUS TO RETURN"},
++    { 0x000016, 0xFFFFFF, "OPERATION IN PROGRESS"},
++    { 0x040017, 0xFFFFFF, "CLEANING REQUESTED"},
++    { 0x040100, 0xFFFFFF, "NO INDEX/SECTOR SIGNAL"},
++    { 0x030200, 0xFFFFFF, "NO SEEK COMPLETE"},
++    { 0x030300, 0xFFFFFF, "PERIPHERAL DEVICE WRITE FAULT"},
++    { 0x030301, 0xFFFFFF, "NO WRITE CURRENT"},
++    { 0x030302, 0xFFFFFF, "EXCESSIVE WRITE ERRORS"},
++    { 0x020400, 0xFFFFFF, "LOGICAL UNIT NOT READY, CAUSE NOT REPORTABLE"},
++    { 0x020401, 0xFFFFFF, "LOGICAL UNIT IS IN PROCESS OF BECOMING READY"},
++    { 0x020402, 0xFFFFFF, "LOGICAL UNIT NOT READY, INITIALIZING CMD. REQUIRED"},
++    { 0x020403, 0xFFFFFF, "LOGICAL UNIT NOT READY, MANUAL INTERVENTION REQUIRED"},
++    { 0x020404, 0xFFFFFF, "LOGICAL UNIT NOT READY, FORMAT IN PROGRESS"},
++    { 0x020405, 0xFFFFFF, "LOGICAL UNIT NOT READY, REBUILD IN PROGRESS"},
++    { 0x020406, 0xFFFFFF, "LOGICAL UNIT NOT READY, RECALCULATION IN PROGRESS"},
++    { 0x020407, 0xFFFFFF, "LOGICAL UNIT NOT READY, OPERATION IN PROGRESS"},
++    { 0x020408, 0xFFFFFF, "LOGICAL UNIT NOT READY, LONG WRITE IN PROGRESS"},
++    { 0x020500, 0xFFFFFF, "LOGICAL UNIT DOES NOT RESPOND TO SELECTION"},
++    { 0x020600, 0xFFFFFF, "NO REFERENCE POSITION FOUND (medium may be upside down)"},
++    { 0x050700, 0xFFFFFF, "MULTIPLE PERIPHERAL DEVICES SELECTED"},
++    { 0x040800, 0xFFFFFF, "LOGICAL UNIT COMMUNICATION FAILURE"},
++    { 0x040801, 0xFFFFFF, "LOGICAL UNIT COMMUNICATION TIME-OUT"},
++    { 0x040802, 0xFFFFFF, "LOGICAL UNIT COMMUNICATION PARITY ERROR"},
++    { 0x040803, 0xFFFFFF, "LOGICAL UNIT COMMUNICATION CRC ERROR (ULTRA-DMA/32)"},
++    { 0x040900, 0xFFFFFF, "TRACK FOLLOWING ERROR"},
++    { 0x040901, 0xFFFFFF, "TRACKING SERVO FAILURE"},
++    { 0x040902, 0xFFFFFF, "FOCUS SERVO FAILURE"},
++    { 0x040903, 0xFFFFFF, "SPINDLE SERVO FAILURE"},
++    { 0x040904, 0xFFFFFF, "HEAD SELECT FAULT"},
++    { 0x060A00, 0xFFFFFF, "ERROR LOG OVERFLOW"},
++    { 0x010B00, 0xFFFFFF, "WARNING"},
++    { 0x010B01, 0xFFFFFF, "WARNING - SPECIFIED TEMPERATURE EXCEEDED"},
++    { 0x010B02, 0xFFFFFF, "WARNING - ENCLOSURE DEGRADED"},
++    { 0x030C00, 0xFFFFFF, "WRITE ERROR"},
++    { 0x030C01, 0xFFFFFF, "WRITE ERROR - RECOVERED WITH AUTO REALLOCATION"},
++    { 0x030C02, 0xFFFFFF, "WRITE ERROR - AUTO REALLOCATION FAILED"},
++    { 0x030C03, 0xFFFFFF, "WRITE ERROR - RECOMMEND REASSIGNMENT"},
++    { 0x030C04, 0xFFFFFF, "COMPRESSION CHECK MISCOMPARE ERROR"},
++    { 0x030C05, 0xFFFFFF, "DATA EXPANSION OCCURRED DURING COMPRESSION"},
++    { 0x030C06, 0xFFFFFF, "BLOCK NOT COMPRESSIBLE"},
++    { 0x030C07, 0xFFFFFF, "WRITE ERROR - RECOVERY NEEDED"},
++    { 0x030C08, 0xFFFFFF, "WRITE ERROR - RECOVERY FAILED"},
++    { 0x030C09, 0xFFFFFF, "WRITE ERROR - LOSS OF STREAMING"},
++    { 0x010C0A, 0xFFFFFF, "WRITE ERROR - PADDING BLOCKS ADDED"},
++    { 0x000D00, 0x00FFFF, "Reserved"},
++    { 0x000E00, 0x00FFFF, "Reserved"},
++    { 0x000F00, 0x00FFFF, "Reserved"},
++    { 0x031000, 0xFFFFFF, "ID CRC OR ECC ERROR"},
++    { 0x031100, 0xFFFFFF, "UNRECOVERED READ ERROR"},
++    { 0x031101, 0xFFFFFF, "READ RETRIES EXHAUSTED"},
++    { 0x031102, 0xFFFFFF, "ERROR TOO LONG TO CORRECT"},
++    { 0x031103, 0xFFFFFF, "MULTIPLE READ ERRORS"},
++    { 0x031104, 0xFFFFFF, "UNRECOVERED READ ERROR - AUTO REALLOCATE FAILED"},
++    { 0x031105, 0xFFFFFF, "L-EC UNCORRECTABLE ERROR"},
++    { 0x031106, 0xFFFFFF, "CIRC UNRECOVERED ERROR"},
++    { 0x031107, 0xFFFFFF, "RE-SYNCHRONIZATION ERROR"},
++    { 0x031108, 0xFFFFFF, "INCOMPLETE BLOCK READ"},
++    { 0x031109, 0xFFFFFF, "NO GAP FOUND"},
++    { 0x03110A, 0xFFFFFF, "MISCORRECTED ERROR"},
++    { 0x03110B, 0xFFFFFF, "UNRECOVERED READ ERROR - RECOMMEND REASSIGNMENT"},
++    { 0x03110C, 0xFFFFFF, "UNRECOVERED READ ERROR - RECOMMEND REWRITE THE DATA"},
++    { 0x03110D, 0xFFFFFF, "DE-COMPRESSION CRC ERROR"},
++    { 0x03110E, 0xFFFFFF, "CANNOT DECOMPRESS USING DECLARED ALGORITHM"},
++    { 0x03110F, 0xFFFFFF, "ERROR READING UPC/EAN NUMBER"},
++    { 0x031110, 0xFFFFFF, "ERROR READING ISRC NUMBER"},
++    { 0x0B1111, 0xFFFFFF, "READ ERROR - LOSS OF STREAMING"},
++    { 0x031200, 0xFFFFFF, "ADDRESS MARK NOT FOUND FOR ID FIELD"},
++    { 0x031300, 0xFFFFFF, "ADDRESS MARK NOT FOUND FOR DATA FIELD"},
++    { 0x031400, 0xFFFFFF, "RECORDED ENTITY NOT FOUND"},
++    { 0x031401, 0xFFFFFF, "RECORD NOT FOUND"},
++    { 0x031402, 0xFFFFFF, "FILEMARK OR SETMARK NOT FOUND"},
++    { 0x031403, 0xFFFFFF, "END-OF-DATA NOT FOUND"},
++    { 0x031404, 0xFFFFFF, "BLOCK SEQUENCE ERROR"},
++    { 0x031405, 0xFFFFFF, "RECORD NOT FOUND - RECOMMEND REASSIGNMENT"},
++    { 0x031406, 0xFFFFFF, "RECORD NOT FOUND - DATA AUTO-REALLOCATED"},
++    { 0x041500, 0xFFFFFF, "RANDOM POSITIONING ERROR"},
++    { 0x041501, 0xFFFFFF, "MECHANICAL POSITIONING ERROR"},
++    { 0x031502, 0xFFFFFF, "POSITIONING ERROR DETECTED BY READ OF MEDIUM"},
++    { 0x031600, 0xFFFFFF, "DATA SYNCHRONIZATION MARK ERROR"},
++    { 0x031601, 0xFFFFFF, "DATA SYNC ERROR - DATA REWRITTEN"},
++    { 0x031602, 0xFFFFFF, "DATA SYNC ERROR - RECOMMEND REWRITE"},
++    { 0x031603, 0xFFFFFF, "DATA SYNC ERROR - DATA AUTO-REALLOCATED"},
++    { 0x031604, 0xFFFFFF, "DATA SYNC ERROR - RECOMMEND REASSIGNMENT"},
++    { 0x011700, 0xFFFFFF, "RECOVERED DATA WITH NO ERROR CORRECTION APPLIED"},
++    { 0x011701, 0xFFFFFF, "RECOVERED DATA WITH RETRIES"},
++    { 0x011702, 0xFFFFFF, "RECOVERED DATA WITH POSITIVE HEAD OFFSET"},
++    { 0x011703, 0xFFFFFF, "RECOVERED DATA WITH NEGATIVE HEAD OFFSET"},
++    { 0x011704, 0xFFFFFF, "RECOVERED DATA WITH RETRIES AND/OR CIRC APPLIED"},
++    { 0x011705, 0xFFFFFF, "RECOVERED DATA USING PREVIOUS SECTOR ID"},
++    { 0x011706, 0xFFFFFF, "RECOVERED DATA WITHOUT ECC - DATA AUTO-REALLOCATED"},
++    { 0x011707, 0xFFFFFF, "RECOVERED DATA WITHOUT ECC - RECOMMEND REASSIGNMENT"},
++    { 0x011708, 0xFFFFFF, "RECOVERED DATA WITHOUT ECC - RECOMMEND REWRITE"},
++    { 0x011709, 0xFFFFFF, "RECOVERED DATA WITHOUT ECC - DATA REWRITTEN"},
++    { 0x011800, 0xFFFFFF, "RECOVERED DATA WITH ERROR CORRECTION APPLIED"},
++    { 0x011801, 0xFFFFFF, "RECOVERED DATA WITH ERROR CORR. & RETRIES APPLIED"},
++    { 0x011802, 0xFFFFFF, "RECOVERED DATA - DATA AUTO-REALLOCATED"},
++    { 0x011803, 0xFFFFFF, "RECOVERED DATA WITH CIRC"},
++    { 0x011804, 0xFFFFFF, "RECOVERED DATA WITH L-EC"},
++    { 0x011805, 0xFFFFFF, "RECOVERED DATA - RECOMMEND REASSIGNMENT"},
++    { 0x011806, 0xFFFFFF, "RECOVERED DATA - RECOMMEND REWRITE"},
++    { 0x011807, 0xFFFFFF, "RECOVERED DATA WITH ECC - DATA REWRITTEN"},
++    { 0x011808, 0xFFFFFF, "RECOVERED DATA WITH LINKING"},
++    { 0x031900, 0xFFFFFF, "DEFECT LIST ERROR"},
++    { 0x031901, 0xFFFFFF, "DEFECT LIST NOT AVAILABLE"},
++    { 0x031902, 0xFFFFFF, "DEFECT LIST ERROR IN PRIMARY LIST"},
++    { 0x031903, 0xFFFFFF, "DEFECT LIST ERROR IN GROWN LIST"},
++    { 0x051A00, 0xFFFFFF, "PARAMETER LIST LENGTH ERROR"},
++    { 0x041B00, 0xFFFFFF, "SYNCHRONOUS DATA TRANSFER ERROR"},
++    { 0x041C00, 0xFFFFFF, "DEFECT LIST NOT FOUND"},
++    { 0x041C01, 0xFFFFFF, "PRIMARY DEFECT LIST NOT FOUND"},
++    { 0x041C02, 0xFFFFFF, "GROWN DEFECT LIST NOT FOUND"},
++    { 0x0E1D00, 0xFFFFFF, "MISCOMPARE DURING VERIFY OPERATION"},
++    { 0x011E00, 0xFFFFFF, "RECOVERED ID WITH ECC CORRECTION"},
++    { 0x031F00, 0xFFFFFF, "PARTIAL DEFECT LIST TRANSFER"},
++    { 0x052000, 0xFFFFFF, "INVALID COMMAND OPERATION CODE"},
++    { 0x052100, 0xFFFFFF, "LOGICAL BLOCK ADDRESS OUT OF RANGE"},
++    { 0x052101, 0xFFFFFF, "INVALID ELEMENT ADDRESS"},
++    { 0x052102, 0xFFFFFF, "INVALID ADDRESS FOR WRITE"},
++    { 0x052200, 0xFFFFFF, "ILLEGAL FUNCTION (USE 20 00, 24 00, OR 26 00)"},
++    { 0x002300, 0x00FFFF, "Reserved"},
++    { 0x052400, 0xFFFFFF, "INVALID FIELD IN CDB"},
++    { 0x052500, 0xFFFFFF, "LOGICAL UNIT NOT SUPPORTED"},
++    { 0x052600, 0xFFFFFF, "INVALID FIELD IN PARAMETER LIST"},
++    { 0x052601, 0xFFFFFF, "PARAMETER NOT SUPPORTED"},
++    { 0x052602, 0xFFFFFF, "PARAMETER VALUE INVALID"},
++    { 0x052603, 0xFFFFFF, "THRESHOLD PARAMETERS NOT SUPPORTED"},
++    { 0x052604, 0xFFFFFF, "INVALID RELEASE OF ACTIVE PERSISTENT RESERVATION"},
++    { 0x072700, 0xFFFFFF, "WRITE PROTECTED"},
++    { 0x072701, 0xFFFFFF, "HARDWARE WRITE PROTECTED"},
++    { 0x072702, 0xFFFFFF, "LOGICAL UNIT SOFTWARE WRITE PROTECTED"},
++    { 0x072703, 0xFFFFFF, "ASSOCIATED WRITE PROTECT"},
++    { 0x072704, 0xFFFFFF, "PERSISTENT WRITE PROTECT"},
++    { 0x072705, 0xFFFFFF, "PERMANENT WRITE PROTECT"},
++    { 0x072706, 0xFFFFFF, "CONDITIONAL WRITE PROTECT"},
++    { 0x062800, 0xFFFFFF, "NOT READY TO READY CHANGE, MEDIUM MAY HAVE CHANGED"},
++    { 0x062801, 0xFFFFFF, "IMPORT OR EXPORT ELEMENT ACCESSED"},
++    { 0x062900, 0xFFFFFF, "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED"},
++    { 0x062901, 0xFFFFFF, "POWER ON OCCURRED"},
++    { 0x062902, 0xFFFFFF, "SCSI BUS RESET OCCURRED"},
++    { 0x062903, 0xFFFFFF, "BUS DEVICE RESET FUNCTION OCCURRED"},
++    { 0x062904, 0xFFFFFF, "DEVICE INTERNAL RESET"},
++    { 0x062A00, 0xFFFFFF, "PARAMETERS CHANGED"},
++    { 0x062A01, 0xFFFFFF, "MODE PARAMETERS CHANGED"},
++    { 0x062A02, 0xFFFFFF, "LOG PARAMETERS CHANGED"},
++    { 0x062A03, 0xFFFFFF, "RESERVATIONS PREEMPTED"},
++    { 0x052B00, 0xFFFFFF, "COPY CANNOT EXECUTE SINCE HOST CANNOT DISCONNECT"},
++    { 0x052C00, 0xFFFFFF, "COMMAND SEQUENCE ERROR"},
++    { 0x052C01, 0xFFFFFF, "TOO MANY WINDOWS SPECIFIED"},
++    { 0x052C02, 0xFFFFFF, "INVALID COMBINATION OF WINDOWS SPECIFIED"},
++    { 0x052C03, 0xFFFFFF, "CURRENT PROGRAM AREA IS NOT EMPTY"},
++    { 0x052C04, 0xFFFFFF, "CURRENT PROGRAM AREA IS EMPTY"},
++    { 0x052C05, 0xFFFFFF, "PERSISTENT PREVENT CONFLICT"},
++    { 0x032D00, 0xFFFFFF, "OVERWRITE ERROR ON UPDATE IN PLACE"},
++    { 0x062E00, 0xFFFFFF, "INSUFFICIENT TIME FOR OPERATION"},
++    { 0x062F00, 0xFFFFFF, "COMMANDS CLEARED BY ANOTHER INITIATOR"},
++    { 0x023000, 0xFFFFFF, "INCOMPATIBLE MEDIUM INSTALLED"},
++    { 0x023001, 0xFFFFFF, "CANNOT READ MEDIUM - UNKNOWN FORMAT"},
++    { 0x023002, 0xFFFFFF, "CANNOT READ MEDIUM - INCOMPATIBLE FORMAT"},
++    { 0x053002, 0xFFFFFF, "CANNOT READ MEDIUM - INCOMPATIBLE FORMAT"},
++    { 0x023003, 0xFFFFFF, "CLEANING CARTRIDGE INSTALLED"},
++    { 0x053004, 0xFFFFFF, "CANNOT WRITE MEDIUM - UNKNOWN FORMAT"},
++    { 0x053005, 0xFFFFFF, "CANNOT WRITE MEDIUM - INCOMPATIBLE FORMAT"},
++    { 0x053006, 0xFFFFFF, "CANNOT FORMAT MEDIUM - INCOMPATIBLE MEDIUM"},
++    { 0x023007, 0xFFFFFF, "CLEANING FAILURE"},
++    { 0x053008, 0xFFFFFF, "CANNOT WRITE - APPLICATION CODE MISMATCH"},
++    { 0x053009, 0xFFFFFF, "CURRENT SESSION NOT FIXATED FOR APPEND"},
++    { 0x033100, 0xFFFFFF, "MEDIUM FORMAT CORRUPTED"},
++    { 0x033101, 0xFFFFFF, "FORMAT COMMAND FAILED"},
++    { 0x033102, 0xFFFFFF, "ZONED FORMATTING FAILED DUE TO SPARE LINKING"},
++    { 0x033200, 0xFFFFFF, "NO DEFECT SPARE LOCATION AVAILABLE"},
++    { 0x033201, 0xFFFFFF, "DEFECT LIST UPDATE FAILURE"},
++    { 0x033300, 0xFFFFFF, "TAPE LENGTH ERROR"},
++    { 0x043400, 0xFFFFFF, "ENCLOSURE FAILURE"},
++    { 0x043500, 0xFFFFFF, "ENCLOSURE SERVICES FAILURE"},
++    { 0x053501, 0xFFFFFF, "UNSUPPORTED ENCLOSURE FUNCTION"},
++    { 0x023502, 0xFFFFFF, "ENCLOSURE SERVICES UNAVAILABLE"},
++    { 0x043503, 0xFFFFFF, "ENCLOSURE SERVICES TRANSFER FAILURE"},
++    { 0x053504, 0xFFFFFF, "ENCLOSURE SERVICES TRANSFER REFUSED"},
++    { 0x033600, 0xFFFFFF, "RIBBON, INK, OR TONER FAILURE"},
++    { 0x013700, 0xFFFFFF, "ROUNDED PARAMETER"},
++    { 0x053800, 0xFFFFFF, "Reserved"},
++    { 0x053900, 0xFFFFFF, "SAVING PARAMETERS NOT SUPPORTED"},
++    { 0x023A00, 0xFFFFFF, "MEDIUM NOT PRESENT"},
++    { 0x023A01, 0xFFFFFF, "MEDIUM NOT PRESENT - TRAY CLOSED"},
++    { 0x023A02, 0xFFFFFF, "MEDIUM NOT PRESENT - TRAY OPEN"},
++    { 0x033B00, 0xFFFFFF, "SEQUENTIAL POSITIONING ERROR"},
++    { 0x033B01, 0xFFFFFF, "TAPE POSITION ERROR AT BEGINNING-OF-MEDIUM"},
++    { 0x033B02, 0xFFFFFF, "TAPE POSITION ERROR AT END-OF-MEDIUM"},
++    { 0x033B03, 0xFFFFFF, "TAPE OR ELECTRONIC VERTICAL FORMS UNIT NOT READY"},
++    { 0x043B04, 0xFFFFFF, "SLEW FAILURE"},
++    { 0x043B05, 0xFFFFFF, "PAPER JAM"},
++    { 0x033B06, 0xFFFFFF, "FAILED TO SENSE TOP-OF-FORM"},
++    { 0x033B07, 0xFFFFFF, "FAILED TO SENSE BOTTOM-OF-FORM"},
++    { 0x033B08, 0xFFFFFF, "REPOSITION ERROR"},
++    { 0x033B09, 0xFFFFFF, "READ PAST END OF MEDIUM"},
++    { 0x033B0A, 0xFFFFFF, "READ PAST BEGINNING OF MEDIUM"},
++    { 0x033B0B, 0xFFFFFF, "POSITION PAST END OF MEDIUM"},
++    { 0x033B0C, 0xFFFFFF, "POSITION PAST BEGINNING OF MEDIUM"},
++    { 0x053B0D, 0xFFFFFF, "MEDIUM DESTINATION ELEMENT FULL"},
++    { 0x053B0E, 0xFFFFFF, "MEDIUM SOURCE ELEMENT EMPTY"},
++    { 0x063B0F, 0xFFFFFF, "END OF MEDIUM REACHED"},
++    { 0x023B11, 0xFFFFFF, "MEDIUM MAGAZINE NOT ACCESSIBLE"},
++    { 0x063B12, 0xFFFFFF, "MEDIUM MAGAZINE REMOVED"},
++    { 0x063B13, 0xFFFFFF, "MEDIUM MAGAZINE INSERTED"},
++    { 0x063B14, 0xFFFFFF, "MEDIUM MAGAZINE LOCKED"},
++    { 0x063B15, 0xFFFFFF, "MEDIUM MAGAZINE UNLOCKED"},
++    { 0x043B16, 0xFFFFFF, "MECHANICAL POSITIONING OR CHANGER ERROR"},
++    { 0x003C00, 0x00FFFF, "Reserved"},
++    { 0x053D00, 0xFFFFFF, "INVALID BITS IN IDENTIFY MESSAGE"},
++    { 0x023E00, 0xFFFFFF, "LOGICAL UNIT HAS NOT SELF-CONFIGURED YET"},
++    { 0x043E01, 0xFFFFFF, "LOGICAL UNIT FAILURE"},
++    { 0x043E02, 0xFFFFFF, "TIMEOUT ON LOGICAL UNIT"},
++    { 0x063F00, 0xFFFFFF, "TARGET OPERATING CONDITIONS HAVE CHANGED"},
++    { 0x063F01, 0xFFFFFF, "MICROCODE HAS BEEN CHANGED"},
++    { 0x063F02, 0xFFFFFF, "CHANGED OPERATING DEFINITION"},
++    { 0x063F03, 0xFFFFFF, "INQUIRY DATA HAS CHANGED"},
++    { 0x044000, 0xFFFFFF, "RAM FAILURE (SHOULD USE 40 NN)"},
++    { 0x044000, 0xFFFF80, "DIAGNOSTIC FAILURE ON COMPONENT NN (80H-FFH)"},
++    { 0x044100, 0xFFFFFF, "DATA PATH FAILURE (SHOULD USE 40 NN)"},
++    { 0x044200, 0xFFFFFF, "POWER-ON OR SELF-TEST FAILURE (SHOULD USE 40 NN)"},
++    { 0x054300, 0xFFFFFF, "MESSAGE ERROR"},
++    { 0x044400, 0xFFFFFF, "INTERNAL TARGET FAILURE"},
++    { 0x0b4500, 0xFFFFFF, "SELECT OR RESELECT FAILURE"},
++    { 0x044600, 0xFFFFFF, "UNSUCCESSFUL SOFT RESET"},
++    { 0x044700, 0xFFFFFF, "SCSI PARITY ERROR"},
++    { 0x0b4800, 0xFFFFFF, "INITIATOR DETECTED ERROR MESSAGE RECEIVED"},
++    { 0x0b4900, 0xFFFFFF, "INVALID MESSAGE ERROR"},
++    { 0x044A00, 0xFFFFFF, "COMMAND PHASE ERROR"},
++    { 0x044B00, 0xFFFFFF, "DATA PHASE ERROR"},
++    { 0x044C00, 0xFFFFFF, "LOGICAL UNIT FAILED SELF-CONFIGURATION"},
++    { 0x0b4D00, 0xFFFF00, "TAGGED OVERLAPPED COMMANDS (NN = QUEUE TAG)"},
++    { 0x0B4E00, 0xFFFFFF, "OVERLAPPED COMMANDS ATTEMPTED"},
++    { 0x004F00, 0x00FFFF, "Reserved"},
++    { 0x005000, 0x00FFFF, "WRITE APPEND ERROR"},
++    { 0x005001, 0x00FFFF, "WRITE APPEND POSITION ERROR"},
++    { 0x005002, 0x00FFFF, "POSITION ERROR RELATED TO TIMING"},
++    { 0x035100, 0xFFFFFF, "ERASE FAILURE"},
++    { 0x035101, 0xFFFFFF, "ERASE FAILURE - Incomplete erase operation detected"},
++    { 0x035200, 0xFFFFFF, "CARTRIDGE FAULT"},
++    { 0x045300, 0xFFFFFF, "MEDIA LOAD OR EJECT FAILED"},
++    { 0x005301, 0x00FFFF, "UNLOAD TAPE FAILURE"},
++    { 0x025302, 0xFFFFFF, "MEDIUM REMOVAL PREVENTED"},
++    { 0x055302, 0xFFFFFF, "MEDIUM REMOVAL PREVENTED"},
++    { 0x005400, 0x00FFFF, "SCSI TO HOST SYSTEM INTERFACE FAILURE"},
++    { 0x055500, 0xFFFFFF, "SYSTEM RESOURCE FAILURE"},
++    { 0x005501, 0x00FFFF, "SYSTEM BUFFER FULL"},
++    { 0x005600, 0x00FFFF, "Reserved"},
++    { 0x035700, 0xFFFFFF, "UNABLE TO RECOVER TABLE-OF-CONTENTS"},
++    { 0x005800, 0x00FFFF, "GENERATION DOES NOT EXIST"},
++    { 0x005900, 0x00FFFF, "UPDATED BLOCK READ"},
++    { 0x065A00, 0xFFFFFF, "OPERATOR REQUEST OR STATE CHANGE INPUT"},
++    { 0x065A01, 0xFFFFFF, "OPERATOR MEDIUM REMOVAL REQUEST"},
++    { 0x065A02, 0xFFFFFF, "OPERATOR SELECTED WRITE PROTECT"},
++    { 0x065A03, 0xFFFFFF, "OPERATOR SELECTED WRITE PERMIT"},
++    { 0x065B00, 0xFFFFFF, "LOG EXCEPTION"},
++    { 0x065B01, 0xFFFFFF, "THRESHOLD CONDITION MET"},
++    { 0x065B02, 0xFFFFFF, "LOG COUNTER AT MAXIMUM"},
++    { 0x065B03, 0xFFFFFF, "LOG LIST CODES EXHAUSTED"},
++    { 0x065C00, 0xFFFFFF, "RPL STATUS CHANGE"},
++    { 0x065C01, 0xFFFFFF, "SPINDLES SYNCHRONIZED"},
++    { 0x035C02, 0xFFFFFF, "SPINDLES NOT SYNCHRONIZED"},
++    { 0x015D00, 0xFFFFFF, "FAILURE PREDICTION THRESHOLD EXCEEDED - Predicted Logical Unit Failure"},
++    { 0x015D01, 0xFFFFFF, "FAILURE PREDICTION THRESHOLD EXCEEDED - Predicted Media Failure"},
++    { 0x015D03, 0xFFFFFF, "FAILURE PREDICTION THRESHOLD EXCEEDED - Predicted Spare Area Exhaustion"},
++    { 0x015DFF, 0xFFFFFF, "FAILURE PREDICTION THRESHOLD EXCEEDED (FALSE)"},
++    { 0x065E00, 0xFFFFFF, "LOW POWER CONDITION ON"},
++    { 0x065E01, 0xFFFFFF, "IDLE CONDITION ACTIVATED BY TIMER"},
++    { 0x065E02, 0xFFFFFF, "STANDBY CONDITION ACTIVATED BY TIMER"},
++    { 0x065E03, 0xFFFFFF, "IDLE CONDITION ACTIVATED BY COMMAND"},
++    { 0x065E04, 0xFFFFFF, "STANDBY CONDITION ACTIVATED BY COMMAND"},
++    { 0x005F00, 0x00FFFF, "Reserved"},
++    { 0x046000, 0xFFFFFF, "LAMP FAILURE"},
++    { 0x036100, 0xFFFFFF, "VIDEO ACQUISITION ERROR"},
++    { 0x036101, 0xFFFFFF, "UNABLE TO ACQUIRE VIDEO"},
++    { 0x036102, 0xFFFFFF, "OUT OF FOCUS"},
++    { 0x046200, 0xFFFFFF, "SCAN HEAD POSITIONING ERROR"},
++    { 0x056300, 0xFFFFFF, "END OF USER AREA ENCOUNTERED ON THIS TRACK"},
++    { 0x056301, 0xFFFFFF, "PACKET DOES NOT FIT IN AVAILABLE SPACE"},
++    { 0x056400, 0xFFFFFF, "ILLEGAL MODE FOR THIS TRACK"},
++    { 0x056401, 0xFFFFFF, "INVALID PACKET SIZE"},
++    { 0x046500, 0xFFFFFF, "VOLTAGE FAULT"},
++    { 0x046600, 0xFFFFFF, "AUTOMATIC DOCUMENT FEEDER COVER UP"},
++    { 0x046601, 0xFFFFFF, "AUTOMATIC DOCUMENT FEEDER LIFT UP"},
++    { 0x046602, 0xFFFFFF, "DOCUMENT JAM IN AUTOMATIC DOCUMENT FEEDER"},
++    { 0x046603, 0xFFFFFF, "DOCUMENT MISS FEED AUTOMATIC IN DOCUMENT FEEDER"},
++    { 0x046700, 0xFFFFFF, "CONFIGURATION FAILURE"},
++    { 0x046701, 0xFFFFFF, "CONFIGURATION OF INCAPABLE LOGICAL UNITS FAILED"},
++    { 0x046702, 0xFFFFFF, "ADD LOGICAL UNIT FAILED"},
++    { 0x046703, 0xFFFFFF, "MODIFICATION OF LOGICAL UNIT FAILED"},
++    { 0x046704, 0xFFFFFF, "EXCHANGE OF LOGICAL UNIT FAILED"},
++    { 0x046705, 0xFFFFFF, "REMOVE OF LOGICAL UNIT FAILED"},
++    { 0x046706, 0xFFFFFF, "ATTACHMENT OF LOGICAL UNIT FAILED"},
++    { 0x046707, 0xFFFFFF, "CREATION OF LOGICAL UNIT FAILED"},
++    { 0x026800, 0xFFFFFF, "LOGICAL UNIT NOT CONFIGURED"},
++    { 0x046900, 0xFFFFFF, "DATA LOSS ON LOGICAL UNIT"},
++    { 0x046901, 0xFFFFFF, "MULTIPLE LOGICAL UNIT FAILURES"},
++    { 0x046902, 0xFFFFFF, "A PARITY/DATA MISMATCH"},
++    { 0x016A00, 0xFFFFFF, "INFORMATIONAL, REFER TO LOG"},
++    { 0x066B00, 0xFFFFFF, "STATE CHANGE HAS OCCURRED"},
++    { 0x066B01, 0xFFFFFF, "REDUNDANCY LEVEL GOT BETTER"},
++    { 0x066B02, 0xFFFFFF, "REDUNDANCY LEVEL GOT WORSE"},
++    { 0x036C00, 0xFFFFFF, "REBUILD FAILURE OCCURRED"},
++    { 0x036D00, 0xFFFFFF, "RECALCULATE FAILURE OCCURRED"},
++    { 0x046E00, 0xFFFFFF, "COMMAND TO LOGICAL UNIT FAILED"},
++    { 0x056F00, 0xFFFFFF, "COPY PROTECTION KEY EXCHANGE FAILURE - AUTHENTICATION FAILURE"},
++    { 0x056F01, 0xFFFFFF, "COPY PROTECTION KEY EXCHANGE FAILURE - KEY NOT PRESENT"},
++    { 0x056F02, 0xFFFFFF, "COPY PROTECTION KEY EXCHANGE FAILURE - KEY NOT ESTABLISHED"},
++    { 0x056F03, 0xFFFFFF, "READ OF SCRAMBLED SECTOR WITHOUT AUTHENTICATION"},
++    { 0x056F04, 0xFFFFFF, "MEDIA REGION CODE IS MISMATCHED TO LOGICAL UNIT REGION"},
++    { 0x056F05, 0xFFFFFF, "DRIVE REGION MUST BE PERMANENT/REGION RESET COUNT ERROR"},
++    { 0x037000, 0xFFFF00, "DECOMPRESSION EXCEPTION SHORT ALGORITHM ID OF NN"},
++    { 0x037100, 0xFFFFFF, "DECOMPRESSION EXCEPTION LONG ALGORITHM ID"},
++    { 0x037200, 0xFFFFFF, "SESSION FIXATION ERROR"},
++    { 0x037201, 0xFFFFFF, "SESSION FIXATION ERROR WRITING LEAD-IN"},
++    { 0x037202, 0xFFFFFF, "SESSION FIXATION ERROR WRITING LEAD-OUT"},
++    { 0x057203, 0xFFFFFF, "SESSION FIXATION ERROR - INCOMPLETE TRACK IN SESSION"},
++    { 0x057204, 0xFFFFFF, "EMPTY OR PARTIALLY WRITTEN RESERVED TRACK"},
++    { 0x057205, 0xFFFFFF, "NO MORE RZONE RESERVATIONS ARE ALLOWED"},
++    { 0x037300, 0xFFFFFF, "CD CONTROL ERROR"},
++    { 0x017301, 0xFFFFFF, "POWER CALIBRATION AREA ALMOST FULL"},
++    { 0x037302, 0xFFFFFF, "POWER CALIBRATION AREA IS FULL"},
++    { 0x037303, 0xFFFFFF, "POWER CALIBRATION AREA ERROR"},
++    { 0x037304, 0xFFFFFF, "PROGRAM MEMORY AREA/RMA UPDATE FAILURE"},
++    { 0x037305, 0xFFFFFF, "PROGRAM MEMORY AREA/RMA IS FULL"},
++    { 0x017306, 0xFFFFFF, "PROGRAM MEMORY AREA/RMA IS (almost) FULL"},
++    { 0x008000, 0x008000, "VENDOR SPECIFIC"},
++    { 0x000000, 0x000000, "Unrecognised sense data"}
 +};
 +
-+static const char *atapi_ascq_to_str(int ascq)
++static const char *atapi_sense_to_str(int key, int asc, int ascq)
 +{
 +    int i;
++    unsigned long code;
++
++    code = ((key & 0xFF) << 16) | ((asc & 0xFF) << 8) | (ascq & 0xFF);
 +
-+    for (i = 0; sense_data_texts[i].text; ++i)
-+        if (sense_data_texts[i].asc_ascq == ascq)
++    for (i = 0; 1; ++i)
++      if ((code & sense_data_texts[i].mask) == sense_data_texts[i].code)
 +            return sense_data_texts[i].text;
-+    return 0;
 +}
 +
++
 +static void ide_atapi_pt_set_error(IDEState *s, int sense_key, int asc, int error)
 +{
 +    s->atapi_pt.sense.sense_key  = sense_key;
@@ -380,15 +608,51 @@ index 0000000..2f63492
 +    ide_set_irq(s);
 +}
 +
++#if 0
++static int cmd_count = 0;
++static int finish_count = 0;
++static int no_finish_count = 0;
++
 +static void ide_atapi_pt_sg_io_finished(IDEState *s)
 +{
 +    BDRVRawState *raw_state = s->bs->opaque;
 +    int read_bytes;
++    int i;
++
++    ++finish_count;
++    DEBUG_PRINTF("****  finish   (%p, u=%p, raw=%p, fd=%d, %d-%d(%d))\n",
++                 s, s->atapi_pt.cmd.usr_ptr,
++                 raw_state, raw_state->fd, cmd_count,
++                 finish_count + no_finish_count, no_finish_count);
++
++    DEBUG_PRINTF("Preread:  0x");
++    for(i = 0; i < sizeof(s->atapi_pt.cmd); ++i)
++        DEBUG_PRINTF("%02x", ((unsigned char *)&s->atapi_pt.cmd)[i]);
++    DEBUG_PRINTF("\n");
++
++#if 1
 +    read_bytes = read(raw_state->fd, &s->atapi_pt.cmd, sizeof (s->atapi_pt.cmd));
 +
++    DEBUG_PRINTF("Postread: 0x");
++    for(i = 0; i < sizeof(s->atapi_pt.cmd); ++i)
++        DEBUG_PRINTF("%02x", ((unsigned char *)&s->atapi_pt.cmd)[i]);
++    DEBUG_PRINTF("\n");
++#else
++    DEBUG_PRINTF("Postread: 0x");
++    for(i = 0; i < sizeof (s->atapi_pt.cmd); ++i) {
++        read(raw_state->fd, &((unsigned char *)&s->atapi_pt.cmd)[i], 1);
++        DEBUG_PRINTF("%02x", ((unsigned char *)&s->atapi_pt.cmd)[i]);
++    }
++    DEBUG_PRINTF("\n");
++    read_bytes = i;
++#endif
++
++    //    DEBUG_PRINTF("finish read\n");
++
 +    if (read_bytes != sizeof (s->atapi_pt.cmd))
 +    {
 +        ide_atapi_pt_error(s);
++        s->atapi_pt.cmd_sent = NULL;
 +        return;
 +    }
 +
@@ -407,16 +671,31 @@ index 0000000..2f63492
 +                     s->atapi_pt.sense.error_code,
 +                     s->atapi_pt.sense.asc,
 +                     s->atapi_pt.sense.ascq,
-+                     atapi_ascq_to_str(s->atapi_pt.sense.ascq),
++                     atapi_sense_to_str(s->atapi_pt.sense.sense_key,
++                                        s->atapi_pt.sense.asc,
++                                        s->atapi_pt.sense.ascq),
 +                     errno,
 +                     strerror(errno) ? : "(null)",
 +                     s->atapi_pt.cmd.driver_status,
 +                     s->atapi_pt.cmd.transport_status,
 +                     s->atapi_pt.cmd.device_status);
 +        ide_atapi_pt_error(s);
++        s->atapi_pt.cmd_sent = NULL;
++        return;
++    }
++    if(s->atapi_pt.cmd_sent == NULL) {
++        static int null_count = 0;
++        ++null_count;
++        DEBUG_PRINTF("\e[1;31m%s called with cmd_sent = NULL %d time%c\e[m\n",
++                     __FUNCTION__, null_count, (null_count == 1) ? ' ' : 's');
++        ide_atapi_cmd_ok(s);
++        s->atapi_pt.cmd_sent = NULL;
 +        return;
 +    }
++    //    DEBUG_PRINTF("finish sent\n");
 +    s->atapi_pt.cmd_sent(s);
++    s->atapi_pt.cmd_sent = NULL;
++    DEBUG_PRINTF("****  finished (%p)\n", s);
 +}
 +
 +#define ATAPI_PT_SEND_PACKET                                            \
@@ -460,7 +739,9 @@ index 0000000..2f63492
 +    i = dma_buf_rw(bm, 0);
 +    ide_atapi_pt_read_finish(s);
 +}
++#endif
 +
++#if 0
 +static void ide_atapi_pt_wcmd(IDEState *s)
 +{
 +    if (s->atapi_dma)
@@ -487,6 +768,7 @@ index 0000000..2f63492
 +    ide_set_irq(s);
 +    return;
 +}
++#endif
 +
 +static void ide_atapi_pt_read_format_capacities_sent(IDEState *s)
 +{
@@ -518,9 +800,6 @@ index 0000000..2f63492
 +        assert(0);
 +        break;
 +    }
-+    printf("[reply] size: %d, din_resid: %d, max_in:%d, response_len: %d\n",
-+           size, s->atapi_pt.cmd.din_resid, s->atapi_pt.cmd.din_xfer_len,
-+           s->atapi_pt.cmd.response_len);
 +    ide_atapi_cmd_reply(s, size, s->atapi_pt.cmd.din_xfer_len);
 +}
 +
@@ -645,9 +924,13 @@ index 0000000..2f63492
 +    return block_size;
 +}
 +
++
 +static void ide_atapi_pt_cmd(IDEState *s)
 +{
 +    struct sg_io_v4 *cmd = &s->atapi_pt.cmd;
++    int r;
++    int command;
++    BDRVRawState *raw_state = s->bs->opaque;
 +
 +    memset(cmd, 0, sizeof (*cmd));
 +    memcpy(s->atapi_pt.request, s->io_buffer, ATAPI_PACKET_SIZE);
@@ -665,6 +948,11 @@ index 0000000..2f63492
 +    s->atapi_pt.reply_size_offset = 0;
 +    s->atapi_pt.reply_size_len    = 0;
 +
++    cmd->din_xferp = (__u64)s->io_buffer;
++    cmd->dout_xferp = (__u64)(s->io_buffer + ATAPI_PACKET_SIZE);
++    s->atapi_pt.cmd_sent = ide_atapi_cmd_ok;
++    command = s->io_buffer[0];
++
 +    switch (s->io_buffer[0])
 +    {
 +        /*******************/
@@ -694,9 +982,7 @@ index 0000000..2f63492
 +    simple_cmd:
 +        CHECK_SAME_VALUE(s->lcyl, 0);
 +        CHECK_SAME_VALUE(s->hcyl, 0);
-+        s->atapi_pt.cmd_sent = ide_atapi_cmd_ok;
-+        ATAPI_PT_SEND_PACKET;
-+        return;
++        break;
 +
 +        /******************/
 +        /* WRITE COMMANDS */
@@ -705,17 +991,25 @@ index 0000000..2f63492
 +    case GPCMD_WRITE_10:
 +    case GPCMD_WRITE_AND_VERIFY_10:
 +        cmd->dout_xfer_len = ube16_to_cpu(s->io_buffer + 7) * CD_FRAMESIZE;
++
++        DEBUG_PRINTF("Write (%s) %d bytes\n", atapi_cmd_to_str(command),
++                     cmd->dout_xfer_len);
++
 +        if (cmd->dout_xfer_len == 0)
 +            goto simple_cmd;
-+        ide_atapi_pt_wcmd(s);
-+        return;
++        break;
 +
 +    case GPCMD_WRITE_12:
 +        cmd->dout_xfer_len = ube32_to_cpu(s->io_buffer + 6);
++
++        DEBUG_PRINTF("Write (%s) %d bytes\n", atapi_cmd_to_str(command),
++                     cmd->dout_xfer_len);
++
 +        if (cmd->dout_xfer_len == 0)
 +            goto simple_cmd;
-+        ide_atapi_pt_wcmd(s);
-+        return;
++        //        ide_atapi_pt_wcmd(s);
++        //        return;
++        break;
 +
 +    case GPCMD_WRITE_BUFFER:
 +    {
@@ -742,71 +1036,115 @@ index 0000000..2f63492
 +            goto illegal_request;
 +        }
 +
-+        ide_atapi_pt_wcmd(s);
-+        return;
++
++        DEBUG_PRINTF("Write (%s) %d bytes\n", atapi_cmd_to_str(command),
++                     cmd->dout_xfer_len);
++
++        //        ide_atapi_pt_wcmd(s);
++        //        return;
++        break;
 +    }
 +
 +    case GPCMD_SEND_CUE_SHEET:
 +        cmd->dout_xfer_len = ube24_to_cpu(s->io_buffer + 6);
++
++        DEBUG_PRINTF("Write (%s) %d bytes\n", atapi_cmd_to_str(command),
++                     cmd->dout_xfer_len);
++
 +        if (cmd->dout_xfer_len == 0)
 +            goto simple_cmd;
-+        ide_atapi_pt_wcmd(s);
-+        return;
++        //        ide_atapi_pt_wcmd(s);
++        //        return;
++        break;
 +
 +    case GPCMD_MODE_SELECT_10:
 +        cmd->dout_xfer_len = ube16_to_cpu(s->io_buffer + 7);
 +        CHECK_SAME_VALUE(s->lcyl | (s->hcyl << 8), cmd->dout_xfer_len);
++
++        DEBUG_PRINTF("Mode select 10  %d bytes\n", cmd->dout_xfer_len);
++        {
++            int i;
++            DEBUG_PRINTF("0x");
++            for(i = 0; i < 12; ++i)
++                DEBUG_PRINTF("%02x ", s->io_buffer[i]);
++            DEBUG_PRINTF("\n0x");
++            for(i = 0; i < cmd->dout_xfer_len; ++i)
++                DEBUG_PRINTF("%02x ", s->io_buffer[i + 12]);
++            DEBUG_PRINTF("\n");
++        }
++
 +        if (cmd->dout_xfer_len == 0)
 +            goto simple_cmd;
-+        ide_atapi_pt_wcmd(s);
-+        return;
++        //        ide_atapi_pt_wcmd(s);
++        //        return;
++        break;
 +
 +    case GPCMD_SEND_KEY:
 +    case GPCMD_SEND_EVENT:
 +        cmd->dout_xfer_len = ube16_to_cpu(s->io_buffer + 8);
++
++        DEBUG_PRINTF("Write (%s) %d bytes\n", atapi_cmd_to_str(command),
++                     cmd->dout_xfer_len);
++
 +        if (cmd->dout_xfer_len == 0)
 +            goto simple_cmd;
-+        ide_atapi_pt_wcmd(s);
-+        return;
++        //        ide_atapi_pt_wcmd(s);
++        //        return;
++        break;
 +
 +    case GPCMD_SEND_OPC:
 +        cmd->dout_xfer_len = ube16_to_cpu(s->io_buffer + 7) << 3;
 +        CHECK_SAME_VALUE(s->lcyl | (s->hcyl << 8), cmd->dout_xfer_len);
++
++        DEBUG_PRINTF("Write (%s) %d bytes\n", atapi_cmd_to_str(command),
++                     cmd->dout_xfer_len);
++
 +        if (cmd->dout_xfer_len == 0)
 +            goto simple_cmd;
-+        ide_atapi_pt_wcmd(s);
-+        return;
++        //        ide_atapi_pt_wcmd(s);
++        //        return;
++        break;
 +
 +    case GPCMD_SET_STREAMING:
 +        cmd->dout_xfer_len = ube16_to_cpu(s->io_buffer + 9);
++
++        DEBUG_PRINTF("Write (%s) %d bytes\n", atapi_cmd_to_str(command),
++                     cmd->dout_xfer_len);
++
 +        if (cmd->dout_xfer_len == 0)
 +            goto simple_cmd;
-+        ide_atapi_pt_wcmd(s);
-+        return;
++        //        ide_atapi_pt_wcmd(s);
++        //        return;
++        break;
 +
 +    case GPCMD_FORMAT_UNIT:
 +        cmd->dout_xfer_len = 12;
-+        ide_atapi_pt_wcmd(s);
-+        return;
++
++        DEBUG_PRINTF("Write (%s) %d bytes\n", atapi_cmd_to_str(command),
++                     cmd->dout_xfer_len);
++
++        //        ide_atapi_pt_wcmd(s);
++        //        return;
++        break;
 +
 +        /*****************/
 +        /* READ COMMANDS */
 +        /*****************/
 +
 +    case GPCMD_INQUIRY:
-+        cmd->din_xferp = (__u64)s->io_buffer;
++        //        cmd->din_xferp = (__u64)s->io_buffer;
 +        cmd->din_xfer_len = s->io_buffer[4];
 +        s->atapi_pt.reply_size_init = 5;
 +        s->atapi_pt.reply_size_offset = 4;
 +        s->atapi_pt.reply_size_len = 1;
 +        s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
-+        ATAPI_PT_SEND_PACKET;
++        //        ATAPI_PT_SEND_PACKET;
 +        break;
 +
 +    case GPCMD_REQUEST_SENSE:
 +    {
 +        // send the previous sense command
-+        DEBUG_PRINTF("=== REQUEST SENSE ===\n"
++        DEBUG_PRINTF("=== REQUEST SENSE ===  "
 +                     "atapi_cmd_error: sense=0x%x asc=0x%x error=0x%x\n",
 +                     s->atapi_pt.sense.sense_key,
 +                     s->atapi_pt.sense.asc,
@@ -816,61 +1154,68 @@ index 0000000..2f63492
 +
 +        int size = 8 + s->atapi_pt.sense.add_sense_len;
 +
-+        printf("max_size: %d, add_sense_len: %d, sizeof: %lu\n",
-+               max_size, s->atapi_pt.sense.add_sense_len,
-+               sizeof (s->atapi_pt.sense));
++        //        printf("max_size: %d, add_sense_len: %d, sizeof: %lu\n",
++        //               max_size, s->atapi_pt.sense.add_sense_len,
++        //             sizeof (s->atapi_pt.sense));
 +        memcpy(s->io_buffer, &s->atapi_pt.sense, sizeof (s->atapi_pt.sense));
 +        ide_atapi_cmd_reply(s, size, max_size);
 +        return;
 +    }
++
 +    case GPCMD_READ_DVD_STRUCTURE:
 +        cmd->din_xfer_len = ube16_to_cpu(s->io_buffer + 8);
-+        cmd->din_xferp = (__u64)s->io_buffer;
++        //        cmd->din_xferp = (__u64)s->io_buffer;
 +        s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
-+        s->atapi_pt.reply_size_len = 4;
-+        ATAPI_PT_SEND_PACKET;
-+        return;
++        s->atapi_pt.reply_size_len = 2;
++        //        ATAPI_PT_SEND_PACKET;
++        //        return;
++        break;
 +
 +    case GPCMD_READ_HEADER:
 +        cmd->din_xfer_len = ube16_to_cpu(s->io_buffer + 7);
-+        cmd->din_xferp = (__u64)s->io_buffer;
++        //        cmd->din_xferp = (__u64)s->io_buffer;
 +        s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
 +        s->atapi_pt.reply_size_init = cmd->din_xfer_len;
-+        ATAPI_PT_SEND_PACKET;
-+        return;
++        //        ATAPI_PT_SEND_PACKET;
++        //        return;
++        break;
 +
 +    case GPCMD_MECHANISM_STATUS:
 +        cmd->din_xfer_len = ube16_to_cpu(s->io_buffer + 8);
-+        cmd->din_xferp = (__u64)s->io_buffer;
++        //        cmd->din_xferp = (__u64)s->io_buffer;
 +        s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
 +        s->atapi_pt.reply_size_offset = 6;
-+        ATAPI_PT_SEND_PACKET;
-+        return;
++        //        ATAPI_PT_SEND_PACKET;
++        //        return;
++        break;
 +
 +    case GPCMD_REPORT_KEY:
 +        cmd->din_xfer_len = ube16_to_cpu(s->io_buffer + 8);
-+        cmd->din_xferp = (__u64)s->io_buffer;
++        //        cmd->din_xferp = (__u64)s->io_buffer;
 +        s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
 +        s->atapi_pt.reply_size_len = 2;
 +        s->atapi_pt.reply_size_init = 2;
-+        ATAPI_PT_SEND_PACKET;
-+        return;
++        //        ATAPI_PT_SEND_PACKET;
++        //        return;
++        break;
 +
 +    case GPCMD_READ_BUFFER_CAPACITY:
 +        cmd->din_xfer_len = ube16_to_cpu(s->io_buffer + 7);
-+        cmd->din_xferp = (__u64)s->io_buffer;
++        //        cmd->din_xferp = (__u64)s->io_buffer;
 +        s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
 +        s->atapi_pt.reply_size_len = 2;
 +        s->atapi_pt.reply_size_init = 2;
-+        return;
++        //        return;
++        break;
 +
 +    case GPCMD_GET_PERFORMANCE:
 +        cmd->din_xfer_len = 8 + 8 * ube16_to_cpu(s->io_buffer + 8);
-+        cmd->din_xferp = (__u64)s->io_buffer;
++        //        cmd->din_xferp = (__u64)s->io_buffer;
 +        s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
 +        s->atapi_pt.reply_size_len = 4;
-+        ATAPI_PT_SEND_PACKET;
-+        return;
++        //        ATAPI_PT_SEND_PACKET;
++        //        return;
++        break;
 +
 +    case GPCMD_READ_10:
 +    case GPCMD_READ_12:
@@ -889,16 +1234,17 @@ index 0000000..2f63492
 +        default: assert(0);
 +        }
 +        cmd->din_xfer_len = nbblocks * blocksize;
-+        cmd->din_xferp = (__u64)s->io_buffer;
++        //        cmd->din_xferp = (__u64)s->io_buffer;
 +        s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
 +        s->atapi_pt.reply_size_init = cmd->din_xfer_len;
-+        ATAPI_PT_SEND_PACKET;
-+        return;
++        //        ATAPI_PT_SEND_PACKET;
++        //        return;
++        break;
 +    }
 +
 +    case GPCMD_READ_BUFFER:
 +        // TODO check this one is correct
-+        cmd->din_xferp = (__u64)s->io_buffer;
++        //        cmd->din_xferp = (__u64)s->io_buffer;
 +        cmd->din_xfer_len = ube24_to_cpu(s->io_buffer + 6);
 +
 +        switch (s->io_buffer[1] & 0x7)
@@ -922,49 +1268,54 @@ index 0000000..2f63492
 +            goto illegal_request;
 +        }
 +        s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
-+        ATAPI_PT_SEND_PACKET;
-+        return;
++        //        ATAPI_PT_SEND_PACKET;
++        //        return;
++        break;
 +
 +    case GPCMD_READ_CDVD_CAPACITY:
 +        cmd->din_xfer_len = 8;
 +        CHECK_SAME_VALUE(s->lcyl | (s->hcyl << 8), cmd->din_xfer_len);
-+        cmd->din_xferp = (__u64)s->io_buffer;
++        //        cmd->din_xferp = (__u64)s->io_buffer;
 +        s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
 +        s->atapi_pt.reply_size_init = cmd->din_xfer_len;
-+        ATAPI_PT_SEND_PACKET;
-+        return;
++        //        ATAPI_PT_SEND_PACKET;
++        //        return;
++        break;
 +
 +    case GPCMD_MODE_SENSE_10:
 +        cmd->din_xfer_len = ube16_to_cpu(s->io_buffer + 7);
 +        CHECK_SAME_VALUE(s->lcyl | (s->hcyl << 8), cmd->din_xfer_len);
-+        cmd->din_xferp = (__u64)s->io_buffer;
++        //        cmd->din_xferp = (__u64)s->io_buffer;
 +        s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
 +        s->atapi_pt.reply_size_len = 2;
 +        s->atapi_pt.reply_size_init = 2;
 +        //s->atapi_pt.reply_size_init = cmd->din_xfer_len;
-+        ATAPI_PT_SEND_PACKET;
-+        return;
++        //        ATAPI_PT_SEND_PACKET;
++        //        return;
++        break;
 +
 +    case GPCMD_GET_EVENT_STATUS_NOTIFICATION:
 +    case GPCMD_READ_DISC_INFO:
 +    case GPCMD_READ_TOC_PMA_ATIP:
 +    case GPCMD_READ_TRACK_RZONE_INFO:
 +        cmd->din_xfer_len = ube16_to_cpu(s->io_buffer + 7);
-+        cmd->din_xferp = (__u64)s->io_buffer;
++        //        cmd->din_xferp = (__u64)s->io_buffer;
 +        s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
 +        s->atapi_pt.reply_size_len = 2;
 +        s->atapi_pt.reply_size_init = 2;
-+        ATAPI_PT_SEND_PACKET;
-+        return;
++        //        ATAPI_PT_SEND_PACKET;
++        //        return;
++        break;
 +
 +    case GPCMD_READ_SUBCHANNEL:
 +        cmd->din_xfer_len = ube16_to_cpu(s->io_buffer + 7);
-+        cmd->din_xferp = (__u64)s->io_buffer;
++        //        cmd->din_xferp = (__u64)s->io_buffer;
 +        s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
 +        s->atapi_pt.reply_size_len = 2;
 +        s->atapi_pt.reply_size_offset = 2;
-+        ATAPI_PT_SEND_PACKET;
-+        return;
++        //        ATAPI_PT_SEND_PACKET;
++        //        return;
++        break;
 +
 +    case GPCMD_READ_CD:
 +    {
@@ -974,11 +1325,12 @@ index 0000000..2f63492
 +        int block_size = ide_atapi_pt_read_cd_block_size(s->io_buffer);
 +
 +        cmd->din_xfer_len = block_count * block_size;
-+        cmd->din_xferp = (__u64)s->io_buffer;
++        //        cmd->din_xferp = (__u64)s->io_buffer;
 +        s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
 +        s->atapi_pt.reply_size_init = cmd->din_xfer_len;
-+        ATAPI_PT_SEND_PACKET;
-+        return;
++        //        ATAPI_PT_SEND_PACKET;
++        //        return;
++        break;
 +    }
 +
 +    case GPCMD_READ_CD_MSF:
@@ -992,22 +1344,24 @@ index 0000000..2f63492
 +        int block_size = ide_atapi_pt_read_cd_block_size(s->io_buffer);
 +
 +        cmd->din_xfer_len = block_count * block_size;
-+        cmd->din_xferp = (__u64)s->io_buffer;
++        //        cmd->din_xferp = (__u64)s->io_buffer;
 +        s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
 +        s->atapi_pt.reply_size_init = cmd->din_xfer_len;
-+        ATAPI_PT_SEND_PACKET;
-+        return;
++        //        ATAPI_PT_SEND_PACKET;
++        //        return;
++        break;
 +    }
 +
 +    case GPCMD_PLAY_AUDIO_10:
 +    {
 +        int block_count = ube16_to_cpu(s->io_buffer + 7);
 +        cmd->din_xfer_len = block_count * CD_FRAMESIZE;
-+        cmd->din_xferp = (__u64)s->io_buffer;
++        //        cmd->din_xferp = (__u64)s->io_buffer;
 +        s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
 +        s->atapi_pt.reply_size_init = cmd->din_xfer_len;
-+        ATAPI_PT_SEND_PACKET;
-+        return;
++        //        ATAPI_PT_SEND_PACKET;
++        //        return;
++        break;
 +    }
 +
 +    case GPCMD_PLAY_AUDIO_MSF:
@@ -1018,37 +1372,41 @@ index 0000000..2f63492
 +            MSF_TO_FRAMES(s->io_buffer[6], s->io_buffer[7], s->io_buffer[8]);
 +        int block_count = ending_frame - starting_frame;
 +        cmd->din_xfer_len = block_count * CD_FRAMESIZE;
-+        cmd->din_xferp = (__u64)s->io_buffer;
++        //        cmd->din_xferp = (__u64)s->io_buffer;
 +        s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
 +        s->atapi_pt.reply_size_init = cmd->din_xfer_len;
-+        ATAPI_PT_SEND_PACKET;
-+        return;
++        //        ATAPI_PT_SEND_PACKET;
++        //        return;
++        break;
 +    }
 +
 +    case GPCMD_READ_FORMAT_CAPACITIES:
 +        cmd->din_xfer_len = ube16_to_cpu(s->io_buffer + 7);
-+        cmd->din_xferp = (__u64)s->io_buffer;
++        //        cmd->din_xferp = (__u64)s->io_buffer;
 +        s->atapi_pt.cmd_sent = ide_atapi_pt_read_format_capacities_sent;
-+        ATAPI_PT_SEND_PACKET;
-+        return;
++        //        ATAPI_PT_SEND_PACKET;
++        //        return;
++        break;
 +
 +    case GPCMD_GET_CONFIGURATION:
 +        cmd->din_xfer_len = ube16_to_cpu(s->io_buffer + 7);
-+        cmd->din_xferp = (__u64)s->io_buffer;
++        //        cmd->din_xferp = (__u64)s->io_buffer;
 +        s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
 +        s->atapi_pt.reply_size_init = 4;
 +        s->atapi_pt.reply_size_len = 4;
-+        ATAPI_PT_SEND_PACKET;
-+        return;
++        //        ATAPI_PT_SEND_PACKET;
++        //        return;
++        break;
 +
 +    case GPCMD_SEND_DVD_STRUCTURE:
 +        cmd->din_xfer_len = ube16_to_cpu(s->io_buffer + 8);
-+        cmd->din_xferp = (__u64)s->io_buffer;
++        //        cmd->din_xferp = (__u64)s->io_buffer;
 +        s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
 +        s->atapi_pt.reply_size_init = 2;
 +        s->atapi_pt.reply_size_len = 2;
-+        ATAPI_PT_SEND_PACKET;
-+        return;
++        //        ATAPI_PT_SEND_PACKET;
++        //        return;
++        break;
 +
 +    case 0x01: // GPMODE_R_W_ERROR_PAGE ?
 +    case 0x1a: // GPMODE_POWER_PAGE ?
@@ -1070,9 +1428,116 @@ index 0000000..2f63492
 +        exit(1);
 +        return;
 +    }
++
++
++    s->atapi_pt.sense.error_code = 0;
++    s->atapi_pt.sense.sense_key = 0;
++    s->atapi_pt.sense.asc = 0;
++    s->atapi_pt.sense.ascq = 0;
++
++    /* Send command and wait for reply, SG_IO ioctl*/
++    r = ioctl(raw_state->fd, 0x2285, cmd);
++
++    if(command == GPCMD_GET_EVENT_STATUS_NOTIFICATION)
++    {
++        struct stat file_stat;
++
++        if(s->io_buffer[2] == 4 && s->io_buffer[4] == 2)
++        {
++            /* This is a "new media" message, tell any other VMs */
++            DEBUG_PRINTF("[ATAPI] new media\n");
++            system("touch " IDE_ATAPI_PT_NEW_CD_FILE);
++
++            if(stat(IDE_ATAPI_PT_NEW_CD_FILE, &file_stat) != 0)
++                DEBUG_PRINTF("Error writing to new CD file\n");
++            else
++                s->atapi_pt.new_cd_time = file_stat.st_ctime;
++        }
++
++        if(s->io_buffer[2] == 4 && s->io_buffer[4] == 3)
++        {
++            /* This is a "media removed" message, tell any other VMs */
++            DEBUG_PRINTF("[ATAPI] media removed\n");
++            system("touch " IDE_ATAPI_PT_EJECT_CD_FILE);
++
++            if(stat(IDE_ATAPI_PT_EJECT_CD_FILE, &file_stat) != 0)
++                DEBUG_PRINTF("Error writing to eject CD file\n");
++            else
++                s->atapi_pt.eject_time = file_stat.st_ctime;
++        }
++
++        if((s->io_buffer[2] == 4 && s->io_buffer[4] == 0 && s->io_buffer[5] == 2) ||
++           (s->io_buffer[4] == 0 && s->io_buffer[5] == 0 &&
++            s->io_buffer[6] == 0 && s->io_buffer[7] == 0))
++        {
++            /* This is a no activity message we can hijack if we need to */
++
++            if(stat(IDE_ATAPI_PT_NEW_CD_FILE, &file_stat) == 0 &&
++               s->atapi_pt.new_cd_time < file_stat.st_ctime)
++            {
++                /* There's been a new media message that we haven't seen yet */
++                DEBUG_PRINTF("[ATAPI] new media message spotted\n");
++                s->atapi_pt.new_cd_time = file_stat.st_ctime;
++
++                s->io_buffer[2] = 4;
++                s->io_buffer[4] = 2;
++                s->io_buffer[5] = 2;
++                s->io_buffer[6] = 0;
++                s->io_buffer[7] = 0;
++            }
++            else if(stat(IDE_ATAPI_PT_EJECT_CD_FILE, &file_stat) == 0 &&
++               s->atapi_pt.eject_time < file_stat.st_ctime)
++            {
++                /* There's been an eject message that we haven't seen yet */
++                DEBUG_PRINTF("[ATAPI] media removed message spotted\n");
++                s->atapi_pt.eject_time = file_stat.st_ctime;
++
++                s->io_buffer[2] = 4;
++                s->io_buffer[4] = 3;
++                s->io_buffer[5] = 1;
++                s->io_buffer[6] = 0;
++                s->io_buffer[7] = 0;
++            }
++        }
++    }
++
++    if(r || cmd->driver_status || cmd->transport_status ||
++       cmd->device_status) {
++        /*
++        DEBUG_PRINTF("[\e[1;31mERROR\e[m]\n"
++                     "\tcommand 0x%02x (%s)\n"
++                     "\terrno: %d (%s)\n"
++                     "\tsense: 0x%02x,%02x,%02x (%s)\n"
++                     "\tdriver: %d, transport: %d, device: %d\n",
++                     command, atapi_cmd_to_str(command),
++                     errno,
++                     strerror(errno) ? : "(null)",
++                     s->atapi_pt.sense.sense_key,
++                     s->atapi_pt.sense.asc,
++                     s->atapi_pt.sense.ascq,
++                     atapi_sense_to_str(s->atapi_pt.sense.sense_key,
++                                        s->atapi_pt.sense.asc,
++                                        s->atapi_pt.sense.ascq),
++                     cmd->driver_status,
++                     cmd->transport_status,
++                     cmd->device_status);
++        */
++        DEBUG_PRINTF("[\e[1;31mERROR\e[m] (%s)  sense: 0x%02x,%02x,%02x (%s)\n",
++                     atapi_cmd_to_str(command),
++                     s->atapi_pt.sense.sense_key,
++                     s->atapi_pt.sense.asc,
++                     s->atapi_pt.sense.ascq,
++                     atapi_sense_to_str(s->atapi_pt.sense.sense_key,
++                                        s->atapi_pt.sense.asc,
++                                        s->atapi_pt.sense.ascq));
++        ide_atapi_pt_error(s);
++        return;
++    }
++
++    s->atapi_pt.cmd_sent(s);
 +}
 diff --git a/hw/ide.c b/hw/ide.c
-index e8d676e..85a2813 100644
+index e8d676e..6c1d60a 100644
 --- a/hw/ide.c
 +++ b/hw/ide.c
 @@ -22,6 +22,7 @@
@@ -1083,7 +1548,7 @@ index e8d676e..85a2813 100644
  #include "hw.h"
  #include "pc.h"
  #include "pci.h"
-@@ -36,6 +37,15 @@
+@@ -36,6 +37,16 @@
  #include "sh.h"
  #include "dma.h"
  
@@ -1092,6 +1557,7 @@ index e8d676e..85a2813 100644
 +
 +# include <linux/cdrom.h>
 +# include <linux/bsg.h>
++# include <linux/ioctl.h>
 +#endif /* __linux__ */
 +
 +#include <assert.h>
@@ -1099,7 +1565,7 @@ index e8d676e..85a2813 100644
  /* debug IDE devices */
  //#define DEBUG_IDE
  //#define DEBUG_IDE_ATAPI
-@@ -221,83 +231,94 @@
+@@ -221,83 +232,94 @@
  
  #define ATAPI_PACKET_SIZE 12
  
@@ -1258,7 +1724,7 @@ index e8d676e..85a2813 100644
  
  /*
   * Based on values from <linux/cdrom.h> but extending CD_MINS
-@@ -309,10 +330,13 @@
+@@ -309,10 +331,13 @@
   */
  
  /* Some generally useful CD-ROM information */
@@ -1276,7 +1742,7 @@ index e8d676e..85a2813 100644
  #define CD_MAX_BYTES       (CD_MINS * CD_SECS * CD_FRAMES * CD_FRAMESIZE)
  #define CD_MAX_SECTORS     (CD_MAX_BYTES / 512)
  
-@@ -351,12 +375,15 @@
+@@ -351,12 +376,15 @@
  #define MMC_PROFILE_HDDVD_RW_DL         0x005A
  #define MMC_PROFILE_INVALID             0xFFFF
  
@@ -1292,7 +1758,7 @@ index e8d676e..85a2813 100644
  #define ASC_ILLEGAL_OPCODE                   0x20
  #define ASC_LOGICAL_BLOCK_OOR                0x21
  #define ASC_INV_FIELD_IN_CMD_PACKET          0x24
-@@ -371,15 +398,42 @@
+@@ -371,15 +399,45 @@
  #define CFA_INVALID_ADDRESS     0x21
  #define CFA_ADDRESS_OVERFLOW    0x2f
  
@@ -1333,13 +1799,16 @@ index e8d676e..85a2813 100644
 +    uint32_t             reply_size_init;   // initial value
 +    uint32_t             reply_size_offset; // offset in s->io_buffer
 +    uint32_t             reply_size_len;    // length in byte (0, 1, 2, 3 or 4)
++
++    time_t               new_cd_time;
++    time_t               eject_time;
 +} ATAPIPassThroughState;
 +#endif /* __linux__ */
 +
  /* NOTE: IDEState represents in fact one drive */
  typedef struct IDEState {
      /* ide config */
-@@ -429,6 +483,10 @@ typedef struct IDEState {
+@@ -429,6 +487,10 @@ typedef struct IDEState {
      int lba;
      int cd_sector_size;
      int atapi_dma; /* true if dma is requested for the packet cmd */
@@ -1350,7 +1819,16 @@ index e8d676e..85a2813 100644
      /* ATA DMA state */
      int io_buffer_size;
      QEMUSGList sg;
-@@ -1321,9 +1379,9 @@ static void ide_sector_write(IDEState *s)
+@@ -940,6 +1002,8 @@ static inline void ide_set_irq(IDEState *s)
+         if (bm) {
+             bm->status |= BM_STATUS_INT;
+         }
++        //        if (s->is_cdrom)
++        //            puts("@@@@@@@@ CDROM IRQ");
+         qemu_irq_raise(s->irq);
+     }
+ }
+@@ -1321,9 +1385,9 @@ static void ide_sector_write(IDEState *s)
             that at the expense of slower write performances. Use this
             option _only_ to install Windows 2000. You must disable it
             for normal use. */
@@ -1362,7 +1840,7 @@ index e8d676e..85a2813 100644
  #endif
      {
          ide_set_irq(s);
-@@ -1499,6 +1557,13 @@ static inline int ube16_to_cpu(const uint8_t *buf)
+@@ -1499,6 +1563,13 @@ static inline int ube16_to_cpu(const uint8_t *buf)
      return (buf[0] << 8) | buf[1];
  }
  
@@ -1376,7 +1854,7 @@ index e8d676e..85a2813 100644
  static inline int ube32_to_cpu(const uint8_t *buf)
  {
      return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
-@@ -1567,12 +1632,14 @@ static void ide_atapi_io_error(IDEState *s, int ret)
+@@ -1567,12 +1638,14 @@ static void ide_atapi_io_error(IDEState *s, int ret)
  static void ide_atapi_cmd_reply_end(IDEState *s)
  {
      int byte_count_limit, size, ret;
@@ -1391,7 +1869,7 @@ index e8d676e..85a2813 100644
      if (s->packet_transfer_size <= 0) {
          /* end of transfer */
          ide_transfer_stop(s);
-@@ -1582,63 +1649,65 @@ static void ide_atapi_cmd_reply_end(IDEState *s)
+@@ -1582,63 +1655,65 @@ static void ide_atapi_cmd_reply_end(IDEState *s)
  #ifdef DEBUG_IDE_ATAPI
          printf("status=0x%x\n", s->status);
  #endif
@@ -1508,7 +1986,7 @@ index e8d676e..85a2813 100644
      }
  }
  
-@@ -1882,6 +1951,10 @@ static int ide_dvd_read_structure(IDEState *s, int format,
+@@ -1882,6 +1957,10 @@ static int ide_dvd_read_structure(IDEState *s, int format,
      }
  }
  
@@ -1519,7 +1997,7 @@ index e8d676e..85a2813 100644
  static void ide_atapi_cmd(IDEState *s)
  {
      const uint8_t *packet;
-@@ -1922,7 +1995,6 @@ static void ide_atapi_cmd(IDEState *s)
+@@ -1922,7 +2001,6 @@ static void ide_atapi_cmd(IDEState *s)
                                  ASC_MEDIUM_NOT_PRESENT);
          }
          break;
@@ -1527,7 +2005,7 @@ index e8d676e..85a2813 100644
      case GPCMD_MODE_SENSE_10:
          {
              int action, code;
-@@ -1935,9 +2007,9 @@ static void ide_atapi_cmd(IDEState *s)
+@@ -1935,9 +2013,9 @@ static void ide_atapi_cmd(IDEState *s)
              switch(action) {
              case 0: /* current values */
                  switch(code) {
@@ -1539,7 +2017,7 @@ index e8d676e..85a2813 100644
                      buf[3] = 0;
                      buf[4] = 0;
                      buf[5] = 0;
-@@ -1954,17 +2026,17 @@ static void ide_atapi_cmd(IDEState *s)
+@@ -1954,17 +2032,17 @@ static void ide_atapi_cmd(IDEState *s)
                      buf[15] = 0x00;
                      ide_atapi_cmd_reply(s, 16, max_len);
                      break;
@@ -1561,7 +2039,7 @@ index e8d676e..85a2813 100644
                      buf[10] = 0x00;
                      buf[11] = 0x00;
  
-@@ -1987,6 +2059,7 @@ static void ide_atapi_cmd(IDEState *s)
+@@ -1987,6 +2065,7 @@ static void ide_atapi_cmd(IDEState *s)
                      buf[27] = 0;
                      ide_atapi_cmd_reply(s, 28, max_len);
                      break;
@@ -1569,7 +2047,7 @@ index e8d676e..85a2813 100644
                  default:
                      goto error_cmd;
                  }
-@@ -2110,7 +2183,7 @@ static void ide_atapi_cmd(IDEState *s)
+@@ -2110,7 +2189,7 @@ static void ide_atapi_cmd(IDEState *s)
          break;
      case GPCMD_MECHANISM_STATUS:
          {
@@ -1578,7 +2056,7 @@ index e8d676e..85a2813 100644
              cpu_to_ube16(buf, 0);
              /* no current LBA */
              buf[2] = 0;
-@@ -2125,7 +2198,6 @@ static void ide_atapi_cmd(IDEState *s)
+@@ -2125,7 +2204,6 @@ static void ide_atapi_cmd(IDEState *s)
          {
              int format, msf, start_track, len;
              uint64_t total_sectors;
@@ -1586,7 +2064,7 @@ index e8d676e..85a2813 100644
              bdrv_get_geometry(s->bs, &total_sectors);
              total_sectors >>= 2;
              if (total_sectors == 0) {
-@@ -2279,7 +2351,7 @@ static void ide_atapi_cmd(IDEState *s)
+@@ -2279,7 +2357,7 @@ static void ide_atapi_cmd(IDEState *s)
                  max_len = 512;
  
              memset(buf, 0, max_len);
@@ -1595,7 +2073,7 @@ index e8d676e..85a2813 100644
               * the number of sectors from the media tells us which profile
               * to use as current.  0 means there is no media
               */
-@@ -2484,7 +2556,11 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+@@ -2484,7 +2562,11 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
  
          /* Only DEVICE RESET is allowed while BSY or/and DRQ are set */
          if ((s->status & (BUSY_STAT|DRQ_STAT)) && val != WIN_DEVICE_RESET)
@@ -1607,7 +2085,7 @@ index e8d676e..85a2813 100644
  
          switch(val) {
          case WIN_IDENTIFY:
-@@ -2727,7 +2803,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+@@ -2727,7 +2809,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
              else
                  s->status = READY_STAT | SEEK_STAT;
              s->error = 0x01; /* Device 0 passed, Device 1 passed or not
@@ -1616,7 +2094,7 @@ index e8d676e..85a2813 100644
                                */
              ide_set_irq(s);
              break;
-@@ -2748,7 +2824,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+@@ -2748,7 +2830,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
              s->atapi_dma = s->feature & 1;
              s->nsector = 1;
              ide_transfer_start(s, s->io_buffer, ATAPI_PACKET_SIZE,
@@ -1625,7 +2103,7 @@ index e8d676e..85a2813 100644
              break;
          /* CF-ATA commands */
          case CFA_REQ_EXT_ERROR_CODE:
-@@ -3133,8 +3209,20 @@ static void ide_init2(IDEState *ide_state,
+@@ -3133,8 +3215,20 @@ static void ide_init2(IDEState *ide_state,
  
              if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) {
                  s->is_cdrom = 1;
@@ -1634,20 +2112,20 @@ index e8d676e..85a2813 100644
              }
 +#ifdef __linux__
 +            else if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM_PT) {
-+                BDRVRawState *raw_state = s->bs->opaque;
++                //              BDRVRawState *raw_state = s->bs->opaque;
 +                s->is_cdrom = 1;
 +                s->atapi_cmd = ide_atapi_pt_cmd;
 +                bdrv_set_change_cb(s->bs, cdrom_change_cb, s);
-+                qemu_set_fd_handler(raw_state->fd,
-+                                    (IOHandler *)ide_atapi_pt_sg_io_finished,
-+                                    NULL, s);
++                //                qemu_set_fd_handler(raw_state->fd,
++                //                                  (IOHandler *)ide_atapi_pt_sg_io_finished,
++                //                                  NULL, s);
 +            }
 +#endif /* __linux__ */
          }
          s->drive_serial = drive_serial++;
          strncpy(s->drive_serial_str, drive_get_serial(s->bs),
 diff --git a/vl.c b/vl.c
-index f3b0dae..91fb696 100644
+index cd354de..b5dfbd5 100644
 --- a/vl.c
 +++ b/vl.c
 @@ -2192,8 +2192,10 @@ static int bt_parse(const char *opt)
@@ -1689,7 +2167,16 @@ index f3b0dae..91fb696 100644
        }
          break;
      case IF_SD:
-@@ -4244,6 +4251,7 @@ enum {
+@@ -2669,6 +2676,8 @@ int drive_init(struct drive_opt *arg, int snapshot, void *opaque)
+         bdrv_flags |= BDRV_O_CACHE_WB;
+     else if (cache == 3) /* not specified */
+         bdrv_flags |= BDRV_O_CACHE_DEF;
++
++    printf("**** vl open(%s)\n", file);
+     if (bdrv_open2(bdrv, file, bdrv_flags, drv) < 0) {
+         fprintf(stderr, "qemu: could not open disk image %s\n",
+                         file);
+@@ -4244,6 +4253,7 @@ enum {
      QEMU_OPTION_hdc,
      QEMU_OPTION_hdd,
      QEMU_OPTION_cdrom,
@@ -1697,7 +2184,7 @@ index f3b0dae..91fb696 100644
      QEMU_OPTION_drive,
      QEMU_OPTION_mtdblock,
      QEMU_OPTION_sd,
-@@ -4366,6 +4374,7 @@ static const QEMUOption qemu_options[] = {
+@@ -4366,6 +4376,7 @@ static const QEMUOption qemu_options[] = {
      { "hdc", HAS_ARG, QEMU_OPTION_hdc },
      { "hdd", HAS_ARG, QEMU_OPTION_hdd },
      { "cdrom", HAS_ARG, QEMU_OPTION_cdrom },
@@ -1705,7 +2192,7 @@ index f3b0dae..91fb696 100644
      { "drive", HAS_ARG, QEMU_OPTION_drive },
      { "mtdblock", HAS_ARG, QEMU_OPTION_mtdblock },
      { "sd", HAS_ARG, QEMU_OPTION_sd },
-@@ -5035,13 +5044,16 @@ int main(int argc, char **argv, char **envp)
+@@ -5035,13 +5046,16 @@ int main(int argc, char **argv, char **envp)
              case QEMU_OPTION_cdrom:
                  drive_add(optarg, CDROM_ALIAS);
                  break;