@@ -327,7 +327,7 @@ obj-y += e1000.o
obj-y += wdt_ib700.o wdt_i6300esb.o
# Hardware support
-obj-i386-y = ide.o pckbd.o vga.o $(sound-obj-y) dma.o
+obj-i386-y = ide.o atapi-pt.o atapi-data.o pckbd.o vga.o $(sound-obj-y) dma.o
obj-i386-y += fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o
obj-i386-y += cirrus_vga.o apic.o ioapic.o parallel.o acpi.o piix_pci.o
obj-i386-y += usb-uhci.o vmmouse.o vmport.o vmware_vga.o hpet.o
@@ -338,7 +338,8 @@ CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
endif
# shared objects
-obj-ppc-y = ppc.o ide.o vga.o $(sound-obj-y) dma.o openpic.o
+obj-ppc-y = ppc.o ide.o atapi-pt.o atapi-data.o
+obj-ppc-y += vga.o $(sound-obj-y) dma.o openpic.o
# PREP target
obj-ppc-y += pckbd.o serial.o i8259.o i8254.o fdc.o mc146818rtc.o
obj-ppc-y += prep_pci.o ppc_prep.o
@@ -365,7 +366,8 @@ LIBS+= $(FDT_LIBS)
obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
obj-mips-y += mips_timer.o mips_int.o dma.o vga.o serial.o i8254.o i8259.o rc4030.o
obj-mips-y += g364fb.o jazz_led.o dp8393x.o
-obj-mips-y += ide.o gt64xxx.o pckbd.o fdc.o mc146818rtc.o usb-uhci.o acpi.o ds1225y.o
+obj-mips-y += ide.o atapi-pt.o atapi-data.o gt64xxx.o
+obj-mips-y += pckbd.o fdc.o mc146818rtc.o usb-uhci.o acpi.o ds1225y.o
obj-mips-y += piix_pci.o parallel.o cirrus_vga.o pcspk.o $(sound-obj-y)
obj-mips-y += mipsnet.o
obj-mips-y += pflash_cfi01.o
@@ -401,7 +403,7 @@ obj-cris-y += etraxfs_ser.o
obj-cris-y += pflash_cfi02.o
ifeq ($(TARGET_ARCH), sparc64)
-obj-sparc-y = sun4u.o ide.o pckbd.o vga.o apb_pci.o
+obj-sparc-y = sun4u.o ide.o atapi-pt.o atapi-data.o pckbd.o vga.o apb_pci.o
obj-sparc-y += fdc.o mc146818rtc.o serial.o
obj-sparc-y += cirrus_vga.o parallel.o
else
@@ -420,7 +422,7 @@ obj-arm-y += arm-semi.o
obj-arm-y += pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o
obj-arm-y += pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o
obj-arm-y += pflash_cfi01.o gumstix.o
-obj-arm-y += zaurus.o ide.o serial.o spitz.o tosa.o tc6393xb.o
+obj-arm-y += zaurus.o ide.o atapi-pt.o atapi-data.o serial.o spitz.o tosa.o tc6393xb.o
obj-arm-y += omap1.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o
obj-arm-y += omap2.o omap_dss.o soc_dma.o
obj-arm-y += omap_sx1.o palm.o tsc210x.o
@@ -438,7 +440,7 @@ endif
obj-sh4-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o
obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o serial.o
-obj-sh4-y += ide.o
+obj-sh4-y += ide.o atapi-pt.o atapi-data.o
obj-m68k-y = an5206.o mcf5206.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o
obj-m68k-y += m68k-semi.o dummy_m68k.o
new file mode 100644
@@ -0,0 +1,796 @@
+/*
+ * ATAPI pass through implementation
+ *
+ * Copyright (c) 2009 Alexandre Bique
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "block.h"
+#include "atapi-defines.h"
+#include "atapi-pt.h"
+
+int atapi_pt_allow_fw_upgrade = 0;
+
+#define DEBUG_IDE_ATAPI_PT
+
+#ifdef DEBUG_IDE_ATAPI_PT
+# define DPRINTF(Args...) printf(Args)
+# define CHECK_EQUAL(Val1, Val2) \
+ do { \
+ if ((Val1) != (Val2)) \
+ printf("[\e[1;32m!VALUE\e[m] %s:%d, %s=%d %s=%d\n", \
+ __PRETTY_FUNCTION__, __LINE__, #Val1, (Val1), \
+ #Val2, (Val2)); \
+ } while (0)
+#else
+# define DPRINTF(Args...)
+# define CHECK_EQUAL(Val1, Val2)
+#endif /* DEBUG_IDE_ATAPI_PT */
+
+static inline uint32_t msf_to_frames(uint32_t minutes,
+ uint32_t seconds,
+ uint32_t frames)
+{
+ return (minutes * CD_SECS + seconds) * CD_FRAMES + frames;
+}
+
+static void ide_atapi_pt_set_error(IDEState *s, int sense_key, int asc, int error)
+{
+ s->atapi_pt.sense.sense_key = sense_key;
+ s->atapi_pt.sense.asc = asc;
+ s->atapi_pt.sense.error_code = error;
+ s->status = READY_STAT | ERR_STAT;
+ s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
+ ide_set_irq(s);
+}
+
+static void ide_atapi_pt_error(IDEState *s)
+{
+ s->status = READY_STAT | ERR_STAT;
+ s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
+ ide_set_irq(s);
+}
+
+static void ide_atapi_pt_sg_io_finished(void *opaque, int ret)
+{
+ IDEState *s = opaque;
+
+ if (ret) {
+ DPRINTF("IO error\n");
+ ide_atapi_pt_error(s);
+ return;
+ }
+
+ if (s->atapi_pt.cmd.driver_status ||
+ s->atapi_pt.cmd.host_status ||
+ s->atapi_pt.cmd.status)
+ {
+ DPRINTF("[\e[1;31mERROR\e[m]\n"
+ "\tsense_key: 0x%02x (\e[0;35m%s\e[m)\n"
+ "\terror: 0x%02x\n"
+ "\tasc: 0x%02x, 0x%x (\e[0;35m%s\e[m)\n"
+ "\terrno: %d (%s)\n"
+ "\tdriver: %d, host: %d, status: %d\n",
+ s->atapi_pt.sense.sense_key,
+ sense_key_texts[s->atapi_pt.sense.sense_key],
+ s->atapi_pt.sense.error_code,
+ s->atapi_pt.sense.asc,
+ s->atapi_pt.sense.ascq,
+ atapi_ascq_to_str(s->atapi_pt.sense.ascq),
+ errno,
+ strerror(errno) ? : "(null)",
+ s->atapi_pt.cmd.driver_status,
+ s->atapi_pt.cmd.host_status,
+ s->atapi_pt.cmd.status);
+ ide_atapi_pt_error(s);
+ return;
+ }
+ s->atapi_pt.cmd_sent(s);
+}
+
+static void ide_atapi_pt_send_packet(IDEState *s)
+{
+ DPRINTF("[ATAPI-PT] sending command: 0x%02x (\e[0;32m%s\e[m)\n",
+ s->atapi_pt.request[0], atapi_cmd_to_str(s->atapi_pt.request[0]));
+ bdrv_aio_ioctl(s->bs, SG_IO, &s->atapi_pt.cmd,
+ ide_atapi_pt_sg_io_finished, s);
+}
+
+static void ide_atapi_pt_read_finish(IDEState *s)
+{
+ s->atapi_pt.cmd.dxferp = s->io_buffer;
+ s->atapi_pt.cmd_sent = ide_atapi_cmd_ok;
+ ide_atapi_pt_send_packet(s);
+}
+
+static void ide_atapi_pt_read_pio_end(IDEState *s)
+{
+ ide_transfer_stop(s);
+ ide_atapi_pt_read_finish(s);
+}
+
+static void ide_atapi_pt_read_dma_cb(void *opaque, int ret)
+{
+ BMDMAState *bm = opaque;
+ IDEState *s = bm->ide_if;
+ int i = 0;
+
+ if (ret < 0) {
+ ide_atapi_io_error(s, ret);
+ return;
+ }
+
+ i = dma_buf_rw(bm, 0);
+ ide_atapi_pt_read_finish(s);
+}
+
+static void ide_atapi_pt_wcmd(IDEState *s)
+{
+ if (s->atapi_dma)
+ {
+ /* DMA */
+ s->io_buffer_index = 0;
+ s->io_buffer_size = s->atapi_pt.cmd.dxfer_len;
+ ide_dma_start(s, ide_atapi_pt_read_dma_cb);
+ return;
+ }
+
+ /* PIO */
+ s->packet_transfer_size = s->atapi_pt.cmd.dxfer_len;
+ s->io_buffer_size = 0;
+ s->elementary_transfer_size = 0;
+ s->io_buffer_index = 0;
+ s->status |= DRQ_STAT;
+ s->status &= ~BUSY_STAT;
+ s->nsector = (s->nsector & ~7) &
+ ~ATAPI_INT_REASON_IO &
+ ~ATAPI_INT_REASON_CD;
+ ide_transfer_start(s, s->io_buffer, s->atapi_pt.cmd.dxfer_len,
+ ide_atapi_pt_read_pio_end);
+ ide_set_irq(s);
+ return;
+}
+
+static void ide_atapi_pt_read_format_capacities_sent(IDEState *s)
+{
+ int size = (s->io_buffer[3] << 3) + 4;
+ ide_atapi_cmd_reply(s, size, s->atapi_pt.cmd.dxfer_len);
+}
+
+static void ide_atapi_pt_standard_reply(IDEState *s)
+{
+ uint32_t size = s->atapi_pt.reply_size_init;
+
+ switch (s->atapi_pt.reply_size_len)
+ {
+ case 0:
+ break;
+ case 1:
+ size += s->io_buffer[s->atapi_pt.reply_size_offset];
+ break;
+ case 2:
+ size += ube16_to_cpu(s->io_buffer + s->atapi_pt.reply_size_offset);
+ break;
+ case 3:
+ size += ube24_to_cpu(s->io_buffer + s->atapi_pt.reply_size_offset);
+ break;
+ case 4:
+ size += ube32_to_cpu(s->io_buffer + s->atapi_pt.reply_size_offset);
+ break;
+ default:
+ fprintf(stderr,
+ "The imposible has happened!!! We received a reply with a %d "
+ "bytes length field. Please inform "
+ "Alexandre Bique <bique.alexandre@gmail.com>.",
+ s->atapi_pt.reply_size_len);
+ assert(0);
+ break;
+ }
+ DPRINTF("[reply] size: %d, resid: %d, max_in:%d\n",
+ size, s->atapi_pt.cmd.resid, s->atapi_pt.cmd.dxfer_len);
+ ide_atapi_cmd_reply(s, size, s->atapi_pt.cmd.dxfer_len);
+}
+
+/* This data comes from the "Mt. Fuji Commands for
+ * Multimedia Devices SFF8090i v4" page 343. */
+static int ide_atapi_pt_read_cd_block_size(const uint8_t *io_buffer)
+{
+ int sector_type = (io_buffer[2] >> 2) & 7;
+ int error_flags = (io_buffer[9] >> 1) & 3;
+ int flags_bits = io_buffer[9] & ~7;
+ int block_size = 0;
+
+ // expected sector type
+ switch (sector_type)
+ {
+ case 0: // Any type
+ case 1: // CD-DA
+ block_size = (flags_bits) ? 2352 : 0;
+ break;
+
+ case 2: // Mode 1
+ switch (flags_bits)
+ {
+ case 0x0: block_size = 0; break;
+ case 0x10:
+ case 0x50: block_size = 2048; break;
+ case 0x18:
+ case 0x58: block_size = 2336; break;
+ case 0x20:
+ case 0x60: block_size = 4; break;
+ case 0x30:
+ case 0x70:
+ case 0x78: block_size = 2052; break;
+ case 0x38: block_size = 2340; break;
+ case 0x40: block_size = 0; break;
+ case 0xa0: block_size = 16; break;
+ case 0xb0: block_size = 2064; break;
+ case 0xb8: block_size = 2352; break;
+ case 0xe0: block_size = 16; break;
+ case 0xf0: block_size = 2064; break;
+ case 0xf8: block_size = 2352; break;
+
+ default: return 0; // illegal
+ }
+ break;
+
+ case 3: // Mode 2
+ switch (flags_bits)
+ {
+ case 0x0: block_size = 0; break;
+ case 0x10:
+ case 0x50:
+ case 0x18:
+ case 0x58: block_size = 2336; break;
+ case 0x20:
+ case 0x60: block_size = 4; break;
+ case 0x30:
+ case 0x70:
+ case 0x78:
+ case 0x38: block_size = 2340; break;
+ case 0x40: block_size = 0; break;
+ case 0xa0: block_size = 16; break;
+ case 0xb0:
+ case 0xb8: block_size = 2352; break;
+ case 0xe0: block_size = 16; break;
+ case 0xf0:
+ case 0xf8: block_size = 2352; break;
+ default: return 0; // illegal
+ }
+ break;
+
+ case 4: // Mode 2 Form 1
+ switch (flags_bits)
+ {
+ case 0x0: block_size = 0; break;
+ case 0x10: block_size = 2048; break;
+ case 0x18: block_size = 2328; break;
+ case 0x20: block_size = 4; break;
+ case 0x40: block_size = 8; break;
+ case 0x50: block_size = 2056; break;
+ case 0x58: block_size = 2336; break;
+ case 0x60: block_size = 12; break;
+ case 0x70: block_size = 2060; break;
+ case 0x78: block_size = 2340; break;
+ case 0xa0: block_size = 16; break;
+ case 0xe0: block_size = 24; break;
+ case 0xf0: block_size = 2072; break;
+ case 0xf8: block_size = 2352; break;
+ default: return 0; // illegal
+ }
+ break;
+
+ case 5: // Mode 2 Form 2
+ switch (flags_bits)
+ {
+ case 0x0: block_size = 0; break;
+ case 0x10:
+ case 0x18: block_size = 2328; break;
+ case 0x20: block_size = 4; break;
+ case 0x40: block_size = 8; break;
+ case 0x50:
+ case 0x58: block_size = 2336; break;
+ case 0x60: block_size = 12; break;
+ case 0x70:
+ case 0x78: block_size = 2340; break;
+ case 0xa0: block_size = 16; break;
+ case 0xe0: block_size = 24; break;
+ case 0xf0:
+ case 0xf8: block_size = 2352; break;
+ default: return 0; // illegal
+ }
+ break;
+
+ default:
+ return 0; // illegal
+ }
+
+ switch (error_flags)
+ {
+ case 1: block_size += 294; break;
+ case 2: block_size += 296; break;
+ }
+
+ return block_size;
+}
+
+void ide_atapi_pt_cmd(IDEState *s)
+{
+ struct sg_io_hdr *cmd = &s->atapi_pt.cmd;
+
+ memcpy(s->atapi_pt.request, s->io_buffer, ATAPI_PACKET_SIZE);
+ cmd->interface_id = 'S';
+ cmd->dxfer_direction = SG_DXFER_NONE;
+ cmd->cmd_len = ATAPI_PACKET_SIZE;
+ cmd->mx_sb_len = sizeof (s->atapi_pt.sense);
+ cmd->dxfer_len = 0;
+ cmd->iovec_count = 0;
+ cmd->dxferp = s->io_buffer;
+ cmd->cmdp = s->atapi_pt.request;
+ cmd->sbp = (unsigned char *)&s->atapi_pt.sense;
+ cmd->timeout = 0xffffff; // 15 seconds
+
+ s->status |= BUSY_STAT;
+ s->atapi_pt.reply_size_init = 0;
+ s->atapi_pt.reply_size_offset = 0;
+ s->atapi_pt.reply_size_len = 0;
+
+ switch (s->io_buffer[0])
+ {
+ /*******************/
+ /* SIMPLE COMMANDS */
+ /*******************/
+
+ case GPCMD_BLANK: // bigger timeout while blanking
+ cmd->timeout = 1000 * 60 * 80; // 80 mins
+ goto simple_cmd;
+ case GPCMD_CLOSE_TRACK:
+ cmd->timeout = 1000 * 60 * 5; // 5 mins
+ goto simple_cmd;
+ case GPCMD_FLUSH_CACHE: // also called SYNCHRONIZE_CACHE
+ case GPCMD_LOAD_UNLOAD:
+ case GPCMD_PAUSE_RESUME:
+ case GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
+ case GPCMD_REPAIR_RZONE_TRACK:
+ case GPCMD_RESERVE_RZONE_TRACK:
+ case GPCMD_SCAN:
+ case GPCMD_SEEK:
+ case GPCMD_SET_READ_AHEAD:
+ case GPCMD_START_STOP_UNIT:
+ case GPCMD_STOP_PLAY_SCAN:
+ case GPCMD_TEST_UNIT_READY:
+ case GPCMD_VERIFY_10:
+ case GPCMD_SET_SPEED: /* FIXME: find the documentation */
+ simple_cmd:
+ CHECK_EQUAL(s->lcyl, 0);
+ CHECK_EQUAL(s->hcyl, 0);
+ cmd->dxfer_direction = SG_DXFER_NONE;
+ s->atapi_pt.cmd_sent = ide_atapi_cmd_ok;
+ ide_atapi_pt_send_packet(s);
+ return;
+
+ /******************/
+ /* WRITE COMMANDS */
+ /******************/
+
+ case GPCMD_WRITE_10:
+ case GPCMD_WRITE_AND_VERIFY_10:
+ cmd->dxfer_direction = SG_DXFER_TO_DEV;
+ cmd->dxfer_len = ube16_to_cpu(s->io_buffer + 7) * CD_FRAMESIZE;
+ if (cmd->dxfer_len == 0)
+ goto simple_cmd;
+ ide_atapi_pt_wcmd(s);
+ return;
+
+ case GPCMD_WRITE_12:
+ cmd->dxfer_direction = SG_DXFER_TO_DEV;
+ cmd->dxfer_len = ube32_to_cpu(s->io_buffer + 6);
+ if (cmd->dxfer_len == 0)
+ goto simple_cmd;
+ ide_atapi_pt_wcmd(s);
+ return;
+
+ case GPCMD_WRITE_BUFFER:
+ {
+ int32_t parameter_list_length = ube24_to_cpu(s->io_buffer + 3);
+ int8_t mode = s->io_buffer[1] & 0x03;
+
+ cmd->dxfer_direction = SG_DXFER_TO_DEV;
+ switch (mode)
+ {
+ case 0x0: // Combined header and data mode
+ // The documentation is confusing because it says that parameter
+ // list length contains all the data, but the buffer should be
+ // greater than parameter list length + 4...
+ cmd->dxfer_len = parameter_list_length + 4;
+ break;
+ case 0x2: // Data mode
+ cmd->dxfer_len = parameter_list_length;
+ break;
+ case 0x1: // Vendor specific
+ case 0x4: // Download microcode
+ case 0x5: // Download microcode and save mode
+ case 0x6: // Download microcode with offsets
+ case 0x7: // Download microcode with offsets and save mode
+ default:
+ if (!atapi_pt_allow_fw_upgrade)
+ goto illegal_request;
+ cmd->dxfer_len = parameter_list_length;
+ break;
+ }
+
+ ide_atapi_pt_wcmd(s);
+ return;
+ }
+
+ case GPCMD_SEND_CUE_SHEET:
+ cmd->dxfer_direction = SG_DXFER_TO_DEV;
+ cmd->dxfer_len = ube24_to_cpu(s->io_buffer + 6);
+ if (cmd->dxfer_len == 0)
+ goto simple_cmd;
+ ide_atapi_pt_wcmd(s);
+ return;
+
+ case GPCMD_MODE_SELECT_10:
+ cmd->dxfer_direction = SG_DXFER_TO_DEV;
+ cmd->dxfer_len = ube16_to_cpu(s->io_buffer + 7);
+ CHECK_EQUAL(s->lcyl | (s->hcyl << 8), cmd->dxfer_len);
+ if (cmd->dxfer_len == 0)
+ goto simple_cmd;
+ ide_atapi_pt_wcmd(s);
+ return;
+
+ case GPCMD_SEND_KEY:
+ case GPCMD_SEND_EVENT:
+ cmd->dxfer_direction = SG_DXFER_TO_DEV;
+ cmd->dxfer_len = ube16_to_cpu(s->io_buffer + 8);
+ if (cmd->dxfer_len == 0)
+ goto simple_cmd;
+ CHECK_EQUAL(s->lcyl | (s->hcyl << 8), cmd->dxfer_len);
+ ide_atapi_pt_wcmd(s);
+ return;
+
+ case GPCMD_SEND_OPC:
+ cmd->dxfer_direction = SG_DXFER_TO_DEV;
+ cmd->dxfer_len = ube16_to_cpu(s->io_buffer + 7) << 3;
+ CHECK_EQUAL(s->lcyl | (s->hcyl << 8), cmd->dxfer_len);
+ if (cmd->dxfer_len == 0)
+ goto simple_cmd;
+ ide_atapi_pt_wcmd(s);
+ return;
+
+ case GPCMD_SET_STREAMING:
+ cmd->dxfer_direction = SG_DXFER_TO_DEV;
+ cmd->dxfer_len = ube16_to_cpu(s->io_buffer + 9);
+ if (cmd->dxfer_len == 0)
+ goto simple_cmd;
+ ide_atapi_pt_wcmd(s);
+ return;
+
+ case GPCMD_FORMAT_UNIT:
+ cmd->dxfer_direction = SG_DXFER_TO_DEV;
+ cmd->dxfer_len = 12;
+ ide_atapi_pt_wcmd(s);
+ return;
+
+ /*****************/
+ /* READ COMMANDS */
+ /*****************/
+
+ case GPCMD_INQUIRY:
+ cmd->dxfer_direction = SG_DXFER_FROM_DEV;
+ cmd->dxfer_len = s->io_buffer[4];
+ s->atapi_pt.reply_size_init = 5;
+ s->atapi_pt.reply_size_offset = 4;
+ s->atapi_pt.reply_size_len = 1;
+ s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+ ide_atapi_pt_send_packet(s);
+ return;
+
+ case GPCMD_REQUEST_SENSE:
+ {
+ // send the previous sense command
+ DPRINTF("=== REQUEST SENSE ===\n"
+ "atapi_cmd_error: sense=0x%x asc=0x%x error=0x%x\n",
+ s->atapi_pt.sense.sense_key,
+ s->atapi_pt.sense.asc,
+ s->atapi_pt.sense.error_code);
+
+ int max_size = s->io_buffer[4];
+
+ int size = 8 + s->atapi_pt.sense.add_sense_len;
+
+ DPRINTF("max_size: %d, add_sense_len: %d, sizeof: %lu\n",
+ max_size, s->atapi_pt.sense.add_sense_len,
+ sizeof (s->atapi_pt.sense));
+ memcpy(s->io_buffer, &s->atapi_pt.sense, sizeof (s->atapi_pt.sense));
+ ide_atapi_cmd_reply(s, size, max_size);
+ return;
+ }
+
+ case GPCMD_READ_DVD_STRUCTURE:
+ cmd->dxfer_direction = SG_DXFER_FROM_DEV;
+ cmd->dxfer_len = ube16_to_cpu(s->io_buffer + 8);
+ s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+ s->atapi_pt.reply_size_len = 4;
+ ide_atapi_pt_send_packet(s);
+ return;
+
+ case GPCMD_READ_HEADER:
+ cmd->dxfer_direction = SG_DXFER_FROM_DEV;
+ cmd->dxfer_len = ube16_to_cpu(s->io_buffer + 7);
+ s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+ s->atapi_pt.reply_size_init = cmd->dxfer_len;
+ ide_atapi_pt_send_packet(s);
+ return;
+
+ case GPCMD_MECHANISM_STATUS:
+ cmd->dxfer_len = ube16_to_cpu(s->io_buffer + 8);
+ s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+ s->atapi_pt.reply_size_offset = 6;
+ ide_atapi_pt_send_packet(s);
+ return;
+
+ case GPCMD_REPORT_KEY:
+ cmd->dxfer_direction = SG_DXFER_FROM_DEV;
+ cmd->dxfer_len = ube16_to_cpu(s->io_buffer + 8);
+ s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+ s->atapi_pt.reply_size_len = 2;
+ s->atapi_pt.reply_size_init = 2;
+ ide_atapi_pt_send_packet(s);
+ return;
+
+ case GPCMD_READ_BUFFER_CAPACITY:
+ cmd->dxfer_direction = SG_DXFER_FROM_DEV;
+ cmd->dxfer_len = ube16_to_cpu(s->io_buffer + 7);
+ s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+ s->atapi_pt.reply_size_len = 2;
+ s->atapi_pt.reply_size_init = 2;
+ return;
+
+ case GPCMD_GET_PERFORMANCE:
+ cmd->dxfer_direction = SG_DXFER_FROM_DEV;
+ cmd->dxfer_len = 8 + 8 * ube16_to_cpu(s->io_buffer + 8);
+ s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+ s->atapi_pt.reply_size_len = 4;
+ ide_atapi_pt_send_packet(s);
+ return;
+
+ case GPCMD_READ_10:
+ case GPCMD_READ_12:
+ {
+ int blocksize = 0, nbblocks;
+
+ cmd->dxfer_direction = SG_DXFER_FROM_DEV;
+ switch (s->io_buffer[0]) {
+ case GPCMD_READ_10:
+ blocksize = CD_FRAMESIZE;
+ nbblocks = ube16_to_cpu(s->io_buffer + 7);
+ break;
+ case GPCMD_READ_12:
+ blocksize = CD_FRAMESIZE_RAW0;
+ nbblocks = ube32_to_cpu(s->io_buffer + 6);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ cmd->dxfer_len = nbblocks * blocksize;
+ CHECK_EQUAL(cmd->dxfer_len, (s->hcyl << 8) | s->lcyl);
+ s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+ s->atapi_pt.reply_size_init = cmd->dxfer_len;
+ ide_atapi_pt_send_packet(s);
+ return;
+ }
+
+ case GPCMD_READ_BUFFER:
+ // TODO check this one is correct
+ cmd->dxfer_direction = SG_DXFER_FROM_DEV;
+ cmd->dxfer_len = ube24_to_cpu(s->io_buffer + 6);
+
+ switch (s->io_buffer[1] & 0x7)
+ {
+ case 0: // data with header
+ s->atapi_pt.reply_size_init = 4;
+ s->atapi_pt.reply_size_len = 3;
+ s->atapi_pt.reply_size_offset = 1;
+ break;
+
+ case 2: // data only
+ s->atapi_pt.reply_size_init = cmd->dxfer_len;
+ break;
+
+ case 3: // header only
+ s->atapi_pt.reply_size_init = 4;
+ break;
+
+ case 1: // vendor specific
+ default:
+ goto illegal_request;
+ }
+ s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+ ide_atapi_pt_send_packet(s);
+ return;
+
+ case GPCMD_READ_CDVD_CAPACITY:
+ cmd->dxfer_direction = SG_DXFER_FROM_DEV;
+ cmd->dxfer_len = 8;
+ CHECK_EQUAL(s->lcyl | (s->hcyl << 8), cmd->dxfer_len);
+ s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+ s->atapi_pt.reply_size_init = cmd->dxfer_len;
+ ide_atapi_pt_send_packet(s);
+ return;
+
+ case GPCMD_MODE_SENSE_10:
+ cmd->dxfer_direction = SG_DXFER_FROM_DEV;
+ cmd->dxfer_len = ube16_to_cpu(s->io_buffer + 7);
+ CHECK_EQUAL(s->lcyl | (s->hcyl << 8), cmd->dxfer_len);
+ s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+ s->atapi_pt.reply_size_len = 2;
+ s->atapi_pt.reply_size_init = 2;
+ //s->atapi_pt.reply_size_init = cmd->dxfer_len;
+ ide_atapi_pt_send_packet(s);
+ return;
+
+ case GPCMD_GET_EVENT_STATUS_NOTIFICATION:
+ case GPCMD_READ_DISC_INFO:
+ case GPCMD_READ_TOC_PMA_ATIP:
+ case GPCMD_READ_TRACK_RZONE_INFO:
+ cmd->dxfer_direction = SG_DXFER_FROM_DEV;
+ cmd->dxfer_len = ube16_to_cpu(s->io_buffer + 7);
+ s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+ s->atapi_pt.reply_size_len = 2;
+ s->atapi_pt.reply_size_init = 2;
+ ide_atapi_pt_send_packet(s);
+ return;
+
+ case GPCMD_READ_SUBCHANNEL:
+ cmd->dxfer_direction = SG_DXFER_FROM_DEV;
+ cmd->dxfer_len = ube16_to_cpu(s->io_buffer + 7);
+ s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+ s->atapi_pt.reply_size_len = 2;
+ s->atapi_pt.reply_size_offset = 2;
+ ide_atapi_pt_send_packet(s);
+ return;
+
+ case GPCMD_READ_CD:
+ {
+ // command fields
+ int block_count = ((s->io_buffer[6] << 16) |
+ ube16_to_cpu(s->io_buffer + 7));
+ int block_size = ide_atapi_pt_read_cd_block_size(s->io_buffer);
+
+ cmd->dxfer_direction = SG_DXFER_FROM_DEV;
+ cmd->dxfer_len = block_count * block_size;
+ s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+ s->atapi_pt.reply_size_init = cmd->dxfer_len;
+ ide_atapi_pt_send_packet(s);
+ return;
+ }
+
+ case GPCMD_READ_CD_MSF:
+ {
+ // command fields
+ int starting_frame =
+ msf_to_frames(s->io_buffer[3], s->io_buffer[4], s->io_buffer[5]);
+ int ending_frame =
+ msf_to_frames(s->io_buffer[6], s->io_buffer[7], s->io_buffer[8]);
+ int block_count = ending_frame - starting_frame;
+ int block_size = ide_atapi_pt_read_cd_block_size(s->io_buffer);
+
+ cmd->dxfer_direction = SG_DXFER_FROM_DEV;
+ cmd->dxfer_len = block_count * block_size;
+ s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+ s->atapi_pt.reply_size_init = cmd->dxfer_len;
+ ide_atapi_pt_send_packet(s);
+ return;
+ }
+
+ case GPCMD_PLAY_AUDIO_10:
+ {
+ int block_count = ube16_to_cpu(s->io_buffer + 7);
+ cmd->dxfer_direction = SG_DXFER_FROM_DEV;
+ cmd->dxfer_len = block_count * CD_FRAMESIZE;
+ s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+ s->atapi_pt.reply_size_init = cmd->dxfer_len;
+ ide_atapi_pt_send_packet(s);
+ return;
+ }
+
+ case GPCMD_PLAY_AUDIO_MSF:
+ {
+ int starting_frame =
+ msf_to_frames(s->io_buffer[3], s->io_buffer[4], s->io_buffer[5]);
+ int ending_frame =
+ msf_to_frames(s->io_buffer[6], s->io_buffer[7], s->io_buffer[8]);
+ int block_count = ending_frame - starting_frame;
+ cmd->dxfer_direction = SG_DXFER_FROM_DEV;
+ cmd->dxfer_len = block_count * CD_FRAMESIZE;
+ s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+ s->atapi_pt.reply_size_init = cmd->dxfer_len;
+ ide_atapi_pt_send_packet(s);
+ return;
+ }
+
+ case GPCMD_READ_FORMAT_CAPACITIES:
+ cmd->dxfer_direction = SG_DXFER_FROM_DEV;
+ cmd->dxfer_len = ube16_to_cpu(s->io_buffer + 7);
+ s->atapi_pt.cmd_sent = ide_atapi_pt_read_format_capacities_sent;
+ ide_atapi_pt_send_packet(s);
+ return;
+
+ case GPCMD_GET_CONFIGURATION:
+ cmd->dxfer_direction = SG_DXFER_FROM_DEV;
+ cmd->dxfer_len = ube16_to_cpu(s->io_buffer + 7);
+ s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+ s->atapi_pt.reply_size_init = 4;
+ s->atapi_pt.reply_size_len = 4;
+ ide_atapi_pt_send_packet(s);
+ return;
+
+ case GPCMD_SEND_DVD_STRUCTURE:
+ cmd->dxfer_direction = SG_DXFER_FROM_DEV;
+ cmd->dxfer_len = ube16_to_cpu(s->io_buffer + 8);
+ s->atapi_pt.cmd_sent = ide_atapi_pt_standard_reply;
+ s->atapi_pt.reply_size_init = 2;
+ s->atapi_pt.reply_size_len = 2;
+ ide_atapi_pt_send_packet(s);
+ return;
+
+ case 0x01: // GPMODE_R_W_ERROR_PAGE ?
+ case 0x1a: // GPMODE_POWER_PAGE ?
+ case 0xfa:
+ case 0xfd:
+ case 0xf2:
+ case 0xf3: // WIN_SECURITY_ERASE_PREPARE ?
+ case 0xee: // WIN_IDENTIFY_DMA ?
+ case 0xdf: // WIN_DOORUNLOCK ?
+ DPRINTF("[\e[3;31mILLEGAL?\e[m] 0x%02x, size: %d\n",
+ s->io_buffer[0], s->lcyl | (s->hcyl << 8));
+ illegal_request:
+ ide_atapi_pt_set_error(s, SENSE_ILLEGAL_REQUEST,
+ ASC_ILLEGAL_OPCODE, 0x70);
+ return;
+
+ default:
+ fprintf(stderr, "[ATAPI-PT] We got an unhandled command: 0x%02x. "
+ "Please report.\n", s->io_buffer[0]);
+ exit(1);
+ return;
+ }
+}
+
+void ide_atapi_pt_identify(IDEState *s)
+{
+ if (s->identify_set) {
+ memcpy(s->io_buffer, s->identify_data, sizeof(s->identify_data));
+ return;
+ }
+
+ if (bdrv_ioctl(s->bs, HDIO_GET_IDENTITY, s->io_buffer)) {
+ ide_atapi_identify(s);
+ perror("atapi");
+ exit(1);
+ return;
+ }
+
+ memcpy(s->identify_data, s->io_buffer, sizeof(s->identify_data));
+ s->identify_set = 1;
+}
new file mode 100644
@@ -0,0 +1,35 @@
+/*
+ * ATAPI pass through declarations
+ *
+ * Copyright (c) 2009 Alexandre Bique
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef ATAPI_PT_H
+# define ATAPI_PT_H
+
+# include "ide.h"
+
+extern int atapi_pt_allow_fw_upgrade;
+
+void ide_atapi_pt_cmd(IDEState * s);
+void ide_atapi_pt_identify(IDEState * s);
+
+#endif /* !ATAPI_PT_H */
@@ -22,21 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#include "hw.h"
-#include "pc.h"
-#include "pci.h"
-#include "scsi-disk.h"
-#include "pcmcia.h"
-#include "block.h"
-#include "block_int.h"
-#include "qemu-timer.h"
-#include "sysemu.h"
-#include "ppc_mac.h"
-#include "mac_dbdma.h"
-#include "sh.h"
-#include "dma.h"
#include "ide.h"
-#include "atapi-defines.h"
+#include "atapi-pt.h"
/* debug IDE devices */
//#define DEBUG_IDE
@@ -44,6 +31,7 @@
//#define DEBUG_AIO
#define USE_DMA_CDROM
+
/* XXX: DVDs that could fit on a CD will be reported as a CD */
static inline int media_present(IDEState *s)
{
@@ -62,7 +50,6 @@ static inline int media_is_cd(IDEState *s)
static void ide_dma_restart(IDEState *s);
static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret);
-static void ide_atapi_cmd_error(IDEState *s, int sense_key, int asc);
static void padstr(char *str, const char *src, int len)
{
@@ -1977,7 +1964,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
/* ATAPI commands */
case WIN_PIDENTIFY:
if (s->is_cdrom) {
- ide_atapi_identify(s);
+ s->atapi_identify(s);
s->status = READY_STAT | SEEK_STAT;
ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop);
} else {
@@ -2015,7 +2002,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
s->atapi_dma = s->feature & 1;
s->nsector = 1;
ide_transfer_start(s, s->io_buffer, ATAPI_PACKET_SIZE,
- ide_atapi_cmd);
+ s->atapi_cmd);
break;
/* CF-ATA commands */
case CFA_REQ_EXT_ERROR_CODE:
@@ -2354,6 +2341,16 @@ static void ide_init2(IDEState *ide_state,
if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) {
s->is_cdrom = 1;
+ if (!bdrv_is_sg(s->bs)) {
+ s->atapi_cmd = ide_atapi_cmd;
+ s->atapi_identify = ide_atapi_identify;
+ }
+#if CONFIG_ATAPI_PT
+ else {
+ s->atapi_cmd = ide_atapi_pt_cmd;
+ s->atapi_identify = ide_atapi_pt_identify;
+ }
+#endif /* CONFIG_ATAPI_PT */
bdrv_set_change_cb(s->bs, cdrom_change_cb, s);
}
}
@@ -40,7 +40,20 @@
#include "dma.h"
#include "atapi-defines.h"
+
#include <stdint.h>
+#include <limits.h>
+#include <asm/byteorder.h>
+#include <assert.h>
+
+#ifdef __linux__
+# include <linux/hdreg.h>
+# define CONFIG_ATAPI_PT 1
+#else
+# define CONFIG_ATAPI_PT 0
+#endif /* __linux__ */
+
+#include <scsi/sg.h>
/* Bits of HD_STATUS */
#define ERR_STAT 0x01
@@ -218,6 +231,50 @@ struct IDEState;
typedef void EndTransferFunc(struct IDEState *);
+typedef struct request_sense {
+#if defined(__BIG_ENDIAN_BITFIELD)
+ uint8_t valid : 1;
+ uint8_t error_code : 7;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ uint8_t error_code : 7;
+ uint8_t valid : 1;
+#endif
+ uint8_t segment_number;
+#if defined(__BIG_ENDIAN_BITFIELD)
+ uint8_t reserved1 : 2;
+ uint8_t ili : 1;
+ uint8_t reserved2 : 1;
+ uint8_t sense_key : 4;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ uint8_t sense_key : 4;
+ uint8_t reserved2 : 1;
+ uint8_t ili : 1;
+ uint8_t reserved1 : 2;
+#endif
+ uint8_t information[4];
+ uint8_t add_sense_len;
+ uint8_t command_info[4];
+ uint8_t asc;
+ uint8_t ascq;
+ uint8_t fruc;
+ uint8_t sks[3];
+ uint8_t asb[46];
+} request_sense;
+
+#if CONFIG_ATAPI_PT
+typedef struct ATAPIPassThroughState
+{
+ uint8_t request[ATAPI_PACKET_SIZE];
+ struct sg_io_hdr cmd;
+ struct request_sense sense;
+ void (*cmd_sent)(struct IDEState *);
+
+ uint32_t reply_size_init; // initial value
+ uint32_t reply_size_offset; // offset in s->io_buffer
+ uint32_t reply_size_len; // length in byte (0, 1, 2, 3 or 4)
+} ATAPIPassThroughState;
+#endif /* CONFIG_ATAPI_PT */
+
/* NOTE: IDEState represents in fact one drive */
typedef struct IDEState {
/* ide config */
@@ -266,6 +323,11 @@ typedef struct IDEState {
int lba;
int cd_sector_size;
int atapi_dma; /* true if dma is requested for the packet cmd */
+#if CONFIG_ATAPI_PT
+ ATAPIPassThroughState atapi_pt;
+#endif /* CONFIG_ATAPI_PT */
+ void (*atapi_identify)(struct IDEState *); // the ATAPI identify
+ void (*atapi_cmd)(struct IDEState *); // the ATAPI cmd handler
/* ATA DMA state */
int io_buffer_size;
QEMUSGList sg;
@@ -287,27 +349,27 @@ typedef struct IDEState {
int is_read;
} IDEState;
-#define BM_STATUS_DMAING 0x01
-#define BM_STATUS_ERROR 0x02
-#define BM_STATUS_INT 0x04
-#define BM_STATUS_DMA_RETRY 0x08
-#define BM_STATUS_PIO_RETRY 0x10
+#define BM_STATUS_DMAING 0x01
+#define BM_STATUS_ERROR 0x02
+#define BM_STATUS_INT 0x04
+#define BM_STATUS_DMA_RETRY 0x08
+#define BM_STATUS_PIO_RETRY 0x10
-#define BM_CMD_START 0x01
-#define BM_CMD_READ 0x08
+#define BM_CMD_START 0x01
+#define BM_CMD_READ 0x08
-#define IDE_TYPE_PIIX3 0
-#define IDE_TYPE_CMD646 1
-#define IDE_TYPE_PIIX4 2
+#define IDE_TYPE_PIIX3 0
+#define IDE_TYPE_CMD646 1
+#define IDE_TYPE_PIIX4 2
/* CMD646 specific */
-#define MRDMODE 0x71
-#define MRDMODE_INTR_CH0 0x04
-#define MRDMODE_INTR_CH1 0x08
-#define MRDMODE_BLK_CH0 0x10
-#define MRDMODE_BLK_CH1 0x20
-#define UDIDETCR0 0x73
-#define UDIDETCR1 0x7B
+#define MRDMODE 0x71
+#define MRDMODE_INTR_CH0 0x04
+#define MRDMODE_INTR_CH1 0x08
+#define MRDMODE_BLK_CH0 0x10
+#define MRDMODE_BLK_CH1 0x20
+#define UDIDETCR0 0x73
+#define UDIDETCR1 0x7B
typedef struct BMDMAState {
uint8_t cmd;
@@ -367,6 +429,14 @@ static inline int ube16_to_cpu(const uint8_t *buf)
return (buf[0] << 8) | buf[1];
}
+#if CONFIG_ATAPI_PT /* only atapi-pt uses it so let's avoid unused
+ * warning */
+static inline int ube24_to_cpu(const uint8_t *buf)
+{
+ return (buf[0] << 16) | (buf[1] << 8) | buf[2];
+}
+#endif /* CONFIG_ATAPI_PT */
+
static inline int ube32_to_cpu(const uint8_t *buf)
{
return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
@@ -91,6 +91,13 @@ Use @var{file} as CD-ROM image (you cannot use @option{-hdc} and
using @file{/dev/cdrom} as filename (@pxref{host_drives}).
ETEXI
+DEF("cdrom-allow-fw-upgrade", 0, QEMU_OPTION_cdrom_allow_fw_upgrade,
+ "-cdrom-allow-fw-upgrade allow the guest to process cdrom firmware upgrade.\n")
+STEXI
+@item -cdrom-allow-fw-upgrade
+Allow Qemu to pass through ATAPI firmware upgrade command.
+ETEXI
+
DEF("drive", HAS_ARG, QEMU_OPTION_drive,
"-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][,index=i]\n"
" [,cyls=c,heads=h,secs=s[,trans=t]][,snapshot=on|off]\n"
@@ -142,6 +142,7 @@ int main(int argc, char **argv)
#include "hw/smbios.h"
#include "hw/xen.h"
#include "hw/qdev.h"
+#include "hw/atapi-pt.h"
#include "bt-host.h"
#include "net.h"
#include "monitor.h"
@@ -1792,6 +1793,7 @@ static int bt_parse(const char *opt)
#define HD_ALIAS "index=%d,media=disk"
#define CDROM_ALIAS "index=2,media=cdrom"
+#define CDROM_PT_ALIAS "index=2,media=cdrompt"
#define FD_ALIAS "index=%d,if=floppy"
#define PFLASH_ALIAS "if=pflash"
#define MTD_ALIAS "if=mtd"
@@ -5119,6 +5121,9 @@ int main(int argc, char **argv, char **envp)
case QEMU_OPTION_cdrom:
drive_add(optarg, CDROM_ALIAS);
break;
+ case QEMU_OPTION_cdrom_allow_fw_upgrade:
+ atapi_pt_allow_fw_upgrade = 1;
+ break;
case QEMU_OPTION_boot:
{
static const char * const params[] = {
This patch introduce atapi pass through. The pass through code is used by default when the underlying block is a scsi device. This brings 1 new option to the command line interface: -cdrom-allow-fw-upgrade which allow to pass through the firmware upgrade which is blocked by default. See the WRITE_BUFFER command for more details. Signed-off-by: Alexandre Bique <alexandre.bique@citrix.com> --- Makefile.target | 14 +- hw/atapi-pt.c | 796 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/atapi-pt.h | 35 +++ hw/ide.c | 31 +-- hw/ide.h | 104 ++++++-- qemu-options.hx | 7 + vl.c | 5 + 7 files changed, 952 insertions(+), 40 deletions(-) create mode 100644 hw/atapi-pt.c create mode 100644 hw/atapi-pt.h