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 44 #include <scsi/sg.h>
45 45 #include <scsi/scsi.h>
46 46  
  47 +#define REWIND 0x01
  48 +#define REPORT_DENSITY_SUPPORT 0x44
47 49 #define LOAD_UNLOAD 0xa6
48 50 #define SET_CD_SPEED 0xbb
49 51 #define BLANK 0xa1
50 52  
51 53 #define SCSI_CMD_BUF_SIZE 16
52   -#define SCSI_SENSE_BUF_SIZE 32
  54 +#define SCSI_SENSE_BUF_SIZE 96
53 55  
54 56 #define SG_ERR_DRIVER_TIMEOUT 0x06
55 57 #define SG_ERR_DRIVER_SENSE 0x08
... ... @@ -75,6 +77,7 @@ struct SCSIDeviceState
75 77 {
76 78 SCSIRequest *requests;
77 79 BlockDriverState *bdrv;
  80 + int type;
78 81 int blocksize;
79 82 int lun;
80 83 scsi_completionfn completion;
... ... @@ -163,7 +166,7 @@ static void scsi_command_complete(void *opaque, int ret)
163 166 } else if ((s->driver_status & SG_ERR_DRIVER_SENSE) == 0)
164 167 sense = NO_SENSE;
165 168 else
166   - sense = s->sensebuf[2] & 0x0f;
  169 + sense = s->sensebuf[2];
167 170 }
168 171  
169 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 276  
274 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 281 r->io_header.driver_status = 0;
278 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 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 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 470 static int is_write(int command)
438 471 {
439 472 switch (command) {
... ... @@ -495,9 +528,16 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
495 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 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 673 s->completion = completion;
634 674 s->opaque = opaque;
635 675 s->lun = scsiid.lun;
  676 + s->type = scsiid.scsi_type;
636 677 s->blocksize = get_blocksize(s->bdrv);
637 678 s->driver_status = 0;
638 679 memset(s->sensebuf, 0, sizeof(s->sensebuf));
639 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 688 /* define function to manage device */
644 689  
... ...