From 79cf37c5b89c9e10fd77d2374b79dd5f51e95ff6 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 22 Feb 2012 14:12:18 +0100 Subject: [PATCH 062/109] scsi-generic: snoop READ CAPACITY commands to get block size RH-Author: Paolo Bonzini Message-id: <1329919979-20948-62-git-send-email-pbonzini@redhat.com> Patchwork-id: 37542 O-Subject: [RHEL 6.3 qemu-kvm PATCH v2 061/102] scsi-generic: snoop READ CAPACITY commands to get block size Bugzilla: 782029 RH-Acked-by: Laszlo Ersek RH-Acked-by: Orit Wasserman RH-Acked-by: Gerd Hoffmann Instead of "guessing" the block size when there is no medium in the drive, wait for the guest to send a READ CAPACITY command and snoop it from there. Upstream used ld*_be_p functions, which are not available to common code in RHEL6 qemu. Signed-off-by: Paolo Bonzini Signed-off-by: Kevin Wolf (cherry picked from 9b6eef8a319f11f977add658b622b60900877410) --- hw/scsi-generic.c | 68 +++++++++++++++++++++-------------------------------- 1 files changed, 27 insertions(+), 41 deletions(-) Signed-off-by: Michal Novotny --- hw/scsi-generic.c | 68 +++++++++++++++++++++-------------------------------- 1 files changed, 27 insertions(+), 41 deletions(-) diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c index 9835f38..2a3fc82 100644 --- a/hw/scsi-generic.c +++ b/hw/scsi-generic.c @@ -155,6 +155,7 @@ static int execute_command(BlockDriverState *bdrv, static void scsi_read_complete(void * opaque, int ret) { SCSIGenericReq *r = (SCSIGenericReq *)opaque; + SCSIDevice *s = r->req.dev; int len; r->req.aiocb = NULL; @@ -170,6 +171,17 @@ static void scsi_read_complete(void * opaque, int ret) if (len == 0) { scsi_command_complete(r, 0); } else { + /* Snoop READ CAPACITY output to set the blocksize. */ + if (r->req.cmd.buf[0] == READ_CAPACITY_10) { + s->blocksize = (r->buf[4] << 24) | (r->buf[5] << 16) | + (r->buf[6] << 8) | r->buf[7]; + } else if (r->req.cmd.buf[0] == SERVICE_ACTION_IN_16 && + (r->req.cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) { + s->blocksize = (r->buf[8] << 24) | (r->buf[9] << 16) | + (r->buf[10] << 8) | r->buf[11]; + } + s->conf.bs->buffer_alignment = s->blocksize; + scsi_req_data(&r->req, len); } } @@ -298,36 +310,6 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd) } } -static int get_blocksize(BlockDriverState *bdrv) -{ - uint8_t cmd[10]; - uint8_t buf[8]; - uint8_t sensebuf[8]; - sg_io_hdr_t io_header; - int ret; - - memset(cmd, 0, sizeof(cmd)); - memset(buf, 0, sizeof(buf)); - cmd[0] = READ_CAPACITY_10; - - memset(&io_header, 0, sizeof(io_header)); - io_header.interface_id = 'S'; - io_header.dxfer_direction = SG_DXFER_FROM_DEV; - io_header.dxfer_len = sizeof(buf); - io_header.dxferp = buf; - io_header.cmdp = cmd; - io_header.cmd_len = sizeof(cmd); - io_header.mx_sb_len = sizeof(sensebuf); - io_header.sbp = sensebuf; - io_header.timeout = 6000; /* XXX */ - - ret = bdrv_ioctl(bdrv, SG_IO, &io_header); - if (ret < 0 || io_header.driver_status || io_header.host_status) { - return -1; - } - return (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7]; -} - static int get_stream_blocksize(BlockDriverState *bdrv) { uint8_t cmd[6]; @@ -413,21 +395,25 @@ static int scsi_generic_initfn(SCSIDevice *s) /* define device state */ s->type = scsiid.scsi_type; DPRINTF("device type %d\n", s->type); - if (s->type == TYPE_TAPE) { + switch (s->type) { + case TYPE_TAPE: s->blocksize = get_stream_blocksize(s->conf.bs); if (s->blocksize == -1) { s->blocksize = 0; } - } else { - s->blocksize = get_blocksize(s->conf.bs); - /* removable media returns 0 if not present */ - if (s->blocksize <= 0) { - if (s->type == TYPE_ROM || s->type == TYPE_WORM) { - s->blocksize = 2048; - } else { - s->blocksize = 512; - } - } + break; + + /* Make a guess for block devices, we'll fix it when the guest sends. + * READ CAPACITY. If they don't, they likely would assume these sizes + * anyway. (TODO: they could also send MODE SENSE). + */ + case TYPE_ROM: + case TYPE_WORM: + s->blocksize = 2048; + break; + default: + s->blocksize = 512; + break; } DPRINTF("block size %d\n", s->blocksize); -- 1.7.7.6