]>
Commit | Line | Data |
---|---|---|
2cc977e2 TS |
1 | /* |
2 | * Generic SCSI Device support | |
3 | * | |
4 | * Copyright (c) 2007 Bull S.A.S. | |
5 | * Based on code by Paul Brook | |
6 | * Based on code by Fabrice Bellard | |
7 | * | |
8 | * Written by Laurent Vivier <Laurent.Vivier@bull.net> | |
9 | * | |
8e31bf38 | 10 | * This code is licensed under the LGPL. |
2cc977e2 TS |
11 | * |
12 | */ | |
13 | ||
a4ab4792 | 14 | #include "qemu/osdep.h" |
da34e65c | 15 | #include "qapi/error.h" |
856dfd8a | 16 | #include "qemu/ctype.h" |
1de7afc9 | 17 | #include "qemu/error-report.h" |
0b8fa32f | 18 | #include "qemu/module.h" |
0d09e41a | 19 | #include "hw/scsi/scsi.h" |
ca77ee28 | 20 | #include "migration/qemu-file-types.h" |
a27bd6c7 | 21 | #include "hw/qdev-properties.h" |
ce35e229 | 22 | #include "hw/qdev-properties-system.h" |
3d4a8bf0 | 23 | #include "hw/scsi/emulation.h" |
4be74634 | 24 | #include "sysemu/block-backend.h" |
56853498 | 25 | #include "trace.h" |
2cc977e2 | 26 | |
d52affa7 | 27 | #ifdef __linux__ |
2cc977e2 | 28 | |
2cc977e2 | 29 | #include <scsi/sg.h> |
08e2c9f1 | 30 | #include "scsi/constants.h" |
2cc977e2 | 31 | |
2cc977e2 TS |
32 | #ifndef MAX_UINT |
33 | #define MAX_UINT ((unsigned int)-1) | |
34 | #endif | |
35 | ||
4c41d2ef GH |
36 | typedef struct SCSIGenericReq { |
37 | SCSIRequest req; | |
2cc977e2 TS |
38 | uint8_t *buf; |
39 | int buflen; | |
40 | int len; | |
41 | sg_io_hdr_t io_header; | |
4c41d2ef | 42 | } SCSIGenericReq; |
2cc977e2 | 43 | |
56b1fc48 PB |
44 | static void scsi_generic_save_request(QEMUFile *f, SCSIRequest *req) |
45 | { | |
46 | SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); | |
47 | ||
48 | qemu_put_sbe32s(f, &r->buflen); | |
49 | if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) { | |
50 | assert(!r->req.sg); | |
51 | qemu_put_buffer(f, r->buf, r->req.cmd.xfer); | |
52 | } | |
53 | } | |
54 | ||
55 | static void scsi_generic_load_request(QEMUFile *f, SCSIRequest *req) | |
56 | { | |
57 | SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); | |
58 | ||
59 | qemu_get_sbe32s(f, &r->buflen); | |
60 | if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) { | |
61 | assert(!r->req.sg); | |
62 | qemu_get_buffer(f, r->buf, r->req.cmd.xfer); | |
63 | } | |
64 | } | |
65 | ||
ad2d30f7 | 66 | static void scsi_free_request(SCSIRequest *req) |
2cc977e2 | 67 | { |
ad2d30f7 PB |
68 | SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); |
69 | ||
7267c094 | 70 | g_free(r->buf); |
2cc977e2 TS |
71 | } |
72 | ||
2cc977e2 | 73 | /* Helper function for command completion. */ |
fa0d653b | 74 | static void scsi_command_complete_noio(SCSIGenericReq *r, int ret) |
2cc977e2 | 75 | { |
682a9b21 | 76 | int status; |
1ead6b4e | 77 | SCSISense sense; |
a108557b | 78 | sg_io_hdr_t *io_hdr = &r->io_header; |
2cc977e2 | 79 | |
fa0d653b PB |
80 | assert(r->req.aiocb == NULL); |
81 | ||
6c25fa6c | 82 | if (r->req.io_canceled) { |
d5776465 | 83 | scsi_req_cancel_complete(&r->req); |
6c25fa6c FZ |
84 | goto done; |
85 | } | |
a108557b HR |
86 | if (ret < 0) { |
87 | status = scsi_sense_from_errno(-ret, &sense); | |
88 | if (status == CHECK_CONDITION) { | |
1ead6b4e | 89 | scsi_req_build_sense(&r->req, sense); |
682a9b21 | 90 | } |
a108557b | 91 | } else if (io_hdr->host_status != SCSI_HOST_OK) { |
f3126d65 HR |
92 | scsi_req_complete_failed(&r->req, io_hdr->host_status); |
93 | goto done; | |
a108557b HR |
94 | } else if (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT) { |
95 | status = BUSY; | |
96 | } else { | |
97 | status = io_hdr->status; | |
98 | if (io_hdr->driver_status & SG_ERR_DRIVER_SENSE) { | |
99 | r->req.sense_len = io_hdr->sb_len_wr; | |
100 | } | |
2cc977e2 | 101 | } |
56853498 | 102 | trace_scsi_generic_command_complete_noio(r, r->req.tag, status); |
ed3a34a3 | 103 | |
682a9b21 | 104 | scsi_req_complete(&r->req, status); |
6c25fa6c | 105 | done: |
3df9caf8 | 106 | scsi_req_unref(&r->req); |
2cc977e2 TS |
107 | } |
108 | ||
fa0d653b PB |
109 | static void scsi_command_complete(void *opaque, int ret) |
110 | { | |
111 | SCSIGenericReq *r = (SCSIGenericReq *)opaque; | |
b9e413dd | 112 | SCSIDevice *s = r->req.dev; |
fa0d653b PB |
113 | |
114 | assert(r->req.aiocb != NULL); | |
115 | r->req.aiocb = NULL; | |
b9e413dd PB |
116 | |
117 | aio_context_acquire(blk_get_aio_context(s->conf.blk)); | |
fa0d653b | 118 | scsi_command_complete_noio(r, ret); |
b9e413dd | 119 | aio_context_release(blk_get_aio_context(s->conf.blk)); |
fa0d653b PB |
120 | } |
121 | ||
4be74634 | 122 | static int execute_command(BlockBackend *blk, |
4c41d2ef | 123 | SCSIGenericReq *r, int direction, |
097310b5 | 124 | BlockCompletionFunc *complete) |
2cc977e2 | 125 | { |
c9b6609b HR |
126 | SCSIDevice *s = r->req.dev; |
127 | ||
2cc977e2 TS |
128 | r->io_header.interface_id = 'S'; |
129 | r->io_header.dxfer_direction = direction; | |
130 | r->io_header.dxferp = r->buf; | |
131 | r->io_header.dxfer_len = r->buflen; | |
29362ebe GH |
132 | r->io_header.cmdp = r->req.cmd.buf; |
133 | r->io_header.cmd_len = r->req.cmd.len; | |
b45ef674 PB |
134 | r->io_header.mx_sb_len = sizeof(r->req.sense); |
135 | r->io_header.sbp = r->req.sense; | |
c9b6609b | 136 | r->io_header.timeout = s->io_timeout * 1000; |
2cc977e2 TS |
137 | r->io_header.usr_ptr = r; |
138 | r->io_header.flags |= SG_FLAG_DIRECT_IO; | |
139 | ||
b2d50a33 HR |
140 | trace_scsi_generic_aio_sgio_command(r->req.tag, r->req.cmd.buf[0], |
141 | r->io_header.timeout); | |
4be74634 | 142 | r->req.aiocb = blk_aio_ioctl(blk, SG_IO, &r->io_header, complete, r); |
d836f8d3 PH |
143 | if (r->req.aiocb == NULL) { |
144 | return -EIO; | |
145 | } | |
2cc977e2 TS |
146 | |
147 | return 0; | |
148 | } | |
149 | ||
51e15194 KW |
150 | static uint64_t calculate_max_transfer(SCSIDevice *s) |
151 | { | |
152 | uint64_t max_transfer = blk_get_max_hw_transfer(s->conf.blk); | |
153 | uint32_t max_iov = blk_get_max_hw_iov(s->conf.blk); | |
154 | ||
155 | assert(max_transfer); | |
156 | max_transfer = MIN_NON_ZERO(max_transfer, | |
157 | max_iov * qemu_real_host_page_size()); | |
158 | ||
159 | return max_transfer / s->blocksize; | |
160 | } | |
161 | ||
06b80795 | 162 | static int scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s, int len) |
0a96ca24 | 163 | { |
6c219fc8 | 164 | uint8_t page, page_idx; |
a71c775b | 165 | |
0a96ca24 DHB |
166 | /* |
167 | * EVPD set to zero returns the standard INQUIRY data. | |
168 | * | |
169 | * Check if scsi_version is unset (-1) to avoid re-defining it | |
170 | * each time an INQUIRY with standard data is received. | |
171 | * scsi_version is initialized with -1 in scsi_generic_reset | |
172 | * and scsi_disk_reset, making sure that we'll set the | |
173 | * scsi_version after a reset. If the version field of the | |
174 | * INQUIRY response somehow changes after a guest reboot, | |
175 | * we'll be able to keep track of it. | |
176 | * | |
177 | * On SCSI-2 and older, first 3 bits of byte 2 is the | |
178 | * ANSI-approved version, while on later versions the | |
179 | * whole byte 2 contains the version. Check if we're dealing | |
180 | * with a newer version and, in that case, assign the | |
181 | * whole byte. | |
182 | */ | |
183 | if (s->scsi_version == -1 && !(r->req.cmd.buf[1] & 0x01)) { | |
184 | s->scsi_version = r->buf[2] & 0x07; | |
185 | if (s->scsi_version > 2) { | |
186 | s->scsi_version = r->buf[2]; | |
187 | } | |
188 | } | |
0a96ca24 | 189 | |
afff2db6 DF |
190 | if ((s->type == TYPE_DISK || s->type == TYPE_ZBC) && |
191 | (r->req.cmd.buf[1] & 0x01)) { | |
a71c775b DHB |
192 | page = r->req.cmd.buf[2]; |
193 | if (page == 0xb0) { | |
51e15194 | 194 | uint64_t max_transfer = calculate_max_transfer(s); |
a71c775b DHB |
195 | stl_be_p(&r->buf[8], max_transfer); |
196 | /* Also take care of the opt xfer len. */ | |
197 | stl_be_p(&r->buf[12], | |
198 | MIN_NON_ZERO(max_transfer, ldl_be_p(&r->buf[12]))); | |
e909ff93 | 199 | } else if (s->needs_vpd_bl_emulation && page == 0x00 && r->buflen >= 4) { |
a71c775b DHB |
200 | /* |
201 | * Now we're capable of supplying the VPD Block Limits | |
202 | * response if the hardware can't. Add it in the INQUIRY | |
203 | * Supported VPD pages response in case we are using the | |
204 | * emulation for this device. | |
205 | * | |
206 | * This way, the guest kernel will be aware of the support | |
207 | * and will use it to proper setup the SCSI device. | |
6c219fc8 PB |
208 | * |
209 | * VPD page numbers must be sorted, so insert 0xb0 at the | |
e909ff93 PB |
210 | * right place with an in-place insert. When the while loop |
211 | * begins the device response is at r[0] to r[page_idx - 1]. | |
a71c775b | 212 | */ |
e909ff93 PB |
213 | page_idx = lduw_be_p(r->buf + 2) + 4; |
214 | page_idx = MIN(page_idx, r->buflen); | |
215 | while (page_idx > 4 && r->buf[page_idx - 1] >= 0xb0) { | |
6c219fc8 PB |
216 | if (page_idx < r->buflen) { |
217 | r->buf[page_idx] = r->buf[page_idx - 1]; | |
218 | } | |
e909ff93 PB |
219 | page_idx--; |
220 | } | |
221 | if (page_idx < r->buflen) { | |
222 | r->buf[page_idx] = 0xb0; | |
6c219fc8 | 223 | } |
6c219fc8 | 224 | stw_be_p(r->buf + 2, lduw_be_p(r->buf + 2) + 1); |
06b80795 ML |
225 | |
226 | if (len < r->buflen) { | |
227 | len++; | |
228 | } | |
a71c775b | 229 | } |
0a96ca24 | 230 | } |
06b80795 | 231 | return len; |
0a96ca24 DHB |
232 | } |
233 | ||
3d4a8bf0 | 234 | static int scsi_generic_emulate_block_limits(SCSIGenericReq *r, SCSIDevice *s) |
a71c775b | 235 | { |
3d4a8bf0 PB |
236 | int len; |
237 | uint8_t buf[64]; | |
238 | ||
239 | SCSIBlockLimits bl = { | |
51e15194 | 240 | .max_io_sectors = calculate_max_transfer(s), |
3d4a8bf0 PB |
241 | }; |
242 | ||
243 | memset(r->buf, 0, r->buflen); | |
244 | stb_p(buf, s->type); | |
245 | stb_p(buf + 1, 0xb0); | |
246 | len = scsi_emulate_block_limits(buf + 4, &bl); | |
247 | assert(len <= sizeof(buf) - 4); | |
248 | stw_be_p(buf + 2, len); | |
249 | ||
250 | memcpy(r->buf, buf, MIN(r->buflen, len + 4)); | |
251 | ||
a71c775b DHB |
252 | r->io_header.sb_len_wr = 0; |
253 | ||
254 | /* | |
255 | * We have valid contents in the reply buffer but the | |
256 | * io_header can report a sense error coming from | |
257 | * the hardware in scsi_command_complete_noio. Clean | |
258 | * up the io_header to avoid reporting it. | |
259 | */ | |
260 | r->io_header.driver_status = 0; | |
261 | r->io_header.status = 0; | |
262 | ||
263 | return r->buflen; | |
264 | } | |
265 | ||
2cc977e2 TS |
266 | static void scsi_read_complete(void * opaque, int ret) |
267 | { | |
4c41d2ef | 268 | SCSIGenericReq *r = (SCSIGenericReq *)opaque; |
9b6eef8a | 269 | SCSIDevice *s = r->req.dev; |
2cc977e2 TS |
270 | int len; |
271 | ||
fa0d653b | 272 | assert(r->req.aiocb != NULL); |
d33e0ce2 | 273 | r->req.aiocb = NULL; |
fa0d653b | 274 | |
b9e413dd PB |
275 | aio_context_acquire(blk_get_aio_context(s->conf.blk)); |
276 | ||
6c25fa6c | 277 | if (ret || r->req.io_canceled) { |
fa0d653b | 278 | scsi_command_complete_noio(r, ret); |
b9e413dd | 279 | goto done; |
2cc977e2 | 280 | } |
fa0d653b | 281 | |
2cc977e2 | 282 | len = r->io_header.dxfer_len - r->io_header.resid; |
56853498 | 283 | trace_scsi_generic_read_complete(r->req.tag, len); |
2cc977e2 TS |
284 | |
285 | r->len = -1; | |
a71c775b | 286 | |
1849f297 | 287 | if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) { |
763c5687 PB |
288 | SCSISense sense = |
289 | scsi_parse_sense_buf(r->req.sense, r->io_header.sb_len_wr); | |
1849f297 SK |
290 | |
291 | /* | |
292 | * Check if this is a VPD Block Limits request that | |
293 | * resulted in sense error but would need emulation. | |
294 | * In this case, emulate a valid VPD response. | |
295 | */ | |
296 | if (sense.key == ILLEGAL_REQUEST && | |
297 | s->needs_vpd_bl_emulation && | |
298 | r->req.cmd.buf[0] == INQUIRY && | |
299 | (r->req.cmd.buf[1] & 0x01) && | |
300 | r->req.cmd.buf[2] == 0xb0) { | |
3d4a8bf0 | 301 | len = scsi_generic_emulate_block_limits(r, s); |
a71c775b | 302 | /* |
1849f297 SK |
303 | * It's okay to jup to req_complete: no need to |
304 | * let scsi_handle_inquiry_reply handle an | |
a71c775b DHB |
305 | * INQUIRY VPD BL request we created manually. |
306 | */ | |
1849f297 SK |
307 | } |
308 | if (sense.key) { | |
a71c775b DHB |
309 | goto req_complete; |
310 | } | |
311 | } | |
312 | ||
9738c657 PB |
313 | if (r->io_header.host_status != SCSI_HOST_OK || |
314 | (r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT) || | |
315 | r->io_header.status != GOOD || | |
316 | len == 0) { | |
fa0d653b | 317 | scsi_command_complete_noio(r, 0); |
b9e413dd | 318 | goto done; |
fa0d653b | 319 | } |
9b6eef8a | 320 | |
fa0d653b PB |
321 | /* Snoop READ CAPACITY output to set the blocksize. */ |
322 | if (r->req.cmd.buf[0] == READ_CAPACITY_10 && | |
323 | (ldl_be_p(&r->buf[0]) != 0xffffffffU || s->max_lba == 0)) { | |
324 | s->blocksize = ldl_be_p(&r->buf[4]); | |
325 | s->max_lba = ldl_be_p(&r->buf[0]) & 0xffffffffULL; | |
326 | } else if (r->req.cmd.buf[0] == SERVICE_ACTION_IN_16 && | |
327 | (r->req.cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) { | |
328 | s->blocksize = ldl_be_p(&r->buf[8]); | |
329 | s->max_lba = ldq_be_p(&r->buf[0]); | |
40f16dd1 | 330 | } |
fa0d653b | 331 | |
afff2db6 DF |
332 | /* |
333 | * Patch MODE SENSE device specific parameters if the BDS is opened | |
0eb2baeb PB |
334 | * readonly. |
335 | */ | |
afff2db6 | 336 | if ((s->type == TYPE_DISK || s->type == TYPE_TAPE || s->type == TYPE_ZBC) && |
86b1cf32 | 337 | !blk_is_writable(s->conf.blk) && |
0eb2baeb PB |
338 | (r->req.cmd.buf[0] == MODE_SENSE || |
339 | r->req.cmd.buf[0] == MODE_SENSE_10) && | |
340 | (r->req.cmd.buf[1] & 0x8) == 0) { | |
341 | if (r->req.cmd.buf[0] == MODE_SENSE) { | |
342 | r->buf[2] |= 0x80; | |
343 | } else { | |
344 | r->buf[3] |= 0x80; | |
345 | } | |
346 | } | |
29e560f0 | 347 | if (r->req.cmd.buf[0] == INQUIRY) { |
06b80795 | 348 | len = scsi_handle_inquiry_reply(r, s, len); |
063143d5 | 349 | } |
a71c775b DHB |
350 | |
351 | req_complete: | |
fa0d653b PB |
352 | scsi_req_data(&r->req, len); |
353 | scsi_req_unref(&r->req); | |
b9e413dd PB |
354 | |
355 | done: | |
356 | aio_context_release(blk_get_aio_context(s->conf.blk)); | |
2cc977e2 TS |
357 | } |
358 | ||
359 | /* Read more data from scsi device into buffer. */ | |
5c6c0e51 | 360 | static void scsi_read_data(SCSIRequest *req) |
2cc977e2 | 361 | { |
5c6c0e51 | 362 | SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); |
8869e103 | 363 | SCSIDevice *s = r->req.dev; |
2cc977e2 TS |
364 | int ret; |
365 | ||
56853498 | 366 | trace_scsi_generic_read_data(req->tag); |
c9501c95 PB |
367 | |
368 | /* The request is used as the AIO opaque value, so add a ref. */ | |
369 | scsi_req_ref(&r->req); | |
2cc977e2 | 370 | if (r->len == -1) { |
fa0d653b | 371 | scsi_command_complete_noio(r, 0); |
2cc977e2 TS |
372 | return; |
373 | } | |
374 | ||
4be74634 MA |
375 | ret = execute_command(s->conf.blk, r, SG_DXFER_FROM_DEV, |
376 | scsi_read_complete); | |
a1f0cce2 | 377 | if (ret < 0) { |
fa0d653b | 378 | scsi_command_complete_noio(r, ret); |
2cc977e2 TS |
379 | } |
380 | } | |
381 | ||
382 | static void scsi_write_complete(void * opaque, int ret) | |
383 | { | |
4c41d2ef | 384 | SCSIGenericReq *r = (SCSIGenericReq *)opaque; |
8869e103 | 385 | SCSIDevice *s = r->req.dev; |
2cc977e2 | 386 | |
56853498 | 387 | trace_scsi_generic_write_complete(ret); |
fa0d653b PB |
388 | |
389 | assert(r->req.aiocb != NULL); | |
d33e0ce2 | 390 | r->req.aiocb = NULL; |
fa0d653b | 391 | |
b9e413dd PB |
392 | aio_context_acquire(blk_get_aio_context(s->conf.blk)); |
393 | ||
6c25fa6c | 394 | if (ret || r->req.io_canceled) { |
fa0d653b | 395 | scsi_command_complete_noio(r, ret); |
b9e413dd | 396 | goto done; |
2cc977e2 TS |
397 | } |
398 | ||
29362ebe | 399 | if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 && |
8869e103 PB |
400 | s->type == TYPE_TAPE) { |
401 | s->blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11]; | |
56853498 | 402 | trace_scsi_generic_write_complete_blocksize(s->blocksize); |
89c0f643 AJ |
403 | } |
404 | ||
fa0d653b | 405 | scsi_command_complete_noio(r, ret); |
b9e413dd PB |
406 | |
407 | done: | |
408 | aio_context_release(blk_get_aio_context(s->conf.blk)); | |
2cc977e2 TS |
409 | } |
410 | ||
411 | /* Write data to a scsi device. Returns nonzero on failure. | |
412 | The transfer may complete asynchronously. */ | |
42741212 | 413 | static void scsi_write_data(SCSIRequest *req) |
2cc977e2 | 414 | { |
5c6c0e51 | 415 | SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); |
8869e103 | 416 | SCSIDevice *s = r->req.dev; |
2cc977e2 TS |
417 | int ret; |
418 | ||
56853498 | 419 | trace_scsi_generic_write_data(req->tag); |
2cc977e2 TS |
420 | if (r->len == 0) { |
421 | r->len = r->buflen; | |
ab9adc88 | 422 | scsi_req_data(&r->req, r->len); |
42741212 | 423 | return; |
2cc977e2 TS |
424 | } |
425 | ||
c9501c95 PB |
426 | /* The request is used as the AIO opaque value, so add a ref. */ |
427 | scsi_req_ref(&r->req); | |
4be74634 | 428 | ret = execute_command(s->conf.blk, r, SG_DXFER_TO_DEV, scsi_write_complete); |
a1f0cce2 | 429 | if (ret < 0) { |
fa0d653b | 430 | scsi_command_complete_noio(r, ret); |
2cc977e2 | 431 | } |
2cc977e2 TS |
432 | } |
433 | ||
434 | /* Return a pointer to the data buffer. */ | |
5c6c0e51 | 435 | static uint8_t *scsi_get_buf(SCSIRequest *req) |
2cc977e2 | 436 | { |
5c6c0e51 HR |
437 | SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); |
438 | ||
2cc977e2 TS |
439 | return r->buf; |
440 | } | |
441 | ||
56853498 LV |
442 | static void scsi_generic_command_dump(uint8_t *cmd, int len) |
443 | { | |
444 | int i; | |
445 | char *line_buffer, *p; | |
446 | ||
447 | line_buffer = g_malloc(len * 5 + 1); | |
448 | ||
449 | for (i = 0, p = line_buffer; i < len; i++) { | |
450 | p += sprintf(p, " 0x%02x", cmd[i]); | |
451 | } | |
452 | trace_scsi_generic_send_command(line_buffer); | |
453 | ||
454 | g_free(line_buffer); | |
455 | } | |
456 | ||
2cc977e2 TS |
457 | /* Execute a scsi command. Returns the length of the data expected by the |
458 | command. This will be Positive for data transfers from the device | |
459 | (eg. disk reads), negative for transfers to the device (eg. disk writes), | |
460 | and zero if the command does not transfer any data. */ | |
461 | ||
5c6c0e51 | 462 | static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd) |
2cc977e2 | 463 | { |
5c6c0e51 | 464 | SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); |
8869e103 | 465 | SCSIDevice *s = r->req.dev; |
2cc977e2 TS |
466 | int ret; |
467 | ||
56853498 LV |
468 | if (trace_event_get_state_backends(TRACE_SCSI_GENERIC_SEND_COMMAND)) { |
469 | scsi_generic_command_dump(cmd, r->req.cmd.len); | |
aa2b1e89 | 470 | } |
2cc977e2 | 471 | |
2ec749cb | 472 | if (r->req.cmd.xfer == 0) { |
1c3381af | 473 | g_free(r->buf); |
2cc977e2 TS |
474 | r->buflen = 0; |
475 | r->buf = NULL; | |
c9501c95 PB |
476 | /* The request is used as the AIO opaque value, so add a ref. */ |
477 | scsi_req_ref(&r->req); | |
4be74634 MA |
478 | ret = execute_command(s->conf.blk, r, SG_DXFER_NONE, |
479 | scsi_command_complete); | |
a1f0cce2 | 480 | if (ret < 0) { |
fa0d653b | 481 | scsi_command_complete_noio(r, ret); |
a1f0cce2 | 482 | return 0; |
2cc977e2 TS |
483 | } |
484 | return 0; | |
485 | } | |
486 | ||
2ec749cb | 487 | if (r->buflen != r->req.cmd.xfer) { |
1c3381af | 488 | g_free(r->buf); |
7267c094 | 489 | r->buf = g_malloc(r->req.cmd.xfer); |
2ec749cb | 490 | r->buflen = r->req.cmd.xfer; |
2cc977e2 TS |
491 | } |
492 | ||
493 | memset(r->buf, 0, r->buflen); | |
2ec749cb | 494 | r->len = r->req.cmd.xfer; |
97a06435 | 495 | if (r->req.cmd.mode == SCSI_XFER_TO_DEV) { |
2cc977e2 | 496 | r->len = 0; |
5c6c0e51 | 497 | return -r->req.cmd.xfer; |
ad2d30f7 | 498 | } else { |
5c6c0e51 | 499 | return r->req.cmd.xfer; |
2cc977e2 | 500 | } |
2cc977e2 TS |
501 | } |
502 | ||
9fd7e859 PB |
503 | static int read_naa_id(const uint8_t *p, uint64_t *p_wwn) |
504 | { | |
505 | int i; | |
506 | ||
507 | if ((p[1] & 0xF) == 3) { | |
508 | /* NAA designator type */ | |
509 | if (p[3] != 8) { | |
510 | return -EINVAL; | |
511 | } | |
512 | *p_wwn = ldq_be_p(p + 4); | |
513 | return 0; | |
514 | } | |
515 | ||
516 | if ((p[1] & 0xF) == 8) { | |
517 | /* SCSI name string designator type */ | |
518 | if (p[3] < 20 || memcmp(&p[4], "naa.", 4)) { | |
519 | return -EINVAL; | |
520 | } | |
521 | if (p[3] > 20 && p[24] != ',') { | |
522 | return -EINVAL; | |
523 | } | |
524 | *p_wwn = 0; | |
525 | for (i = 8; i < 24; i++) { | |
95a5befc | 526 | char c = qemu_toupper(p[i]); |
9fd7e859 PB |
527 | c -= (c >= '0' && c <= '9' ? '0' : 'A' - 10); |
528 | *p_wwn = (*p_wwn << 4) | c; | |
529 | } | |
530 | return 0; | |
531 | } | |
532 | ||
533 | return -EINVAL; | |
534 | } | |
535 | ||
a0c7e35b | 536 | int scsi_SG_IO_FROM_DEV(BlockBackend *blk, uint8_t *cmd, uint8_t cmd_size, |
c9b6609b | 537 | uint8_t *buf, uint8_t buf_size, uint32_t timeout) |
9fd7e859 | 538 | { |
9fd7e859 | 539 | sg_io_hdr_t io_header; |
a0c7e35b | 540 | uint8_t sensebuf[8]; |
9fd7e859 | 541 | int ret; |
9fd7e859 PB |
542 | |
543 | memset(&io_header, 0, sizeof(io_header)); | |
544 | io_header.interface_id = 'S'; | |
545 | io_header.dxfer_direction = SG_DXFER_FROM_DEV; | |
a0c7e35b | 546 | io_header.dxfer_len = buf_size; |
9fd7e859 PB |
547 | io_header.dxferp = buf; |
548 | io_header.cmdp = cmd; | |
a0c7e35b | 549 | io_header.cmd_len = cmd_size; |
9fd7e859 PB |
550 | io_header.mx_sb_len = sizeof(sensebuf); |
551 | io_header.sbp = sensebuf; | |
c9b6609b | 552 | io_header.timeout = timeout * 1000; |
9fd7e859 | 553 | |
b2d50a33 | 554 | trace_scsi_generic_ioctl_sgio_command(cmd[0], io_header.timeout); |
a0c7e35b | 555 | ret = blk_ioctl(blk, SG_IO, &io_header); |
b2d50a33 HR |
556 | if (ret < 0 || io_header.status || |
557 | io_header.driver_status || io_header.host_status) { | |
558 | trace_scsi_generic_ioctl_sgio_done(cmd[0], ret, io_header.status, | |
559 | io_header.host_status); | |
a0c7e35b DHB |
560 | return -1; |
561 | } | |
562 | return 0; | |
563 | } | |
564 | ||
a71c775b DHB |
565 | /* |
566 | * Executes an INQUIRY request with EVPD set to retrieve the | |
567 | * available VPD pages of the device. If the device does | |
568 | * not support the Block Limits page (page 0xb0), set | |
569 | * the needs_vpd_bl_emulation flag for future use. | |
570 | */ | |
571 | static void scsi_generic_set_vpd_bl_emulation(SCSIDevice *s) | |
572 | { | |
573 | uint8_t cmd[6]; | |
574 | uint8_t buf[250]; | |
575 | uint8_t page_len; | |
576 | int ret, i; | |
577 | ||
578 | memset(cmd, 0, sizeof(cmd)); | |
579 | memset(buf, 0, sizeof(buf)); | |
580 | cmd[0] = INQUIRY; | |
581 | cmd[1] = 1; | |
582 | cmd[2] = 0x00; | |
583 | cmd[4] = sizeof(buf); | |
584 | ||
585 | ret = scsi_SG_IO_FROM_DEV(s->conf.blk, cmd, sizeof(cmd), | |
c9b6609b | 586 | buf, sizeof(buf), s->io_timeout); |
a71c775b DHB |
587 | if (ret < 0) { |
588 | /* | |
589 | * Do not assume anything if we can't retrieve the | |
590 | * INQUIRY response to assert the VPD Block Limits | |
591 | * support. | |
592 | */ | |
593 | s->needs_vpd_bl_emulation = false; | |
594 | return; | |
595 | } | |
596 | ||
597 | page_len = buf[3]; | |
57dbb58d | 598 | for (i = 4; i < MIN(sizeof(buf), page_len + 4); i++) { |
a71c775b DHB |
599 | if (buf[i] == 0xb0) { |
600 | s->needs_vpd_bl_emulation = false; | |
601 | return; | |
602 | } | |
603 | } | |
604 | s->needs_vpd_bl_emulation = true; | |
605 | } | |
606 | ||
607 | static void scsi_generic_read_device_identification(SCSIDevice *s) | |
a0c7e35b DHB |
608 | { |
609 | uint8_t cmd[6]; | |
610 | uint8_t buf[250]; | |
611 | int ret; | |
612 | int i, len; | |
613 | ||
614 | memset(cmd, 0, sizeof(cmd)); | |
615 | memset(buf, 0, sizeof(buf)); | |
616 | cmd[0] = INQUIRY; | |
617 | cmd[1] = 1; | |
618 | cmd[2] = 0x83; | |
619 | cmd[4] = sizeof(buf); | |
620 | ||
621 | ret = scsi_SG_IO_FROM_DEV(s->conf.blk, cmd, sizeof(cmd), | |
c9b6609b | 622 | buf, sizeof(buf), s->io_timeout); |
a0c7e35b | 623 | if (ret < 0) { |
9fd7e859 PB |
624 | return; |
625 | } | |
626 | ||
627 | len = MIN((buf[2] << 8) | buf[3], sizeof(buf) - 4); | |
628 | for (i = 0; i + 3 <= len; ) { | |
629 | const uint8_t *p = &buf[i + 4]; | |
630 | uint64_t wwn; | |
631 | ||
632 | if (i + (p[3] + 4) > len) { | |
633 | break; | |
634 | } | |
635 | ||
636 | if ((p[1] & 0x10) == 0) { | |
637 | /* Associated with the logical unit */ | |
638 | if (read_naa_id(p, &wwn) == 0) { | |
639 | s->wwn = wwn; | |
640 | } | |
641 | } else if ((p[1] & 0x10) == 0x10) { | |
642 | /* Associated with the target port */ | |
643 | if (read_naa_id(p, &wwn) == 0) { | |
644 | s->port_wwn = wwn; | |
645 | } | |
646 | } | |
647 | ||
648 | i += p[3] + 4; | |
649 | } | |
650 | } | |
651 | ||
a71c775b DHB |
652 | void scsi_generic_read_device_inquiry(SCSIDevice *s) |
653 | { | |
654 | scsi_generic_read_device_identification(s); | |
afff2db6 | 655 | if (s->type == TYPE_DISK || s->type == TYPE_ZBC) { |
a71c775b DHB |
656 | scsi_generic_set_vpd_bl_emulation(s); |
657 | } else { | |
658 | s->needs_vpd_bl_emulation = false; | |
659 | } | |
660 | } | |
661 | ||
4be74634 | 662 | static int get_stream_blocksize(BlockBackend *blk) |
89c0f643 AJ |
663 | { |
664 | uint8_t cmd[6]; | |
665 | uint8_t buf[12]; | |
89c0f643 AJ |
666 | int ret; |
667 | ||
668 | memset(cmd, 0, sizeof(cmd)); | |
669 | memset(buf, 0, sizeof(buf)); | |
670 | cmd[0] = MODE_SENSE; | |
671 | cmd[4] = sizeof(buf); | |
672 | ||
c9b6609b | 673 | ret = scsi_SG_IO_FROM_DEV(blk, cmd, sizeof(cmd), buf, sizeof(buf), 6); |
a0c7e35b | 674 | if (ret < 0) { |
89c0f643 | 675 | return -1; |
fe0ed712 | 676 | } |
a0c7e35b | 677 | |
89c0f643 AJ |
678 | return (buf[9] << 16) | (buf[10] << 8) | buf[11]; |
679 | } | |
680 | ||
f8b6d672 BK |
681 | static void scsi_generic_reset(DeviceState *dev) |
682 | { | |
b9eea3e6 | 683 | SCSIDevice *s = SCSI_DEVICE(dev); |
f8b6d672 | 684 | |
2343be0d | 685 | s->scsi_version = s->default_scsi_version; |
8869e103 | 686 | scsi_device_purge_requests(s, SENSE_CODE(RESET)); |
f8b6d672 BK |
687 | } |
688 | ||
a818a4b6 | 689 | static void scsi_generic_realize(SCSIDevice *s, Error **errp) |
2cc977e2 | 690 | { |
6ee143a0 | 691 | int rc; |
2cc977e2 | 692 | int sg_version; |
2cc977e2 TS |
693 | struct sg_scsi_id scsiid; |
694 | ||
4be74634 | 695 | if (!s->conf.blk) { |
a818a4b6 FZ |
696 | error_setg(errp, "drive property not set"); |
697 | return; | |
d52affa7 | 698 | } |
2cc977e2 | 699 | |
166854f7 ZC |
700 | if (blk_get_on_error(s->conf.blk, 0) != BLOCKDEV_ON_ERROR_ENOSPC && |
701 | blk_get_on_error(s->conf.blk, 0) != BLOCKDEV_ON_ERROR_REPORT) { | |
a818a4b6 FZ |
702 | error_setg(errp, "Device doesn't support drive option werror"); |
703 | return; | |
620f862e | 704 | } |
4be74634 | 705 | if (blk_get_on_error(s->conf.blk, 1) != BLOCKDEV_ON_ERROR_REPORT) { |
a818a4b6 FZ |
706 | error_setg(errp, "Device doesn't support drive option rerror"); |
707 | return; | |
620f862e MA |
708 | } |
709 | ||
2cc977e2 | 710 | /* check we are using a driver managing SG_IO (version 3 and after */ |
4be74634 | 711 | rc = blk_ioctl(s->conf.blk, SG_GET_VERSION_NUM, &sg_version); |
6ee143a0 | 712 | if (rc < 0) { |
09c2c6ff PB |
713 | error_setg_errno(errp, -rc, "cannot get SG_IO version number"); |
714 | if (rc != -EPERM) { | |
715 | error_append_hint(errp, "Is this a SCSI device?\n"); | |
716 | } | |
a818a4b6 | 717 | return; |
98392453 RS |
718 | } |
719 | if (sg_version < 30000) { | |
a818a4b6 FZ |
720 | error_setg(errp, "scsi generic interface too old"); |
721 | return; | |
d52affa7 | 722 | } |
2cc977e2 TS |
723 | |
724 | /* get LUN of the /dev/sg? */ | |
4be74634 | 725 | if (blk_ioctl(s->conf.blk, SG_GET_SCSI_ID, &scsiid)) { |
a818a4b6 FZ |
726 | error_setg(errp, "SG_GET_SCSI_ID ioctl failed"); |
727 | return; | |
d52affa7 | 728 | } |
c6caae55 | 729 | if (!blkconf_apply_backend_options(&s->conf, |
86b1cf32 | 730 | !blk_supports_write_perm(s->conf.blk), |
c6caae55 | 731 | true, errp)) { |
d9bcd6f7 FZ |
732 | return; |
733 | } | |
2cc977e2 TS |
734 | |
735 | /* define device state */ | |
8869e103 | 736 | s->type = scsiid.scsi_type; |
56853498 | 737 | trace_scsi_generic_realize_type(s->type); |
28b77657 | 738 | |
9b6eef8a PB |
739 | switch (s->type) { |
740 | case TYPE_TAPE: | |
4be74634 | 741 | s->blocksize = get_stream_blocksize(s->conf.blk); |
8869e103 PB |
742 | if (s->blocksize == -1) { |
743 | s->blocksize = 0; | |
744 | } | |
9b6eef8a PB |
745 | break; |
746 | ||
747 | /* Make a guess for block devices, we'll fix it when the guest sends. | |
748 | * READ CAPACITY. If they don't, they likely would assume these sizes | |
749 | * anyway. (TODO: they could also send MODE SENSE). | |
750 | */ | |
751 | case TYPE_ROM: | |
752 | case TYPE_WORM: | |
753 | s->blocksize = 2048; | |
754 | break; | |
755 | default: | |
756 | s->blocksize = 512; | |
757 | break; | |
89c0f643 | 758 | } |
8869e103 | 759 | |
56853498 | 760 | trace_scsi_generic_realize_blocksize(s->blocksize); |
9fd7e859 | 761 | |
29e560f0 DHB |
762 | /* Only used by scsi-block, but initialize it nevertheless to be clean. */ |
763 | s->default_scsi_version = -1; | |
c9b6609b | 764 | s->io_timeout = DEFAULT_IO_TIMEOUT; |
a71c775b | 765 | scsi_generic_read_device_inquiry(s); |
d52affa7 | 766 | } |
2cc977e2 | 767 | |
765d1525 | 768 | const SCSIReqOps scsi_generic_req_ops = { |
8dbd4574 | 769 | .size = sizeof(SCSIGenericReq), |
12010e7b PB |
770 | .free_req = scsi_free_request, |
771 | .send_command = scsi_send_command, | |
772 | .read_data = scsi_read_data, | |
773 | .write_data = scsi_write_data, | |
12010e7b | 774 | .get_buf = scsi_get_buf, |
56b1fc48 PB |
775 | .load_request = scsi_generic_load_request, |
776 | .save_request = scsi_generic_save_request, | |
8dbd4574 PB |
777 | }; |
778 | ||
779 | static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun, | |
63db0f0e | 780 | uint8_t *buf, void *hba_private) |
8dbd4574 | 781 | { |
9be38598 | 782 | return scsi_req_alloc(&scsi_generic_req_ops, d, tag, lun, hba_private); |
8dbd4574 PB |
783 | } |
784 | ||
39bffca2 | 785 | static Property scsi_generic_properties[] = { |
4be74634 | 786 | DEFINE_PROP_DRIVE("drive", SCSIDevice, conf.blk), |
d9bcd6f7 | 787 | DEFINE_PROP_BOOL("share-rw", SCSIDevice, conf.share_rw, false), |
c9b6609b HR |
788 | DEFINE_PROP_UINT32("io_timeout", SCSIDevice, io_timeout, |
789 | DEFAULT_IO_TIMEOUT), | |
39bffca2 AL |
790 | DEFINE_PROP_END_OF_LIST(), |
791 | }; | |
792 | ||
3e7e180a | 793 | static int scsi_generic_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, |
fe9d8927 JM |
794 | uint8_t *buf, size_t buf_len, |
795 | void *hba_private) | |
3e7e180a | 796 | { |
fe9d8927 | 797 | return scsi_bus_parse_cdb(dev, cmd, buf, buf_len, hba_private); |
3e7e180a PB |
798 | } |
799 | ||
b9eea3e6 AL |
800 | static void scsi_generic_class_initfn(ObjectClass *klass, void *data) |
801 | { | |
39bffca2 | 802 | DeviceClass *dc = DEVICE_CLASS(klass); |
b9eea3e6 AL |
803 | SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass); |
804 | ||
a818a4b6 | 805 | sc->realize = scsi_generic_realize; |
b9eea3e6 | 806 | sc->alloc_req = scsi_new_request; |
3e7e180a | 807 | sc->parse_cdb = scsi_generic_parse_cdb; |
39bffca2 AL |
808 | dc->fw_name = "disk"; |
809 | dc->desc = "pass through generic scsi device (/dev/sg*)"; | |
810 | dc->reset = scsi_generic_reset; | |
4f67d30b | 811 | device_class_set_props(dc, scsi_generic_properties); |
56b1fc48 | 812 | dc->vmsd = &vmstate_scsi_device; |
b9eea3e6 AL |
813 | } |
814 | ||
8c43a6f0 | 815 | static const TypeInfo scsi_generic_info = { |
39bffca2 AL |
816 | .name = "scsi-generic", |
817 | .parent = TYPE_SCSI_DEVICE, | |
818 | .instance_size = sizeof(SCSIDevice), | |
819 | .class_init = scsi_generic_class_initfn, | |
d52affa7 | 820 | }; |
2cc977e2 | 821 | |
83f7d43a | 822 | static void scsi_generic_register_types(void) |
d52affa7 | 823 | { |
39bffca2 | 824 | type_register_static(&scsi_generic_info); |
2cc977e2 | 825 | } |
83f7d43a AF |
826 | |
827 | type_init(scsi_generic_register_types) | |
d52affa7 | 828 | |
2cc977e2 | 829 | #endif /* __linux__ */ |