Revision 5dba48a8

b/blockdev.c
314 314
    on_write_error = BLOCK_ERR_STOP_ENOSPC;
315 315
    if ((buf = qemu_opt_get(opts, "werror")) != NULL) {
316 316
        if (type != IF_IDE && type != IF_SCSI && type != IF_VIRTIO && type != IF_NONE) {
317
            fprintf(stderr, "werror is no supported by this format\n");
317
            fprintf(stderr, "werror is not supported by this format\n");
318 318
            return NULL;
319 319
        }
320 320

  
......
326 326

  
327 327
    on_read_error = BLOCK_ERR_REPORT;
328 328
    if ((buf = qemu_opt_get(opts, "rerror")) != NULL) {
329
        if (type != IF_IDE && type != IF_VIRTIO && type != IF_NONE) {
330
            fprintf(stderr, "rerror is no supported by this format\n");
329
        if (type != IF_IDE && type != IF_VIRTIO && type != IF_SCSI && type != IF_NONE) {
330
            fprintf(stderr, "rerror is not supported by this format\n");
331 331
            return NULL;
332 332
        }
333 333

  
b/hw/scsi-disk.c
41 41
#define SCSI_DMA_BUF_SIZE    131072
42 42
#define SCSI_MAX_INQUIRY_LEN 256
43 43

  
44
#define SCSI_REQ_STATUS_RETRY 0x01
44
#define SCSI_REQ_STATUS_RETRY           0x01
45
#define SCSI_REQ_STATUS_RETRY_TYPE_MASK 0x06
46
#define SCSI_REQ_STATUS_RETRY_READ      0x00
47
#define SCSI_REQ_STATUS_RETRY_WRITE     0x02
45 48

  
46 49
typedef struct SCSIDiskState SCSIDiskState;
47 50

  
......
70 73
    char *serial;
71 74
};
72 75

  
76
static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type);
77

  
73 78
static SCSIDiskReq *scsi_new_request(SCSIDiskState *s, uint32_t tag,
74 79
        uint32_t lun)
75 80
{
......
127 132
static void scsi_read_complete(void * opaque, int ret)
128 133
{
129 134
    SCSIDiskReq *r = (SCSIDiskReq *)opaque;
135
    int n;
130 136

  
131 137
    r->req.aiocb = NULL;
132 138

  
133 139
    if (ret) {
134
        DPRINTF("IO error\n");
135
        r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, 0);
136
        scsi_command_complete(r, CHECK_CONDITION, NO_SENSE);
137
        return;
140
        if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_READ)) {
141
            return;
142
        }
138 143
    }
144

  
139 145
    DPRINTF("Data ready tag=0x%x len=%zd\n", r->req.tag, r->iov.iov_len);
140 146

  
147
    n = r->iov.iov_len / 512;
148
    r->sector += n;
149
    r->sector_count -= n;
141 150
    r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, r->iov.iov_len);
142 151
}
143 152

  
144
/* Read more data from scsi device into buffer.  */
145
static void scsi_read_data(SCSIDevice *d, uint32_t tag)
153

  
154
static void scsi_read_request(SCSIDiskReq *r)
146 155
{
147
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
148
    SCSIDiskReq *r;
156
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
149 157
    uint32_t n;
150 158

  
151
    r = scsi_find_request(s, tag);
152
    if (!r) {
153
        BADF("Bad read tag 0x%x\n", tag);
154
        /* ??? This is the wrong error.  */
155
        scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR);
156
        return;
157
    }
158 159
    if (r->sector_count == (uint32_t)-1) {
159 160
        DPRINTF("Read buf_len=%zd\n", r->iov.iov_len);
160 161
        r->sector_count = 0;
......
177 178
                              scsi_read_complete, r);
178 179
    if (r->req.aiocb == NULL)
179 180
        scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR);
180
    r->sector += n;
181
    r->sector_count -= n;
182 181
}
183 182

  
184
static int scsi_handle_write_error(SCSIDiskReq *r, int error)
183
/* Read more data from scsi device into buffer.  */
184
static void scsi_read_data(SCSIDevice *d, uint32_t tag)
185 185
{
186
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
187
    SCSIDiskReq *r;
188

  
189
    r = scsi_find_request(s, tag);
190
    if (!r) {
191
        BADF("Bad read tag 0x%x\n", tag);
192
        /* ??? This is the wrong error.  */
193
        scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR);
194
        return;
195
    }
