qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] ATAPI pass throug v4
@ 2009-08-07 17:33 Alexandre Bique
  2009-08-07 17:33 ` [Qemu-devel] [PATCH 1/7] atapi: fix up a few comments Alexandre Bique
  2009-08-10 20:09 ` [Qemu-devel] ATAPI pass throug v4 Anthony Liguori
  0 siblings, 2 replies; 10+ messages in thread
From: Alexandre Bique @ 2009-08-07 17:33 UTC (permalink / raw)
  To: qemu-devel

Hi,

This is the new version of the ATAPI pass through patches.

What's new from the v3 ?
 - applied Christoph and Juan comments
 - made some part of ide.c public and added new files:
   - ide.h               some defines, structures and function declarations
   - atapi-defines.h     atapi related defines and function to retrive name
                         from the command
   - atapi-data.c        some data tables
   - atapi-pt.h          atapi pass through structures and public functions
   - atapi-pt.c          atapi pass through implementation

I hope this one is alright.

Thanks.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH 1/7] atapi: fix up a few comments
  2009-08-07 17:33 [Qemu-devel] ATAPI pass throug v4 Alexandre Bique
@ 2009-08-07 17:33 ` Alexandre Bique
  2009-08-07 17:33   ` [Qemu-devel] [PATCH 2/7] atapi: protocol define updates Alexandre Bique
  2009-08-10 20:09 ` [Qemu-devel] ATAPI pass throug v4 Anthony Liguori
  1 sibling, 1 reply; 10+ messages in thread
From: Alexandre Bique @ 2009-08-07 17:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Alexandre Bique

Signed-off-by: Alexandre Bique <alexandre.bique@citrix.com>
---
 hw/ide.c |   12 ++++++------
 1 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/hw/ide.c b/hw/ide.c
index 6cf04a6..e4e2ab7 100644
--- a/hw/ide.c
+++ b/hw/ide.c
@@ -1680,9 +1680,9 @@ static void ide_atapi_cmd(IDEState *s)
             switch(action) {
             case 0: /* current values */
                 switch(code) {
-                case 0x01: /* error recovery */
+                case 0x01: /* read write error recovery parameters */
                     cpu_to_ube16(&buf[0], 16 + 6);
-                    buf[2] = 0x70;
+                    buf[2] = 0x70; /* Obsolete: medium type code */
                     buf[3] = 0;
                     buf[4] = 0;
                     buf[5] = 0;
@@ -1699,17 +1699,17 @@ static void ide_atapi_cmd(IDEState *s)
                     buf[15] = 0x00;
                     ide_atapi_cmd_reply(s, 16, max_len);
                     break;
-                case 0x2a:
+                case 0x2a: /* CD/DVD capabilities & mechanical status */
                     cpu_to_ube16(&buf[0], 28 + 6);
-                    buf[2] = 0x70;
+                    buf[2] = 0x70; /* Obsolete: medium type code */
                     buf[3] = 0;
                     buf[4] = 0;
                     buf[5] = 0;
                     buf[6] = 0;
                     buf[7] = 0;
 
-                    buf[8] = 0x2a;
-                    buf[9] = 0x12;
+                    buf[8] = 0x2a; /* page code */
+                    buf[9] = 0x12; /* page length */
                     buf[10] = 0x00;
                     buf[11] = 0x00;
 
-- 
1.6.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH 2/7] atapi: protocol define updates
  2009-08-07 17:33 ` [Qemu-devel] [PATCH 1/7] atapi: fix up a few comments Alexandre Bique
@ 2009-08-07 17:33   ` Alexandre Bique
  2009-08-07 17:33     ` [Qemu-devel] [PATCH 3/7] atapi: guessing if the cdrom device is a scsi device Alexandre Bique
  0 siblings, 1 reply; 10+ messages in thread
From: Alexandre Bique @ 2009-08-07 17:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Alexandre Bique

Add some missing ATAPI protocol defintions, and fix up some whitespaces
and comments on the way.

Signed-off-by: Alexandre Bique <alexandre.bique@citrix.com>
---
 hw/ide.c |   77 ++++++++++++++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 60 insertions(+), 17 deletions(-)

diff --git a/hw/ide.c b/hw/ide.c
index e4e2ab7..5c2693e 100644
--- a/hw/ide.c
+++ b/hw/ide.c
@@ -216,13 +216,17 @@
 
 #define ATAPI_PACKET_SIZE 12
 
-/* The generic packet command opcodes for CD/DVD Logical Units,
- * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
+/*********************************************************************
+ * Generic Packet commands, MMC commands, and such
+ *********************************************************************/
+
+ /* The generic packet command opcodes for CD/DVD Logical Units,
+  * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
 #define GPCMD_BLANK			    0xa1
 #define GPCMD_CLOSE_TRACK		    0x5b
 #define GPCMD_FLUSH_CACHE		    0x35
 #define GPCMD_FORMAT_UNIT		    0x04
-#define GPCMD_GET_CONFIGURATION		    0x46
+#define GPCMD_GET_CONFIGURATION             0x46
 #define GPCMD_GET_EVENT_STATUS_NOTIFICATION 0x4a
 #define GPCMD_GET_PERFORMANCE		    0xac
 #define GPCMD_INQUIRY			    0x12
@@ -238,6 +242,8 @@
 #define GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL  0x1e
 #define GPCMD_READ_10			    0x28
 #define GPCMD_READ_12			    0xa8
+#define GPCMD_READ_BUFFER		    0x3c
+#define GPCMD_READ_BUFFER_CAPACITY	    0x5c
 #define GPCMD_READ_CDVD_CAPACITY	    0x25
 #define GPCMD_READ_CD			    0xbe
 #define GPCMD_READ_CD_MSF		    0xb9
@@ -246,15 +252,16 @@
 #define GPCMD_READ_FORMAT_CAPACITIES	    0x23
 #define GPCMD_READ_HEADER		    0x44
 #define GPCMD_READ_TRACK_RZONE_INFO	    0x52
-#define GPCMD_READ_SUBCHANNEL		    0x42
-#define GPCMD_READ_TOC_PMA_ATIP		    0x43
+#define GPCMD_READ_SUBCHANNEL	            0x42
+#define GPCMD_READ_TOC_PMA_ATIP             0x43
 #define GPCMD_REPAIR_RZONE_TRACK	    0x58
 #define GPCMD_REPORT_KEY		    0xa4
 #define GPCMD_REQUEST_SENSE		    0x03
 #define GPCMD_RESERVE_RZONE_TRACK	    0x53
+#define GPCMD_SEND_CUE_SHEET		    0x5d
 #define GPCMD_SCAN			    0xba
 #define GPCMD_SEEK			    0x2b
-#define GPCMD_SEND_DVD_STRUCTURE	    0xad
+#define GPCMD_SEND_DVD_STRUCTURE	    0xbf
 #define GPCMD_SEND_EVENT		    0xa2
 #define GPCMD_SEND_KEY			    0xa3
 #define GPCMD_SEND_OPC			    0x54
@@ -263,9 +270,11 @@
 #define GPCMD_START_STOP_UNIT		    0x1b
 #define GPCMD_STOP_PLAY_SCAN		    0x4e
 #define GPCMD_TEST_UNIT_READY		    0x00
-#define GPCMD_VERIFY_10			    0x2f
+#define GPCMD_VERIFY_10                     0x2f
 #define GPCMD_WRITE_10			    0x2a
+#define GPCMD_WRITE_12			    0xaa
 #define GPCMD_WRITE_AND_VERIFY_10	    0x2e
+#define GPCMD_WRITE_BUFFER		    0x3b
 /* This is listed as optional in ATAPI 2.6, but is (curiously)
  * missing from Mt. Fuji, Table 57.  It _is_ mentioned in Mt. Fuji
  * Table 377 as an MMC command for SCSi devices though...  Most ATAPI
@@ -279,18 +288,20 @@
  * older drives only.
  */
 #define GPCMD_GET_MEDIA_STATUS		    0xda
-#define GPCMD_MODE_SENSE_6		    0x1a
+#define GPCMD_MODE_SENSE_6                  0x1a
 
 /* Mode page codes for mode sense/set */
+#define GPMODE_VENDOR_PAGE		0x00
 #define GPMODE_R_W_ERROR_PAGE		0x01
 #define GPMODE_WRITE_PARMS_PAGE		0x05
+#define GPMODE_WCACHING_PAGE		0x08
 #define GPMODE_AUDIO_CTL_PAGE		0x0e
 #define GPMODE_POWER_PAGE		0x1a
 #define GPMODE_FAULT_FAIL_PAGE		0x1c
 #define GPMODE_TO_PROTECT_PAGE		0x1d
 #define GPMODE_CAPABILITIES_PAGE	0x2a
 #define GPMODE_ALL_PAGES		0x3f
-/* Not in Mt. Fuji, but in ATAPI 2.6 -- depricated now in favor
+/* Not in Mt. Fuji, but in ATAPI 2.6 -- deprecated now in favor
  * of MODE_SENSE_POWER_PAGE */
 #define GPMODE_CDROM_PAGE		0x0d
 
@@ -304,10 +315,26 @@
  */
 
 /* Some generally useful CD-ROM information */
-#define CD_MINS                       80 /* max. minutes per CD */
-#define CD_SECS                       60 /* seconds per minute */
-#define CD_FRAMES                     75 /* frames per second */
-#define CD_FRAMESIZE                2048 /* bytes per frame, "cooked" mode */
+#define CD_MINS              80 /* max. minutes per CD */
+#define CD_SECS              60 /* seconds per minute */
+#define CD_FRAMES            75 /* frames per second */
+#define CD_SYNC_SIZE         12 /* 12 sync bytes per raw data frame */
+#define CD_MSF_OFFSET       150 /* MSF numbering offset of first frame */
+#define CD_CHUNK_SIZE        24 /* lowest-level "data bytes piece" */
+#define CD_NUM_OF_CHUNKS     98 /* chunks per frame */
+#define CD_FRAMESIZE_SUB     96 /* subchannel data "frame" size */
+#define CD_HEAD_SIZE          4 /* header (address) bytes per raw data frame */
+#define CD_SUBHEAD_SIZE       8 /* subheader bytes per raw XA data frame */
+#define CD_EDC_SIZE           4 /* bytes EDC per most raw data frame types */
+#define CD_ZERO_SIZE          8 /* bytes zero per yellow book mode 1 frame */
+#define CD_ECC_SIZE         276 /* bytes ECC per most raw data frame types */
+#define CD_FRAMESIZE       2048 /* bytes per frame, "cooked" mode */
+#define CD_FRAMESIZE_RAW   2352 /* bytes per frame, "raw" mode */
+#define CD_FRAMESIZE_RAWER 2646 /* The maximum possible returned bytes */
+/* most drives don't deliver everything: */
+#define CD_FRAMESIZE_RAW1 (CD_FRAMESIZE_RAW-CD_SYNC_SIZE) /*2340*/
+#define CD_FRAMESIZE_RAW0 (CD_FRAMESIZE_RAW-CD_SYNC_SIZE-CD_HEAD_SIZE) /*2336*/
+
 #define CD_MAX_BYTES       (CD_MINS * CD_SECS * CD_FRAMES * CD_FRAMESIZE)
 #define CD_MAX_SECTORS     (CD_MAX_BYTES / 512)
 
@@ -346,12 +373,15 @@
 #define MMC_PROFILE_HDDVD_RW_DL         0x005A
 #define MMC_PROFILE_INVALID             0xFFFF
 
+
 #define ATAPI_INT_REASON_CD             0x01 /* 0 = data transfer */
 #define ATAPI_INT_REASON_IO             0x02 /* 1 = transfer to the host */
 #define ATAPI_INT_REASON_REL            0x04
 #define ATAPI_INT_REASON_TAG            0xf8
 
 /* same constants as bochs */
+#define ASC_NONE                             0x00
+#define ASC_READ_ERROR                       0x11
 #define ASC_ILLEGAL_OPCODE                   0x20
 #define ASC_LOGICAL_BLOCK_OOR                0x21
 #define ASC_INV_FIELD_IN_CMD_PACKET          0x24
@@ -367,10 +397,23 @@
 #define CFA_INVALID_ADDRESS     0x21
 #define CFA_ADDRESS_OVERFLOW    0x2f
 
-#define SENSE_NONE            0
-#define SENSE_NOT_READY       2
-#define SENSE_ILLEGAL_REQUEST 5
-#define SENSE_UNIT_ATTENTION  6
+/* Sense keys */
+#define SENSE_NONE             0
+#define SENSE_RECOVERED_ERROR  1
+#define SENSE_NOT_READY        2
+#define SENSE_MEDIUM_ERROR     3
+#define SENSE_HARDWARE_ERROR   4
+#define SENSE_ILLEGAL_REQUEST  5
+#define SENSE_UNIT_ATTENTION   6
+#define SENSE_DATA_PROTECT     7
+#define SENSE_BLANK_CHECK      8
+#define SENSE_VENDOR_SPECIFIC  9
+#define SENSE_COPY_ABORTED     10
+#define SENSE_ABORTED_COMMAND  11
+#define SENSE_VOLUME_OVERFLOW  13
+#define SENSE_MISCOMPARE       14
+
+#define IO_BUFFER_MAX_SIZE      (IDE_DMA_BUF_SECTORS * 512 + 4)
 
 struct IDEState;
 
-- 
1.6.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH 3/7] atapi: guessing if the cdrom device is a scsi device.
  2009-08-07 17:33   ` [Qemu-devel] [PATCH 2/7] atapi: protocol define updates Alexandre Bique
@ 2009-08-07 17:33     ` Alexandre Bique
  2009-08-07 17:33       ` [Qemu-devel] [PATCH 4/7] atapi: adds header guards to hw/pcmia.h Alexandre Bique
  0 siblings, 1 reply; 10+ messages in thread
From: Alexandre Bique @ 2009-08-07 17:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Alexandre Bique

ATAPI pass through code is enabled when the block device is a scsi
device. So we have to guess if the block device is a scsi device in
cdrom_open().

Signed-off-by: Alexandre Bique <alexandre.bique@citrix.com>
---
 block/raw-posix.c |    8 ++++++++
 1 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/block/raw-posix.c b/block/raw-posix.c
index bdee07f..ebb13d4 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -1305,6 +1305,14 @@ static int cdrom_open(BlockDriverState *bs, const char *filename, int flags)
     s->type = FTYPE_CD;
 
     /* open will not fail even if no CD is inserted, so add O_NONBLOCK */
+#if defined(__linux__) && defined(CONFIG_AIO)
+    if (strstart(filename, "/dev/sg", NULL) ||
+        strstart(filename, "/dev/cd", NULL) ||
+        strstart(filename, "/dev/dvd", NULL) ||
+        strstart(filename, "/dev/sr", NULL)) {
+        bs->sg = 1;
+    }
+#endif
     return raw_open_common(bs, filename, flags, O_NONBLOCK);
 }
 
-- 
1.6.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH 4/7] atapi: adds header guards to hw/pcmia.h
  2009-08-07 17:33     ` [Qemu-devel] [PATCH 3/7] atapi: guessing if the cdrom device is a scsi device Alexandre Bique
@ 2009-08-07 17:33       ` Alexandre Bique
  2009-08-07 17:33         ` [Qemu-devel] [PATCH 5/7] atapi: adds header guards to hw/mac_dbdma.h Alexandre Bique
  0 siblings, 1 reply; 10+ messages in thread
From: Alexandre Bique @ 2009-08-07 17:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Alexandre Bique

Signed-off-by: Alexandre Bique <alexandre.bique@citrix.com>
---
 hw/pcmcia.h |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/hw/pcmcia.h b/hw/pcmcia.h
index 7171504..3c59698 100644
--- a/hw/pcmcia.h
+++ b/hw/pcmcia.h
@@ -1,5 +1,8 @@
 /* PCMCIA/Cardbus */
 
