* [Qemu-devel] [PATCH] ATAPI pass through v3
@ 2009-08-06 15:40 Bique Alexandre
2009-08-06 15:47 ` [Qemu-devel] [PATCH 1/4] " Bique Alexandre
` (3 more replies)
0 siblings, 4 replies; 14+ messages in thread
From: Bique Alexandre @ 2009-08-06 15:40 UTC (permalink / raw)
To: qemu-devel
Hi,
Here is the updated ATAPI pass through patches.
What's new ?
- no more switch -cdrom-pt, we rely on bdrv_is_sg() to know if we use the
pass through code or not.
- opening the device with O_NONBLOCK, so it doesn't fail when there is no
media in the drive.
- added a command line switch (-cdrom-allow-fw-upgrade) to enable cdrom
firmware upgrade (see WRITE_BUFFER command). By default the firmware upgrade
is disabled.
- fixed REPORT_KEY command.
- fixed READ_12 command.
Thanks.
--
Alexandre Bique
^ permalink raw reply [flat|nested] 14+ messages in thread
* [Qemu-devel] [PATCH 1/4] ATAPI pass through v3
2009-08-06 15:40 [Qemu-devel] [PATCH] ATAPI pass through v3 Bique Alexandre
@ 2009-08-06 15:47 ` Bique Alexandre
2009-08-06 16:08 ` Christoph Hellwig
2009-08-06 15:48 ` [Qemu-devel] [PATCH 2/4] " Bique Alexandre
` (2 subsequent siblings)
3 siblings, 1 reply; 14+ messages in thread
From: Bique Alexandre @ 2009-08-06 15:47 UTC (permalink / raw)
To: qemu-devel
[-- Attachment #1: Type: text/plain, Size: 37 bytes --]
Better TAG rule
--
Alexandre Bique
[-- Attachment #2: makefile-tags-rule --]
[-- Type: text/x-patch, Size: 323 bytes --]
diff --git a/Makefile b/Makefile
index 2a4b3f3..df5b5c4 100644
--- a/Makefile
+++ b/Makefile
@@ -300,8 +300,9 @@ endif
test speed: all
$(MAKE) -C tests $@
+.PHONY: TAGS
TAGS:
- etags *.[ch] tests/*.[ch] block/*.[ch] hw/*.[ch]
+ find "$(SRC_PATH)" -name '*.[hc]' -print0 | xargs -0 etags
cscope:
rm -f ./cscope.*
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [Qemu-devel] [PATCH 2/4] ATAPI pass through v3
2009-08-06 15:40 [Qemu-devel] [PATCH] ATAPI pass through v3 Bique Alexandre
2009-08-06 15:47 ` [Qemu-devel] [PATCH 1/4] " Bique Alexandre
@ 2009-08-06 15:48 ` Bique Alexandre
2009-08-06 16:09 ` Christoph Hellwig
2009-08-06 15:49 ` [Qemu-devel] [PATCH 3/4] " Bique Alexandre
2009-08-06 15:50 ` [Qemu-devel] [PATCH 4/4] " Bique Alexandre
3 siblings, 1 reply; 14+ messages in thread
From: Bique Alexandre @ 2009-08-06 15:48 UTC (permalink / raw)
To: qemu-devel
[-- Attachment #1: Type: text/plain, Size: 34 bytes --]
Few comments
--
Alexandre Bique
[-- Attachment #2: atapi-comments --]
[-- Type: text/x-patch, Size: 1500 bytes --]
diff --git a/hw/ide.c b/hw/ide.c
index 1e56786..16ca80c 100644
--- a/hw/ide.c
+++ b/hw/ide.c
@@ -1664,9 +1664,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;
@@ -1683,17 +1683,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;
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [Qemu-devel] [PATCH 3/4] ATAPI pass through v3
2009-08-06 15:40 [Qemu-devel] [PATCH] ATAPI pass through v3 Bique Alexandre
2009-08-06 15:47 ` [Qemu-devel] [PATCH 1/4] " Bique Alexandre
2009-08-06 15:48 ` [Qemu-devel] [PATCH 2/4] " Bique Alexandre
@ 2009-08-06 15:49 ` Bique Alexandre
2009-08-06 16:12 ` Christoph Hellwig
2009-08-07 15:49 ` [Qemu-devel] " Juan Quintela
2009-08-06 15:50 ` [Qemu-devel] [PATCH 4/4] " Bique Alexandre
3 siblings, 2 replies; 14+ messages in thread
From: Bique Alexandre @ 2009-08-06 15:49 UTC (permalink / raw)
To: qemu-devel
[-- Attachment #1: Type: text/plain, Size: 44 bytes --]
Updates ATAPI defines.
--
Alexandre Bique
[-- Attachment #2: atapi-defines --]
[-- Type: text/x-patch, Size: 6743 bytes --]
diff --git a/hw/ide.c b/hw/ide.c
index 063f08d..34cdd93 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;
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [Qemu-devel] [PATCH 4/4] ATAPI pass through v3
2009-08-06 15:40 [Qemu-devel] [PATCH] ATAPI pass through v3 Bique Alexandre
` (2 preceding siblings ...)
2009-08-06 15:49 ` [Qemu-devel] [PATCH 3/4] " Bique Alexandre
@ 2009-08-06 15:50 ` Bique Alexandre
2009-08-06 16:23 ` Christoph Hellwig
[not found] ` <m34osj8v77.fsf@neno.mitica>
3 siblings, 2 replies; 14+ messages in thread
From: Bique Alexandre @ 2009-08-06 15:50 UTC (permalink / raw)
To: qemu-devel
[-- Attachment #1: Type: text/plain, Size: 53 bytes --]
The ATAPI pass through feature.
--
Alexandre Bique
[-- Attachment #2: atapi-pass-through --]
[-- Type: text/x-patch, Size: 44204 bytes --]
diff --git a/block/raw-posix.c b/block/raw-posix.c
index bdee07f..0510379 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -154,6 +154,12 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
else if (!(bdrv_flags & BDRV_O_CACHE_WB))
s->open_flags |= O_DSYNC;
+ /* If we open a cdrom device, and there is no media inside, we
+ * have to add O_NONBLOCK to open else it will fail */
+ if (bdrv_get_type_hint(bs) == BDRV_TYPE_CDROM &&
+ bdrv_is_sg(bs))
+ s->open_flags |= O_NONBLOCK;
+
s->fd = -1;
fd = open(filename, s->open_flags, 0644);
if (fd < 0) {
@@ -1027,7 +1033,10 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
s->type = FTYPE_FILE;
#if defined(__linux__) && defined(CONFIG_AIO)
- if (strstart(filename, "/dev/sg", NULL)) {
+ 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
diff --git a/hw/atapi-pt.c b/hw/atapi-pt.c
new file mode 100644
index 0000000..85f6b6a
--- /dev/null
+++ b/hw/atapi-pt.c
@@ -0,0 +1,1002 @@
+int atapi_pt_allow_fw_upgrade = 0;
+
+#define DEBUG_IDE_ATAPI_PT
+
+#define MSF_TO_FRAMES(M, S, F) (((M) * CD_SECS + (S)) * CD_FRAMES + (F))
+
+#ifdef DEBUG_IDE_ATAPI_PT
+# define DPRINTF(Args...) printf(Args)
+# define CHECK_SAME_VALUE(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_SAME_VALUE(Val1, Val2)
+#endif /* DEBUG_IDE_ATAPI_PT */
+
+/* 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 }
+};
+
+#ifdef DEBUG_IDE_ATAPI_PT
+static 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;
+}
+#endif /* DEBUG_IDE_ATAPI_PT */
+
+/* From Table 303 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
+static 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" },
+};
+
+#ifdef DEBUG_IDE_ATAPI_PT
+static 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;
+}
+#endif /* DEBUG_IDE_ATAPI_PT */
+
+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:
+ 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);
+}
+
+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;
+}
+
+static 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_SAME_VALUE(s->lcyl, 0);
+ CHECK_SAME_VALUE(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_SAME_VALUE(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_SAME_VALUE(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_SAME_VALUE(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);
+ }
+ cmd->dxfer_len = nbblocks * blocksize;
+ CHECK_SAME_VALUE(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_SAME_VALUE(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_SAME_VALUE(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;
+ }
+}
+
+static 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..61dc443
--- /dev/null
+++ b/hw/atapi-pt.h
@@ -0,0 +1,6 @@
+#ifndef ATAPI_PT_H
+# define ATAPI_PT_H
+
+extern int atapi_pt_allow_fw_upgrade;
+
+#endif /* !ATAPI_PT_H */
diff --git a/hw/ide.c b/hw/ide.c
index 5c2693e..35cef28 100644
--- a/hw/ide.c
+++ b/hw/ide.c
@@ -36,6 +36,19 @@
#include "sh.h"
#include "dma.h"
+#include <stdint.h>
+#include <limits.h>
+#include <asm/byteorder.h>
+#include <scsi/sg.h>
+#include <assert.h>
+
+#ifdef __linux__
+# include <linux/hdreg.h>
+# define CONFIG_ATAPI_PT 1
+#else
+# define CONFIG_ATAPI_PT 0
+#endif /* __linux__ */
+
/* debug IDE devices */
//#define DEBUG_IDE
//#define DEBUG_IDE_ATAPI
@@ -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 */
@@ -467,6 +524,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;
@@ -1288,6 +1350,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];
@@ -1675,6 +1745,10 @@ static int ide_dvd_read_structure(IDEState *s, int format,
}
}
+#if CONFIG_ATAPI_PT
+#include "atapi-pt.c"
+#endif
+
static void ide_atapi_cmd(IDEState *s)
{
const uint8_t *packet;
@@ -2495,7 +2569,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 {
@@ -2533,7 +2607,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:
@@ -2872,6 +2946,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/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[] = {
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [Qemu-devel] [PATCH 1/4] ATAPI pass through v3
2009-08-06 15:47 ` [Qemu-devel] [PATCH 1/4] " Bique Alexandre
@ 2009-08-06 16:08 ` Christoph Hellwig
0 siblings, 0 replies; 14+ messages in thread
From: Christoph Hellwig @ 2009-08-06 16:08 UTC (permalink / raw)
To: Bique Alexandre; +Cc: qemu-devel
On Thu, Aug 06, 2009 at 04:47:35PM +0100, Bique Alexandre wrote:
> Better TAG rule
This should be the subject of the patch, and the body should include a
short description and a Signed-off-by tag.
Given that it's not directly related to ATAPI support you might want to
send it out seperately.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Qemu-devel] [PATCH 2/4] ATAPI pass through v3
2009-08-06 15:48 ` [Qemu-devel] [PATCH 2/4] " Bique Alexandre
@ 2009-08-06 16:09 ` Christoph Hellwig
0 siblings, 0 replies; 14+ messages in thread
From: Christoph Hellwig @ 2009-08-06 16:09 UTC (permalink / raw)
To: Bique Alexandre; +Cc: qemu-devel
On Thu, Aug 06, 2009 at 04:48:20PM +0100, Bique Alexandre wrote:
> Few comments
Again not a very useful format for the patch.
I'd say something like
Subject: [PATCH n/m] atapi: fix up a few comments
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Qemu-devel] [PATCH 3/4] ATAPI pass through v3
2009-08-06 15:49 ` [Qemu-devel] [PATCH 3/4] " Bique Alexandre
@ 2009-08-06 16:12 ` Christoph Hellwig
2009-08-06 16:17 ` Bique Alexandre
2009-08-07 15:49 ` [Qemu-devel] " Juan Quintela
1 sibling, 1 reply; 14+ messages in thread
From: Christoph Hellwig @ 2009-08-06 16:12 UTC (permalink / raw)
To: Bique Alexandre; +Cc: qemu-devel
Should be
Subject: [PATCH n/m] atapi: protocol define updates
Add some missing ATAPI protocol defintions, and fix up some whitespaces
and comments on the way.
Signed-off-by: Bique Alexandre <alexandre.bique@citrix.com>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Qemu-devel] [PATCH 3/4] ATAPI pass through v3
2009-08-06 16:12 ` Christoph Hellwig
@ 2009-08-06 16:17 ` Bique Alexandre
0 siblings, 0 replies; 14+ messages in thread
From: Bique Alexandre @ 2009-08-06 16:17 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: qemu-devel
On Thursday 06 August 2009 17:12:04 Christoph Hellwig wrote:
> Should be
>
> Subject: [PATCH n/m] atapi: protocol define updates
>
> Add some missing ATAPI protocol defintions, and fix up some whitespaces
> and comments on the way.
>
>
> Signed-off-by: Bique Alexandre <alexandre.bique@citrix.com>
Sorry about that.
If you want I can re-send the patches.
--
Alexandre Bique
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Qemu-devel] [PATCH 4/4] ATAPI pass through v3
2009-08-06 15:50 ` [Qemu-devel] [PATCH 4/4] " Bique Alexandre
@ 2009-08-06 16:23 ` Christoph Hellwig
2009-08-06 17:49 ` Bique Alexandre
[not found] ` <m34osj8v77.fsf@neno.mitica>
1 sibling, 1 reply; 14+ messages in thread
From: Christoph Hellwig @ 2009-08-06 16:23 UTC (permalink / raw)
To: Bique Alexandre; +Cc: qemu-devel
On Thu, Aug 06, 2009 at 04:50:05PM +0100, Bique Alexandre wrote:
> The ATAPI pass through feature.
Again, this should be the subject, and the body should have a short
description on how it's done and why it's useful.
Is the firmware upgrade command really that special that we need to
filter it and not other harmfull commands? That really needs
explanation in the patch description and/or a comment.
Some comments on the patch:
diff --git a/block/raw-posix.c b/block/raw-posix.c
index bdee07f..0510379 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -154,6 +154,12 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
else if (!(bdrv_flags & BDRV_O_CACHE_WB))
s->open_flags |= O_DSYNC;
+ /* If we open a cdrom device, and there is no media inside, we
+ * have to add O_NONBLOCK to open else it will fail */
+ if (bdrv_get_type_hint(bs) == BDRV_TYPE_CDROM &&
+ bdrv_is_sg(bs))
+ s->open_flags |= O_NONBLOCK;
this should be in cdrom_open, that way you won't need the
bdrv_get_type_hint check either.
diff --git a/hw/atapi-pt.c b/hw/atapi-pt.c
new file mode 100644
index 0000000..85f6b6a
--- /dev/null
+++ b/hw/atapi-pt.c
@@ -0,0 +1,1002 @@
+int atapi_pt_allow_fw_upgrade = 0;
+
This seems to be missing any sort of author/copyright line.
+#define MSF_TO_FRAMES(M, S, F) (((M) * CD_SECS + (S)) * CD_FRAMES + (F))
Would be much nicer as a small (inline) function.
+/* 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[] = {
Maybe move all these tables into a separate file?
@@ -1288,6 +1350,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 */
When did gcc start issuing unused warnings for inlines?
@@ -1675,6 +1745,10 @@ static int ide_dvd_read_structure(IDEState *s, int format,
}
}
+#if CONFIG_ATAPI_PT
+#include "atapi-pt.c"
+#endif
Including .c files is areally horrible style, just make the function you
also need from atapi-pt.c non-static.
@@ -2872,6 +2946,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)) {
This check looks reversed to me.
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [Qemu-devel] [PATCH 4/4] ATAPI pass through v3
2009-08-06 16:23 ` Christoph Hellwig
@ 2009-08-06 17:49 ` Bique Alexandre
0 siblings, 0 replies; 14+ messages in thread
From: Bique Alexandre @ 2009-08-06 17:49 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: qemu-devel
On Thursday 06 August 2009 17:23:56 Christoph Hellwig wrote:
> On Thu, Aug 06, 2009 at 04:50:05PM +0100, Bique Alexandre wrote:
> > The ATAPI pass through feature.
>
> Again, this should be the subject, and the body should have a short
> description on how it's done and why it's useful.
>
>
> Is the firmware upgrade command really that special that we need to
> filter it and not other harmfull commands? That really needs
> explanation in the patch description and/or a comment.
>
> Some comments on the patch:
>
>
> diff --git a/block/raw-posix.c b/block/raw-posix.c
> index bdee07f..0510379 100644
> --- a/block/raw-posix.c
> +++ b/block/raw-posix.c
> @@ -154,6 +154,12 @@ static int raw_open_common(BlockDriverState *bs, const
> char *filename, else if (!(bdrv_flags & BDRV_O_CACHE_WB))
> s->open_flags |= O_DSYNC;
>
> + /* If we open a cdrom device, and there is no media inside, we
> + * have to add O_NONBLOCK to open else it will fail */
> + if (bdrv_get_type_hint(bs) == BDRV_TYPE_CDROM &&
> + bdrv_is_sg(bs))
> + s->open_flags |= O_NONBLOCK;
>
> this should be in cdrom_open, that way you won't need the
> bdrv_get_type_hint check either.
Thank you for this one :-)
> diff --git a/hw/atapi-pt.c b/hw/atapi-pt.c
> new file mode 100644
> index 0000000..85f6b6a
> --- /dev/null
> +++ b/hw/atapi-pt.c
> @@ -0,0 +1,1002 @@
> +int atapi_pt_allow_fw_upgrade = 0;
> +
>
> This seems to be missing any sort of author/copyright line.
Done.
> +#define MSF_TO_FRAMES(M, S, F) (((M) * CD_SECS + (S)) * CD_FRAMES + (F))
>
> Would be much nicer as a small (inline) function.
Done.
> +/* 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[] = {
>
> Maybe move all these tables into a separate file?
Alright, moving this in hw/atapi-data.{h,c}
> @@ -1288,6 +1350,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 */
>
> When did gcc start issuing unused warnings for inlines?
Because there is the static keyword.
> @@ -1675,6 +1745,10 @@ static int ide_dvd_read_structure(IDEState *s, int
> format, }
> }
>
> +#if CONFIG_ATAPI_PT
> +#include "atapi-pt.c"
> +#endif
>
> Including .c files is areally horrible style, just make the function you
> also need from atapi-pt.c non-static.
Alright. Doing.
> @@ -2872,6 +2946,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)) {
>
> This check looks reversed to me.
Oh my god, you're right. Fixed!
Thanks for reviewing, I'll send new patches as soon as possible!
--
Alexandre Bique
^ permalink raw reply [flat|nested] 14+ messages in thread
* [Qemu-devel] Re: [PATCH 3/4] ATAPI pass through v3
2009-08-06 15:49 ` [Qemu-devel] [PATCH 3/4] " Bique Alexandre
2009-08-06 16:12 ` Christoph Hellwig
@ 2009-08-07 15:49 ` Juan Quintela
1 sibling, 0 replies; 14+ messages in thread
From: Juan Quintela @ 2009-08-07 15:49 UTC (permalink / raw)
To: Bique Alexandre; +Cc: qemu-devel
Bique Alexandre <alexandre.bique@citrix.com> wrote:
> Updates ATAPI defines.
Appart from Christoph comments, once there, please align correctly the
ones that you are moving, please.
Later, Juan.
^ permalink raw reply [flat|nested] 14+ messages in thread
* [Qemu-devel] Re: [PATCH 4/4] ATAPI pass through v3
[not found] ` <m34osj8v77.fsf@neno.mitica>
@ 2009-08-07 16:34 ` Bique Alexandre
[not found] ` <m3ws5f7et3.fsf@neno.mitica>
0 siblings, 1 reply; 14+ messages in thread
From: Bique Alexandre @ 2009-08-07 16:34 UTC (permalink / raw)
To: Juan Quintela; +Cc: qemu-devel
On Friday 07 August 2009 17:06:36 Juan Quintela wrote:
> Bique Alexandre <alexandre.bique@citrix.com> wrote:
> > The ATAPI pass through feature.
>
> +# define CHECK_SAME_VALUE(Val1, Val2)
>
> Can we call this something like: assert_equal() ? or anything else more
> descriptive?
It's not an assertion because Val1 and Val2 are allowed to be different and it
doesn't call abort. It just displays some debut information. Would CHECK_EQUAL
be alright for you ?
>
> +/* 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[] = {
>
> Please, use C99 intializers:
>
> + { GPCMD_TEST_UNIT_READY, "Test Unit Ready" },
>
> use this format, same for rest of structs
>
> {
> .packet_command = GPCMD_TEST_UNIT_READY,
> .text = "Test Unit Ready"
> },
I see no reason to do that. It takes more place. We are not going to add a lot
of additional fields. And even if we do, this structure should be used only
time at only one place and if we decide to add a new field in the beginning or
the middle of this structure, it should be worth to do some regexp to fix the
declaration.
> +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:
> + assert(0);
> ^^^^^^^
> print a nice error message?
> die?
> something?
I Will do it, but what do you want me to say ?
"We reached a part of the code we should never reach. Please send a bug report
to Qemu developers. Thanks." ?
> + break;
> + }
>
> +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 0x40: block_size = 0; break;
>
> move this one here, same fro the same two with 16 value?
> group all of them by block_size? Same for the rest of the cases.
I can but I don't want to. Because if you want to double check this, you would
prefer to see this sorted so you can check the reference table at the same
time you check your switch case.
> + 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 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
> + }
>
>
> +#if CONFIG_ATAPI_PT
> +#include "atapi-pt.c"
> +#endif
>
> Why do we include it here? coulden't yust compile it as a new file?
I did. I am going to send you my new patches where I made some part of ide.c
public and introduced 3 new headers.
Thanks for review.
--
Alexandre Bique
^ permalink raw reply [flat|nested] 14+ messages in thread
* [Qemu-devel] Re: [PATCH 4/4] ATAPI pass through v3
[not found] ` <m3ws5f7et3.fsf@neno.mitica>
@ 2009-08-07 17:10 ` Bique Alexandre
0 siblings, 0 replies; 14+ messages in thread
From: Bique Alexandre @ 2009-08-07 17:10 UTC (permalink / raw)
To: Juan Quintela; +Cc: qemu-devel
On Friday 07 August 2009 17:46:00 Juan Quintela wrote:
> Bique Alexandre <alexandre.bique@citrix.com> wrote:
> > On Friday 07 August 2009 17:06:36 Juan Quintela wrote:
> >> Bique Alexandre <alexandre.bique@citrix.com> wrote:
> >> > The ATAPI pass through feature.
> >>
> >> +# define CHECK_SAME_VALUE(Val1, Val2)
> >>
> >> Can we call this something like: assert_equal() ? or anything else more
> >> descriptive?
> >
> > It's not an assertion because Val1 and Val2 are allowed to be different
> > and it doesn't call abort. It just displays some debut information. Would
> > CHECK_EQUAL be alright for you ?
> >
> >> +/* 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[] = {
> >>
> >> Please, use C99 intializers:
> >>
> >> + { GPCMD_TEST_UNIT_READY, "Test Unit Ready" },
> >>
> >> use this format, same for rest of structs
> >>
> >> {
> >> .packet_command = GPCMD_TEST_UNIT_READY,
> >> .text = "Test Unit Ready"
> >> },
> >
> > I see no reason to do that. It takes more place. We are not going to add
> > a lot of additional fields. And even if we do, this structure should be
> > used only time at only one place and if we decide to add a new field in
> > the beginning or the middle of this structure, it should be worth to do
> > some regexp to fix the declaration.
>
> Being coherent with everyhing else (new fields use C99 initilizers).
> Consistence is important IMHO.
C89 features are also part of C99. I agree that C99 initializers is a great
feature, but I really feel that it's not the right place to use it :)
> >> +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:
> >> + assert(0);
> >> ^^^^^^^
> >> print a nice error message?
> >> die?
> >> something?
> >
> > I Will do it, but what do you want me to say ?
> > "We reached a part of the code we should never reach. Please send a bug
> > report to Qemu developers. Thanks." ?
>
> The imposible has happened!!! We received a reply with size %d. Please
> inform <foo@bar.com>.
>
> Not sure about the mail/web adderss, etc.
Hey fun. For sure I'll add this :)
> >> + break;
> >> + }
> >>
> >> +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 0x40: block_size = 0; break;
> >>
> >> move this one here, same fro the same two with 16 value?
> >> group all of them by block_size? Same for the rest of the cases.
> >
> > I can but I don't want to. Because if you want to double check this, you
> > would prefer to see this sorted so you can check the reference table at
> > the same time you check your switch case.
>
> Then, were is the reference table pointer? :)
It comes from the "Mt. Fuji Commands for Multimedia Devices SFF8090i v4" page
343.
> One comment indicating it would be nice.
>
> /* The order of this case is the same that table number foo at page X */
>
> Otherwise, it looks very random.
Done.
> >> + 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 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
> >> + }
> >>
> >>
> >> +#if CONFIG_ATAPI_PT
> >> +#include "atapi-pt.c"
> >> +#endif
> >>
> >> Why do we include it here? coulden't yust compile it as a new file?
> >
> > I did. I am going to send you my new patches where I made some part of
> > ide.c public and introduced 3 new headers.
> >
> > Thanks for review.
>
> You are welcome.
Thanks. I send the new patches with git format and git send-mail this time
:-).
--
Alexandre Bique
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2009-08-07 17:12 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-08-06 15:40 [Qemu-devel] [PATCH] ATAPI pass through v3 Bique Alexandre
2009-08-06 15:47 ` [Qemu-devel] [PATCH 1/4] " Bique Alexandre
2009-08-06 16:08 ` Christoph Hellwig
2009-08-06 15:48 ` [Qemu-devel] [PATCH 2/4] " Bique Alexandre
2009-08-06 16:09 ` Christoph Hellwig
2009-08-06 15:49 ` [Qemu-devel] [PATCH 3/4] " Bique Alexandre
2009-08-06 16:12 ` Christoph Hellwig
2009-08-06 16:17 ` Bique Alexandre
2009-08-07 15:49 ` [Qemu-devel] " Juan Quintela
2009-08-06 15:50 ` [Qemu-devel] [PATCH 4/4] " Bique Alexandre
2009-08-06 16:23 ` Christoph Hellwig
2009-08-06 17:49 ` Bique Alexandre
[not found] ` <m34osj8v77.fsf@neno.mitica>
2009-08-07 16:34 ` [Qemu-devel] " Bique Alexandre
[not found] ` <m3ws5f7et3.fsf@neno.mitica>
2009-08-07 17:10 ` Bique Alexandre
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.