Commit 89c0f6438d16ebceccdcd096bbc0b5536146a443

Authored by aurel32
1 parent e65bdffa

scsi-generic: correct error management

this patch allows to fully use a tape device connected to qemu through
the scsi-generic interface.

Previous patch introduced tape SCSI commands management, this one
improve error case management:

- the SCSI controller command completion must be called with the status
value, not the sense value. In the case of scsi-generic, the SCSI status
is given by the field status of sg_io_hdr_t (the value is left shifted
by one regarding status codes defined in /usr/include/scsi/scsi.h)

- when a read is aborted due to a mark/EOF/EOD/EOM, the len reported to
controller can be 0. LSI controller emulation doesn't know how to manage
this. A workaround found is to call the completion routine with
SCSI_REASON_DONE just after calling it with SCSI_REASON_DATA with len=0.

This patch also manages correctly the block size of the tape device.

This patch has been tested with a real tape device "HP C5683A", linux
guest (debian etch) and tools like "mt", "tar" and "btape".

Windows guest is not better supported than before...

Signed-off-by: Laurent Vivier <Laurent.Vivier@bull.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5497 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 103 additions and 29 deletions
hw/scsi-generic.c
@@ -84,6 +84,7 @@ struct SCSIDeviceState @@ -84,6 +84,7 @@ struct SCSIDeviceState
84 void *opaque; 84 void *opaque;
85 int driver_status; 85 int driver_status;
86 uint8_t sensebuf[SCSI_SENSE_BUF_SIZE]; 86 uint8_t sensebuf[SCSI_SENSE_BUF_SIZE];
  87 + uint8_t senselen;
87 }; 88 };
88 89
89 /* Global pool of SCSIRequest structures. */ 90 /* Global pool of SCSIRequest structures. */
@@ -154,25 +155,30 @@ static void scsi_command_complete(void *opaque, int ret) @@ -154,25 +155,30 @@ static void scsi_command_complete(void *opaque, int ret)
154 SCSIRequest *r = (SCSIRequest *)opaque; 155 SCSIRequest *r = (SCSIRequest *)opaque;
155 SCSIDeviceState *s = r->dev; 156 SCSIDeviceState *s = r->dev;
156 uint32_t tag; 157 uint32_t tag;
157 - int sense; 158 + int status;
158 159
159 s->driver_status = r->io_header.driver_status; 160 s->driver_status = r->io_header.driver_status;
  161 + if (s->driver_status & SG_ERR_DRIVER_SENSE)
  162 + s->senselen = r->io_header.sb_len_wr;
  163 +
160 if (ret != 0) 164 if (ret != 0)
161 - sense = HARDWARE_ERROR; 165 + status = BUSY << 1;
162 else { 166 else {
163 if (s->driver_status & SG_ERR_DRIVER_TIMEOUT) { 167 if (s->driver_status & SG_ERR_DRIVER_TIMEOUT) {
164 - sense = HARDWARE_ERROR; 168 + status = BUSY << 1;
165 BADF("Driver Timeout\n"); 169 BADF("Driver Timeout\n");
166 - } else if ((s->driver_status & SG_ERR_DRIVER_SENSE) == 0)  
167 - sense = NO_SENSE; 170 + } else if (r->io_header.status)
  171 + status = r->io_header.status;
  172 + else if (s->driver_status & SG_ERR_DRIVER_SENSE)
  173 + status = CHECK_CONDITION << 1;
168 else 174 else
169 - sense = s->sensebuf[2]; 175 + status = GOOD << 1;
170 } 176 }
171 -  
172 - DPRINTF("Command complete 0x%p tag=0x%x sense=%d\n", r, r->tag, sense); 177 + DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
  178 + r, r->tag, status);
173 tag = r->tag; 179 tag = r->tag;
174 scsi_remove_request(r); 180 scsi_remove_request(r);
175 - s->completion(s->opaque, SCSI_REASON_DONE, tag, sense); 181 + s->completion(s->opaque, SCSI_REASON_DONE, tag, status);
176 } 182 }
177 183
178 /* Cancel a pending data transfer. */ 184 /* Cancel a pending data transfer. */
@@ -251,6 +257,8 @@ static void scsi_read_complete(void * opaque, int ret) @@ -251,6 +257,8 @@ static void scsi_read_complete(void * opaque, int ret)
251 257
252 r->len = -1; 258 r->len = -1;
253 s->completion(s->opaque, SCSI_REASON_DATA, r->tag, len); 259 s->completion(s->opaque, SCSI_REASON_DATA, r->tag, len);
  260 + if (len == 0)
  261 + scsi_command_complete(r, 0);