+#ifndef PCMCIA_H
+#define PCMCIA_H
+
 #include "qemu-common.h"
 
 typedef struct {
@@ -49,3 +52,5 @@ struct PCMCIACardState {
 
 /* dscm1xxxx.c */
 PCMCIACardState *dscm1xxxx_init(BlockDriverState *bdrv);
+
+#endif
-- 
1.6.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH 5/7] atapi: adds header guards to hw/mac_dbdma.h
  2009-08-07 17:33       ` [Qemu-devel] [PATCH 4/7] atapi: adds header guards to hw/pcmia.h Alexandre Bique
@ 2009-08-07 17:33         ` Alexandre Bique
  2009-08-07 17:33           ` [Qemu-devel] [PATCH 6/7] atapi: made some part of ide.c public and moved some part to atapi Alexandre Bique
  0 siblings, 1 reply; 10+ messages in thread
From: Alexandre Bique @ 2009-08-07 17:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Alexandre Bique

Signed-off-by: Alexandre Bique <alexandre.bique@citrix.com>
---
 hw/mac_dbdma.h |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/hw/mac_dbdma.h b/hw/mac_dbdma.h
index d236c5b..fc37590 100644
--- a/hw/mac_dbdma.h
+++ b/hw/mac_dbdma.h
@@ -20,6 +20,9 @@
  * THE SOFTWARE.
  */
 
+#ifndef MAC_DBDMA_H
+#define MAC_DBDMA_H
+
 typedef struct DBDMA_io DBDMA_io;
 
 typedef void (*DBDMA_flush)(DBDMA_io *io);
@@ -41,3 +44,5 @@ void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq,
                             void *opaque);
 void DBDMA_schedule(void);
 void* DBDMA_init (int *dbdma_mem_index);
+
+#endif /* !MAC_DBDMA_H */
-- 
1.6.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH 6/7] atapi: made some part of ide.c public and moved some part to atapi.
  2009-08-07 17:33         ` [Qemu-devel] [PATCH 5/7] atapi: adds header guards to hw/mac_dbdma.h Alexandre Bique
@ 2009-08-07 17:33           ` Alexandre Bique
  2009-08-07 17:33             ` [Qemu-devel] [PATCH 7/7] atapi: introducing atapi pass through Alexandre Bique
  0 siblings, 1 reply; 10+ messages in thread
From: Alexandre Bique @ 2009-08-07 17:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Alexandre Bique

Signed-off-by: Alexandre Bique <alexandre.bique@citrix.com>
---
 hw/atapi-data.c    |  269 ++++++++++++++++++++++++++
 hw/atapi-defines.h |  234 ++++++++++++++++++++++
 hw/ide.c           |  544 ++--------------------------------------------------
 hw/ide.h           |  377 ++++++++++++++++++++++++++++++++++++
 4 files changed, 893 insertions(+), 531 deletions(-)
 create mode 100644 hw/atapi-data.c
 create mode 100644 hw/atapi-defines.h
 create mode 100644 hw/ide.h

diff --git a/hw/atapi-data.c b/hw/atapi-data.c
new file mode 100644
index 0000000..b995b77
--- /dev/null
+++ b/hw/atapi-data.c
@@ -0,0 +1,269 @@
+/*
+ * ATAPI pass through addition data
+ *
+ * Copyright (c) 2009 Alexandre Bique
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "atapi-defines.h"
+
+/* 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 {
+    unsigned short packet_command;
+    const char * const text;
+} packet_command_texts[] = {
+    { GPCMD_TEST_UNIT_READY, "Test Unit Ready" },
+    { GPCMD_REQUEST_SENSE, "Request Sense" },
+    { GPCMD_FORMAT_UNIT, "Format Unit" },
+    { GPCMD_INQUIRY, "Inquiry" },
+    { GPCMD_START_STOP_UNIT, "Start/Stop Unit" },
+    { GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL, "Prevent/Allow Medium Removal" },
+    { GPCMD_READ_FORMAT_CAPACITIES, "Read Format Capacities" },
+    { GPCMD_READ_CDVD_CAPACITY, "Read Cd/Dvd Capacity" },
+    { GPCMD_READ_10, "Read 10" },
+    { GPCMD_WRITE_10, "Write 10" },
+    { GPCMD_SEEK, "Seek" },
+    { GPCMD_WRITE_AND_VERIFY_10, "Write and Verify 10" },
+    { GPCMD_VERIFY_10, "Verify 10" },
+    { GPCMD_FLUSH_CACHE, "Flush Cache" },
+    { GPCMD_READ_SUBCHANNEL, "Read Subchannel" },
+    { GPCMD_READ_TOC_PMA_ATIP, "Read Table of Contents" },
+    { GPCMD_READ_HEADER, "Read Header" },
+    { GPCMD_PLAY_AUDIO_10, "Play Audio 10" },
+    { GPCMD_GET_CONFIGURATION, "Get Configuration" },
+    { GPCMD_PLAY_AUDIO_MSF, "Play Audio MSF" },
+    { GPCMD_PLAYAUDIO_TI, "Play Audio TrackIndex" },
+    { GPCMD_GET_EVENT_STATUS_NOTIFICATION,
+      "Get Event Status Notification" },
+    { GPCMD_PAUSE_RESUME, "Pause/Resume" },
+    { GPCMD_STOP_PLAY_SCAN, "Stop Play/Scan" },
+    { GPCMD_READ_DISC_INFO, "Read Disc Info" },
+    { GPCMD_READ_TRACK_RZONE_INFO, "Read Track Rzone Info" },
+    { GPCMD_RESERVE_RZONE_TRACK, "Reserve Rzone Track" },
+    { GPCMD_SEND_OPC, "Send OPC" },
+    { GPCMD_MODE_SELECT_10, "Mode Select 10" },
+    { GPCMD_REPAIR_RZONE_TRACK, "Repair Rzone Track" },
+    { GPCMD_MODE_SENSE_10, "Mode Sense 10" },
+    { GPCMD_CLOSE_TRACK, "Close Track" },
+    { GPCMD_BLANK, "Blank" },
+    { GPCMD_SEND_EVENT, "Send Event" },
+    { GPCMD_SEND_KEY, "Send Key" },
+    { GPCMD_REPORT_KEY, "Report Key" },
+    { GPCMD_LOAD_UNLOAD, "Load/Unload" },
+    { GPCMD_SET_READ_AHEAD, "Set Read-ahead" },
+    { GPCMD_READ_12, "Read 12" },
+    { GPCMD_GET_PERFORMANCE, "Get Performance" },
+    { GPCMD_SEND_DVD_STRUCTURE, "Send DVD Structure" },
+    { GPCMD_READ_DVD_STRUCTURE, "Read DVD Structure" },
+    { GPCMD_SET_STREAMING, "Set Streaming" },
+    { GPCMD_READ_CD_MSF, "Read CD MSF" },
+    { GPCMD_SCAN, "Scan" },
+    { GPCMD_SET_SPEED, "Set Speed" },
+    { GPCMD_PLAY_CD, "Play CD" },
+    { GPCMD_MECHANISM_STATUS, "Mechanism Status" },
+    { GPCMD_READ_CD, "Read CD" },
+    { GPCMD_READ_BUFFER_CAPACITY, "Read Buffer Capacity" },
+    { GPCMD_READ_BUFFER, "Read Buffer" },
+    { GPCMD_SEND_CUE_SHEET, "Send Cue Sheet" },
+    { 0, 0 }
+};
+
+const char *atapi_cmd_to_str(int cmd)
+{
+    int i;
+
+    for (i = 0; packet_command_texts[i].text; ++i)
+        if (packet_command_texts[i].packet_command == cmd)
+            return packet_command_texts[i].text;
+    return 0;
+}
+
+/* From Table 303 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
+const char * const sense_key_texts[16] = {
+    "No sense data",
+    "Recovered error",
+    "Not ready",
+    "Medium error",
+    "Hardware error",
+    "Illegal request",
+    "Unit attention",
+    "Data protect",
+    "Blank check",
+    "(reserved)",
+    "(reserved)",
+    "Aborted command",
+    "(reserved)",
+    "(reserved)",
+    "Miscompare",
+    "(reserved)",
+};
+
+/* From Table 304 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
+static const struct {
+    unsigned long asc_ascq;
+    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" },
+};
+
+const char *atapi_ascq_to_str(int ascq)
+{
+    int i;
+
+    for (i = 0; sense_data_texts[i].text; ++i)
+        if (sense_data_texts[i].asc_ascq == ascq)
+            return sense_data_texts[i].text;
+    return 0;
+}
diff --git a/hw/atapi-defines.h b/hw/atapi-defines.h
new file mode 100644
index 0000000..82b1da4
--- /dev/null
+++ b/hw/atapi-defines.h
@@ -0,0 +1,234 @@
+/*
+ * ATAPI definitions
+ *
+ * Copyright (c) 2009 Alexandre Bique
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef ATAPI_DEFINES_H
+#define ATAPI_DEFINES_H
+
+/* ATAPI defines */
+
+#define ATAPI_PACKET_SIZE 12
+
+/*********************************************************************
+ * Generic Packet commands, MMC commands, and such
+ *********************************************************************/
+
+ /* The generic packet command opcodes for CD/DVD Logical Units,
+  * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
+#define GPCMD_BLANK			    0xa1
+#define GPCMD_CLOSE_TRACK		    0x5b
+#define GPCMD_FLUSH_CACHE		    0x35
+#define GPCMD_FORMAT_UNIT		    0x04
+#define GPCMD_GET_CONFIGURATION             0x46
+#define GPCMD_GET_EVENT_STATUS_NOTIFICATION 0x4a
+#define GPCMD_GET_PERFORMANCE		    0xac
+#define GPCMD_INQUIRY			    0x12
+#define GPCMD_LOAD_UNLOAD		    0xa6
+#define GPCMD_MECHANISM_STATUS		    0xbd
+#define GPCMD_MODE_SELECT_10		    0x55
+#define GPCMD_MODE_SENSE_10		    0x5a
+#define GPCMD_PAUSE_RESUME		    0x4b
+#define GPCMD_PLAY_AUDIO_10		    0x45
+#define GPCMD_PLAY_AUDIO_MSF		    0x47
+#define GPCMD_PLAY_AUDIO_TI		    0x48
+#define GPCMD_PLAY_CD			    0xbc
+#define GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL  0x1e
+#define GPCMD_READ_10			    0x28
+#define GPCMD_READ_12			    0xa8
+#define GPCMD_READ_BUFFER		    0x3c
+#define GPCMD_READ_BUFFER_CAPACITY	    0x5c
+#define GPCMD_READ_CDVD_CAPACITY	    0x25
+#define GPCMD_READ_CD			    0xbe
+#define GPCMD_READ_CD_MSF		    0xb9
+#define GPCMD_READ_DISC_INFO		    0x51
+#define GPCMD_READ_DVD_STRUCTURE	    0xad
+#define GPCMD_READ_FORMAT_CAPACITIES	    0x23
+#define GPCMD_READ_HEADER		    0x44
+#define GPCMD_READ_TRACK_RZONE_INFO	    0x52
+#define GPCMD_READ_SUBCHANNEL	            0x42
+#define GPCMD_READ_TOC_PMA_ATIP             0x43
+#define GPCMD_REPAIR_RZONE_TRACK	    0x58
+#define GPCMD_REPORT_KEY		    0xa4
+#define GPCMD_REQUEST_SENSE		    0x03
+#define GPCMD_RESERVE_RZONE_TRACK	    0x53
+#define GPCMD_SEND_CUE_SHEET		    0x5d
+#define GPCMD_SCAN			    0xba
+#define GPCMD_SEEK			    0x2b
+#define GPCMD_SEND_DVD_STRUCTURE	    0xbf
+#define GPCMD_SEND_EVENT		    0xa2
+#define GPCMD_SEND_KEY			    0xa3
+#define GPCMD_SEND_OPC			    0x54
+#define GPCMD_SET_READ_AHEAD		    0xa7
+#define GPCMD_SET_STREAMING		    0xb6
+#define GPCMD_START_STOP_UNIT		    0x1b
+#define GPCMD_STOP_PLAY_SCAN		    0x4e
+#define GPCMD_TEST_UNIT_READY		    0x00
+#define GPCMD_VERIFY_10                     0x2f
+#define GPCMD_WRITE_10			    0x2a
+#define GPCMD_WRITE_12			    0xaa
+#define GPCMD_WRITE_AND_VERIFY_10	    0x2e
+#define GPCMD_WRITE_BUFFER		    0x3b
+/* This is listed as optional in ATAPI 2.6, but is (curiously)
+ * missing from Mt. Fuji, Table 57.  It _is_ mentioned in Mt. Fuji
+ * Table 377 as an MMC command for SCSi devices though...  Most ATAPI
+ * drives support it. */
+#define GPCMD_SET_SPEED			    0xbb
+/* This seems to be a SCSI specific CD-ROM opcode
+ * to play data at track/index */
+#define GPCMD_PLAYAUDIO_TI		    0x48
+/*
+ * From MS Media Status Notification Support Specification. For
+ * older drives only.
+ */
+#define GPCMD_GET_MEDIA_STATUS		    0xda
+#define GPCMD_MODE_SENSE_6                  0x1a
+
+/* Mode page codes for mode sense/set */
+#define GPMODE_VENDOR_PAGE		0x00
+#define GPMODE_R_W_ERROR_PAGE		0x01
+#define GPMODE_WRITE_PARMS_PAGE		0x05
+#define GPMODE_WCACHING_PAGE		0x08
+#define GPMODE_AUDIO_CTL_PAGE		0x0e
+#define GPMODE_POWER_PAGE		0x1a
+#define GPMODE_FAULT_FAIL_PAGE		0x1c
+#define GPMODE_TO_PROTECT_PAGE		0x1d
+#define GPMODE_CAPABILITIES_PAGE	0x2a
+#define GPMODE_ALL_PAGES		0x3f
+/* Not in Mt. Fuji, but in ATAPI 2.6 -- deprecated now in favor
+ * of MODE_SENSE_POWER_PAGE */
+#define GPMODE_CDROM_PAGE		0x0d
+
+/*
+ * Based on values from <linux/cdrom.h> but extending CD_MINS
+ * to the maximum common size allowed by the Orange's Book ATIP
+ *
+ * 90 and 99 min CDs are also available but using them as the
+ * upper limit reduces the effectiveness of the heuristic to
+ * detect DVDs burned to less than 25% of their maximum capacity
+ */
+
+/* Some generally useful CD-ROM information */
+#define CD_MINS              80 /* max. minutes per CD */
+#define CD_SECS              60 /* seconds per minute */
+#define CD_FRAMES            75 /* frames per second */
+#define CD_SYNC_SIZE         12 /* 12 sync bytes per raw data frame */
+#define CD_MSF_OFFSET       150 /* MSF numbering offset of first frame */
+#define CD_CHUNK_SIZE        24 /* lowest-level "data bytes piece" */
+#define CD_NUM_OF_CHUNKS     98 /* chunks per frame */
+#define CD_FRAMESIZE_SUB     96 /* subchannel data "frame" size */
+#define CD_HEAD_SIZE          4 /* header (address) bytes per raw data frame */
+#define CD_SUBHEAD_SIZE       8 /* subheader bytes per raw XA data frame */
+#define CD_EDC_SIZE           4 /* bytes EDC per most raw data frame types */
+#define CD_ZERO_SIZE          8 /* bytes zero per yellow book mode 1 frame */
+#define CD_ECC_SIZE         276 /* bytes ECC per most raw data frame types */
+#define CD_FRAMESIZE       2048 /* bytes per frame, "cooked" mode */
+#define CD_FRAMESIZE_RAW   2352 /* bytes per frame, "raw" mode */
+#define CD_FRAMESIZE_RAWER 2646 /* The maximum possible returned bytes */
+/* most drives don't deliver everything: */
+#define CD_FRAMESIZE_RAW1 (CD_FRAMESIZE_RAW-CD_SYNC_SIZE) /*2340*/
+#define CD_FRAMESIZE_RAW0 (CD_FRAMESIZE_RAW-CD_SYNC_SIZE-CD_HEAD_SIZE) /*2336*/
+
+#define CD_MAX_BYTES       (CD_MINS * CD_SECS * CD_FRAMES * CD_FRAMESIZE)
+#define CD_MAX_SECTORS     (CD_MAX_BYTES / 512)
+
+/*
+ * The MMC values are not IDE specific and might need to be moved
+ * to a common header if they are also needed for the SCSI emulation
+ */
+
+/* Profile list from MMC-6 revision 1 table 91 */
+#define MMC_PROFILE_NONE                0x0000
+#define MMC_PROFILE_CD_ROM              0x0008
+#define MMC_PROFILE_CD_R                0x0009
+#define MMC_PROFILE_CD_RW               0x000A
+#define MMC_PROFILE_DVD_ROM             0x0010
+#define MMC_PROFILE_DVD_R_SR            0x0011
+#define MMC_PROFILE_DVD_RAM             0x0012
+#define MMC_PROFILE_DVD_RW_RO           0x0013
+#define MMC_PROFILE_DVD_RW_SR           0x0014
+#define MMC_PROFILE_DVD_R_DL_SR         0x0015
+#define MMC_PROFILE_DVD_R_DL_JR         0x0016
+#define MMC_PROFILE_DVD_RW_DL           0x0017
+#define MMC_PROFILE_DVD_DDR             0x0018
+#define MMC_PROFILE_DVD_PLUS_RW         0x001A
+#define MMC_PROFILE_DVD_PLUS_R          0x001B
+#define MMC_PROFILE_DVD_PLUS_RW_DL      0x002A
+#define MMC_PROFILE_DVD_PLUS_R_DL       0x002B
+#define MMC_PROFILE_BD_ROM              0x0040
+#define MMC_PROFILE_BD_R_SRM            0x0041
+#define MMC_PROFILE_BD_R_RRM            0x0042
+#define MMC_PROFILE_BD_RE               0x0043
+#define MMC_PROFILE_HDDVD_ROM           0x0050
+#define MMC_PROFILE_HDDVD_R             0x0051
+#define MMC_PROFILE_HDDVD_RAM           0x0052
+#define MMC_PROFILE_HDDVD_RW            0x0053
+#define MMC_PROFILE_HDDVD_R_DL          0x0058
+#define MMC_PROFILE_HDDVD_RW_DL         0x005A
+#define MMC_PROFILE_INVALID             0xFFFF
+
+
+#define ATAPI_INT_REASON_CD             0x01 /* 0 = data transfer */
+#define ATAPI_INT_REASON_IO             0x02 /* 1 = transfer to the host */
+#define ATAPI_INT_REASON_REL            0x04
+#define ATAPI_INT_REASON_TAG            0xf8
+
+/* same constants as bochs */
+#define ASC_NONE                             0x00
+#define ASC_READ_ERROR                       0x11
+#define ASC_ILLEGAL_OPCODE                   0x20
+#define ASC_LOGICAL_BLOCK_OOR                0x21
+#define ASC_INV_FIELD_IN_CMD_PACKET          0x24
+#define ASC_MEDIUM_MAY_HAVE_CHANGED          0x28
+#define ASC_INCOMPATIBLE_FORMAT              0x30
+#define ASC_MEDIUM_NOT_PRESENT               0x3a
+#define ASC_SAVING_PARAMETERS_NOT_SUPPORTED  0x39
+#define ASC_MEDIA_REMOVAL_PREVENTED          0x53
+
+#define CFA_NO_ERROR            0x00
+#define CFA_MISC_ERROR          0x09
+#define CFA_INVALID_COMMAND     0x20
+#define CFA_INVALID_ADDRESS     0x21
+#define CFA_ADDRESS_OVERFLOW    0x2f
+
+/* Sense keys */
+#define SENSE_NONE             0
+#define SENSE_RECOVERED_ERROR  1
+#define SENSE_NOT_READY        2
+#define SENSE_MEDIUM_ERROR     3
+#define SENSE_HARDWARE_ERROR   4
+#define SENSE_ILLEGAL_REQUEST  5
+#define SENSE_UNIT_ATTENTION   6
+#define SENSE_DATA_PROTECT     7
+#define SENSE_BLANK_CHECK      8
+#define SENSE_VENDOR_SPECIFIC  9
+#define SENSE_COPY_ABORTED     10
+#define SENSE_ABORTED_COMMAND  11
+#define SENSE_VOLUME_OVERFLOW  13
+#define SENSE_MISCOMPARE       14
+
+extern const char * const sense_key_texts[16];
+
+const char *atapi_cmd_to_str(int cmd);
+const char *atapi_ascq_to_str(int ascq);
+
+#endif /* !ATAPI_DEFINES_H */
diff --git a/hw/ide.c b/hw/ide.c
index 5c2693e..9db9cb2 100644
--- a/hw/ide.c
+++ b/hw/ide.c
@@ -35,6 +35,8 @@
 #include "mac_dbdma.h"
 #include "sh.h"
 #include "dma.h"
+#include "ide.h"
+#include "atapi-defines.h"
 
 /* debug IDE devices */
 //#define DEBUG_IDE
@@ -42,452 +44,6 @@
 //#define DEBUG_AIO
 #define USE_DMA_CDROM
 
-/* Bits of HD_STATUS */
-#define ERR_STAT		0x01
-#define INDEX_STAT		0x02
-#define ECC_STAT		0x04	/* Corrected error */
-#define DRQ_STAT		0x08
-#define SEEK_STAT		0x10
-#define SRV_STAT		0x10
-#define WRERR_STAT		0x20
-#define READY_STAT		0x40
-#define BUSY_STAT		0x80
-
-/* Bits for HD_ERROR */
-#define MARK_ERR		0x01	/* Bad address mark */
-#define TRK0_ERR		0x02	/* couldn't find track 0 */
-#define ABRT_ERR		0x04	/* Command aborted */
-#define MCR_ERR			0x08	/* media change request */
-#define ID_ERR			0x10	/* ID field not found */
-#define MC_ERR			0x20	/* media changed */
-#define ECC_ERR			0x40	/* Uncorrectable ECC error */
-#define BBD_ERR			0x80	/* pre-EIDE meaning:  block marked bad */
-#define ICRC_ERR		0x80	/* new meaning:  CRC error during transfer */
-
-/* Bits of HD_NSECTOR */
-#define CD			0x01
-#define IO			0x02
-#define REL			0x04
-#define TAG_MASK		0xf8
-
-#define IDE_CMD_RESET           0x04
-#define IDE_CMD_DISABLE_IRQ     0x02
-
-/* ATA/ATAPI Commands pre T13 Spec */
-#define WIN_NOP				0x00
-/*
- *	0x01->0x02 Reserved
- */
-#define CFA_REQ_EXT_ERROR_CODE		0x03 /* CFA Request Extended Error Code */
-/*
- *	0x04->0x07 Reserved
- */
-#define WIN_SRST			0x08 /* ATAPI soft reset command */
-#define WIN_DEVICE_RESET		0x08
-/*
- *	0x09->0x0F Reserved
- */
-#define WIN_RECAL			0x10
-#define WIN_RESTORE			WIN_RECAL
-/*
- *	0x10->0x1F Reserved
- */
-#define WIN_READ			0x20 /* 28-Bit */
-#define WIN_READ_ONCE			0x21 /* 28-Bit without retries */
-#define WIN_READ_LONG			0x22 /* 28-Bit */
-#define WIN_READ_LONG_ONCE		0x23 /* 28-Bit without retries */
-#define WIN_READ_EXT			0x24 /* 48-Bit */
-#define WIN_READDMA_EXT			0x25 /* 48-Bit */
-#define WIN_READDMA_QUEUED_EXT		0x26 /* 48-Bit */
-#define WIN_READ_NATIVE_MAX_EXT		0x27 /* 48-Bit */
-/*
- *	0x28
- */
-#define WIN_MULTREAD_EXT		0x29 /* 48-Bit */
-/*
- *	0x2A->0x2F Reserved
- */
-#define WIN_WRITE			0x30 /* 28-Bit */
-#define WIN_WRITE_ONCE			0x31 /* 28-Bit without retries */
-#define WIN_WRITE_LONG			0x32 /* 28-Bit */
-#define WIN_WRITE_LONG_ONCE		0x33 /* 28-Bit without retries */
-#define WIN_WRITE_EXT			0x34 /* 48-Bit */
-#define WIN_WRITEDMA_EXT		0x35 /* 48-Bit */
-#define WIN_WRITEDMA_QUEUED_EXT		0x36 /* 48-Bit */
-#define WIN_SET_MAX_EXT			0x37 /* 48-Bit */
-#define CFA_WRITE_SECT_WO_ERASE		0x38 /* CFA Write Sectors without erase */
-#define WIN_MULTWRITE_EXT		0x39 /* 48-Bit */
-/*
- *	0x3A->0x3B Reserved
- */
-#define WIN_WRITE_VERIFY		0x3C /* 28-Bit */
-/*
- *	0x3D->0x3F Reserved
- */
-#define WIN_VERIFY			0x40 /* 28-Bit - Read Verify Sectors */
-#define WIN_VERIFY_ONCE			0x41 /* 28-Bit - without retries */
-#define WIN_VERIFY_EXT			0x42 /* 48-Bit */
-/*
- *	0x43->0x4F Reserved
- */
-#define WIN_FORMAT			0x50
-/*
- *	0x51->0x5F Reserved
- */
-#define WIN_INIT			0x60
-/*
- *	0x61->0x5F Reserved
- */
-#define WIN_SEEK			0x70 /* 0x70-0x7F Reserved */
-#define CFA_TRANSLATE_SECTOR		0x87 /* CFA Translate Sector */
-#define WIN_DIAGNOSE			0x90
-#define WIN_SPECIFY			0x91 /* set drive geometry translation */
-#define WIN_DOWNLOAD_MICROCODE		0x92
-#define WIN_STANDBYNOW2			0x94
-#define CFA_IDLEIMMEDIATE		0x95 /* force drive to become "ready" */
-#define WIN_STANDBY2			0x96
-#define WIN_SETIDLE2			0x97
-#define WIN_CHECKPOWERMODE2		0x98
-#define WIN_SLEEPNOW2			0x99
-/*
- *	0x9A VENDOR
- */
-#define WIN_PACKETCMD			0xA0 /* Send a packet command. */
-#define WIN_PIDENTIFY			0xA1 /* identify ATAPI device	*/
-#define WIN_QUEUED_SERVICE		0xA2
-#define WIN_SMART			0xB0 /* self-monitoring and reporting */
-#define CFA_ACCESS_METADATA_STORAGE	0xB8
-#define CFA_ERASE_SECTORS       	0xC0 /* microdrives implement as NOP */
-#define WIN_MULTREAD			0xC4 /* read sectors using multiple mode*/
-#define WIN_MULTWRITE			0xC5 /* write sectors using multiple mode */
-#define WIN_SETMULT			0xC6 /* enable/disable multiple mode */
-#define WIN_READDMA_QUEUED		0xC7 /* read sectors using Queued DMA transfers */
-#define WIN_READDMA			0xC8 /* read sectors using DMA transfers */
-#define WIN_READDMA_ONCE		0xC9 /* 28-Bit - without retries */
-#define WIN_WRITEDMA			0xCA /* write sectors using DMA transfers */
-#define WIN_WRITEDMA_ONCE		0xCB /* 28-Bit - without retries */
-#define WIN_WRITEDMA_QUEUED		0xCC /* write sectors using Queued DMA transfers */
-#define CFA_WRITE_MULTI_WO_ERASE	0xCD /* CFA Write multiple without erase */
-#define WIN_GETMEDIASTATUS		0xDA
-#define WIN_ACKMEDIACHANGE		0xDB /* ATA-1, ATA-2 vendor */
-#define WIN_POSTBOOT			0xDC
-#define WIN_PREBOOT			0xDD
-#define WIN_DOORLOCK			0xDE /* lock door on removable drives */
-#define WIN_DOORUNLOCK			0xDF /* unlock door on removable drives */
-#define WIN_STANDBYNOW1			0xE0
-#define WIN_IDLEIMMEDIATE		0xE1 /* force drive to become "ready" */
-#define WIN_STANDBY             	0xE2 /* Set device in Standby Mode */
-#define WIN_SETIDLE1			0xE3
-#define WIN_READ_BUFFER			0xE4 /* force read only 1 sector */
-#define WIN_CHECKPOWERMODE1		0xE5
-#define WIN_SLEEPNOW1			0xE6
-#define WIN_FLUSH_CACHE			0xE7
-#define WIN_WRITE_BUFFER		0xE8 /* force write only 1 sector */
-#define WIN_WRITE_SAME			0xE9 /* read ata-2 to use */
-	/* SET_FEATURES 0x22 or 0xDD */
-#define WIN_FLUSH_CACHE_EXT		0xEA /* 48-Bit */
-#define WIN_IDENTIFY			0xEC /* ask drive to identify itself	*/
-#define WIN_MEDIAEJECT			0xED
-#define WIN_IDENTIFY_DMA		0xEE /* same as WIN_IDENTIFY, but DMA */
-#define WIN_SETFEATURES			0xEF /* set special drive features */
-#define EXABYTE_ENABLE_NEST		0xF0
-#define IBM_SENSE_CONDITION		0xF0 /* measure disk temperature */
-#define WIN_SECURITY_SET_PASS		0xF1
-#define WIN_SECURITY_UNLOCK		0xF2
-#define WIN_SECURITY_ERASE_PREPARE	0xF3
-#define WIN_SECURITY_ERASE_UNIT		0xF4
-#define WIN_SECURITY_FREEZE_LOCK	0xF5
-#define CFA_WEAR_LEVEL			0xF5 /* microdrives implement as NOP */
-#define WIN_SECURITY_DISABLE		0xF6
-#define WIN_READ_NATIVE_MAX		0xF8 /* return the native maximum address */
-#define WIN_SET_MAX			0xF9
-#define DISABLE_SEAGATE			0xFB
-
-/* set to 1 set disable mult support */
-#define MAX_MULT_SECTORS 16
-
-#define IDE_DMA_BUF_SECTORS 256
-
-#if (IDE_DMA_BUF_SECTORS < MAX_MULT_SECTORS)
-#error "IDE_DMA_BUF_SECTORS must be bigger or equal to MAX_MULT_SECTORS"
-#endif
-
-/* ATAPI defines */
-
-#define ATAPI_PACKET_SIZE 12
-
-/*********************************************************************
- * Generic Packet commands, MMC commands, and such
- *********************************************************************/
-
- /* The generic packet command opcodes for CD/DVD Logical Units,
-  * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
-#define GPCMD_BLANK			    0xa1
-#define GPCMD_CLOSE_TRACK		    0x5b
-#define GPCMD_FLUSH_CACHE		    0x35
-#define GPCMD_FORMAT_UNIT		    0x04
-#define GPCMD_GET_CONFIGURATION             0x46
-#define GPCMD_GET_EVENT_STATUS_NOTIFICATION 0x4a
-#define GPCMD_GET_PERFORMANCE		    0xac
-#define GPCMD_INQUIRY			    0x12
-#define GPCMD_LOAD_UNLOAD		    0xa6
-#define GPCMD_MECHANISM_STATUS		    0xbd
-#define GPCMD_MODE_SELECT_10		    0x55
-#define GPCMD_MODE_SENSE_10		    0x5a
-#define GPCMD_PAUSE_RESUME		    0x4b
-#define GPCMD_PLAY_AUDIO_10		    0x45
-#define GPCMD_PLAY_AUDIO_MSF		    0x47
-#define GPCMD_PLAY_AUDIO_TI		    0x48
-#define GPCMD_PLAY_CD			    0xbc
-#define GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL  0x1e
-#define GPCMD_READ_10			    0x28
-#define GPCMD_READ_12			    0xa8
-#define GPCMD_READ_BUFFER		    0x3c
-#define GPCMD_READ_BUFFER_CAPACITY	    0x5c
-#define GPCMD_READ_CDVD_CAPACITY	    0x25
-#define GPCMD_READ_CD			    0xbe
-#define GPCMD_READ_CD_MSF		    0xb9
-#define GPCMD_READ_DISC_INFO		    0x51
-#define GPCMD_READ_DVD_STRUCTURE	    0xad
-#define GPCMD_READ_FORMAT_CAPACITIES	    0x23
-#define GPCMD_READ_HEADER		    0x44
-#define GPCMD_READ_TRACK_RZONE_INFO	    0x52
-#define GPCMD_READ_SUBCHANNEL	            0x42
-#define GPCMD_READ_TOC_PMA_ATIP             0x43
-#define GPCMD_REPAIR_RZONE_TRACK	    0x58
-#define GPCMD_REPORT_KEY		    0xa4
-#define GPCMD_REQUEST_SENSE		    0x03
-#define GPCMD_RESERVE_RZONE_TRACK	    0x53
-#define GPCMD_SEND_CUE_SHEET		    0x5d
-#define GPCMD_SCAN			    0xba
-#define GPCMD_SEEK			    0x2b
-#define GPCMD_SEND_DVD_STRUCTURE	    0xbf
-#define GPCMD_SEND_EVENT		    0xa2
-#define GPCMD_SEND_KEY			    0xa3
-#define GPCMD_SEND_OPC			    0x54
-#define GPCMD_SET_READ_AHEAD		    0xa7
-#define GPCMD_SET_STREAMING		    0xb6
-#define GPCMD_START_STOP_UNIT		    0x1b
-#define GPCMD_STOP_PLAY_SCAN		    0x4e
-#define GPCMD_TEST_UNIT_READY		    0x00
-#define GPCMD_VERIFY_10                     0x2f
-#define GPCMD_WRITE_10			    0x2a
-#define GPCMD_WRITE_12			    0xaa
-#define GPCMD_WRITE_AND_VERIFY_10	    0x2e
-#define GPCMD_WRITE_BUFFER		    0x3b
-/* This is listed as optional in ATAPI 2.6, but is (curiously)
- * missing from Mt. Fuji, Table 57.  It _is_ mentioned in Mt. Fuji
- * Table 377 as an MMC command for SCSi devices though...  Most ATAPI
- * drives support it. */
-#define GPCMD_SET_SPEED			    0xbb
-/* This seems to be a SCSI specific CD-ROM opcode
- * to play data at track/index */
-#define GPCMD_PLAYAUDIO_TI		    0x48
-/*
- * From MS Media Status Notification Support Specification. For
- * older drives only.
- */
-#define GPCMD_GET_MEDIA_STATUS		    0xda
-#define GPCMD_MODE_SENSE_6                  0x1a
-
-/* Mode page codes for mode sense/set */
-#define GPMODE_VENDOR_PAGE		0x00
-#define GPMODE_R_W_ERROR_PAGE		0x01
-#define GPMODE_WRITE_PARMS_PAGE		0x05
-#define GPMODE_WCACHING_PAGE		0x08
-#define GPMODE_AUDIO_CTL_PAGE		0x0e
-#define GPMODE_POWER_PAGE		0x1a
-#define GPMODE_FAULT_FAIL_PAGE		0x1c
-#define GPMODE_TO_PROTECT_PAGE		0x1d
-#define GPMODE_CAPABILITIES_PAGE	0x2a
-#define GPMODE_ALL_PAGES		0x3f
-/* Not in Mt. Fuji, but in ATAPI 2.6 -- deprecated now in favor
- * of MODE_SENSE_POWER_PAGE */
-#define GPMODE_CDROM_PAGE		0x0d
-
-/*
- * Based on values from <linux/cdrom.h> but extending CD_MINS
- * to the maximum common size allowed by the Orange's Book ATIP
- *
- * 90 and 99 min CDs are also available but using them as the
- * upper limit reduces the effectiveness of the heuristic to
- * detect DVDs burned to less than 25% of their maximum capacity
- */
-
-/* Some generally useful CD-ROM information */
-#define CD_MINS              80 /* max. minutes per CD */
-#define CD_SECS              60 /* seconds per minute */
-#define CD_FRAMES            75 /* frames per second */
-#define CD_SYNC_SIZE         12 /* 12 sync bytes per raw data frame */
-#define CD_MSF_OFFSET       150 /* MSF numbering offset of first frame */
-#define CD_CHUNK_SIZE        24 /* lowest-level "data bytes piece" */
-#define CD_NUM_OF_CHUNKS     98 /* chunks per frame */
-#define CD_FRAMESIZE_SUB     96 /* subchannel data "frame" size */
-#define CD_HEAD_SIZE          4 /* header (address) bytes per raw data frame */
-#define CD_SUBHEAD_SIZE       8 /* subheader bytes per raw XA data frame */
-#define CD_EDC_SIZE           4 /* bytes EDC per most raw data frame types */
-#define CD_ZERO_SIZE          8 /* bytes zero per yellow book mode 1 frame */
-#define CD_ECC_SIZE         276 /* bytes ECC per most raw data frame types */
-#define CD_FRAMESIZE       2048 /* bytes per frame, "cooked" mode */
-#define CD_FRAMESIZE_RAW   2352 /* bytes per frame, "raw" mode */
-#define CD_FRAMESIZE_RAWER 2646 /* The maximum possible returned bytes */
-/* most drives don't deliver everything: */
-#define CD_FRAMESIZE_RAW1 (CD_FRAMESIZE_RAW-CD_SYNC_SIZE) /*2340*/
-#define CD_FRAMESIZE_RAW0 (CD_FRAMESIZE_RAW-CD_SYNC_SIZE-CD_HEAD_SIZE) /*2336*/
-
-#define CD_MAX_BYTES       (CD_MINS * CD_SECS * CD_FRAMES * CD_FRAMESIZE)
-#define CD_MAX_SECTORS     (CD_MAX_BYTES / 512)
-
-/*
- * The MMC values are not IDE specific and might need to be moved
- * to a common header if they are also needed for the SCSI emulation
- */
-
-/* Profile list from MMC-6 revision 1 table 91 */
-#define MMC_PROFILE_NONE                0x0000
-#define MMC_PROFILE_CD_ROM              0x0008
-#define MMC_PROFILE_CD_R                0x0009
-#define MMC_PROFILE_CD_RW               0x000A
-#define MMC_PROFILE_DVD_ROM             0x0010
-#define MMC_PROFILE_DVD_R_SR            0x0011
-#define MMC_PROFILE_DVD_RAM             0x0012
-#define MMC_PROFILE_DVD_RW_RO           0x0013
-#define MMC_PROFILE_DVD_RW_SR           0x0014
-#define MMC_PROFILE_DVD_R_DL_SR         0x0015
-#define MMC_PROFILE_DVD_R_DL_JR         0x0016
-#define MMC_PROFILE_DVD_RW_DL           0x0017
-#define MMC_PROFILE_DVD_DDR             0x0018
-#define MMC_PROFILE_DVD_PLUS_RW         0x001A
-#define MMC_PROFILE_DVD_PLUS_R          0x001B
-#define MMC_PROFILE_DVD_PLUS_RW_DL      0x002A
-#define MMC_PROFILE_DVD_PLUS_R_DL       0x002B
-#define MMC_PROFILE_BD_ROM              0x0040
-#define MMC_PROFILE_BD_R_SRM            0x0041
-#define MMC_PROFILE_BD_R_RRM            0x0042
-#define MMC_PROFILE_BD_RE               0x0043
-#define MMC_PROFILE_HDDVD_ROM           0x0050
-#define MMC_PROFILE_HDDVD_R             0x0051
-#define MMC_PROFILE_HDDVD_RAM           0x0052
-#define MMC_PROFILE_HDDVD_RW            0x0053
-#define MMC_PROFILE_HDDVD_R_DL          0x0058
-#define MMC_PROFILE_HDDVD_RW_DL         0x005A
-#define MMC_PROFILE_INVALID             0xFFFF
-
-
-#define ATAPI_INT_REASON_CD             0x01 /* 0 = data transfer */
-#define ATAPI_INT_REASON_IO             0x02 /* 1 = transfer to the host */
-#define ATAPI_INT_REASON_REL            0x04
-#define ATAPI_INT_REASON_TAG            0xf8
-
-/* same constants as bochs */
-#define ASC_NONE                             0x00
-#define ASC_READ_ERROR                       0x11
-#define ASC_ILLEGAL_OPCODE                   0x20
-#define ASC_LOGICAL_BLOCK_OOR                0x21
-#define ASC_INV_FIELD_IN_CMD_PACKET          0x24
-#define ASC_MEDIUM_MAY_HAVE_CHANGED          0x28
-#define ASC_INCOMPATIBLE_FORMAT              0x30
-#define ASC_MEDIUM_NOT_PRESENT               0x3a
-#define ASC_SAVING_PARAMETERS_NOT_SUPPORTED  0x39
-#define ASC_MEDIA_REMOVAL_PREVENTED          0x53
-
-#define CFA_NO_ERROR            0x00
-#define CFA_MISC_ERROR          0x09
-#define CFA_INVALID_COMMAND     0x20
-#define CFA_INVALID_ADDRESS     0x21
-#define CFA_ADDRESS_OVERFLOW    0x2f
-
-/* Sense keys */
-#define SENSE_NONE             0
-#define SENSE_RECOVERED_ERROR  1
-#define SENSE_NOT_READY        2
-#define SENSE_MEDIUM_ERROR     3
-#define SENSE_HARDWARE_ERROR   4
-#define SENSE_ILLEGAL_REQUEST  5
-#define SENSE_UNIT_ATTENTION   6
-#define SENSE_DATA_PROTECT     7
-#define SENSE_BLANK_CHECK      8
-#define SENSE_VENDOR_SPECIFIC  9
-#define SENSE_COPY_ABORTED     10
-#define SENSE_ABORTED_COMMAND  11
-#define SENSE_VOLUME_OVERFLOW  13
-#define SENSE_MISCOMPARE       14
-
-#define IO_BUFFER_MAX_SIZE      (IDE_DMA_BUF_SECTORS * 512 + 4)
-
-struct IDEState;
-
-typedef void EndTransferFunc(struct IDEState *);
-
-/* NOTE: IDEState represents in fact one drive */
-typedef struct IDEState {
-    /* ide config */
-    int is_cdrom;
-    int is_cf;
-    int cylinders, heads, sectors;
-    int64_t nb_sectors;
-    int mult_sectors;
-    int identify_set;
-    uint16_t identify_data[256];
-    qemu_irq irq;
-    PCIDevice *pci_dev;
-    struct BMDMAState *bmdma;
-    int drive_serial;
-    char drive_serial_str[21];
-    /* ide regs */
-    uint8_t feature;
-    uint8_t error;
-    uint32_t nsector;
-    uint8_t sector;
-    uint8_t lcyl;
-    uint8_t hcyl;
-    /* other part of tf for lba48 support */
-    uint8_t hob_feature;
-    uint8_t hob_nsector;
-    uint8_t hob_sector;
-    uint8_t hob_lcyl;
-    uint8_t hob_hcyl;
-
-    uint8_t select;
-    uint8_t status;
-
-    /* 0x3f6 command, only meaningful for drive 0 */
-    uint8_t cmd;
-    /* set for lba48 access */
-    uint8_t lba48;
-    /* depends on bit 4 in select, only meaningful for drive 0 */
-    struct IDEState *cur_drive;
-    BlockDriverState *bs;
-    /* ATAPI specific */
-    uint8_t sense_key;
-    uint8_t asc;
-    int packet_transfer_size;
-    int elementary_transfer_size;
-    int io_buffer_index;
-    int lba;
-    int cd_sector_size;
-    int atapi_dma; /* true if dma is requested for the packet cmd */
-    /* ATA DMA state */
-    int io_buffer_size;
-    QEMUSGList sg;
-    /* PIO transfer handling */
-    int req_nb_sectors; /* number of sectors per interrupt */
-    EndTransferFunc *end_transfer_func;
-    uint8_t *data_ptr;
-    uint8_t *data_end;
-    uint8_t *io_buffer;
-    QEMUTimer *sector_write_timer; /* only used for win2k install hack */
-    uint32_t irq_count; /* counts IRQs when using win2k install hack */
-    /* CF-ATA extended error */
-    uint8_t ext_error;
-    /* CF-ATA metadata storage */
-    uint32_t mdata_size;
-    uint8_t *mdata_storage;
-    int media_changed;
-    /* for pmac */
-    int is_read;
-} IDEState;
-
 /* XXX: DVDs that could fit on a CD will be reported as a CD */
 static inline int media_present(IDEState *s)
 {
@@ -504,59 +60,9 @@ static inline int media_is_cd(IDEState *s)
     return (media_present(s) && s->nb_sectors <= CD_MAX_SECTORS);
 }
 
-#define BM_STATUS_DMAING 0x01
-#define BM_STATUS_ERROR  0x02
-#define BM_STATUS_INT    0x04
-#define BM_STATUS_DMA_RETRY  0x08
-#define BM_STATUS_PIO_RETRY  0x10
-
-#define BM_CMD_START     0x01
-#define BM_CMD_READ      0x08
-
-#define IDE_TYPE_PIIX3   0
-#define IDE_TYPE_CMD646  1
-#define IDE_TYPE_PIIX4   2
-
-/* CMD646 specific */
-#define MRDMODE		0x71
-#define   MRDMODE_INTR_CH0	0x04
-#define   MRDMODE_INTR_CH1	0x08
-#define   MRDMODE_BLK_CH0	0x10
-#define   MRDMODE_BLK_CH1	0x20
-#define UDIDETCR0	0x73
-#define UDIDETCR1	0x7B
-
-typedef struct BMDMAState {
-    uint8_t cmd;
-    uint8_t status;
-    uint32_t addr;
-
-    struct PCIIDEState *pci_dev;
-    /* current transfer state */
-    uint32_t cur_addr;
-    uint32_t cur_prd_last;
-    uint32_t cur_prd_addr;
-    uint32_t cur_prd_len;
-    IDEState *ide_if;
-    BlockDriverCompletionFunc *dma_cb;
-    BlockDriverAIOCB *aiocb;
-    struct iovec iov;
-    QEMUIOVector qiov;
-    int64_t sector_num;
-    uint32_t nsector;
-    QEMUBH *bh;
-} BMDMAState;
-
-typedef struct PCIIDEState {
-    PCIDevice dev;
-    IDEState ide_if[4];
-    BMDMAState bmdma[2];
-    int type; /* see IDE_TYPE_xxx */
-} PCIIDEState;
-
-static void ide_dma_start(IDEState *s, BlockDriverCompletionFunc *dma_cb);
 static void ide_dma_restart(IDEState *s);
 static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret);
