summaryrefslogtreecommitdiff
path: root/hw/scsi/scsi-disk.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/scsi/scsi-disk.c')
-rw-r--r--hw/scsi/scsi-disk.c25
1 files changed, 18 insertions, 7 deletions
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index f5cdb9ad4b..efee6739f9 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -1591,7 +1591,7 @@ static void scsi_disk_emulate_mode_select(SCSIDiskReq *r, uint8_t *inbuf)
int cmd = r->req.cmd.buf[0];
int len = r->req.cmd.xfer;
int hdr_len = (cmd == MODE_SELECT ? 4 : 8);
- int bd_len;
+ int bd_len, bs;
int pass;
if ((r->req.cmd.buf[1] & 0x11) != 0x10) {
@@ -1617,9 +1617,19 @@ static void scsi_disk_emulate_mode_select(SCSIDiskReq *r, uint8_t *inbuf)
}
/* Allow changing the block size */
- if (bd_len && p[6] != (s->qdev.blocksize >> 8)) {
- s->qdev.blocksize = p[6] << 8;
- trace_scsi_disk_mode_select_set_blocksize(s->qdev.blocksize);
+ if (bd_len) {
+ bs = p[5] << 16 | p[6] << 8 | p[7];
+
+ /*
+ * Since the existing code only checks/updates bits 8-15 of the block
+ * size, restrict ourselves to the same requirement for now to ensure
+ * that a block size set by a block descriptor and then read back by
+ * a subsequent SCSI command will be the same
+ */
+ if (bs && !(bs & ~0xff00) && bs != s->qdev.blocksize) {
+ s->qdev.blocksize = bs;
+ trace_scsi_disk_mode_select_set_blocksize(s->qdev.blocksize);
+ }
}
len -= bd_len;
@@ -1849,7 +1859,7 @@ static void scsi_disk_emulate_write_same(SCSIDiskReq *r, uint8_t *inbuf)
uint32_t nb_sectors = scsi_data_cdb_xfer(r->req.cmd.buf);
WriteSameCBData *data;
uint8_t *buf;
- int i;
+ int i, l;
/* Fail if PBDATA=1 or LBDATA=1 or ANCHOR=1. */
if (nb_sectors == 0 || (req->cmd.buf[1] & 0x16)) {
@@ -1891,8 +1901,9 @@ static void scsi_disk_emulate_write_same(SCSIDiskReq *r, uint8_t *inbuf)
data->iov.iov_len);
qemu_iovec_init_external(&data->qiov, &data->iov, 1);
- for (i = 0; i < data->iov.iov_len; i += s->qdev.blocksize) {
- memcpy(&buf[i], inbuf, s->qdev.blocksize);
+ for (i = 0; i < data->iov.iov_len; i += l) {
+ l = MIN(s->qdev.blocksize, data->iov.iov_len - i);
+ memcpy(&buf[i], inbuf, l);
}
scsi_req_ref(&r->req);