254 } 262 }
255 263
256 /* Read more data from scsi device into buffer. */ 264 /* Read more data from scsi device into buffer. */
@@ -276,14 +284,17 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag) @@ -276,14 +284,17 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag)
276 284
277 if (r->cmd[0] == REQUEST_SENSE && s->driver_status & SG_ERR_DRIVER_SENSE) 285 if (r->cmd[0] == REQUEST_SENSE && s->driver_status & SG_ERR_DRIVER_SENSE)
278 { 286 {
279 - int len = MIN(r->len, SCSI_SENSE_BUF_SIZE);  
280 - memcpy(r->buf, s->sensebuf, len); 287 + s->senselen = MIN(r->len, s->senselen);
  288 + memcpy(r->buf, s->sensebuf, s->senselen);
281 r->io_header.driver_status = 0; 289 r->io_header.driver_status = 0;
  290 + r->io_header.status = 0;
  291 + r->io_header.dxfer_len = s->senselen;
282 r->len = -1; 292 r->len = -1;
  293 + DPRINTF("Data ready tag=0x%x len=%d\n", r->tag, s->senselen);
283 DPRINTF("Sense: %d %d %d %d %d %d %d %d\n", 294 DPRINTF("Sense: %d %d %d %d %d %d %d %d\n",
284 r->buf[0], r->buf[1], r->buf[2], r->buf[3], 295 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]); 296 r->buf[4], r->buf[5], r->buf[6], r->buf[7]);
286 - s->completion(s->opaque, SCSI_REASON_DATA, r->tag, len); 297 + s->completion(s->opaque, SCSI_REASON_DATA, r->tag, s->senselen);
287 return; 298 return;
288 } 299 }
289 300
@@ -305,6 +316,12 @@ static void scsi_write_complete(void * opaque, int ret) @@ -305,6 +316,12 @@ static void scsi_write_complete(void * opaque, int ret)
305 return; 316 return;
306 } 317 }
307 318
  319 + if (r->cmd[0] == MODE_SELECT && r->cmd[4] == 12 &&
  320 + r->dev->type == TYPE_TAPE) {
  321 + r->dev->blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
  322 + DPRINTF("block size %d\n", r->dev->blocksize);
  323 + }
  324 +
308 scsi_command_complete(r, ret); 325 scsi_command_complete(r, ret);
309 } 326 }
310 327
@@ -437,6 +454,9 @@ static int scsi_length(uint8_t *cmd, int blocksize, int *cmdlen, uint32_t *len) @@ -437,6 +454,9 @@ static int scsi_length(uint8_t *cmd, int blocksize, int *cmdlen, uint32_t *len)
437 case READ_12: 454 case READ_12:
438 *len *= blocksize; 455 *len *= blocksize;
439 break; 456 break;
  457 + case INQUIRY:
  458 + *len = cmd[4] | (cmd[3] << 8);
  459 + break;
