Commit a9dd6843be390ec94a4e51cbaa50c43b7cb0357a

Authored by aliguori
1 parent 82889986

scsi-generic: decode correctly SCSI tape commands (Laurent Vivier)

This patch allows to use a "real" SCSI tape with qemu using
"-drive /dev/sgX,if=scsi".

It allows to decode correctly transfer length when the type of the
device is a tape.

Some issues remain when the application reading the tape tries to go
beyond the end of the stream (but they must be corrected at the SCSI
controller level).

Signed-off-by: Laurent Vivier <Laurent.Vivier@bull.net>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>



git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5305 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 54 additions and 9 deletions
hw/scsi-generic.c
@@ -44,12 +44,14 @@ do { fprintf(stderr, &quot;scsi-generic: &quot; fmt , ##args); } while (0) @@ -44,12 +44,14 @@ do { fprintf(stderr, &quot;scsi-generic: &quot; fmt , ##args); } while (0)
44 #include <scsi/sg.h> 44 #include <scsi/sg.h>
45 #include <scsi/scsi.h> 45 #include <scsi/scsi.h>
46 46
  47 +#define REWIND 0x01
  48 +#define REPORT_DENSITY_SUPPORT 0x44
47 #define LOAD_UNLOAD 0xa6 49 #define LOAD_UNLOAD 0xa6
48 #define SET_CD_SPEED 0xbb 50 #define SET_CD_SPEED 0xbb
49 #define BLANK 0xa1 51 #define BLANK 0xa1
50 52
51 #define SCSI_CMD_BUF_SIZE 16 53 #define SCSI_CMD_BUF_SIZE 16
52 -#define SCSI_SENSE_BUF_SIZE 32 54 +#define SCSI_SENSE_BUF_SIZE 96
53 55
54 #define SG_ERR_DRIVER_TIMEOUT 0x06 56 #define SG_ERR_DRIVER_TIMEOUT 0x06
55 #define SG_ERR_DRIVER_SENSE 0x08 57 #define SG_ERR_DRIVER_SENSE 0x08
@@ -75,6 +77,7 @@ struct SCSIDeviceState @@ -75,6 +77,7 @@ struct SCSIDeviceState
75 { 77 {
76 SCSIRequest *requests; 78 SCSIRequest *requests;
77 BlockDriverState *bdrv; 79 BlockDriverState *bdrv;
  80 + int type;
78 int blocksize; 81 int blocksize;
79 int lun; 82 int lun;
80 scsi_completionfn completion; 83 scsi_completionfn completion;
@@ -163,7 +166,7 @@ static void scsi_command_complete(void *opaque, int ret) @@ -163,7 +166,7 @@ static void scsi_command_complete(void *opaque, int ret)
163 } else if ((s->driver_status & SG_ERR_DRIVER_SENSE) == 0) 166 } else if ((s->driver_status & SG_ERR_DRIVER_SENSE) == 0)
164 sense = NO_SENSE; 167 sense = NO_SENSE;
165 else 168 else
166 - sense = s->sensebuf[2] & 0x0f; 169 + sense = s->sensebuf[2];
167 } 170 }
168 171
169 DPRINTF("Command complete 0x%p tag=0x%x sense=%d\n", r, r->tag, sense); 172 DPRINTF("Command complete 0x%p tag=0x%x sense=%d\n", r, r->tag, sense);
@@ -273,10 +276,14 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag) @@ -273,10 +276,14 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag)
273 276
274 if (r->cmd[0] == REQUEST_SENSE && s->driver_status & SG_ERR_DRIVER_SENSE) 277 if (r->cmd[0] == REQUEST_SENSE && s->driver_status & SG_ERR_DRIVER_SENSE)
275 { 278 {
276 - memcpy(r->buf, s->sensebuf, 16); 279 + int len = MIN(r->len, SCSI_SENSE_BUF_SIZE);
  280 + memcpy(r->buf, s->sensebuf, len);
277 r->io_header.driver_status = 0; 281 r->io_header.driver_status = 0;
278 r->len = -1; 282 r->len = -1;
279 - s->completion(s->opaque, SCSI_REASON_DATA, r->tag, 16); 283 + DPRINTF("Sense: %d %d %d %d %d %d %d %d\n",
  284 + r->buf[0], r->buf[1], r->buf[2], r->buf[3],
  285 + r->buf[4], r->buf[5], r->buf[6], r->buf[7]);
  286 + s->completion(s->opaque, SCSI_REASON_DATA, r->tag, len);
280 return; 287 return;
281 } 288 }
282 289
@@ -434,6 +441,32 @@ static int scsi_length(uint8_t *cmd, int blocksize, int *cmdlen, uint32_t *len) @@ -434,6 +441,32 @@ static int scsi_length(uint8_t *cmd, int blocksize, int *cmdlen, uint32_t *len)
434 return 0; 441 return 0;
435 } 442 }
436 443
  444 +static int scsi_stream_length(uint8_t *cmd, int blocksize, int *cmdlen, uint32_t *len)
  445 +{
  446 + switch(cmd[0]) {
  447 + /* stream commands */
  448 + case READ_6:
  449 + case READ_REVERSE:
  450 + case RECOVER_BUFFERED_DATA:
  451 + case WRITE_6:
  452 + *cmdlen = 6;
  453 + *len = cmd[4] | (cmd[3] << 8) | (cmd[2] << 16);
  454 + if (cmd[1] & 0x01) /* fixed */
  455 + *len *= blocksize;
  456 + break;
  457 + case REWIND:
  458 + case START_STOP:
  459 + *cmdlen = 6;
  460 + *len = 0;
  461 + cmd[1] = 0x01; /* force IMMED, otherwise qemu waits end of command */
  462 + break;
  463 + /* generic commands */
  464 + default:
  465 + return scsi_length(cmd, blocksize, cmdlen, len);
  466 + }
  467 + return 0;
  468 +}
  469 +
