Patchwork [6/7] atapi: made some part of ide.c public and moved some part to atapi.

login
register
mail settings
Submitter Bique Alexandre
Date Aug. 7, 2009, 5:33 p.m.
Message ID <1249666392-31905-7-git-send-email-alexandre.bique@citrix.com>
Download mbox | patch
Permalink /patch/30956/
State Superseded
Headers show

Comments

Bique Alexandre - Aug. 7, 2009, 5:33 p.m.
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

Patch

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 */
+