aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorpbrook <pbrook@c046a42c-6fe2-441c-8c8c-71466251a162>2006-05-26 16:46:55 +0000
committerpbrook <pbrook@c046a42c-6fe2-441c-8c8c-71466251a162>2006-05-26 16:46:55 +0000
commit7c22dd5216a7c1ff941e37bc30a6ade6e1370ca1 (patch)
tree8b70aa6c8b4cfe311bf7297748ec15131218be68 /hw
parent0aff66b5c8bbe89cb61df75e0511af2c1802a593 (diff)
Fix scsi sector size confusion (Blue Swirl).
Fix short TOC read. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1942 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'hw')
-rw-r--r--hw/scsi-disk.c79
1 files changed, 41 insertions, 38 deletions
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 937eb94ec2..d6c7aa6f66 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -31,10 +31,13 @@ struct SCSIDevice
int command;
uint32_t tag;
BlockDriverState *bdrv;
- int sector_size;
+ /* The qemu block layer uses a fixed 512 byte sector size.
+ This is the number of 512 byte blocks in a single scsi sector. */
+ int cluster_size;
/* When transfering data buf_pos and buf_len contain a partially
transferred block of data (or response to a command), and
- sector/sector_count identify any remaining sectors. */
+ sector/sector_count identify any remaining sectors.
+ Both sector and sector_count are in terms of qemu 512 byte blocks. */
/* ??? We should probably keep track of whether the data trasfer is
a read or a write. Currently we rely on the host getting it right. */
int sector;
@@ -42,7 +45,7 @@ struct SCSIDevice
int buf_pos;
int buf_len;
int sense;
- char buf[2048];
+ char buf[512];
scsi_completionfn completion;
void *opaque;
};
@@ -75,24 +78,24 @@ int scsi_read_data(SCSIDevice *s, uint8_t *data, uint32_t len)
s->buf_pos = 0;
}
- n = len / s->sector_size;
+ n = len / 512;
if (n > s->sector_count)
n = s->sector_count;
if (n != 0) {
bdrv_read(s->bdrv, s->sector, data, n);
- data += n * s->sector_size;
- len -= n * s->sector_size;
+ data += n * 512;
+ len -= n * 512;
s->sector += n;
s->sector_count -= n;
}
if (len && s->sector_count) {
- bdrv_read(s->bdrv, s->sector, s->buf, 1);
+ bdrv_read(s->bdrv, s->sector, s->buf, 512);
s->sector++;
s->sector_count--;
s->buf_pos = 0;
- s->buf_len = s->sector_size;
+ s->buf_len = 512;
/* Recurse to complete the partial read. */
return scsi_read_data(s, data, len);
}
@@ -120,8 +123,8 @@ int scsi_write_data(SCSIDevice *s, uint8_t *data, uint32_t len)
if (s->sector_count == 0)
return 1;
- if (s->buf_len != 0 || len < s->sector_size) {
- n = s->sector_size - s->buf_len;
+ if (s->buf_len != 0 || len < 512) {
+ n = 512 - s->buf_len;
if (n > len)
n = len;
@@ -129,7 +132,7 @@ int scsi_write_data(SCSIDevice *s, uint8_t *data, uint32_t len)
data += n;
s->buf_len += n;
len -= n;
- if (s->buf_len == s->sector_size) {
+ if (s->buf_len == 512) {
/* A full sector has been accumulated. Write it to disk. */
bdrv_write(s->bdrv, s->sector, s->buf, 1);
s->buf_len = 0;
@@ -138,19 +141,19 @@ int scsi_write_data(SCSIDevice *s, uint8_t *data, uint32_t len)
}
}
- n = len / s->sector_size;
+ n = len / 512;
if (n > s->sector_count)
n = s->sector_count;
if (n != 0) {
bdrv_write(s->bdrv, s->sector, data, n);
- data += n * s->sector_size;
- len -= n * s->sector_size;
+ data += n * 512;
+ len -= n * 512;
s->sector += n;
s->sector_count -= n;
}
- if (len >= s->sector_size)
+ if (len >= 512)
return 1;
if (len && s->sector_count) {
@@ -296,26 +299,26 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf)
s->buf[3] = nb_sectors & 0xff;
s->buf[4] = 0;
s->buf[5] = 0;
- s->buf[6] = s->sector_size >> 8;
- s->buf[7] = s->sector_size & 0xff;
+ s->buf[6] = s->cluster_size * 2;
+ s->buf[7] = 0;
s->buf_len = 8;
break;
case 0x08:
case 0x28:
DPRINTF("Read (sector %d, count %d)\n", lba, len);
- s->sector = lba;
- s->sector_count = len;
+ s->sector = lba * s->cluster_size;
+ s->sector_count = len * s->cluster_size;
break;
case 0x0a:
case 0x2a:
DPRINTF("Write (sector %d, count %d)\n", lba, len);
- s->sector = lba;
- s->sector_count = len;
+ s->sector = lba * s->cluster_size;
+ s->sector_count = len * s->cluster_size;
is_write = 1;
break;
case 0x43:
{
- int start_track, format, msf;
+ int start_track, format, msf, toclen;
msf = buf[1] & 2;
format = buf[2] & 0xf;
@@ -324,31 +327,31 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf)
DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1);
switch(format) {
case 0:
- len = cdrom_read_toc(nb_sectors, s->buf, msf, start_track);
- if (len < 0)
- goto error_cmd;
- s->buf_len = len;
+ toclen = cdrom_read_toc(nb_sectors, s->buf, msf, start_track);
break;
case 1:
/* multi session : only a single session defined */
+ toclen = 12;
memset(s->buf, 0, 12);
s->buf[1] = 0x0a;
s->buf[2] = 0x01;
s->buf[3] = 0x01;
- s->buf_len = 12;
break;
case 2:
- len = cdrom_read_toc_raw(nb_sectors, s->buf, msf, start_track);
- if (len < 0)
- goto error_cmd;
- s->buf_len = len;
+ toclen = cdrom_read_toc_raw(nb_sectors, s->buf, msf, start_track);
break;
default:
- error_cmd:
- DPRINTF("Read TOC error\n");
- goto fail;
+ goto error_cmd;
+ }
+ if (toclen > 0) {
+ if (len > toclen)
+ len = toclen;
+ s->buf_len = len;
+ break;
}
- break;
+ error_cmd:
+ DPRINTF("Read TOC error\n");
+ goto fail;
}
case 0x56:
DPRINTF("Reserve(10)\n");
@@ -377,7 +380,7 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf)
if (s->sector_count == 0 && s->buf_len == 0) {
scsi_command_complete(s, SENSE_NO_SENSE);
}
- len = s->sector_count * s->sector_size + s->buf_len;
+ len = s->sector_count * 512 + s->buf_len;
return is_write ? -len : len;
}
@@ -398,9 +401,9 @@ SCSIDevice *scsi_disk_init(BlockDriverState *bdrv,
s->completion = completion;
s->opaque = opaque;
if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) {
- s->sector_size = 2048;
+ s->cluster_size = 4;
} else {
- s->sector_size = 512;
+ s->cluster_size = 1;
}
return s;