Revision 06114d72 hw/virtio-scsi.c

b/hw/virtio-scsi.c
134 134
    VirtQueue *cmd_vq;
135 135
    uint32_t sense_size;
136 136
    uint32_t cdb_size;
137
    int resetting;
137 138
} VirtIOSCSI;
138 139

  
139 140
typedef struct VirtIOSCSIReq {
......
236 237
    return req;
237 238
}
238 239

  
239
static void virtio_scsi_fail_ctrl_req(VirtIOSCSIReq *req)
240
static void virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req)
240 241
{
241
    if (req->req.tmf->type == VIRTIO_SCSI_T_TMF) {
242
        req->resp.tmf->response = VIRTIO_SCSI_S_FAILURE;
243
    } else {
244
        req->resp.an->response = VIRTIO_SCSI_S_FAILURE;
242
    SCSIDevice *d = virtio_scsi_device_find(s, req->req.tmf->lun);
243
    SCSIRequest *r, *next;
244
    DeviceState *qdev;
245
    int target;
246

  
247
    /* Here VIRTIO_SCSI_S_OK means "FUNCTION COMPLETE".  */
248
    req->resp.tmf->response = VIRTIO_SCSI_S_OK;
249

  
250
    switch (req->req.tmf->subtype) {
251
    case VIRTIO_SCSI_T_TMF_ABORT_TASK:
252
    case VIRTIO_SCSI_T_TMF_QUERY_TASK:
253
        if (!d) {
254
            goto fail;
255
        }
256
        if (d->lun != virtio_scsi_get_lun(req->req.tmf->lun)) {
257
            goto incorrect_lun;
258
        }
259
        QTAILQ_FOREACH_SAFE(r, &d->requests, next, next) {
260
            if (r->tag == req->req.tmf->tag) {
261
                break;
262
            }
263
        }
264
        if (r && r->hba_private) {
265
            if (req->req.tmf->subtype == VIRTIO_SCSI_T_TMF_QUERY_TASK) {
266
                /* "If the specified command is present in the task set, then
267
                 * return a service response set to FUNCTION SUCCEEDED".
268
                 */
269
                req->resp.tmf->response = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED;
270
            } else {
271
                scsi_req_cancel(r);
272
            }
273
        }
274
        break;
275

  
276
    case VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET:
277
        if (!d) {
278
            goto fail;
279
        }
280
        if (d->lun != virtio_scsi_get_lun(req->req.tmf->lun)) {
281
            goto incorrect_lun;
282
        }
283
        s->resetting++;
284
        qdev_reset_all(&d->qdev);
285
        s->resetting--;
286
        break;
287

  
288
    case VIRTIO_SCSI_T_TMF_ABORT_TASK_SET:
289
    case VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET:
290
    case VIRTIO_SCSI_T_TMF_QUERY_TASK_SET:
291
        if (!d) {
292
            goto fail;
293
        }
294
        if (d->lun != virtio_scsi_get_lun(req->req.tmf->lun)) {
295
            goto incorrect_lun;
296
        }
297
        QTAILQ_FOREACH_SAFE(r, &d->requests, next, next) {
298
            if (r->hba_private) {
299
                if (req->req.tmf->subtype == VIRTIO_SCSI_T_TMF_QUERY_TASK_SET) {
300
                    /* "If there is any command present in the task set, then
301
                     * return a service response set to FUNCTION SUCCEEDED".
302
                     */
303
                    req->resp.tmf->response = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED;
304
                    break;
305
                } else {
306
                    scsi_req_cancel(r);
307
                }
308
            }
309
        }
310
        break;
311

  
312
    case VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET:
313
        target = req->req.tmf->lun[1];
314
        s->resetting++;
315
        QTAILQ_FOREACH(qdev, &s->bus.qbus.children, sibling) {
316
             d = DO_UPCAST(SCSIDevice, qdev, qdev);
317
             if (d->channel == 0 && d->id == target) {
318
                qdev_reset_all(&d->qdev);
319
             }
320
        }
321
        s->resetting--;
322
        break;
323

  
324
    case VIRTIO_SCSI_T_TMF_CLEAR_ACA:
325
    default:
326
        req->resp.tmf->response = VIRTIO_SCSI_S_FUNCTION_REJECTED;
327
        break;
245 328
    }
246 329

  
247
    virtio_scsi_complete_req(req);
330
    return;
331

  
332
incorrect_lun:
333
    req->resp.tmf->response = VIRTIO_SCSI_S_INCORRECT_LUN;
334
    return;
335

  
336
fail:
337
    req->resp.tmf->response = VIRTIO_SCSI_S_BAD_TARGET;
248 338
}
249 339

  
250 340
static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
......
253 343
    VirtIOSCSIReq *req;
254 344

  
255 345
    while ((req = virtio_scsi_pop_req(s, vq))) {
256
        virtio_scsi_fail_ctrl_req(req);
346
        int out_size, in_size;
347
        if (req->elem.out_num < 1 || req->elem.in_num < 1) {
348
            virtio_scsi_bad_req();
349
            continue;
350
        }
351

  
352
        out_size = req->elem.out_sg[0].iov_len;
353
        in_size = req->elem.in_sg[0].iov_len;
354
        if (req->req.tmf->type == VIRTIO_SCSI_T_TMF) {
355
            if (out_size < sizeof(VirtIOSCSICtrlTMFReq) ||
356
                in_size < sizeof(VirtIOSCSICtrlTMFResp)) {
357
                virtio_scsi_bad_req();
358
            }
359
            virtio_scsi_do_tmf(s, req);
360

  
361
        } else if (req->req.tmf->type == VIRTIO_SCSI_T_AN_QUERY ||
362
                   req->req.tmf->type == VIRTIO_SCSI_T_AN_SUBSCRIBE) {
363
            if (out_size < sizeof(VirtIOSCSICtrlANReq) ||
364
                in_size < sizeof(VirtIOSCSICtrlANResp)) {
365
                virtio_scsi_bad_req();
366
            }
367
            req->resp.an->event_actual = 0;
368
            req->resp.an->response = VIRTIO_SCSI_S_OK;
369
        }
370
        virtio_scsi_complete_req(req);
257 371
    }
258 372
}
259 373

  
......
288 402
    if (!req) {
289 403
        return;
290 404
    }
291
    req->resp.cmd->response = VIRTIO_SCSI_S_ABORTED;
405
    if (req->dev->resetting) {
406
        req->resp.cmd->response = VIRTIO_SCSI_S_RESET;
407
    } else {
408
        req->resp.cmd->response = VIRTIO_SCSI_S_ABORTED;
409
    }
292 410
    virtio_scsi_complete_req(req);
293 411
}
294 412

  

Also available in: Unified diff