From 5f71eace010fc799cd0aefbfe2969d3f763ccb7a Mon Sep 17 00:00:00 2001 From: Andrew McNeil Date: Tue, 15 Sep 2009 12:23:24 +0100 Subject: [PATCH] Merge atapi-passthrough and atapi-pt-write --- master/atapi-pass-through | 1046 ++++++++++++++----------------------- master/series | 1 - 2 files changed, 391 insertions(+), 656 deletions(-) diff --git a/master/atapi-pass-through b/master/atapi-pass-through index 1bc525c..4c1889f 100644 --- a/master/atapi-pass-through +++ b/master/atapi-pass-through @@ -105,11 +105,13 @@ index 0000000..f9bdee9 +#endif /* !BLOCK_RAW_POSIX_H */ diff --git a/hw/atapi-pt.c b/hw/atapi-pt.c new file mode 100644 -index 0000000..413cc47 +index 0000000..47ee6af --- /dev/null +++ b/hw/atapi-pt.c -@@ -0,0 +1,1427 @@ +@@ -0,0 +1,1163 @@ ++#include +#include ++#include + +#undef DEBUG_IDE_ATAPI_PT + @@ -591,6 +593,183 @@ index 0000000..413cc47 +} + + ++/* 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; @@ -608,124 +787,173 @@ index 0000000..413cc47 + 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_do_sg_io(IDEState *s) +{ ++ struct sg_io_v4 *cmd = &s->atapi_pt.cmd; + BDRVRawState *raw_state = s->bs->opaque; -+ 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); ++ 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"); ++ 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)); + -+ DEBUG_PRINTF("Postread: 0x"); -+ for(i = 0; i < sizeof(s->atapi_pt.cmd); ++i) -+ DEBUG_PRINTF("%02x", ((unsigned char *)&s->atapi_pt.cmd)[i]); -+ DEBUG_PRINTF("\n"); -+#else -+ DEBUG_PRINTF("Postread: 0x"); -+ for(i = 0; i < sizeof (s->atapi_pt.cmd); ++i) { -+ read(raw_state->fd, &((unsigned char *)&s->atapi_pt.cmd)[i], 1); -+ DEBUG_PRINTF("%02x", ((unsigned char *)&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"); ++ ++ 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(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"); ++ ++ 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"); ++ 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) ++ { ++ /* 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; ++ } ++ 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 (s->atapi_pt.cmd.driver_status || -+ s->atapi_pt.cmd.transport_status || -+ s->atapi_pt.cmd.device_status) -+ { -+ DEBUG_PRINTF("[\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, transport: %d, device: %d\n", ++ if(r || 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, -+ 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_sense_to_str(s->atapi_pt.sense.sense_key, + s->atapi_pt.sense.asc, -+ s->atapi_pt.sense.ascq), -+ errno, -+ strerror(errno) ? : "(null)", -+ s->atapi_pt.cmd.driver_status, -+ s->atapi_pt.cmd.transport_status, -+ s->atapi_pt.cmd.device_status); ++ s->atapi_pt.sense.ascq)); + ide_atapi_pt_error(s); -+ s->atapi_pt.cmd_sent = NULL; + 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'); ++ ++ if(cmd->din_xfer_len == 0) ++ { ++ // Nothing else to do + ide_atapi_cmd_ok(s); -+ s->atapi_pt.cmd_sent = NULL; + return; + } -+ // DEBUG_PRINTF("finish sent\n"); -+ s->atapi_pt.cmd_sent(s); -+ s->atapi_pt.cmd_sent = NULL; -+ DEBUG_PRINTF("**** finished (%p)\n", s); -+} + -+#define ATAPI_PT_SEND_PACKET \ -+ do { \ -+ BDRVRawState *raw_state = s->bs->opaque; \ -+ DEBUG_PRINTF("[ATAPI:%d] sending command: 0x%02x (\e[0;32m%s\e[m)\n", \ -+ raw_state->fd, s->atapi_pt.request[0], \ -+ atapi_cmd_to_str(s->atapi_pt.request[0])); \ -+ memset(&s->atapi_pt.sense, 0, sizeof (s->atapi_pt.sense)); \ -+ int wrote = write(raw_state->fd, &s->atapi_pt.cmd, \ -+ sizeof (s->atapi_pt.cmd)); \ -+ if (wrote != sizeof (s->atapi_pt.cmd)) \ -+ ide_atapi_pt_error(s); \ -+ } while (0) + -+static void ide_atapi_pt_read_finish(IDEState *s) -+{ -+ assert(s->atapi_pt.cmd.dout_xfer_len > 0); -+ s->atapi_pt.cmd.dout_xferp = (__u64)s->io_buffer; -+ s->atapi_pt.cmd_sent = ide_atapi_cmd_ok; -+ ATAPI_PT_SEND_PACKET; ++ 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) ++static void ide_atapi_pt_dout_fetch_pio_done(IDEState *s) +{ + ide_transfer_stop(s); -+ ide_atapi_pt_read_finish(s); ++ ide_atapi_pt_do_sg_io(s); +} + -+static void ide_atapi_pt_read_dma_cb(void *opaque, int ret) ++static void ide_atapi_pt_dout_fetch_dma_done(void *opaque, int ret) +{ + BMDMAState *bm = opaque; + IDEState *s = bm->ide_if; @@ -737,11 +965,9 @@ index 0000000..413cc47 + } + + i = dma_buf_rw(bm, 0); -+ ide_atapi_pt_read_finish(s); ++ ide_atapi_pt_do_sg_io(s); +} -+#endif + -+#if 0 +static void ide_atapi_pt_wcmd(IDEState *s) +{ + if (s->atapi_dma) @@ -749,7 +975,7 @@ index 0000000..413cc47 + /* DMA */ + s->io_buffer_index = 0; + s->io_buffer_size = s->atapi_pt.cmd.dout_xfer_len; -+ ide_dma_start(s, ide_atapi_pt_read_dma_cb); ++ ide_dma_start(s, ide_atapi_pt_dout_fetch_dma_done); + return; + } + @@ -764,44 +990,10 @@ index 0000000..413cc47 + ~ATAPI_INT_REASON_IO & + ~ATAPI_INT_REASON_CD; + ide_transfer_start(s, s->io_buffer, s->atapi_pt.cmd.dout_xfer_len, -+ ide_atapi_pt_read_pio_end); ++ ide_atapi_pt_dout_fetch_pio_done); + ide_set_irq(s); + 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 int ide_atapi_pt_read_cd_block_size(const uint8_t *io_buffer) +{ @@ -924,221 +1116,66 @@ index 0000000..413cc47 + 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)); + memcpy(s->atapi_pt.request, s->io_buffer, ATAPI_PACKET_SIZE); ++ 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); -+ s->atapi_pt.cmd_sent = ide_atapi_cmd_ok; -+ command = s->io_buffer[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); -+ break; -+ -+ /******************/ -+ /* WRITE COMMANDS */ -+ /******************/ ++ cmd->dout_xferp = (__u64)s->io_buffer; + -+ 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("[ATAPI] sending command: 0x%02x (\e[0;32m%s\e[m)\n", ++ cmd_code, atapi_cmd_to_str(cmd_code)); + -+ DEBUG_PRINTF("Write (%s) %d bytes\n", atapi_cmd_to_str(command), -+ cmd->dout_xfer_len); ++ 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); + -+ if (cmd->dout_xfer_len == 0) -+ goto simple_cmd; -+ break; -+ -+ case GPCMD_WRITE_12: -+ cmd->dout_xfer_len = ube32_to_cpu(s->io_buffer + 6); ++ 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); + -+ 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; -+ // ide_atapi_pt_wcmd(s); -+ // return; -+ break; -+ -+ case GPCMD_WRITE_BUFFER: ++ /* A few commands need special attention */ ++ switch(cmd_code) + { -+ 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; ++ 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; -+ // 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); -+ -+ 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) -+ DEBUG_PRINTF("%02x ", s->io_buffer[i]); -+ DEBUG_PRINTF("\n0x"); -+ for(i = 0; i < cmd->dout_xfer_len; ++i) -+ DEBUG_PRINTF("%02x ", s->io_buffer[i + 12]); -+ DEBUG_PRINTF("\n"); ++ 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; -+ -+ 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; -+ // ide_atapi_pt_wcmd(s); -+ // return; -+ break; -+ -+ 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; -+ // ide_atapi_pt_wcmd(s); -+ // return; -+ break; -+ -+ 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; -+ // ide_atapi_pt_wcmd(s); -+ // return; -+ break; -+ -+ 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; -+ -+ /*****************/ -+ /* 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; -+ // ATAPI_PT_SEND_PACKET; + break; + + case GPCMD_REQUEST_SENSE: @@ -1153,185 +1190,15 @@ index 0000000..413cc47 + int max_size = s->io_buffer[4]; + + int size = 8 + s->atapi_pt.sense.add_sense_len; -+ -+ // printf("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->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; -+ // ATAPI_PT_SEND_PACKET; -+ // return; -+ 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; -+ // ATAPI_PT_SEND_PACKET; -+ // return; -+ 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; -+ // ATAPI_PT_SEND_PACKET; -+ // return; -+ 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; -+ // ATAPI_PT_SEND_PACKET; -+ // return; -+ 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; -+ // return; -+ 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; -+ // ATAPI_PT_SEND_PACKET; -+ // return; -+ 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; -+ // ATAPI_PT_SEND_PACKET; -+ // return; -+ 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) -+ { -+ 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); -+ // 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; -+ // 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); -+ // 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.reply_size_init = cmd->din_xfer_len; -+ // ATAPI_PT_SEND_PACKET; -+ // return; -+ 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; -+ // ATAPI_PT_SEND_PACKET; -+ // return; -+ 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; -+ // ATAPI_PT_SEND_PACKET; -+ // return; -+ break; -+ + 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->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; -+ // 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; -+ } + + case GPCMD_READ_CD_MSF: + { @@ -1344,23 +1211,6 @@ index 0000000..413cc47 + 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; -+ // ATAPI_PT_SEND_PACKET; -+ // return; -+ 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; -+ // ATAPI_PT_SEND_PACKET; -+ // return; + break; + } + @@ -1372,169 +1222,55 @@ index 0000000..413cc47 + 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; -+ // ATAPI_PT_SEND_PACKET; -+ // return; + break; + } + -+ 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; -+ // ATAPI_PT_SEND_PACKET; -+ // return; -+ 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); -+ // 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; -+ // ATAPI_PT_SEND_PACKET; -+ // return; -+ 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); -+ // 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; -+ // ATAPI_PT_SEND_PACKET; -+ // return; -+ 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 ? -+ 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; + } + -+ -+ 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; -+ -+ /* Send command and wait for reply, SG_IO ioctl*/ -+ 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) -+ { -+ /* 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) -+ { -+ /* 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; -+ } -+ 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; -+ } -+ } ++ DEBUG_PRINTF("[UNHANDLED SCSI COMMAND] 0x%02x\n", cmd_code); ++ exit(1); + } + -+ 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(command), -+ 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); ++ 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); +} diff --git a/hw/ide.c b/hw/ide.c index e8d676e..6c1d60a 100644 @@ -2125,7 +1861,7 @@ index e8d676e..6c1d60a 100644 s->drive_serial = drive_serial++; strncpy(s->drive_serial_str, drive_get_serial(s->bs), diff --git a/vl.c b/vl.c -index cd354de..b5dfbd5 100644 +index f3b0dae..ae461c8 100644 --- a/vl.c +++ b/vl.c @@ -2192,8 +2192,10 @@ static int bt_parse(const char *opt) diff --git a/master/series b/master/series index 2b162e9..9a55651 100644 --- a/master/series +++ b/master/series @@ -30,4 +30,3 @@ new-input-code atapi-pass-through pv_driver_throttling_disabled move-iso-cdrom -atapi-pt-write -- 2.39.5