196

  
197
    /* No data transfer may already be in progress */
198
    assert(r->req.aiocb == NULL);
199

  
200
    scsi_read_request(r);
201
}
202

  
203
static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type)
204
{
205
    int is_read = (type == SCSI_REQ_STATUS_RETRY_READ);
186 206
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
187
    BlockErrorAction action = bdrv_get_on_error(s->bs, 0);
207
    BlockErrorAction action = bdrv_get_on_error(s->bs, is_read);
188 208

  
189 209
    if (action == BLOCK_ERR_IGNORE) {
190
        bdrv_mon_event(s->bs, BDRV_ACTION_IGNORE, 0);
210
        bdrv_mon_event(s->bs, BDRV_ACTION_IGNORE, is_read);
191 211
        return 0;
192 212
    }
193 213

  
194 214
    if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC)
195 215
            || action == BLOCK_ERR_STOP_ANY) {
196
        r->status |= SCSI_REQ_STATUS_RETRY;
197
        bdrv_mon_event(s->bs, BDRV_ACTION_STOP, 0);
216

  
217
        type &= SCSI_REQ_STATUS_RETRY_TYPE_MASK;
218
        r->status |= SCSI_REQ_STATUS_RETRY | type;
219

  
220
        bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read);
198 221
        vm_stop(0);
199 222
    } else {
223
        if (type == SCSI_REQ_STATUS_RETRY_READ) {
224
            r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, 0);
225
        }
200 226
        scsi_command_complete(r, CHECK_CONDITION,
201 227
                HARDWARE_ERROR);
202
        bdrv_mon_event(s->bs, BDRV_ACTION_REPORT, 0);
228
        bdrv_mon_event(s->bs, BDRV_ACTION_REPORT, is_read);
203 229
    }
204 230

  
205 231
    return 1;
......
214 240
    r->req.aiocb = NULL;
215 241

  
216 242
    if (ret) {
217
        if (scsi_handle_write_error(r, -ret))
243
        if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_WRITE)) {
218 244
            return;
245
        }
219 246
    }
220 247

  
221 248
    n = r->iov.iov_len / 512;
......
268 295
        return 1;
269 296
    }
270 297

  
271
    if (r->req.aiocb)
272
        BADF("Data transfer already in progress\n");
298
    /* No data transfer may already be in progress */
299
    assert(r->req.aiocb == NULL);
273 300

  
274 301
    scsi_write_request(r);
275 302

  
......
288 315
    QTAILQ_FOREACH(req, &s->qdev.requests, next) {
289 316
        r = DO_UPCAST(SCSIDiskReq, req, req);
290 317
        if (r->status & SCSI_REQ_STATUS_RETRY) {
291
            r->status &= ~SCSI_REQ_STATUS_RETRY;
292
            scsi_write_request(r); 
318
            int status = r->status;
319
            r->status &=
320
                ~(SCSI_REQ_STATUS_RETRY | SCSI_REQ_STATUS_RETRY_TYPE_MASK);
321

  
322
            switch (status & SCSI_REQ_STATUS_RETRY_TYPE_MASK) {
323
            case SCSI_REQ_STATUS_RETRY_READ:
324
                scsi_read_request(r);
325
                break;
326
            case SCSI_REQ_STATUS_RETRY_WRITE:
327
                scsi_write_request(r);
328
                break;
329
            }
293 330
        }
294 331
    }
295 332
}
......
1152 1189
        return -1;
1153 1190
    }
1154 1191

  
1155
    if (bdrv_get_on_error(s->bs, 1) != BLOCK_ERR_REPORT) {
1156
        error_report("Device doesn't support drive option rerror");
1157
        return -1;
1158
    }
1159

  
1160 1192
    if (!s->serial) {
1161 1193
        /* try to fall back to value set with legacy -drive serial=... */
1162 1194
        dinfo = drive_get_by_blockdev(s->bs);

Also available in: Unified diff