aboutsummaryrefslogtreecommitdiff
path: root/hw/scsi-disk.c
diff options
context:
space:
mode:
authorbalrog <balrog@c046a42c-6fe2-441c-8c8c-71466251a162>2008-02-03 04:05:50 +0000
committerbalrog <balrog@c046a42c-6fe2-441c-8c8c-71466251a162>2008-02-03 04:05:50 +0000
commit1d4db89c09264463ec8d388e84b665f90763b29d (patch)
tree861523c971dc2f63508391df443fa0600310d1ca /hw/scsi-disk.c
parentb5a23ad40c38ab6f5d496c1b0fbd92c460e36efa (diff)
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
Diffstat (limited to 'hw/scsi-disk.c')
-rw-r--r--hw/scsi-disk.c129
1 files changed, 125 insertions, 4 deletions
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index b3e1ed71b0..44462d4351 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -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) {