root / hw / virtio-scsi.c @ 16fd921b
History | View | Annotate | Download (18.6 kB)
1 | 973abc7f | Stefan Hajnoczi | /*
|
---|---|---|---|
2 | 973abc7f | Stefan Hajnoczi | * Virtio SCSI HBA
|
3 | 973abc7f | Stefan Hajnoczi | *
|
4 | 973abc7f | Stefan Hajnoczi | * Copyright IBM, Corp. 2010
|
5 | 973abc7f | Stefan Hajnoczi | * Copyright Red Hat, Inc. 2011
|
6 | 973abc7f | Stefan Hajnoczi | *
|
7 | 973abc7f | Stefan Hajnoczi | * Authors:
|
8 | 973abc7f | Stefan Hajnoczi | * Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
|
9 | 973abc7f | Stefan Hajnoczi | * Paolo Bonzini <pbonzini@redhat.com>
|
10 | 973abc7f | Stefan Hajnoczi | *
|
11 | 973abc7f | Stefan Hajnoczi | * This work is licensed under the terms of the GNU GPL, version 2 or later.
|
12 | 973abc7f | Stefan Hajnoczi | * See the COPYING file in the top-level directory.
|
13 | 973abc7f | Stefan Hajnoczi | *
|
14 | 973abc7f | Stefan Hajnoczi | */
|
15 | 973abc7f | Stefan Hajnoczi | |
16 | 973abc7f | Stefan Hajnoczi | #include "virtio-scsi.h" |
17 | 973abc7f | Stefan Hajnoczi | #include <hw/scsi.h> |
18 | 973abc7f | Stefan Hajnoczi | #include <hw/scsi-defs.h> |
19 | 973abc7f | Stefan Hajnoczi | |
20 | 973abc7f | Stefan Hajnoczi | #define VIRTIO_SCSI_VQ_SIZE 128 |
21 | 973abc7f | Stefan Hajnoczi | #define VIRTIO_SCSI_CDB_SIZE 32 |
22 | 973abc7f | Stefan Hajnoczi | #define VIRTIO_SCSI_SENSE_SIZE 96 |
23 | 973abc7f | Stefan Hajnoczi | #define VIRTIO_SCSI_MAX_CHANNEL 0 |
24 | 973abc7f | Stefan Hajnoczi | #define VIRTIO_SCSI_MAX_TARGET 255 |
25 | 973abc7f | Stefan Hajnoczi | #define VIRTIO_SCSI_MAX_LUN 16383 |
26 | 973abc7f | Stefan Hajnoczi | |
27 | 973abc7f | Stefan Hajnoczi | /* Response codes */
|
28 | 973abc7f | Stefan Hajnoczi | #define VIRTIO_SCSI_S_OK 0 |
29 | 973abc7f | Stefan Hajnoczi | #define VIRTIO_SCSI_S_OVERRUN 1 |
30 | 973abc7f | Stefan Hajnoczi | #define VIRTIO_SCSI_S_ABORTED 2 |
31 | 973abc7f | Stefan Hajnoczi | #define VIRTIO_SCSI_S_BAD_TARGET 3 |
32 | 973abc7f | Stefan Hajnoczi | #define VIRTIO_SCSI_S_RESET 4 |
33 | 973abc7f | Stefan Hajnoczi | #define VIRTIO_SCSI_S_BUSY 5 |
34 | 973abc7f | Stefan Hajnoczi | #define VIRTIO_SCSI_S_TRANSPORT_FAILURE 6 |
35 | 973abc7f | Stefan Hajnoczi | #define VIRTIO_SCSI_S_TARGET_FAILURE 7 |
36 | 973abc7f | Stefan Hajnoczi | #define VIRTIO_SCSI_S_NEXUS_FAILURE 8 |
37 | 973abc7f | Stefan Hajnoczi | #define VIRTIO_SCSI_S_FAILURE 9 |
38 | 973abc7f | Stefan Hajnoczi | #define VIRTIO_SCSI_S_FUNCTION_SUCCEEDED 10 |
39 | 973abc7f | Stefan Hajnoczi | #define VIRTIO_SCSI_S_FUNCTION_REJECTED 11 |
40 | 973abc7f | Stefan Hajnoczi | #define VIRTIO_SCSI_S_INCORRECT_LUN 12 |
41 | 973abc7f | Stefan Hajnoczi | |
42 | 973abc7f | Stefan Hajnoczi | /* Controlq type codes. */
|
43 | 973abc7f | Stefan Hajnoczi | #define VIRTIO_SCSI_T_TMF 0 |
44 | 973abc7f | Stefan Hajnoczi | #define VIRTIO_SCSI_T_AN_QUERY 1 |
45 | 973abc7f | Stefan Hajnoczi | #define VIRTIO_SCSI_T_AN_SUBSCRIBE 2 |
46 | 973abc7f | Stefan Hajnoczi | |
47 | 973abc7f | Stefan Hajnoczi | /* Valid TMF subtypes. */
|
48 | 973abc7f | Stefan Hajnoczi | #define VIRTIO_SCSI_T_TMF_ABORT_TASK 0 |
49 | 973abc7f | Stefan Hajnoczi | #define VIRTIO_SCSI_T_TMF_ABORT_TASK_SET 1 |
50 | 973abc7f | Stefan Hajnoczi | #define VIRTIO_SCSI_T_TMF_CLEAR_ACA 2 |
51 | 973abc7f | Stefan Hajnoczi | #define VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET 3 |
52 | 973abc7f | Stefan Hajnoczi | #define VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET 4 |
53 | 973abc7f | Stefan Hajnoczi | #define VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET 5 |
54 | 973abc7f | Stefan Hajnoczi | #define VIRTIO_SCSI_T_TMF_QUERY_TASK 6 |
55 | 973abc7f | Stefan Hajnoczi | #define VIRTIO_SCSI_T_TMF_QUERY_TASK_SET 7 |
56 | 973abc7f | Stefan Hajnoczi | |
57 | 973abc7f | Stefan Hajnoczi | /* Events. */
|
58 | 973abc7f | Stefan Hajnoczi | #define VIRTIO_SCSI_T_EVENTS_MISSED 0x80000000 |
59 | 973abc7f | Stefan Hajnoczi | #define VIRTIO_SCSI_T_NO_EVENT 0 |
60 | 973abc7f | Stefan Hajnoczi | #define VIRTIO_SCSI_T_TRANSPORT_RESET 1 |
61 | 973abc7f | Stefan Hajnoczi | #define VIRTIO_SCSI_T_ASYNC_NOTIFY 2 |
62 | 973abc7f | Stefan Hajnoczi | |
63 | 973abc7f | Stefan Hajnoczi | /* SCSI command request, followed by data-out */
|
64 | 973abc7f | Stefan Hajnoczi | typedef struct { |
65 | 973abc7f | Stefan Hajnoczi | uint8_t lun[8]; /* Logical Unit Number */ |
66 | 973abc7f | Stefan Hajnoczi | uint64_t tag; /* Command identifier */
|
67 | 973abc7f | Stefan Hajnoczi | uint8_t task_attr; /* Task attribute */
|
68 | 973abc7f | Stefan Hajnoczi | uint8_t prio; |
69 | 973abc7f | Stefan Hajnoczi | uint8_t crn; |
70 | 973abc7f | Stefan Hajnoczi | uint8_t cdb[]; |
71 | 973abc7f | Stefan Hajnoczi | } QEMU_PACKED VirtIOSCSICmdReq; |
72 | 973abc7f | Stefan Hajnoczi | |
73 | 973abc7f | Stefan Hajnoczi | /* Response, followed by sense data and data-in */
|
74 | 973abc7f | Stefan Hajnoczi | typedef struct { |
75 | 973abc7f | Stefan Hajnoczi | uint32_t sense_len; /* Sense data length */
|
76 | 973abc7f | Stefan Hajnoczi | uint32_t resid; /* Residual bytes in data buffer */
|
77 | 973abc7f | Stefan Hajnoczi | uint16_t status_qualifier; /* Status qualifier */
|
78 | 973abc7f | Stefan Hajnoczi | uint8_t status; /* Command completion status */
|
79 | 973abc7f | Stefan Hajnoczi | uint8_t response; /* Response values */
|
80 | 973abc7f | Stefan Hajnoczi | uint8_t sense[]; |
81 | 973abc7f | Stefan Hajnoczi | } QEMU_PACKED VirtIOSCSICmdResp; |
82 | 973abc7f | Stefan Hajnoczi | |
83 | 973abc7f | Stefan Hajnoczi | /* Task Management Request */
|
84 | 973abc7f | Stefan Hajnoczi | typedef struct { |
85 | 973abc7f | Stefan Hajnoczi | uint32_t type; |
86 | 973abc7f | Stefan Hajnoczi | uint32_t subtype; |
87 | 973abc7f | Stefan Hajnoczi | uint8_t lun[8];
|
88 | 973abc7f | Stefan Hajnoczi | uint64_t tag; |
89 | 973abc7f | Stefan Hajnoczi | } QEMU_PACKED VirtIOSCSICtrlTMFReq; |
90 | 973abc7f | Stefan Hajnoczi | |
91 | 973abc7f | Stefan Hajnoczi | typedef struct { |
92 | 973abc7f | Stefan Hajnoczi | uint8_t response; |
93 | 973abc7f | Stefan Hajnoczi | } QEMU_PACKED VirtIOSCSICtrlTMFResp; |
94 | 973abc7f | Stefan Hajnoczi | |
95 | 973abc7f | Stefan Hajnoczi | /* Asynchronous notification query/subscription */
|
96 | 973abc7f | Stefan Hajnoczi | typedef struct { |
97 | 973abc7f | Stefan Hajnoczi | uint32_t type; |
98 | 973abc7f | Stefan Hajnoczi | uint8_t lun[8];
|
99 | 973abc7f | Stefan Hajnoczi | uint32_t event_requested; |
100 | 973abc7f | Stefan Hajnoczi | } QEMU_PACKED VirtIOSCSICtrlANReq; |
101 | 973abc7f | Stefan Hajnoczi | |
102 | 973abc7f | Stefan Hajnoczi | typedef struct { |
103 | 973abc7f | Stefan Hajnoczi | uint32_t event_actual; |
104 | 973abc7f | Stefan Hajnoczi | uint8_t response; |
105 | 973abc7f | Stefan Hajnoczi | } QEMU_PACKED VirtIOSCSICtrlANResp; |
106 | 973abc7f | Stefan Hajnoczi | |
107 | 973abc7f | Stefan Hajnoczi | typedef struct { |
108 | 973abc7f | Stefan Hajnoczi | uint32_t event; |
109 | 973abc7f | Stefan Hajnoczi | uint8_t lun[8];
|
110 | 973abc7f | Stefan Hajnoczi | uint32_t reason; |
111 | 973abc7f | Stefan Hajnoczi | } QEMU_PACKED VirtIOSCSIEvent; |
112 | 973abc7f | Stefan Hajnoczi | |
113 | 973abc7f | Stefan Hajnoczi | typedef struct { |
114 | 973abc7f | Stefan Hajnoczi | uint32_t num_queues; |
115 | 973abc7f | Stefan Hajnoczi | uint32_t seg_max; |
116 | 973abc7f | Stefan Hajnoczi | uint32_t max_sectors; |
117 | 973abc7f | Stefan Hajnoczi | uint32_t cmd_per_lun; |
118 | 973abc7f | Stefan Hajnoczi | uint32_t event_info_size; |
119 | 973abc7f | Stefan Hajnoczi | uint32_t sense_size; |
120 | 973abc7f | Stefan Hajnoczi | uint32_t cdb_size; |
121 | 973abc7f | Stefan Hajnoczi | uint16_t max_channel; |
122 | 973abc7f | Stefan Hajnoczi | uint16_t max_target; |
123 | 973abc7f | Stefan Hajnoczi | uint32_t max_lun; |
124 | 973abc7f | Stefan Hajnoczi | } QEMU_PACKED VirtIOSCSIConfig; |
125 | 973abc7f | Stefan Hajnoczi | |
126 | 973abc7f | Stefan Hajnoczi | typedef struct { |
127 | 973abc7f | Stefan Hajnoczi | VirtIODevice vdev; |
128 | 973abc7f | Stefan Hajnoczi | DeviceState *qdev; |
129 | 973abc7f | Stefan Hajnoczi | VirtIOSCSIConf *conf; |
130 | 973abc7f | Stefan Hajnoczi | |
131 | 2ccdcd8d | Paolo Bonzini | SCSIBus bus; |
132 | 973abc7f | Stefan Hajnoczi | uint32_t sense_size; |
133 | 973abc7f | Stefan Hajnoczi | uint32_t cdb_size; |
134 | 06114d72 | Paolo Bonzini | int resetting;
|
135 | d2ad7dd4 | Paolo Bonzini | VirtQueue *ctrl_vq; |
136 | d2ad7dd4 | Paolo Bonzini | VirtQueue *event_vq; |
137 | d2ad7dd4 | Paolo Bonzini | VirtQueue *cmd_vqs[0];
|
138 | 973abc7f | Stefan Hajnoczi | } VirtIOSCSI; |
139 | 973abc7f | Stefan Hajnoczi | |
140 | 326799c0 | Stefan Hajnoczi | typedef struct VirtIOSCSIReq { |
141 | 326799c0 | Stefan Hajnoczi | VirtIOSCSI *dev; |
142 | 326799c0 | Stefan Hajnoczi | VirtQueue *vq; |
143 | 326799c0 | Stefan Hajnoczi | VirtQueueElement elem; |
144 | 326799c0 | Stefan Hajnoczi | QEMUSGList qsgl; |
145 | 326799c0 | Stefan Hajnoczi | SCSIRequest *sreq; |
146 | 326799c0 | Stefan Hajnoczi | union {
|
147 | 326799c0 | Stefan Hajnoczi | char *buf;
|
148 | 326799c0 | Stefan Hajnoczi | VirtIOSCSICmdReq *cmd; |
149 | 326799c0 | Stefan Hajnoczi | VirtIOSCSICtrlTMFReq *tmf; |
150 | 326799c0 | Stefan Hajnoczi | VirtIOSCSICtrlANReq *an; |
151 | 326799c0 | Stefan Hajnoczi | } req; |
152 | 326799c0 | Stefan Hajnoczi | union {
|
153 | 326799c0 | Stefan Hajnoczi | char *buf;
|
154 | 326799c0 | Stefan Hajnoczi | VirtIOSCSICmdResp *cmd; |
155 | 326799c0 | Stefan Hajnoczi | VirtIOSCSICtrlTMFResp *tmf; |
156 | 326799c0 | Stefan Hajnoczi | VirtIOSCSICtrlANResp *an; |
157 | 326799c0 | Stefan Hajnoczi | VirtIOSCSIEvent *event; |
158 | 326799c0 | Stefan Hajnoczi | } resp; |
159 | 326799c0 | Stefan Hajnoczi | } VirtIOSCSIReq; |
160 | 326799c0 | Stefan Hajnoczi | |
161 | 2ccdcd8d | Paolo Bonzini | static inline int virtio_scsi_get_lun(uint8_t *lun) |
162 | 2ccdcd8d | Paolo Bonzini | { |
163 | 2ccdcd8d | Paolo Bonzini | return ((lun[2] << 8) | lun[3]) & 0x3FFF; |
164 | 2ccdcd8d | Paolo Bonzini | } |
165 | 2ccdcd8d | Paolo Bonzini | |
166 | 2ccdcd8d | Paolo Bonzini | static inline SCSIDevice *virtio_scsi_device_find(VirtIOSCSI *s, uint8_t *lun) |
167 | 2ccdcd8d | Paolo Bonzini | { |
168 | 2ccdcd8d | Paolo Bonzini | if (lun[0] != 1) { |
169 | 2ccdcd8d | Paolo Bonzini | return NULL; |
170 | 2ccdcd8d | Paolo Bonzini | } |
171 | 2ccdcd8d | Paolo Bonzini | if (lun[2] != 0 && !(lun[2] >= 0x40 && lun[2] < 0x80)) { |
172 | 2ccdcd8d | Paolo Bonzini | return NULL; |
173 | 2ccdcd8d | Paolo Bonzini | } |
174 | 2ccdcd8d | Paolo Bonzini | return scsi_device_find(&s->bus, 0, lun[1], virtio_scsi_get_lun(lun)); |
175 | 2ccdcd8d | Paolo Bonzini | } |
176 | 2ccdcd8d | Paolo Bonzini | |
177 | 326799c0 | Stefan Hajnoczi | static void virtio_scsi_complete_req(VirtIOSCSIReq *req) |
178 | 326799c0 | Stefan Hajnoczi | { |
179 | 326799c0 | Stefan Hajnoczi | VirtIOSCSI *s = req->dev; |
180 | 326799c0 | Stefan Hajnoczi | VirtQueue *vq = req->vq; |
181 | 326799c0 | Stefan Hajnoczi | virtqueue_push(vq, &req->elem, req->qsgl.size + req->elem.in_sg[0].iov_len);
|
182 | 326799c0 | Stefan Hajnoczi | qemu_sglist_destroy(&req->qsgl); |
183 | 326799c0 | Stefan Hajnoczi | if (req->sreq) {
|
184 | 326799c0 | Stefan Hajnoczi | req->sreq->hba_private = NULL;
|
185 | 326799c0 | Stefan Hajnoczi | scsi_req_unref(req->sreq); |
186 | 326799c0 | Stefan Hajnoczi | } |
187 | 326799c0 | Stefan Hajnoczi | g_free(req); |
188 | 326799c0 | Stefan Hajnoczi | virtio_notify(&s->vdev, vq); |
189 | 326799c0 | Stefan Hajnoczi | } |
190 | 326799c0 | Stefan Hajnoczi | |
191 | 326799c0 | Stefan Hajnoczi | static void virtio_scsi_bad_req(void) |
192 | 326799c0 | Stefan Hajnoczi | { |
193 | 326799c0 | Stefan Hajnoczi | error_report("wrong size for virtio-scsi headers");
|
194 | 326799c0 | Stefan Hajnoczi | exit(1);
|
195 | 326799c0 | Stefan Hajnoczi | } |
196 | 326799c0 | Stefan Hajnoczi | |
197 | 326799c0 | Stefan Hajnoczi | static void qemu_sgl_init_external(QEMUSGList *qsgl, struct iovec *sg, |
198 | 326799c0 | Stefan Hajnoczi | target_phys_addr_t *addr, int num)
|
199 | 326799c0 | Stefan Hajnoczi | { |
200 | 326799c0 | Stefan Hajnoczi | memset(qsgl, 0, sizeof(*qsgl)); |
201 | 326799c0 | Stefan Hajnoczi | while (num--) {
|
202 | 326799c0 | Stefan Hajnoczi | qemu_sglist_add(qsgl, *(addr++), (sg++)->iov_len); |
203 | 326799c0 | Stefan Hajnoczi | } |
204 | 326799c0 | Stefan Hajnoczi | } |
205 | 326799c0 | Stefan Hajnoczi | |
206 | 326799c0 | Stefan Hajnoczi | static void virtio_scsi_parse_req(VirtIOSCSI *s, VirtQueue *vq, |
207 | 326799c0 | Stefan Hajnoczi | VirtIOSCSIReq *req) |
208 | 326799c0 | Stefan Hajnoczi | { |
209 | 326799c0 | Stefan Hajnoczi | assert(req->elem.out_num && req->elem.in_num); |
210 | 326799c0 | Stefan Hajnoczi | req->vq = vq; |
211 | 326799c0 | Stefan Hajnoczi | req->dev = s; |
212 | 326799c0 | Stefan Hajnoczi | req->sreq = NULL;
|
213 | 326799c0 | Stefan Hajnoczi | req->req.buf = req->elem.out_sg[0].iov_base;
|
214 | 326799c0 | Stefan Hajnoczi | req->resp.buf = req->elem.in_sg[0].iov_base;
|
215 | 326799c0 | Stefan Hajnoczi | |
216 | 326799c0 | Stefan Hajnoczi | if (req->elem.out_num > 1) { |
217 | 326799c0 | Stefan Hajnoczi | qemu_sgl_init_external(&req->qsgl, &req->elem.out_sg[1],
|
218 | 326799c0 | Stefan Hajnoczi | &req->elem.out_addr[1],
|
219 | 326799c0 | Stefan Hajnoczi | req->elem.out_num - 1);
|
220 | 326799c0 | Stefan Hajnoczi | } else {
|
221 | 326799c0 | Stefan Hajnoczi | qemu_sgl_init_external(&req->qsgl, &req->elem.in_sg[1],
|
222 | 326799c0 | Stefan Hajnoczi | &req->elem.in_addr[1],
|
223 | 326799c0 | Stefan Hajnoczi | req->elem.in_num - 1);
|
224 | 326799c0 | Stefan Hajnoczi | } |
225 | 326799c0 | Stefan Hajnoczi | } |
226 | 326799c0 | Stefan Hajnoczi | |
227 | 326799c0 | Stefan Hajnoczi | static VirtIOSCSIReq *virtio_scsi_pop_req(VirtIOSCSI *s, VirtQueue *vq)
|
228 | 326799c0 | Stefan Hajnoczi | { |
229 | 326799c0 | Stefan Hajnoczi | VirtIOSCSIReq *req; |
230 | 326799c0 | Stefan Hajnoczi | req = g_malloc(sizeof(*req));
|
231 | 326799c0 | Stefan Hajnoczi | if (!virtqueue_pop(vq, &req->elem)) {
|
232 | 326799c0 | Stefan Hajnoczi | g_free(req); |
233 | 326799c0 | Stefan Hajnoczi | return NULL; |
234 | 326799c0 | Stefan Hajnoczi | } |
235 | 326799c0 | Stefan Hajnoczi | |
236 | 326799c0 | Stefan Hajnoczi | virtio_scsi_parse_req(s, vq, req); |
237 | 326799c0 | Stefan Hajnoczi | return req;
|
238 | 326799c0 | Stefan Hajnoczi | } |
239 | 326799c0 | Stefan Hajnoczi | |
240 | 5db1764c | Paolo Bonzini | static void virtio_scsi_save_request(QEMUFile *f, SCSIRequest *sreq) |
241 | 5db1764c | Paolo Bonzini | { |
242 | 5db1764c | Paolo Bonzini | VirtIOSCSIReq *req = sreq->hba_private; |
243 | d2ad7dd4 | Paolo Bonzini | uint32_t n = virtio_queue_get_id(req->vq) - 2;
|
244 | 5db1764c | Paolo Bonzini | |
245 | d2ad7dd4 | Paolo Bonzini | assert(n < req->dev->conf->num_queues); |
246 | fcf104a7 | Paolo Bonzini | qemu_put_be32s(f, &n); |
247 | 5db1764c | Paolo Bonzini | qemu_put_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem)); |
248 | 5db1764c | Paolo Bonzini | } |
249 | 5db1764c | Paolo Bonzini | |
250 | 5db1764c | Paolo Bonzini | static void *virtio_scsi_load_request(QEMUFile *f, SCSIRequest *sreq) |
251 | 5db1764c | Paolo Bonzini | { |
252 | 5db1764c | Paolo Bonzini | SCSIBus *bus = sreq->bus; |
253 | 5db1764c | Paolo Bonzini | VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus); |
254 | 5db1764c | Paolo Bonzini | VirtIOSCSIReq *req; |
255 | fcf104a7 | Paolo Bonzini | uint32_t n; |
256 | 5db1764c | Paolo Bonzini | |
257 | 5db1764c | Paolo Bonzini | req = g_malloc(sizeof(*req));
|
258 | fcf104a7 | Paolo Bonzini | qemu_get_be32s(f, &n); |
259 | d2ad7dd4 | Paolo Bonzini | assert(n < s->conf->num_queues); |
260 | 5db1764c | Paolo Bonzini | qemu_get_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem)); |
261 | d2ad7dd4 | Paolo Bonzini | virtio_scsi_parse_req(s, s->cmd_vqs[n], req); |
262 | 5db1764c | Paolo Bonzini | |
263 | 5db1764c | Paolo Bonzini | scsi_req_ref(sreq); |
264 | 5db1764c | Paolo Bonzini | req->sreq = sreq; |
265 | 5db1764c | Paolo Bonzini | if (req->sreq->cmd.mode != SCSI_XFER_NONE) {
|
266 | 5db1764c | Paolo Bonzini | int req_mode =
|
267 | 5db1764c | Paolo Bonzini | (req->elem.in_num > 1 ? SCSI_XFER_FROM_DEV : SCSI_XFER_TO_DEV);
|
268 | 5db1764c | Paolo Bonzini | |
269 | 5db1764c | Paolo Bonzini | assert(req->sreq->cmd.mode == req_mode); |
270 | 5db1764c | Paolo Bonzini | } |
271 | 5db1764c | Paolo Bonzini | return req;
|
272 | 5db1764c | Paolo Bonzini | } |
273 | 5db1764c | Paolo Bonzini | |
274 | 06114d72 | Paolo Bonzini | static void virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) |
275 | 326799c0 | Stefan Hajnoczi | { |
276 | 06114d72 | Paolo Bonzini | SCSIDevice *d = virtio_scsi_device_find(s, req->req.tmf->lun); |
277 | 06114d72 | Paolo Bonzini | SCSIRequest *r, *next; |
278 | 0866aca1 | Anthony Liguori | BusChild *kid; |
279 | 06114d72 | Paolo Bonzini | int target;
|
280 | 06114d72 | Paolo Bonzini | |
281 | 06114d72 | Paolo Bonzini | /* Here VIRTIO_SCSI_S_OK means "FUNCTION COMPLETE". */
|
282 | 06114d72 | Paolo Bonzini | req->resp.tmf->response = VIRTIO_SCSI_S_OK; |
283 | 06114d72 | Paolo Bonzini | |
284 | 06114d72 | Paolo Bonzini | switch (req->req.tmf->subtype) {
|
285 | 06114d72 | Paolo Bonzini | case VIRTIO_SCSI_T_TMF_ABORT_TASK:
|
286 | 06114d72 | Paolo Bonzini | case VIRTIO_SCSI_T_TMF_QUERY_TASK:
|
287 | 06114d72 | Paolo Bonzini | if (!d) {
|
288 | 06114d72 | Paolo Bonzini | goto fail;
|
289 | 06114d72 | Paolo Bonzini | } |
290 | 06114d72 | Paolo Bonzini | if (d->lun != virtio_scsi_get_lun(req->req.tmf->lun)) {
|
291 | 06114d72 | Paolo Bonzini | goto incorrect_lun;
|
292 | 06114d72 | Paolo Bonzini | } |
293 | 06114d72 | Paolo Bonzini | QTAILQ_FOREACH_SAFE(r, &d->requests, next, next) { |
294 | 06114d72 | Paolo Bonzini | if (r->tag == req->req.tmf->tag) {
|
295 | 06114d72 | Paolo Bonzini | break;
|
296 | 06114d72 | Paolo Bonzini | } |
297 | 06114d72 | Paolo Bonzini | } |
298 | 06114d72 | Paolo Bonzini | if (r && r->hba_private) {
|
299 | 06114d72 | Paolo Bonzini | if (req->req.tmf->subtype == VIRTIO_SCSI_T_TMF_QUERY_TASK) {
|
300 | 06114d72 | Paolo Bonzini | /* "If the specified command is present in the task set, then
|
301 | 06114d72 | Paolo Bonzini | * return a service response set to FUNCTION SUCCEEDED".
|
302 | 06114d72 | Paolo Bonzini | */
|
303 | 06114d72 | Paolo Bonzini | req->resp.tmf->response = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED; |
304 | 06114d72 | Paolo Bonzini | } else {
|
305 | 06114d72 | Paolo Bonzini | scsi_req_cancel(r); |
306 | 06114d72 | Paolo Bonzini | } |
307 | 06114d72 | Paolo Bonzini | } |
308 | 06114d72 | Paolo Bonzini | break;
|
309 | 06114d72 | Paolo Bonzini | |
310 | 06114d72 | Paolo Bonzini | case VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET:
|
311 | 06114d72 | Paolo Bonzini | if (!d) {
|
312 | 06114d72 | Paolo Bonzini | goto fail;
|
313 | 06114d72 | Paolo Bonzini | } |
314 | 06114d72 | Paolo Bonzini | if (d->lun != virtio_scsi_get_lun(req->req.tmf->lun)) {
|
315 | 06114d72 | Paolo Bonzini | goto incorrect_lun;
|
316 | 06114d72 | Paolo Bonzini | } |
317 | 06114d72 | Paolo Bonzini | s->resetting++; |
318 | 06114d72 | Paolo Bonzini | qdev_reset_all(&d->qdev); |
319 | 06114d72 | Paolo Bonzini | s->resetting--; |
320 | 06114d72 | Paolo Bonzini | break;
|
321 | 06114d72 | Paolo Bonzini | |
322 | 06114d72 | Paolo Bonzini | case VIRTIO_SCSI_T_TMF_ABORT_TASK_SET:
|
323 | 06114d72 | Paolo Bonzini | case VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET:
|
324 | 06114d72 | Paolo Bonzini | case VIRTIO_SCSI_T_TMF_QUERY_TASK_SET:
|
325 | 06114d72 | Paolo Bonzini | if (!d) {
|
326 | 06114d72 | Paolo Bonzini | goto fail;
|
327 | 06114d72 | Paolo Bonzini | } |
328 | 06114d72 | Paolo Bonzini | if (d->lun != virtio_scsi_get_lun(req->req.tmf->lun)) {
|
329 | 06114d72 | Paolo Bonzini | goto incorrect_lun;
|
330 | 06114d72 | Paolo Bonzini | } |
331 | 06114d72 | Paolo Bonzini | QTAILQ_FOREACH_SAFE(r, &d->requests, next, next) { |
332 | 06114d72 | Paolo Bonzini | if (r->hba_private) {
|
333 | 06114d72 | Paolo Bonzini | if (req->req.tmf->subtype == VIRTIO_SCSI_T_TMF_QUERY_TASK_SET) {
|
334 | 06114d72 | Paolo Bonzini | /* "If there is any command present in the task set, then
|
335 | 06114d72 | Paolo Bonzini | * return a service response set to FUNCTION SUCCEEDED".
|
336 | 06114d72 | Paolo Bonzini | */
|
337 | 06114d72 | Paolo Bonzini | req->resp.tmf->response = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED; |
338 | 06114d72 | Paolo Bonzini | break;
|
339 | 06114d72 | Paolo Bonzini | } else {
|
340 | 06114d72 | Paolo Bonzini | scsi_req_cancel(r); |
341 | 06114d72 | Paolo Bonzini | } |
342 | 06114d72 | Paolo Bonzini | } |
343 | 06114d72 | Paolo Bonzini | } |
344 | 06114d72 | Paolo Bonzini | break;
|
345 | 06114d72 | Paolo Bonzini | |
346 | 06114d72 | Paolo Bonzini | case VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET:
|
347 | 06114d72 | Paolo Bonzini | target = req->req.tmf->lun[1];
|
348 | 06114d72 | Paolo Bonzini | s->resetting++; |
349 | 0866aca1 | Anthony Liguori | QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) { |
350 | 0866aca1 | Anthony Liguori | d = DO_UPCAST(SCSIDevice, qdev, kid->child); |
351 | 06114d72 | Paolo Bonzini | if (d->channel == 0 && d->id == target) { |
352 | 06114d72 | Paolo Bonzini | qdev_reset_all(&d->qdev); |
353 | 06114d72 | Paolo Bonzini | } |
354 | 06114d72 | Paolo Bonzini | } |
355 | 06114d72 | Paolo Bonzini | s->resetting--; |
356 | 06114d72 | Paolo Bonzini | break;
|
357 | 06114d72 | Paolo Bonzini | |
358 | 06114d72 | Paolo Bonzini | case VIRTIO_SCSI_T_TMF_CLEAR_ACA:
|
359 | 06114d72 | Paolo Bonzini | default:
|
360 | 06114d72 | Paolo Bonzini | req->resp.tmf->response = VIRTIO_SCSI_S_FUNCTION_REJECTED; |
361 | 06114d72 | Paolo Bonzini | break;
|
362 | 326799c0 | Stefan Hajnoczi | } |
363 | 326799c0 | Stefan Hajnoczi | |
364 | 06114d72 | Paolo Bonzini | return;
|
365 | 06114d72 | Paolo Bonzini | |
366 | 06114d72 | Paolo Bonzini | incorrect_lun:
|
367 | 06114d72 | Paolo Bonzini | req->resp.tmf->response = VIRTIO_SCSI_S_INCORRECT_LUN; |
368 | 06114d72 | Paolo Bonzini | return;
|
369 | 06114d72 | Paolo Bonzini | |
370 | 06114d72 | Paolo Bonzini | fail:
|
371 | 06114d72 | Paolo Bonzini | req->resp.tmf->response = VIRTIO_SCSI_S_BAD_TARGET; |
372 | 326799c0 | Stefan Hajnoczi | } |
373 | 326799c0 | Stefan Hajnoczi | |
374 | 973abc7f | Stefan Hajnoczi | static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) |
375 | 973abc7f | Stefan Hajnoczi | { |
376 | 326799c0 | Stefan Hajnoczi | VirtIOSCSI *s = (VirtIOSCSI *)vdev; |
377 | 326799c0 | Stefan Hajnoczi | VirtIOSCSIReq *req; |
378 | 326799c0 | Stefan Hajnoczi | |
379 | 326799c0 | Stefan Hajnoczi | while ((req = virtio_scsi_pop_req(s, vq))) {
|
380 | 06114d72 | Paolo Bonzini | int out_size, in_size;
|
381 | 06114d72 | Paolo Bonzini | if (req->elem.out_num < 1 || req->elem.in_num < 1) { |
382 | 06114d72 | Paolo Bonzini | virtio_scsi_bad_req(); |
383 | 06114d72 | Paolo Bonzini | continue;
|
384 | 06114d72 | Paolo Bonzini | } |
385 | 06114d72 | Paolo Bonzini | |
386 | 06114d72 | Paolo Bonzini | out_size = req->elem.out_sg[0].iov_len;
|
387 | 06114d72 | Paolo Bonzini | in_size = req->elem.in_sg[0].iov_len;
|
388 | 06114d72 | Paolo Bonzini | if (req->req.tmf->type == VIRTIO_SCSI_T_TMF) {
|
389 | 06114d72 | Paolo Bonzini | if (out_size < sizeof(VirtIOSCSICtrlTMFReq) || |
390 | 06114d72 | Paolo Bonzini | in_size < sizeof(VirtIOSCSICtrlTMFResp)) {
|
391 | 06114d72 | Paolo Bonzini | virtio_scsi_bad_req(); |
392 | 06114d72 | Paolo Bonzini | } |
393 | 06114d72 | Paolo Bonzini | virtio_scsi_do_tmf(s, req); |
394 | 06114d72 | Paolo Bonzini | |
395 | 06114d72 | Paolo Bonzini | } else if (req->req.tmf->type == VIRTIO_SCSI_T_AN_QUERY || |
396 | 06114d72 | Paolo Bonzini | req->req.tmf->type == VIRTIO_SCSI_T_AN_SUBSCRIBE) { |
397 | 06114d72 | Paolo Bonzini | if (out_size < sizeof(VirtIOSCSICtrlANReq) || |
398 | 06114d72 | Paolo Bonzini | in_size < sizeof(VirtIOSCSICtrlANResp)) {
|
399 | 06114d72 | Paolo Bonzini | virtio_scsi_bad_req(); |
400 | 06114d72 | Paolo Bonzini | } |
401 | 06114d72 | Paolo Bonzini | req->resp.an->event_actual = 0;
|
402 | 06114d72 | Paolo Bonzini | req->resp.an->response = VIRTIO_SCSI_S_OK; |
403 | 06114d72 | Paolo Bonzini | } |
404 | 06114d72 | Paolo Bonzini | virtio_scsi_complete_req(req); |
405 | 326799c0 | Stefan Hajnoczi | } |
406 | 326799c0 | Stefan Hajnoczi | } |
407 | 326799c0 | Stefan Hajnoczi | |
408 | 619d7ae9 | Paolo Bonzini | static void virtio_scsi_handle_event(VirtIODevice *vdev, VirtQueue *vq) |
409 | 619d7ae9 | Paolo Bonzini | { |
410 | 619d7ae9 | Paolo Bonzini | } |
411 | 619d7ae9 | Paolo Bonzini | |
412 | 2ccdcd8d | Paolo Bonzini | static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status, |
413 | 2ccdcd8d | Paolo Bonzini | size_t resid) |
414 | 2ccdcd8d | Paolo Bonzini | { |
415 | 2ccdcd8d | Paolo Bonzini | VirtIOSCSIReq *req = r->hba_private; |
416 | 2ccdcd8d | Paolo Bonzini | |
417 | 2ccdcd8d | Paolo Bonzini | req->resp.cmd->response = VIRTIO_SCSI_S_OK; |
418 | 2ccdcd8d | Paolo Bonzini | req->resp.cmd->status = status; |
419 | 2ccdcd8d | Paolo Bonzini | if (req->resp.cmd->status == GOOD) {
|
420 | 2ccdcd8d | Paolo Bonzini | req->resp.cmd->resid = resid; |
421 | 2ccdcd8d | Paolo Bonzini | } else {
|
422 | 2ccdcd8d | Paolo Bonzini | req->resp.cmd->resid = 0;
|
423 | 2ccdcd8d | Paolo Bonzini | req->resp.cmd->sense_len = |
424 | 2ccdcd8d | Paolo Bonzini | scsi_req_get_sense(r, req->resp.cmd->sense, VIRTIO_SCSI_SENSE_SIZE); |
425 | 2ccdcd8d | Paolo Bonzini | } |
426 | 2ccdcd8d | Paolo Bonzini | virtio_scsi_complete_req(req); |
427 | 2ccdcd8d | Paolo Bonzini | } |
428 | 2ccdcd8d | Paolo Bonzini | |
429 | 2ccdcd8d | Paolo Bonzini | static QEMUSGList *virtio_scsi_get_sg_list(SCSIRequest *r)
|
430 | 2ccdcd8d | Paolo Bonzini | { |
431 | 2ccdcd8d | Paolo Bonzini | VirtIOSCSIReq *req = r->hba_private; |
432 | 2ccdcd8d | Paolo Bonzini | |
433 | 2ccdcd8d | Paolo Bonzini | return &req->qsgl;
|
434 | 2ccdcd8d | Paolo Bonzini | } |
435 | 2ccdcd8d | Paolo Bonzini | |
436 | 2ccdcd8d | Paolo Bonzini | static void virtio_scsi_request_cancelled(SCSIRequest *r) |
437 | 2ccdcd8d | Paolo Bonzini | { |
438 | 2ccdcd8d | Paolo Bonzini | VirtIOSCSIReq *req = r->hba_private; |
439 | 2ccdcd8d | Paolo Bonzini | |
440 | 2ccdcd8d | Paolo Bonzini | if (!req) {
|
441 | 2ccdcd8d | Paolo Bonzini | return;
|
442 | 2ccdcd8d | Paolo Bonzini | } |
443 | 06114d72 | Paolo Bonzini | if (req->dev->resetting) {
|
444 | 06114d72 | Paolo Bonzini | req->resp.cmd->response = VIRTIO_SCSI_S_RESET; |
445 | 06114d72 | Paolo Bonzini | } else {
|
446 | 06114d72 | Paolo Bonzini | req->resp.cmd->response = VIRTIO_SCSI_S_ABORTED; |
447 | 06114d72 | Paolo Bonzini | } |
448 | 2ccdcd8d | Paolo Bonzini | virtio_scsi_complete_req(req); |
449 | 2ccdcd8d | Paolo Bonzini | } |
450 | 2ccdcd8d | Paolo Bonzini | |
451 | 2ccdcd8d | Paolo Bonzini | static void virtio_scsi_fail_cmd_req(VirtIOSCSIReq *req) |
452 | 326799c0 | Stefan Hajnoczi | { |
453 | 326799c0 | Stefan Hajnoczi | req->resp.cmd->response = VIRTIO_SCSI_S_FAILURE; |
454 | 326799c0 | Stefan Hajnoczi | virtio_scsi_complete_req(req); |
455 | 973abc7f | Stefan Hajnoczi | } |
456 | 973abc7f | Stefan Hajnoczi | |
457 | 973abc7f | Stefan Hajnoczi | static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq) |
458 | 973abc7f | Stefan Hajnoczi | { |
459 | 326799c0 | Stefan Hajnoczi | VirtIOSCSI *s = (VirtIOSCSI *)vdev; |
460 | 326799c0 | Stefan Hajnoczi | VirtIOSCSIReq *req; |
461 | 2ccdcd8d | Paolo Bonzini | int n;
|
462 | 326799c0 | Stefan Hajnoczi | |
463 | 326799c0 | Stefan Hajnoczi | while ((req = virtio_scsi_pop_req(s, vq))) {
|
464 | 2ccdcd8d | Paolo Bonzini | SCSIDevice *d; |
465 | 326799c0 | Stefan Hajnoczi | int out_size, in_size;
|
466 | 326799c0 | Stefan Hajnoczi | if (req->elem.out_num < 1 || req->elem.in_num < 1) { |
467 | 326799c0 | Stefan Hajnoczi | virtio_scsi_bad_req(); |
468 | 326799c0 | Stefan Hajnoczi | } |
469 | 326799c0 | Stefan Hajnoczi | |
470 | 326799c0 | Stefan Hajnoczi | out_size = req->elem.out_sg[0].iov_len;
|
471 | 326799c0 | Stefan Hajnoczi | in_size = req->elem.in_sg[0].iov_len;
|
472 | 326799c0 | Stefan Hajnoczi | if (out_size < sizeof(VirtIOSCSICmdReq) + s->cdb_size || |
473 | 326799c0 | Stefan Hajnoczi | in_size < sizeof(VirtIOSCSICmdResp) + s->sense_size) {
|
474 | 326799c0 | Stefan Hajnoczi | virtio_scsi_bad_req(); |
475 | 326799c0 | Stefan Hajnoczi | } |
476 | 326799c0 | Stefan Hajnoczi | |
477 | 326799c0 | Stefan Hajnoczi | if (req->elem.out_num > 1 && req->elem.in_num > 1) { |
478 | 2ccdcd8d | Paolo Bonzini | virtio_scsi_fail_cmd_req(req); |
479 | 326799c0 | Stefan Hajnoczi | continue;
|
480 | 326799c0 | Stefan Hajnoczi | } |
481 | 326799c0 | Stefan Hajnoczi | |
482 | 2ccdcd8d | Paolo Bonzini | d = virtio_scsi_device_find(s, req->req.cmd->lun); |
483 | 2ccdcd8d | Paolo Bonzini | if (!d) {
|
484 | 2ccdcd8d | Paolo Bonzini | req->resp.cmd->response = VIRTIO_SCSI_S_BAD_TARGET; |
485 | 2ccdcd8d | Paolo Bonzini | virtio_scsi_complete_req(req); |
486 | 2ccdcd8d | Paolo Bonzini | continue;
|
487 | 2ccdcd8d | Paolo Bonzini | } |
488 | 2ccdcd8d | Paolo Bonzini | req->sreq = scsi_req_new(d, req->req.cmd->tag, |
489 | 2ccdcd8d | Paolo Bonzini | virtio_scsi_get_lun(req->req.cmd->lun), |
490 | 2ccdcd8d | Paolo Bonzini | req->req.cmd->cdb, req); |
491 | 2ccdcd8d | Paolo Bonzini | |
492 | 2ccdcd8d | Paolo Bonzini | if (req->sreq->cmd.mode != SCSI_XFER_NONE) {
|
493 | 2ccdcd8d | Paolo Bonzini | int req_mode =
|
494 | 2ccdcd8d | Paolo Bonzini | (req->elem.in_num > 1 ? SCSI_XFER_FROM_DEV : SCSI_XFER_TO_DEV);
|
495 | 2ccdcd8d | Paolo Bonzini | |
496 | 2ccdcd8d | Paolo Bonzini | if (req->sreq->cmd.mode != req_mode ||
|
497 | 2ccdcd8d | Paolo Bonzini | req->sreq->cmd.xfer > req->qsgl.size) { |
498 | 2ccdcd8d | Paolo Bonzini | req->resp.cmd->response = VIRTIO_SCSI_S_OVERRUN; |
499 | 2ccdcd8d | Paolo Bonzini | virtio_scsi_complete_req(req); |
500 | 2ccdcd8d | Paolo Bonzini | continue;
|
501 | 2ccdcd8d | Paolo Bonzini | } |
502 | 2ccdcd8d | Paolo Bonzini | } |
503 | 2ccdcd8d | Paolo Bonzini | |
504 | 2ccdcd8d | Paolo Bonzini | n = scsi_req_enqueue(req->sreq); |
505 | 2ccdcd8d | Paolo Bonzini | if (n) {
|
506 | 2ccdcd8d | Paolo Bonzini | scsi_req_continue(req->sreq); |
507 | 2ccdcd8d | Paolo Bonzini | } |
508 | 326799c0 | Stefan Hajnoczi | } |
509 | 973abc7f | Stefan Hajnoczi | } |
510 | 973abc7f | Stefan Hajnoczi | |
511 | 973abc7f | Stefan Hajnoczi | static void virtio_scsi_get_config(VirtIODevice *vdev, |
512 | 973abc7f | Stefan Hajnoczi | uint8_t *config) |
513 | 973abc7f | Stefan Hajnoczi | { |
514 | 973abc7f | Stefan Hajnoczi | VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config; |
515 | 973abc7f | Stefan Hajnoczi | VirtIOSCSI *s = (VirtIOSCSI *)vdev; |
516 | 973abc7f | Stefan Hajnoczi | |
517 | 973abc7f | Stefan Hajnoczi | stl_raw(&scsiconf->num_queues, s->conf->num_queues); |
518 | 973abc7f | Stefan Hajnoczi | stl_raw(&scsiconf->seg_max, 128 - 2); |
519 | 973abc7f | Stefan Hajnoczi | stl_raw(&scsiconf->max_sectors, s->conf->max_sectors); |
520 | 973abc7f | Stefan Hajnoczi | stl_raw(&scsiconf->cmd_per_lun, s->conf->cmd_per_lun); |
521 | 973abc7f | Stefan Hajnoczi | stl_raw(&scsiconf->event_info_size, sizeof(VirtIOSCSIEvent));
|
522 | 973abc7f | Stefan Hajnoczi | stl_raw(&scsiconf->sense_size, s->sense_size); |
523 | 973abc7f | Stefan Hajnoczi | stl_raw(&scsiconf->cdb_size, s->cdb_size); |
524 | 973abc7f | Stefan Hajnoczi | stl_raw(&scsiconf->max_channel, VIRTIO_SCSI_MAX_CHANNEL); |
525 | 973abc7f | Stefan Hajnoczi | stl_raw(&scsiconf->max_target, VIRTIO_SCSI_MAX_TARGET); |
526 | 973abc7f | Stefan Hajnoczi | stl_raw(&scsiconf->max_lun, VIRTIO_SCSI_MAX_LUN); |
527 | 973abc7f | Stefan Hajnoczi | } |
528 | 973abc7f | Stefan Hajnoczi | |
529 | 973abc7f | Stefan Hajnoczi | static void virtio_scsi_set_config(VirtIODevice *vdev, |
530 | 973abc7f | Stefan Hajnoczi | const uint8_t *config)
|
531 | 973abc7f | Stefan Hajnoczi | { |
532 | 973abc7f | Stefan Hajnoczi | VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config; |
533 | 973abc7f | Stefan Hajnoczi | VirtIOSCSI *s = (VirtIOSCSI *)vdev; |
534 | 973abc7f | Stefan Hajnoczi | |
535 | 973abc7f | Stefan Hajnoczi | if ((uint32_t) ldl_raw(&scsiconf->sense_size) >= 65536 || |
536 | 973abc7f | Stefan Hajnoczi | (uint32_t) ldl_raw(&scsiconf->cdb_size) >= 256) {
|
537 | 973abc7f | Stefan Hajnoczi | error_report("bad data written to virtio-scsi configuration space");
|
538 | 973abc7f | Stefan Hajnoczi | exit(1);
|
539 | 973abc7f | Stefan Hajnoczi | } |
540 | 973abc7f | Stefan Hajnoczi | |
541 | 973abc7f | Stefan Hajnoczi | s->sense_size = ldl_raw(&scsiconf->sense_size); |
542 | 973abc7f | Stefan Hajnoczi | s->cdb_size = ldl_raw(&scsiconf->cdb_size); |
543 | 973abc7f | Stefan Hajnoczi | } |
544 | 973abc7f | Stefan Hajnoczi | |
545 | 973abc7f | Stefan Hajnoczi | static uint32_t virtio_scsi_get_features(VirtIODevice *vdev,
|
546 | 973abc7f | Stefan Hajnoczi | uint32_t requested_features) |
547 | 973abc7f | Stefan Hajnoczi | { |
548 | 973abc7f | Stefan Hajnoczi | return requested_features;
|
549 | 973abc7f | Stefan Hajnoczi | } |
550 | 973abc7f | Stefan Hajnoczi | |
551 | 973abc7f | Stefan Hajnoczi | static void virtio_scsi_reset(VirtIODevice *vdev) |
552 | 973abc7f | Stefan Hajnoczi | { |
553 | 973abc7f | Stefan Hajnoczi | VirtIOSCSI *s = (VirtIOSCSI *)vdev; |
554 | 973abc7f | Stefan Hajnoczi | |
555 | 973abc7f | Stefan Hajnoczi | s->sense_size = VIRTIO_SCSI_SENSE_SIZE; |
556 | 973abc7f | Stefan Hajnoczi | s->cdb_size = VIRTIO_SCSI_CDB_SIZE; |
557 | 973abc7f | Stefan Hajnoczi | } |
558 | 973abc7f | Stefan Hajnoczi | |
559 | 5db1764c | Paolo Bonzini | /* The device does not have anything to save beyond the virtio data.
|
560 | 5db1764c | Paolo Bonzini | * Request data is saved with callbacks from SCSI devices.
|
561 | 5db1764c | Paolo Bonzini | */
|
562 | 5db1764c | Paolo Bonzini | static void virtio_scsi_save(QEMUFile *f, void *opaque) |
563 | 5db1764c | Paolo Bonzini | { |
564 | 5db1764c | Paolo Bonzini | VirtIOSCSI *s = opaque; |
565 | 5db1764c | Paolo Bonzini | virtio_save(&s->vdev, f); |
566 | 5db1764c | Paolo Bonzini | } |
567 | 5db1764c | Paolo Bonzini | |
568 | 5db1764c | Paolo Bonzini | static int virtio_scsi_load(QEMUFile *f, void *opaque, int version_id) |
569 | 5db1764c | Paolo Bonzini | { |
570 | 5db1764c | Paolo Bonzini | VirtIOSCSI *s = opaque; |
571 | 2a633c46 | Orit Wassermann | int ret;
|
572 | 2a633c46 | Orit Wassermann | |
573 | 2a633c46 | Orit Wassermann | ret = virtio_load(&s->vdev, f); |
574 | 2a633c46 | Orit Wassermann | if (ret) {
|
575 | 2a633c46 | Orit Wassermann | return ret;
|
576 | 2a633c46 | Orit Wassermann | } |
577 | 5db1764c | Paolo Bonzini | return 0; |
578 | 5db1764c | Paolo Bonzini | } |
579 | 5db1764c | Paolo Bonzini | |
580 | 2ccdcd8d | Paolo Bonzini | static struct SCSIBusInfo virtio_scsi_scsi_info = { |
581 | 2ccdcd8d | Paolo Bonzini | .tcq = true,
|
582 | 2ccdcd8d | Paolo Bonzini | .max_channel = VIRTIO_SCSI_MAX_CHANNEL, |
583 | 2ccdcd8d | Paolo Bonzini | .max_target = VIRTIO_SCSI_MAX_TARGET, |
584 | 2ccdcd8d | Paolo Bonzini | .max_lun = VIRTIO_SCSI_MAX_LUN, |
585 | 2ccdcd8d | Paolo Bonzini | |
586 | 2ccdcd8d | Paolo Bonzini | .complete = virtio_scsi_command_complete, |
587 | 2ccdcd8d | Paolo Bonzini | .cancel = virtio_scsi_request_cancelled, |
588 | 2ccdcd8d | Paolo Bonzini | .get_sg_list = virtio_scsi_get_sg_list, |
589 | 5db1764c | Paolo Bonzini | .save_request = virtio_scsi_save_request, |
590 | 5db1764c | Paolo Bonzini | .load_request = virtio_scsi_load_request, |
591 | 2ccdcd8d | Paolo Bonzini | }; |
592 | 2ccdcd8d | Paolo Bonzini | |
593 | 973abc7f | Stefan Hajnoczi | VirtIODevice *virtio_scsi_init(DeviceState *dev, VirtIOSCSIConf *proxyconf) |
594 | 973abc7f | Stefan Hajnoczi | { |
595 | 973abc7f | Stefan Hajnoczi | VirtIOSCSI *s; |
596 | 5db1764c | Paolo Bonzini | static int virtio_scsi_id; |
597 | d2ad7dd4 | Paolo Bonzini | size_t sz; |
598 | d2ad7dd4 | Paolo Bonzini | int i;
|
599 | 973abc7f | Stefan Hajnoczi | |
600 | d2ad7dd4 | Paolo Bonzini | sz = sizeof(VirtIOSCSI) + proxyconf->num_queues * sizeof(VirtQueue *); |
601 | 973abc7f | Stefan Hajnoczi | s = (VirtIOSCSI *)virtio_common_init("virtio-scsi", VIRTIO_ID_SCSI,
|
602 | d2ad7dd4 | Paolo Bonzini | sizeof(VirtIOSCSIConfig), sz);
|
603 | 973abc7f | Stefan Hajnoczi | |
604 | 973abc7f | Stefan Hajnoczi | s->qdev = dev; |
605 | 973abc7f | Stefan Hajnoczi | s->conf = proxyconf; |
606 | 973abc7f | Stefan Hajnoczi | |
607 | 973abc7f | Stefan Hajnoczi | /* TODO set up vdev function pointers */
|
608 | 973abc7f | Stefan Hajnoczi | s->vdev.get_config = virtio_scsi_get_config; |
609 | 973abc7f | Stefan Hajnoczi | s->vdev.set_config = virtio_scsi_set_config; |
610 | 973abc7f | Stefan Hajnoczi | s->vdev.get_features = virtio_scsi_get_features; |
611 | 973abc7f | Stefan Hajnoczi | s->vdev.reset = virtio_scsi_reset; |
612 | 973abc7f | Stefan Hajnoczi | |
613 | 973abc7f | Stefan Hajnoczi | s->ctrl_vq = virtio_add_queue(&s->vdev, VIRTIO_SCSI_VQ_SIZE, |
614 | 973abc7f | Stefan Hajnoczi | virtio_scsi_handle_ctrl); |
615 | 973abc7f | Stefan Hajnoczi | s->event_vq = virtio_add_queue(&s->vdev, VIRTIO_SCSI_VQ_SIZE, |
616 | 619d7ae9 | Paolo Bonzini | virtio_scsi_handle_event); |
617 | d2ad7dd4 | Paolo Bonzini | for (i = 0; i < s->conf->num_queues; i++) { |
618 | d2ad7dd4 | Paolo Bonzini | s->cmd_vqs[i] = virtio_add_queue(&s->vdev, VIRTIO_SCSI_VQ_SIZE, |
619 | d2ad7dd4 | Paolo Bonzini | virtio_scsi_handle_cmd); |
620 | d2ad7dd4 | Paolo Bonzini | } |
621 | 973abc7f | Stefan Hajnoczi | |
622 | 2ccdcd8d | Paolo Bonzini | scsi_bus_new(&s->bus, dev, &virtio_scsi_scsi_info); |
623 | 2ccdcd8d | Paolo Bonzini | if (!dev->hotplugged) {
|
624 | 2ccdcd8d | Paolo Bonzini | scsi_bus_legacy_handle_cmdline(&s->bus); |
625 | 2ccdcd8d | Paolo Bonzini | } |
626 | 2ccdcd8d | Paolo Bonzini | |
627 | 5db1764c | Paolo Bonzini | register_savevm(dev, "virtio-scsi", virtio_scsi_id++, 1, |
628 | 5db1764c | Paolo Bonzini | virtio_scsi_save, virtio_scsi_load, s); |
629 | 973abc7f | Stefan Hajnoczi | |
630 | 973abc7f | Stefan Hajnoczi | return &s->vdev;
|
631 | 973abc7f | Stefan Hajnoczi | } |
632 | 973abc7f | Stefan Hajnoczi | |
633 | 973abc7f | Stefan Hajnoczi | void virtio_scsi_exit(VirtIODevice *vdev)
|
634 | 973abc7f | Stefan Hajnoczi | { |
635 | eb2fa764 | Paolo Bonzini | VirtIOSCSI *s = (VirtIOSCSI *)vdev; |
636 | eb2fa764 | Paolo Bonzini | unregister_savevm(s->qdev, "virtio-scsi", s);
|
637 | 973abc7f | Stefan Hajnoczi | virtio_cleanup(vdev); |
638 | 973abc7f | Stefan Hajnoczi | } |