+static void ide_atapi_cmd_error(IDEState *s, int sense_key, int asc);
 
 static void padstr(char *str, const char *src, int len)
 {
@@ -655,7 +161,7 @@ static void ide_identify(IDEState *s)
     s->identify_set = 1;
 }
 
-static void ide_atapi_identify(IDEState *s)
+void ide_atapi_identify(IDEState *s)
 {
     uint16_t *p;
 
@@ -801,7 +307,7 @@ static inline void ide_dma_submit_check(IDEState *s,
     dma_cb(bm, -1);
 }
 
-static inline void ide_set_irq(IDEState *s)
+void ide_set_irq(IDEState *s)
 {
     BMDMAState *bm = s->bmdma;
     if (!(s->cmd & IDE_CMD_DISABLE_IRQ)) {
@@ -813,8 +319,8 @@ static inline void ide_set_irq(IDEState *s)
 }
 
 /* prepare data transfer and tell what to do after */
-static void ide_transfer_start(IDEState *s, uint8_t *buf, int size,
-                               EndTransferFunc *end_transfer_func)
+void ide_transfer_start(IDEState *s, uint8_t *buf, int size,
+                        EndTransferFunc *end_transfer_func)
 {
     s->end_transfer_func = end_transfer_func;
     s->data_ptr = buf;
@@ -823,7 +329,7 @@ static void ide_transfer_start(IDEState *s, uint8_t *buf, int size,
         s->status |= DRQ_STAT;
 }
 
-static void ide_transfer_stop(IDEState *s)
+void ide_transfer_stop(IDEState *s)
 {
     s->end_transfer_func = ide_transfer_stop;
     s->data_ptr = s->io_buffer;
@@ -994,7 +500,7 @@ static int ide_handle_write_error(IDEState *s, int error, int op)
 }
 
 /* return 0 if buffer completed */
-static int dma_buf_rw(BMDMAState *bm, int is_write)
+int dma_buf_rw(BMDMAState *bm, int is_write)
 {
     IDEState *s = bm->ide_if;
     struct {
@@ -1237,7 +743,7 @@ static void ide_sector_write_dma(IDEState *s)
     ide_dma_start(s, ide_write_dma_cb);
 }
 
-static void ide_atapi_cmd_ok(IDEState *s)
+void ide_atapi_cmd_ok(IDEState *s)
 {
     s->error = 0;
     s->status = READY_STAT | SEEK_STAT;
@@ -1269,30 +775,6 @@ static void ide_atapi_cmd_check_status(IDEState *s)
     ide_set_irq(s);
 }
 
-static inline void cpu_to_ube16(uint8_t *buf, int val)
-{
-    buf[0] = val >> 8;
-    buf[1] = val & 0xff;
-}
-
-static inline void cpu_to_ube32(uint8_t *buf, unsigned int val)
-{
-    buf[0] = val >> 24;
-    buf[1] = val >> 16;
-    buf[2] = val >> 8;
-    buf[3] = val & 0xff;
-}
-
-static inline int ube16_to_cpu(const uint8_t *buf)
-{
-    return (buf[0] << 8) | buf[1];
-}
-
-static inline int ube32_to_cpu(const uint8_t *buf)
-{
-    return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
-}
-
 static void lba_to_msf(uint8_t *buf, int lba)
 {
     lba += 150;
@@ -1340,7 +822,7 @@ static int cd_read_sector(BlockDriverState *bs, int lba, uint8_t *buf,
     return ret;
 }
 
-static void ide_atapi_io_error(IDEState *s, int ret)
+void ide_atapi_io_error(IDEState *s, int ret)
 {
     /* XXX: handle more errors */
     if (ret == -ENOMEDIUM) {
@@ -1432,7 +914,7 @@ static void ide_atapi_cmd_reply_end(IDEState *s)
 }
 
 /* send a reply of 'size' bytes in s->io_buffer to an ATAPI command */
-static void ide_atapi_cmd_reply(IDEState *s, int size, int max_size)
+void ide_atapi_cmd_reply(IDEState *s, int size, int max_size)
 {
     if (size > max_size)
         size = max_size;
@@ -3003,7 +2485,7 @@ static void ide_map(PCIDevice *pci_dev, int region_num,
     }
 }
 
-static void ide_dma_start(IDEState *s, BlockDriverCompletionFunc *dma_cb)
+void ide_dma_start(IDEState *s, BlockDriverCompletionFunc *dma_cb)
 {
     BMDMAState *bm = s->bmdma;
     if(!bm)
diff --git a/hw/ide.h b/hw/ide.h
new file mode 100644
index 0000000..064e2d3
--- /dev/null
+++ b/hw/ide.h
@@ -0,0 +1,377 @@
+/*
+ * QEMU IDE disk and CD/DVD-ROM Emulator definitions
+ *
+ * Copyright (c) 2009 Alexandre Bique
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef IDE_H
+#define IDE_H
+
+#include "hw.h"
+#include "pc.h"
+#include "pci.h"
+#include "scsi-disk.h"
+#include "pcmcia.h"
+#include "block.h"
+#include "block_int.h"
+#include "qemu-timer.h"
+#include "sysemu.h"
+#include "ppc_mac.h"
+#include "mac_dbdma.h"
+#include "sh.h"
+#include "dma.h"
+#include "atapi-defines.h"
+
+#include <stdint.h>
+
+/* Bits of HD_STATUS */
+#define ERR_STAT		0x01
+#define INDEX_STAT		0x02
+#define ECC_STAT		0x04	/* Corrected error */
+#define DRQ_STAT		0x08
+#define SEEK_STAT		0x10
+#define SRV_STAT		0x10
+#define WRERR_STAT		0x20
+#define READY_STAT		0x40
+#define BUSY_STAT		0x80
+
+/* Bits for HD_ERROR */
+#define MARK_ERR		0x01	/* Bad address mark */
+#define TRK0_ERR		0x02	/* couldn't find track 0 */
+#define ABRT_ERR		0x04	/* Command aborted */
+#define MCR_ERR			0x08	/* media change request */
+#define ID_ERR			0x10	/* ID field not found */
+#define MC_ERR			0x20	/* media changed */
+#define ECC_ERR			0x40	/* Uncorrectable ECC error */
+#define BBD_ERR			0x80	/* pre-EIDE meaning:  block marked bad */
+#define ICRC_ERR		0x80	/* new meaning:  CRC error during transfer */
+
+/* Bits of HD_NSECTOR */
+#define CD			0x01
+#define IO			0x02
+#define REL			0x04
+#define TAG_MASK		0xf8
+
+#define IDE_CMD_RESET           0x04
+#define IDE_CMD_DISABLE_IRQ     0x02
+
+/* ATA/ATAPI Commands pre T13 Spec */
+#define WIN_NOP				0x00
+/*
+ *	0x01->0x02 Reserved
+ */
+#define CFA_REQ_EXT_ERROR_CODE		0x03 /* CFA Request Extended Error Code */
+/*
+ *	0x04->0x07 Reserved
+ */
+#define WIN_SRST			0x08 /* ATAPI soft reset command */
+#define WIN_DEVICE_RESET		0x08
+/*
+ *	0x09->0x0F Reserved
+ */
+#define WIN_RECAL			0x10
+#define WIN_RESTORE			WIN_RECAL
+/*
+ *	0x10->0x1F Reserved
+ */
+#define WIN_READ			0x20 /* 28-Bit */
+#define WIN_READ_ONCE			0x21 /* 28-Bit without retries */
+#define WIN_READ_LONG			0x22 /* 28-Bit */
+#define WIN_READ_LONG_ONCE		0x23 /* 28-Bit without retries */
+#define WIN_READ_EXT			0x24 /* 48-Bit */
+#define WIN_READDMA_EXT			0x25 /* 48-Bit */
+#define WIN_READDMA_QUEUED_EXT		0x26 /* 48-Bit */
+#define WIN_READ_NATIVE_MAX_EXT		0x27 /* 48-Bit */
+/*
+ *	0x28
+ */
+#define WIN_MULTREAD_EXT		0x29 /* 48-Bit */
+/*
+ *	0x2A->0x2F Reserved
+ */
+#define WIN_WRITE			0x30 /* 28-Bit */
+#define WIN_WRITE_ONCE			0x31 /* 28-Bit without retries */
+#define WIN_WRITE_LONG			0x32 /* 28-Bit */
+#define WIN_WRITE_LONG_ONCE		0x33 /* 28-Bit without retries */
+#define WIN_WRITE_EXT			0x34 /* 48-Bit */
+#define WIN_WRITEDMA_EXT		0x35 /* 48-Bit */
+#define WIN_WRITEDMA_QUEUED_EXT		0x36 /* 48-Bit */
+#define WIN_SET_MAX_EXT			0x37 /* 48-Bit */
+#define CFA_WRITE_SECT_WO_ERASE		0x38 /* CFA Write Sectors without erase */
+#define WIN_MULTWRITE_EXT		0x39 /* 48-Bit */
+/*
+ *	0x3A->0x3B Reserved
+ */
+#define WIN_WRITE_VERIFY		0x3C /* 28-Bit */
+/*
+ *	0x3D->0x3F Reserved
+ */
+#define WIN_VERIFY			0x40 /* 28-Bit - Read Verify Sectors */
+#define WIN_VERIFY_ONCE			0x41 /* 28-Bit - without retries */
+#define WIN_VERIFY_EXT			0x42 /* 48-Bit */
+/*
+ *	0x43->0x4F Reserved
+ */
+#define WIN_FORMAT			0x50
+/*
+ *	0x51->0x5F Reserved
+ */
+#define WIN_INIT			0x60
+/*
+ *	0x61->0x5F Reserved
+ */
+#define WIN_SEEK			0x70 /* 0x70-0x7F Reserved */
+#define CFA_TRANSLATE_SECTOR		0x87 /* CFA Translate Sector */
+#define WIN_DIAGNOSE			0x90
+#define WIN_SPECIFY			0x91 /* set drive geometry translation */
+#define WIN_DOWNLOAD_MICROCODE		0x92
+#define WIN_STANDBYNOW2			0x94
+#define CFA_IDLEIMMEDIATE		0x95 /* force drive to become "ready" */
+#define WIN_STANDBY2			0x96
+#define WIN_SETIDLE2			0x97
+#define WIN_CHECKPOWERMODE2		0x98
+#define WIN_SLEEPNOW2			0x99
+/*
+ *	0x9A VENDOR
+ */
+#define WIN_PACKETCMD			0xA0 /* Send a packet command. */
+#define WIN_PIDENTIFY			0xA1 /* identify ATAPI device	*/
+#define WIN_QUEUED_SERVICE		0xA2
+#define WIN_SMART			0xB0 /* self-monitoring and reporting */
+#define CFA_ACCESS_METADATA_STORAGE	0xB8
+#define CFA_ERASE_SECTORS       	0xC0 /* microdrives implement as NOP */
+#define WIN_MULTREAD			0xC4 /* read sectors using multiple mode*/
+#define WIN_MULTWRITE			0xC5 /* write sectors using multiple mode */
+#define WIN_SETMULT			0xC6 /* enable/disable multiple mode */
+#define WIN_READDMA_QUEUED		0xC7 /* read sectors using Queued DMA transfers */
+#define WIN_READDMA			0xC8 /* read sectors using DMA transfers */
+#define WIN_READDMA_ONCE		0xC9 /* 28-Bit - without retries */
+#define WIN_WRITEDMA			0xCA /* write sectors using DMA transfers */
+#define WIN_WRITEDMA_ONCE		0xCB /* 28-Bit - without retries */
+#define WIN_WRITEDMA_QUEUED		0xCC /* write sectors using Queued DMA transfers */
+#define CFA_WRITE_MULTI_WO_ERASE	0xCD /* CFA Write multiple without erase */
+#define WIN_GETMEDIASTATUS		0xDA
+#define WIN_ACKMEDIACHANGE		0xDB /* ATA-1, ATA-2 vendor */
+#define WIN_POSTBOOT			0xDC
+#define WIN_PREBOOT			0xDD
+#define WIN_DOORLOCK			0xDE /* lock door on removable drives */
+#define WIN_DOORUNLOCK			0xDF /* unlock door on removable drives */
+#define WIN_STANDBYNOW1			0xE0
+#define WIN_IDLEIMMEDIATE		0xE1 /* force drive to become "ready" */
+#define WIN_STANDBY             	0xE2 /* Set device in Standby Mode */
+#define WIN_SETIDLE1			0xE3
+#define WIN_READ_BUFFER			0xE4 /* force read only 1 sector */
+#define WIN_CHECKPOWERMODE1		0xE5
+#define WIN_SLEEPNOW1			0xE6
+#define WIN_FLUSH_CACHE			0xE7
+#define WIN_WRITE_BUFFER		0xE8 /* force write only 1 sector */
+#define WIN_WRITE_SAME			0xE9 /* read ata-2 to use */
+	/* SET_FEATURES 0x22 or 0xDD */
+#define WIN_FLUSH_CACHE_EXT		0xEA /* 48-Bit */
+#define WIN_IDENTIFY			0xEC /* ask drive to identify itself	*/
+#define WIN_MEDIAEJECT			0xED
+#define WIN_IDENTIFY_DMA		0xEE /* same as WIN_IDENTIFY, but DMA */
+#define WIN_SETFEATURES			0xEF /* set special drive features */
+#define EXABYTE_ENABLE_NEST		0xF0
+#define IBM_SENSE_CONDITION		0xF0 /* measure disk temperature */
+#define WIN_SECURITY_SET_PASS		0xF1
+#define WIN_SECURITY_UNLOCK		0xF2
+#define WIN_SECURITY_ERASE_PREPARE	0xF3
+#define WIN_SECURITY_ERASE_UNIT		0xF4
+#define WIN_SECURITY_FREEZE_LOCK	0xF5
+#define CFA_WEAR_LEVEL			0xF5 /* microdrives implement as NOP */
+#define WIN_SECURITY_DISABLE		0xF6
+#define WIN_READ_NATIVE_MAX		0xF8 /* return the native maximum address */
+#define WIN_SET_MAX			0xF9
+#define DISABLE_SEAGATE			0xFB
+
+/* set to 1 set disable mult support */
+#define MAX_MULT_SECTORS 16
+
+#define IDE_DMA_BUF_SECTORS 256
+
+#if (IDE_DMA_BUF_SECTORS < MAX_MULT_SECTORS)
+#error "IDE_DMA_BUF_SECTORS must be bigger or equal to MAX_MULT_SECTORS"
+#endif
+
+#define IO_BUFFER_MAX_SIZE      (IDE_DMA_BUF_SECTORS * 512 + 4)
+
+struct IDEState;
+
+typedef void EndTransferFunc(struct IDEState *);
+
+/* NOTE: IDEState represents in fact one drive */
+typedef struct IDEState {
+    /* ide config */
+    int is_cdrom;
+    int is_cf;
+    int cylinders, heads, sectors;
+    int64_t nb_sectors;
+    int mult_sectors;
+    int identify_set;
+    uint16_t identify_data[256];
+    qemu_irq irq;
+    PCIDevice *pci_dev;
+    struct BMDMAState *bmdma;
+    int drive_serial;
+    char drive_serial_str[21];
+    /* ide regs */
+    uint8_t feature;
+    uint8_t error;
+    uint32_t nsector;
+    uint8_t sector;
+    uint8_t lcyl;
+    uint8_t hcyl;
+    /* other part of tf for lba48 support */
+    uint8_t hob_feature;
+    uint8_t hob_nsector;
+    uint8_t hob_sector;
+    uint8_t hob_lcyl;
+    uint8_t hob_hcyl;
+
+    uint8_t select;
+    uint8_t status;
+
+    /* 0x3f6 command, only meaningful for drive 0 */
+    uint8_t cmd;
+    /* set for lba48 access */
+    uint8_t lba48;
+    /* depends on bit 4 in select, only meaningful for drive 0 */
+    struct IDEState *cur_drive;
+    BlockDriverState *bs;
+    /* ATAPI specific */
+    uint8_t sense_key;
+    uint8_t asc;
+    int packet_transfer_size;
+    int elementary_transfer_size;
+    int io_buffer_index;
+    int lba;
+    int cd_sector_size;
+    int atapi_dma; /* true if dma is requested for the packet cmd */
+    /* ATA DMA state */
+    int io_buffer_size;
+    QEMUSGList sg;
+    /* PIO transfer handling */
+    int req_nb_sectors; /* number of sectors per interrupt */
+    EndTransferFunc *end_transfer_func;
+    uint8_t *data_ptr;
+    uint8_t *data_end;
+    uint8_t *io_buffer;
+    QEMUTimer *sector_write_timer; /* only used for win2k install hack */
+    uint32_t irq_count; /* counts IRQs when using win2k install hack */
+    /* CF-ATA extended error */
+    uint8_t ext_error;
+    /* CF-ATA metadata storage */
+    uint32_t mdata_size;
+    uint8_t *mdata_storage;
+    int media_changed;
+    /* for pmac */
+    int is_read;
+} IDEState;
+
+#define BM_STATUS_DMAING 0x01
+#define BM_STATUS_ERROR  0x02
+#define BM_STATUS_INT    0x04
+#define BM_STATUS_DMA_RETRY  0x08
+#define BM_STATUS_PIO_RETRY  0x10
+
+#define BM_CMD_START     0x01
+#define BM_CMD_READ      0x08
+
+#define IDE_TYPE_PIIX3   0
+#define IDE_TYPE_CMD646  1
+#define IDE_TYPE_PIIX4   2
+
+/* CMD646 specific */
+#define MRDMODE		0x71
+#define   MRDMODE_INTR_CH0	0x04
+#define   MRDMODE_INTR_CH1	0x08
+#define   MRDMODE_BLK_CH0	0x10
+#define   MRDMODE_BLK_CH1	0x20
+#define UDIDETCR0	0x73
+#define UDIDETCR1	0x7B
+
+typedef struct BMDMAState {
+    uint8_t cmd;
+    uint8_t status;
+    uint32_t addr;
+
+    struct PCIIDEState *pci_dev;
+    /* current transfer state */
+    uint32_t cur_addr;
+    uint32_t cur_prd_last;
+    uint32_t cur_prd_addr;
+    uint32_t cur_prd_len;
+    IDEState *ide_if;
+    BlockDriverCompletionFunc *dma_cb;
+    BlockDriverAIOCB *aiocb;
+    struct iovec iov;
+    QEMUIOVector qiov;
+    int64_t sector_num;
+    uint32_t nsector;
+    QEMUBH *bh;
+} BMDMAState;
+
+typedef struct PCIIDEState {
+    PCIDevice dev;
+    IDEState ide_if[4];
+    BMDMAState bmdma[2];
+    int type; /* see IDE_TYPE_xxx */
+} PCIIDEState;
+
+void ide_set_irq(IDEState *s);
+void ide_atapi_cmd_ok(IDEState *s);
+void ide_transfer_stop(IDEState *s);
+void ide_atapi_io_error(IDEState *s, int ret);
+int  dma_buf_rw(BMDMAState *bm, int is_write);
+void ide_atapi_identify(IDEState *s);
+void ide_dma_start(IDEState *s, BlockDriverCompletionFunc *dma_cb);
+void ide_transfer_start(IDEState *s, uint8_t *buf, int size,
+                        EndTransferFunc *end_transfer_func);
+void ide_atapi_cmd_reply(IDEState *s, int size, int max_size);
+
+static inline void cpu_to_ube16(uint8_t *buf, int val)
+{
+    buf[0] = val >> 8;
+    buf[1] = val & 0xff;
+}
+
+static inline void cpu_to_ube32(uint8_t *buf, unsigned int val)
+{
+    buf[0] = val >> 24;
+    buf[1] = val >> 16;
+    buf[2] = val >> 8;
+    buf[3] = val & 0xff;
+}
+
+static inline int ube16_to_cpu(const uint8_t *buf)
+{
+    return (buf[0] << 8) | buf[1];
+}
+
+static inline int ube32_to_cpu(const uint8_t *buf)
+{
+    return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
+}
+
+
+#endif /* !IDE_H */
+
-- 
1.6.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH 7/7] atapi: introducing atapi pass through
  2009-08-07 17:33           ` [Qemu-devel] [PATCH 6/7] atapi: made some part of ide.c public and moved some part to atapi Alexandre Bique
@ 2009-08-07 17:33             ` Alexandre Bique
  0 siblings, 0 replies; 10+ messages in thread
From: Alexandre Bique @ 2009-08-07 17:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Alexandre Bique

This patch introduce atapi pass through. The pass through code is used
by default when the underlying block is a scsi device.

This brings 1 new option to the command line interface:
 -cdrom-allow-fw-upgrade which allow to pass through the firmware
upgrade which is blocked by default. See the WRITE_BUFFER command for
more details.

Signed-off-by: Alexandre Bique <alexandre.bique@citrix.com>
---
 Makefile.target |   14 +-
 hw/atapi-pt.c   |  796 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/atapi-pt.h   |   35 +++
 hw/ide.c        |   31 +--
 hw/ide.h        |  104 ++++++--
 qemu-options.hx |    7 +
 vl.c            |    5 +
 7 files changed, 952 insertions(+), 40 deletions(-)
 create mode 100644 hw/atapi-pt.c
 create mode 100644 hw/atapi-pt.h

diff --git a/Makefile.target b/Makefile.target
index 49ba08d..cf0cb27 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -327,7 +327,7 @@ obj-y += e1000.o
 obj-y += wdt_ib700.o wdt_i6300esb.o
 
 # Hardware support
-obj-i386-y = ide.o pckbd.o vga.o $(sound-obj-y) dma.o
+obj-i386-y = ide.o atapi-pt.o atapi-data.o pckbd.o vga.o $(sound-obj-y) dma.o
 obj-i386-y += fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o
 obj-i386-y += cirrus_vga.o apic.o ioapic.o parallel.o acpi.o piix_pci.o
 obj-i386-y += usb-uhci.o vmmouse.o vmport.o vmware_vga.o hpet.o
@@ -338,7 +338,8 @@ CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
 endif
 
 # shared objects
-obj-ppc-y = ppc.o ide.o vga.o $(sound-obj-y) dma.o openpic.o
+obj-ppc-y = ppc.o ide.o atapi-pt.o atapi-data.o
+obj-ppc-y += vga.o $(sound-obj-y) dma.o openpic.o
 # PREP target
 obj-ppc-y += pckbd.o serial.o i8259.o i8254.o fdc.o mc146818rtc.o
 obj-ppc-y += prep_pci.o ppc_prep.o
@@ -365,7 +366,8 @@ LIBS+= $(FDT_LIBS)
 obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
 obj-mips-y += mips_timer.o mips_int.o dma.o vga.o serial.o i8254.o i8259.o rc4030.o
 obj-mips-y += g364fb.o jazz_led.o dp8393x.o
-obj-mips-y += ide.o gt64xxx.o pckbd.o fdc.o mc146818rtc.o usb-uhci.o acpi.o ds1225y.o
+obj-mips-y += ide.o  atapi-pt.o atapi-data.o gt64xxx.o
+obj-mips-y += pckbd.o fdc.o mc146818rtc.o usb-uhci.o acpi.o ds1225y.o
 obj-mips-y += piix_pci.o parallel.o cirrus_vga.o pcspk.o $(sound-obj-y)
 obj-mips-y += mipsnet.o
 obj-mips-y += pflash_cfi01.o
@@ -401,7 +403,7 @@ obj-cris-y += etraxfs_ser.o
 obj-cris-y += pflash_cfi02.o
 
 ifeq ($(TARGET_ARCH), sparc64)
-obj-sparc-y = sun4u.o ide.o pckbd.o vga.o apb_pci.o
+obj-sparc-y = sun4u.o ide.o atapi-pt.o atapi-data.o pckbd.o vga.o apb_pci.o
 obj-sparc-y += fdc.o mc146818rtc.o serial.o
 obj-sparc-y += cirrus_vga.o parallel.o
 else
@@ -420,7 +422,7 @@ obj-arm-y += arm-semi.o
 obj-arm-y += pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o
 obj-arm-y += pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o
 obj-arm-y += pflash_cfi01.o gumstix.o
-obj-arm-y += zaurus.o ide.o serial.o spitz.o tosa.o tc6393xb.o
+obj-arm-y += zaurus.o ide.o atapi-pt.o atapi-data.o serial.o spitz.o tosa.o tc6393xb.o
 obj-arm-y += omap1.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o
 obj-arm-y += omap2.o omap_dss.o soc_dma.o
 obj-arm-y += omap_sx1.o palm.o tsc210x.o
@@ -438,7 +440,7 @@ endif
 
 obj-sh4-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o
 obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o serial.o
-obj-sh4-y += ide.o
+obj-sh4-y += ide.o atapi-pt.o atapi-data.o
 
 obj-m68k-y = an5206.o mcf5206.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o
 obj-m68k-y += m68k-semi.o dummy_m68k.o
diff --git a/hw/atapi-pt.c b/hw/atapi-pt.c
new file mode 100644
index 0000000..abb5c26
--- /dev/null
+++ b/hw/atapi-pt.c
@@ -0,0 +1,796 @@
+/*
+ * ATAPI pass through implementation
+ *
+ * Copyright (c) 2009 Alexandre Bique
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "block.h"
+#include "atapi-defines.h"
+#include "atapi-pt.h"
+
+int atapi_pt_allow_fw_upgrade = 0;
+
+#define DEBUG_IDE_ATAPI_PT
+
+#ifdef DEBUG_IDE_ATAPI_PT
+# define DPRINTF(Args...) printf(Args)
+# define CHECK_EQUAL(Val1, Val2)                                        \
+    do {                                                                \
+        if ((Val1) != (Val2))                                           \
+            printf("[\e[1;32m!VALUE\e[m] %s:%d, %s=%d %s=%d\n",         \
+                   __PRETTY_FUNCTION__, __LINE__, #Val1, (Val1),        \
+                   #Val2, (Val2));                                      \
+    } while (0)
+#else
+# define DPRINTF(Args...)
+# define CHECK_EQUAL(Val1, Val2)
+#endif /* DEBUG_IDE_ATAPI_PT */
+
+static inline uint32_t msf_to_frames(uint32_t minutes,
+                                     uint32_t seconds,
+                                     uint32_t frames)
+{
+    return (minutes * CD_SECS + seconds) * CD_FRAMES + frames;
+}
+
+static void ide_atapi_pt_set_error(IDEState *s, int sense_key, int asc, int error)
+{
+    s->atapi_pt.sense.sense_key  = sense_key;
+    s->atapi_pt.sense.asc        = asc;
+    s->atapi_pt.sense.error_code = error;
+    s->status  = READY_STAT | ERR_STAT;
+    s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
+    ide_set_irq(s);
+}
+
+static void ide_atapi_pt_error(IDEState *s)
+{
+    s->status  = READY_STAT | ERR_STAT;
+    s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
+    ide_set_irq(s);
+}
+
+static void ide_atapi_pt_sg_io_finished(void *opaque, int ret)
+{
+    IDEState *s = opaque;
+
+    if (ret) {
+        DPRINTF("IO error\n");
+        ide_atapi_pt_error(s);
+        return;
+    }
+
+    if (s->atapi_pt.cmd.driver_status ||
+        s->atapi_pt.cmd.host_status ||
+        s->atapi_pt.cmd.status)
+    {
+        DPRINTF("[\e[1;31mERROR\e[m]\n"
+                "\tsense_key: 0x%02x (\e[0;35m%s\e[m)\n"
+                "\terror: 0x%02x\n"
+                "\tasc: 0x%02x, 0x%x (\e[0;35m%s\e[m)\n"
+                "\terrno: %d (%s)\n"
+                "\tdriver: %d, host: %d, status: %d\n",
+                s->atapi_pt.sense.sense_key,
+                sense_key_texts[s->atapi_pt.sense.sense_key],
+                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),
+                errno,
+                strerror(errno) ? : "(null)",
+                s->atapi_pt.cmd.driver_status,
+                s->atapi_pt.cmd.host_status,
+                s->atapi_pt.cmd.status);
+        ide_atapi_pt_error(s);
+        return;
+    }
+    s->atapi_pt.cmd_sent(s);
+}
+
+static void ide_atapi_pt_send_packet(IDEState *s)
+{
+    DPRINTF("[ATAPI-PT] sending command: 0x%02x (\e[0;32m%s\e[m)\n",
+            s->atapi_pt.request[0], atapi_cmd_to_str(s->atapi_pt.request[0]));
+    bdrv_aio_ioctl(s->bs, SG_IO, &s->atapi_pt.cmd,
+                   ide_atapi_pt_sg_io_finished, s);
+}
+
+static void ide_atapi_pt_read_finish(IDEState *s)
+{
+    s->atapi_pt.cmd.dxferp = s->io_buffer;
+    s->atapi_pt.cmd_sent = ide_atapi_cmd_ok;
+    ide_atapi_pt_send_packet(s);
+}
+
+static void ide_atapi_pt_read_pio_end(IDEState *s)
+{
+    ide_transfer_stop(s);
+    ide_atapi_pt_read_finish(s);
+}
+
+static void ide_atapi_pt_read_dma_cb(void *opaque, int ret)
+{
+    BMDMAState *bm = opaque;
+    IDEState *s = bm->ide_if;
+    int i = 0;
+
+    if (ret < 0) {
+        ide_atapi_io_error(s, ret);
+        return;
+    }
+
+    i = dma_buf_rw(bm, 0);
+    ide_atapi_pt_read_finish(s);
+}
+
+static void ide_atapi_pt_wcmd(IDEState *s)
+{
+    if (s->atapi_dma)
+    {
+        /* DMA */
+        s->io_buffer_index = 0;
+        s->io_buffer_size = s->atapi_pt.cmd.dxfer_len;
+        ide_dma_start(s, ide_atapi_pt_read_dma_cb);
+        return;
+    }
+
+    /* PIO */
+    s->packet_transfer_size = s->atapi_pt.cmd.dxfer_len;
+    s->io_buffer_size = 0;
+    s->elementary_transfer_size = 0;
+    s->io_buffer_index = 0;
+    s->status |= DRQ_STAT;
+    s->status &= ~BUSY_STAT;
+    s->nsector = (s->nsector & ~7) &
+        ~ATAPI_INT_REASON_IO &
+        ~ATAPI_INT_REASON_CD;
+    ide_transfer_start(s, s->io_buffer, s->atapi_pt.cmd.dxfer_len,
+                       ide_atapi_pt_read_pio_end);
+    ide_set_irq(s);
+    return;
+}
+
+static void ide_atapi_pt_read_format_capacities_sent(IDEState *s)
+{
+    int size = (s->io_buffer[3] << 3) + 4;
+    ide_atapi_cmd_reply(s, size, s->atapi_pt.cmd.dxfer_len);
+}
+
+static void ide_atapi_pt_standard_reply(IDEState *s)
+{
+    uint32_t size = s->atapi_pt.reply_size_init;
+
+    switch (s->atapi_pt.reply_size_len)
+    {
+    case 0:
+        break;
+    case 1:
+        size += s->io_buffer[s->atapi_pt.reply_size_offset];
+        break;
+    case 2:
+        size += ube16_to_cpu(s->io_buffer + s->atapi_pt.reply_size_offset);
+        break;
+    case 3:
+        size += ube24_to_cpu(s->io_buffer + s->atapi_pt.reply_size_offset);
+        break;
+    case 4:
+        size += ube32_to_cpu(s->io_buffer + s->atapi_pt.reply_size_offset);
+        break;
+    default:
+        fprintf(stderr,
+                "The imposible has happened!!! We received a reply with a %d "
+                "bytes length field. Please inform "
+                "Alexandre Bique <bique.alexandre@gmail.com>.",
+                s->atapi_pt.reply_size_len);
+        assert(0);
+        break;
+    }
+    DPRINTF("[reply] size: %d, resid: %d, max_in:%d\n",
+            size, s->atapi_pt.cmd.resid, s->atapi_pt.cmd.dxfer_len);
+    ide_atapi_cmd_reply(s, size, s->atapi_pt.cmd.dxfer_len);
+}
+
+/* This data comes from the "Mt. Fuji Commands for
+ * Multimedia Devices SFF8090i v4" page 343. */
+static int ide_atapi_pt_read_cd_block_size(const uint8_t *io_buffer)
+{
+    int sector_type = (io_buffer[2] >> 2) & 7;
+    int error_flags = (io_buffer[9] >> 1) & 3;
+    int flags_bits = io_buffer[9] & ~7;
+    int block_size = 0;
+
+    // expected sector type
+    switch (sector_type)
+    {
+    case 0: // Any type
+    case 1: // CD-DA
+        block_size = (flags_bits) ? 2352 : 0;
+        break;
+
+    case 2: // Mode 1
+        switch (flags_bits)
+        {
+        case 0x0: block_size = 0; break;
+        case 0x10:
+        case 0x50: block_size = 2048; break;
+        case 0x18:
+        case 0x58: block_size = 2336; break;
+        case 0x20:
+        case 0x60: block_size = 4; break;
+        case 0x30:
+        case 0x70:
+        case 0x78: block_size = 2052; break;
+        case 0x38: block_size = 2340; break;
+        case 0x40: block_size = 0; break;
+        case 0xa0: block_size = 16; break;
+        case 0xb0: block_size = 2064; break;
+        case 0xb8: block_size = 2352; break;
+        case 0xe0: block_size = 16; break;
+        case 0xf0: block_size = 2064; break;
+        case 0xf8: block_size = 2352; break;
+
+        default: return 0; // illegal
+        }
+        break;
+
+    case 3: // Mode 2
+        switch (flags_bits)
+        {
+        case 0x0: block_size = 0; break;
+        case 0x10:
+        case 0x50:
+        case 0x18:
+        case 0x58: block_size = 2336; break;
+        case 0x20:
+        case 0x60: block_size = 4; break;
+        case 0x30:
+        case 0x70:
+        case 0x78:
+        case 0x38: block_size = 2340; break;
+        case 0x40: block_size = 0; break;
+        case 0xa0: block_size = 16; break;
+        case 0xb0:
+        case 0xb8: block_size = 2352; break;
+        case 0xe0: block_size = 16; break;
+        case 0xf0:
+        case 0xf8: block_size = 2352; break;
+        default: return 0; // illegal
+        }
+        break;
+
+    case 4: // Mode 2 Form 1
+        switch (flags_bits)
+        {
+        case 0x0: block_size = 0; break;
+        case 0x10: block_size = 2048; break;
+        case 0x18: block_size = 2328; break;
+        case 0x20: block_size = 4; break;
+        case 0x40: block_size = 8; break;
+        case 0x50: block_size = 2056; break;
+        case 0x58: block_size = 2336; break;
+        case 0x60: block_size = 12; break;
+        case 0x70: block_size = 2060; break;
+        case 0x78: block_size = 2340; break;
+        case 0xa0: block_size = 16; break;
+        case 0xe0: block_size = 24; break;
+        case 0xf0: block_size = 2072; break;
+        case 0xf8: block_size = 2352; break;
+        default: return 0; // illegal
+        }
+        break;
+
+    case 5: // Mode 2 Form 2
+        switch (flags_bits)
+        {
+        case 0x0: block_size = 0; break;
+        case 0x10:
+        case 0x18: block_size = 2328; break;
+        case 0x20: block_size = 4; break;
+        case 0x40: block_size = 8; break;
+        case 0x50:
+        case 0x58: block_size = 2336; break;
+        case 0x60: block_size = 12; break;
+        case 0x70:
+        case 0x78: block_size = 2340; break;
+        case 0xa0: block_size = 16; break;
+        case 0xe0: block_size = 24; break;
+        case 0xf0:
+        case 0xf8: block_size = 2352; break;
+        default: return 0; // illegal
+        }
+        break;
+
+    default:
+        return 0; // illegal
+    }
+
+    switch (error_flags)
+    {
+    case 1: block_size += 294; break;
+    case 2: block_size += 296; break;
+    }
+
+    return block_size;
+}
+
+void ide_atapi_pt_cmd(IDEState *s)
+{
+    struct sg_io_hdr *cmd = &s->atapi_pt.cmd;
+
+    memcpy(s->atapi_pt.request, s->io_buffer, ATAPI_PACKET_SIZE);
+    cmd->interface_id    = 'S';
+    cmd->dxfer_direction = SG_DXFER_NONE;
+    cmd->cmd_len         = ATAPI_PACKET_SIZE;
+    cmd->mx_sb_len       = sizeof (s->atapi_pt.sense);
+    cmd->dxfer_len       = 0;
+    cmd->iovec_count     = 0;
+    cmd->dxferp          = s->io_buffer;
+    cmd->cmdp            = s->atapi_pt.request;
+    cmd->sbp             = (unsigned char *)&s->atapi_pt.sense;
+    cmd->timeout         = 0xffffff; // 15 seconds
+
+    s->status                    |= BUSY_STAT;
+    s->atapi_pt.reply_size_init   = 0;
+    s->atapi_pt.reply_size_offset = 0;
+    s->atapi_pt.reply_size_len    = 0;
+
+    switch (s->io_buffer[0])
+    {
+        /*******************/
+        /* SIMPLE COMMANDS */
+        /*******************/
+
+    case GPCMD_BLANK: // bigger timeout while blanking
+        cmd->timeout = 1000 * 60 * 80; // 80 mins
+        goto simple_cmd;
+    case GPCMD_CLOSE_TRACK:
+        cmd->timeout = 1000 * 60 * 5; // 5 mins
+        goto simple_cmd;
+    case GPCMD_FLUSH_CACHE: // also called SYNCHRONIZE_CACHE
+    case GPCMD_LOAD_UNLOAD:
+    case GPCMD_PAUSE_RESUME:
+    case GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
+    case GPCMD_REPAIR_RZONE_TRACK:
+    case GPCMD_RESERVE_RZONE_TRACK:
+    case GPCMD_SCAN:
+    case GPCMD_SEEK:
+    case GPCMD_SET_READ_AHEAD:
+    case GPCMD_START_STOP_UNIT:
+    case GPCMD_STOP_PLAY_SCAN:
+    case GPCMD_TEST_UNIT_READY:
+    case GPCMD_VERIFY_10:
+    case GPCMD_SET_SPEED: /* FIXME: find the documentation */
+    simple_cmd:
+        CHECK_EQUAL(s->lcyl, 0);
+        CHECK_EQUAL(s->hcyl, 0);
+        cmd->dxfer_direction = SG_DXFER_NONE;
+        s->atapi_pt.cmd_sent = ide_atapi_cmd_ok;
+        ide_atapi_pt_send_packet(s);
+        return;
+
+        /******************/
+        /* WRITE COMMANDS */
+        /******************/
+
+    case GPCMD_WRITE_10:
+    case GPCMD_WRITE_AND_VERIFY_10:
+        cmd->dxfer_direction = SG_DXFER_TO_DEV;
+        cmd->dxfer_len = ube16_to_cpu(s->io_buffer + 7) * CD_FRAMESIZE;
+        if (cmd->dxfer_len == 0)
+            goto simple_cmd;
+        ide_atapi_pt_wcmd(s);
+        return;
+
+    case GPCMD_WRITE_12:
+        cmd->dxfer_direction = SG_DXFER_TO_DEV;
+        cmd->dxfer_len = ube32_to_cpu(s->io_buffer + 6);
+        if (cmd->dxfer_len == 0)
+            goto simple_cmd;
+        ide_atapi_pt_wcmd(s);
+        return;
+
+    case GPCMD_WRITE_BUFFER:
+    {
+        int32_t parameter_list_length = ube24_to_cpu(s->io_buffer + 3);
+        int8_t mode = s->io_buffer[1] & 0x03;
+
+        cmd->dxfer_direction = SG_DXFER_TO_DEV;
+        switch (mode)
+        {
+        case 0x0: // Combined header and data mode
+            // The documentation is confusing because it says that parameter
+            // list length contains all the data, but the buffer should be
+            // greater than parameter list length + 4...
+            cmd->dxfer_len = parameter_list_length + 4;
+            break;
+        case 0x2: // Data mode
+            cmd->dxfer_len = parameter_list_length;
+            break;
+        case 0x1: // Vendor specific
+        case 0x4: // Download microcode
+        case 0x5: // Download microcode and save mode
+        case 0x6: // Download microcode with offsets
+        case 0x7: // Download microcode with offsets and save mode
+        default:
+            if (!atapi_pt_allow_fw_upgrade)
+                goto illegal_request;
+            cmd->dxfer_len = parameter_list_length;
+            break;
+        }
+
+        ide_atapi_pt_wcmd(s);
+        return;
+    }
+
+    case GPCMD_SEND_CUE_SHEET:
+        cmd->dxfer_direction = SG_DXFER_TO_DEV;
+        cmd->dxfer_len = ube24_to_cpu(s->io_buffer + 6);
+        if (cmd->dxfer_len == 0)
+            goto simple_cmd;
+        ide_atapi_pt_wcmd(s);
+        return;
+
+    case GPCMD_MODE_SELECT_10:
+        cmd->dxfer_direction = SG_DXFER_TO_DEV;
+        cmd->dxfer_len = ube16_to_cpu(s->io_buffer + 7);
+        CHECK_EQUAL(s->lcyl | (s->hcyl << 8), cmd->dxfer_len);
+        if (cmd->dxfer_len == 0)
+            goto simple_cmd;
+        ide_atapi_pt_wcmd(s);
+        return;
+
+    case GPCMD_SEND_KEY:
+    case GPCMD_SEND_EVENT:
+        cmd->dxfer_direction = SG_DXFER_TO_DEV;
+        cmd->dxfer_len = ube16_to_cpu(s->io_buffer + 8);
+        if (cmd->dxfer_len == 0)
+            goto simple_cmd;
+        CHECK_EQUAL(s->lcyl | (s->hcyl << 8), cmd->dxfer_len);
+        ide_atapi_pt_wcmd(s);
+        return;
+
+    case GPCMD_SEND_OPC:
+        cmd->dxfer_direction = SG_DXFER_TO_DEV;
+        cmd->dxfer_len = ube16_to_cpu(s->io_buffer + 7) << 3;
+        CHECK_EQUAL(s->lcyl | (s->hcyl << 8), cmd->dxfer_len);
+        if (cmd->dxfer_len == 0)
+            goto simple_cmd;
+        ide_atapi_pt_wcmd(s);
+        return;
+
+    case GPCMD_SET_STREAMING:
+        cmd->dxfer_direction = SG_DXFER_TO_DEV;
+        cmd->dxfer_len = ube16_to_cpu(s->io_buffer + 9);
+        if (cmd->dxfer_len == 0)
+            goto simple_cmd;
+        ide_atapi_pt_wcmd(s);
+        return;
+
+    case GPCMD_FORMAT_UNIT:
+        cmd->dxfer_direction = SG_DXFER_TO_DEV;
+        cmd->dxfer_len = 12;
+        ide_atapi_pt_wcmd(s);
+        return;
+
+        /*****************/
+        /* READ COMMANDS */
+        /*****************/
+
+    case GPCMD_INQUIRY:
+        cmd->dxfer_direction = SG_DXFER_FROM_DEV;
+        cmd->dxfer_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;
+        ide_atapi_pt_send_packet(s);
+        return;
+
+    case GPCMD_REQUEST_SENSE:
+    {
+        // send the previous sense command
+        DPRINTF("=== REQUEST SENSE ===\n"
+                "atapi_cmd_error: sense=0x%x asc=0x%x error=0x%x\n",
+                s->atapi_pt.sense.sense_key,
+                s->atapi_pt.sense.asc,
+                s->atapi_pt.sense.error_code);
+
+        int max_size = s->io_buffer[4];
+
+        int size = 8 + s->atapi_pt.sense.add_sense_len;
+
+        DPRINTF("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->dxfer_direction = SG_DXFER_FROM_DEV;
+        cmd->dxfer_len = ube16_to_cpu(s->io_buffer + 8);
+        s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+        s->atapi_pt.reply_size_len = 4;
+        ide_atapi_pt_send_packet(s);
+        return;
+
+    case GPCMD_READ_HEADER:
+        cmd->dxfer_direction = SG_DXFER_FROM_DEV;
+        cmd->dxfer_len = ube16_to_cpu(s->io_buffer + 7);
+        s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+        s->atapi_pt.reply_size_init = cmd->dxfer_len;
+        ide_atapi_pt_send_packet(s);
+        return;
+
+    case GPCMD_MECHANISM_STATUS:
+        cmd->dxfer_len = ube16_to_cpu(s->io_buffer + 8);
+        s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+        s->atapi_pt.reply_size_offset = 6;
+        ide_atapi_pt_send_packet(s);
+        return;
+
+    case GPCMD_REPORT_KEY:
+        cmd->dxfer_direction = SG_DXFER_FROM_DEV;
+        cmd->dxfer_len = ube16_to_cpu(s->io_buffer + 8);
+        s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+        s->atapi_pt.reply_size_len = 2;
+        s->atapi_pt.reply_size_init = 2;
+        ide_atapi_pt_send_packet(s);
+        return;
+
+    case GPCMD_READ_BUFFER_CAPACITY:
+        cmd->dxfer_direction = SG_DXFER_FROM_DEV;
+        cmd->dxfer_len = ube16_to_cpu(s->io_buffer + 7);
+        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;
+
+    case GPCMD_GET_PERFORMANCE:
+        cmd->dxfer_direction = SG_DXFER_FROM_DEV;
+        cmd->dxfer_len = 8 + 8 * ube16_to_cpu(s->io_buffer + 8);
+        s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+        s->atapi_pt.reply_size_len = 4;
+        ide_atapi_pt_send_packet(s);
+        return;
+
+    case GPCMD_READ_10:
+    case GPCMD_READ_12:
+    {
+        int blocksize = 0, nbblocks;
+
+        cmd->dxfer_direction = SG_DXFER_FROM_DEV;
+        switch (s->io_buffer[0]) {
+        case GPCMD_READ_10:
+            blocksize = CD_FRAMESIZE;
+            nbblocks = ube16_to_cpu(s->io_buffer + 7);
+            break;
+        case GPCMD_READ_12:
+            blocksize = CD_FRAMESIZE_RAW0;
+            nbblocks = ube32_to_cpu(s->io_buffer + 6);
+            break;
+        default:
+            assert(0);
+            break;
+        }
+        cmd->dxfer_len = nbblocks * blocksize;
+        CHECK_EQUAL(cmd->dxfer_len, (s->hcyl << 8) | s->lcyl);
+        s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+        s->atapi_pt.reply_size_init = cmd->dxfer_len;
+        ide_atapi_pt_send_packet(s);
+        return;
+    }
+
+    case GPCMD_READ_BUFFER:
+        // TODO check this one is correct
+        cmd->dxfer_direction = SG_DXFER_FROM_DEV;
+        cmd->dxfer_len = ube24_to_cpu(s->io_buffer + 6);
+
+        switch (s->io_buffer[1] & 0x7)
+        {
+        case 0: // data with header
+            s->atapi_pt.reply_size_init = 4;
+            s->atapi_pt.reply_size_len = 3;
+            s->atapi_pt.reply_size_offset = 1;
+            break;
+
+        case 2: // data only
+            s->atapi_pt.reply_size_init = cmd->dxfer_len;
+            break;
+
+        case 3: // header only
+            s->atapi_pt.reply_size_init = 4;
+            break;
+
+        case 1: // vendor specific
+        default:
+            goto illegal_request;
+        }
+        s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+        ide_atapi_pt_send_packet(s);
+        return;
+
+    case GPCMD_READ_CDVD_CAPACITY:
+        cmd->dxfer_direction = SG_DXFER_FROM_DEV;
+        cmd->dxfer_len = 8;
+        CHECK_EQUAL(s->lcyl | (s->hcyl << 8), cmd->dxfer_len);
+        s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+        s->atapi_pt.reply_size_init = cmd->dxfer_len;
+        ide_atapi_pt_send_packet(s);
+        return;
+
+    case GPCMD_MODE_SENSE_10:
+        cmd->dxfer_direction = SG_DXFER_FROM_DEV;
+        cmd->dxfer_len = ube16_to_cpu(s->io_buffer + 7);
+        CHECK_EQUAL(s->lcyl | (s->hcyl << 8), cmd->dxfer_len);
+        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->dxfer_len;
+        ide_atapi_pt_send_packet(s);
+        return;
+
+    case GPCMD_GET_EVENT_STATUS_NOTIFICATION:
+    case GPCMD_READ_DISC_INFO:
+    case GPCMD_READ_TOC_PMA_ATIP:
+    case GPCMD_READ_TRACK_RZONE_INFO:
+        cmd->dxfer_direction = SG_DXFER_FROM_DEV;
+        cmd->dxfer_len = ube16_to_cpu(s->io_buffer + 7);
+        s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+        s->atapi_pt.reply_size_len = 2;
+        s->atapi_pt.reply_size_init = 2;
+        ide_atapi_pt_send_packet(s);
+        return;
+
+    case GPCMD_READ_SUBCHANNEL:
+        cmd->dxfer_direction = SG_DXFER_FROM_DEV;
+        cmd->dxfer_len = ube16_to_cpu(s->io_buffer + 7);
+        s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+        s->atapi_pt.reply_size_len = 2;
+        s->atapi_pt.reply_size_offset = 2;
+        ide_atapi_pt_send_packet(s);
+        return;
+
+    case GPCMD_READ_CD:
+    {
+        // command fields
+        int block_count = ((s->io_buffer[6] << 16) |
+                           ube16_to_cpu(s->io_buffer + 7));
+        int block_size = ide_atapi_pt_read_cd_block_size(s->io_buffer);
+
+        cmd->dxfer_direction = SG_DXFER_FROM_DEV;
+        cmd->dxfer_len = block_count * block_size;
+        s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+        s->atapi_pt.reply_size_init = cmd->dxfer_len;
+        ide_atapi_pt_send_packet(s);
+        return;
+    }
+
+    case GPCMD_READ_CD_MSF:
+    {
+        // command fields
+        int starting_frame =
+            msf_to_frames(s->io_buffer[3], s->io_buffer[4], s->io_buffer[5]);
+        int ending_frame =
+            msf_to_frames(s->io_buffer[6], s->io_buffer[7], s->io_buffer[8]);
+        int block_count = ending_frame - starting_frame;
+        int block_size = ide_atapi_pt_read_cd_block_size(s->io_buffer);
+
+        cmd->dxfer_direction = SG_DXFER_FROM_DEV;
+        cmd->dxfer_len = block_count * block_size;
+        s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+        s->atapi_pt.reply_size_init = cmd->dxfer_len;
+        ide_atapi_pt_send_packet(s);
+        return;
+    }
+
+    case GPCMD_PLAY_AUDIO_10:
+    {
+        int block_count = ube16_to_cpu(s->io_buffer + 7);
+        cmd->dxfer_direction = SG_DXFER_FROM_DEV;
+        cmd->dxfer_len = block_count * CD_FRAMESIZE;
+        s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+        s->atapi_pt.reply_size_init = cmd->dxfer_len;
+        ide_atapi_pt_send_packet(s);
+        return;
+    }
+
+    case GPCMD_PLAY_AUDIO_MSF:
+    {
+        int starting_frame =
+            msf_to_frames(s->io_buffer[3], s->io_buffer[4], s->io_buffer[5]);
+        int ending_frame =
+            msf_to_frames(s->io_buffer[6], s->io_buffer[7], s->io_buffer[8]);
+        int block_count = ending_frame - starting_frame;
+        cmd->dxfer_direction = SG_DXFER_FROM_DEV;
+        cmd->dxfer_len = block_count * CD_FRAMESIZE;
+        s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+        s->atapi_pt.reply_size_init = cmd->dxfer_len;
+        ide_atapi_pt_send_packet(s);
+        return;
+    }
+
+    case GPCMD_READ_FORMAT_CAPACITIES:
+        cmd->dxfer_direction = SG_DXFER_FROM_DEV;
+        cmd->dxfer_len = ube16_to_cpu(s->io_buffer + 7);
+        s->atapi_pt.cmd_sent = ide_atapi_pt_read_format_capacities_sent;
+        ide_atapi_pt_send_packet(s);
+        return;
+
+    case GPCMD_GET_CONFIGURATION:
+        cmd->dxfer_direction = SG_DXFER_FROM_DEV;
+        cmd->dxfer_len = ube16_to_cpu(s->io_buffer + 7);
+        s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+        s->atapi_pt.reply_size_init = 4;
+        s->atapi_pt.reply_size_len = 4;
+        ide_atapi_pt_send_packet(s);
+        return;
+
+    case GPCMD_SEND_DVD_STRUCTURE:
+        cmd->dxfer_direction = SG_DXFER_FROM_DEV;
+        cmd->dxfer_len = ube16_to_cpu(s->io_buffer + 8);
+        s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+        s->atapi_pt.reply_size_init = 2;
+        s->atapi_pt.reply_size_len = 2;
+        ide_atapi_pt_send_packet(s);
+        return;
+
+    case 0x01: // GPMODE_R_W_ERROR_PAGE ?
+    case 0x1a: // GPMODE_POWER_PAGE ?
+    case 0xfa:
+    case 0xfd:
+    case 0xf2:
+    case 0xf3: // WIN_SECURITY_ERASE_PREPARE ?
+    case 0xee: // WIN_IDENTIFY_DMA ?
+    case 0xdf: // WIN_DOORUNLOCK ?
+        DPRINTF("[\e[3;31mILLEGAL?\e[m] 0x%02x, size: %d\n",
+                s->io_buffer[0], s->lcyl | (s->hcyl << 8));
+    illegal_request:
+        ide_atapi_pt_set_error(s, SENSE_ILLEGAL_REQUEST,
+                               ASC_ILLEGAL_OPCODE, 0x70);
+        return;
+
+    default:
+        fprintf(stderr, "[ATAPI-PT] We got an unhandled command: 0x%02x. "
+                "Please report.\n", s->io_buffer[0]);
+        exit(1);
+        return;
+    }
+}
+
+void ide_atapi_pt_identify(IDEState *s)
+{
+    if (s->identify_set) {
+	memcpy(s->io_buffer, s->identify_data, sizeof(s->identify_data));
+	return;
+    }
+
+    if (bdrv_ioctl(s->bs, HDIO_GET_IDENTITY, s->io_buffer)) {
+        ide_atapi_identify(s);
+        perror("atapi");
+        exit(1);
+        return;
+    }
+
+    memcpy(s->identify_data, s->io_buffer, sizeof(s->identify_data));
+    s->identify_set = 1;
+}
diff --git a/hw/atapi-pt.h b/hw/atapi-pt.h
new file mode 100644
index 0000000..639270e
--- /dev/null
+++ b/hw/atapi-pt.h
@@ -0,0 +1,35 @@
+/*
+ * ATAPI pass through declarations
+ *
+ * Copyright (c) 2009 Alexandre Bique
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef ATAPI_PT_H
+# define ATAPI_PT_H
+
+# include "ide.h"
+
+extern int atapi_pt_allow_fw_upgrade;
+
+void ide_atapi_pt_cmd(IDEState * s);
+void ide_atapi_pt_identify(IDEState * s);
+
+#endif /* !ATAPI_PT_H */
diff --git a/hw/ide.c b/hw/ide.c
index 9db9cb2..382b05e 100644
--- a/hw/ide.c
+++ b/hw/ide.c
@@ -22,21 +22,8 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
-#include "hw.h"
-#include "pc.h"
-#include "pci.h"
-#include "scsi-disk.h"
-#include "pcmcia.h"
-#include "block.h"
-#include "block_int.h"
-#include "qemu-timer.h"
-#include "sysemu.h"
-#include "ppc_mac.h"
-#include "mac_dbdma.h"
-#include "sh.h"
-#include "dma.h"
 #include "ide.h"
-#include "atapi-defines.h"
+#include "atapi-pt.h"
 
 /* debug IDE devices */
 //#define DEBUG_IDE
@@ -44,6 +31,7 @@
 //#define DEBUG_AIO
 #define USE_DMA_CDROM
 
+
 /* XXX: DVDs that could fit on a CD will be reported as a CD */
 static inline int media_present(IDEState *s)
 {
@@ -62,7 +50,6 @@ static inline int media_is_cd(IDEState *s)
 
 static void ide_dma_restart(IDEState *s);
 static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret);
-static void ide_atapi_cmd_error(IDEState *s, int sense_key, int asc);
 
 static void padstr(char *str, const char *src, int len)
 {
@@ -1977,7 +1964,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
             /* ATAPI commands */
         case WIN_PIDENTIFY:
             if (s->is_cdrom) {
-                ide_atapi_identify(s);
+                s->atapi_identify(s);
                 s->status = READY_STAT | SEEK_STAT;
                 ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop);
             } else {
@@ -2015,7 +2002,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,
-                               ide_atapi_cmd);
+                               s->atapi_cmd);
             break;
         /* CF-ATA commands */
         case CFA_REQ_EXT_ERROR_CODE:
@@ -2354,6 +2341,16 @@ static void ide_init2(IDEState *ide_state,
 
             if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) {
                 s->is_cdrom = 1;
+                if (!bdrv_is_sg(s->bs)) {
+                    s->atapi_cmd = ide_atapi_cmd;
+                    s->atapi_identify = ide_atapi_identify;
+                }
+#if CONFIG_ATAPI_PT
+                else {
+                    s->atapi_cmd = ide_atapi_pt_cmd;
+                    s->atapi_identify = ide_atapi_pt_identify;
+                }
+#endif /* CONFIG_ATAPI_PT */
 		bdrv_set_change_cb(s->bs, cdrom_change_cb, s);
             }
         }
diff --git a/hw/ide.h b/hw/ide.h
index 064e2d3..58c74b9 100644
--- a/hw/ide.h
+++ b/hw/ide.h
@@ -40,7 +40,20 @@
 #include "dma.h"
 #include "atapi-defines.h"
 
+
 #include <stdint.h>
+#include <limits.h>
+#include <asm/byteorder.h>
+#include <assert.h>
+
+#ifdef __linux__
+# include <linux/hdreg.h>
+# define CONFIG_ATAPI_PT 1
+#else
+# define CONFIG_ATAPI_PT 0
+#endif /* __linux__ */
+
+#include <scsi/sg.h>
 
 /* Bits of HD_STATUS */
 #define ERR_STAT		0x01
@@ -218,6 +231,50 @@ struct IDEState;
 
 typedef void EndTransferFunc(struct IDEState *);
 
+typedef struct request_sense {
+#if defined(__BIG_ENDIAN_BITFIELD)
+    uint8_t valid      : 1;
+    uint8_t error_code : 7;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+    uint8_t error_code : 7;
+    uint8_t valid      : 1;
+#endif
+    uint8_t segment_number;
+#if defined(__BIG_ENDIAN_BITFIELD)
+    uint8_t reserved1 : 2;
+    uint8_t ili       : 1;
+    uint8_t reserved2 : 1;
+    uint8_t sense_key : 4;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+    uint8_t sense_key : 4;
+    uint8_t reserved2 : 1;
+    uint8_t ili       : 1;
+    uint8_t reserved1 : 2;
+#endif
+    uint8_t information[4];
+    uint8_t add_sense_len;
+    uint8_t command_info[4];
+    uint8_t asc;
+    uint8_t ascq;
+    uint8_t fruc;
+    uint8_t sks[3];
+    uint8_t asb[46];
+} request_sense;
+
+#if CONFIG_ATAPI_PT
+typedef struct ATAPIPassThroughState
+{
+    uint8_t              request[ATAPI_PACKET_SIZE];
+    struct sg_io_hdr     cmd;
+    struct request_sense sense;
+    void                 (*cmd_sent)(struct IDEState *);
+
+    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)
+} ATAPIPassThroughState;
+#endif /* CONFIG_ATAPI_PT */
+
 /* NOTE: IDEState represents in fact one drive */
 typedef struct IDEState {
     /* ide config */
@@ -266,6 +323,11 @@ typedef struct IDEState {
     int lba;
     int cd_sector_size;
     int atapi_dma; /* true if dma is requested for the packet cmd */
+#if CONFIG_ATAPI_PT
+    ATAPIPassThroughState atapi_pt;
+#endif /* CONFIG_ATAPI_PT */
+    void (*atapi_identify)(struct IDEState *); // the ATAPI identify
+    void (*atapi_cmd)(struct IDEState *); // the ATAPI cmd handler
     /* ATA DMA state */
     int io_buffer_size;
     QEMUSGList sg;
@@ -287,27 +349,27 @@ typedef struct IDEState {
     int is_read;
 } IDEState;
 
-#define BM_STATUS_DMAING 0x01
-#define BM_STATUS_ERROR  0x02
-#define BM_STATUS_INT    0x04
-#define BM_STATUS_DMA_RETRY  0x08
-#define BM_STATUS_PIO_RETRY  0x10
+#define BM_STATUS_DMAING        0x01
+#define BM_STATUS_ERROR         0x02
+#define BM_STATUS_INT           0x04
+#define BM_STATUS_DMA_RETRY     0x08
+#define BM_STATUS_PIO_RETRY     0x10
 
-#define BM_CMD_START     0x01
-#define BM_CMD_READ      0x08
+#define BM_CMD_START            0x01
+#define BM_CMD_READ             0x08
 
-#define IDE_TYPE_PIIX3   0
-#define IDE_TYPE_CMD646  1
-#define IDE_TYPE_PIIX4   2
+#define IDE_TYPE_PIIX3          0
+#define IDE_TYPE_CMD646         1
+#define IDE_TYPE_PIIX4          2
 
 /* CMD646 specific */
-#define MRDMODE		0x71
-#define   MRDMODE_INTR_CH0	0x04
-#define   MRDMODE_INTR_CH1	0x08
-#define   MRDMODE_BLK_CH0	0x10
-#define   MRDMODE_BLK_CH1	0x20
-#define UDIDETCR0	0x73
-#define UDIDETCR1	0x7B
+#define MRDMODE                 0x71
+#define MRDMODE_INTR_CH0	0x04
+#define MRDMODE_INTR_CH1	0x08
+#define MRDMODE_BLK_CH0         0x10
+#define MRDMODE_BLK_CH1         0x20
+#define UDIDETCR0               0x73
+#define UDIDETCR1               0x7B
 
 typedef struct BMDMAState {
     uint8_t cmd;
@@ -367,6 +429,14 @@ static inline int ube16_to_cpu(const uint8_t *buf)
     return (buf[0] << 8) | buf[1];
 }
 
+#if CONFIG_ATAPI_PT /* only atapi-pt uses it so let's avoid unused
+                            * warning */
+static inline int ube24_to_cpu(const uint8_t *buf)
+{
+    return (buf[0] << 16) | (buf[1] << 8) | buf[2];
+}
+#endif /* CONFIG_ATAPI_PT */
+
 static inline int ube32_to_cpu(const uint8_t *buf)
 {
     return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
diff --git a/qemu-options.hx b/qemu-options.hx
index 1b420a3..2761223 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -91,6 +91,13 @@ Use @var{file} as CD-ROM image (you cannot use @option{-hdc} and
 using @file{/dev/cdrom} as filename (@pxref{host_drives}).
 ETEXI
 
+DEF("cdrom-allow-fw-upgrade", 0, QEMU_OPTION_cdrom_allow_fw_upgrade,
+    "-cdrom-allow-fw-upgrade     allow the guest to process cdrom firmware upgrade.\n")
+STEXI
+@item -cdrom-allow-fw-upgrade
+Allow Qemu to pass through ATAPI firmware upgrade command.
+ETEXI
+
 DEF("drive", HAS_ARG, QEMU_OPTION_drive,
     "-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][,index=i]\n"
     "       [,cyls=c,heads=h,secs=s[,trans=t]][,snapshot=on|off]\n"
diff --git a/vl.c b/vl.c
index fdd4f03..e29d13c 100644
--- a/vl.c
+++ b/vl.c
@@ -142,6 +142,7 @@ int main(int argc, char **argv)
 #include "hw/smbios.h"
 #include "hw/xen.h"
 #include "hw/qdev.h"
+#include "hw/atapi-pt.h"
 #include "bt-host.h"
 #include "net.h"
 #include "monitor.h"
@@ -1792,6 +1793,7 @@ static int bt_parse(const char *opt)
 
 #define HD_ALIAS "index=%d,media=disk"
 #define CDROM_ALIAS "index=2,media=cdrom"
+#define CDROM_PT_ALIAS "index=2,media=cdrompt"
 #define FD_ALIAS "index=%d,if=floppy"
 #define PFLASH_ALIAS "if=pflash"
 #define MTD_ALIAS "if=mtd"
@@ -5119,6 +5121,9 @@ int main(int argc, char **argv, char **envp)
             case QEMU_OPTION_cdrom:
                 drive_add(optarg, CDROM_ALIAS);
                 break;
+            case QEMU_OPTION_cdrom_allow_fw_upgrade:
+                atapi_pt_allow_fw_upgrade = 1;
+                break;
             case QEMU_OPTION_boot:
                 {
                     static const char * const params[] = {
-- 
1.6.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] ATAPI pass throug v4
  2009-08-07 17:33 [Qemu-devel] ATAPI pass throug v4 Alexandre Bique
  2009-08-07 17:33 ` [Qemu-devel] [PATCH 1/7] atapi: fix up a few comments Alexandre Bique
@ 2009-08-10 20:09 ` Anthony Liguori
  1 sibling, 0 replies; 10+ messages in thread
From: Anthony Liguori @ 2009-08-10 20:09 UTC (permalink / raw)
  To: Alexandre Bique; +Cc: qemu-devel

Alexandre Bique wrote:
> Hi,
>
> This is the new version of the ATAPI pass through patches.
>   

This series breaks the cris-softmmu build.

Also, I think Paul and I both requested that fw upgrade not be disabled 
by default.  I would also suggest that you only expose this as an option 
through qdev properties instead of a new command line option as it 
should be controllable on a per-device basis.

Regards,

Anthony Liguori

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH 7/7] atapi: introducing atapi pass through
       [not found] <<19074.63829.151234.423348@mariner.uk.xensource.com>
@ 2009-08-12 16:56 ` Ian Jackson
  0 siblings, 0 replies; 10+ messages in thread
From: Ian Jackson @ 2009-08-12 16:56 UTC (permalink / raw)
  To: qemu-devel

This patch introduces atapi pass through. The pass through code is used
by default when the underlying block device is a scsi device.

This brings one new option to the command line interface:
  -cdrom-reject-fw-upgrade
which blocks firmware upgrades by the guest.  By default these are
*allowed* which could be a security problem in some setups. See the
WRITE_BUFFER command for more details.

Signed-off-by: Alexandre Bique <alexandre.bique@citrix.com>
Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
---
 Makefile.target |    9 +++--
 hw/ide.c        |   31 +++++++---------
 hw/ide.h        |  104 ++++++++++++++++++++++++++++++++++++++++++++++---------
 qemu-options.hx |    7 ++++
 sysemu.h        |    1 +
 vl.c            |    6 +++
 6 files changed, 121 insertions(+), 37 deletions(-)

diff --git a/Makefile.target b/Makefile.target
index 3f5d24a..a035e64 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -184,6 +184,7 @@ obj-y += wdt_ib700.o wdt_i6300esb.o
 
 # Hardware support
 obj-i386-y = ide.o pckbd.o vga.o $(sound-obj-y) dma.o isa-bus.o
+obj-i386-y += atapi-pt.o atapi-data.o
 obj-i386-y += fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o
 obj-i386-y += cirrus_vga.o apic.o ioapic.o parallel.o acpi.o piix_pci.o
 obj-i386-y += usb-uhci.o vmmouse.o vmport.o vmware_vga.o hpet.o
@@ -191,6 +192,7 @@ obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o
 
 # shared objects
 obj-ppc-y = ppc.o ide.o vga.o $(sound-obj-y) dma.o isa-bus.o openpic.o
+obj-ppc-y += atapi-pt.o atapi-data.o
 # PREP target
 obj-ppc-y += pckbd.o serial.o i8259.o i8254.o fdc.o mc146818rtc.o
 obj-ppc-y += prep_pci.o ppc_prep.o
@@ -212,6 +214,7 @@ obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
 obj-mips-y += mips_timer.o mips_int.o dma.o vga.o serial.o i8254.o i8259.o rc4030.o
 obj-mips-y += g364fb.o jazz_led.o dp8393x.o
 obj-mips-y += ide.o gt64xxx.o pckbd.o fdc.o mc146818rtc.o usb-uhci.o acpi.o ds1225y.o
+obj-mips-y += atapi-pt.o atapi-data.o
 obj-mips-y += piix_pci.o parallel.o cirrus_vga.o isa-bus.o pcspk.o $(sound-obj-y)
 obj-mips-y += mipsnet.o
 obj-mips-y += pflash_cfi01.o
@@ -242,7 +245,7 @@ obj-cris-y += etraxfs_ser.o
 obj-cris-y += pflash_cfi02.o
 
 ifeq ($(TARGET_ARCH), sparc64)
-obj-sparc-y = sun4u.o ide.o isa-bus.o pckbd.o vga.o apb_pci.o
+obj-sparc-y = sun4u.o ide.o atapi-pt.o atapi-data.o isa-bus.o pckbd.o vga.o apb_pci.o
 obj-sparc-y += fdc.o mc146818rtc.o serial.o
 obj-sparc-y += cirrus_vga.o parallel.o
 else
@@ -261,7 +264,7 @@ obj-arm-y += arm-semi.o
 obj-arm-y += pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o
 obj-arm-y += pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o
 obj-arm-y += pflash_cfi01.o gumstix.o
-obj-arm-y += zaurus.o ide.o serial.o spitz.o tosa.o tc6393xb.o
+obj-arm-y += zaurus.o ide.o atapi-pt.o atapi-data.o serial.o spitz.o tosa.o tc6393xb.o
 obj-arm-y += omap1.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o
 obj-arm-y += omap2.o omap_dss.o soc_dma.o
 obj-arm-y += omap_sx1.o palm.o tsc210x.o
@@ -275,7 +278,7 @@ obj-arm-y += syborg_virtio.o
 
 obj-sh4-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o
 obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o serial.o
-obj-sh4-y += ide.o
+obj-sh4-y += ide.o atapi-pt.o atapi-data.o
 
 obj-m68k-y = an5206.o mcf5206.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o
 obj-m68k-y += m68k-semi.o dummy_m68k.o
diff --git a/hw/ide.c b/hw/ide.c
index 83d7acc..78c0d79 100644
--- a/hw/ide.c
+++ b/hw/ide.c
@@ -22,21 +22,8 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
-#include "hw.h"
-#include "pc.h"
-#include "pci.h"
-#include "scsi-disk.h"
-#include "pcmcia.h"
-#include "block.h"
-#include "block_int.h"
-#include "qemu-timer.h"
-#include "sysemu.h"
-#include "ppc_mac.h"
-#include "mac_dbdma.h"
-#include "sh.h"
-#include "dma.h"
 #include "ide.h"
-#include "atapi-defines.h"
+#include "atapi-pt.h"
 
 /* debug IDE devices */
 //#define DEBUG_IDE
@@ -44,6 +31,7 @@
 //#define DEBUG_AIO
 #define USE_DMA_CDROM
 
+
 /* XXX: DVDs that could fit on a CD will be reported as a CD */
 static inline int media_present(IDEState *s)
 {
@@ -62,7 +50,6 @@ static inline int media_is_cd(IDEState *s)
 
 static void ide_dma_restart(IDEState *s);
 static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret);
-static void ide_atapi_cmd_error(IDEState *s, int sense_key, int asc);
 
 static void padstr(char *str, const char *src, int len)
 {
@@ -1978,7 +1965,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
             /* ATAPI commands */
         case WIN_PIDENTIFY:
             if (s->is_cdrom) {
-                ide_atapi_identify(s);
+                s->atapi_identify(s);
                 s->status = READY_STAT | SEEK_STAT;
                 ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop);
             } else {
@@ -2016,7 +2003,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,
-                               ide_atapi_cmd);
+                               s->atapi_cmd);
             break;
         /* CF-ATA commands */
         case CFA_REQ_EXT_ERROR_CODE:
@@ -2355,6 +2342,16 @@ static void ide_init2(IDEState *ide_state,
 
             if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) {
                 s->is_cdrom = 1;
+                if (!bdrv_is_sg(s->bs)) {
+                    s->atapi_cmd = ide_atapi_cmd;
+                    s->atapi_identify = ide_atapi_identify;
+                }
+#if CONFIG_ATAPI_PT
+                else {
+                    s->atapi_cmd = ide_atapi_pt_cmd;
+                    s->atapi_identify = ide_atapi_pt_identify;
+                }
+#endif /* CONFIG_ATAPI_PT */
 		bdrv_set_change_cb(s->bs, cdrom_change_cb, s);
             }
         }
diff --git a/hw/ide.h b/hw/ide.h
index 2c24e08..ffefeb1 100644
--- a/hw/ide.h
+++ b/hw/ide.h
@@ -40,7 +40,20 @@
 #include "dma.h"
 #include "atapi-defines.h"
 
+
 #include <stdint.h>
+#include <limits.h>
+#include <asm/byteorder.h>
+#include <assert.h>
+
+#ifdef __linux__
+# include <linux/hdreg.h>
+# define CONFIG_ATAPI_PT 1
+#else
+# define CONFIG_ATAPI_PT 0
+#endif /* __linux__ */
+
+#include <scsi/sg.h>
 
 /* Bits of HD_STATUS */
 #define ERR_STAT		0x01
@@ -419,6 +432,50 @@ struct IDEState;
 
 typedef void EndTransferFunc(struct IDEState *);
 
+typedef struct request_sense {
+#if defined(__BIG_ENDIAN_BITFIELD)
+    uint8_t valid      : 1;
+    uint8_t error_code : 7;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+    uint8_t error_code : 7;
+    uint8_t valid      : 1;
+#endif
+    uint8_t segment_number;
+#if defined(__BIG_ENDIAN_BITFIELD)
+    uint8_t reserved1 : 2;
+    uint8_t ili       : 1;
+    uint8_t reserved2 : 1;
+    uint8_t sense_key : 4;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+    uint8_t sense_key : 4;
+    uint8_t reserved2 : 1;
+    uint8_t ili       : 1;
+    uint8_t reserved1 : 2;
+#endif
+    uint8_t information[4];
+    uint8_t add_sense_len;
+    uint8_t command_info[4];
+    uint8_t asc;
+    uint8_t ascq;
+    uint8_t fruc;
+    uint8_t sks[3];
+    uint8_t asb[46];
+} request_sense;
+
+#if CONFIG_ATAPI_PT
+typedef struct ATAPIPassThroughState
+{
+    uint8_t              request[ATAPI_PACKET_SIZE];
+    struct sg_io_hdr     cmd;
+    struct request_sense sense;
+    void                 (*cmd_sent)(struct IDEState *);
+
+    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)
+} ATAPIPassThroughState;
+#endif /* CONFIG_ATAPI_PT */
+
 /* NOTE: IDEState represents in fact one drive */
 typedef struct IDEState {
     /* ide config */
@@ -468,6 +525,11 @@ typedef struct IDEState {
     int lba;
     int cd_sector_size;
     int atapi_dma; /* true if dma is requested for the packet cmd */
+#if CONFIG_ATAPI_PT
+    ATAPIPassThroughState atapi_pt;
+#endif /* CONFIG_ATAPI_PT */
+    void (*atapi_identify)(struct IDEState *); // the ATAPI identify
+    void (*atapi_cmd)(struct IDEState *); // the ATAPI cmd handler
     /* ATA DMA state */
     int io_buffer_size;
     QEMUSGList sg;
@@ -489,27 +551,27 @@ typedef struct IDEState {
     int is_read;
 } IDEState;
 
-#define BM_STATUS_DMAING 0x01
-#define BM_STATUS_ERROR  0x02
-#define BM_STATUS_INT    0x04
-#define BM_STATUS_DMA_RETRY  0x08
-#define BM_STATUS_PIO_RETRY  0x10
+#define BM_STATUS_DMAING        0x01
+#define BM_STATUS_ERROR         0x02
+#define BM_STATUS_INT           0x04
+#define BM_STATUS_DMA_RETRY     0x08
+#define BM_STATUS_PIO_RETRY     0x10
 
-#define BM_CMD_START     0x01
-#define BM_CMD_READ      0x08
+#define BM_CMD_START            0x01
+#define BM_CMD_READ             0x08
 
-#define IDE_TYPE_PIIX3   0
-#define IDE_TYPE_CMD646  1
-#define IDE_TYPE_PIIX4   2
+#define IDE_TYPE_PIIX3          0
+#define IDE_TYPE_CMD646         1
+#define IDE_TYPE_PIIX4          2
 
 /* CMD646 specific */
-#define MRDMODE		0x71
-#define   MRDMODE_INTR_CH0	0x04
-#define   MRDMODE_INTR_CH1	0x08
-#define   MRDMODE_BLK_CH0	0x10
-#define   MRDMODE_BLK_CH1	0x20
-#define UDIDETCR0	0x73
-#define UDIDETCR1	0x7B
+#define MRDMODE                 0x71
+#define MRDMODE_INTR_CH0	0x04
+#define MRDMODE_INTR_CH1	0x08
+#define MRDMODE_BLK_CH0         0x10
+#define MRDMODE_BLK_CH1         0x20
+#define UDIDETCR0               0x73
+#define UDIDETCR1               0x7B
 
 typedef struct BMDMAState {
     uint8_t cmd;
@@ -569,6 +631,14 @@ static inline int ube16_to_cpu(const uint8_t *buf)
     return (buf[0] << 8) | buf[1];
 }
 
+#if CONFIG_ATAPI_PT /* only atapi-pt uses it so let's avoid unused
+                            * warning */
+static inline int ube24_to_cpu(const uint8_t *buf)
+{
+    return (buf[0] << 16) | (buf[1] << 8) | buf[2];
+}
+#endif /* CONFIG_ATAPI_PT */
+
 static inline int ube32_to_cpu(const uint8_t *buf)
 {
     return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
diff --git a/qemu-options.hx b/qemu-options.hx
index 38989f1..4992bf9 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -91,6 +91,13 @@ Use @var{file} as CD-ROM image (you cannot use @option{-hdc} and
 using @file{/dev/cdrom} as filename (@pxref{host_drives}).
 ETEXI
 
+DEF("cdrom-reject-fw-upgrade", 0, QEMU_OPTION_cdrom_reject_fw_upgrade,
+    "-cdrom-reject-fw-upgrade     prevent the guest from upgrading cdrom firmware.\n")
+STEXI
+@item -cdrom-reject-fw-upgrade
+Prevent Qemu from passing through ATAPI firmware upgrade command.
+ETEXI
+
 DEF("drive", HAS_ARG, QEMU_OPTION_drive,
     "-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][,index=i]\n"
     "       [,cyls=c,heads=h,secs=s[,trans=t]][,snapshot=on|off]\n"
diff --git a/sysemu.h b/sysemu.h
index dffb2f1..9904c82 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -122,6 +122,7 @@ extern int no_quit;
 extern int semihosting_enabled;
 extern int old_param;
 extern int boot_menu;
+extern int atapi_pt_reject_fw_upgrade;
 
 #ifdef CONFIG_KQEMU
 extern int kqemu_allowed;
diff --git a/vl.c b/vl.c
index 8b2b289..28cd424 100644
--- a/vl.c
+++ b/vl.c
@@ -142,6 +142,7 @@ int main(int argc, char **argv)
 #include "hw/smbios.h"
 #include "hw/xen.h"
 #include "hw/qdev.h"
+#include "hw/atapi-pt.h"
 #include "bt-host.h"
 #include "net.h"
 #include "monitor.h"
@@ -248,6 +249,7 @@ unsigned int nb_prom_envs = 0;
 const char *prom_envs[MAX_PROM_ENVS];
 #endif
 int boot_menu;
+int atapi_pt_reject_fw_upgrade;
 
 int nb_numa_nodes;
 uint64_t node_mem[MAX_NODES];
@@ -1793,6 +1795,7 @@ static int bt_parse(const char *opt)
 
 #define HD_ALIAS "index=%d,media=disk"
 #define CDROM_ALIAS "index=2,media=cdrom"
+#define CDROM_PT_ALIAS "index=2,media=cdrompt"
 #define FD_ALIAS "index=%d,if=floppy"
 #define PFLASH_ALIAS "if=pflash"
 #define MTD_ALIAS "if=mtd"
@@ -5068,6 +5071,9 @@ int main(int argc, char **argv, char **envp)
             case QEMU_OPTION_cdrom:
                 drive_add(optarg, CDROM_ALIAS);
                 break;
+            case QEMU_OPTION_cdrom_reject_fw_upgrade:
+                atapi_pt_reject_fw_upgrade = 1;
+                break;
             case QEMU_OPTION_boot:
                 {
                     static const char * const params[] = {
-- 
1.4.4.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2009-08-12 17:19 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-08-07 17:33 [Qemu-devel] ATAPI pass throug v4 Alexandre Bique
2009-08-07 17:33 ` [Qemu-devel] [PATCH 1/7] atapi: fix up a few comments Alexandre Bique
2009-08-07 17:33   ` [Qemu-devel] [PATCH 2/7] atapi: protocol define updates Alexandre Bique
2009-08-07 17:33     ` [Qemu-devel] [PATCH 3/7] atapi: guessing if the cdrom device is a scsi device Alexandre Bique
2009-08-07 17:33       ` [Qemu-devel] [PATCH 4/7] atapi: adds header guards to hw/pcmia.h Alexandre Bique
2009-08-07 17:33         ` [Qemu-devel] [PATCH 5/7] atapi: adds header guards to hw/mac_dbdma.h Alexandre Bique
2009-08-07 17:33           ` [Qemu-devel] [PATCH 6/7] atapi: made some part of ide.c public and moved some part to atapi Alexandre Bique
2009-08-07 17:33             ` [Qemu-devel] [PATCH 7/7] atapi: introducing atapi pass through Alexandre Bique
2009-08-10 20:09 ` [Qemu-devel] ATAPI pass throug v4 Anthony Liguori
     [not found] <<19074.63829.151234.423348@mariner.uk.xensource.com>
2009-08-12 16:56 ` [Qemu-devel] [PATCH 7/7] atapi: introducing atapi pass through Ian Jackson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).