CD burning commands do strange things including writing beyond the maximum LBA and even to negative blocks for the lead-in.
WRITE(6), WRITE(16), WRITE AND VERIFY(16) are not in MMC. WRITE AND VERIFY(12) is not in MMC but it seemed a good idea to treat it like WRITE(12). Also detect blanking of a disc and reset the maximum LBA. It's possible that more special casing is necessary, e.g. for track-at-once, since those do not start with blanking. Signed-off-by: Paolo Bonzini <pbonz...@redhat.com> --- hw/scsi-disk.c | 18 +++++++++++++----- hw/scsi-generic.c | 5 +++++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 19e846c..f18a9e6 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -1755,17 +1755,25 @@ static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag, SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); switch (buf[0]) { - case READ_6: - case READ_10: - case READ_12: - case READ_16: - case WRITE_6: case WRITE_10: case WRITE_12: + case WRITE_VERIFY_10: + case WRITE_VERIFY_12: + /* Detect if writing the lead-in of a CD, which is represented by + * negative LBA addresses. If so, just pass through. Also, + * when burning the maximum LBA is zero. Play it safe and pass + * those writes through as well. */ + if (s->qdev.type == TYPE_ROM && (s->qdev.max_lba == 0 || buf[2] > 0x7F)) { + break; + } + + case WRITE_6: case WRITE_16: - case WRITE_VERIFY_10: - case WRITE_VERIFY_12: case WRITE_VERIFY_16: + case READ_6: + case READ_10: + case READ_12: + case READ_16: return scsi_req_alloc(&scsi_disk_reqops, &s->qdev, tag, lun, hba_private); } diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c index a86e5a8..fb34a33 100644 --- a/hw/scsi-generic.c +++ b/hw/scsi-generic.c @@ -236,6 +236,11 @@ static void scsi_read_complete(void * opaque, int ret) } bdrv_set_buffer_alignment(s->conf.bs, s->blocksize); + /* ... and BLANK to update the maximum LBA. */ + if (s->type == TYPE_ROM && r->req.cmd.buf[0] == BLANK) { + s->max_lba = 0; + } + scsi_req_data(&r->req, len); if (!r->req.io_canceled) { scsi_req_unref(&r->req); -- 1.7.7.1