* [Qemu-devel] [PATCH] ATAPI pass through
@ 2009-06-30 15:34 Bique Alexandre
2009-06-30 16:26 ` Kevin Wolf
2009-06-30 17:01 ` Christoph Hellwig
0 siblings, 2 replies; 10+ messages in thread
From: Bique Alexandre @ 2009-06-30 15:34 UTC (permalink / raw)
To: qemu-devel
[-- Attachment #1: Type: text/plain, Size: 1157 bytes --]
Hi,
This patch implements ATAPI pass through on Linux by using bsg device.
What works:
- read CD
- burn CD with TAO
- blank CD
- play audio CD
- play DVD movie
What doesn't work:
- burn CD with SAO
DVD blanking and burning needs some testing.
Things which can be done better:
- I exported the data structure BDRVRawState from raw-posix.c in raw-posix.h,
because I use the file descriptor of the bsg device to poll, write and read.
Maybe there is a better solution, but I didn't find what I was looking for in
block.h.
- file splitting: everything is in ide.c, even my atapi pass through code in
the beginning. I didn't want to put everything in this file so I moved my code
in atapi-pt.c but I did #include "atapi-pt.c" in ide.c so it's still in the
spirit of what has been done before: all in ide.c. I'd like to split correctly
this code but I will have to make some static functions public, and if I move
atapi-pt out from ide.c why not atapi out from ide.c and maybe some other
stuff ? That's why I did nothing yet. What would you prefer ?
Please, can you comment on this patch ? Thank you very much.
Regards,
--
Alexandre Bique
[-- Attachment #2: atapi-pass-through --]
[-- Type: text/x-patch, Size: 53824 bytes --]
diff --git a/Makefile b/Makefile
index 2a4b3f3..df5b5c4 100644
--- a/Makefile
+++ b/Makefile
@@ -300,8 +300,9 @@ endif
test speed: all
$(MAKE) -C tests $@
+.PHONY: TAGS
TAGS:
- etags *.[ch] tests/*.[ch] block/*.[ch] hw/*.[ch]
+ find "$(SRC_PATH)" -name '*.[hc]' -print0 | xargs -0 etags
cscope:
rm -f ./cscope.*
diff --git a/block.c b/block.c
index 3fe9317..962b640 100644
--- a/block.c
+++ b/block.c
@@ -883,6 +883,7 @@ void bdrv_set_type_hint(BlockDriverState *bs, int type)
{
bs->type = type;
bs->removable = ((type == BDRV_TYPE_CDROM ||
+ type == BDRV_TYPE_CDROM_PT ||
type == BDRV_TYPE_FLOPPY));
}
diff --git a/block.h b/block.h
index b595772..b362218 100644
--- a/block.h
+++ b/block.h
@@ -102,9 +102,11 @@ void bdrv_flush_all(void);
int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
int *pnum);
-#define BDRV_TYPE_HD 0
-#define BDRV_TYPE_CDROM 1
-#define BDRV_TYPE_FLOPPY 2
+#define BDRV_TYPE_HD 0
+#define BDRV_TYPE_CDROM 1
+#define BDRV_TYPE_FLOPPY 2
+#define BDRV_TYPE_CDROM_PT 3
+
#define BIOS_ATA_TRANSLATION_AUTO 0
#define BIOS_ATA_TRANSLATION_NONE 1
#define BIOS_ATA_TRANSLATION_LBA 2
diff --git a/block/raw-posix.c b/block/raw-posix.c
index 8b1e67c..39a83f3 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -99,20 +99,7 @@
reopen it to see if the disk has been changed */
#define FD_OPEN_TIMEOUT 1000
-typedef struct BDRVRawState {
- int fd;
- int type;
- unsigned int lseek_err_cnt;
- int open_flags;
-#if defined(__linux__)
- /* linux floppy specific */
- int64_t fd_open_time;
- int64_t fd_error_time;
- int fd_got_error;
- int fd_media_changed;
-#endif
- uint8_t* aligned_buf;
-} BDRVRawState;
+#include "raw-posix.h"
static int posix_aio_init(void);
diff --git a/block/raw-posix.h b/block/raw-posix.h
new file mode 100644
index 0000000..0d3bf85
--- /dev/null
+++ b/block/raw-posix.h
@@ -0,0 +1,19 @@
+#ifndef BLOCK_RAW_POSIX_H
+# define BLOCK_RAW_POSIX_H
+
+typedef struct BDRVRawState {
+ int fd;
+ int type;
+ unsigned int lseek_err_cnt;
+ int open_flags;
+#if defined(__linux__)
+ /* linux floppy specific */
+ int64_t fd_open_time;
+ int64_t fd_error_time;
+ int fd_got_error;
+ int fd_media_changed;
+#endif
+ uint8_t* aligned_buf;
+} BDRVRawState;
+
+#endif /* !BLOCK_RAW_POSIX_H */
diff --git a/configure b/configure
index eb9d73a..9a28082 100755
--- a/configure
+++ b/configure
@@ -191,6 +191,7 @@ nptl="yes"
mixemu="no"
bluez="yes"
kvm="no"
+atapi_pt="no"
kerneldir=""
aix="no"
blobs="yes"
@@ -323,6 +324,19 @@ AIX)
aix="yes"
make="gmake"
;;
+Linux)
+atapi_pt="yes"
+audio_drv_list="oss"
+audio_possible_drivers="oss alsa sdl esd pa"
+linux="yes"
+linux_user="yes"
+usb="linux"
+kvm="yes"
+if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
+ kqemu="yes"
+ audio_possible_drivers="$audio_possible_drivers fmod"
+fi
+;;
*)
audio_drv_list="oss"
audio_possible_drivers="oss alsa sdl esd pa"
@@ -501,6 +515,10 @@ for opt do
;;
--disable-docs) build_docs="no"
;;
+ --enable-atapi-pt) atapi_pt="yes"
+ ;;
+ --disable-atapi-pt) atapi_pt="no"
+ ;;
*) echo "ERROR: unknown option $opt"; show_help="yes"
;;
esac
@@ -646,6 +664,8 @@ echo " --disable-vde disable support for vde network"
echo " --disable-pthread disable pthread support"
echo " --disable-aio disable AIO support"
echo " --enable-io-thread enable IO thread"
+echo " --enable-atapi-pt enable atapi device pass through"
+echo " --disable-atapi-pt disable atapi device pass through"
echo " --disable-blobs disable installing provided firmware blobs"
echo " --kerneldir=PATH look for kernel includes in PATH"
echo ""
@@ -1453,6 +1473,7 @@ echo "Install blobs $blobs"
echo -e "KVM support $kvm"
echo "fdt support $fdt"
echo "preadv support $preadv"
+echo "atapi-pt support $atapi_pt"
if test $sdl_too_old = "yes"; then
echo "-> Your SDL version is too old - please upgrade to have SDL support"
@@ -1823,6 +1844,22 @@ bsd)
;;
esac
+# ATAPI pass through
+if [ "$atapi_pt" = "yes" ] ; then
+ if [ "$targetos" != "Linux" ] ; then
+ echo "error: you need a Linux target OS to use ATAPI pass through" >&2
+ exit 1
+ fi
+ cat <<EOF >>$config_h
+#define CONFIG_ATAPI_PT 1
+#ifndef __linux__
+#error "You can't enable ATAPI pass through if you're not using linux."
+#endif /* __linux__ */
+EOF
+else
+ echo "#define CONFIG_ATAPI_PT 0" >>$config_h
+fi
+
# Determine what linker flags to use to force archive inclusion
check_linker_flags()
{
diff --git a/hw/atapi-pt.c b/hw/atapi-pt.c
new file mode 100644
index 0000000..692042e
--- /dev/null
+++ b/hw/atapi-pt.c
@@ -0,0 +1,968 @@
+//#define DEBUG_IDE_ATAPI_PT
+
+#define MSF_TO_FRAMES(M, S, F) (((M) * CD_SECS + (S)) * CD_FRAMES + (F))
+
+#ifdef DEBUG_IDE_ATAPI_PT
+# define DEBUG_PRINTF(Args...) printf(Args)
+# define CHECK_SAME_VALUE(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 DEBUG_PRINTF(Args...)
+# define CHECK_SAME_VALUE(Val1, Val2)
+#endif /* DEBUG_IDE_ATAPI_PT */
+
+/* The generic packet command opcodes for CD/DVD Logical Units,
+ * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
+static const struct {
+ unsigned short packet_command;
+ const char * const text;
+} packet_command_texts[] = {
+ { GPCMD_TEST_UNIT_READY, "Test Unit Ready" },
+ { GPCMD_REQUEST_SENSE, "Request Sense" },
+ { GPCMD_FORMAT_UNIT, "Format Unit" },
+ { GPCMD_INQUIRY, "Inquiry" },
+ { GPCMD_START_STOP_UNIT, "Start/Stop Unit" },
+ { GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL, "Prevent/Allow Medium Removal" },
+ { GPCMD_READ_FORMAT_CAPACITIES, "Read Format Capacities" },
+ { GPCMD_READ_CDVD_CAPACITY, "Read Cd/Dvd Capacity" },
+ { GPCMD_READ_10, "Read 10" },
+ { GPCMD_WRITE_10, "Write 10" },
+ { GPCMD_SEEK, "Seek" },
+ { GPCMD_WRITE_AND_VERIFY_10, "Write and Verify 10" },
+ { GPCMD_VERIFY_10, "Verify 10" },
+ { GPCMD_FLUSH_CACHE, "Flush Cache" },
+ { GPCMD_READ_SUBCHANNEL, "Read Subchannel" },
+ { GPCMD_READ_TOC_PMA_ATIP, "Read Table of Contents" },
+ { GPCMD_READ_HEADER, "Read Header" },
+ { GPCMD_PLAY_AUDIO_10, "Play Audio 10" },
+ { GPCMD_GET_CONFIGURATION, "Get Configuration" },
+ { GPCMD_PLAY_AUDIO_MSF, "Play Audio MSF" },
+ { GPCMD_PLAYAUDIO_TI, "Play Audio TrackIndex" },
+ { GPCMD_GET_EVENT_STATUS_NOTIFICATION,
+ "Get Event Status Notification" },
+ { GPCMD_PAUSE_RESUME, "Pause/Resume" },
+ { GPCMD_STOP_PLAY_SCAN, "Stop Play/Scan" },
+ { GPCMD_READ_DISC_INFO, "Read Disc Info" },
+ { GPCMD_READ_TRACK_RZONE_INFO, "Read Track Rzone Info" },
+ { GPCMD_RESERVE_RZONE_TRACK, "Reserve Rzone Track" },
+ { GPCMD_SEND_OPC, "Send OPC" },
+ { GPCMD_MODE_SELECT_10, "Mode Select 10" },
+ { GPCMD_REPAIR_RZONE_TRACK, "Repair Rzone Track" },
+ { GPCMD_MODE_SENSE_10, "Mode Sense 10" },
+ { GPCMD_CLOSE_TRACK, "Close Track" },
+ { GPCMD_BLANK, "Blank" },
+ { GPCMD_SEND_EVENT, "Send Event" },
+ { GPCMD_SEND_KEY, "Send Key" },
+ { GPCMD_REPORT_KEY, "Report Key" },
+ { GPCMD_LOAD_UNLOAD, "Load/Unload" },
+ { GPCMD_SET_READ_AHEAD, "Set Read-ahead" },
+ { GPCMD_READ_12, "Read 12" },
+ { GPCMD_GET_PERFORMANCE, "Get Performance" },
+ { GPCMD_SEND_DVD_STRUCTURE, "Send DVD Structure" },
+ { GPCMD_READ_DVD_STRUCTURE, "Read DVD Structure" },
+ { GPCMD_SET_STREAMING, "Set Streaming" },
+ { GPCMD_READ_CD_MSF, "Read CD MSF" },
+ { GPCMD_SCAN, "Scan" },
+ { GPCMD_SET_SPEED, "Set Speed" },
+ { GPCMD_PLAY_CD, "Play CD" },
+ { GPCMD_MECHANISM_STATUS, "Mechanism Status" },
+ { GPCMD_READ_CD, "Read CD" },
+ { GPCMD_READ_BUFFER_CAPACITY, "Read Buffer Capacity" },
+ { GPCMD_READ_BUFFER, "Read Buffer" },
+ { GPCMD_SEND_CUE_SHEET, "Send Cue Sheet" },
+ { 0, 0 }
+};
+
+#ifdef DEBUG_IDE_ATAPI_PT
+static const char *atapi_cmd_to_str(int cmd)
+{
+ int i;
+
+ for (i = 0; packet_command_texts[i].text; ++i)
+ if (packet_command_texts[i].packet_command == cmd)
+ return packet_command_texts[i].text;
+ return 0;
+}
+#endif /* DEBUG_IDE_ATAPI_PT */
+
+/* From Table 303 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
+static const char * const sense_key_texts[16] = {
+ "No sense data",
+ "Recovered error",
+ "Not ready",
+ "Medium error",
+ "Hardware error",
+ "Illegal request",
+ "Unit attention",
+ "Data protect",
+ "Blank check",
+ "(reserved)",
+ "(reserved)",
+ "Aborted command",
+ "(reserved)",
+ "(reserved)",
+ "Miscompare",
+ "(reserved)",
+};
+
+/* From Table 304 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
+static const struct {
+ unsigned long asc_ascq;
+ const char * const text;
+} sense_data_texts[] = {
+ { 0x000000, "No additional sense information" },
+ { 0x000011, "Play operation in progress" },
+ { 0x000012, "Play operation paused" },
+ { 0x000013, "Play operation successfully completed" },
+ { 0x000014, "Play operation stopped due to error" },
+ { 0x000015, "No current audio status to return" },
+ { 0x010c0a, "Write error - padding blocks added" },
+ { 0x011700, "Recovered data with no error correction applied" },
+ { 0x011701, "Recovered data with retries" },
+ { 0x011702, "Recovered data with positive head offset" },
+ { 0x011703, "Recovered data with negative head offset" },
+ { 0x011704, "Recovered data with retries and/or CIRC applied" },
+ { 0x011705, "Recovered data using previous sector ID" },
+ { 0x011800, "Recovered data with error correction applied" },
+ { 0x011801, "Recovered data with error correction and retries applied"},
+ { 0x011802, "Recovered data - the data was auto-reallocated" },
+ { 0x011803, "Recovered data with CIRC" },
+ { 0x011804, "Recovered data with L-EC" },
+ { 0x015d00, "Failure prediction threshold exceeded"
+ " - Predicted logical unit failure" },
+ { 0x015d01, "Failure prediction threshold exceeded"
+ " - Predicted media failure" },
+ { 0x015dff, "Failure prediction threshold exceeded - False" },
+ { 0x017301, "Power calibration area almost full" },
+ { 0x020400, "Logical unit not ready - cause not reportable" },
+ /* Following is misspelled in ATAPI 2.6, _and_ in Mt. Fuji */
+ { 0x020401, "Logical unit not ready"
+ " - in progress [sic] of becoming ready" },
+ { 0x020402, "Logical unit not ready - initializing command required" },
+ { 0x020403, "Logical unit not ready - manual intervention required" },
+ { 0x020404, "Logical unit not ready - format in progress" },
+ { 0x020407, "Logical unit not ready - operation in progress" },
+ { 0x020408, "Logical unit not ready - long write in progress" },
+ { 0x020600, "No reference position found (media may be upside down)" },
+ { 0x023000, "Incompatible medium installed" },
+ { 0x023a00, "Medium not present" },
+ { 0x025300, "Media load or eject failed" },
+ { 0x025700, "Unable to recover table of contents" },
+ { 0x030300, "Peripheral device write fault" },
+ { 0x030301, "No write current" },
+ { 0x030302, "Excessive write errors" },
+ { 0x030c00, "Write error" },
+ { 0x030c01, "Write error - Recovered with auto reallocation" },
+ { 0x030c02, "Write error - auto reallocation failed" },
+ { 0x030c03, "Write error - recommend reassignment" },
+ { 0x030c04, "Compression check miscompare error" },
+ { 0x030c05, "Data expansion occurred during compress" },
+ { 0x030c06, "Block not compressible" },
+ { 0x030c07, "Write error - recovery needed" },
+ { 0x030c08, "Write error - recovery failed" },
+ { 0x030c09, "Write error - loss of streaming" },
+ { 0x031100, "Unrecovered read error" },
+ { 0x031106, "CIRC unrecovered error" },
+ { 0x033101, "Format command failed" },
+ { 0x033200, "No defect spare location available" },
+ { 0x033201, "Defect list update failure" },
+ { 0x035100, "Erase failure" },
+ { 0x037200, "Session fixation error" },
+ { 0x037201, "Session fixation error writin lead-in" },
+ { 0x037202, "Session fixation error writin lead-out" },
+ { 0x037300, "CD control error" },
+ { 0x037302, "Power calibration area is full" },
+ { 0x037303, "Power calibration area error" },
+ { 0x037304, "Program memory area / RMA update failure" },
+ { 0x037305, "Program memory area / RMA is full" },
+ { 0x037306, "Program memory area / RMA is (almost) full" },
+ { 0x040200, "No seek complete" },
+ { 0x040300, "Write fault" },
+ { 0x040900, "Track following error" },
+ { 0x040901, "Tracking servo failure" },
+ { 0x040902, "Focus servo failure" },
+ { 0x040903, "Spindle servo failure" },
+ { 0x041500, "Random positioning error" },
+ { 0x041501, "Mechanical positioning or changer error" },
+ { 0x041502, "Positioning error detected by read of medium" },
+ { 0x043c00, "Mechanical positioning or changer error" },
+ { 0x044000, "Diagnostic failure on component (ASCQ)" },
+ { 0x044400, "Internal CD/DVD logical unit failure" },
+ { 0x04b600, "Media load mechanism failed" },
+ { 0x051a00, "Parameter list length error" },
+ { 0x052000, "Invalid command operation code" },
+ { 0x052100, "Logical block address out of range" },
+ { 0x052102, "Invalid address for write" },
+ { 0x052400, "Invalid field in command packet" },
+ { 0x052600, "Invalid field in parameter list" },
+ { 0x052601, "Parameter not supported" },
+ { 0x052602, "Parameter value invalid" },
+ { 0x052700, "Write protected media" },
+ { 0x052c00, "Command sequence error" },
+ { 0x052c03, "Current program area is not empty" },
+ { 0x052c04, "Current program area is empty" },
+ { 0x053001, "Cannot read medium - unknown format" },
+ { 0x053002, "Cannot read medium - incompatible format" },
+ { 0x053900, "Saving parameters not supported" },
+ { 0x054e00, "Overlapped commands attempted" },
+ { 0x055302, "Medium removal prevented" },
+ { 0x055500, "System resource failure" },
+ { 0x056300, "End of user area encountered on this track" },
+ { 0x056400, "Illegal mode for this track or incompatible medium" },
+ { 0x056f00, "Copy protection key exchange failure"
+ " - Authentication failure" },
+ { 0x056f01, "Copy protection key exchange failure - Key not present" },
+ { 0x056f02, "Copy protection key exchange failure"
+ " - Key not established" },
+ { 0x056f03, "Read of scrambled sector without authentication" },
+ { 0x056f04, "Media region code is mismatched to logical unit" },
+ { 0x056f05, "Drive region must be permanent"
+ " / region reset count error" },
+ { 0x057203, "Session fixation error - incomplete track in session" },
+ { 0x057204, "Empty or partially written reserved track" },
+ { 0x057205, "No more RZONE reservations are allowed" },
+ { 0x05bf00, "Loss of streaming" },
+ { 0x062800, "Not ready to ready transition, medium may have changed" },
+ { 0x062900, "Power on, reset or hardware reset occurred" },
+ { 0x062a00, "Parameters changed" },
+ { 0x062a01, "Mode parameters changed" },
+ { 0x062e00, "Insufficient time for operation" },
+ { 0x063f00, "Logical unit operating conditions have changed" },
+ { 0x063f01, "Microcode has been changed" },
+ { 0x065a00, "Operator request or state change input (unspecified)" },
+ { 0x065a01, "Operator medium removal request" },
+ { 0x0bb900, "Play operation aborted" },
+ /* Here we use 0xff for the key (not a valid key) to signify
+ * that these can have _any_ key value associated with them... */
+ { 0xff0401, "Logical unit is in process of becoming ready" },
+ { 0xff0400, "Logical unit not ready, cause not reportable" },
+ { 0xff0402, "Logical unit not ready, initializing command required" },
+ { 0xff0403, "Logical unit not ready, manual intervention required" },
+ { 0xff0500, "Logical unit does not respond to selection" },
+ { 0xff0800, "Logical unit communication failure" },
+ { 0xff0802, "Logical unit communication parity error" },
+ { 0xff0801, "Logical unit communication time-out" },
+ { 0xff2500, "Logical unit not supported" },
+ { 0xff4c00, "Logical unit failed self-configuration" },
+ { 0xff3e00, "Logical unit has not self-configured yet" },
+};
+
+#ifdef DEBUG_IDE_ATAPI_PT
+static const char *atapi_ascq_to_str(int ascq)
+{
+ int i;
+
+ for (i = 0; sense_data_texts[i].text; ++i)
+ if (sense_data_texts[i].asc_ascq == ascq)
+ return sense_data_texts[i].text;
+ return 0;
+}
+#endif /* DEBUG_IDE_ATAPI_PT */
+
+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(IDEState *s)
+{
+ BDRVRawState *raw_state = s->bs->opaque;
+ int read_bytes;
+ read_bytes = read(raw_state->fd, &s->atapi_pt.cmd, sizeof (s->atapi_pt.cmd));
+
+ if (read_bytes != sizeof (s->atapi_pt.cmd))
+ {
+ ide_atapi_pt_error(s);
+ return;
+ }
+
+ 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",
+ 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.transport_status,
+ s->atapi_pt.cmd.device_status);
+ ide_atapi_pt_error(s);
+ return;
+ }
+ s->atapi_pt.cmd_sent(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;
+}
+
+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.dout_xfer_len;
+ ide_dma_start(s, ide_atapi_pt_read_dma_cb);
+ return;
+ }
+
+ /* PIO */
+ s->packet_transfer_size = s->atapi_pt.cmd.dout_xfer_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.dout_xfer_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.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;
+ }
+ DEBUG_PRINTF("[reply] size: %d, din_resid: %d, max_in:%d, response_len: %d\n",
+ size, s->atapi_pt.cmd.din_resid, s->atapi_pt.cmd.din_xfer_len,
+ s->atapi_pt.cmd.response_len);
+ 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)
+{
+ 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;
+}
+
+static void ide_atapi_pt_cmd(IDEState *s)
+{
+ struct sg_io_v4 *cmd = &s->atapi_pt.cmd;
+
+ memset(cmd, 0, sizeof (*cmd));
+ memcpy(s->atapi_pt.request, s->io_buffer, ATAPI_PACKET_SIZE);
+ 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->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;
+
+ 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);
+ s->atapi_pt.cmd_sent = ide_atapi_cmd_ok;
+ ATAPI_PT_SEND_PACKET;
+ return;
+
+ /******************/
+ /* WRITE COMMANDS */
+ /******************/
+
+ case GPCMD_WRITE_10:
+ case GPCMD_WRITE_AND_VERIFY_10:
+ cmd->dout_xfer_len = ube16_to_cpu(s->io_buffer + 7) * CD_FRAMESIZE;
+ if (cmd->dout_xfer_len == 0)
+ goto simple_cmd;
+ ide_atapi_pt_wcmd(s);
+ return;
+
+ case GPCMD_WRITE_12:
+ cmd->dout_xfer_len = ube32_to_cpu(s->io_buffer + 6);
+ if (cmd->dout_xfer_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;
+
+ 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;
+ }
+
+ ide_atapi_pt_wcmd(s);
+ return;
+ }
+
+ case GPCMD_SEND_CUE_SHEET:
+ cmd->dout_xfer_len = ube24_to_cpu(s->io_buffer + 6);
+ if (cmd->dout_xfer_len == 0)
+ goto simple_cmd;
+ ide_atapi_pt_wcmd(s);
+ return;
+
+ 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);
+ if (cmd->dout_xfer_len == 0)
+ goto simple_cmd;
+ ide_atapi_pt_wcmd(s);
+ return;
+
+ case GPCMD_SEND_KEY:
+ case GPCMD_SEND_EVENT:
+ cmd->dout_xfer_len = ube16_to_cpu(s->io_buffer + 8);
+ if (cmd->dout_xfer_len == 0)
+ goto simple_cmd;
+ ide_atapi_pt_wcmd(s);
+ return;
+
+ case GPCMD_SEND_OPC:
+ cmd->dout_xfer_len = ube16_to_cpu(s->io_buffer + 7) << 3;
+ CHECK_SAME_VALUE(s->lcyl | (s->hcyl << 8), cmd->dout_xfer_len);
+ if (cmd->dout_xfer_len == 0)
+ goto simple_cmd;
+ ide_atapi_pt_wcmd(s);
+ return;
+
+ case GPCMD_SET_STREAMING:
+ cmd->dout_xfer_len = ube16_to_cpu(s->io_buffer + 9);
+ if (cmd->dout_xfer_len == 0)
+ goto simple_cmd;
+ ide_atapi_pt_wcmd(s);
+ return;
+
+ case GPCMD_FORMAT_UNIT:
+ cmd->dout_xfer_len = 12;
+ ide_atapi_pt_wcmd(s);
+ return;
+
+ /*****************/
+ /* 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:
+ {
+ // send the previous sense command
+ DEBUG_PRINTF("=== 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;
+
+ DEBUG_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 = 4;
+ ATAPI_PT_SEND_PACKET;
+ return;
+
+ 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;
+
+ 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;
+
+ 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;
+ ATAPI_PT_SEND_PACKET;
+ return;
+
+ 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;
+
+ 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;
+
+ case GPCMD_READ_10:
+ case GPCMD_READ_12:
+ {
+ int blocksize = 0, nbblocks;
+
+ switch (s->io_buffer[0]) {
+ case GPCMD_READ_10: blocksize = CD_FRAMESIZE; break;
+ case GPCMD_READ_12: blocksize = CD_FRAMESIZE_RAW0; break;
+ default: assert(0);
+ }
+ nbblocks = ube16_to_cpu(s->io_buffer + 7);
+ 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;
+ }
+
+ 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;
+
+ 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;
+
+ 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;
+
+ 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;
+
+ 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;
+
+ 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;
+ }
+
+ 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->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;
+ }
+
+ 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;
+ }
+
+ 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->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;
+ }
+
+ 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;
+
+ 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;
+
+ 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;
+
+ 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;
+
+ default:
+ fprintf(stderr, "[ATAPI-PT] We got an unhandled command: 0x%02x. "
+ "Please report.\n", s->io_buffer[0]);
+ exit(1);
+ return;
+ }
+}
diff --git a/hw/ide.c b/hw/ide.c
index 1e56786..01e153f 100644
--- a/hw/ide.c
+++ b/hw/ide.c
@@ -22,6 +22,7 @@
* 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"
@@ -36,6 +37,15 @@
#include "sh.h"
#include "dma.h"
+#if CONFIG_ATAPI_PT
+#include "block/raw-posix.h"
+
+#include <linux/cdrom.h>
+#include <linux/bsg.h>
+#endif /* CONFIG_ATAPI_PT */
+
+#include <assert.h>
+
/* debug IDE devices */
//#define DEBUG_IDE
//#define DEBUG_IDE_ATAPI
@@ -216,13 +226,18 @@
#define ATAPI_PACKET_SIZE 12
-/* The generic packet command opcodes for CD/DVD Logical Units,
- * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
+#ifndef _LINUX_CDROM_H
+/*********************************************************************
+ * Generic Packet commands, MMC commands, and such
+ *********************************************************************/
+
+ /* The generic packet command opcodes for CD/DVD Logical Units,
+ * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
#define GPCMD_BLANK 0xa1
#define GPCMD_CLOSE_TRACK 0x5b
#define GPCMD_FLUSH_CACHE 0x35
#define GPCMD_FORMAT_UNIT 0x04
-#define GPCMD_GET_CONFIGURATION 0x46
+#define GPCMD_GET_CONFIGURATION 0x46
#define GPCMD_GET_EVENT_STATUS_NOTIFICATION 0x4a
#define GPCMD_GET_PERFORMANCE 0xac
#define GPCMD_INQUIRY 0x12
@@ -238,6 +253,8 @@
#define GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e
#define GPCMD_READ_10 0x28
#define GPCMD_READ_12 0xa8
+#define GPCMD_READ_BUFFER 0x3c
+#define GPCMD_READ_BUFFER_CAPACITY 0x5c
#define GPCMD_READ_CDVD_CAPACITY 0x25
#define GPCMD_READ_CD 0xbe
#define GPCMD_READ_CD_MSF 0xb9
@@ -246,15 +263,16 @@
#define GPCMD_READ_FORMAT_CAPACITIES 0x23
#define GPCMD_READ_HEADER 0x44
#define GPCMD_READ_TRACK_RZONE_INFO 0x52
-#define GPCMD_READ_SUBCHANNEL 0x42
-#define GPCMD_READ_TOC_PMA_ATIP 0x43
+#define GPCMD_READ_SUBCHANNEL 0x42
+#define GPCMD_READ_TOC_PMA_ATIP 0x43
#define GPCMD_REPAIR_RZONE_TRACK 0x58
#define GPCMD_REPORT_KEY 0xa4
#define GPCMD_REQUEST_SENSE 0x03
#define GPCMD_RESERVE_RZONE_TRACK 0x53
+#define GPCMD_SEND_CUE_SHEET 0x5d
#define GPCMD_SCAN 0xba
#define GPCMD_SEEK 0x2b
-#define GPCMD_SEND_DVD_STRUCTURE 0xad
+#define GPCMD_SEND_DVD_STRUCTURE 0xbf
#define GPCMD_SEND_EVENT 0xa2
#define GPCMD_SEND_KEY 0xa3
#define GPCMD_SEND_OPC 0x54
@@ -263,9 +281,11 @@
#define GPCMD_START_STOP_UNIT 0x1b
#define GPCMD_STOP_PLAY_SCAN 0x4e
#define GPCMD_TEST_UNIT_READY 0x00
-#define GPCMD_VERIFY_10 0x2f
+#define GPCMD_VERIFY_10 0x2f
#define GPCMD_WRITE_10 0x2a
+#define GPCMD_WRITE_12 0xaa
#define GPCMD_WRITE_AND_VERIFY_10 0x2e
+#define GPCMD_WRITE_BUFFER 0x3b
/* This is listed as optional in ATAPI 2.6, but is (curiously)
* missing from Mt. Fuji, Table 57. It _is_ mentioned in Mt. Fuji
* Table 377 as an MMC command for SCSi devices though... Most ATAPI
@@ -279,18 +299,20 @@
* older drives only.
*/
#define GPCMD_GET_MEDIA_STATUS 0xda
-#define GPCMD_MODE_SENSE_6 0x1a
+#define GPCMD_MODE_SENSE_6 0x1a
/* Mode page codes for mode sense/set */
+#define GPMODE_VENDOR_PAGE 0x00
#define GPMODE_R_W_ERROR_PAGE 0x01
#define GPMODE_WRITE_PARMS_PAGE 0x05
+#define GPMODE_WCACHING_PAGE 0x08
#define GPMODE_AUDIO_CTL_PAGE 0x0e
#define GPMODE_POWER_PAGE 0x1a
#define GPMODE_FAULT_FAIL_PAGE 0x1c
#define GPMODE_TO_PROTECT_PAGE 0x1d
#define GPMODE_CAPABILITIES_PAGE 0x2a
#define GPMODE_ALL_PAGES 0x3f
-/* Not in Mt. Fuji, but in ATAPI 2.6 -- depricated now in favor
+/* Not in Mt. Fuji, but in ATAPI 2.6 -- deprecated now in favor
* of MODE_SENSE_POWER_PAGE */
#define GPMODE_CDROM_PAGE 0x0d
@@ -308,6 +330,14 @@
#define CD_SECS 60 /* seconds per minute */
#define CD_FRAMES 75 /* frames per second */
#define CD_FRAMESIZE 2048 /* bytes per frame, "cooked" mode */
+
+#else
+
+/* This one is not present in linux/cdrom.h */
+#define GPCMD_MODE_SENSE_6 0x1a
+
+#endif /* !_LINUX_CDROM_H */
+
#define CD_MAX_BYTES (CD_MINS * CD_SECS * CD_FRAMES * CD_FRAMESIZE)
#define CD_MAX_SECTORS (CD_MAX_BYTES / 512)
@@ -346,12 +376,15 @@
#define MMC_PROFILE_HDDVD_RW_DL 0x005A
#define MMC_PROFILE_INVALID 0xFFFF
+
#define ATAPI_INT_REASON_CD 0x01 /* 0 = data transfer */
#define ATAPI_INT_REASON_IO 0x02 /* 1 = transfer to the host */
#define ATAPI_INT_REASON_REL 0x04
#define ATAPI_INT_REASON_TAG 0xf8
/* same constants as bochs */
+#define ASC_NONE 0x00
+#define ASC_READ_ERROR 0x11
#define ASC_ILLEGAL_OPCODE 0x20
#define ASC_LOGICAL_BLOCK_OOR 0x21
#define ASC_INV_FIELD_IN_CMD_PACKET 0x24
@@ -367,15 +400,42 @@
#define CFA_INVALID_ADDRESS 0x21
#define CFA_ADDRESS_OVERFLOW 0x2f
-#define SENSE_NONE 0
-#define SENSE_NOT_READY 2
-#define SENSE_ILLEGAL_REQUEST 5
-#define SENSE_UNIT_ATTENTION 6
+/* Sense keys */
+#define SENSE_NONE 0
+#define SENSE_RECOVERED_ERROR 1
+#define SENSE_NOT_READY 2
+#define SENSE_MEDIUM_ERROR 3
+#define SENSE_HARDWARE_ERROR 4
+#define SENSE_ILLEGAL_REQUEST 5
+#define SENSE_UNIT_ATTENTION 6
+#define SENSE_DATA_PROTECT 7
+#define SENSE_BLANK_CHECK 8
+#define SENSE_VENDOR_SPECIFIC 9
+#define SENSE_COPY_ABORTED 10
+#define SENSE_ABORTED_COMMAND 11
+#define SENSE_VOLUME_OVERFLOW 13
+#define SENSE_MISCOMPARE 14
+
+#define IO_BUFFER_MAX_SIZE (IDE_DMA_BUF_SECTORS * 512 + 4)
struct IDEState;
typedef void EndTransferFunc(struct IDEState *);
+#if CONFIG_ATAPI_PT
+typedef struct ATAPIPassThroughState
+{
+ uint8_t request[ATAPI_PACKET_SIZE];
+ struct sg_io_v4 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 */
@@ -424,6 +484,10 @@ 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_cmd)(struct IDEState *); // the ATAPI cmd handler
/* ATA DMA state */
int io_buffer_size;
QEMUSGList sg;
@@ -1229,6 +1293,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];
@@ -1616,6 +1688,10 @@ static int ide_dvd_read_structure(IDEState *s, int format,
}
}
+#if CONFIG_ATAPI_PT
+#include "atapi-pt.c"
+#endif
+
static void ide_atapi_cmd(IDEState *s)
{
const uint8_t *packet;
@@ -1664,9 +1740,9 @@ static void ide_atapi_cmd(IDEState *s)
switch(action) {
case 0: /* current values */
switch(code) {
- case 0x01: /* error recovery */
+ case 0x01: /* read write error recovery parameters */
cpu_to_ube16(&buf[0], 16 + 6);
- buf[2] = 0x70;
+ buf[2] = 0x70; /* Obselete: medium type code */
buf[3] = 0;
buf[4] = 0;
buf[5] = 0;
@@ -1683,17 +1759,17 @@ static void ide_atapi_cmd(IDEState *s)
buf[15] = 0x00;
ide_atapi_cmd_reply(s, 16, max_len);
break;
- case 0x2a:
+ case 0x2a: /* CD/DVD capabilities & mechanical status */
cpu_to_ube16(&buf[0], 28 + 6);
- buf[2] = 0x70;
+ buf[2] = 0x70; /* Obselete: medium type code */
buf[3] = 0;
buf[4] = 0;
buf[5] = 0;
buf[6] = 0;
buf[7] = 0;
- buf[8] = 0x2a;
- buf[9] = 0x12;
+ buf[8] = 0x2a; /* page code */
+ buf[9] = 0x12; /* page lenght */
buf[10] = 0x00;
buf[11] = 0x00;
@@ -2474,7 +2550,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:
@@ -2813,8 +2889,20 @@ static void ide_init2(IDEState *ide_state,
if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) {
s->is_cdrom = 1;
+ s->atapi_cmd = ide_atapi_cmd;
bdrv_set_change_cb(s->bs, cdrom_change_cb, s);
}
+#if CONFIG_ATAPI_PT
+ else if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM_PT) {
+ BDRVRawState *raw_state = s->bs->opaque;
+ s->is_cdrom = 1;
+ s->atapi_cmd = ide_atapi_pt_cmd;
+ bdrv_set_change_cb(s->bs, cdrom_change_cb, s);
+ qemu_set_fd_handler(raw_state->fd,
+ (IOHandler *)ide_atapi_pt_sg_io_finished,
+ NULL, s);
+ }
+#endif /* CONFIG_ATAPI_PT */
}
s->drive_serial = drive_serial++;
strncpy(s->drive_serial_str, drive_get_serial(s->bs),
diff --git a/qemu-options.hx b/qemu-options.hx
index a94f9d3..d362954 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -88,6 +88,14 @@ 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-pt", HAS_ARG, QEMU_OPTION_cdrom_pt,
+ "-cdrom-pt file use cdrom pass through\n")
+STEXI
+@item -cdrom-pt @var{device}
+Use @var{device} as CD-ROM device. It uses bsg on linux so the device
+should be something like @file{/dev/bsg/1:0:0:0}.
+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 7b7489c..178125a 100644
--- a/vl.c
+++ b/vl.c
@@ -2071,6 +2071,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"
@@ -2207,7 +2208,7 @@ int drive_init(struct drive_opt *arg, int snapshot, void *opaque)
char serial[21];
const char *mediastr = "";
BlockInterfaceType type;
- enum { MEDIA_DISK, MEDIA_CDROM } media;
+ enum { MEDIA_DISK, MEDIA_CDROM, MEDIA_CDROM_PT } media;
int bus_id, unit_id;
int cyls, heads, secs, translation;
BlockDriverState *bdrv;
@@ -2366,6 +2367,8 @@ int drive_init(struct drive_opt *arg, int snapshot, void *opaque)
return -1;
}
media = MEDIA_CDROM;
+ } else if (!strcmp(buf, "cdrompt")) {
+ media = MEDIA_CDROM_PT;
} else {
fprintf(stderr, "qemu: '%s' invalid media\n", str);
return -1;
@@ -2531,6 +2534,9 @@ int drive_init(struct drive_opt *arg, int snapshot, void *opaque)
case MEDIA_CDROM:
bdrv_set_type_hint(bdrv, BDRV_TYPE_CDROM);
break;
+ case MEDIA_CDROM_PT:
+ bdrv_set_type_hint(bdrv, BDRV_TYPE_CDROM_PT);
+ break;
}
break;
case IF_SD:
@@ -5266,6 +5272,9 @@ int main(int argc, char **argv, char **envp)
case QEMU_OPTION_cdrom:
drive_add(optarg, CDROM_ALIAS);
break;
+ case QEMU_OPTION_cdrom_pt:
+ drive_add(optarg, CDROM_PT_ALIAS);
+ break;
case QEMU_OPTION_boot:
boot_devices = optarg;
/* We just do some generic consistency checks */
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [Qemu-devel] [PATCH] ATAPI pass through
2009-06-30 15:34 [Qemu-devel] [PATCH] ATAPI pass through Bique Alexandre
@ 2009-06-30 16:26 ` Kevin Wolf
2009-06-30 18:10 ` Bique Alexandre
2009-07-01 6:57 ` Alexander Graf
2009-06-30 17:01 ` Christoph Hellwig
1 sibling, 2 replies; 10+ messages in thread
From: Kevin Wolf @ 2009-06-30 16:26 UTC (permalink / raw)
To: Bique Alexandre; +Cc: qemu-devel
Bique Alexandre schrieb:
> Hi,
>
> This patch implements ATAPI pass through on Linux by using bsg device.
>
> What works:
> - read CD
> - burn CD with TAO
> - blank CD
> - play audio CD
> - play DVD movie
>
> What doesn't work:
> - burn CD with SAO
>
> DVD blanking and burning needs some testing.
First of all, I would suggest splitting this patch up. You seem to have
included some pieces of unrelated changes like adding comments, changing
constants (Are these fixes? Definitely need a good patch description!),
moving code (block-raw-posix.h) and probably some more.
> Things which can be done better:
> - I exported the data structure BDRVRawState from raw-posix.c in raw-posix.h,
> because I use the file descriptor of the bsg device to poll, write and read.
> Maybe there is a better solution, but I didn't find what I was looking for in
> block.h.
Don't do that. If there is something missing in the block interface, we
need to add it there and properly wire things up. Just poking in block
driver internals is clearly the wrong approach.
>From what I see the only thing you are doing with it is read/write. Why
can't you use the normal block layer functions for it?
> - file splitting: everything is in ide.c, even my atapi pass through code in
> the beginning. I didn't want to put everything in this file so I moved my code
> in atapi-pt.c but I did #include "atapi-pt.c" in ide.c so it's still in the
> spirit of what has been done before: all in ide.c. I'd like to split correctly
> this code but I will have to make some static functions public, and if I move
> atapi-pt out from ide.c why not atapi out from ide.c and maybe some other
> stuff ? That's why I did nothing yet. What would you prefer ?
I guess proper splitting wouldn't hurt anyway. ide.c looks way too large.
>
> Please, can you comment on this patch ? Thank you very much.
Another detail I saw is ATAPI_PT_SEND_PACKET. I mean, isn't this a bit
too big for a macro? No chance to make this nicer?
I haven't really looked at the functionality. There are most probably
people around who can do a better review of it.
Kevin
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Qemu-devel] [PATCH] ATAPI pass through
2009-06-30 15:34 [Qemu-devel] [PATCH] ATAPI pass through Bique Alexandre
2009-06-30 16:26 ` Kevin Wolf
@ 2009-06-30 17:01 ` Christoph Hellwig
2009-06-30 17:55 ` Bique Alexandre
1 sibling, 1 reply; 10+ messages in thread
From: Christoph Hellwig @ 2009-06-30 17:01 UTC (permalink / raw)
To: Bique Alexandre; +Cc: qemu-devel
On Tue, Jun 30, 2009 at 04:34:53PM +0100, Bique Alexandre wrote:
> - I exported the data structure BDRVRawState from raw-posix.c in raw-posix.h,
> because I use the file descriptor of the bsg device to poll, write and read.
> Maybe there is a better solution, but I didn't find what I was looking for in
> block.h.
The way we do scsi passthrough (and ATAPI really just is SCSI
passthrough over ATA with a slightly special command set) is to call
into the ioctl/aio_ioctl methods of the block driver and let that do
the actual I/O. I think your patch would be simpler and cleaner by
following that model
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Qemu-devel] [PATCH] ATAPI pass through
2009-06-30 17:01 ` Christoph Hellwig
@ 2009-06-30 17:55 ` Bique Alexandre
2009-07-01 8:43 ` Christoph Hellwig
0 siblings, 1 reply; 10+ messages in thread
From: Bique Alexandre @ 2009-06-30 17:55 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: qemu-devel@nongnu.org
On Tuesday 30 June 2009 18:01:00 Christoph Hellwig wrote:
> On Tue, Jun 30, 2009 at 04:34:53PM +0100, Bique Alexandre wrote:
> > - I exported the data structure BDRVRawState from raw-posix.c in
> > raw-posix.h, because I use the file descriptor of the bsg device to poll,
> > write and read. Maybe there is a better solution, but I didn't find what
> > I was looking for in block.h.
>
> The way we do scsi passthrough (and ATAPI really just is SCSI
> passthrough over ATA with a slightly special command set) is to call
> into the ioctl/aio_ioctl methods of the block driver and let that do
> the actual I/O. I think your patch would be simpler and cleaner by
> following that model
I can switch to aio_ioctl, and use CDROM_SEND_PACKET ioctl.
Is it possible to send multiple requests at the same time with aio_ioctl ?
When CONFIG_AIO is not available ?
Thanks.
--
Alexandre Bique
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Qemu-devel] [PATCH] ATAPI pass through
2009-06-30 16:26 ` Kevin Wolf
@ 2009-06-30 18:10 ` Bique Alexandre
2009-07-01 6:57 ` Alexander Graf
1 sibling, 0 replies; 10+ messages in thread
From: Bique Alexandre @ 2009-06-30 18:10 UTC (permalink / raw)
To: Kevin Wolf; +Cc: qemu-devel@nongnu.org
On Tuesday 30 June 2009 17:26:31 Kevin Wolf wrote:
> Bique Alexandre schrieb:
> > Hi,
> >
> > This patch implements ATAPI pass through on Linux by using bsg device.
> >
> > What works:
> > - read CD
> > - burn CD with TAO
> > - blank CD
> > - play audio CD
> > - play DVD movie
> >
> > What doesn't work:
> > - burn CD with SAO
> >
> > DVD blanking and burning needs some testing.
>
> First of all, I would suggest splitting this patch up. You seem to have
> included some pieces of unrelated changes like adding comments, changing
> constants (Are these fixes? Definitely need a good patch description!),
> moving code (block-raw-posix.h) and probably some more.
Ok, I will.
> > Things which can be done better:
> > - I exported the data structure BDRVRawState from raw-posix.c in
> > raw-posix.h, because I use the file descriptor of the bsg device to poll,
> > write and read. Maybe there is a better solution, but I didn't find what
> > I was looking for in block.h.
>
> Don't do that. If there is something missing in the block interface, we
> need to add it there and properly wire things up. Just poking in block
> driver internals is clearly the wrong approach.
>
> From what I see the only thing you are doing with it is read/write. Why
> can't you use the normal block layer functions for it?
I also use poll (qemu_set_fd_handler). bsg works like that:
- write your command
=> I am not writing a sector, but just a command which is <512B. So I won't
use bdrv_write. I may use bdrv_pwrite, but why should I seek before writing ?
And where ?
- poll for command completion.
=> I didn't find any polling function from block.h. I can't use bdrv_aio_read
because I am not reading a sector.
- read the result
=> The same as for writing.
Maybe block is not the right semantic for the bsg device and I should open it
manually instead of using QEMU's block driver?
> > - file splitting: everything is in ide.c, even my atapi pass through
> > code in the beginning. I didn't want to put everything in this file so I
> > moved my code in atapi-pt.c but I did #include "atapi-pt.c" in ide.c so
> > it's still in the spirit of what has been done before: all in ide.c. I'd
> > like to split correctly this code but I will have to make some static
> > functions public, and if I move atapi-pt out from ide.c why not atapi out
> > from ide.c and maybe some other stuff ? That's why I did nothing yet.
> > What would you prefer ?
>
> I guess proper splitting wouldn't hurt anyway. ide.c looks way too large.
>
> > Please, can you comment on this patch ? Thank you very much.
>
> Another detail I saw is ATAPI_PT_SEND_PACKET. I mean, isn't this a bit
> too big for a macro? No chance to make this nicer?
It was a macro for historical reason, but it's a static function now.
> I haven't really looked at the functionality. There are most probably
> people around who can do a better review of it.
>
> Kevin
Thanks Kevin.
--
Alexandre Bique
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Qemu-devel] [PATCH] ATAPI pass through
2009-06-30 16:26 ` Kevin Wolf
2009-06-30 18:10 ` Bique Alexandre
@ 2009-07-01 6:57 ` Alexander Graf
2009-07-01 8:44 ` Christoph Hellwig
2009-07-01 9:36 ` Paul Brook
1 sibling, 2 replies; 10+ messages in thread
From: Alexander Graf @ 2009-07-01 6:57 UTC (permalink / raw)
To: Kevin Wolf; +Cc: qemu-devel, Bique Alexandre
On 30.06.2009, at 18:26, Kevin Wolf wrote:
> Bique Alexandre schrieb:
>
>> - file splitting: everything is in ide.c, even my atapi pass
>> through code in
>> the beginning. I didn't want to put everything in this file so I
>> moved my code
>> in atapi-pt.c but I did #include "atapi-pt.c" in ide.c so it's
>> still in the
>> spirit of what has been done before: all in ide.c. I'd like to
>> split correctly
>> this code but I will have to make some static functions public, and
>> if I move
>> atapi-pt out from ide.c why not atapi out from ide.c and maybe some
>> other
>> stuff ? That's why I did nothing yet. What would you prefer ?
>
> I guess proper splitting wouldn't hurt anyway. ide.c looks way too
> large.
I don't really know what became of the SCSI layer since I haven't
looked at it for quite some time now.
But last time I checked, we had a cdrom emulation in scsi-disk.c _and_
in ide.c.
I personally see no reason for that. Why can't we just have an atapi
emulation layer in ide.c and use whatever scsi backends we have? That
way, we'd only need to implement cd-rom and scsi passthrough once and
have it available either via SCSI or via ATAPI.
Theoretically it should even be possible to do scsi-disk or scsi-tape
over ATAPI ;-).
I'd really love to see all this cleaned up a bit, but having atapi
passthrough is probably better than nothing already.
Alex
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Qemu-devel] [PATCH] ATAPI pass through
2009-06-30 17:55 ` Bique Alexandre
@ 2009-07-01 8:43 ` Christoph Hellwig
0 siblings, 0 replies; 10+ messages in thread
From: Christoph Hellwig @ 2009-07-01 8:43 UTC (permalink / raw)
To: Bique Alexandre; +Cc: Christoph Hellwig, qemu-devel@nongnu.org
On Tue, Jun 30, 2009 at 06:55:42PM +0100, Bique Alexandre wrote:
> I can switch to aio_ioctl, and use CDROM_SEND_PACKET ioctl.
CDROM_SEND_PACKET has a rather horrible API and should be avoided.
Just use SG_IO like the the scsi passthrough code. In fact there might
be some quite a few ways to unify that code if you're motivated.
> Is it possible to send multiple requests at the same time with aio_ioctl ?
SG_IO sends one requests per ioctl, but you can have multiple requests
outstanding on a single file descriptor.
> When CONFIG_AIO is not available ?
aio_ioctl needs CONFIG_AIO - but on Linux hosts where you have
bsd/sg/etc it always is available.
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Qemu-devel] [PATCH] ATAPI pass through
2009-07-01 6:57 ` Alexander Graf
@ 2009-07-01 8:44 ` Christoph Hellwig
2009-07-01 9:36 ` Paul Brook
1 sibling, 0 replies; 10+ messages in thread
From: Christoph Hellwig @ 2009-07-01 8:44 UTC (permalink / raw)
To: Alexander Graf; +Cc: Kevin Wolf, qemu-devel, Bique Alexandre
On Wed, Jul 01, 2009 at 08:57:37AM +0200, Alexander Graf wrote:
> But last time I checked, we had a cdrom emulation in scsi-disk.c _and_
> in ide.c.
>
> I personally see no reason for that. Why can't we just have an atapi
> emulation layer in ide.c and use whatever scsi backends we have? That
> way, we'd only need to implement cd-rom and scsi passthrough once and
> have it available either via SCSI or via ATAPI.
That would be best. Note that we don't implement SCSI passthrough in
scsi-disk.c but rather in scsi-generic.c. But being able to attach
both of them to ata.c using an ATAPI shim would indeed be best.
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Qemu-devel] [PATCH] ATAPI pass through
2009-07-01 6:57 ` Alexander Graf
2009-07-01 8:44 ` Christoph Hellwig
@ 2009-07-01 9:36 ` Paul Brook
2009-07-01 11:29 ` Christoph Hellwig
1 sibling, 1 reply; 10+ messages in thread
From: Paul Brook @ 2009-07-01 9:36 UTC (permalink / raw)
To: qemu-devel; +Cc: Kevin Wolf, Alexander Graf, Bique Alexandre
> I don't really know what became of the SCSI layer since I haven't
> looked at it for quite some time now.
> But last time I checked, we had a cdrom emulation in scsi-disk.c _and_
> in ide.c.
IIRC ATAPI and SCSI are not the same. They provide very similar functionality,
however the actual commands are different.
While it is possible to connect SATA drives to a SAS HBA, I believe this is
done by tunneling IDE/ATAPI commands, rather then using native SCSI commands.
The common bits of the cdrom emulation are already broken out into cdrom.c.
USB Mass Storage can (in theory) use both ATAPI and SCSI devices. Currently we
only implement SCSI.
Paul
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Qemu-devel] [PATCH] ATAPI pass through
2009-07-01 9:36 ` Paul Brook
@ 2009-07-01 11:29 ` Christoph Hellwig
0 siblings, 0 replies; 10+ messages in thread
From: Christoph Hellwig @ 2009-07-01 11:29 UTC (permalink / raw)
To: Paul Brook; +Cc: Kevin Wolf, qemu-devel, Bique Alexandre, Alexander Graf
On Wed, Jul 01, 2009 at 10:36:01AM +0100, Paul Brook wrote:
> IIRC ATAPI and SCSI are not the same. They provide very similar functionality,
> however the actual commands are different.
ATAPI has somewhat more limited command sets, mostly because it does not
support the traditional 6 byte commands and doesn't support the scsi
block commands (SBC) used for disks. For CDROMs both traditional
parallel scsi and atap use the same command set (MMC in various
revisions)
> While it is possible to connect SATA drives to a SAS HBA, I believe this is
> done by tunneling IDE/ATAPI commands, rather then using native SCSI commands.
There are no ATAPI hard drives, just plain ATA which is not a SCSI
command set at all. For directly connected disks on a SAS HBA the HBA
speaks plain SATA to the disk (as the SAS and SATA link layers are the
same). If you connect a SATA disk to a SAS expander the expander talks
SATA to the disk and the expander encapsulates it in STP which is just a
thin layer of SAS routing information around the ATA command block,
similar to the SSP protocol used to talk to SCSI devices which is a thin
layer around SCSI command blocks.
I would expect an ATAPI cdrom attached to a SAS expander to talk MMC
command blocks over ATAPI over STP, but I haven't actually seen this
setup in practice.
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2009-07-01 11:29 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-06-30 15:34 [Qemu-devel] [PATCH] ATAPI pass through Bique Alexandre
2009-06-30 16:26 ` Kevin Wolf
2009-06-30 18:10 ` Bique Alexandre
2009-07-01 6:57 ` Alexander Graf
2009-07-01 8:44 ` Christoph Hellwig
2009-07-01 9:36 ` Paul Brook
2009-07-01 11:29 ` Christoph Hellwig
2009-06-30 17:01 ` Christoph Hellwig
2009-06-30 17:55 ` Bique Alexandre
2009-07-01 8:43 ` Christoph Hellwig
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).