diff --git a/hw/atapi-pt.c b/hw/atapi-pt.c
-index 413cc47..66da45a 100644
+index 413cc47..a097f78 100644
--- a/hw/atapi-pt.c
+++ b/hw/atapi-pt.c
-@@ -497,124 +497,106 @@ static void ide_atapi_pt_error(IDEState *s)
+@@ -1,4 +1,6 @@
++#include <utime.h>
+ #include <sys/stat.h>
++#include <fcntl.h>
+
+ #define DEBUG_IDE_ATAPI_PT
+
+@@ -480,6 +482,183 @@ static const char *atapi_sense_to_str(int key, int asc, int ascq)
+ }
+
+
++/* 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.
++ * 3. The amount of data the LU wanted to send.
++ *
++ * These are all measured in bytes.
++ *
++ * The table ide_atapi_cmd_data_sizes specifies how to determine these sizes for
++ * each SCSI command. Each size is given by:
++ *
++ * constant + (base * block_size)
++ *
++ * where base is a value specified within the command data. This is specified in
++ * our table as an offset into the data at which the value starts and the size of
++ * the value, in bytes. All base value are assumed to be MSB first (lowest offset).
++ *
++ * The number of bytes forming the base value can only take values between 0 and 4
++ * inclusive, with 0 indicating that there is no base value.
++ *
++ * The amount of data to send to the LU and the size of the receiving buffer are
++ * both determined from the CDB. A value of 0 means that no data is transfered and
++ * a value of -1 indicates that the table entry is invalid (eg undefined command).
++ *
++ * The amount of data the LU wanted to return is determined from the returned data.
++ * A value of 0 is invalid and a value of -1 indicates that this size is the same
++ * as the receiving buffer size.
++ *
++ * A few commands are too complex for this scheme and so are handled by code in
++ * ide_atapi_pt_cmd() and ide_atapi_pt_do_sg_io().
++ */
++static struct
++{
++ int dout_len_const; // size of data to send to LU, dout
++ int dout_len_offset;
++ int dout_len_size;
++ int dout_block_size;
++
++ int alloc_len_const; // size of buffer to receive din
++ int alloc_len_offset;
++ int alloc_len_size;
++ int alloc_block_size;
++
++ int din_len_const; // size of data LU wanted to send, din
++ int din_len_offset;
++ int din_len_size;
++ int din_block_size;
++} atapi_data_sizes[256] = {
++ // dout buffer din
++ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 0x00 GPCMD_TEST_UNIT_READY
++ {-1},{-1}, // 0x01-0x02
++ {-1, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0}, // 0x03 GPCMD_REQUEST_SENSE
++ {12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 0x04 GPCMD_FORMAT_UNIT
++ {-1},{-1},{-1},{-1},{-1},{-1},{-1},{-1}, // 0x05-0x0c
++ {-1},{-1},{-1},{-1},{-1}, // 0x0d-0x11
++ { 0, 0, 0, 0, 0, 4, 1, 1, 5, 4, 1, 1}, // 0x12 GPCMD_INQUIRY
++ {-1},{-1},{-1},{-1},{-1},{-1},{-1},{-1}, // 0x13-0x1a
++ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 0x1b GPCMD_START_STOP_UNIT
++ {-1},{-1}, // 0x1c-0x1d
++ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 0x1e GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL
++ {-1},{-1},{-1},{-1}, // 0x1f-0x20
++ { 0, 0, 0, 0, 0, 7, 2, 1, 4, 3, 1, 1}, // 0x23 GPCMD_READ_FORMAT_CAPACITIES
++ {-1}, // 0x24
++ { 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0}, // 0x25 GPCMD_READ_CDVD_CAPACITY
++ {-1},{-1}, // 0x26-0x27
++ { 0, 0, 0, 0, 0, 7, 2, CD_FRAMESIZE,
++ -1, 0, 0, 0}, // 0x28 GPCMD_READ_10
++ {-1}, // 0x29
++ { 0, 7, 2, CD_FRAMESIZE,
++ 0, 0, 0, 0 , 0, 0, 0, 0}, // 0x2a GPCMD_WRITE_10
++ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 0x2b GPCMD_SEEK
++ {-1},{-1}, // 0x2c-0x2d
++ { 0, 7, 2, CD_FRAMESIZE,
++ 0, 0, 0, 0, 0, 0, 0, 0}, // 0x2e GPCMD_WRITE_AND_VERIFY_10
++ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 0x2f GPCMD_VERIFY_10
++ {-1},{-1},{-1},{-1},{-1}, // 0x30-0x34
++ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 0x35 GPCMD_FLUSH_CACHE
++ {-1},{-1},{-1},{-1},{-1}, // 0x36-0x3a
++ { 0, 6, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0}, // 0x3b GPCMD_WRITE_BUFFER
++ { 0, 0, 0, 0, 0, 6, 3, 1, 4, 1, 3, 1}, // 0x3c GPCMD_READ_BUFFER
++ {-1},{-1},{-1},{-1},{-1}, // 0x3d-0x41
++ { 0, 0, 0, 0, 0, 7, 2, 1, 4, 2, 2, 1}, // 0x42 GPCMD_READ_SUBCHANNEL
++ { 0, 0, 0, 0, 0, 7, 2, 1, 2, 0, 2, 1}, // 0x43 GPCMD_READ_TOC_PMA_ATIP
++ { 0, 0, 0, 0, 0, 7, 2, 1, 8, 0, 0, 0}, // 0x44 GPCMD_READ_HEADER
++ { 0, 0, 0, 0, 0, 7, 2, CD_FRAMESIZE,
++ -1, 0, 0, 0}, // 0x45 GPCMD_PLAY_AUDIO_10
++ { 0, 0, 0, 0, 0, 7, 2, 1, 4, 0, 4, 1}, // 0x46 GPCMD_GET_CONFIGURATION
++ { 0, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0}, // 0x47 GPCMD_PLAY_AUDIO_MSF
++ {-1},{-1}, // 0x48-0x49
++ { 0, 0, 0, 0, 0, 7, 2, 1, 2, 0, 2, 1}, // 0x4a GPCMD_GET_EVENT_STATUS_NOTIFICATION
++ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 0x4b GPCMD_PAUSE_RESUME
++ {-1},{-1}, // 0x4c-0x4d
++ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 0x4e GPCMD_STOP_PLAY_SCAN
++ {-1},{-1}, // 0x4f-0x50
++ { 0, 0, 0, 0, 0, 7, 2, 1, 2, 0, 2, 1}, // 0x51 GPCMD_READ_DISC_INFO
++ { 0, 0, 0, 0, 0, 7, 2, 1, 2, 0, 2, 1}, // 0x52 GPCMD_READ_TRACK_RZONE_INFO
++ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 0x53 GPCMD_RESERVE_RZONE_TRACK
++ { 0, 7, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0}, // 0x54 GPCMD_SEND_OPC
++ { 0, 7, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0}, // 0x55 GPCMD_MODE_SELECT_10
++ {-1},{-1}, // 0x56-0x57
++ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 0x58 GPCMD_REPAIR_RZONE_TRACK
++ {-1}, // 0x59
++ { 0, 0, 0, 0, 0, 7, 2, 1, 2, 0, 2, 1}, // 0x5a GPCMD_MODE_SENSE_10
++ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 0x5b GPCMD_CLOSE_TRACK
++ { 0, 0, 0, 0, 0, 7, 2, 1, 2, 0, 2, 1}, // 0x5c GPCMD_READ_BUFFER_CAPACITY
++ { 0, 6, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0}, // 0x5d GPCMD_SEND_CUE_SHEET
++ {-1},{-1}, // 0x5e-0x5f
++ {-1},{-1},{-1},{-1},{-1},{-1},{-1},{-1}, // 0x60-0x67
++ {-1},{-1},{-1},{-1},{-1},{-1},{-1},{-1}, // 0x68-0x6f
++ {-1},{-1},{-1},{-1},{-1},{-1},{-1},{-1}, // 0x70-0x77
++ {-1},{-1},{-1},{-1},{-1},{-1},{-1},{-1}, // 0x78-0x7f
++ {-1},{-1},{-1},{-1},{-1},{-1},{-1},{-1}, // 0x80-0x87
++ {-1},{-1},{-1},{-1},{-1},{-1},{-1},{-1}, // 0x88-0x8f
++ {-1},{-1},{-1},{-1},{-1},{-1},{-1},{-1}, // 0x90-0x97
++ {-1},{-1},{-1},{-1},{-1},{-1},{-1},{-1}, // 0x98-0x9f
++ {-1}, // 0xa0
++ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 0xa1 GPCMD_BLANK
++ { 0, 8, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0}, // 0xa2 GPCMD_SEND_EVENT
++ { 0, 8, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0}, // 0xa3 GPCMD_SEND_KEY
++ { 0, 0, 0, 0, 0, 8, 2, 1, 2, 0, 2, 1}, // 0xa4 GPCMD_REPORT_KEY
++ {-1}, // 0xa5
++ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 0xa6 GPCMD_LOAD_UNLOAD
++ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 0xa7 GPCMD_SET_READ_AHEAD
++ { 0, 0, 0, 0, 0, 6, 4, CD_FRAMESIZE,
++ -1, 0, 0, 0}, // 0xa8 GPCMD_READ_12
++ {-1}, // 0xa9
++ { 0, 6, 4, CD_FRAMESIZE,
++ 0, 0, 0, 0, 0, 0, 0, 0}, // 0xaa GPCMD_WRITE_12
++ {-1}, // 0xab
++ { 0, 0, 0, 0, 0, 8, 2, 1, 4, 0, 4, 1}, // 0xac GPCMD_GET_PERFORMANCE
++ { 0, 0, 0, 0, 0, 8, 2, 1, 2, 0, 2, 1}, // 0xad GPCMD_READ_DVD_STRUCTURE
++ {-1},{-1},{-1},{-1},{-1},{-1},{-1},{-1}, // 0xae-0xb5
++ { 0, 9, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0}, // 0xb6 GPCMD_SET_STREAMING
++ {-1},{-1}, // 0xb7-0xb8
++ { 0, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0}, // 0xb9 GPCMD_READ_CD_MSF
++ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 0xba GPCMD_SCAN
++ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 0xbb GPCMD_SET_SPEED - Not in docs
++ {-1}, // 0xbc
++ { 0, 0, 0, 0, 0, 8, 2, 1, 8, 6, 2, 1}, // 0xbd GPCMD_MECHANISM_STATUS
++ { 0, 0, 0, 0, 0, 6, 3, 1, -1, 0, 0, 0}, // 0xbe GPCMD_READ_CD
++ { 0, 8, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0}, // 0xbf GPCMD_SEND_DVD_STRUCTURE
++ {-1},{-1},{-1},{-1},{-1},{-1},{-1},{-1}, // 0xc0-0xc7
++ {-1},{-1},{-1},{-1},{-1},{-1},{-1},{-1}, // 0xc8-0xcf
++ {-1},{-1},{-1},{-1},{-1},{-1},{-1},{-1}, // 0xd0-0xd7
++ {-1},{-1},{-1},{-1},{-1},{-1},{-1},{-1}, // 0xd8-0xdf
++ {-1},{-1},{-1},{-1},{-1},{-1},{-1},{-1}, // 0xe0-0xe7
++ {-1},{-1},{-1},{-1},{-1},{-1},{-1},{-1}, // 0xe8-0xef
++ {-1},{-1},{-1},{-1},{-1},{-1},{-1},{-1}, // 0xf0-0xf7
++ {-1},{-1},{-1},{-1},{-1},{-1},{-1},{-1} // 0xf8-0xff
++};
++
++// TODO: check these commands:
++//# define GPCMD_PLAY_CD 0xbc
++//# define GPCMD_PLAYAUDIO_TI 0x48
++//# define GPCMD_GET_MEDIA_STATUS 0xda
++
++
++static uint32_t ide_atapi_pt_read_field_at_offset(uint8_t *data, int offset, int field_size)
++{
++ switch(field_size)
++ {
++ case 0:
++ return 0;
++ case 1:
++ return data[offset];
++ case 2:
++ return ube16_to_cpu(data + offset);
++ case 3:
++ return ube24_to_cpu(data + offset);
++ case 4:
++ return ube32_to_cpu(data + offset);
++ default:
++ assert(0);
++ return -1;
++ }
++}
++
++
+ static void ide_atapi_pt_set_error(IDEState *s, int sense_key, int asc, int error)
+ {
+ s->atapi_pt.sense.sense_key = sense_key;
+@@ -497,124 +676,173 @@ static void ide_atapi_pt_error(IDEState *s)
ide_set_irq(s);
}
- int read_bytes;
- int i;
+ int r;
++ uint8_t cmd_code = s->atapi_pt.request[0];
++ uint32_t din_desired;
- ++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,
- finish_count + no_finish_count, no_finish_count);
-+ 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;
++ assert(cmd->din_xfer_len != (__u32)-1);
- DEBUG_PRINTF("Preread: 0x");
- for(i = 0; i < sizeof(s->atapi_pt.cmd); ++i)
- DEBUG_PRINTF("%02x", ((unsigned char *)&s->atapi_pt.cmd)[i]);
- DEBUG_PRINTF("\n");
-+ /* Send command and wait for reply, SG_IO ioctl*/
-+ r = ioctl(raw_state->fd, 0x2285, cmd);
++ 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 1
- read_bytes = read(raw_state->fd, &s->atapi_pt.cmd, sizeof (s->atapi_pt.cmd));
-+ if(s->atapi_pt.request[0] == GPCMD_GET_EVENT_STATUS_NOTIFICATION)
-+ {
-+ struct stat file_stat;
- DEBUG_PRINTF("Postread: 0x");
- for(i = 0; i < sizeof(s->atapi_pt.cmd); ++i)
- DEBUG_PRINTF("\n");
- read_bytes = i;
-#endif
+-
+- // DEBUG_PRINTF("finish read\n");
++ /* Send command and wait for reply, SG_IO ioctl*/
++ r = ioctl(raw_state->fd, 0x2285, cmd);
+
+- if (read_bytes != sizeof (s->atapi_pt.cmd))
++ if(s->atapi_pt.request[0] == GPCMD_GET_EVENT_STATUS_NOTIFICATION)
+ {
+- ide_atapi_pt_error(s);
+- s->atapi_pt.cmd_sent = NULL;
+- return;
++ struct stat file_stat;
++ int fd;
++
+ 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 detected\n");
-+ system("touch " IDE_ATAPI_PT_NEW_CD_FILE);
-
-- // DEBUG_PRINTF("finish read\n");
++
++ fd = open(IDE_ATAPI_PT_NEW_CD_FILE, O_WRONLY | O_TRUNC | O_CREAT, 0666);
++ if(fd < 0) {
++ DEBUG_PRINTF("Error touching new CD file\n");
++ } else {
++ close(fd);
++ utime(IDE_ATAPI_PT_NEW_CD_FILE, NULL);
++ }
++
+ 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 (read_bytes != sizeof (s->atapi_pt.cmd))
-- {
-- ide_atapi_pt_error(s);
-- s->atapi_pt.cmd_sent = NULL;
-- return;
++
+ 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);
++
++ fd = open(IDE_ATAPI_PT_NEW_CD_FILE, O_WRONLY | O_TRUNC | O_CREAT, 0666);
++ if(fd < 0) {
++ DEBUG_PRINTF("Error touching new CD file\n");
++ } else {
++ close(fd);
++ utime(IDE_ATAPI_PT_NEW_CD_FILE, NULL);
++ }
+
+ if(stat(IDE_ATAPI_PT_EJECT_CD_FILE, &file_stat) != 0)
+ DEBUG_PRINTF("Error writing to eject CD file\n");
+ s->atapi_pt.sense.ascq));
ide_atapi_pt_error(s);
- s->atapi_pt.cmd_sent = NULL;
-- return;
-- }
+ return;
+ }
- if(s->atapi_pt.cmd_sent == NULL) {
- static int null_count = 0;
- ++null_count;
- DEBUG_PRINTF("\e[1;31m%s called with cmd_sent = NULL %d time%c\e[m\n",
- __FUNCTION__, null_count, (null_count == 1) ? ' ' : 's');
-- ide_atapi_cmd_ok(s);
++
++ if(cmd->din_xfer_len == 0)
++ {
++ // Nothing else to do
+ ide_atapi_cmd_ok(s);
- s->atapi_pt.cmd_sent = NULL;
return;
}
- s->atapi_pt.cmd_sent = NULL;
- DEBUG_PRINTF("**** finished (%p)\n", s);
-}
--
+
-#define ATAPI_PT_SEND_PACKET \
- do { \
- BDRVRawState *raw_state = s->bs->opaque; \
- s->atapi_pt.cmd.dout_xferp = (__u64)s->io_buffer;
- s->atapi_pt.cmd_sent = ide_atapi_cmd_ok;
- ATAPI_PT_SEND_PACKET;
-+ s->atapi_pt.cmd_sent(s);
++ din_desired = atapi_data_sizes[cmd_code].din_len_const +
++ (ide_atapi_pt_read_field_at_offset(s->io_buffer,
++ atapi_data_sizes[cmd_code].din_len_offset,
++ atapi_data_sizes[cmd_code].din_len_size) *
++ atapi_data_sizes[cmd_code].din_block_size);
++
++ /* cmd->din_xfer_len is the size of the buffer provided for the din data,
++ * din_desired in the size of the data the LU tried to send to us. Either one
++ * may be bigger. */
++
++ if(s->atapi_pt.request[0] == GPCMD_READ_BUFFER)
++ {
++ switch (s->atapi_pt.request[1] & 7)
++ {
++ case 0: // data with header, as specified in atapi_data_sizes table
++ break;
++
++ case 2: // data only
++ din_desired = cmd->din_xfer_len;
++ break;
++
++ case 3: // header only
++ din_desired = 4;
++ break;
++
++ case 1: // vendor specific
++ default:
++ DEBUG_PRINTF("\e[3;31mIllegal read buffer mode %d\e[m\n",
++ s->io_buffer[1] & 7);
++ ide_atapi_pt_set_error(s, SENSE_ILLEGAL_REQUEST,
++ ASC_ILLEGAL_OPCODE, 0x70);
++ return;
++ }
++ }
++
++ 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);
}
-static void ide_atapi_pt_read_pio_end(IDEState *s)
{
BMDMAState *bm = opaque;
IDEState *s = bm->ide_if;
-@@ -626,11 +608,9 @@ static void ide_atapi_pt_read_dma_cb(void *opaque, int ret)
+@@ -626,11 +854,9 @@ static void ide_atapi_pt_read_dma_cb(void *opaque, int ret)
}
i = dma_buf_rw(bm, 0);
static void ide_atapi_pt_wcmd(IDEState *s)
{
if (s->atapi_dma)
-@@ -638,7 +618,7 @@ static void ide_atapi_pt_wcmd(IDEState *s)
+@@ -638,7 +864,7 @@ static void ide_atapi_pt_wcmd(IDEState *s)
/* DMA */
s->io_buffer_index = 0;
s->io_buffer_size = s->atapi_pt.cmd.dout_xfer_len;
return;
}
-@@ -653,11 +633,10 @@ static void ide_atapi_pt_wcmd(IDEState *s)
+@@ -653,44 +879,10 @@ static void ide_atapi_pt_wcmd(IDEState *s)
~ATAPI_INT_REASON_IO &
~ATAPI_INT_REASON_CD;
ide_transfer_start(s, s->io_buffer, s->atapi_pt.cmd.dout_xfer_len,
return;
}
-#endif
+-
+-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.din_xfer_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;
+- }
+- ide_atapi_cmd_reply(s, size, s->atapi_pt.cmd.din_xfer_len);
+-}
- static void ide_atapi_pt_read_format_capacities_sent(IDEState *s)
+ static int ide_atapi_pt_read_cd_block_size(const uint8_t *io_buffer)
{
-@@ -817,9 +796,6 @@ static int ide_atapi_pt_read_cd_block_size(const uint8_t *io_buffer)
+@@ -813,221 +1005,66 @@ 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)
{
struct sg_io_v4 *cmd = &s->atapi_pt.cmd;
- int r;
- int command;
- BDRVRawState *raw_state = s->bs->opaque;
++ uint8_t cmd_code;
- memset(cmd, 0, sizeof (*cmd));
+- memset(cmd, 0, sizeof (*cmd));
++ memset(cmd, 0, sizeof(*cmd));
memcpy(s->atapi_pt.request, s->io_buffer, ATAPI_PACKET_SIZE);
-@@ -838,11 +814,13 @@ static void ide_atapi_pt_cmd(IDEState *s)
- s->atapi_pt.reply_size_len = 0;
++ cmd_code = s->atapi_pt.request[0];
+ cmd->guard = 'Q';
+ cmd->protocol = 0;
+ cmd->subprotocol = 0;
+ cmd->request_len = ATAPI_PACKET_SIZE;
+ cmd->request = (__u64)s->atapi_pt.request;
+ cmd->response = (__u64)&s->atapi_pt.sense;
+- cmd->max_response_len = sizeof (s->atapi_pt.sense);
++ cmd->max_response_len = sizeof(s->atapi_pt.sense);
+ cmd->timeout = 15000; // 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;
++ s->status |= BUSY_STAT;
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;
+- s->atapi_pt.cmd_sent = ide_atapi_cmd_ok;
- command = s->io_buffer[0];
++ cmd->dout_xferp = (__u64)s->io_buffer;
- switch (s->io_buffer[0])
+- {
+- /*******************/
+- /* SIMPLE COMMANDS */
+- /*******************/
+ 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 */
-@@ -880,25 +858,19 @@ static void ide_atapi_pt_cmd(IDEState *s)
- case GPCMD_WRITE_10:
- case GPCMD_WRITE_AND_VERIFY_10:
- cmd->dout_xfer_len = ube16_to_cpu(s->io_buffer + 7) * CD_FRAMESIZE;
--
++ cmd_code, atapi_cmd_to_str(cmd_code));
+
+- 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);
+- break;
++ 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].dout_len_size) *
++ atapi_data_sizes[cmd_code].dout_block_size);
+
+- /******************/
+- /* WRITE COMMANDS */
+- /******************/
++ cmd->din_xfer_len = atapi_data_sizes[cmd_code].alloc_len_const +
++ (ide_atapi_pt_read_field_at_offset(s->atapi_pt.request,
++ atapi_data_sizes[cmd_code].alloc_len_offset,
++ atapi_data_sizes[cmd_code].alloc_len_size) *
++ atapi_data_sizes[cmd_code].alloc_block_size);
+
+- case GPCMD_WRITE_10:
+- 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),
- cmd->dout_xfer_len);
-
- if (cmd->dout_xfer_len == 0)
- goto simple_cmd;
+- 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);
+-
+- 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),
- cmd->dout_xfer_len);
-
- if (cmd->dout_xfer_len == 0)
- goto simple_cmd;
+- 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:
+-
+- case GPCMD_WRITE_BUFFER:
++ /* A few commands need special attention */
++ switch(cmd_code)
{
-@@ -925,109 +897,68 @@ static void ide_atapi_pt_cmd(IDEState *s)
- goto illegal_request;
- }
-
+- int32_t parameter_list_length = ube24_to_cpu(s->io_buffer + 3);
+- int8_t mode = s->io_buffer[1] & 0x03;
+-
+- 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->dout_xfer_len = parameter_list_length + 4;
+- break;
+- case 0x2: // Data mode
+- cmd->dout_xfer_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:
+- goto illegal_request;
+- }
+-
-
- DEBUG_PRINTF("Write (%s) %d bytes\n", atapi_cmd_to_str(command),
- 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);
++ case GPCMD_BLANK: // bigger timeout while blanking
++ cmd->timeout = 1000 * 60 * 80; // 80 mins
+ break;
+- }
-
+- 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),
- cmd->dout_xfer_len);
-
- if (cmd->dout_xfer_len == 0)
- goto simple_cmd;
+- if (cmd->dout_xfer_len == 0)
+- goto simple_cmd;
- // ide_atapi_pt_wcmd(s);
- // return;
-- break;
-+
-+ ide_atapi_pt_wcmd(s);
-+ return;
++ case GPCMD_CLOSE_TRACK:
++ cmd->timeout = 1000 * 60 * 5; // 5 mins
+ break;
- case GPCMD_MODE_SELECT_10:
- cmd->dout_xfer_len = ube16_to_cpu(s->io_buffer + 7);
- CHECK_SAME_VALUE(s->lcyl | (s->hcyl << 8), cmd->dout_xfer_len);
+- case GPCMD_MODE_SELECT_10:
+- cmd->dout_xfer_len = ube16_to_cpu(s->io_buffer + 7);
+- CHECK_SAME_VALUE(s->lcyl | (s->hcyl << 8), cmd->dout_xfer_len);
-
- DEBUG_PRINTF("Mode select 10 %d bytes\n", cmd->dout_xfer_len);
-- {
++ case GPCMD_WRITE_BUFFER:
++ if((s->io_buffer[1] & 7) != 0 && // Combined header and data mode
++ (s->io_buffer[1] & 7) != 2) // Data mode
+ {
- int i;
- DEBUG_PRINTF("0x");
- for(i = 0; i < 12; ++i)
- for(i = 0; i < cmd->dout_xfer_len; ++i)
- DEBUG_PRINTF("%02x ", s->io_buffer[i + 12]);
- DEBUG_PRINTF("\n");
-- }
--
- if (cmd->dout_xfer_len == 0)
- goto simple_cmd;
++ DEBUG_PRINTF("\e[3;31mIllegal write buffer mode %d\e[m\n",
++ s->io_buffer[1] & 7);
++ ide_atapi_pt_set_error(s, SENSE_ILLEGAL_REQUEST,
++ ASC_ILLEGAL_OPCODE, 0x70);
++ return;
+ }
+
+- 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);
+-
+- 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),
- cmd->dout_xfer_len);
-
- if (cmd->dout_xfer_len == 0)
- goto simple_cmd;
+- 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);
+-
+- 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),
- cmd->dout_xfer_len);
-
- if (cmd->dout_xfer_len == 0)
- goto simple_cmd;
+- 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);
+-
+- 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),
- cmd->dout_xfer_len);
-
- if (cmd->dout_xfer_len == 0)
- goto simple_cmd;
+- 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;
+-
+- case GPCMD_FORMAT_UNIT:
+- cmd->dout_xfer_len = 12;
-
- DEBUG_PRINTF("Write (%s) %d bytes\n", atapi_cmd_to_str(command),
- cmd->dout_xfer_len);
- // ide_atapi_pt_wcmd(s);
- // return;
- break;
-+ ide_atapi_pt_wcmd(s);
-+ return;
-
- /*****************/
- /* READ COMMANDS */
- /*****************/
-
- case GPCMD_INQUIRY:
+-
+- /*****************/
+- /* READ COMMANDS */
+- /*****************/
+-
+- case GPCMD_INQUIRY:
- // cmd->din_xferp = (__u64)s->io_buffer;
- cmd->din_xfer_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;
+- cmd->din_xfer_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;
- // ATAPI_PT_SEND_PACKET;
break;
case GPCMD_REQUEST_SENSE:
-@@ -1042,10 +973,6 @@ static void ide_atapi_pt_cmd(IDEState *s)
+@@ -1042,185 +1079,15 @@ static void ide_atapi_pt_cmd(IDEState *s)
int max_size = s->io_buffer[4];
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);
return;
-@@ -1053,57 +980,41 @@ static void ide_atapi_pt_cmd(IDEState *s)
+ }
- case GPCMD_READ_DVD_STRUCTURE:
- cmd->din_xfer_len = ube16_to_cpu(s->io_buffer + 8);
+- case GPCMD_READ_DVD_STRUCTURE:
+- cmd->din_xfer_len = ube16_to_cpu(s->io_buffer + 8);
- // cmd->din_xferp = (__u64)s->io_buffer;
- s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
-+ s->atapi_pt.reply_size_init = 4;
- s->atapi_pt.reply_size_len = 2;
+- s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+- s->atapi_pt.reply_size_len = 2;
- // ATAPI_PT_SEND_PACKET;
- // return;
- break;
-
- case GPCMD_READ_HEADER:
- cmd->din_xfer_len = ube16_to_cpu(s->io_buffer + 7);
+- break;
+-
+- case GPCMD_READ_HEADER:
+- cmd->din_xfer_len = ube16_to_cpu(s->io_buffer + 7);
- // cmd->din_xferp = (__u64)s->io_buffer;
- s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
- s->atapi_pt.reply_size_init = cmd->din_xfer_len;
+- s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+- s->atapi_pt.reply_size_init = cmd->din_xfer_len;
- // ATAPI_PT_SEND_PACKET;
- // return;
- break;
-
- case GPCMD_MECHANISM_STATUS:
- cmd->din_xfer_len = ube16_to_cpu(s->io_buffer + 8);
+- break;
+-
+- case GPCMD_MECHANISM_STATUS:
+- cmd->din_xfer_len = ube16_to_cpu(s->io_buffer + 8);
- // cmd->din_xferp = (__u64)s->io_buffer;
- s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
- s->atapi_pt.reply_size_offset = 6;
+- s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+- s->atapi_pt.reply_size_offset = 6;
- // ATAPI_PT_SEND_PACKET;
- // return;
- break;
-
- case GPCMD_REPORT_KEY:
- cmd->din_xfer_len = ube16_to_cpu(s->io_buffer + 8);
+- break;
+-
+- case GPCMD_REPORT_KEY:
+- cmd->din_xfer_len = ube16_to_cpu(s->io_buffer + 8);
- // cmd->din_xferp = (__u64)s->io_buffer;
- 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.cmd_sent = ide_atapi_pt_standard_reply;
+- s->atapi_pt.reply_size_len = 2;
+- s->atapi_pt.reply_size_init = 2;
- // ATAPI_PT_SEND_PACKET;
- // return;
- break;
-
- case GPCMD_READ_BUFFER_CAPACITY:
- cmd->din_xfer_len = ube16_to_cpu(s->io_buffer + 7);
+- break;
+-
+- case GPCMD_READ_BUFFER_CAPACITY:
+- cmd->din_xfer_len = ube16_to_cpu(s->io_buffer + 7);
- // cmd->din_xferp = (__u64)s->io_buffer;
- 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.cmd_sent = ide_atapi_pt_standard_reply;
+- s->atapi_pt.reply_size_len = 2;
+- s->atapi_pt.reply_size_init = 2;
- // return;
- break;
-
- case GPCMD_GET_PERFORMANCE:
- cmd->din_xfer_len = 8 + 8 * ube16_to_cpu(s->io_buffer + 8);
+- break;
+-
+- case GPCMD_GET_PERFORMANCE:
+- cmd->din_xfer_len = 8 + 8 * ube16_to_cpu(s->io_buffer + 8);
- // cmd->din_xferp = (__u64)s->io_buffer;
- s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
- s->atapi_pt.reply_size_len = 4;
+- s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+- s->atapi_pt.reply_size_len = 4;
- // ATAPI_PT_SEND_PACKET;
- // return;
- break;
-
- case GPCMD_READ_10:
-@@ -1123,17 +1034,12 @@ static void ide_atapi_pt_cmd(IDEState *s)
- default: assert(0);
- }
- cmd->din_xfer_len = nbblocks * blocksize;
+- break;
+-
+- case GPCMD_READ_10:
+- case GPCMD_READ_12:
+- {
+- int blocksize = 0, nbblocks;
+-
+- 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->din_xfer_len = nbblocks * blocksize;
- // cmd->din_xferp = (__u64)s->io_buffer;
- s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
- s->atapi_pt.reply_size_init = cmd->din_xfer_len;
+- s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+- s->atapi_pt.reply_size_init = cmd->din_xfer_len;
- // ATAPI_PT_SEND_PACKET;
- // return;
- break;
- }
-
- case GPCMD_READ_BUFFER:
+- break;
+- }
+-
+- case GPCMD_READ_BUFFER:
- // TODO check this one is correct
- // cmd->din_xferp = (__u64)s->io_buffer;
- cmd->din_xfer_len = ube24_to_cpu(s->io_buffer + 6);
-
- switch (s->io_buffer[1] & 0x7)
-@@ -1157,30 +1063,21 @@ static void ide_atapi_pt_cmd(IDEState *s)
- goto illegal_request;
- }
- s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+- cmd->din_xfer_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->din_xfer_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;
- // ATAPI_PT_SEND_PACKET;
- // return;
- break;
-
- case GPCMD_READ_CDVD_CAPACITY:
- cmd->din_xfer_len = 8;
- CHECK_SAME_VALUE(s->lcyl | (s->hcyl << 8), cmd->din_xfer_len);
+- break;
+-
+- case GPCMD_READ_CDVD_CAPACITY:
+- cmd->din_xfer_len = 8;
+- CHECK_SAME_VALUE(s->lcyl | (s->hcyl << 8), cmd->din_xfer_len);
- // cmd->din_xferp = (__u64)s->io_buffer;
- s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
- s->atapi_pt.reply_size_init = cmd->din_xfer_len;
+- s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+- s->atapi_pt.reply_size_init = cmd->din_xfer_len;
- // ATAPI_PT_SEND_PACKET;
- // return;
- break;
-
- case GPCMD_MODE_SENSE_10:
- cmd->din_xfer_len = ube16_to_cpu(s->io_buffer + 7);
- CHECK_SAME_VALUE(s->lcyl | (s->hcyl << 8), cmd->din_xfer_len);
+- break;
+-
+- case GPCMD_MODE_SENSE_10:
+- cmd->din_xfer_len = ube16_to_cpu(s->io_buffer + 7);
+- CHECK_SAME_VALUE(s->lcyl | (s->hcyl << 8), cmd->din_xfer_len);
- // cmd->din_xferp = (__u64)s->io_buffer;
- 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.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->din_xfer_len;
- // ATAPI_PT_SEND_PACKET;
- // return;
- break;
-
- case GPCMD_GET_EVENT_STATUS_NOTIFICATION:
-@@ -1188,22 +1085,16 @@ static void ide_atapi_pt_cmd(IDEState *s)
- case GPCMD_READ_TOC_PMA_ATIP:
- case GPCMD_READ_TRACK_RZONE_INFO:
- cmd->din_xfer_len = ube16_to_cpu(s->io_buffer + 7);
+- break;
+-
+- case GPCMD_GET_EVENT_STATUS_NOTIFICATION:
+- case GPCMD_READ_DISC_INFO:
+- case GPCMD_READ_TOC_PMA_ATIP:
+- case GPCMD_READ_TRACK_RZONE_INFO:
+- cmd->din_xfer_len = ube16_to_cpu(s->io_buffer + 7);
- // cmd->din_xferp = (__u64)s->io_buffer;
- 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.cmd_sent = ide_atapi_pt_standard_reply;
+- s->atapi_pt.reply_size_len = 2;
+- s->atapi_pt.reply_size_init = 2;
- // ATAPI_PT_SEND_PACKET;
- // return;
- break;
-
- case GPCMD_READ_SUBCHANNEL:
- cmd->din_xfer_len = ube16_to_cpu(s->io_buffer + 7);
+- break;
+-
+- case GPCMD_READ_SUBCHANNEL:
+- cmd->din_xfer_len = ube16_to_cpu(s->io_buffer + 7);
- // cmd->din_xferp = (__u64)s->io_buffer;
- s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
- s->atapi_pt.reply_size_len = 2;
- s->atapi_pt.reply_size_offset = 2;
+- s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+- s->atapi_pt.reply_size_len = 2;
+- s->atapi_pt.reply_size_offset = 2;
- // ATAPI_PT_SEND_PACKET;
- // return;
- break;
-
+- break;
+-
case GPCMD_READ_CD:
-@@ -1214,11 +1105,8 @@ static void ide_atapi_pt_cmd(IDEState *s)
- int block_size = ide_atapi_pt_read_cd_block_size(s->io_buffer);
-
- cmd->din_xfer_len = block_count * block_size;
+- {
+- // 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->din_xfer_len = block_count * block_size;
- // cmd->din_xferp = (__u64)s->io_buffer;
- s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
- s->atapi_pt.reply_size_init = cmd->din_xfer_len;
+- s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+- s->atapi_pt.reply_size_init = cmd->din_xfer_len;
- // ATAPI_PT_SEND_PACKET;
- // return;
++ // We read blocks, not bytes
++ cmd->din_xfer_len *= ide_atapi_pt_read_cd_block_size(s->io_buffer);
break;
- }
+- }
-@@ -1233,11 +1121,8 @@ static void ide_atapi_pt_cmd(IDEState *s)
+ case GPCMD_READ_CD_MSF:
+ {
+@@ -1233,23 +1100,6 @@ static void ide_atapi_pt_cmd(IDEState *s)
int block_size = ide_atapi_pt_read_cd_block_size(s->io_buffer);
cmd->din_xfer_len = block_count * block_size;
- // cmd->din_xferp = (__u64)s->io_buffer;
- s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
- s->atapi_pt.reply_size_init = cmd->din_xfer_len;
+- s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+- s->atapi_pt.reply_size_init = cmd->din_xfer_len;
- // ATAPI_PT_SEND_PACKET;
- // return;
- break;
- }
-
-@@ -1245,11 +1130,8 @@ static void ide_atapi_pt_cmd(IDEState *s)
- {
- int block_count = ube16_to_cpu(s->io_buffer + 7);
- cmd->din_xfer_len = block_count * CD_FRAMESIZE;
+- break;
+- }
+-
+- case GPCMD_PLAY_AUDIO_10:
+- {
+- int block_count = ube16_to_cpu(s->io_buffer + 7);
+- cmd->din_xfer_len = block_count * CD_FRAMESIZE;
- // cmd->din_xferp = (__u64)s->io_buffer;
- s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
- s->atapi_pt.reply_size_init = cmd->din_xfer_len;
+- s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+- s->atapi_pt.reply_size_init = cmd->din_xfer_len;
- // ATAPI_PT_SEND_PACKET;
- // return;
break;
}
-@@ -1261,40 +1143,28 @@ static void ide_atapi_pt_cmd(IDEState *s)
+@@ -1261,167 +1111,53 @@ static void ide_atapi_pt_cmd(IDEState *s)
MSF_TO_FRAMES(s->io_buffer[6], s->io_buffer[7], s->io_buffer[8]);
int block_count = ending_frame - starting_frame;
cmd->din_xfer_len = block_count * CD_FRAMESIZE;
- // cmd->din_xferp = (__u64)s->io_buffer;
- s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
- s->atapi_pt.reply_size_init = cmd->din_xfer_len;
+- s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+- s->atapi_pt.reply_size_init = cmd->din_xfer_len;
- // ATAPI_PT_SEND_PACKET;
- // return;
break;
}
- case GPCMD_READ_FORMAT_CAPACITIES:
- cmd->din_xfer_len = ube16_to_cpu(s->io_buffer + 7);
+- case GPCMD_READ_FORMAT_CAPACITIES:
+- cmd->din_xfer_len = ube16_to_cpu(s->io_buffer + 7);
- // cmd->din_xferp = (__u64)s->io_buffer;
- s->atapi_pt.cmd_sent = ide_atapi_pt_read_format_capacities_sent;
+- s->atapi_pt.cmd_sent = ide_atapi_pt_read_format_capacities_sent;
- // ATAPI_PT_SEND_PACKET;
- // return;
- break;
+- break;
++ case GPCMD_GET_PERFORMANCE:
++ // din_xfer_len is currently the max number of descriptors
++ switch(s->io_buffer[10])
++ {
++ case 0: // performance
++ if((s->io_buffer[1] & 3) == 0) // nominal performance, 16 byte descriptors
++ cmd->din_xfer_len *= 16;
++ else // exceptions, 6 byte descriptors
++ cmd->din_xfer_len *= 6;
- case GPCMD_GET_CONFIGURATION:
- cmd->din_xfer_len = ube16_to_cpu(s->io_buffer + 7);
+- case GPCMD_GET_CONFIGURATION:
+- cmd->din_xfer_len = ube16_to_cpu(s->io_buffer + 7);
- // cmd->din_xferp = (__u64)s->io_buffer;
- s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
- s->atapi_pt.reply_size_init = 4;
- s->atapi_pt.reply_size_len = 4;
+- s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+- s->atapi_pt.reply_size_init = 4;
+- s->atapi_pt.reply_size_len = 4;
- // ATAPI_PT_SEND_PACKET;
- // return;
- break;
+- break;
++ cmd->din_xfer_len += 8; // 8 bytes of header
++ break;
- case GPCMD_SEND_DVD_STRUCTURE:
- cmd->din_xfer_len = ube16_to_cpu(s->io_buffer + 8);
+- case GPCMD_SEND_DVD_STRUCTURE:
+- cmd->din_xfer_len = ube16_to_cpu(s->io_buffer + 8);
- // cmd->din_xferp = (__u64)s->io_buffer;
- s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
- s->atapi_pt.reply_size_init = 2;
- s->atapi_pt.reply_size_len = 2;
+- s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+- s->atapi_pt.reply_size_init = 2;
+- s->atapi_pt.reply_size_len = 2;
- // ATAPI_PT_SEND_PACKET;
- // return;
- break;
+- break;
++ case 1: // unusable area
++ cmd->din_xfer_len *= 8; // 8 byte descriptors
++ cmd->din_xfer_len += 8; // 8 bytes of header
++ break;
- case 0x01: // GPMODE_R_W_ERROR_PAGE ?
-@@ -1318,110 +1188,5 @@ static void ide_atapi_pt_cmd(IDEState *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 ?
+- DEBUG_PRINTF("[\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;
++ case 2: // defect status
++ cmd->din_xfer_len *= 2048; // 2048 byte descriptors
++ cmd->din_xfer_len += 8; // 8 bytes of header
++ break;
+
+- default:
+- DEBUG_PRINTF("[UNHANDLED] 0x%02x\n", s->io_buffer[0]);
+- exit(1);
+- return;
++ default:
++ DEBUG_PRINTF("\e[3;31mReserved get performance type %d\e[m\n",
++ s->io_buffer[10]);
++ ide_atapi_pt_set_error(s, SENSE_ILLEGAL_REQUEST,
++ ASC_ILLEGAL_OPCODE, 0x70);
++ return;
++ }
++ break;
}
-
- r = ioctl(raw_state->fd, 0x2285, cmd);
-
- if(command == GPCMD_GET_EVENT_STATUS_NOTIFICATION)
-- {
++ if(cmd->dout_xfer_len == (__u32)-1)
+ {
- struct stat file_stat;
-
- if(s->io_buffer[2] == 4 && s->io_buffer[4] == 2)
- s->io_buffer[7] = 0;
- }
- }
-- }
--
++ DEBUG_PRINTF("[UNHANDLED SCSI COMMAND] 0x%02x\n", cmd_code);
++ exit(1);
+ }
+
- if(r || cmd->driver_status || cmd->transport_status ||
- cmd->device_status) {
- /*
- s->atapi_pt.sense.asc,
- s->atapi_pt.sense.ascq));
- ide_atapi_pt_error(s);
-- return;
-- }
--
++ if(cmd->dout_xfer_len > 0)
++ {
++ ide_atapi_pt_wcmd(s);
+ return;
+ }
+
- s->atapi_pt.cmd_sent(s);
+ ide_atapi_pt_do_sg_io(s);
}