437 static int is_write(int command) 470 static int is_write(int command)
438 { 471 {
439 switch (command) { 472 switch (command) {
@@ -495,9 +528,16 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, @@ -495,9 +528,16 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
495 return 0; 528 return 0;
496 } 529 }
497 530
498 - if (scsi_length(cmd, s->blocksize, &cmdlen, &len) == -1) {  
499 - BADF("Unsupported command length, command %x\n", cmd[0]);  
500 - return 0; 531 + if (s->type == TYPE_TAPE) {
  532 + if (scsi_stream_length(cmd, s->blocksize, &cmdlen, &len) == -1) {
  533 + BADF("Unsupported command length, command %x\n", cmd[0]);
  534 + return 0;
  535 + }
  536 + } else {
  537 + if (scsi_length(cmd, s->blocksize, &cmdlen, &len) == -1) {
  538 + BADF("Unsupported command length, command %x\n", cmd[0]);
  539 + return 0;
  540 + }
501 } 541 }
502 542
503 DPRINTF("Command: lun=%d tag=0x%x data=0x%02x len %d\n", lun, tag, 543 DPRINTF("Command: lun=%d tag=0x%x data=0x%02x len %d\n", lun, tag,
@@ -633,12 +673,17 @@ SCSIDevice *scsi_generic_init(BlockDriverState *bdrv, int tcq, @@ -633,12 +673,17 @@ SCSIDevice *scsi_generic_init(BlockDriverState *bdrv, int tcq,
633 s->completion = completion; 673 s->completion = completion;
634 s->opaque = opaque; 674 s->opaque = opaque;
635 s->lun = scsiid.lun; 675 s->lun = scsiid.lun;
  676 + s->type = scsiid.scsi_type;
636 s->blocksize = get_blocksize(s->bdrv); 677 s->blocksize = get_blocksize(s->bdrv);
637 s->driver_status = 0; 678 s->driver_status = 0;
638 memset(s->sensebuf, 0, sizeof(s->sensebuf)); 679 memset(s->sensebuf, 0, sizeof(s->sensebuf));
639 /* removable media returns 0 if not present */ 680 /* removable media returns 0 if not present */
640 - if (s->blocksize <= 0)  
641 - s->blocksize = 2048; 681 + if (s->blocksize <= 0) {
  682 + if (s->type == TYPE_ROM || s->type == TYPE_WORM)
  683 + s->blocksize = 2048;
  684 + else
  685 + s->blocksize = 512;
  686 + }
642 687
643 /* define function to manage device */ 688 /* define function to manage device */
644 689