--- /dev/null
+diff --git a/hw/atapi-pt.c b/hw/atapi-pt.c
+index 413cc47..2441096 100644
+--- a/hw/atapi-pt.c
++++ b/hw/atapi-pt.c
+@@ -497,18 +497,157 @@ static void ide_atapi_pt_error(IDEState *s)
+ ide_set_irq(s);
+ }
+
+-#if 0
+-static int cmd_count = 0;
+-static int finish_count = 0;
+-static int no_finish_count = 0;
+-
+-static void ide_atapi_pt_sg_io_finished(IDEState *s)
++static void ide_atapi_pt_sg_io_finish(IDEState *s)
+ {
++ struct sg_io_v4 *cmd = &s->atapi_pt.cmd;
++ BDRVRawState *raw_state = s->bs->opaque;
++ int r;
++
++ s->atapi_pt.sense.error_code = 0;
++ s->atapi_pt.sense.sense_key = 0;
++ s->atapi_pt.sense.asc = 0;
++ s->atapi_pt.sense.ascq = 0;
++
++ if(cmd->dout_xfer_len > 0)
++ {
++ int max, i;
++
++ max = cmd->dout_xfer_len;
++ if(max > 0x100)
++ max = 0x100;
++
++ DEBUG_PRINTF("Dout: 0x");
++ for(i = 0; i < max; ++i)
++ DEBUG_PRINTF("%02x ", ((char *)cmd->dout_xferp)[i]);
++ DEBUG_PRINTF("\n");
++ }
++
++
++ /* Send command and wait for reply, SG_IO ioctl*/
++ r = ioctl(raw_state->fd, 0x2285, cmd);
++
++ if(s->atapi_pt.request[0] == GPCMD_MODE_SENSE_10)
++ {
++ DEBUG_PRINTF("Mode sense 10, %d bytes\n", cmd->din_xfer_len);
++ {
++ int i;
++ DEBUG_PRINTF("0x");
++ for(i = 0; i < cmd->din_xfer_len; ++i)
++ DEBUG_PRINTF("%02x ", s->io_buffer[i]);
++ DEBUG_PRINTF("\n");
++ }
++ }
++
++
++ if(s->atapi_pt.request[0] == GPCMD_GET_EVENT_STATUS_NOTIFICATION)
++ {
++ struct stat file_stat;
++
++ if(s->io_buffer[2] == 4 && s->io_buffer[4] == 2)
++ {
++ /* This is a "new media" message, tell any other VMs */
++ DEBUG_PRINTF("[ATAPI] new media\n");
++ system("touch " IDE_ATAPI_PT_NEW_CD_FILE);
++
++ if(stat(IDE_ATAPI_PT_NEW_CD_FILE, &file_stat) != 0)
++ DEBUG_PRINTF("Error writing to new CD file\n");
++ else
++ s->atapi_pt.new_cd_time = file_stat.st_ctime;
++ }
++
++ if(s->io_buffer[2] == 4 && s->io_buffer[4] == 3)
++ {
++ /* This is a "media removed" message, tell any other VMs */
++ DEBUG_PRINTF("[ATAPI] media removed\n");
++ system("touch " IDE_ATAPI_PT_EJECT_CD_FILE);
++
++ if(stat(IDE_ATAPI_PT_EJECT_CD_FILE, &file_stat) != 0)
++ DEBUG_PRINTF("Error writing to eject CD file\n");
++ else
++ s->atapi_pt.eject_time = file_stat.st_ctime;
++ }
++
++ if((s->io_buffer[2] == 4 && s->io_buffer[4] == 0 && s->io_buffer[5] == 2) ||
++ (s->io_buffer[4] == 0 && s->io_buffer[5] == 0 &&
++ s->io_buffer[6] == 0 && s->io_buffer[7] == 0))
++ {
++ /* This is a no activity message we can hijack if we need to */
++
++ if((stat(IDE_ATAPI_PT_NEW_CD_FILE, &file_stat) == 0 &&
++ s->atapi_pt.new_cd_time < file_stat.st_ctime) ||
++ s->atapi_pt.aardvark == 1)
++ {
++ /* 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->atapi_pt.aardvark = 0;
++
++ s->io_buffer[2] = 4;
++ s->io_buffer[4] = 2;
++ s->io_buffer[5] = 2;
++ s->io_buffer[6] = 0;
++ s->io_buffer[7] = 0;
++ }
++ else if(stat(IDE_ATAPI_PT_EJECT_CD_FILE, &file_stat) == 0 &&
++ s->atapi_pt.eject_time < file_stat.st_ctime)
++ {
++ /* There's been an eject message that we haven't seen yet */
++ DEBUG_PRINTF("[ATAPI] media removed message spotted\n");
++ s->atapi_pt.eject_time = file_stat.st_ctime;
++
++ s->io_buffer[2] = 4;
++ s->io_buffer[4] = 3;
++ s->io_buffer[5] = 1;
++ s->io_buffer[6] = 0;
++ s->io_buffer[7] = 0;
++ }
++ }
++ }
++
++ if(r || cmd->driver_status || cmd->transport_status ||
++ cmd->device_status) {
++ /*
++ DEBUG_PRINTF("[\e[1;31mERROR\e[m]\n"
++ "\tcommand 0x%02x (%s)\n"
++ "\terrno: %d (%s)\n"
++ "\tsense: 0x%02x,%02x,%02x (%s)\n"
++ "\tdriver: %d, transport: %d, device: %d\n",
++ command, atapi_cmd_to_str(command),
++ errno,
++ strerror(errno) ? : "(null)",
++ s->atapi_pt.sense.sense_key,
++ s->atapi_pt.sense.asc,
++ s->atapi_pt.sense.ascq,
++ atapi_sense_to_str(s->atapi_pt.sense.sense_key,
++ s->atapi_pt.sense.asc,
++ s->atapi_pt.sense.ascq),
++ cmd->driver_status,
++ cmd->transport_status,
++ cmd->device_status);
++ */
++ DEBUG_PRINTF("[\e[1;31mERROR\e[m] (%s) sense: 0x%02x,%02x,%02x (%s)\n",
++ atapi_cmd_to_str(s->atapi_pt.request[0]),
++ s->atapi_pt.sense.sense_key,
++ s->atapi_pt.sense.asc,
++ s->atapi_pt.sense.ascq,
++ atapi_sense_to_str(s->atapi_pt.sense.sense_key,
++ s->atapi_pt.sense.asc,
++ s->atapi_pt.sense.ascq));
++ ide_atapi_pt_error(s);
++ return;
++ }
++
++ s->atapi_pt.cmd_sent(s);
++}
++
++
++
++
++#if 0
+ BDRVRawState *raw_state = s->bs->opaque;
+ int read_bytes;
+ int i;
+
+- ++finish_count;
+ DEBUG_PRINTF("**** finish (%p, u=%p, raw=%p, fd=%d, %d-%d(%d))\n",
+ s, s->atapi_pt.cmd.usr_ptr,
+ raw_state, raw_state->fd, cmd_count,
+@@ -607,11 +746,12 @@ static void ide_atapi_pt_read_finish(IDEState *s)
+ s->atapi_pt.cmd_sent = ide_atapi_cmd_ok;
+ ATAPI_PT_SEND_PACKET;
+ }
++#endif
+
+ static void ide_atapi_pt_read_pio_end(IDEState *s)
+ {
+ ide_transfer_stop(s);
+- ide_atapi_pt_read_finish(s);
++ ide_atapi_pt_sg_io_finish(s);
+ }
+
+ static void ide_atapi_pt_read_dma_cb(void *opaque, int ret)
+@@ -626,11 +766,9 @@ static void ide_atapi_pt_read_dma_cb(void *opaque, int ret)
+ }
+
+ i = dma_buf_rw(bm, 0);
+- ide_atapi_pt_read_finish(s);
++ ide_atapi_pt_sg_io_finish(s);
+ }
+-#endif
+
+-#if 0
+ static void ide_atapi_pt_wcmd(IDEState *s)
+ {
+ if (s->atapi_dma)
+@@ -657,7 +795,6 @@ static void ide_atapi_pt_wcmd(IDEState *s)
+ ide_set_irq(s);
+ return;
+ }
+-#endif
+
+ static void ide_atapi_pt_read_format_capacities_sent(IDEState *s)
+ {
+@@ -817,9 +954,14 @@ static int ide_atapi_pt_read_cd_block_size(const uint8_t *io_buffer)
+ static void ide_atapi_pt_cmd(IDEState *s)
+ {
+ struct sg_io_v4 *cmd = &s->atapi_pt.cmd;
+- int r;
+- int command;
+- BDRVRawState *raw_state = s->bs->opaque;
++
++ {
++ static int foo = 0;
++
++ if(foo == 0)
++ printf("Welcome to pt 2.1\n");
++ foo = 1;
++ }
+
+ memset(cmd, 0, sizeof (*cmd));
+ memcpy(s->atapi_pt.request, s->io_buffer, ATAPI_PACKET_SIZE);
+@@ -838,11 +980,13 @@ static void ide_atapi_pt_cmd(IDEState *s)
+ s->atapi_pt.reply_size_len = 0;
+
+ cmd->din_xferp = (__u64)s->io_buffer;
+- cmd->dout_xferp = (__u64)(s->io_buffer + ATAPI_PACKET_SIZE);
++ cmd->dout_xferp = (__u64)s->io_buffer;
+ s->atapi_pt.cmd_sent = ide_atapi_cmd_ok;
+- command = s->io_buffer[0];
+
+- switch (s->io_buffer[0])
++ DEBUG_PRINTF("[ATAPI] 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]));
++
++ switch (s->atapi_pt.request[0])
+ {
+ /*******************/
+ /* SIMPLE COMMANDS */
+@@ -881,24 +1025,24 @@ static void ide_atapi_pt_cmd(IDEState *s)
+ case GPCMD_WRITE_AND_VERIFY_10:
+ cmd->dout_xfer_len = ube16_to_cpu(s->io_buffer + 7) * CD_FRAMESIZE;
+
+- DEBUG_PRINTF("Write (%s) %d bytes\n", atapi_cmd_to_str(command),
++ DEBUG_PRINTF("Write (%s) %d bytes\n", atapi_cmd_to_str(s->atapi_pt.request[0]),
+ cmd->dout_xfer_len);
+
+ if (cmd->dout_xfer_len == 0)
+ goto simple_cmd;
+- break;
++ ide_atapi_pt_wcmd(s);
++ return;
+
+ case GPCMD_WRITE_12:
+ cmd->dout_xfer_len = ube32_to_cpu(s->io_buffer + 6);
+
+- DEBUG_PRINTF("Write (%s) %d bytes\n", atapi_cmd_to_str(command),
++ DEBUG_PRINTF("Write (%s) %d bytes\n", atapi_cmd_to_str(s->atapi_pt.request[0]),
+ cmd->dout_xfer_len);
+
+ if (cmd->dout_xfer_len == 0)
+ goto simple_cmd;
+- // ide_atapi_pt_wcmd(s);
+- // return;
+- break;
++ ide_atapi_pt_wcmd(s);
++ return;
+
+ case GPCMD_WRITE_BUFFER:
+ {
+@@ -926,25 +1070,23 @@ static void ide_atapi_pt_cmd(IDEState *s)
+ }
+
+
+- DEBUG_PRINTF("Write (%s) %d bytes\n", atapi_cmd_to_str(command),
++ DEBUG_PRINTF("Write (%s) %d bytes\n", atapi_cmd_to_str(s->atapi_pt.request[0]),
+ cmd->dout_xfer_len);
+
+- // ide_atapi_pt_wcmd(s);
+- // return;
+- break;
++ ide_atapi_pt_wcmd(s);
++ return;
+ }
+
+ case GPCMD_SEND_CUE_SHEET:
+ cmd->dout_xfer_len = ube24_to_cpu(s->io_buffer + 6);
+
+- DEBUG_PRINTF("Write (%s) %d bytes\n", atapi_cmd_to_str(command),
++ DEBUG_PRINTF("Write (%s) %d bytes\n", atapi_cmd_to_str(s->atapi_pt.request[0]),
+ cmd->dout_xfer_len);
+
+ if (cmd->dout_xfer_len == 0)
+ goto simple_cmd;
+- // ide_atapi_pt_wcmd(s);
+- // return;
+- break;
++ ide_atapi_pt_wcmd(s);
++ return;
+
+ case GPCMD_MODE_SELECT_10:
+ cmd->dout_xfer_len = ube16_to_cpu(s->io_buffer + 7);
+@@ -956,65 +1098,63 @@ static void ide_atapi_pt_cmd(IDEState *s)
+ DEBUG_PRINTF("0x");
+ for(i = 0; i < 12; ++i)
+ DEBUG_PRINTF("%02x ", s->io_buffer[i]);
+- DEBUG_PRINTF("\n0x");
++ DEBUG_PRINTF("\n+12 0x");
+ for(i = 0; i < cmd->dout_xfer_len; ++i)
+ DEBUG_PRINTF("%02x ", s->io_buffer[i + 12]);
++ DEBUG_PRINTF("\n+512 0x");
++ for(i = 0; i < cmd->dout_xfer_len; ++i)
++ DEBUG_PRINTF("%02x ", s->io_buffer[i + 512]);
+ DEBUG_PRINTF("\n");
+ }
+
+ if (cmd->dout_xfer_len == 0)
+ goto simple_cmd;
+- // ide_atapi_pt_wcmd(s);
+- // return;
+- break;
++ ide_atapi_pt_wcmd(s);
++ return;
+
+ case GPCMD_SEND_KEY:
+ case GPCMD_SEND_EVENT:
+ cmd->dout_xfer_len = ube16_to_cpu(s->io_buffer + 8);
+
+- DEBUG_PRINTF("Write (%s) %d bytes\n", atapi_cmd_to_str(command),
++ DEBUG_PRINTF("Write (%s) %d bytes\n", atapi_cmd_to_str(s->atapi_pt.request[0]),
+ cmd->dout_xfer_len);
+
+ if (cmd->dout_xfer_len == 0)
+ goto simple_cmd;
+- // ide_atapi_pt_wcmd(s);
+- // return;
+- break;
++ ide_atapi_pt_wcmd(s);
++ return;
+
+ case GPCMD_SEND_OPC:
+ cmd->dout_xfer_len = ube16_to_cpu(s->io_buffer + 7) << 3;
+ CHECK_SAME_VALUE(s->lcyl | (s->hcyl << 8), cmd->dout_xfer_len);
+
+- DEBUG_PRINTF("Write (%s) %d bytes\n", atapi_cmd_to_str(command),
++ DEBUG_PRINTF("Write (%s) %d bytes\n", atapi_cmd_to_str(s->atapi_pt.request[0]),
+ cmd->dout_xfer_len);
+
+ if (cmd->dout_xfer_len == 0)
+ goto simple_cmd;
+- // ide_atapi_pt_wcmd(s);
+- // return;
+- break;
++ ide_atapi_pt_wcmd(s);
++ return;
+
+ case GPCMD_SET_STREAMING:
+ cmd->dout_xfer_len = ube16_to_cpu(s->io_buffer + 9);
+
+- DEBUG_PRINTF("Write (%s) %d bytes\n", atapi_cmd_to_str(command),
++ DEBUG_PRINTF("Write (%s) %d bytes\n", atapi_cmd_to_str(s->atapi_pt.request[0]),
+ cmd->dout_xfer_len);
+
+ if (cmd->dout_xfer_len == 0)
+ goto simple_cmd;
+- // ide_atapi_pt_wcmd(s);
+- // return;
+- break;
++ ide_atapi_pt_wcmd(s);
++ return;
+
+ case GPCMD_FORMAT_UNIT:
+ cmd->dout_xfer_len = 12;
+
+- DEBUG_PRINTF("Write (%s) %d bytes\n", atapi_cmd_to_str(command),
++ DEBUG_PRINTF("Write (%s) %d bytes\n", atapi_cmd_to_str(s->atapi_pt.request[0]),
+ cmd->dout_xfer_len);
+
+- // ide_atapi_pt_wcmd(s);
+- // return;
+- break;
++ ide_atapi_pt_wcmd(s);
++ return;
+
+ /*****************/
+ /* READ COMMANDS */
+@@ -1047,6 +1187,13 @@ static void ide_atapi_pt_cmd(IDEState *s)
+ // 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));
++ {
++ int i;
++ DEBUG_PRINTF("Sense data: 0x");
++ for(i = 0; i < sizeof(s->atapi_pt.sense); ++i)
++ DEBUG_PRINTF("%02x ", s->io_buffer[i]);
++ DEBUG_PRINTF("\n");
++ }
+ ide_atapi_cmd_reply(s, size, max_size);
+ return;
+ }
+@@ -1181,6 +1328,13 @@ static void ide_atapi_pt_cmd(IDEState *s)
+ //s->atapi_pt.reply_size_init = cmd->din_xfer_len;
+ // ATAPI_PT_SEND_PACKET;
+ // return;
++ {
++ int i;
++ DEBUG_PRINTF("Cmd: 0x");
++ for(i = 0; i < ATAPI_PACKET_SIZE; ++i)
++ DEBUG_PRINTF("%02x ", s->io_buffer[i]);
++ DEBUG_PRINTF("\n");
++ }
+ break;
+
+ case GPCMD_GET_EVENT_STATUS_NOTIFICATION:
+@@ -1318,7 +1472,9 @@ static void ide_atapi_pt_cmd(IDEState *s)
+ return;
+ }
+
++ ide_atapi_pt_sg_io_finish(s);
+
++#if 0
+ s->atapi_pt.sense.error_code = 0;
+ s->atapi_pt.sense.sense_key = 0;
+ s->atapi_pt.sense.asc = 0;
+@@ -1327,6 +1483,19 @@ static void ide_atapi_pt_cmd(IDEState *s)
+ /* Send command and wait for reply, SG_IO ioctl*/
+ r = ioctl(raw_state->fd, 0x2285, cmd);
+
++ if(command == GPCMD_MODE_SENSE_10)
++ {
++ DEBUG_PRINTF("Mode sense 10, %d bytes\n", cmd->din_xfer_len);
++ {
++ int i;
++ DEBUG_PRINTF("0x");
++ for(i = 0; i < cmd->din_xfer_len; ++i)
++ DEBUG_PRINTF("%02x ", s->io_buffer[i]);
++ DEBUG_PRINTF("\n");
++ }
++ }
++
++
+ if(command == GPCMD_GET_EVENT_STATUS_NOTIFICATION)
+ {
+ struct stat file_stat;
+@@ -1361,12 +1530,14 @@ static void ide_atapi_pt_cmd(IDEState *s)
+ {
+ /* This is a no activity message we can hijack if we need to */
+
+- if(stat(IDE_ATAPI_PT_NEW_CD_FILE, &file_stat) == 0 &&
+- s->atapi_pt.new_cd_time < file_stat.st_ctime)
++ if((stat(IDE_ATAPI_PT_NEW_CD_FILE, &file_stat) == 0 &&
++ s->atapi_pt.new_cd_time < file_stat.st_ctime) ||
++ s->atapi_pt.aardvark == 1)
+ {
+ /* 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->atapi_pt.aardvark = 0;
+
+ s->io_buffer[2] = 4;
+ s->io_buffer[4] = 2;
+@@ -1424,4 +1595,5 @@ static void ide_atapi_pt_cmd(IDEState *s)
+ }
+
+ s->atapi_pt.cmd_sent(s);
++#endif
+ }