From patchwork Fri Aug 7 17:33:12 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bique Alexandre X-Patchwork-Id: 30954 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by bilbo.ozlabs.org (Postfix) with ESMTPS id 2901CB70CF for ; Sat, 8 Aug 2009 03:48:47 +1000 (EST) Received: from localhost ([127.0.0.1]:58715 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1MZTYJ-0007lo-Uw for incoming@patchwork.ozlabs.org; Fri, 07 Aug 2009 13:48:27 -0400 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1MZTLr-00045Y-LJ for qemu-devel@nongnu.org; Fri, 07 Aug 2009 13:35:35 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1MZTLm-00042e-CY for qemu-devel@nongnu.org; Fri, 07 Aug 2009 13:35:34 -0400 Received: from [199.232.76.173] (port=39304 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1MZTLl-00042Z-Bt for qemu-devel@nongnu.org; Fri, 07 Aug 2009 13:35:29 -0400 Received: from smtp.ctxuk.citrix.com ([62.200.22.115]:17657 helo=SMTP.EU.CITRIX.COM) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1MZTLj-0002FR-8p for qemu-devel@nongnu.org; Fri, 07 Aug 2009 13:35:28 -0400 X-IronPort-AV: E=Sophos;i="4.43,343,1246838400"; d="scan'208";a="6538160" Received: from lonpmailmx01.citrite.net ([10.30.224.162]) by LONPIPO01.EU.CITRIX.COM with ESMTP; 07 Aug 2009 17:35:26 +0000 Received: from localhost.localdomain (10.80.2.58) by smtprelay.citirx.com (10.30.224.162) with Microsoft SMTP Server id 8.1.358.0; Fri, 7 Aug 2009 18:35:25 +0100 From: Alexandre Bique To: Date: Fri, 7 Aug 2009 18:33:12 +0100 Message-ID: <1249666392-31905-8-git-send-email-alexandre.bique@citrix.com> X-Mailer: git-send-email 1.6.4 In-Reply-To: <1249666392-31905-7-git-send-email-alexandre.bique@citrix.com> References: <1249666392-31905-1-git-send-email-alexandre.bique@citrix.com> <1249666392-31905-2-git-send-email-alexandre.bique@citrix.com> <1249666392-31905-3-git-send-email-alexandre.bique@citrix.com> <1249666392-31905-4-git-send-email-alexandre.bique@citrix.com> <1249666392-31905-5-git-send-email-alexandre.bique@citrix.com> <1249666392-31905-6-git-send-email-alexandre.bique@citrix.com> <1249666392-31905-7-git-send-email-alexandre.bique@citrix.com> MIME-Version: 1.0 X-detected-operating-system: by monty-python.gnu.org: Genre and OS details not recognized. Cc: Alexandre Bique Subject: [Qemu-devel] [PATCH 7/7] atapi: introducing atapi pass through X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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 --- 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 diff --git a/Makefile.target b/Makefile.target index 49ba08d..cf0cb27 100644 --- a/Makefile.target +++ b/Makefile.target @@ -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 diff --git a/hw/atapi-pt.c b/hw/atapi-pt.c new file mode 100644 index 0000000..abb5c26 --- /dev/null +++ b/hw/atapi-pt.c @@ -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 .", + 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; +} diff --git a/hw/atapi-pt.h b/hw/atapi-pt.h new file mode 100644 index 0000000..639270e --- /dev/null +++ b/hw/atapi-pt.h @@ -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 */ diff --git a/hw/ide.c b/hw/ide.c index 9db9cb2..382b05e 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -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); } } diff --git a/hw/ide.h b/hw/ide.h index 064e2d3..58c74b9 100644 --- a/hw/ide.h +++ b/hw/ide.h @@ -40,7 +40,20 @@ #include "dma.h" #include "atapi-defines.h" + #include +#include +#include +#include + +#ifdef __linux__ +# include +# define CONFIG_ATAPI_PT 1 +#else +# define CONFIG_ATAPI_PT 0 +#endif /* __linux__ */ + +#include /* 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]; diff --git a/qemu-options.hx b/qemu-options.hx index 1b420a3..2761223 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -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" diff --git a/vl.c b/vl.c index fdd4f03..e29d13c 100644 --- a/vl.c +++ b/vl.c @@ -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[] = {