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
This commit is contained in:
pbrook 2006-05-26 16:46:55 +00:00
parent 0aff66b5c8
commit 7c22dd5216

View File

@ -31,10 +31,13 @@ struct SCSIDevice
int command; int command;
uint32_t tag; uint32_t tag;
BlockDriverState *bdrv; 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 /* When transfering data buf_pos and buf_len contain a partially
transferred block of data (or response to a command), and 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 /* ??? 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. */ a read or a write. Currently we rely on the host getting it right. */
int sector; int sector;
@ -42,7 +45,7 @@ struct SCSIDevice
int buf_pos; int buf_pos;
int buf_len; int buf_len;
int sense; int sense;
char buf[2048]; char buf[512];
scsi_completionfn completion; scsi_completionfn completion;
void *opaque; void *opaque;
}; };
@ -75,24 +78,24 @@ int scsi_read_data(SCSIDevice *s, uint8_t *data, uint32_t len)
s->buf_pos = 0; s->buf_pos = 0;
} }
n = len / s->sector_size; n = len / 512;
if (n > s->sector_count) if (n > s->sector_count)
n = s->sector_count; n = s->sector_count;
if (n != 0) { if (n != 0) {
bdrv_read(s->bdrv, s->sector, data, n); bdrv_read(s->bdrv, s->sector, data, n);
data += n * s->sector_size; data += n * 512;
len -= n * s->sector_size; len -= n * 512;
s->sector += n; s->sector += n;
s->sector_count -= n; s->sector_count -= n;
} }
if (len && s->sector_count) { 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++;
s->sector_count--; s->sector_count--;
s->buf_pos = 0; s->buf_pos = 0;
s->buf_len = s->sector_size; s->buf_len = 512;
/* Recurse to complete the partial read. */ /* Recurse to complete the partial read. */
return scsi_read_data(s, data, len); 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) if (s->sector_count == 0)
return 1; return 1;
if (s->buf_len != 0 || len < s->sector_size) { if (s->buf_len != 0 || len < 512) {
n = s->sector_size - s->buf_len; n = 512 - s->buf_len;
if (n > len) if (n > len)
n = len; n = len;
@ -129,7 +132,7 @@ int scsi_write_data(SCSIDevice *s, uint8_t *data, uint32_t len)
data += n; data += n;
s->buf_len += n; s->buf_len += n;
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. */ /* A full sector has been accumulated. Write it to disk. */
bdrv_write(s->bdrv, s->sector, s->buf, 1); bdrv_write(s->bdrv, s->sector, s->buf, 1);
s->buf_len = 0; 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) if (n > s->sector_count)
n = s->sector_count; n = s->sector_count;
if (n != 0) { if (n != 0) {
bdrv_write(s->bdrv, s->sector, data, n); bdrv_write(s->bdrv, s->sector, data, n);
data += n * s->sector_size; data += n * 512;
len -= n * s->sector_size; len -= n * 512;
s->sector += n; s->sector += n;
s->sector_count -= n; s->sector_count -= n;
} }
if (len >= s->sector_size) if (len >= 512)
return 1; return 1;
if (len && s->sector_count) { 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[3] = nb_sectors & 0xff;
s->buf[4] = 0; s->buf[4] = 0;
s->buf[5] = 0; s->buf[5] = 0;
s->buf[6] = s->sector_size >> 8; s->buf[6] = s->cluster_size * 2;
s->buf[7] = s->sector_size & 0xff; s->buf[7] = 0;
s->buf_len = 8; s->buf_len = 8;
break; break;
case 0x08: case 0x08:
case 0x28: case 0x28:
DPRINTF("Read (sector %d, count %d)\n", lba, len); DPRINTF("Read (sector %d, count %d)\n", lba, len);
s->sector = lba; s->sector = lba * s->cluster_size;
s->sector_count = len; s->sector_count = len * s->cluster_size;
break; break;
case 0x0a: case 0x0a:
case 0x2a: case 0x2a:
DPRINTF("Write (sector %d, count %d)\n", lba, len); DPRINTF("Write (sector %d, count %d)\n", lba, len);
s->sector = lba; s->sector = lba * s->cluster_size;
s->sector_count = len; s->sector_count = len * s->cluster_size;
is_write = 1; is_write = 1;
break; break;
case 0x43: case 0x43:
{ {
int start_track, format, msf; int start_track, format, msf, toclen;
msf = buf[1] & 2; msf = buf[1] & 2;
format = buf[2] & 0xf; 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); DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1);
switch(format) { switch(format) {
case 0: case 0:
len = cdrom_read_toc(nb_sectors, s->buf, msf, start_track); toclen = cdrom_read_toc(nb_sectors, s->buf, msf, start_track);
if (len < 0)
goto error_cmd;
s->buf_len = len;
break; break;
case 1: case 1:
/* multi session : only a single session defined */ /* multi session : only a single session defined */
toclen = 12;
memset(s->buf, 0, 12); memset(s->buf, 0, 12);
s->buf[1] = 0x0a; s->buf[1] = 0x0a;
s->buf[2] = 0x01; s->buf[2] = 0x01;
s->buf[3] = 0x01; s->buf[3] = 0x01;
s->buf_len = 12;
break; break;
case 2: case 2:
len = cdrom_read_toc_raw(nb_sectors, s->buf, msf, start_track); toclen = cdrom_read_toc_raw(nb_sectors, s->buf, msf, start_track);
if (len < 0)
goto error_cmd;
s->buf_len = len;
break; break;
default: default:
error_cmd: goto error_cmd;
DPRINTF("Read TOC error\n");
goto fail;
} }
break; if (toclen > 0) {
if (len > toclen)
len = toclen;
s->buf_len = len;
break;
}
error_cmd:
DPRINTF("Read TOC error\n");
goto fail;
} }
case 0x56: case 0x56:
DPRINTF("Reserve(10)\n"); 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) { if (s->sector_count == 0 && s->buf_len == 0) {
scsi_command_complete(s, SENSE_NO_SENSE); 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; return is_write ? -len : len;
} }
@ -398,9 +401,9 @@ SCSIDevice *scsi_disk_init(BlockDriverState *bdrv,
s->completion = completion; s->completion = completion;
s->opaque = opaque; s->opaque = opaque;
if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) {
s->sector_size = 2048; s->cluster_size = 4;
} else { } else {
s->sector_size = 512; s->cluster_size = 1;
} }
return s; return s;