[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH 1/4] scsi-disk: Implement rerror option
From: |
Kevin Wolf |
Subject: |
Re: [Qemu-devel] [PATCH 1/4] scsi-disk: Implement rerror option |
Date: |
Thu, 28 Oct 2010 11:29:05 +0200 |
User-agent: |
Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.12) Gecko/20100907 Fedora/3.0.7-1.fc12 Thunderbird/3.0.7 |
Am 28.10.2010 11:12, schrieb Stefan Hajnoczi:
> On Mon, Oct 25, 2010 at 05:17:33PM +0200, Kevin Wolf wrote:
>> This implements the rerror option for SCSI disks.
>>
>> Signed-off-by: Kevin Wolf <address@hidden>
>> ---
>> blockdev.c | 2 +-
>> hw/scsi-disk.c | 91
>> ++++++++++++++++++++++++++++++++++++++------------------
>> 2 files changed, 63 insertions(+), 30 deletions(-)
>>
>> diff --git a/blockdev.c b/blockdev.c
>> index ff7602b..160fa84 100644
>> --- a/blockdev.c
>> +++ b/blockdev.c
>> @@ -326,7 +326,7 @@ DriveInfo *drive_init(QemuOpts *opts, int
>> default_to_scsi, int *fatal_error)
>>
>> on_read_error = BLOCK_ERR_REPORT;
>> if ((buf = qemu_opt_get(opts, "rerror")) != NULL) {
>> - if (type != IF_IDE && type != IF_VIRTIO && type != IF_NONE) {
>> + if (type != IF_IDE && type != IF_VIRTIO && type != IF_SCSI && type
>> != IF_NONE) {
>> fprintf(stderr, "rerror is no supported by this format\n");
>
> This is a good opportunity to fix the "is *no* supported" typo in the error
> message.
>> return NULL;
>> }
>> diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
>> index 9628b39..55ba558 100644
>> --- a/hw/scsi-disk.c
>> +++ b/hw/scsi-disk.c
>> @@ -41,7 +41,10 @@ do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__);
>> } while (0)
>> #define SCSI_DMA_BUF_SIZE 131072
>> #define SCSI_MAX_INQUIRY_LEN 256
>>
>> -#define SCSI_REQ_STATUS_RETRY 0x01
>> +#define SCSI_REQ_STATUS_RETRY 0x01
>> +#define SCSI_REQ_STATUS_RETRY_TYPE_MASK 0x06
>> +#define SCSI_REQ_STATUS_RETRY_READ 0x00
>> +#define SCSI_REQ_STATUS_RETRY_WRITE 0x02
>>
>> typedef struct SCSIDiskState SCSIDiskState;
>>
>> @@ -70,6 +73,8 @@ struct SCSIDiskState
>> char *serial;
>> };
>>
>> +static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type);
>> +
>> static SCSIDiskReq *scsi_new_request(SCSIDiskState *s, uint32_t tag,
>> uint32_t lun)
>> {
>> @@ -127,34 +132,30 @@ static void scsi_cancel_io(SCSIDevice *d, uint32_t tag)
>> static void scsi_read_complete(void * opaque, int ret)
>> {
>> SCSIDiskReq *r = (SCSIDiskReq *)opaque;
>> + int n;
>>
>> r->req.aiocb = NULL;
>>
>> if (ret) {
>> - DPRINTF("IO error\n");
>> - r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, 0);
>> - scsi_command_complete(r, CHECK_CONDITION, NO_SENSE);
>> - return;
>> + if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_READ)) {
>> + return;
>> + }
>> }
>> +
>> DPRINTF("Data ready tag=0x%x len=%zd\n", r->req.tag, r->iov.iov_len);
>>
>> + n = r->iov.iov_len / 512;
>> + r->sector += n;
>> + r->sector_count -= n;
>> r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag,
>> r->iov.iov_len);
>> }
>>
>> -/* Read more data from scsi device into buffer. */
>> -static void scsi_read_data(SCSIDevice *d, uint32_t tag)
>> +
>> +static void scsi_read_request(SCSIDiskReq *r)
>> {
>> - SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
>> - SCSIDiskReq *r;
>> + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
>> uint32_t n;
>>
>> - r = scsi_find_request(s, tag);
>> - if (!r) {
>> - BADF("Bad read tag 0x%x\n", tag);
>> - /* ??? This is the wrong error. */
>> - scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR);
>> - return;
>> - }
>> if (r->sector_count == (uint32_t)-1) {
>> DPRINTF("Read buf_len=%zd\n", r->iov.iov_len);
>> r->sector_count = 0;
>> @@ -177,14 +178,34 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag)
>> scsi_read_complete, r);
>> if (r->req.aiocb == NULL)
>> scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR);
>> - r->sector += n;
>> - r->sector_count -= n;
>> }
>>
>> -static int scsi_handle_write_error(SCSIDiskReq *r, int error)
>> +/* Read more data from scsi device into buffer. */
>> +static void scsi_read_data(SCSIDevice *d, uint32_t tag)
>> {
>> + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
>> + SCSIDiskReq *r;
>> +
>> + r = scsi_find_request(s, tag);
>> + if (!r) {
>> + BADF("Bad read tag 0x%x\n", tag);
>> + /* ??? This is the wrong error. */
>> + scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR);
>> + return;
>> + }
>> +
>> + if (r->req.aiocb) {
>> + BADF("Data transfer already in progress\n");
>> + }
>
> Can this be triggered from the guest? If yes, then we need to (optionally)
> cancel the request with an error and then return. If no, then this should be
> an assert.
Honestly, I don't know for sure. It's just the same as what we're doing
in scsi_write_disk.
But after a look at the callers, I think an assert should work.
>> +
>> + scsi_read_request(r);
>> +}
>> +
>> +static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type)
>> +{
>> + int is_read = (type == SCSI_REQ_STATUS_RETRY_READ);
>> SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
>> - BlockErrorAction action = bdrv_get_on_error(s->bs, 0);
>> + BlockErrorAction action = bdrv_get_on_error(s->bs, is_read);
>>
>> if (action == BLOCK_ERR_IGNORE) {
>> bdrv_mon_event(s->bs, BDRV_ACTION_IGNORE, 0);
>> @@ -193,10 +214,16 @@ static int scsi_handle_write_error(SCSIDiskReq *r, int
>> error)
>>
>> if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC)
>> || action == BLOCK_ERR_STOP_ANY) {
>> - r->status |= SCSI_REQ_STATUS_RETRY;
>> +
>> + type &= SCSI_REQ_STATUS_RETRY_TYPE_MASK;
>> + r->status |= SCSI_REQ_STATUS_RETRY | type;
>> +
>> bdrv_mon_event(s->bs, BDRV_ACTION_STOP, 0);
>> vm_stop(0);
>> } else {
>> + if (type == SCSI_REQ_STATUS_RETRY_READ) {
>> + r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag,
>> 0);
>> + }
>> scsi_command_complete(r, CHECK_CONDITION,
>> HARDWARE_ERROR);
>> bdrv_mon_event(s->bs, BDRV_ACTION_REPORT, 0);
>
> We don't report whether this was a read or a write here?
Whoops, good catch.
Kevin