+++ /dev/null
-diff --git a/hw/atapi-pt.c b/hw/atapi-pt.c
-index 92f2934..4373a2c 100644
---- a/hw/atapi-pt.c
-+++ b/hw/atapi-pt.c
-@@ -1,29 +1,43 @@
-+#include <scsi/sg.h>
- #include <utime.h>
-+#include <time.h>
-+#include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
-+#include <pthread.h>
-+#include <sys/ioctl.h>
-+#include <unistd.h>
-+#include "xen.h"
-
--#undef DEBUG_IDE_ATAPI_PT
-+/* Even when defined debugging is only enabled if /etc/debugcdrom exists */
-+#define DEBUG_IDE_ATAPI_PT
-
- #define MSF_TO_FRAMES(M, S, F) (((M) * CD_SECS + (S)) * CD_FRAMES + (F))
-+static int log_fd=-1;
-
-+static int debug_fd=-1;
-+static int debug_enabled=-1;
- #ifdef DEBUG_IDE_ATAPI_PT
--# define DEBUG_PRINTF(Args...) printf(Args)
-+# define DEBUG_PRINTF(Args...) atapi_dprintf(Args)
-+# define DEBUG_HEXDUMP(addr, count) atapi_dhexdump(addr, count)
- # 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)); \
-+ if ((Val1) != (Val2)) \
-+ dprintf("[\e[1;32m!VALUE\e[m] %s:%d, %s=%d %s=%d\n", \
-+ __PRETTY_FUNCTION__, __LINE__, #Val1, (Val1), \
-+ #Val2, (Val2)); \
- } while (0)
- #else
- # define DEBUG_PRINTF(Args...)
-+# define DEBUG_HEXDUMP(addr, count)
- # define CHECK_SAME_VALUE(Val1, Val2)
- #endif /* DEBUG_IDE_ATAPI_PT */
-
-
-+#define IDE_ATAPI_PT_DEBUG_ENABLE_FILE "/etc/debugcdrom"
- #define IDE_ATAPI_PT_NEW_CD_FILE "/var/lock/xen-cd-new"
- #define IDE_ATAPI_PT_EJECT_CD_FILE "/var/lock/xen-cd-eject"
--
-+#define IDE_ATAPI_PT_DEBUG_FILE_TEMPLATE "/var/log/cdrom-%d.log"
-
- /* The generic packet command opcodes for CD/DVD Logical Units,
- * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
-@@ -482,6 +496,66 @@ static const char *atapi_sense_to_str(int key, int asc, int ascq)
- }
-
-
-+static void atapi_dprintf(const char *fmt, ...)
-+{
-+ struct stat st;
-+ char debugbuf[2048];
-+ time_t t = time(NULL);
-+ struct tm *tmp = localtime(&t);
-+ struct timeval tv;
-+ va_list args;
-+ int l;
-+ static int sol = 1;
-+ if (debug_enabled == 0)
-+ return;
-+ if (debug_enabled < 0) {
-+ if (stat(IDE_ATAPI_PT_DEBUG_ENABLE_FILE, &st) == 0)
-+ debug_enabled = 1;
-+ else {
-+ debug_enabled = 0;
-+ return;
-+ }
-+ }
-+ if (debug_fd<0) {
-+ sprintf(debugbuf, IDE_ATAPI_PT_DEBUG_FILE_TEMPLATE, domid);
-+ debug_fd=open(debugbuf, O_WRONLY | O_CREAT | O_APPEND, 0666);
-+ }
-+ l = 0;
-+ if (sol) {
-+ gettimeofday(&tv, NULL);
-+ l = snprintf(debugbuf, sizeof(debugbuf)-1, "[%02d:%02d:%02d.%03ld] ",
-+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec, tv.tv_usec/1000);
-+ }
-+ va_start(args, fmt);
-+ l += vsnprintf(debugbuf+l, sizeof(debugbuf)-1-l, fmt, args);
-+ va_end(args);
-+ if ((l>0) && debugbuf[l-1] == '\n') {
-+ sol = 1;
-+ } else {
-+ sol = 0;
-+ }
-+ debugbuf[sizeof(debugbuf)-1] = '\0';
-+ write(debug_fd, debugbuf, strlen(debugbuf));
-+}
-+
-+static void atapi_dhexdump(const void* address, uint32_t len)
-+{
-+ const unsigned char* p = address;
-+ int i, j;
-+
-+ for (i = 0; i < len; i += 16) {
-+ for (j = 0; j < 16 && i + j < len; j++)
-+ atapi_dprintf("%02x ", p[i + j]);
-+ for (; j < 16; j++)
-+ atapi_dprintf(" ");
-+ atapi_dprintf(" ");
-+ for (j = 0; j < 16 && i + j < len; j++)
-+ atapi_dprintf("%c", (p[i + j] < ' ' || p[i + j] > 0x7f) ? '.' : p[i + j]);
-+ atapi_dprintf("\n");
-+ }
-+}
-+
-+
- /* For each SCSI command we need to know up to 3 data sizes. These are:
- * 1. The amount of data to send to the LU.
- * 2. The size of the buffer provided for data sent back from the LU.
-@@ -676,14 +750,63 @@ static void ide_atapi_pt_error(IDEState *s)
- ide_set_irq(s);
- }
-
--static void ide_atapi_pt_do_sg_io(IDEState *s)
-+static void *ide_atapi_pt_sgio_worker_thread(void *arg)
- {
-- struct sg_io_v4 *cmd = &s->atapi_pt.cmd;
-- BDRVRawState *raw_state = s->bs->opaque;
- int r;
-- uint8_t cmd_code = s->atapi_pt.request[0];
-- uint32_t din_desired;
-+ volatile struct sg_io_v4 *cmd;
-+ BDRVRawState *raw_state;
-+ volatile IDEState *s = (volatile IDEState *)arg;
-+
-+ for(;;) {
-+ pthread_mutex_lock(&s->atapi_pt.sgio_mutex);
-+ pthread_cond_wait(&s->atapi_pt.sgio_cv, &s->atapi_pt.sgio_mutex);
-+
-+ /* Send command and wait for reply, SG_IO ioctl*/
-+ cmd = &s->atapi_pt.cmd;
-+ raw_state = s->bs->opaque;
-+ r = ioctl(raw_state->fd, SG_IO, cmd);
-+
-+ /* Unlock _before_ signalling parent */
-+ pthread_mutex_unlock(&s->atapi_pt.sgio_mutex);
-+ write(s->atapi_pt.sgio_wfd, &r, sizeof(int));
-+ }
-+}
-+
-+static int ide_atapi_pt_aio_flush(void *unused)
-+{
-+ return 0;
-+}
-+
-+static void ide_atapi_pt_do_sg_io_complete(void *unused);
-+
-+static void ide_atapi_pt_setup_sgio_thread(IDEState *s)
-+{
-+ int fds[2];
-+
-+ //DEBUG_PRINTF("%s\n", __FUNCTION__);
-+ if (pipe(fds) < 0) {
-+ fprintf(stderr, "atapi-pt failed to create pipe: %m\n");
-+ exit(1);
-+ }
-+ s->atapi_pt.sgio_rfd = fds[0];
-+ s->atapi_pt.sgio_wfd = fds[1];
-+
-+ pthread_mutex_init(&s->atapi_pt.sgio_mutex, NULL);
-+ pthread_cond_init (&s->atapi_pt.sgio_cv, NULL);
-+ if (pthread_create(&s->atapi_pt.sgio_thread, NULL, ide_atapi_pt_sgio_worker_thread, (void *)s))
-+ {
-+ DEBUG_PRINTF("Create CD-ROM worker thread failed\n");
-+ fprintf(stderr, "Create CD-ROM worker thread failed\n");
-+ exit(1);
-+ }
-+ qemu_aio_set_fd_handler(s->atapi_pt.sgio_rfd, ide_atapi_pt_do_sg_io_complete, NULL, ide_atapi_pt_aio_flush, (void *)s);
-+}
-
-+/* Call with ide_atapi_sgio_mutex held */
-+static void ide_atapi_pt_do_sg_io(IDEState *s, int timeout)
-+{
-+ //DEBUG_PRINTF("%s\n", __FUNCTION__);
-+ struct sg_io_v4 *cmd = &s->atapi_pt.cmd;
- assert(cmd->din_xfer_len != (__u32)-1);
-
- s->atapi_pt.sense.error_code = 0;
-@@ -691,9 +814,45 @@ static void ide_atapi_pt_do_sg_io(IDEState *s)
- s->atapi_pt.sense.asc = 0;
- s->atapi_pt.sense.ascq = 0;
-
-+ cmd->timeout = timeout ? timeout : 15000;
-
-- /* Send command and wait for reply, SG_IO ioctl*/
-- r = ioctl(raw_state->fd, 0x2285, cmd);
-+ if ((s->atapi_pt.request[0] == GPCMD_REPORT_KEY) || (s->atapi_pt.request[0] == GPCMD_SEND_KEY)) {
-+ if (cmd->dout_xfer_len > 0) {
-+ DEBUG_PRINTF("write:\n");
-+ DEBUG_HEXDUMP(cmd->dout_xferp, cmd->dout_xfer_len);
-+ }
-+ }
-+
-+ /* Poke worker thread to send command using SG_IO ioctl */
-+ pthread_cond_signal(&s->atapi_pt.sgio_cv);
-+ pthread_mutex_unlock(&s->atapi_pt.sgio_mutex);
-+}
-+
-+static void ide_atapi_pt_do_sg_io_complete(void *arg)
-+{
-+ IDEState *s = (IDEState *)arg;
-+ struct sg_io_v4 *cmd = &s->atapi_pt.cmd;
-+ BDRVRawState *raw_state = s->bs->opaque;
-+ int r;
-+ uint8_t cmd_code = s->atapi_pt.request[0];
-+ uint32_t din_desired;
-+
-+ //DEBUG_PRINTF("%s\n", __FUNCTION__);
-+ assert(s);
-+
-+ /* Get return code of ioctl from worker thread's fd */
-+ read(s->atapi_pt.sgio_rfd, &r, sizeof(int));
-+
-+ if (r) {
-+ DEBUG_PRINTF("[ATAPI] SG_IO is a very naughty boy: %d\n", r);
-+ }
-+
-+ if ((s->atapi_pt.request[0] == GPCMD_REPORT_KEY) || (s->atapi_pt.request[0] == GPCMD_SEND_KEY)) {
-+ if (cmd->din_xfer_len > 0) {
-+ DEBUG_PRINTF("read:\n");
-+ DEBUG_HEXDUMP(cmd->din_xferp, cmd->din_xfer_len);
-+ }
-+ }
-
- if(s->atapi_pt.request[0] == GPCMD_GET_EVENT_STATUS_NOTIFICATION)
- {
-@@ -746,16 +905,18 @@ static void ide_atapi_pt_do_sg_io(IDEState *s)
-
- if(stat(IDE_ATAPI_PT_NEW_CD_FILE, &file_stat) == 0)
- {
-- /* There's been a new media message that we haven't seen yet */
-- DEBUG_PRINTF("[ATAPI] new media message spotted\n");
-- s->atapi_pt.new_cd_time = file_stat.st_ctime;
--
-- s->io_buffer[2] = 4;
-- s->io_buffer[4] = 2;
-- s->io_buffer[5] = 2;
-- s->io_buffer[6] = 0;
-- s->io_buffer[7] = 0;
-- }
-+ if (s->atapi_pt.new_cd_time != file_stat.st_ctime) {
-+ /* There's been a new media message that we haven't seen yet */
-+ s->atapi_pt.new_cd_time = file_stat.st_ctime;
-+ DEBUG_PRINTF("[ATAPI] new media message spotted\n");
-+
-+ s->io_buffer[2] = 4;
-+ s->io_buffer[4] = 2;
-+ s->io_buffer[5] = 2;
-+ s->io_buffer[6] = 0;
-+ s->io_buffer[7] = 0;
-+ }
-+ }
- else if(stat(IDE_ATAPI_PT_EJECT_CD_FILE, &file_stat) == 0 &&
- s->atapi_pt.eject_time < file_stat.st_ctime)
- {
-@@ -832,16 +993,17 @@ static void ide_atapi_pt_do_sg_io(IDEState *s)
- if(din_desired == (__u32)-1)
- din_desired = cmd->din_xfer_len;
-
-- DEBUG_PRINTF("Reply, %d in %d\n", din_desired, cmd->din_xfer_len);
- ide_atapi_cmd_reply(s, din_desired, cmd->din_xfer_len);
- }
-
-+/* Call with ide_atapi_sgio_mutex held */
- static void ide_atapi_pt_dout_fetch_pio_done(IDEState *s)
- {
- ide_transfer_stop(s);
-- ide_atapi_pt_do_sg_io(s);
-+ ide_atapi_pt_do_sg_io(s, 0);
- }
-
-+/* Call with ide_atapi_sgio_mutex held */
- static void ide_atapi_pt_dout_fetch_dma_done(void *opaque, int ret)
- {
- BMDMAState *bm = opaque;
-@@ -850,13 +1012,15 @@ static void ide_atapi_pt_dout_fetch_dma_done(void *opaque, int ret)
-
- if (ret < 0) {
- ide_atapi_io_error(s, ret);
-+ pthread_mutex_unlock(&s->atapi_pt.sgio_mutex);
- return;
- }
-
- i = dma_buf_rw(bm, 0);
-- ide_atapi_pt_do_sg_io(s);
-+ ide_atapi_pt_do_sg_io(s, 0);
- }
-
-+/* Call with ide_atapi_sgio_mutex held */
- static void ide_atapi_pt_wcmd(IDEState *s)
- {
- if (s->atapi_dma)
-@@ -1005,11 +1169,20 @@ static int ide_atapi_pt_read_cd_block_size(const uint8_t *io_buffer)
- return block_size;
- }
-
-+
- static void ide_atapi_pt_cmd(IDEState *s)
- {
-+ int timeout;
- struct sg_io_v4 *cmd = &s->atapi_pt.cmd;
- uint8_t cmd_code;
-
-+
-+ //DEBUG_PRINTF("%s (before mutex)\n", __FUNCTION__);
-+ if (pthread_mutex_trylock(&s->atapi_pt.sgio_mutex)) {
-+ fprintf(stderr, "ide_atapi_pt_cmd() called with existing request processing - ignored!\n");
-+ return;
-+ }
-+
- memset(cmd, 0, sizeof(*cmd));
- memcpy(s->atapi_pt.request, s->io_buffer, ATAPI_PACKET_SIZE);
- cmd_code = s->atapi_pt.request[0];
-@@ -1021,15 +1194,13 @@ static void ide_atapi_pt_cmd(IDEState *s)
- cmd->response = (__u64)&s->atapi_pt.sense;
- cmd->max_response_len = sizeof(s->atapi_pt.sense);
- cmd->timeout = 15000; // 15 seconds
-+ timeout = 0;
-
- s->status |= BUSY_STAT;
-
- cmd->din_xferp = (__u64)s->io_buffer;
- cmd->dout_xferp = (__u64)s->io_buffer;
-
-- DEBUG_PRINTF("[ATAPI] sending command: 0x%02x (\e[0;32m%s\e[m)\n",
-- cmd_code, atapi_cmd_to_str(cmd_code));
--
- cmd->dout_xfer_len = atapi_data_sizes[cmd_code].dout_len_const +
- (ide_atapi_pt_read_field_at_offset(s->atapi_pt.request,
- atapi_data_sizes[cmd_code].dout_len_offset,
-@@ -1043,6 +1214,16 @@ static void ide_atapi_pt_cmd(IDEState *s)
- atapi_data_sizes[cmd_code].alloc_block_size);
-
-
-+ DEBUG_PRINTF("[ATAPI] sending command: 0x%02x (\e[0;32m%s\e[m, in %d out %d)\n",
-+ cmd_code, atapi_cmd_to_str(cmd_code), cmd->din_xfer_len, cmd->dout_xfer_len);
-+
-+ if ((cmd_code == GPCMD_REPORT_KEY) || (cmd_code == GPCMD_SEND_KEY)) {
-+ DEBUG_PRINTF("Command dump:\n");
-+ DEBUG_HEXDUMP(s->atapi_pt.request, 11);
-+ DEBUG_PRINTF("dout_xfer_len: %d din_xfer_len: %d\n",
-+ cmd->dout_xfer_len, cmd->din_xfer_len);
-+ }
-+
- /* A few commands need special attention */
- switch(cmd_code)
- {
-@@ -1054,14 +1235,15 @@ static void ide_atapi_pt_cmd(IDEState *s)
- ide_atapi_pt_set_error(s, SENSE_ILLEGAL_REQUEST,
- ASC_INV_FIELD_IN_CMD_PACKET, 0x70);
-
-+ pthread_mutex_unlock(&s->atapi_pt.sgio_mutex);
- return;
-
- case GPCMD_BLANK: // bigger timeout while blanking
-- cmd->timeout = 1000 * 60 * 80; // 80 mins
-+ timeout = 1000 * 60 * 80; // 80 mins
- break;
-
- case GPCMD_CLOSE_TRACK:
-- cmd->timeout = 1000 * 60 * 5; // 5 mins
-+ timeout = 1000 * 60 * 5; // 5 mins
- break;
-
- case GPCMD_WRITE_BUFFER:
-@@ -1072,6 +1254,7 @@ static void ide_atapi_pt_cmd(IDEState *s)
- s->io_buffer[1] & 7);
- ide_atapi_pt_set_error(s, SENSE_ILLEGAL_REQUEST,
- ASC_ILLEGAL_OPCODE, 0x70);
-+ pthread_mutex_unlock(&s->atapi_pt.sgio_mutex);
- return;
- }
-
-@@ -1091,6 +1274,7 @@ static void ide_atapi_pt_cmd(IDEState *s)
- int size = 8 + s->atapi_pt.sense.add_sense_len;
- memcpy(s->io_buffer, &s->atapi_pt.sense, sizeof (s->atapi_pt.sense));
- ide_atapi_cmd_reply(s, size, max_size);
-+ pthread_mutex_unlock(&s->atapi_pt.sgio_mutex);
- return;
- }
-
-@@ -1152,6 +1336,7 @@ static void ide_atapi_pt_cmd(IDEState *s)
- s->io_buffer[10]);
- ide_atapi_pt_set_error(s, SENSE_ILLEGAL_REQUEST,
- ASC_ILLEGAL_OPCODE, 0x70);
-+ pthread_mutex_unlock(&s->atapi_pt.sgio_mutex);
- return;
- }
- break;
-@@ -1160,7 +1345,10 @@ static void ide_atapi_pt_cmd(IDEState *s)
- if(cmd->dout_xfer_len == (__u32)-1)
- {
- DEBUG_PRINTF("[UNHANDLED SCSI COMMAND] 0x%02x\n", cmd_code);
-- exit(1);
-+ ide_atapi_pt_set_error(s, SENSE_ILLEGAL_REQUEST,
-+ ASC_ILLEGAL_OPCODE, 0x70);
-+ pthread_mutex_unlock(&s->atapi_pt.sgio_mutex);
-+ return;
- }
-
- if(cmd->dout_xfer_len > 0)
-@@ -1169,5 +1357,5 @@ static void ide_atapi_pt_cmd(IDEState *s)
- return;
- }
-
-- ide_atapi_pt_do_sg_io(s);
-+ ide_atapi_pt_do_sg_io(s, timeout);
- }
-diff --git a/hw/ide.c b/hw/ide.c
-index 6c1d60a..2b58728 100644
---- a/hw/ide.c
-+++ b/hw/ide.c
-@@ -435,6 +435,12 @@ typedef struct ATAPIPassThroughState
-
- time_t new_cd_time;
- time_t eject_time;
-+
-+ pthread_t sgio_thread;
-+ pthread_mutex_t sgio_mutex;
-+ pthread_cond_t sgio_cv;
-+ int sgio_rfd;
-+ int sgio_wfd;
- } ATAPIPassThroughState;
- #endif /* __linux__ */
-
-@@ -3220,6 +3226,7 @@ static void ide_init2(IDEState *ide_state,
- }
- #ifdef __linux__
- else if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM_PT) {
-+ ide_atapi_pt_setup_sgio_thread(s);
- // BDRVRawState *raw_state = s->bs->opaque;
- s->is_cdrom = 1;
- s->atapi_cmd = ide_atapi_pt_cmd;
+#endif /* !BLOCK_RAW_POSIX_H */
diff --git a/hw/atapi-pt.c b/hw/atapi-pt.c
new file mode 100644
-index 0000000..92f2934
+index 0000000..4373a2c
--- /dev/null
+++ b/hw/atapi-pt.c
-@@ -0,0 +1,1173 @@
+@@ -0,0 +1,1361 @@
++#include <scsi/sg.h>
+#include <utime.h>
++#include <time.h>
++#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
++#include <pthread.h>
++#include <sys/ioctl.h>
++#include <unistd.h>
++#include "xen.h"
+
-+#undef DEBUG_IDE_ATAPI_PT
++/* Even when defined debugging is only enabled if /etc/debugcdrom exists */
++#define DEBUG_IDE_ATAPI_PT
+
+#define MSF_TO_FRAMES(M, S, F) (((M) * CD_SECS + (S)) * CD_FRAMES + (F))
++static int log_fd=-1;
+
++static int debug_fd=-1;
++static int debug_enabled=-1;
+#ifdef DEBUG_IDE_ATAPI_PT
-+# define DEBUG_PRINTF(Args...) printf(Args)
++# define DEBUG_PRINTF(Args...) atapi_dprintf(Args)
++# define DEBUG_HEXDUMP(addr, count) atapi_dhexdump(addr, count)
+# 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)); \
++ if ((Val1) != (Val2)) \
++ dprintf("[\e[1;32m!VALUE\e[m] %s:%d, %s=%d %s=%d\n", \
++ __PRETTY_FUNCTION__, __LINE__, #Val1, (Val1), \
++ #Val2, (Val2)); \
+ } while (0)
+#else
+# define DEBUG_PRINTF(Args...)
++# define DEBUG_HEXDUMP(addr, count)
+# define CHECK_SAME_VALUE(Val1, Val2)
+#endif /* DEBUG_IDE_ATAPI_PT */
+
+
++#define IDE_ATAPI_PT_DEBUG_ENABLE_FILE "/etc/debugcdrom"
+#define IDE_ATAPI_PT_NEW_CD_FILE "/var/lock/xen-cd-new"
+#define IDE_ATAPI_PT_EJECT_CD_FILE "/var/lock/xen-cd-eject"
-+
++#define IDE_ATAPI_PT_DEBUG_FILE_TEMPLATE "/var/log/cdrom-%d.log"
+
+/* The generic packet command opcodes for CD/DVD Logical Units,
+ * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
+}
+
+
++static void atapi_dprintf(const char *fmt, ...)
++{
++ struct stat st;
++ char debugbuf[2048];
++ time_t t = time(NULL);
++ struct tm *tmp = localtime(&t);
++ struct timeval tv;
++ va_list args;
++ int l;
++ static int sol = 1;
++ if (debug_enabled == 0)
++ return;
++ if (debug_enabled < 0) {
++ if (stat(IDE_ATAPI_PT_DEBUG_ENABLE_FILE, &st) == 0)
++ debug_enabled = 1;
++ else {
++ debug_enabled = 0;
++ return;
++ }
++ }
++ if (debug_fd<0) {
++ sprintf(debugbuf, IDE_ATAPI_PT_DEBUG_FILE_TEMPLATE, domid);
++ debug_fd=open(debugbuf, O_WRONLY | O_CREAT | O_APPEND, 0666);
++ }
++ l = 0;
++ if (sol) {
++ gettimeofday(&tv, NULL);
++ l = snprintf(debugbuf, sizeof(debugbuf)-1, "[%02d:%02d:%02d.%03ld] ",
++ tmp->tm_hour, tmp->tm_min, tmp->tm_sec, tv.tv_usec/1000);
++ }
++ va_start(args, fmt);
++ l += vsnprintf(debugbuf+l, sizeof(debugbuf)-1-l, fmt, args);
++ va_end(args);
++ if ((l>0) && debugbuf[l-1] == '\n') {
++ sol = 1;
++ } else {
++ sol = 0;
++ }
++ debugbuf[sizeof(debugbuf)-1] = '\0';
++ write(debug_fd, debugbuf, strlen(debugbuf));
++}
++
++static void atapi_dhexdump(const void* address, uint32_t len)
++{
++ const unsigned char* p = address;
++ int i, j;
++
++ for (i = 0; i < len; i += 16) {
++ for (j = 0; j < 16 && i + j < len; j++)
++ atapi_dprintf("%02x ", p[i + j]);
++ for (; j < 16; j++)
++ atapi_dprintf(" ");
++ atapi_dprintf(" ");
++ for (j = 0; j < 16 && i + j < len; j++)
++ atapi_dprintf("%c", (p[i + j] < ' ' || p[i + j] > 0x7f) ? '.' : p[i + j]);
++ atapi_dprintf("\n");
++ }
++}
++
++
+/* For each SCSI command we need to know up to 3 data sizes. These are:
+ * 1. The amount of data to send to the LU.
+ * 2. The size of the buffer provided for data sent back from the LU.
+ ide_set_irq(s);
+}
+
-+static void ide_atapi_pt_do_sg_io(IDEState *s)
++static void *ide_atapi_pt_sgio_worker_thread(void *arg)
+{
-+ struct sg_io_v4 *cmd = &s->atapi_pt.cmd;
-+ BDRVRawState *raw_state = s->bs->opaque;
+ int r;
-+ uint8_t cmd_code = s->atapi_pt.request[0];
-+ uint32_t din_desired;
++ volatile struct sg_io_v4 *cmd;
++ BDRVRawState *raw_state;
++ volatile IDEState *s = (volatile IDEState *)arg;
++
++ for(;;) {
++ pthread_mutex_lock(&s->atapi_pt.sgio_mutex);
++ pthread_cond_wait(&s->atapi_pt.sgio_cv, &s->atapi_pt.sgio_mutex);
++
++ /* Send command and wait for reply, SG_IO ioctl*/
++ cmd = &s->atapi_pt.cmd;
++ raw_state = s->bs->opaque;
++ r = ioctl(raw_state->fd, SG_IO, cmd);
++
++ /* Unlock _before_ signalling parent */
++ pthread_mutex_unlock(&s->atapi_pt.sgio_mutex);
++ write(s->atapi_pt.sgio_wfd, &r, sizeof(int));
++ }
++}
++
++static int ide_atapi_pt_aio_flush(void *unused)
++{
++ return 0;
++}
++
++static void ide_atapi_pt_do_sg_io_complete(void *unused);
++
++static void ide_atapi_pt_setup_sgio_thread(IDEState *s)
++{
++ int fds[2];
++
++ //DEBUG_PRINTF("%s\n", __FUNCTION__);
++ if (pipe(fds) < 0) {
++ fprintf(stderr, "atapi-pt failed to create pipe: %m\n");
++ exit(1);
++ }
++ s->atapi_pt.sgio_rfd = fds[0];
++ s->atapi_pt.sgio_wfd = fds[1];
++
++ pthread_mutex_init(&s->atapi_pt.sgio_mutex, NULL);
++ pthread_cond_init (&s->atapi_pt.sgio_cv, NULL);
++ if (pthread_create(&s->atapi_pt.sgio_thread, NULL, ide_atapi_pt_sgio_worker_thread, (void *)s))
++ {
++ DEBUG_PRINTF("Create CD-ROM worker thread failed\n");
++ fprintf(stderr, "Create CD-ROM worker thread failed\n");
++ exit(1);
++ }
++ qemu_aio_set_fd_handler(s->atapi_pt.sgio_rfd, ide_atapi_pt_do_sg_io_complete, NULL, ide_atapi_pt_aio_flush, (void *)s);
++}
+
++/* Call with ide_atapi_sgio_mutex held */
++static void ide_atapi_pt_do_sg_io(IDEState *s, int timeout)
++{
++ //DEBUG_PRINTF("%s\n", __FUNCTION__);
++ struct sg_io_v4 *cmd = &s->atapi_pt.cmd;
+ assert(cmd->din_xfer_len != (__u32)-1);
+
+ s->atapi_pt.sense.error_code = 0;
+ s->atapi_pt.sense.asc = 0;
+ s->atapi_pt.sense.ascq = 0;
+
++ cmd->timeout = timeout ? timeout : 15000;
++
++ if ((s->atapi_pt.request[0] == GPCMD_REPORT_KEY) || (s->atapi_pt.request[0] == GPCMD_SEND_KEY)) {
++ if (cmd->dout_xfer_len > 0) {
++ DEBUG_PRINTF("write:\n");
++ DEBUG_HEXDUMP(cmd->dout_xferp, cmd->dout_xfer_len);
++ }
++ }
++
++ /* Poke worker thread to send command using SG_IO ioctl */
++ pthread_cond_signal(&s->atapi_pt.sgio_cv);
++ pthread_mutex_unlock(&s->atapi_pt.sgio_mutex);
++}
++
++static void ide_atapi_pt_do_sg_io_complete(void *arg)
++{
++ IDEState *s = (IDEState *)arg;
++ struct sg_io_v4 *cmd = &s->atapi_pt.cmd;
++ BDRVRawState *raw_state = s->bs->opaque;
++ int r;
++ uint8_t cmd_code = s->atapi_pt.request[0];
++ uint32_t din_desired;
++
++ //DEBUG_PRINTF("%s\n", __FUNCTION__);
++ assert(s);
++
++ /* Get return code of ioctl from worker thread's fd */
++ read(s->atapi_pt.sgio_rfd, &r, sizeof(int));
++
++ if (r) {
++ DEBUG_PRINTF("[ATAPI] SG_IO is a very naughty boy: %d\n", r);
++ }
+
-+ /* Send command and wait for reply, SG_IO ioctl*/
-+ r = ioctl(raw_state->fd, 0x2285, cmd);
++ if ((s->atapi_pt.request[0] == GPCMD_REPORT_KEY) || (s->atapi_pt.request[0] == GPCMD_SEND_KEY)) {
++ if (cmd->din_xfer_len > 0) {
++ DEBUG_PRINTF("read:\n");
++ DEBUG_HEXDUMP(cmd->din_xferp, cmd->din_xfer_len);
++ }
++ }
+
+ if(s->atapi_pt.request[0] == GPCMD_GET_EVENT_STATUS_NOTIFICATION)
+ {
+
+ if(stat(IDE_ATAPI_PT_NEW_CD_FILE, &file_stat) == 0)
+ {
-+ /* There's been a new media message that we haven't seen yet */
-+ DEBUG_PRINTF("[ATAPI] new media message spotted\n");
-+ s->atapi_pt.new_cd_time = file_stat.st_ctime;
-+
-+ s->io_buffer[2] = 4;
-+ s->io_buffer[4] = 2;
-+ s->io_buffer[5] = 2;
-+ s->io_buffer[6] = 0;
-+ s->io_buffer[7] = 0;
-+ }
++ if (s->atapi_pt.new_cd_time != file_stat.st_ctime) {
++ /* There's been a new media message that we haven't seen yet */
++ s->atapi_pt.new_cd_time = file_stat.st_ctime;
++ DEBUG_PRINTF("[ATAPI] new media message spotted\n");
++
++ s->io_buffer[2] = 4;
++ s->io_buffer[4] = 2;
++ s->io_buffer[5] = 2;
++ s->io_buffer[6] = 0;
++ s->io_buffer[7] = 0;
++ }
++ }
+ else if(stat(IDE_ATAPI_PT_EJECT_CD_FILE, &file_stat) == 0 &&
+ s->atapi_pt.eject_time < file_stat.st_ctime)
+ {
+ if(din_desired == (__u32)-1)
+ din_desired = cmd->din_xfer_len;
+
-+ DEBUG_PRINTF("Reply, %d in %d\n", din_desired, cmd->din_xfer_len);
+ ide_atapi_cmd_reply(s, din_desired, cmd->din_xfer_len);
+}
+
++/* Call with ide_atapi_sgio_mutex held */
+static void ide_atapi_pt_dout_fetch_pio_done(IDEState *s)
+{
+ ide_transfer_stop(s);
-+ ide_atapi_pt_do_sg_io(s);
++ ide_atapi_pt_do_sg_io(s, 0);
+}
+
++/* Call with ide_atapi_sgio_mutex held */
+static void ide_atapi_pt_dout_fetch_dma_done(void *opaque, int ret)
+{
+ BMDMAState *bm = opaque;
+
+ if (ret < 0) {
+ ide_atapi_io_error(s, ret);
++ pthread_mutex_unlock(&s->atapi_pt.sgio_mutex);
+ return;
+ }
+
+ i = dma_buf_rw(bm, 0);
-+ ide_atapi_pt_do_sg_io(s);
++ ide_atapi_pt_do_sg_io(s, 0);
+}
+
++/* Call with ide_atapi_sgio_mutex held */
+static void ide_atapi_pt_wcmd(IDEState *s)
+{
+ if (s->atapi_dma)
+ return block_size;
+}
+
++
+static void ide_atapi_pt_cmd(IDEState *s)
+{
++ int timeout;
+ struct sg_io_v4 *cmd = &s->atapi_pt.cmd;
+ uint8_t cmd_code;
+
++
++ //DEBUG_PRINTF("%s (before mutex)\n", __FUNCTION__);
++ if (pthread_mutex_trylock(&s->atapi_pt.sgio_mutex)) {
++ fprintf(stderr, "ide_atapi_pt_cmd() called with existing request processing - ignored!\n");
++ return;
++ }
++
+ memset(cmd, 0, sizeof(*cmd));
+ memcpy(s->atapi_pt.request, s->io_buffer, ATAPI_PACKET_SIZE);
+ cmd_code = s->atapi_pt.request[0];
+ cmd->response = (__u64)&s->atapi_pt.sense;
+ cmd->max_response_len = sizeof(s->atapi_pt.sense);
+ cmd->timeout = 15000; // 15 seconds
++ timeout = 0;
+
+ s->status |= BUSY_STAT;
+
+ cmd->din_xferp = (__u64)s->io_buffer;
+ cmd->dout_xferp = (__u64)s->io_buffer;
+
-+ DEBUG_PRINTF("[ATAPI] sending command: 0x%02x (\e[0;32m%s\e[m)\n",
-+ cmd_code, atapi_cmd_to_str(cmd_code));
-+
+ cmd->dout_xfer_len = atapi_data_sizes[cmd_code].dout_len_const +
+ (ide_atapi_pt_read_field_at_offset(s->atapi_pt.request,
+ atapi_data_sizes[cmd_code].dout_len_offset,
+ atapi_data_sizes[cmd_code].alloc_block_size);
+
+
++ DEBUG_PRINTF("[ATAPI] sending command: 0x%02x (\e[0;32m%s\e[m, in %d out %d)\n",
++ cmd_code, atapi_cmd_to_str(cmd_code), cmd->din_xfer_len, cmd->dout_xfer_len);
++
++ if ((cmd_code == GPCMD_REPORT_KEY) || (cmd_code == GPCMD_SEND_KEY)) {
++ DEBUG_PRINTF("Command dump:\n");
++ DEBUG_HEXDUMP(s->atapi_pt.request, 11);
++ DEBUG_PRINTF("dout_xfer_len: %d din_xfer_len: %d\n",
++ cmd->dout_xfer_len, cmd->din_xfer_len);
++ }
++
+ /* A few commands need special attention */
+ switch(cmd_code)
+ {
+ ide_atapi_pt_set_error(s, SENSE_ILLEGAL_REQUEST,
+ ASC_INV_FIELD_IN_CMD_PACKET, 0x70);
+
++ pthread_mutex_unlock(&s->atapi_pt.sgio_mutex);
+ return;
+
+ case GPCMD_BLANK: // bigger timeout while blanking
-+ cmd->timeout = 1000 * 60 * 80; // 80 mins
++ timeout = 1000 * 60 * 80; // 80 mins
+ break;
+
+ case GPCMD_CLOSE_TRACK:
-+ cmd->timeout = 1000 * 60 * 5; // 5 mins
++ timeout = 1000 * 60 * 5; // 5 mins
+ break;
+
+ case GPCMD_WRITE_BUFFER:
+ s->io_buffer[1] & 7);
+ ide_atapi_pt_set_error(s, SENSE_ILLEGAL_REQUEST,
+ ASC_ILLEGAL_OPCODE, 0x70);
++ pthread_mutex_unlock(&s->atapi_pt.sgio_mutex);
+ return;
+ }
+
+ int size = 8 + s->atapi_pt.sense.add_sense_len;
+ memcpy(s->io_buffer, &s->atapi_pt.sense, sizeof (s->atapi_pt.sense));
+ ide_atapi_cmd_reply(s, size, max_size);
++ pthread_mutex_unlock(&s->atapi_pt.sgio_mutex);
+ return;
+ }
+
+ s->io_buffer[10]);
+ ide_atapi_pt_set_error(s, SENSE_ILLEGAL_REQUEST,
+ ASC_ILLEGAL_OPCODE, 0x70);
++ pthread_mutex_unlock(&s->atapi_pt.sgio_mutex);
+ return;
+ }
+ break;
+ if(cmd->dout_xfer_len == (__u32)-1)
+ {
+ DEBUG_PRINTF("[UNHANDLED SCSI COMMAND] 0x%02x\n", cmd_code);
-+ exit(1);
++ ide_atapi_pt_set_error(s, SENSE_ILLEGAL_REQUEST,
++ ASC_ILLEGAL_OPCODE, 0x70);
++ pthread_mutex_unlock(&s->atapi_pt.sgio_mutex);
++ return;
+ }
+
+ if(cmd->dout_xfer_len > 0)
+ return;
+ }
+
-+ ide_atapi_pt_do_sg_io(s);
++ ide_atapi_pt_do_sg_io(s, timeout);
+}
diff --git a/hw/ide.c b/hw/ide.c
-index e8d676e..6c1d60a 100644
+index e8d676e..2b58728 100644
--- a/hw/ide.c
+++ b/hw/ide.c
@@ -22,6 +22,7 @@
#define ASC_ILLEGAL_OPCODE 0x20
#define ASC_LOGICAL_BLOCK_OOR 0x21
#define ASC_INV_FIELD_IN_CMD_PACKET 0x24
-@@ -371,15 +399,45 @@
+@@ -371,15 +399,51 @@
#define CFA_INVALID_ADDRESS 0x21
#define CFA_ADDRESS_OVERFLOW 0x2f
+
+ time_t new_cd_time;
+ time_t eject_time;
++
++ pthread_t sgio_thread;
++ pthread_mutex_t sgio_mutex;
++ pthread_cond_t sgio_cv;
++ int sgio_rfd;
++ int sgio_wfd;
+} ATAPIPassThroughState;
+#endif /* __linux__ */
+
/* NOTE: IDEState represents in fact one drive */
typedef struct IDEState {
/* ide config */
-@@ -429,6 +487,10 @@ typedef struct IDEState {
+@@ -429,6 +493,10 @@ typedef struct IDEState {
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;
-@@ -940,6 +1002,8 @@ static inline void ide_set_irq(IDEState *s)
+@@ -940,6 +1008,8 @@ static inline void ide_set_irq(IDEState *s)
if (bm) {
bm->status |= BM_STATUS_INT;
}
qemu_irq_raise(s->irq);
}
}
-@@ -1321,9 +1385,9 @@ static void ide_sector_write(IDEState *s)
+@@ -1321,9 +1391,9 @@ static void ide_sector_write(IDEState *s)
that at the expense of slower write performances. Use this
option _only_ to install Windows 2000. You must disable it
for normal use. */
#endif
{
ide_set_irq(s);
-@@ -1499,6 +1563,13 @@ static inline int ube16_to_cpu(const uint8_t *buf)
+@@ -1499,6 +1569,13 @@ 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];
-@@ -1567,12 +1638,14 @@ static void ide_atapi_io_error(IDEState *s, int ret)
+@@ -1567,12 +1644,14 @@ static void ide_atapi_io_error(IDEState *s, int ret)
static void ide_atapi_cmd_reply_end(IDEState *s)
{
int byte_count_limit, size, ret;
if (s->packet_transfer_size <= 0) {
/* end of transfer */
ide_transfer_stop(s);
-@@ -1582,63 +1655,65 @@ static void ide_atapi_cmd_reply_end(IDEState *s)
+@@ -1582,63 +1661,65 @@ static void ide_atapi_cmd_reply_end(IDEState *s)
#ifdef DEBUG_IDE_ATAPI
printf("status=0x%x\n", s->status);
#endif
}
}
-@@ -1882,6 +1957,10 @@ static int ide_dvd_read_structure(IDEState *s, int format,
+@@ -1882,6 +1963,10 @@ static int ide_dvd_read_structure(IDEState *s, int format,
}
}
static void ide_atapi_cmd(IDEState *s)
{
const uint8_t *packet;
-@@ -1922,7 +2001,6 @@ static void ide_atapi_cmd(IDEState *s)
+@@ -1922,7 +2007,6 @@ static void ide_atapi_cmd(IDEState *s)
ASC_MEDIUM_NOT_PRESENT);
}
break;
case GPCMD_MODE_SENSE_10:
{
int action, code;
-@@ -1935,9 +2013,9 @@ static void ide_atapi_cmd(IDEState *s)
+@@ -1935,9 +2019,9 @@ static void ide_atapi_cmd(IDEState *s)
switch(action) {
case 0: /* current values */
switch(code) {
buf[3] = 0;
buf[4] = 0;
buf[5] = 0;
-@@ -1954,17 +2032,17 @@ static void ide_atapi_cmd(IDEState *s)
+@@ -1954,17 +2038,17 @@ static void ide_atapi_cmd(IDEState *s)
buf[15] = 0x00;
ide_atapi_cmd_reply(s, 16, max_len);
break;
buf[10] = 0x00;
buf[11] = 0x00;
-@@ -1987,6 +2065,7 @@ static void ide_atapi_cmd(IDEState *s)
+@@ -1987,6 +2071,7 @@ static void ide_atapi_cmd(IDEState *s)
buf[27] = 0;
ide_atapi_cmd_reply(s, 28, max_len);
break;
default:
goto error_cmd;
}
-@@ -2110,7 +2189,7 @@ static void ide_atapi_cmd(IDEState *s)
+@@ -2110,7 +2195,7 @@ static void ide_atapi_cmd(IDEState *s)
break;
case GPCMD_MECHANISM_STATUS:
{
cpu_to_ube16(buf, 0);
/* no current LBA */
buf[2] = 0;
-@@ -2125,7 +2204,6 @@ static void ide_atapi_cmd(IDEState *s)
+@@ -2125,7 +2210,6 @@ static void ide_atapi_cmd(IDEState *s)
{
int format, msf, start_track, len;
uint64_t total_sectors;
bdrv_get_geometry(s->bs, &total_sectors);
total_sectors >>= 2;
if (total_sectors == 0) {
-@@ -2279,7 +2357,7 @@ static void ide_atapi_cmd(IDEState *s)
+@@ -2279,7 +2363,7 @@ static void ide_atapi_cmd(IDEState *s)
max_len = 512;
memset(buf, 0, max_len);
* the number of sectors from the media tells us which profile
* to use as current. 0 means there is no media
*/
-@@ -2484,7 +2562,11 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+@@ -2484,7 +2568,11 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
/* Only DEVICE RESET is allowed while BSY or/and DRQ are set */
if ((s->status & (BUSY_STAT|DRQ_STAT)) && val != WIN_DEVICE_RESET)
switch(val) {
case WIN_IDENTIFY:
-@@ -2727,7 +2809,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+@@ -2727,7 +2815,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
else
s->status = READY_STAT | SEEK_STAT;
s->error = 0x01; /* Device 0 passed, Device 1 passed or not
*/
ide_set_irq(s);
break;
-@@ -2748,7 +2830,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+@@ -2748,7 +2836,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,
break;
/* CF-ATA commands */
case CFA_REQ_EXT_ERROR_CODE:
-@@ -3133,8 +3215,20 @@ static void ide_init2(IDEState *ide_state,
+@@ -3133,8 +3221,21 @@ static void ide_init2(IDEState *ide_state,
if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) {
s->is_cdrom = 1;
}
+#ifdef __linux__
+ else if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM_PT) {
++ ide_atapi_pt_setup_sgio_thread(s);
+ // BDRVRawState *raw_state = s->bs->opaque;
+ s->is_cdrom = 1;
+ s->atapi_cmd = ide_atapi_pt_cmd;
s->drive_serial = drive_serial++;
strncpy(s->drive_serial_str, drive_get_serial(s->bs),
diff --git a/vl.c b/vl.c
-index f3b0dae..ae461c8 100644
+index f3b0dae..c9c7c7f 100644
--- a/vl.c
+++ b/vl.c
@@ -2192,8 +2192,10 @@ static int bt_parse(const char *opt)
+#define CDROM_PT_ALIAS "index=1,media=cdrompt"
#else
#define CDROM_ALIAS "index=2,media=cdrom"
-+#define CDROM_PT_ALIAS "index=2,media=cdrompt"
++#define CDROM_PT_ALIAS "index=3,media=cdrompt"
#endif
#define FD_ALIAS "index=%d,if=floppy"
#define PFLASH_ALIAS "if=pflash"