Implement more INQUIRY command replies for scsi disk (Igor Kovalenko).

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3955 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
balrog 2008-02-03 04:05:50 +00:00
parent b5a23ad40c
commit 1d4db89c09
1 changed files with 125 additions and 4 deletions

View File

@ -9,8 +9,8 @@
* This code is licenced under the LGPL.
*
* Note that this file only handles the SCSI architecture model and device
* commands. Emultion of interface/link layer protocols is handled by
* the host adapter emulation.
* commands. Emulation of interface/link layer protocols is handled by
* the host adapter emulator.
*/
//#define DEBUG_SCSI
@ -362,8 +362,129 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
break;
case 0x12:
DPRINTF("Inquiry (len %d)\n", len);
if (len < 36) {
BADF("Inquiry buffer too small (%d)\n", len);
if (buf[1] & 0x2) {
/* Command support data - optional, not implemented */
BADF("optional INQUIRY command support request not implemented\n");
goto fail;
}
else if (buf[1] & 0x1) {
/* Vital product data */
uint8_t page_code = buf[2];
if (len < 4) {
BADF("Error: Inquiry (EVPD[%02X]) buffer size %d is "
"less than 4\n", page_code, len);
goto fail;
}
switch (page_code) {
case 0x00:
{
/* Supported page codes, mandatory */
DPRINTF("Inquiry EVPD[Supported pages] "
"buffer size %d\n", len);
r->buf_len = 0;
if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) {
outbuf[r->buf_len++] = 5;
} else {
outbuf[r->buf_len++] = 0;
}
outbuf[r->buf_len++] = 0x00; // this page
outbuf[r->buf_len++] = 0x00;
outbuf[r->buf_len++] = 3; // number of pages
outbuf[r->buf_len++] = 0x00; // list of supported pages (this page)
outbuf[r->buf_len++] = 0x80; // unit serial number
outbuf[r->buf_len++] = 0x83; // device identification
}
break;
case 0x80:
{
/* Device serial number, optional */
if (len < 4) {
BADF("Error: EVPD[Serial number] Inquiry buffer "
"size %d too small, %d needed\n", len, 4);
goto fail;
}
DPRINTF("Inquiry EVPD[Serial number] buffer size %d\n", len);
r->buf_len = 0;
/* Supported page codes */
if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) {
outbuf[r->buf_len++] = 5;
} else {
outbuf[r->buf_len++] = 0;
}
outbuf[r->buf_len++] = 0x80; // this page
outbuf[r->buf_len++] = 0x00;
outbuf[r->buf_len++] = 0x01; // 1 byte data follow
outbuf[r->buf_len++] = '0'; // 1 byte data follow
}
break;
case 0x83:
{
/* Device identification page, mandatory */
int max_len = 255 - 8;
int id_len = strlen(bdrv_get_device_name(s->bdrv));
if (id_len > max_len)
id_len = max_len;
DPRINTF("Inquiry EVPD[Device identification] "
"buffer size %d\n", len);
r->buf_len = 0;
if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) {
outbuf[r->buf_len++] = 5;
} else {
outbuf[r->buf_len++] = 0;
}
outbuf[r->buf_len++] = 0x83; // this page
outbuf[r->buf_len++] = 0x00;
outbuf[r->buf_len++] = 3 + id_len;
outbuf[r->buf_len++] = 0x2; // ASCII
outbuf[r->buf_len++] = 0; // not officially assigned
outbuf[r->buf_len++] = 0; // reserved
outbuf[r->buf_len++] = id_len; // length of data following
memcpy(&outbuf[r->buf_len],
bdrv_get_device_name(s->bdrv), id_len);
r->buf_len += id_len;
}
break;
default:
BADF("Error: unsupported Inquiry (EVPD[%02X]) "
"buffer size %d\n", page_code, len);
goto fail;
}
/* done with EVPD */
break;
}
else {
/* Standard INQUIRY data */
if (buf[2] != 0) {
BADF("Error: Inquiry (STANDARD) page or code "
"is non-zero [%02X]\n", buf[2]);
goto fail;
}
/* PAGE CODE == 0 */
if (len < 5) {
BADF("Error: Inquiry (STANDARD) buffer size %d "
"is less than 5\n", len);
goto fail;
}
if (len < 36) {
BADF("Error: Inquiry (STANDARD) buffer size %d "
"is less than 36 (TODO: only 5 required)\n", len);
}
}
memset(outbuf, 0, 36);
if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) {