blob: 34a968ecfb5b45d5b2f09aef052197aceab4728e [file] [log] [blame]
Stefan Hajnoczi973abc72011-02-11 08:40:59 +00001/*
2 * Virtio SCSI HBA
3 *
4 * Copyright IBM, Corp. 2010
5 * Copyright Red Hat, Inc. 2011
6 *
7 * Authors:
8 * Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
9 * Paolo Bonzini <pbonzini@redhat.com>
10 *
11 * This work is licensed under the terms of the GNU GPL, version 2 or later.
12 * See the COPYING file in the top-level directory.
13 *
14 */
15
Peter Maydell9b8bfe22016-01-26 18:17:07 +000016#include "qemu/osdep.h"
Markus Armbrusterda34e652016-03-14 09:01:28 +010017#include "qapi/error.h"
Michael S. Tsirkin019adbd2015-02-16 22:36:20 +010018#include "standard-headers/linux/virtio_ids.h"
Paolo Bonzini0d09e412013-02-05 17:06:20 +010019#include "hw/virtio/virtio-scsi.h"
Markus Armbrusterca77ee22019-08-12 07:23:39 +020020#include "migration/qemu-file-types.h"
Paolo Bonzinib4a42f82013-02-04 11:37:52 +010021#include "qemu/error-report.h"
Paolo Bonzini36b15c72014-06-10 16:21:18 +020022#include "qemu/iov.h"
Markus Armbruster0b8fa322019-05-23 16:35:07 +020023#include "qemu/module.h"
Markus Armbruster4be74632014-10-07 13:59:18 +020024#include "sysemu/block-backend.h"
Markus Armbrustera27bd6c2019-08-12 07:23:51 +020025#include "hw/qdev-properties.h"
Markus Armbrustera9c94272016-06-22 19:11:19 +020026#include "hw/scsi/scsi.h"
Paolo Bonzini08e2c9f2017-08-22 09:23:55 +020027#include "scsi/constants.h"
Markus Armbrustera9c94272016-06-22 19:11:19 +020028#include "hw/virtio/virtio-bus.h"
Rusty Russell8c085db2014-06-24 19:48:53 +020029#include "hw/virtio/virtio-access.h"
Hannes Reineckeeb8cb3d2020-11-16 19:31:12 +010030#include "trace.h"
Stefan Hajnoczi973abc72011-02-11 08:40:59 +000031
Paolo Bonzini2ccdcd82011-11-14 16:58:41 +010032static inline int virtio_scsi_get_lun(uint8_t *lun)
33{
34 return ((lun[2] << 8) | lun[3]) & 0x3FFF;
35}
36
Maxim Levitsky07a47d42020-10-06 15:39:03 +030037static inline SCSIDevice *virtio_scsi_device_get(VirtIOSCSI *s, uint8_t *lun)
Paolo Bonzini2ccdcd82011-11-14 16:58:41 +010038{
39 if (lun[0] != 1) {
40 return NULL;
41 }
42 if (lun[2] != 0 && !(lun[2] >= 0x40 && lun[2] < 0x80)) {
43 return NULL;
44 }
Maxim Levitsky07a47d42020-10-06 15:39:03 +030045 return scsi_device_get(&s->bus, 0, lun[1], virtio_scsi_get_lun(lun));
Paolo Bonzini2ccdcd82011-11-14 16:58:41 +010046}
47
Paolo Bonzini51b19eb2016-02-04 16:26:51 +020048void virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq, VirtIOSCSIReq *req)
Paolo Bonzini36b15c72014-06-10 16:21:18 +020049{
Jason Wang025bdea2017-07-04 20:21:06 +080050 VirtIODevice *vdev = VIRTIO_DEVICE(s);
Paolo Bonzinie24a47c2016-02-14 18:17:10 +010051 const size_t zero_skip =
52 offsetof(VirtIOSCSIReq, resp_iov) + sizeof(req->resp_iov);
Paolo Bonzini3eff1f42014-06-10 16:40:31 +020053
Paolo Bonzini36b15c72014-06-10 16:21:18 +020054 req->vq = vq;
55 req->dev = s;
Jason Wang025bdea2017-07-04 20:21:06 +080056 qemu_sglist_init(&req->qsgl, DEVICE(s), 8, vdev->dma_as);
Paolo Bonzini3eff1f42014-06-10 16:40:31 +020057 qemu_iovec_init(&req->resp_iov, 1);
Fam Zhengfaf1e1f2014-09-16 15:20:18 +080058 memset((uint8_t *)req + zero_skip, 0, sizeof(*req) - zero_skip);
Paolo Bonzini36b15c72014-06-10 16:21:18 +020059}
60
Fam Zhengaa8e8f82014-08-06 13:35:04 +080061void virtio_scsi_free_req(VirtIOSCSIReq *req)
Paolo Bonzini36b15c72014-06-10 16:21:18 +020062{
Paolo Bonzini3eff1f42014-06-10 16:40:31 +020063 qemu_iovec_destroy(&req->resp_iov);
Paolo Bonzini36b15c72014-06-10 16:21:18 +020064 qemu_sglist_destroy(&req->qsgl);
Paolo Bonzini633dccb2015-10-01 12:59:01 +020065 g_free(req);
Paolo Bonzini36b15c72014-06-10 16:21:18 +020066}
67
Stefan Hajnoczi326799c2011-02-13 10:55:52 +000068static void virtio_scsi_complete_req(VirtIOSCSIReq *req)
69{
70 VirtIOSCSI *s = req->dev;
71 VirtQueue *vq = req->vq;
KONRAD Frederic0ac8e132013-03-21 15:15:18 +010072 VirtIODevice *vdev = VIRTIO_DEVICE(s);
Paolo Bonzini3eff1f42014-06-10 16:40:31 +020073
74 qemu_iovec_from_buf(&req->resp_iov, 0, &req->resp, req->resp_size);
Paolo Bonzinie24a47c2016-02-14 18:17:10 +010075 virtqueue_push(vq, &req->elem, req->qsgl.size + req->resp_iov.size);
Paolo Bonzini43c696a2016-04-06 12:16:24 +020076 if (s->dataplane_started && !s->dataplane_fenced) {
Paolo Bonzini83d768b2016-11-18 16:07:02 +010077 virtio_notify_irqfd(vdev, vq);
Fam Zheng63c7e542014-09-23 15:49:25 +080078 } else {
Fam Zheng63c7e542014-09-23 15:49:25 +080079 virtio_notify(vdev, vq);
80 }
81
Stefan Hajnoczi326799c2011-02-13 10:55:52 +000082 if (req->sreq) {
83 req->sreq->hba_private = NULL;
84 scsi_req_unref(req->sreq);
85 }
Paolo Bonzini36b15c72014-06-10 16:21:18 +020086 virtio_scsi_free_req(req);
Stefan Hajnoczi326799c2011-02-13 10:55:52 +000087}
88
Greg Kurz661e32f2016-09-30 17:13:40 +020089static void virtio_scsi_bad_req(VirtIOSCSIReq *req)
Stefan Hajnoczi326799c2011-02-13 10:55:52 +000090{
Greg Kurz661e32f2016-09-30 17:13:40 +020091 virtio_error(VIRTIO_DEVICE(req->dev), "wrong size for virtio-scsi headers");
92 virtqueue_detach_element(req->vq, &req->elem, 0);
93 virtio_scsi_free_req(req);
Stefan Hajnoczi326799c2011-02-13 10:55:52 +000094}
95
Paolo Bonzini57fbae62014-06-10 16:39:24 +020096static size_t qemu_sgl_concat(VirtIOSCSIReq *req, struct iovec *iov,
97 hwaddr *addr, int num, size_t skip)
Stefan Hajnoczi326799c2011-02-13 10:55:52 +000098{
Paolo Bonzinif487b672013-06-03 14:17:19 +020099 QEMUSGList *qsgl = &req->qsgl;
Paolo Bonzini57fbae62014-06-10 16:39:24 +0200100 size_t copied = 0;
Paolo Bonzinif487b672013-06-03 14:17:19 +0200101
Paolo Bonzini57fbae62014-06-10 16:39:24 +0200102 while (num) {
103 if (skip >= iov->iov_len) {
104 skip -= iov->iov_len;
105 } else {
106 qemu_sglist_add(qsgl, *addr + skip, iov->iov_len - skip);
107 copied += iov->iov_len - skip;
108 skip = 0;
109 }
110 iov++;
111 addr++;
112 num--;
Stefan Hajnoczi326799c2011-02-13 10:55:52 +0000113 }
Paolo Bonzini57fbae62014-06-10 16:39:24 +0200114
115 assert(skip == 0);
116 return copied;
Stefan Hajnoczi326799c2011-02-13 10:55:52 +0000117}
118
Paolo Bonzini36b15c72014-06-10 16:21:18 +0200119static int virtio_scsi_parse_req(VirtIOSCSIReq *req,
120 unsigned req_size, unsigned resp_size)
Stefan Hajnoczi326799c2011-02-13 10:55:52 +0000121{
Paolo Bonzini55783a52014-11-07 14:00:02 +0100122 VirtIODevice *vdev = (VirtIODevice *) req->dev;
Paolo Bonzini3eff1f42014-06-10 16:40:31 +0200123 size_t in_size, out_size;
124
125 if (iov_to_buf(req->elem.out_sg, req->elem.out_num, 0,
126 &req->req, req_size) < req_size) {
Paolo Bonzini36b15c72014-06-10 16:21:18 +0200127 return -EINVAL;
128 }
129
Paolo Bonzini3eff1f42014-06-10 16:40:31 +0200130 if (qemu_iovec_concat_iov(&req->resp_iov,
131 req->elem.in_sg, req->elem.in_num, 0,
132 resp_size) < resp_size) {
Paolo Bonzini36b15c72014-06-10 16:21:18 +0200133 return -EINVAL;
134 }
Paolo Bonzini55783a52014-11-07 14:00:02 +0100135
Paolo Bonzini489c7902014-06-10 16:58:19 +0200136 req->resp_size = resp_size;
Stefan Hajnoczi326799c2011-02-13 10:55:52 +0000137
Paolo Bonzini55783a52014-11-07 14:00:02 +0100138 /* Old BIOSes left some padding by mistake after the req_size/resp_size.
139 * As a workaround, always consider the first buffer as the virtio-scsi
140 * request/response, making the payload start at the second element
141 * of the iovec.
142 *
143 * The actual length of the response header, stored in req->resp_size,
144 * does not change.
145 *
146 * TODO: always disable this workaround for virtio 1.0 devices.
147 */
Cornelia Huck95129d62015-08-17 11:48:29 +0200148 if (!virtio_vdev_has_feature(vdev, VIRTIO_F_ANY_LAYOUT)) {
Fam Zheng2034e322015-03-13 15:55:54 +0800149 if (req->elem.out_num) {
150 req_size = req->elem.out_sg[0].iov_len;
151 }
152 if (req->elem.in_num) {
153 resp_size = req->elem.in_sg[0].iov_len;
154 }
Paolo Bonzini55783a52014-11-07 14:00:02 +0100155 }
156
Paolo Bonzini3eff1f42014-06-10 16:40:31 +0200157 out_size = qemu_sgl_concat(req, req->elem.out_sg,
158 &req->elem.out_addr[0], req->elem.out_num,
159 req_size);
160 in_size = qemu_sgl_concat(req, req->elem.in_sg,
161 &req->elem.in_addr[0], req->elem.in_num,
162 resp_size);
163
164 if (out_size && in_size) {
165 return -ENOTSUP;
166 }
167
168 if (out_size) {
169 req->mode = SCSI_XFER_TO_DEV;
170 } else if (in_size) {
171 req->mode = SCSI_XFER_FROM_DEV;
Stefan Hajnoczi326799c2011-02-13 10:55:52 +0000172 }
Paolo Bonzini36b15c72014-06-10 16:21:18 +0200173
174 return 0;
Stefan Hajnoczi326799c2011-02-13 10:55:52 +0000175}
176
177static VirtIOSCSIReq *virtio_scsi_pop_req(VirtIOSCSI *s, VirtQueue *vq)
178{
Paolo Bonzini51b19eb2016-02-04 16:26:51 +0200179 VirtIOSCSICommon *vs = (VirtIOSCSICommon *)s;
180 VirtIOSCSIReq *req;
181
182 req = virtqueue_pop(vq, sizeof(VirtIOSCSIReq) + vs->cdb_size);
183 if (!req) {
Stefan Hajnoczi326799c2011-02-13 10:55:52 +0000184 return NULL;
185 }
Paolo Bonzini51b19eb2016-02-04 16:26:51 +0200186 virtio_scsi_init_req(s, vq, req);
Stefan Hajnoczi326799c2011-02-13 10:55:52 +0000187 return req;
188}
189
Paolo Bonzini5db17642011-12-02 15:23:15 +0100190static void virtio_scsi_save_request(QEMUFile *f, SCSIRequest *sreq)
191{
192 VirtIOSCSIReq *req = sreq->hba_private;
Paolo Bonzini292c8e52013-03-29 01:08:15 +0000193 VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(req->dev);
Jason Wang86044b22019-10-25 10:35:24 +0200194 VirtIODevice *vdev = VIRTIO_DEVICE(req->dev);
Stefan Hajnoczi4e5163b2020-08-18 15:33:45 +0100195 uint32_t n = virtio_get_queue_index(req->vq) - VIRTIO_SCSI_VQ_NUM_FIXED;
Paolo Bonzini5db17642011-12-02 15:23:15 +0100196
Paolo Bonzini292c8e52013-03-29 01:08:15 +0000197 assert(n < vs->conf.num_queues);
Paolo Bonzinifcf104a2012-04-06 10:20:43 +0200198 qemu_put_be32s(f, &n);
Jason Wang86044b22019-10-25 10:35:24 +0200199 qemu_put_virtqueue_element(vdev, f, &req->elem);
Paolo Bonzini5db17642011-12-02 15:23:15 +0100200}
201
202static void *virtio_scsi_load_request(QEMUFile *f, SCSIRequest *sreq)
203{
204 SCSIBus *bus = sreq->bus;
205 VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus);
Paolo Bonzini292c8e52013-03-29 01:08:15 +0000206 VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
Jason Wang8607f5c2016-12-30 18:09:10 +0800207 VirtIODevice *vdev = VIRTIO_DEVICE(s);
Paolo Bonzini5db17642011-12-02 15:23:15 +0100208 VirtIOSCSIReq *req;
Paolo Bonzinifcf104a2012-04-06 10:20:43 +0200209 uint32_t n;
Paolo Bonzini5db17642011-12-02 15:23:15 +0100210
Paolo Bonzinifcf104a2012-04-06 10:20:43 +0200211 qemu_get_be32s(f, &n);
Paolo Bonzini292c8e52013-03-29 01:08:15 +0000212 assert(n < vs->conf.num_queues);
Jason Wang8607f5c2016-12-30 18:09:10 +0800213 req = qemu_get_virtqueue_element(vdev, f,
214 sizeof(VirtIOSCSIReq) + vs->cdb_size);
Paolo Bonzini51b19eb2016-02-04 16:26:51 +0200215 virtio_scsi_init_req(s, vs->cmd_vqs[n], req);
Paolo Bonzini36b15c72014-06-10 16:21:18 +0200216
217 if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICmdReq) + vs->cdb_size,
218 sizeof(VirtIOSCSICmdResp) + vs->sense_size) < 0) {
219 error_report("invalid SCSI request migration data");
220 exit(1);
221 }
Paolo Bonzini5db17642011-12-02 15:23:15 +0100222
223 scsi_req_ref(sreq);
224 req->sreq = sreq;
225 if (req->sreq->cmd.mode != SCSI_XFER_NONE) {
Paolo Bonzini3eff1f42014-06-10 16:40:31 +0200226 assert(req->sreq->cmd.mode == req->mode);
Paolo Bonzini5db17642011-12-02 15:23:15 +0100227 }
228 return req;
229}
230
Fam Zheng49e7e312014-09-30 11:40:23 +0800231typedef struct {
232 Notifier notifier;
233 VirtIOSCSIReq *tmf_req;
234} VirtIOSCSICancelNotifier;
235
236static void virtio_scsi_cancel_notify(Notifier *notifier, void *data)
237{
238 VirtIOSCSICancelNotifier *n = container_of(notifier,
239 VirtIOSCSICancelNotifier,
240 notifier);
241
242 if (--n->tmf_req->remaining == 0) {
Hannes Reineckeeb8cb3d2020-11-16 19:31:12 +0100243 VirtIOSCSIReq *req = n->tmf_req;
244
245 trace_virtio_scsi_tmf_resp(virtio_scsi_get_lun(req->req.tmf.lun),
246 req->req.tmf.tag, req->resp.tmf.response);
247 virtio_scsi_complete_req(req);
Fam Zheng49e7e312014-09-30 11:40:23 +0800248 }
Paolo Bonzini633dccb2015-10-01 12:59:01 +0200249 g_free(n);
Fam Zheng49e7e312014-09-30 11:40:23 +0800250}
251
Fam Zheng2a2d69f2016-09-14 18:17:04 +0800252static inline void virtio_scsi_ctx_check(VirtIOSCSI *s, SCSIDevice *d)
253{
254 if (s->dataplane_started && d && blk_is_available(d->conf.blk)) {
255 assert(blk_get_aio_context(d->conf.blk) == s->ctx);
256 }
257}
258
Fam Zheng49e7e312014-09-30 11:40:23 +0800259/* Return 0 if the request is ready to be completed and return to guest;
260 * -EINPROGRESS if the request is submitted and will be completed later, in the
261 * case of async cancellation. */
262static int virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req)
Stefan Hajnoczi326799c2011-02-13 10:55:52 +0000263{
Maxim Levitsky07a47d42020-10-06 15:39:03 +0300264 SCSIDevice *d = virtio_scsi_device_get(s, req->req.tmf.lun);
Paolo Bonzini06114d72011-11-14 17:44:09 +0100265 SCSIRequest *r, *next;
Anthony Liguori0866aca2011-12-23 15:34:39 -0600266 BusChild *kid;
Paolo Bonzini06114d72011-11-14 17:44:09 +0100267 int target;
Fam Zheng49e7e312014-09-30 11:40:23 +0800268 int ret = 0;
Paolo Bonzini06114d72011-11-14 17:44:09 +0100269
Fam Zheng2a2d69f2016-09-14 18:17:04 +0800270 virtio_scsi_ctx_check(s, d);
Paolo Bonzini06114d72011-11-14 17:44:09 +0100271 /* Here VIRTIO_SCSI_S_OK means "FUNCTION COMPLETE". */
Paolo Bonzini3eff1f42014-06-10 16:40:31 +0200272 req->resp.tmf.response = VIRTIO_SCSI_S_OK;
Paolo Bonzini06114d72011-11-14 17:44:09 +0100273
Greg Kurzd8042322019-02-28 18:59:42 +0100274 /*
275 * req->req.tmf has the QEMU_PACKED attribute. Don't use virtio_tswap32s()
276 * to avoid compiler errors.
277 */
278 req->req.tmf.subtype =
279 virtio_tswap32(VIRTIO_DEVICE(s), req->req.tmf.subtype);
280
Hannes Reineckeeb8cb3d2020-11-16 19:31:12 +0100281 trace_virtio_scsi_tmf_req(virtio_scsi_get_lun(req->req.tmf.lun),
282 req->req.tmf.tag, req->req.tmf.subtype);
283
Paolo Bonzini3eff1f42014-06-10 16:40:31 +0200284 switch (req->req.tmf.subtype) {
Paolo Bonzini06114d72011-11-14 17:44:09 +0100285 case VIRTIO_SCSI_T_TMF_ABORT_TASK:
286 case VIRTIO_SCSI_T_TMF_QUERY_TASK:
287 if (!d) {
288 goto fail;
289 }
Paolo Bonzini3eff1f42014-06-10 16:40:31 +0200290 if (d->lun != virtio_scsi_get_lun(req->req.tmf.lun)) {
Paolo Bonzini06114d72011-11-14 17:44:09 +0100291 goto incorrect_lun;
292 }
293 QTAILQ_FOREACH_SAFE(r, &d->requests, next, next) {
Paolo Bonzini4dd7c822012-08-08 16:26:16 +0200294 VirtIOSCSIReq *cmd_req = r->hba_private;
Paolo Bonzini3eff1f42014-06-10 16:40:31 +0200295 if (cmd_req && cmd_req->req.cmd.tag == req->req.tmf.tag) {
Paolo Bonzini06114d72011-11-14 17:44:09 +0100296 break;
297 }
298 }
Paolo Bonzini4dd7c822012-08-08 16:26:16 +0200299 if (r) {
300 /*
301 * Assert that the request has not been completed yet, we
302 * check for it in the loop above.
303 */
304 assert(r->hba_private);
Paolo Bonzini3eff1f42014-06-10 16:40:31 +0200305 if (req->req.tmf.subtype == VIRTIO_SCSI_T_TMF_QUERY_TASK) {
Paolo Bonzini06114d72011-11-14 17:44:09 +0100306 /* "If the specified command is present in the task set, then
307 * return a service response set to FUNCTION SUCCEEDED".
308 */
Paolo Bonzini3eff1f42014-06-10 16:40:31 +0200309 req->resp.tmf.response = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED;
Paolo Bonzini06114d72011-11-14 17:44:09 +0100310 } else {
Fam Zheng49e7e312014-09-30 11:40:23 +0800311 VirtIOSCSICancelNotifier *notifier;
312
313 req->remaining = 1;
Paolo Bonzini633dccb2015-10-01 12:59:01 +0200314 notifier = g_new(VirtIOSCSICancelNotifier, 1);
Fam Zheng49e7e312014-09-30 11:40:23 +0800315 notifier->tmf_req = req;
316 notifier->notifier.notify = virtio_scsi_cancel_notify;
317 scsi_req_cancel_async(r, &notifier->notifier);
318 ret = -EINPROGRESS;
Paolo Bonzini06114d72011-11-14 17:44:09 +0100319 }
320 }
321 break;
322
323 case VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET:
324 if (!d) {
325 goto fail;
326 }
Paolo Bonzini3eff1f42014-06-10 16:40:31 +0200327 if (d->lun != virtio_scsi_get_lun(req->req.tmf.lun)) {
Paolo Bonzini06114d72011-11-14 17:44:09 +0100328 goto incorrect_lun;
329 }
330 s->resetting++;
331 qdev_reset_all(&d->qdev);
332 s->resetting--;
333 break;
334
335 case VIRTIO_SCSI_T_TMF_ABORT_TASK_SET:
336 case VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET:
337 case VIRTIO_SCSI_T_TMF_QUERY_TASK_SET:
338 if (!d) {
339 goto fail;
340 }
Paolo Bonzini3eff1f42014-06-10 16:40:31 +0200341 if (d->lun != virtio_scsi_get_lun(req->req.tmf.lun)) {
Paolo Bonzini06114d72011-11-14 17:44:09 +0100342 goto incorrect_lun;
343 }
Fam Zheng49e7e312014-09-30 11:40:23 +0800344
345 /* Add 1 to "remaining" until virtio_scsi_do_tmf returns.
346 * This way, if the bus starts calling back to the notifiers
347 * even before we finish the loop, virtio_scsi_cancel_notify
348 * will not complete the TMF too early.
349 */
350 req->remaining = 1;
Paolo Bonzini06114d72011-11-14 17:44:09 +0100351 QTAILQ_FOREACH_SAFE(r, &d->requests, next, next) {
352 if (r->hba_private) {
Paolo Bonzini3eff1f42014-06-10 16:40:31 +0200353 if (req->req.tmf.subtype == VIRTIO_SCSI_T_TMF_QUERY_TASK_SET) {
Paolo Bonzini06114d72011-11-14 17:44:09 +0100354 /* "If there is any command present in the task set, then
355 * return a service response set to FUNCTION SUCCEEDED".
356 */
Paolo Bonzini3eff1f42014-06-10 16:40:31 +0200357 req->resp.tmf.response = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED;
Paolo Bonzini06114d72011-11-14 17:44:09 +0100358 break;
359 } else {
Fam Zheng49e7e312014-09-30 11:40:23 +0800360 VirtIOSCSICancelNotifier *notifier;
361
362 req->remaining++;
Paolo Bonzini633dccb2015-10-01 12:59:01 +0200363 notifier = g_new(VirtIOSCSICancelNotifier, 1);
Fam Zheng49e7e312014-09-30 11:40:23 +0800364 notifier->notifier.notify = virtio_scsi_cancel_notify;
365 notifier->tmf_req = req;
366 scsi_req_cancel_async(r, &notifier->notifier);
Paolo Bonzini06114d72011-11-14 17:44:09 +0100367 }
368 }
369 }
Fam Zheng49e7e312014-09-30 11:40:23 +0800370 if (--req->remaining > 0) {
371 ret = -EINPROGRESS;
372 }
Paolo Bonzini06114d72011-11-14 17:44:09 +0100373 break;
374
375 case VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET:
Paolo Bonzini3eff1f42014-06-10 16:40:31 +0200376 target = req->req.tmf.lun[1];
Paolo Bonzini06114d72011-11-14 17:44:09 +0100377 s->resetting++;
Maxim Levitsky2d24a642020-10-06 15:38:59 +0300378
379 rcu_read_lock();
380 QTAILQ_FOREACH_RCU(kid, &s->bus.qbus.children, sibling) {
Maxim Levitsky07a47d42020-10-06 15:39:03 +0300381 SCSIDevice *d1 = SCSI_DEVICE(kid->child);
382 if (d1->channel == 0 && d1->id == target) {
383 qdev_reset_all(&d1->qdev);
384 }
Paolo Bonzini06114d72011-11-14 17:44:09 +0100385 }
Maxim Levitsky2d24a642020-10-06 15:38:59 +0300386 rcu_read_unlock();
387
Paolo Bonzini06114d72011-11-14 17:44:09 +0100388 s->resetting--;
389 break;
390
391 case VIRTIO_SCSI_T_TMF_CLEAR_ACA:
392 default:
Paolo Bonzini3eff1f42014-06-10 16:40:31 +0200393 req->resp.tmf.response = VIRTIO_SCSI_S_FUNCTION_REJECTED;
Paolo Bonzini06114d72011-11-14 17:44:09 +0100394 break;
Stefan Hajnoczi326799c2011-02-13 10:55:52 +0000395 }
396
Maxim Levitsky07a47d42020-10-06 15:39:03 +0300397 object_unref(OBJECT(d));
Fam Zheng49e7e312014-09-30 11:40:23 +0800398 return ret;
Paolo Bonzini06114d72011-11-14 17:44:09 +0100399
400incorrect_lun:
Paolo Bonzini3eff1f42014-06-10 16:40:31 +0200401 req->resp.tmf.response = VIRTIO_SCSI_S_INCORRECT_LUN;
Maxim Levitsky07a47d42020-10-06 15:39:03 +0300402 object_unref(OBJECT(d));
Fam Zheng49e7e312014-09-30 11:40:23 +0800403 return ret;
Paolo Bonzini06114d72011-11-14 17:44:09 +0100404
405fail:
Paolo Bonzini3eff1f42014-06-10 16:40:31 +0200406 req->resp.tmf.response = VIRTIO_SCSI_S_BAD_TARGET;
Maxim Levitsky07a47d42020-10-06 15:39:03 +0300407 object_unref(OBJECT(d));
Fam Zheng49e7e312014-09-30 11:40:23 +0800408 return ret;
Stefan Hajnoczi326799c2011-02-13 10:55:52 +0000409}
410
Paolo Bonzinia8f2e5c2016-04-06 12:16:27 +0200411static void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req)
Fam Zhengdc56b7c2014-08-06 13:35:01 +0800412{
413 VirtIODevice *vdev = (VirtIODevice *)s;
Bin Wu024d9ad2014-10-25 02:43:44 +0000414 uint32_t type;
Fam Zheng49e7e312014-09-30 11:40:23 +0800415 int r = 0;
Fam Zhengdc56b7c2014-08-06 13:35:01 +0800416
417 if (iov_to_buf(req->elem.out_sg, req->elem.out_num, 0,
418 &type, sizeof(type)) < sizeof(type)) {
Greg Kurz661e32f2016-09-30 17:13:40 +0200419 virtio_scsi_bad_req(req);
Fam Zhengdc56b7c2014-08-06 13:35:01 +0800420 return;
421 }
422
Bin Wu024d9ad2014-10-25 02:43:44 +0000423 virtio_tswap32s(vdev, &type);
424 if (type == VIRTIO_SCSI_T_TMF) {
Fam Zhengdc56b7c2014-08-06 13:35:01 +0800425 if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICtrlTMFReq),
426 sizeof(VirtIOSCSICtrlTMFResp)) < 0) {
Greg Kurz661e32f2016-09-30 17:13:40 +0200427 virtio_scsi_bad_req(req);
428 return;
Fam Zhengdc56b7c2014-08-06 13:35:01 +0800429 } else {
Fam Zheng49e7e312014-09-30 11:40:23 +0800430 r = virtio_scsi_do_tmf(s, req);
Fam Zhengdc56b7c2014-08-06 13:35:01 +0800431 }
432
Bin Wu024d9ad2014-10-25 02:43:44 +0000433 } else if (type == VIRTIO_SCSI_T_AN_QUERY ||
434 type == VIRTIO_SCSI_T_AN_SUBSCRIBE) {
Fam Zhengdc56b7c2014-08-06 13:35:01 +0800435 if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICtrlANReq),
436 sizeof(VirtIOSCSICtrlANResp)) < 0) {
Greg Kurz661e32f2016-09-30 17:13:40 +0200437 virtio_scsi_bad_req(req);
438 return;
Fam Zhengdc56b7c2014-08-06 13:35:01 +0800439 } else {
Hannes Reineckeeb8cb3d2020-11-16 19:31:12 +0100440 req->req.an.event_requested =
441 virtio_tswap32(VIRTIO_DEVICE(s), req->req.an.event_requested);
442 trace_virtio_scsi_an_req(virtio_scsi_get_lun(req->req.an.lun),
443 req->req.an.event_requested);
Fam Zhengdc56b7c2014-08-06 13:35:01 +0800444 req->resp.an.event_actual = 0;
445 req->resp.an.response = VIRTIO_SCSI_S_OK;
446 }
447 }
Fam Zheng49e7e312014-09-30 11:40:23 +0800448 if (r == 0) {
Hannes Reineckeeb8cb3d2020-11-16 19:31:12 +0100449 if (type == VIRTIO_SCSI_T_TMF)
450 trace_virtio_scsi_tmf_resp(virtio_scsi_get_lun(req->req.tmf.lun),
451 req->req.tmf.tag,
452 req->resp.tmf.response);
453 else if (type == VIRTIO_SCSI_T_AN_QUERY ||
454 type == VIRTIO_SCSI_T_AN_SUBSCRIBE)
455 trace_virtio_scsi_an_resp(virtio_scsi_get_lun(req->req.an.lun),
456 req->resp.an.response);
Fam Zheng49e7e312014-09-30 11:40:23 +0800457 virtio_scsi_complete_req(req);
458 } else {
459 assert(r == -EINPROGRESS);
460 }
Fam Zhengdc56b7c2014-08-06 13:35:01 +0800461}
462
Fam Zheng07931692017-02-09 16:40:47 +0800463bool virtio_scsi_handle_ctrl_vq(VirtIOSCSI *s, VirtQueue *vq)
Stefan Hajnoczi973abc72011-02-11 08:40:59 +0000464{
Stefan Hajnoczi326799c2011-02-13 10:55:52 +0000465 VirtIOSCSIReq *req;
Fam Zheng07931692017-02-09 16:40:47 +0800466 bool progress = false;
Stefan Hajnoczi326799c2011-02-13 10:55:52 +0000467
468 while ((req = virtio_scsi_pop_req(s, vq))) {
Fam Zheng07931692017-02-09 16:40:47 +0800469 progress = true;
Fam Zhengdc56b7c2014-08-06 13:35:01 +0800470 virtio_scsi_handle_ctrl_req(s, req);
Stefan Hajnoczi326799c2011-02-13 10:55:52 +0000471 }
Fam Zheng07931692017-02-09 16:40:47 +0800472 return progress;
Stefan Hajnoczi326799c2011-02-13 10:55:52 +0000473}
474
Paolo Bonzinia8f2e5c2016-04-06 12:16:27 +0200475static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
476{
477 VirtIOSCSI *s = (VirtIOSCSI *)vdev;
478
479 if (s->ctx) {
Paolo Bonziniad07cd62016-10-21 22:48:10 +0200480 virtio_device_start_ioeventfd(vdev);
Paolo Bonzinia8f2e5c2016-04-06 12:16:27 +0200481 if (!s->dataplane_fenced) {
482 return;
483 }
484 }
Fam Zheng71407782017-03-17 14:14:47 +0800485 virtio_scsi_acquire(s);
Paolo Bonzinia8f2e5c2016-04-06 12:16:27 +0200486 virtio_scsi_handle_ctrl_vq(s, vq);
Fam Zheng71407782017-03-17 14:14:47 +0800487 virtio_scsi_release(s);
Paolo Bonzinia8f2e5c2016-04-06 12:16:27 +0200488}
489
Paolo Bonzinia3de2692014-06-10 20:16:20 +0200490static void virtio_scsi_complete_cmd_req(VirtIOSCSIReq *req)
491{
Hannes Reineckeeb8cb3d2020-11-16 19:31:12 +0100492 trace_virtio_scsi_cmd_resp(virtio_scsi_get_lun(req->req.cmd.lun),
493 req->req.cmd.tag,
494 req->resp.cmd.response,
495 req->resp.cmd.status);
Paolo Bonzini3eff1f42014-06-10 16:40:31 +0200496 /* Sense data is not in req->resp and is copied separately
497 * in virtio_scsi_command_complete.
498 */
499 req->resp_size = sizeof(VirtIOSCSICmdResp);
Paolo Bonzinia3de2692014-06-10 20:16:20 +0200500 virtio_scsi_complete_req(req);
501}
502
Hannes Reineckef3126d62021-02-24 19:14:50 +0100503static void virtio_scsi_command_failed(SCSIRequest *r)
504{
505 VirtIOSCSIReq *req = r->hba_private;
506
507 if (r->io_canceled) {
508 return;
509 }
510
511 req->resp.cmd.status = GOOD;
512 switch (r->host_status) {
513 case SCSI_HOST_NO_LUN:
514 req->resp.cmd.response = VIRTIO_SCSI_S_INCORRECT_LUN;
515 break;
516 case SCSI_HOST_BUSY:
517 req->resp.cmd.response = VIRTIO_SCSI_S_BUSY;
518 break;
519 case SCSI_HOST_TIME_OUT:
520 case SCSI_HOST_ABORTED:
521 req->resp.cmd.response = VIRTIO_SCSI_S_ABORTED;
522 break;
523 case SCSI_HOST_BAD_RESPONSE:
524 req->resp.cmd.response = VIRTIO_SCSI_S_BAD_TARGET;
525 break;
526 case SCSI_HOST_RESET:
527 req->resp.cmd.response = VIRTIO_SCSI_S_RESET;
528 break;
529 case SCSI_HOST_TRANSPORT_DISRUPTED:
530 req->resp.cmd.response = VIRTIO_SCSI_S_TRANSPORT_FAILURE;
531 break;
532 case SCSI_HOST_TARGET_FAILURE:
533 req->resp.cmd.response = VIRTIO_SCSI_S_TARGET_FAILURE;
534 break;
535 case SCSI_HOST_RESERVATION_ERROR:
536 req->resp.cmd.response = VIRTIO_SCSI_S_NEXUS_FAILURE;
537 break;
538 case SCSI_HOST_ALLOCATION_FAILURE:
539 case SCSI_HOST_MEDIUM_ERROR:
540 case SCSI_HOST_ERROR:
541 default:
542 req->resp.cmd.response = VIRTIO_SCSI_S_FAILURE;
543 break;
544 }
545 virtio_scsi_complete_cmd_req(req);
546}
547
Hannes Reinecke17ea26c22020-11-16 19:40:36 +0100548static void virtio_scsi_command_complete(SCSIRequest *r, size_t resid)
Paolo Bonzini2ccdcd82011-11-14 16:58:41 +0100549{
550 VirtIOSCSIReq *req = r->hba_private;
Paolo Bonzini489c7902014-06-10 16:58:19 +0200551 uint8_t sense[SCSI_SENSE_BUF_SIZE];
David Gibson474ee552012-11-23 16:08:44 +1100552 uint32_t sense_len;
Rusty Russell8c085db2014-06-24 19:48:53 +0200553 VirtIODevice *vdev = VIRTIO_DEVICE(req->dev);
Paolo Bonzini2ccdcd82011-11-14 16:58:41 +0100554
Eric Farmane9c0f0f2014-01-14 14:16:25 -0500555 if (r->io_canceled) {
556 return;
557 }
558
Paolo Bonzini3eff1f42014-06-10 16:40:31 +0200559 req->resp.cmd.response = VIRTIO_SCSI_S_OK;
Hannes Reinecke17ea26c22020-11-16 19:40:36 +0100560 req->resp.cmd.status = r->status;
Paolo Bonzini3eff1f42014-06-10 16:40:31 +0200561 if (req->resp.cmd.status == GOOD) {
Rusty Russell8c085db2014-06-24 19:48:53 +0200562 req->resp.cmd.resid = virtio_tswap32(vdev, resid);
Paolo Bonzini2ccdcd82011-11-14 16:58:41 +0100563 } else {
Paolo Bonzini3eff1f42014-06-10 16:40:31 +0200564 req->resp.cmd.resid = 0;
Paolo Bonzini489c7902014-06-10 16:58:19 +0200565 sense_len = scsi_req_get_sense(r, sense, sizeof(sense));
Paolo Bonzini3eff1f42014-06-10 16:40:31 +0200566 sense_len = MIN(sense_len, req->resp_iov.size - sizeof(req->resp.cmd));
567 qemu_iovec_from_buf(&req->resp_iov, sizeof(req->resp.cmd),
Ting Wangb7890c42014-10-27 16:51:41 +0800568 sense, sense_len);
Rusty Russell8c085db2014-06-24 19:48:53 +0200569 req->resp.cmd.sense_len = virtio_tswap32(vdev, sense_len);
Paolo Bonzini2ccdcd82011-11-14 16:58:41 +0100570 }
Paolo Bonzinia3de2692014-06-10 20:16:20 +0200571 virtio_scsi_complete_cmd_req(req);
Paolo Bonzini2ccdcd82011-11-14 16:58:41 +0100572}
573
Paolo Bonzini33cbb2c2014-07-16 11:04:37 +0200574static int virtio_scsi_parse_cdb(SCSIDevice *dev, SCSICommand *cmd,
575 uint8_t *buf, void *hba_private)
576{
577 VirtIOSCSIReq *req = hba_private;
578
579 if (cmd->len == 0) {
Michael S. Tsirkin03325522015-03-11 14:31:29 +0100580 cmd->len = MIN(VIRTIO_SCSI_CDB_DEFAULT_SIZE, SCSI_CMD_BUF_SIZE);
Paolo Bonzini33cbb2c2014-07-16 11:04:37 +0200581 memcpy(cmd->buf, buf, cmd->len);
582 }
583
584 /* Extract the direction and mode directly from the request, for
585 * host device passthrough.
586 */
587 cmd->xfer = req->qsgl.size;
Paolo Bonzini9df7bfd2014-09-17 18:10:37 +0200588 cmd->mode = req->mode;
Paolo Bonzini33cbb2c2014-07-16 11:04:37 +0200589 return 0;
590}
591
Paolo Bonzini2ccdcd82011-11-14 16:58:41 +0100592static QEMUSGList *virtio_scsi_get_sg_list(SCSIRequest *r)
593{
594 VirtIOSCSIReq *req = r->hba_private;
595
596 return &req->qsgl;
597}
598
599static void virtio_scsi_request_cancelled(SCSIRequest *r)
600{
601 VirtIOSCSIReq *req = r->hba_private;
602
603 if (!req) {
604 return;
605 }
Paolo Bonzini06114d72011-11-14 17:44:09 +0100606 if (req->dev->resetting) {
Paolo Bonzini3eff1f42014-06-10 16:40:31 +0200607 req->resp.cmd.response = VIRTIO_SCSI_S_RESET;
Paolo Bonzini06114d72011-11-14 17:44:09 +0100608 } else {
Paolo Bonzini3eff1f42014-06-10 16:40:31 +0200609 req->resp.cmd.response = VIRTIO_SCSI_S_ABORTED;
Paolo Bonzini06114d72011-11-14 17:44:09 +0100610 }
Paolo Bonzinia3de2692014-06-10 20:16:20 +0200611 virtio_scsi_complete_cmd_req(req);
Paolo Bonzini2ccdcd82011-11-14 16:58:41 +0100612}
613
614static void virtio_scsi_fail_cmd_req(VirtIOSCSIReq *req)
Stefan Hajnoczi326799c2011-02-13 10:55:52 +0000615{
Paolo Bonzini3eff1f42014-06-10 16:40:31 +0200616 req->resp.cmd.response = VIRTIO_SCSI_S_FAILURE;
Paolo Bonzinia3de2692014-06-10 20:16:20 +0200617 virtio_scsi_complete_cmd_req(req);
Stefan Hajnoczi973abc72011-02-11 08:40:59 +0000618}
619
Greg Kurz661e32f2016-09-30 17:13:40 +0200620static int virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req)
Fam Zhengbf359a42014-08-06 13:35:00 +0800621{
622 VirtIOSCSICommon *vs = &s->parent_obj;
Fam Zhengbf359a42014-08-06 13:35:00 +0800623 SCSIDevice *d;
624 int rc;
625
626 rc = virtio_scsi_parse_req(req, sizeof(VirtIOSCSICmdReq) + vs->cdb_size,
627 sizeof(VirtIOSCSICmdResp) + vs->sense_size);
628 if (rc < 0) {
629 if (rc == -ENOTSUP) {
630 virtio_scsi_fail_cmd_req(req);
Greg Kurz661e32f2016-09-30 17:13:40 +0200631 return -ENOTSUP;
Fam Zhengbf359a42014-08-06 13:35:00 +0800632 } else {
Greg Kurz661e32f2016-09-30 17:13:40 +0200633 virtio_scsi_bad_req(req);
634 return -EINVAL;
Fam Zhengbf359a42014-08-06 13:35:00 +0800635 }
Fam Zhengbf359a42014-08-06 13:35:00 +0800636 }
Hannes Reineckeeb8cb3d2020-11-16 19:31:12 +0100637 trace_virtio_scsi_cmd_req(virtio_scsi_get_lun(req->req.cmd.lun),
638 req->req.cmd.tag, req->req.cmd.cdb[0]);
Fam Zhengbf359a42014-08-06 13:35:00 +0800639
Maxim Levitsky07a47d42020-10-06 15:39:03 +0300640 d = virtio_scsi_device_get(s, req->req.cmd.lun);
Fam Zhengbf359a42014-08-06 13:35:00 +0800641 if (!d) {
642 req->resp.cmd.response = VIRTIO_SCSI_S_BAD_TARGET;
643 virtio_scsi_complete_cmd_req(req);
Greg Kurz661e32f2016-09-30 17:13:40 +0200644 return -ENOENT;
Fam Zhengbf359a42014-08-06 13:35:00 +0800645 }
Fam Zheng2a2d69f2016-09-14 18:17:04 +0800646 virtio_scsi_ctx_check(s, d);
Fam Zhengbf359a42014-08-06 13:35:00 +0800647 req->sreq = scsi_req_new(d, req->req.cmd.tag,
648 virtio_scsi_get_lun(req->req.cmd.lun),
Michael S. Tsirkinbb724632015-03-11 14:35:47 +0100649 req->req.cmd.cdb, req);
Fam Zhengbf359a42014-08-06 13:35:00 +0800650
651 if (req->sreq->cmd.mode != SCSI_XFER_NONE
652 && (req->sreq->cmd.mode != req->mode ||
653 req->sreq->cmd.xfer > req->qsgl.size)) {
654 req->resp.cmd.response = VIRTIO_SCSI_S_OVERRUN;
655 virtio_scsi_complete_cmd_req(req);
Maxim Levitsky07a47d42020-10-06 15:39:03 +0300656 object_unref(OBJECT(d));
Greg Kurz661e32f2016-09-30 17:13:40 +0200657 return -ENOBUFS;
Fam Zhengbf359a42014-08-06 13:35:00 +0800658 }
Fam Zheng5170f402014-09-23 15:49:29 +0800659 scsi_req_ref(req->sreq);
Markus Armbruster4be74632014-10-07 13:59:18 +0200660 blk_io_plug(d->conf.blk);
Maxim Levitsky07a47d42020-10-06 15:39:03 +0300661 object_unref(OBJECT(d));
Greg Kurz661e32f2016-09-30 17:13:40 +0200662 return 0;
Fam Zheng359eea72014-09-23 15:49:27 +0800663}
Fam Zhengbf359a42014-08-06 13:35:00 +0800664
Paolo Bonzinia8f2e5c2016-04-06 12:16:27 +0200665static void virtio_scsi_handle_cmd_req_submit(VirtIOSCSI *s, VirtIOSCSIReq *req)
Fam Zheng359eea72014-09-23 15:49:27 +0800666{
Paolo Bonzini35e4e962014-10-08 01:19:00 +0200667 SCSIRequest *sreq = req->sreq;
668 if (scsi_req_enqueue(sreq)) {
669 scsi_req_continue(sreq);
Fam Zhengbf359a42014-08-06 13:35:00 +0800670 }
Markus Armbruster4be74632014-10-07 13:59:18 +0200671 blk_io_unplug(sreq->dev->conf.blk);
Paolo Bonzini35e4e962014-10-08 01:19:00 +0200672 scsi_req_unref(sreq);
Fam Zhengbf359a42014-08-06 13:35:00 +0800673}
674
Fam Zheng07931692017-02-09 16:40:47 +0800675bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq)
Stefan Hajnoczi973abc72011-02-11 08:40:59 +0000676{
Fam Zheng1880ad42014-09-23 15:49:28 +0800677 VirtIOSCSIReq *req, *next;
Stefan Hajnoczi23425cc2016-12-01 19:26:47 +0000678 int ret = 0;
Stefan Hajnoczid0435bc2019-12-09 21:09:57 +0000679 bool suppress_notifications = virtio_queue_get_notification(vq);
Fam Zheng07931692017-02-09 16:40:47 +0800680 bool progress = false;
Greg Kurz661e32f2016-09-30 17:13:40 +0200681
Fam Zheng1880ad42014-09-23 15:49:28 +0800682 QTAILQ_HEAD(, VirtIOSCSIReq) reqs = QTAILQ_HEAD_INITIALIZER(reqs);
Stefan Hajnoczi326799c2011-02-13 10:55:52 +0000683
Stefan Hajnoczi23425cc2016-12-01 19:26:47 +0000684 do {
Stefan Hajnoczid0435bc2019-12-09 21:09:57 +0000685 if (suppress_notifications) {
686 virtio_queue_set_notification(vq, 0);
687 }
Stefan Hajnoczi23425cc2016-12-01 19:26:47 +0000688
689 while ((req = virtio_scsi_pop_req(s, vq))) {
Fam Zheng07931692017-02-09 16:40:47 +0800690 progress = true;
Stefan Hajnoczi23425cc2016-12-01 19:26:47 +0000691 ret = virtio_scsi_handle_cmd_req_prepare(s, req);
692 if (!ret) {
693 QTAILQ_INSERT_TAIL(&reqs, req, next);
694 } else if (ret == -EINVAL) {
695 /* The device is broken and shouldn't process any request */
696 while (!QTAILQ_EMPTY(&reqs)) {
697 req = QTAILQ_FIRST(&reqs);
698 QTAILQ_REMOVE(&reqs, req, next);
699 blk_io_unplug(req->sreq->dev->conf.blk);
700 scsi_req_unref(req->sreq);
701 virtqueue_detach_element(req->vq, &req->elem, 0);
702 virtio_scsi_free_req(req);
703 }
Greg Kurz661e32f2016-09-30 17:13:40 +0200704 }
Fam Zheng359eea72014-09-23 15:49:27 +0800705 }
Stefan Hajnoczi23425cc2016-12-01 19:26:47 +0000706
Stefan Hajnoczid0435bc2019-12-09 21:09:57 +0000707 if (suppress_notifications) {
708 virtio_queue_set_notification(vq, 1);
709 }
Stefan Hajnoczi23425cc2016-12-01 19:26:47 +0000710 } while (ret != -EINVAL && !virtio_queue_empty(vq));
Fam Zheng1880ad42014-09-23 15:49:28 +0800711
712 QTAILQ_FOREACH_SAFE(req, &reqs, next, next) {
713 virtio_scsi_handle_cmd_req_submit(s, req);
714 }
Fam Zheng07931692017-02-09 16:40:47 +0800715 return progress;
Stefan Hajnoczi973abc72011-02-11 08:40:59 +0000716}
717
Paolo Bonzinia8f2e5c2016-04-06 12:16:27 +0200718static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq)
719{
720 /* use non-QOM casts in the data path */
721 VirtIOSCSI *s = (VirtIOSCSI *)vdev;
722
Stefan Hajnoczif34e8d82021-12-07 13:23:34 +0000723 if (s->ctx && !s->dataplane_started) {
Paolo Bonziniad07cd62016-10-21 22:48:10 +0200724 virtio_device_start_ioeventfd(vdev);
Paolo Bonzinia8f2e5c2016-04-06 12:16:27 +0200725 if (!s->dataplane_fenced) {
726 return;
727 }
728 }
Fam Zheng71407782017-03-17 14:14:47 +0800729 virtio_scsi_acquire(s);
Paolo Bonzinia8f2e5c2016-04-06 12:16:27 +0200730 virtio_scsi_handle_cmd_vq(s, vq);
Fam Zheng71407782017-03-17 14:14:47 +0800731 virtio_scsi_release(s);
Paolo Bonzinia8f2e5c2016-04-06 12:16:27 +0200732}
733
Stefan Hajnoczi973abc72011-02-11 08:40:59 +0000734static void virtio_scsi_get_config(VirtIODevice *vdev,
735 uint8_t *config)
736{
737 VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config;
Paolo Bonzini292c8e52013-03-29 01:08:15 +0000738 VirtIOSCSICommon *s = VIRTIO_SCSI_COMMON(vdev);
Stefan Hajnoczi973abc72011-02-11 08:40:59 +0000739
Rusty Russell8c085db2014-06-24 19:48:53 +0200740 virtio_stl_p(vdev, &scsiconf->num_queues, s->conf.num_queues);
Denis Plotnikov1bf8a982019-12-20 17:09:04 +0300741 virtio_stl_p(vdev, &scsiconf->seg_max,
742 s->conf.seg_max_adjust ? s->conf.virtqueue_size - 2 : 128 - 2);
Rusty Russell8c085db2014-06-24 19:48:53 +0200743 virtio_stl_p(vdev, &scsiconf->max_sectors, s->conf.max_sectors);
744 virtio_stl_p(vdev, &scsiconf->cmd_per_lun, s->conf.cmd_per_lun);
745 virtio_stl_p(vdev, &scsiconf->event_info_size, sizeof(VirtIOSCSIEvent));
746 virtio_stl_p(vdev, &scsiconf->sense_size, s->sense_size);
747 virtio_stl_p(vdev, &scsiconf->cdb_size, s->cdb_size);
748 virtio_stw_p(vdev, &scsiconf->max_channel, VIRTIO_SCSI_MAX_CHANNEL);
749 virtio_stw_p(vdev, &scsiconf->max_target, VIRTIO_SCSI_MAX_TARGET);
750 virtio_stl_p(vdev, &scsiconf->max_lun, VIRTIO_SCSI_MAX_LUN);
Stefan Hajnoczi973abc72011-02-11 08:40:59 +0000751}
752
753static void virtio_scsi_set_config(VirtIODevice *vdev,
754 const uint8_t *config)
755{
756 VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config;
Paolo Bonzini292c8e52013-03-29 01:08:15 +0000757 VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
Stefan Hajnoczi973abc72011-02-11 08:40:59 +0000758
Rusty Russell8c085db2014-06-24 19:48:53 +0200759 if ((uint32_t) virtio_ldl_p(vdev, &scsiconf->sense_size) >= 65536 ||
760 (uint32_t) virtio_ldl_p(vdev, &scsiconf->cdb_size) >= 256) {
Greg Kurzad14a462016-09-30 17:13:48 +0200761 virtio_error(vdev,
762 "bad data written to virtio-scsi configuration space");
763 return;
Stefan Hajnoczi973abc72011-02-11 08:40:59 +0000764 }
765
Rusty Russell8c085db2014-06-24 19:48:53 +0200766 vs->sense_size = virtio_ldl_p(vdev, &scsiconf->sense_size);
767 vs->cdb_size = virtio_ldl_p(vdev, &scsiconf->cdb_size);
Stefan Hajnoczi973abc72011-02-11 08:40:59 +0000768}
769
Gerd Hoffmann019a3ed2015-06-01 10:45:40 +0200770static uint64_t virtio_scsi_get_features(VirtIODevice *vdev,
Jason Wang9d5b7312015-07-27 17:49:19 +0800771 uint64_t requested_features,
772 Error **errp)
Stefan Hajnoczi973abc72011-02-11 08:40:59 +0000773{
Shannon Zhaoda2f84d2015-04-28 19:51:13 +0800774 VirtIOSCSI *s = VIRTIO_SCSI(vdev);
775
776 /* Firstly sync all virtio-scsi possible supported features */
777 requested_features |= s->host_features;
Stefan Hajnoczi973abc72011-02-11 08:40:59 +0000778 return requested_features;
779}
780
781static void virtio_scsi_reset(VirtIODevice *vdev)
782{
Paolo Bonzini292c8e52013-03-29 01:08:15 +0000783 VirtIOSCSI *s = VIRTIO_SCSI(vdev);
784 VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
Stefan Hajnoczi973abc72011-02-11 08:40:59 +0000785
Paolo Bonziniad07cd62016-10-21 22:48:10 +0200786 assert(!s->dataplane_started);
Paolo Bonzini47a150a2013-01-10 15:49:08 +0100787 s->resetting++;
Philippe Mathieu-Daudé824755b2019-05-28 18:40:12 +0200788 qbus_reset_all(BUS(&s->bus));
Paolo Bonzini47a150a2013-01-10 15:49:08 +0100789 s->resetting--;
790
Michael S. Tsirkin03325522015-03-11 14:31:29 +0100791 vs->sense_size = VIRTIO_SCSI_SENSE_DEFAULT_SIZE;
792 vs->cdb_size = VIRTIO_SCSI_CDB_DEFAULT_SIZE;
Paolo Bonzini2baa1be2012-07-16 14:50:27 +0200793 s->events_dropped = false;
Stefan Hajnoczi973abc72011-02-11 08:40:59 +0000794}
795
Fam Zheng20e6dca2014-08-06 13:35:05 +0800796void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev,
797 uint32_t event, uint32_t reason)
Cong Mengb6866fe2012-06-20 14:47:11 +0800798{
Paolo Bonzini292c8e52013-03-29 01:08:15 +0000799 VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
Markus Armbruster91e7fcc2014-05-16 17:44:06 +0200800 VirtIOSCSIReq *req;
Cong Mengb6866fe2012-06-20 14:47:11 +0800801 VirtIOSCSIEvent *evt;
KONRAD Frederic0ac8e132013-03-21 15:15:18 +0100802 VirtIODevice *vdev = VIRTIO_DEVICE(s);
Cong Mengb6866fe2012-06-20 14:47:11 +0800803
KONRAD Frederic0ac8e132013-03-21 15:15:18 +0100804 if (!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) {
Paolo Bonzinicd41a672012-10-08 16:50:51 +0200805 return;
806 }
807
Paolo Bonzinie24a47c2016-02-14 18:17:10 +0100808 req = virtio_scsi_pop_req(s, vs->event_vq);
Paolo Bonzini64f64852012-07-02 10:47:35 +0200809 if (!req) {
810 s->events_dropped = true;
Fam Zheng71407782017-03-17 14:14:47 +0800811 return;
Paolo Bonzini64f64852012-07-02 10:47:35 +0200812 }
Cong Mengb6866fe2012-06-20 14:47:11 +0800813
Paolo Bonzini64f64852012-07-02 10:47:35 +0200814 if (s->events_dropped) {
815 event |= VIRTIO_SCSI_T_EVENTS_MISSED;
816 s->events_dropped = false;
817 }
818
Greg Kurzdfecbb92014-06-30 17:33:18 +0200819 if (virtio_scsi_parse_req(req, 0, sizeof(VirtIOSCSIEvent))) {
Greg Kurz661e32f2016-09-30 17:13:40 +0200820 virtio_scsi_bad_req(req);
Fam Zheng71407782017-03-17 14:14:47 +0800821 return;
Paolo Bonzini64f64852012-07-02 10:47:35 +0200822 }
823
Paolo Bonzini3eff1f42014-06-10 16:40:31 +0200824 evt = &req->resp.event;
Paolo Bonzini64f64852012-07-02 10:47:35 +0200825 memset(evt, 0, sizeof(VirtIOSCSIEvent));
Cédric Le Goater424baff2014-06-30 17:17:17 +0200826 evt->event = virtio_tswap32(vdev, event);
827 evt->reason = virtio_tswap32(vdev, reason);
Paolo Bonzini64f64852012-07-02 10:47:35 +0200828 if (!dev) {
Eric Farman49fb65c2014-01-14 14:16:26 -0500829 assert(event == VIRTIO_SCSI_T_EVENTS_MISSED);
Paolo Bonzini64f64852012-07-02 10:47:35 +0200830 } else {
Cong Mengb6866fe2012-06-20 14:47:11 +0800831 evt->lun[0] = 1;
832 evt->lun[1] = dev->id;
833
834 /* Linux wants us to keep the same encoding we use for REPORT LUNS. */
835 if (dev->lun >= 256) {
836 evt->lun[2] = (dev->lun >> 8) | 0x40;
837 }
838 evt->lun[3] = dev->lun & 0xFF;
Paolo Bonzini64f64852012-07-02 10:47:35 +0200839 }
Hannes Reineckeeb8cb3d2020-11-16 19:31:12 +0100840 trace_virtio_scsi_event(virtio_scsi_get_lun(evt->lun), event, reason);
841
Paolo Bonzini64f64852012-07-02 10:47:35 +0200842 virtio_scsi_complete_req(req);
843}
844
Fam Zheng07931692017-02-09 16:40:47 +0800845bool virtio_scsi_handle_event_vq(VirtIOSCSI *s, VirtQueue *vq)
Paolo Bonzinia8f2e5c2016-04-06 12:16:27 +0200846{
847 if (s->events_dropped) {
848 virtio_scsi_push_event(s, NULL, VIRTIO_SCSI_T_NO_EVENT, 0);
Fam Zheng07931692017-02-09 16:40:47 +0800849 return true;
Paolo Bonzinia8f2e5c2016-04-06 12:16:27 +0200850 }
Fam Zheng07931692017-02-09 16:40:47 +0800851 return false;
Paolo Bonzinia8f2e5c2016-04-06 12:16:27 +0200852}
853
Paolo Bonzini64f64852012-07-02 10:47:35 +0200854static void virtio_scsi_handle_event(VirtIODevice *vdev, VirtQueue *vq)
855{
KONRAD Frederic0ac8e132013-03-21 15:15:18 +0100856 VirtIOSCSI *s = VIRTIO_SCSI(vdev);
Paolo Bonzini64f64852012-07-02 10:47:35 +0200857
Paolo Bonzinia8f2e5c2016-04-06 12:16:27 +0200858 if (s->ctx) {
Paolo Bonziniad07cd62016-10-21 22:48:10 +0200859 virtio_device_start_ioeventfd(vdev);
Paolo Bonzinia8f2e5c2016-04-06 12:16:27 +0200860 if (!s->dataplane_fenced) {
861 return;
862 }
Fam Zheng63c7e542014-09-23 15:49:25 +0800863 }
Fam Zheng71407782017-03-17 14:14:47 +0800864 virtio_scsi_acquire(s);
Paolo Bonzinia8f2e5c2016-04-06 12:16:27 +0200865 virtio_scsi_handle_event_vq(s, vq);
Fam Zheng71407782017-03-17 14:14:47 +0800866 virtio_scsi_release(s);
Cong Mengb6866fe2012-06-20 14:47:11 +0800867}
868
Paolo Bonzinifeda01e2012-07-16 14:22:52 +0200869static void virtio_scsi_change(SCSIBus *bus, SCSIDevice *dev, SCSISense sense)
870{
871 VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus);
KONRAD Frederic0ac8e132013-03-21 15:15:18 +0100872 VirtIODevice *vdev = VIRTIO_DEVICE(s);
Paolo Bonzinifeda01e2012-07-16 14:22:52 +0200873
Cornelia Huck95129d62015-08-17 11:48:29 +0200874 if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_CHANGE) &&
Paolo Bonzinifeda01e2012-07-16 14:22:52 +0200875 dev->type != TYPE_ROM) {
Fam Zheng71407782017-03-17 14:14:47 +0800876 virtio_scsi_acquire(s);
Paolo Bonzinifeda01e2012-07-16 14:22:52 +0200877 virtio_scsi_push_event(s, dev, VIRTIO_SCSI_T_PARAM_CHANGE,
878 sense.asc | (sense.ascq << 8));
Fam Zheng71407782017-03-17 14:14:47 +0800879 virtio_scsi_release(s);
Paolo Bonzinifeda01e2012-07-16 14:22:52 +0200880 }
881}
882
Kevin Wolf4f71fb42019-04-26 19:29:47 +0200883static void virtio_scsi_pre_hotplug(HotplugHandler *hotplug_dev,
884 DeviceState *dev, Error **errp)
885{
886 SCSIDevice *sd = SCSI_DEVICE(dev);
887 sd->hba_supports_iothread = true;
888}
889
Igor Mammedov02206e52014-09-26 09:28:33 +0000890static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev,
891 Error **errp)
Cong Mengb6866fe2012-06-20 14:47:11 +0800892{
Igor Mammedov02206e52014-09-26 09:28:33 +0000893 VirtIODevice *vdev = VIRTIO_DEVICE(hotplug_dev);
Fam Zheng3e2b2a92014-10-19 12:47:42 +0800894 VirtIOSCSI *s = VIRTIO_SCSI(vdev);
895 SCSIDevice *sd = SCSI_DEVICE(dev);
Sergio Lopezc7040ff2020-12-14 18:05:16 +0100896 AioContext *old_context;
Kevin Wolf97896a42019-05-02 11:10:59 +0200897 int ret;
Fam Zheng3e2b2a92014-10-19 12:47:42 +0800898
Paolo Bonzini43c696a2016-04-06 12:16:24 +0200899 if (s->ctx && !s->dataplane_fenced) {
Fam Zheng3e2b2a92014-10-19 12:47:42 +0800900 if (blk_op_is_blocked(sd->conf.blk, BLOCK_OP_TYPE_DATAPLANE, errp)) {
901 return;
902 }
Sergio Lopezc7040ff2020-12-14 18:05:16 +0100903 old_context = blk_get_aio_context(sd->conf.blk);
904 aio_context_acquire(old_context);
Kevin Wolf97896a42019-05-02 11:10:59 +0200905 ret = blk_set_aio_context(sd->conf.blk, s->ctx, errp);
Sergio Lopezc7040ff2020-12-14 18:05:16 +0100906 aio_context_release(old_context);
Kevin Wolf97896a42019-05-02 11:10:59 +0200907 if (ret < 0) {
908 return;
909 }
Igor Mammedov8b5e6ca2018-10-16 15:33:40 +0200910 }
Cong Mengb6866fe2012-06-20 14:47:11 +0800911
Cornelia Huck95129d62015-08-17 11:48:29 +0200912 if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) {
Fam Zheng71407782017-03-17 14:14:47 +0800913 virtio_scsi_acquire(s);
Fam Zheng3e2b2a92014-10-19 12:47:42 +0800914 virtio_scsi_push_event(s, sd,
Igor Mammedov02206e52014-09-26 09:28:33 +0000915 VIRTIO_SCSI_T_TRANSPORT_RESET,
Cong Mengb6866fe2012-06-20 14:47:11 +0800916 VIRTIO_SCSI_EVT_RESET_RESCAN);
Fam Zheng71407782017-03-17 14:14:47 +0800917 virtio_scsi_release(s);
Cong Mengb6866fe2012-06-20 14:47:11 +0800918 }
919}
920
Igor Mammedov02206e52014-09-26 09:28:33 +0000921static void virtio_scsi_hotunplug(HotplugHandler *hotplug_dev, DeviceState *dev,
922 Error **errp)
Cong Mengb6866fe2012-06-20 14:47:11 +0800923{
Igor Mammedov02206e52014-09-26 09:28:33 +0000924 VirtIODevice *vdev = VIRTIO_DEVICE(hotplug_dev);
Fam Zheng3e2b2a92014-10-19 12:47:42 +0800925 VirtIOSCSI *s = VIRTIO_SCSI(vdev);
926 SCSIDevice *sd = SCSI_DEVICE(dev);
Zhengui li9c5aad82019-07-22 23:05:20 +0200927 AioContext *ctx = s->ctx ?: qemu_get_aio_context();
Cong Mengb6866fe2012-06-20 14:47:11 +0800928
Cornelia Huck95129d62015-08-17 11:48:29 +0200929 if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) {
Fam Zheng71407782017-03-17 14:14:47 +0800930 virtio_scsi_acquire(s);
Fam Zheng3e2b2a92014-10-19 12:47:42 +0800931 virtio_scsi_push_event(s, sd,
Igor Mammedov02206e52014-09-26 09:28:33 +0000932 VIRTIO_SCSI_T_TRANSPORT_RESET,
Cong Mengb6866fe2012-06-20 14:47:11 +0800933 VIRTIO_SCSI_EVT_RESET_REMOVED);
Fam Zheng71407782017-03-17 14:14:47 +0800934 virtio_scsi_release(s);
Cong Mengb6866fe2012-06-20 14:47:11 +0800935 }
Fam Zheng3e2b2a92014-10-19 12:47:42 +0800936
Zhengui li9c5aad82019-07-22 23:05:20 +0200937 aio_disable_external(ctx);
938 qdev_simple_device_unplug_cb(hotplug_dev, dev, errp);
939 aio_enable_external(ctx);
940
Alberto Garciaa6f230c2019-01-22 17:53:21 +0200941 if (s->ctx) {
942 virtio_scsi_acquire(s);
Kevin Wolf97896a42019-05-02 11:10:59 +0200943 /* If other users keep the BlockBackend in the iothread, that's ok */
944 blk_set_aio_context(sd->conf.blk, qemu_get_aio_context(), NULL);
Alberto Garciaa6f230c2019-01-22 17:53:21 +0200945 virtio_scsi_release(s);
946 }
Cong Mengb6866fe2012-06-20 14:47:11 +0800947}
948
Paolo Bonzini2ccdcd82011-11-14 16:58:41 +0100949static struct SCSIBusInfo virtio_scsi_scsi_info = {
950 .tcq = true,
951 .max_channel = VIRTIO_SCSI_MAX_CHANNEL,
952 .max_target = VIRTIO_SCSI_MAX_TARGET,
953 .max_lun = VIRTIO_SCSI_MAX_LUN,
954
955 .complete = virtio_scsi_command_complete,
Hannes Reineckef3126d62021-02-24 19:14:50 +0100956 .fail = virtio_scsi_command_failed,
Paolo Bonzini2ccdcd82011-11-14 16:58:41 +0100957 .cancel = virtio_scsi_request_cancelled,
Paolo Bonzinifeda01e2012-07-16 14:22:52 +0200958 .change = virtio_scsi_change,
Paolo Bonzini33cbb2c2014-07-16 11:04:37 +0200959 .parse_cdb = virtio_scsi_parse_cdb,
Paolo Bonzini2ccdcd82011-11-14 16:58:41 +0100960 .get_sg_list = virtio_scsi_get_sg_list,
Paolo Bonzini5db17642011-12-02 15:23:15 +0100961 .save_request = virtio_scsi_save_request,
962 .load_request = virtio_scsi_load_request,
Paolo Bonzini2ccdcd82011-11-14 16:58:41 +0100963};
964
Fam Zhengbf46e672017-04-21 20:27:07 +0800965void virtio_scsi_common_realize(DeviceState *dev,
Fam Zheng209b27b2016-07-13 13:09:48 +0800966 VirtIOHandleOutput ctrl,
967 VirtIOHandleOutput evt,
Fam Zhengbf46e672017-04-21 20:27:07 +0800968 VirtIOHandleOutput cmd,
969 Error **errp)
Stefan Hajnoczi973abc72011-02-11 08:40:59 +0000970{
Andreas Färber71a65202013-07-30 03:19:55 +0200971 VirtIODevice *vdev = VIRTIO_DEVICE(dev);
972 VirtIOSCSICommon *s = VIRTIO_SCSI_COMMON(dev);
Paolo Bonzinid2ad7dd2012-04-06 10:39:46 +0200973 int i;
Stefan Hajnoczi973abc72011-02-11 08:40:59 +0000974
Andreas Färber7598f0f2013-07-30 05:41:42 +0200975 virtio_init(vdev, "virtio-scsi", VIRTIO_ID_SCSI,
KONRAD Frederic763684b2013-03-21 15:15:19 +0100976 sizeof(VirtIOSCSIConfig));
KONRAD Frederic3ab1dfd2013-03-21 15:15:14 +0100977
Stefan Hajnoczi6a558822020-08-18 15:33:46 +0100978 if (s->conf.num_queues == VIRTIO_SCSI_AUTO_NUM_QUEUES) {
979 s->conf.num_queues = 1;
980 }
Fam Zheng0ba1f532014-10-31 11:04:31 +0800981 if (s->conf.num_queues == 0 ||
Stefan Hajnoczi4e5163b2020-08-18 15:33:45 +0100982 s->conf.num_queues > VIRTIO_QUEUE_MAX - VIRTIO_SCSI_VQ_NUM_FIXED) {
Fam Zheng0ba1f532014-10-31 11:04:31 +0800983 error_setg(errp, "Invalid number of queues (= %" PRIu32 "), "
Fam Zhengc9f65522014-08-26 14:30:30 +0800984 "must be a positive integer less than %d.",
Stefan Hajnoczi4e5163b2020-08-18 15:33:45 +0100985 s->conf.num_queues,
986 VIRTIO_QUEUE_MAX - VIRTIO_SCSI_VQ_NUM_FIXED);
Fam Zheng93bd49a2014-10-30 19:50:26 +0800987 virtio_cleanup(vdev);
Fam Zhengc9f65522014-08-26 14:30:30 +0800988 return;
989 }
Denis Plotnikov1bf8a982019-12-20 17:09:04 +0300990 if (s->conf.virtqueue_size <= 2) {
991 error_setg(errp, "invalid virtqueue_size property (= %" PRIu32 "), "
992 "must be > 2", s->conf.virtqueue_size);
993 return;
994 }
Markus Armbruster3c55fe22014-12-04 14:12:45 +0100995 s->cmd_vqs = g_new0(VirtQueue *, s->conf.num_queues);
Michael S. Tsirkin03325522015-03-11 14:31:29 +0100996 s->sense_size = VIRTIO_SCSI_SENSE_DEFAULT_SIZE;
997 s->cdb_size = VIRTIO_SCSI_CDB_DEFAULT_SIZE;
KONRAD Frederic3ab1dfd2013-03-21 15:15:14 +0100998
Richard W.M. Jones5c0919d2017-08-10 17:52:55 +0100999 s->ctrl_vq = virtio_add_queue(vdev, s->conf.virtqueue_size, ctrl);
1000 s->event_vq = virtio_add_queue(vdev, s->conf.virtqueue_size, evt);
KONRAD Frederic394e2e42013-03-21 15:15:11 +01001001 for (i = 0; i < s->conf.num_queues; i++) {
Richard W.M. Jones5c0919d2017-08-10 17:52:55 +01001002 s->cmd_vqs[i] = virtio_add_queue(vdev, s->conf.virtqueue_size, cmd);
Fam Zheng9786b592014-09-23 15:49:30 +08001003 }
Paolo Bonzini292c8e52013-03-29 01:08:15 +00001004}
1005
Andreas Färber71a65202013-07-30 03:19:55 +02001006static void virtio_scsi_device_realize(DeviceState *dev, Error **errp)
Paolo Bonzini292c8e52013-03-29 01:08:15 +00001007{
Andreas Färber71a65202013-07-30 03:19:55 +02001008 VirtIODevice *vdev = VIRTIO_DEVICE(dev);
Andreas Färber7598f0f2013-07-30 05:41:42 +02001009 VirtIOSCSI *s = VIRTIO_SCSI(dev);
Andreas Färbercaad4eb2013-07-21 12:16:34 +02001010 Error *err = NULL;
Paolo Bonzini292c8e52013-03-29 01:08:15 +00001011
Fam Zhengbf46e672017-04-21 20:27:07 +08001012 virtio_scsi_common_realize(dev,
1013 virtio_scsi_handle_ctrl,
Ming Lei91d670f2014-06-19 16:12:00 +08001014 virtio_scsi_handle_event,
Fam Zhengbf46e672017-04-21 20:27:07 +08001015 virtio_scsi_handle_cmd,
1016 &err);
Andreas Färber71a65202013-07-30 03:19:55 +02001017 if (err != NULL) {
1018 error_propagate(errp, err);
1019 return;
Paolo Bonzini292c8e52013-03-29 01:08:15 +00001020 }
1021
Peter Maydell739e95f2021-09-23 13:11:48 +01001022 scsi_bus_init_named(&s->bus, sizeof(s->bus), dev,
1023 &virtio_scsi_scsi_info, vdev->bus_name);
Igor Mammedov02206e52014-09-26 09:28:33 +00001024 /* override default SCSI bus hotplug-handler, with virtio-scsi's one */
Markus Armbruster9bc6bfd2020-06-30 11:03:39 +02001025 qbus_set_hotplug_handler(BUS(&s->bus), OBJECT(dev));
KONRAD Frederic6f32a6b2013-04-30 16:08:51 +02001026
Paolo Bonziniad07cd62016-10-21 22:48:10 +02001027 virtio_scsi_dataplane_setup(s, errp);
KONRAD Frederic3ab1dfd2013-03-21 15:15:14 +01001028}
1029
Paolo Bonzini12e1dc42019-07-17 11:46:50 +02001030void virtio_scsi_common_unrealize(DeviceState *dev)
KONRAD Frederic3ab1dfd2013-03-21 15:15:14 +01001031{
Andreas Färber306ec6c2013-07-30 03:50:44 +02001032 VirtIODevice *vdev = VIRTIO_DEVICE(dev);
1033 VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev);
Pan Nengyuanc9c0ed62020-01-17 15:55:46 +08001034 int i;
KONRAD Frederic3ab1dfd2013-03-21 15:15:14 +01001035
Pan Nengyuan36fc9bd2020-01-17 15:55:47 +08001036 virtio_delete_queue(vs->ctrl_vq);
1037 virtio_delete_queue(vs->event_vq);
Pan Nengyuanc9c0ed62020-01-17 15:55:46 +08001038 for (i = 0; i < vs->conf.num_queues; i++) {
Pan Nengyuan36fc9bd2020-01-17 15:55:47 +08001039 virtio_delete_queue(vs->cmd_vqs[i]);
Pan Nengyuanc9c0ed62020-01-17 15:55:46 +08001040 }
Paolo Bonzini292c8e52013-03-29 01:08:15 +00001041 g_free(vs->cmd_vqs);
KONRAD Frederic6a1a8cc2013-04-24 10:21:22 +02001042 virtio_cleanup(vdev);
KONRAD Frederic3ab1dfd2013-03-21 15:15:14 +01001043}
1044
Markus Armbrusterb69c3c22020-05-05 17:29:24 +02001045static void virtio_scsi_device_unrealize(DeviceState *dev)
Paolo Bonzini292c8e52013-03-29 01:08:15 +00001046{
Fam Zheng2cbe2de2017-05-18 18:28:08 +08001047 VirtIOSCSI *s = VIRTIO_SCSI(dev);
1048
Markus Armbruster9bc6bfd2020-06-30 11:03:39 +02001049 qbus_set_hotplug_handler(BUS(&s->bus), NULL);
Paolo Bonzini12e1dc42019-07-17 11:46:50 +02001050 virtio_scsi_common_unrealize(dev);
Paolo Bonzini292c8e52013-03-29 01:08:15 +00001051}
1052
KONRAD Frederic3ab1dfd2013-03-21 15:15:14 +01001053static Property virtio_scsi_properties[] = {
Stefan Hajnoczi6a558822020-08-18 15:33:46 +01001054 DEFINE_PROP_UINT32("num_queues", VirtIOSCSI, parent_obj.conf.num_queues,
1055 VIRTIO_SCSI_AUTO_NUM_QUEUES),
Richard W.M. Jones5c0919d2017-08-10 17:52:55 +01001056 DEFINE_PROP_UINT32("virtqueue_size", VirtIOSCSI,
Denis Plotnikovc9b7d9e2020-02-14 10:46:48 +03001057 parent_obj.conf.virtqueue_size, 256),
Denis Plotnikov1bf8a982019-12-20 17:09:04 +03001058 DEFINE_PROP_BOOL("seg_max_adjust", VirtIOSCSI,
1059 parent_obj.conf.seg_max_adjust, true),
Shannon Zhao0c632372015-06-10 23:04:32 +08001060 DEFINE_PROP_UINT32("max_sectors", VirtIOSCSI, parent_obj.conf.max_sectors,
1061 0xFFFF),
1062 DEFINE_PROP_UINT32("cmd_per_lun", VirtIOSCSI, parent_obj.conf.cmd_per_lun,
1063 128),
Shannon Zhao0c632372015-06-10 23:04:32 +08001064 DEFINE_PROP_BIT("hotplug", VirtIOSCSI, host_features,
1065 VIRTIO_SCSI_F_HOTPLUG, true),
1066 DEFINE_PROP_BIT("param_change", VirtIOSCSI, host_features,
1067 VIRTIO_SCSI_F_CHANGE, true),
Fam Zheng08f1ecd2017-07-14 10:14:56 +08001068 DEFINE_PROP_LINK("iothread", VirtIOSCSI, parent_obj.conf.iothread,
1069 TYPE_IOTHREAD, IOThread *),
KONRAD Frederic3ab1dfd2013-03-21 15:15:14 +01001070 DEFINE_PROP_END_OF_LIST(),
1071};
1072
Halil Pasicf20476b2016-10-06 14:55:46 +02001073static const VMStateDescription vmstate_virtio_scsi = {
1074 .name = "virtio-scsi",
1075 .minimum_version_id = 1,
1076 .version_id = 1,
1077 .fields = (VMStateField[]) {
1078 VMSTATE_VIRTIO_DEVICE,
1079 VMSTATE_END_OF_LIST()
1080 },
1081};
Dr. David Alan Gilbert5a289a22016-07-14 18:22:46 +01001082
Paolo Bonzini292c8e52013-03-29 01:08:15 +00001083static void virtio_scsi_common_class_init(ObjectClass *klass, void *data)
1084{
1085 VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
Marcel Apfelbaum125ee0e2013-07-29 17:17:45 +03001086 DeviceClass *dc = DEVICE_CLASS(klass);
Paolo Bonzini292c8e52013-03-29 01:08:15 +00001087
1088 vdc->get_config = virtio_scsi_get_config;
Marcel Apfelbaum125ee0e2013-07-29 17:17:45 +03001089 set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
Paolo Bonzini292c8e52013-03-29 01:08:15 +00001090}
1091
KONRAD Frederic3ab1dfd2013-03-21 15:15:14 +01001092static void virtio_scsi_class_init(ObjectClass *klass, void *data)
1093{
1094 DeviceClass *dc = DEVICE_CLASS(klass);
1095 VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
Igor Mammedov02206e52014-09-26 09:28:33 +00001096 HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
Andreas Färber71a65202013-07-30 03:19:55 +02001097
Marc-André Lureau4f67d302020-01-10 19:30:32 +04001098 device_class_set_props(dc, virtio_scsi_properties);
Dr. David Alan Gilbert5a289a22016-07-14 18:22:46 +01001099 dc->vmsd = &vmstate_virtio_scsi;
Marcel Apfelbaum125ee0e2013-07-29 17:17:45 +03001100 set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
Andreas Färber71a65202013-07-30 03:19:55 +02001101 vdc->realize = virtio_scsi_device_realize;
Andreas Färber306ec6c2013-07-30 03:50:44 +02001102 vdc->unrealize = virtio_scsi_device_unrealize;
KONRAD Frederic3ab1dfd2013-03-21 15:15:14 +01001103 vdc->set_config = virtio_scsi_set_config;
1104 vdc->get_features = virtio_scsi_get_features;
1105 vdc->reset = virtio_scsi_reset;
Paolo Bonziniad07cd62016-10-21 22:48:10 +02001106 vdc->start_ioeventfd = virtio_scsi_dataplane_start;
1107 vdc->stop_ioeventfd = virtio_scsi_dataplane_stop;
Kevin Wolf4f71fb42019-04-26 19:29:47 +02001108 hc->pre_plug = virtio_scsi_pre_hotplug;
Igor Mammedov02206e52014-09-26 09:28:33 +00001109 hc->plug = virtio_scsi_hotplug;
1110 hc->unplug = virtio_scsi_hotunplug;
KONRAD Frederic3ab1dfd2013-03-21 15:15:14 +01001111}
1112
Paolo Bonzini292c8e52013-03-29 01:08:15 +00001113static const TypeInfo virtio_scsi_common_info = {
1114 .name = TYPE_VIRTIO_SCSI_COMMON,
1115 .parent = TYPE_VIRTIO_DEVICE,
1116 .instance_size = sizeof(VirtIOSCSICommon),
Markus Armbrustera27292b2013-08-19 17:53:15 +02001117 .abstract = true,
Paolo Bonzini292c8e52013-03-29 01:08:15 +00001118 .class_init = virtio_scsi_common_class_init,
1119};
1120
KONRAD Frederic3ab1dfd2013-03-21 15:15:14 +01001121static const TypeInfo virtio_scsi_info = {
1122 .name = TYPE_VIRTIO_SCSI,
Paolo Bonzini292c8e52013-03-29 01:08:15 +00001123 .parent = TYPE_VIRTIO_SCSI_COMMON,
KONRAD Frederic3ab1dfd2013-03-21 15:15:14 +01001124 .instance_size = sizeof(VirtIOSCSI),
1125 .class_init = virtio_scsi_class_init,
Igor Mammedov02206e52014-09-26 09:28:33 +00001126 .interfaces = (InterfaceInfo[]) {
1127 { TYPE_HOTPLUG_HANDLER },
1128 { }
1129 }
KONRAD Frederic3ab1dfd2013-03-21 15:15:14 +01001130};
1131
1132static void virtio_register_types(void)
1133{
Paolo Bonzini292c8e52013-03-29 01:08:15 +00001134 type_register_static(&virtio_scsi_common_info);
KONRAD Frederic3ab1dfd2013-03-21 15:15:14 +01001135 type_register_static(&virtio_scsi_info);
1136}
1137
1138type_init(virtio_register_types)