mirror of
https://git.proxmox.com/git/qemu
synced 2025-07-25 16:37:12 +00:00
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:
parent
0aff66b5c8
commit
7c22dd5216
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user