440 } 460 }
441 return 0; 461 return 0;
442 } 462 }
@@ -519,15 +539,6 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, @@ -519,15 +539,6 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
519 SCSIRequest *r; 539 SCSIRequest *r;
520 int ret; 540 int ret;
521 541
522 - /* ??? Tags are not unique for different luns. We only implement a  
523 - single lun, so this should not matter. */  
524 -  
525 - if (lun != s->lun || (cmd[1] >> 5) != s->lun) {  
526 - DPRINTF("Unimplemented LUN %d\n", lun ? lun : cmd[1] >> 5);  
527 - s->completion(s->opaque, SCSI_REASON_DONE, tag, ILLEGAL_REQUEST);  
528 - return 0;  
529 - }  
530 -  
531 if (s->type == TYPE_TAPE) { 542 if (s->type == TYPE_TAPE) {
532 if (scsi_stream_length(cmd, s->blocksize, &cmdlen, &len) == -1) { 543 if (scsi_stream_length(cmd, s->blocksize, &cmdlen, &len) == -1) {
533 BADF("Unsupported command length, command %x\n", cmd[0]); 544 BADF("Unsupported command length, command %x\n", cmd[0]);
@@ -543,6 +554,23 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, @@ -543,6 +554,23 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
543 DPRINTF("Command: lun=%d tag=0x%x data=0x%02x len %d\n", lun, tag, 554 DPRINTF("Command: lun=%d tag=0x%x data=0x%02x len %d\n", lun, tag,
544 cmd[0], len); 555 cmd[0], len);
545 556
  557 + if (cmd[0] != REQUEST_SENSE &&
  558 + (lun != s->lun || (cmd[1] >> 5) != s->lun)) {
  559 + DPRINTF("Unimplemented LUN %d\n", lun ? lun : cmd[1] >> 5);
  560 +
  561 + s->sensebuf[0] = 0x70;
  562 + s->sensebuf[1] = 0x00;
  563 + s->sensebuf[2] = ILLEGAL_REQUEST;
  564 + s->sensebuf[3] = 0x00;
  565 + s->sensebuf[4] = 0x00;
  566 + s->sensebuf[5] = 0x00;
  567 + s->sensebuf[6] = 0x00;
  568 + s->senselen = 7;
  569 + s->driver_status = SG_ERR_DRIVER_SENSE;
  570 + s->completion(s->opaque, SCSI_REASON_DONE, tag, CHECK_CONDITION << 1);
  571 + return 0;
  572 + }
  573 +
546 r = scsi_find_request(s, tag); 574 r = scsi_find_request(s, tag);
547 if (r) { 575 if (r) {
548 BADF("Tag 0x%x already in use %p\n", tag, r); 576 BADF("Tag 0x%x already in use %p\n", tag, r);
@@ -619,6 +647,43 @@ static int get_blocksize(BlockDriverState *bdrv) @@ -619,6 +647,43 @@ static int get_blocksize(BlockDriverState *bdrv)
619 return (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7]; 647 return (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
620 } 648 }
621 649
  650 +static int get_stream_blocksize(BlockDriverState *bdrv)
  651 +{
  652 + uint8_t cmd[6];
  653 + uint8_t buf[12];
  654 + uint8_t sensebuf[8];
  655 + sg_io_hdr_t io_header;
  656 + int ret;
  657 +
  658 + memset(cmd, 0, sizeof(cmd));
  659 + memset(buf, 0, sizeof(buf));
  660 + cmd[0] = MODE_SENSE;
  661 + cmd[4] = sizeof(buf);
  662 +
  663 + memset(&io_header, 0, sizeof(io_header));
  664 + io_header.interface_id = 'S';
  665 + io_header.dxfer_direction = SG_DXFER_FROM_DEV;
  666 + io_header.dxfer_len = sizeof(buf);
  667 + io_header.dxferp = buf;
  668 + io_header.cmdp = cmd;
  669 + io_header.cmd_len = sizeof(cmd);
  670 + io_header.mx_sb_len = sizeof(sensebuf);
  671 + io_header.sbp = sensebuf;
  672 + io_header.timeout = 6000; /* XXX */
  673 +
  674 + ret = bdrv_pwrite(bdrv, -1, &io_header, sizeof(io_header));
  675 + if (ret == -1)
  676 + return -1;
  677 +
  678 + while ((ret = bdrv_pread(bdrv, -1, &io_header, sizeof(io_header))) == -1 &&
  679 + errno == EINTR);
  680 +
  681 + if (ret == -1)
  682 + return -1;
  683 +
  684 + return (buf[9] << 16) | (buf[10] << 8) | buf[11];
  685 +}
  686 +
622 static void scsi_destroy(SCSIDevice *d) 687 static void scsi_destroy(SCSIDevice *d)
623 { 688 {
624 SCSIRequest *r, *n; 689 SCSIRequest *r, *n;
@@ -673,17 +738,26 @@ SCSIDevice *scsi_generic_init(BlockDriverState *bdrv, int tcq, @@ -673,17 +738,26 @@ SCSIDevice *scsi_generic_init(BlockDriverState *bdrv, int tcq,
673 s->completion = completion; 738 s->completion = completion;
674 s->opaque = opaque; 739 s->opaque = opaque;
675 s->lun = scsiid.lun; 740 s->lun = scsiid.lun;
  741 + DPRINTF("LUN %d\n", s->lun);
676 s->type = scsiid.scsi_type; 742 s->type = scsiid.scsi_type;
677 - s->blocksize = get_blocksize(s->bdrv); 743 + DPRINTF("device type %d\n", s->type);
  744 + if (s->type == TYPE_TAPE) {
  745 + s->blocksize = get_stream_blocksize(s->bdrv);
  746 + if (s->blocksize == -1)
  747 + s->blocksize = 0;
  748 + } else {
  749 + s->blocksize = get_blocksize(s->bdrv);
  750 + /* removable media returns 0 if not present */
  751 + if (s->blocksize <= 0) {
  752 + if (s->type == TYPE_ROM || s->type == TYPE_WORM)
  753 + s->blocksize = 2048;
  754 + else
  755 + s->blocksize = 512;
  756 + }
  757 + }
  758 + DPRINTF("block size %d\n", s->blocksize);
678 s->driver_status = 0; 759 s->driver_status = 0;
679 memset(s->sensebuf, 0, sizeof(s->sensebuf)); 760 memset(s->sensebuf, 0, sizeof(s->sensebuf));
680 - /* removable media returns 0 if not present */  
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 - }  
687 761
688 /* define function to manage device */ 762 /* define function to manage device */
689 763