]> Git Repo - qemu.git/blame - hw/scsi/scsi-generic.c
ipmi: Fix SEL get/set time commands
[qemu.git] / hw / scsi / scsi-generic.c
CommitLineData
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 <[email protected]>
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"
2cc977e2 16#include "qemu-common.h"
1de7afc9 17#include "qemu/error-report.h"
0d09e41a 18#include "hw/scsi/scsi.h"
4be74634 19#include "sysemu/block-backend.h"
9c17d615 20#include "sysemu/blockdev.h"
2cc977e2 21
d52affa7 22#ifdef __linux__
2cc977e2
TS
23
24//#define DEBUG_SCSI
25
26#ifdef DEBUG_SCSI
001faf32
BS
27#define DPRINTF(fmt, ...) \
28do { printf("scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
2cc977e2 29#else
001faf32 30#define DPRINTF(fmt, ...) do {} while(0)
2cc977e2
TS
31#endif
32
001faf32
BS
33#define BADF(fmt, ...) \
34do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
2cc977e2 35
2cc977e2 36#include <scsi/sg.h>
08e2c9f1 37#include "scsi/constants.h"
2cc977e2 38
2cc977e2
TS
39#ifndef MAX_UINT
40#define MAX_UINT ((unsigned int)-1)
41#endif
42
4c41d2ef
GH
43typedef struct SCSIGenericReq {
44 SCSIRequest req;
2cc977e2
TS
45 uint8_t *buf;
46 int buflen;
47 int len;
48 sg_io_hdr_t io_header;
4c41d2ef 49} SCSIGenericReq;
2cc977e2 50
56b1fc48
PB
51static void scsi_generic_save_request(QEMUFile *f, SCSIRequest *req)
52{
53 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
54
55 qemu_put_sbe32s(f, &r->buflen);
56 if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) {
57 assert(!r->req.sg);
58 qemu_put_buffer(f, r->buf, r->req.cmd.xfer);
59 }
60}
61
62static void scsi_generic_load_request(QEMUFile *f, SCSIRequest *req)
63{
64 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
65
66 qemu_get_sbe32s(f, &r->buflen);
67 if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) {
68 assert(!r->req.sg);
69 qemu_get_buffer(f, r->buf, r->req.cmd.xfer);
70 }
71}
72
ad2d30f7 73static void scsi_free_request(SCSIRequest *req)
2cc977e2 74{
ad2d30f7
PB
75 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
76
7267c094 77 g_free(r->buf);
2cc977e2
TS
78}
79
2cc977e2 80/* Helper function for command completion. */
fa0d653b 81static void scsi_command_complete_noio(SCSIGenericReq *r, int ret)
2cc977e2 82{
682a9b21 83 int status;
1ead6b4e 84 SCSISense sense;
2cc977e2 85
fa0d653b
PB
86 assert(r->req.aiocb == NULL);
87
6c25fa6c 88 if (r->req.io_canceled) {
d5776465 89 scsi_req_cancel_complete(&r->req);
6c25fa6c
FZ
90 goto done;
91 }
1ead6b4e
PB
92 status = sg_io_sense_from_errno(-ret, &r->io_header, &sense);
93 if (status == CHECK_CONDITION) {
94 if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
95 r->req.sense_len = r->io_header.sb_len_wr;
682a9b21 96 } else {
1ead6b4e 97 scsi_req_build_sense(&r->req, sense);
682a9b21 98 }
2cc977e2 99 }
1ead6b4e 100
89c0f643 101 DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
682a9b21 102 r, r->req.tag, status);
ed3a34a3 103
682a9b21 104 scsi_req_complete(&r->req, status);
6c25fa6c 105done:
3df9caf8 106 scsi_req_unref(&r->req);
2cc977e2
TS
107}
108
fa0d653b
PB
109static 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 122static int execute_command(BlockBackend *blk,
4c41d2ef 123 SCSIGenericReq *r, int direction,
097310b5 124 BlockCompletionFunc *complete)
2cc977e2 125{
2cc977e2
TS
126 r->io_header.interface_id = 'S';
127 r->io_header.dxfer_direction = direction;
128 r->io_header.dxferp = r->buf;
129 r->io_header.dxfer_len = r->buflen;
29362ebe
GH
130 r->io_header.cmdp = r->req.cmd.buf;
131 r->io_header.cmd_len = r->req.cmd.len;
b45ef674
PB
132 r->io_header.mx_sb_len = sizeof(r->req.sense);
133 r->io_header.sbp = r->req.sense;
2cc977e2
TS
134 r->io_header.timeout = MAX_UINT;
135 r->io_header.usr_ptr = r;
136 r->io_header.flags |= SG_FLAG_DIRECT_IO;
137
4be74634 138 r->req.aiocb = blk_aio_ioctl(blk, SG_IO, &r->io_header, complete, r);
d836f8d3
PH
139 if (r->req.aiocb == NULL) {
140 return -EIO;
141 }
2cc977e2
TS
142
143 return 0;
144}
145
146static void scsi_read_complete(void * opaque, int ret)
147{
4c41d2ef 148 SCSIGenericReq *r = (SCSIGenericReq *)opaque;
9b6eef8a 149 SCSIDevice *s = r->req.dev;
2cc977e2
TS
150 int len;
151
fa0d653b 152 assert(r->req.aiocb != NULL);
d33e0ce2 153 r->req.aiocb = NULL;
fa0d653b 154
b9e413dd
PB
155 aio_context_acquire(blk_get_aio_context(s->conf.blk));
156
6c25fa6c 157 if (ret || r->req.io_canceled) {
fa0d653b 158 scsi_command_complete_noio(r, ret);
b9e413dd 159 goto done;
2cc977e2 160 }
fa0d653b 161
2cc977e2 162 len = r->io_header.dxfer_len - r->io_header.resid;
4c41d2ef 163 DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, len);
2cc977e2
TS
164
165 r->len = -1;
40f16dd1 166 if (len == 0) {
fa0d653b 167 scsi_command_complete_noio(r, 0);
b9e413dd 168 goto done;
fa0d653b 169 }
9b6eef8a 170
fa0d653b
PB
171 /* Snoop READ CAPACITY output to set the blocksize. */
172 if (r->req.cmd.buf[0] == READ_CAPACITY_10 &&
173 (ldl_be_p(&r->buf[0]) != 0xffffffffU || s->max_lba == 0)) {
174 s->blocksize = ldl_be_p(&r->buf[4]);
175 s->max_lba = ldl_be_p(&r->buf[0]) & 0xffffffffULL;
176 } else if (r->req.cmd.buf[0] == SERVICE_ACTION_IN_16 &&
177 (r->req.cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) {
178 s->blocksize = ldl_be_p(&r->buf[8]);
179 s->max_lba = ldq_be_p(&r->buf[0]);
40f16dd1 180 }
fa0d653b
PB
181 blk_set_guest_block_size(s->conf.blk, s->blocksize);
182
0eb2baeb
PB
183 /* Patch MODE SENSE device specific parameters if the BDS is opened
184 * readonly.
185 */
186 if ((s->type == TYPE_DISK || s->type == TYPE_TAPE) &&
187 blk_is_read_only(s->conf.blk) &&
188 (r->req.cmd.buf[0] == MODE_SENSE ||
189 r->req.cmd.buf[0] == MODE_SENSE_10) &&
190 (r->req.cmd.buf[1] & 0x8) == 0) {
191 if (r->req.cmd.buf[0] == MODE_SENSE) {
192 r->buf[2] |= 0x80;
193 } else {
194 r->buf[3] |= 0x80;
195 }
196 }
063143d5
FZ
197 if (s->type == TYPE_DISK &&
198 r->req.cmd.buf[0] == INQUIRY &&
199 r->req.cmd.buf[2] == 0xb0) {
5def6b80
EB
200 uint32_t max_transfer =
201 blk_get_max_transfer(s->conf.blk) / s->blocksize;
24ce9a20 202
5def6b80
EB
203 assert(max_transfer);
204 stl_be_p(&r->buf[8], max_transfer);
24ce9a20 205 /* Also take care of the opt xfer len. */
bed58b44
FZ
206 stl_be_p(&r->buf[12],
207 MIN_NON_ZERO(max_transfer, ldl_be_p(&r->buf[12])));
063143d5 208 }
fa0d653b
PB
209 scsi_req_data(&r->req, len);
210 scsi_req_unref(&r->req);
b9e413dd
PB
211
212done:
213 aio_context_release(blk_get_aio_context(s->conf.blk));
2cc977e2
TS
214}
215
216/* Read more data from scsi device into buffer. */
5c6c0e51 217static void scsi_read_data(SCSIRequest *req)
2cc977e2 218{
5c6c0e51 219 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
8869e103 220 SCSIDevice *s = r->req.dev;
2cc977e2
TS
221 int ret;
222
2e144aa7 223 DPRINTF("scsi_read_data tag=0x%x\n", req->tag);
c9501c95
PB
224
225 /* The request is used as the AIO opaque value, so add a ref. */
226 scsi_req_ref(&r->req);
2cc977e2 227 if (r->len == -1) {
fa0d653b 228 scsi_command_complete_noio(r, 0);
2cc977e2
TS
229 return;
230 }
231
4be74634
MA
232 ret = execute_command(s->conf.blk, r, SG_DXFER_FROM_DEV,
233 scsi_read_complete);
a1f0cce2 234 if (ret < 0) {
fa0d653b 235 scsi_command_complete_noio(r, ret);
2cc977e2
TS
236 }
237}
238
239static void scsi_write_complete(void * opaque, int ret)
240{
4c41d2ef 241 SCSIGenericReq *r = (SCSIGenericReq *)opaque;
8869e103 242 SCSIDevice *s = r->req.dev;
2cc977e2
TS
243
244 DPRINTF("scsi_write_complete() ret = %d\n", ret);
fa0d653b
PB
245
246 assert(r->req.aiocb != NULL);
d33e0ce2 247 r->req.aiocb = NULL;
fa0d653b 248
b9e413dd
PB
249 aio_context_acquire(blk_get_aio_context(s->conf.blk));
250
6c25fa6c 251 if (ret || r->req.io_canceled) {
fa0d653b 252 scsi_command_complete_noio(r, ret);
b9e413dd 253 goto done;
2cc977e2
TS
254 }
255
29362ebe 256 if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 &&
8869e103
PB
257 s->type == TYPE_TAPE) {
258 s->blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
259 DPRINTF("block size %d\n", s->blocksize);
89c0f643
AJ
260 }
261
fa0d653b 262 scsi_command_complete_noio(r, ret);
b9e413dd
PB
263
264done:
265 aio_context_release(blk_get_aio_context(s->conf.blk));
2cc977e2
TS
266}
267
268/* Write data to a scsi device. Returns nonzero on failure.
269 The transfer may complete asynchronously. */
42741212 270static void scsi_write_data(SCSIRequest *req)
2cc977e2 271{
5c6c0e51 272 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
8869e103 273 SCSIDevice *s = r->req.dev;
2cc977e2
TS
274 int ret;
275
2e144aa7 276 DPRINTF("scsi_write_data tag=0x%x\n", req->tag);
2cc977e2
TS
277 if (r->len == 0) {
278 r->len = r->buflen;
ab9adc88 279 scsi_req_data(&r->req, r->len);
42741212 280 return;
2cc977e2
TS
281 }
282
c9501c95
PB
283 /* The request is used as the AIO opaque value, so add a ref. */
284 scsi_req_ref(&r->req);
4be74634 285 ret = execute_command(s->conf.blk, r, SG_DXFER_TO_DEV, scsi_write_complete);
a1f0cce2 286 if (ret < 0) {
fa0d653b 287 scsi_command_complete_noio(r, ret);
2cc977e2 288 }
2cc977e2
TS
289}
290
291/* Return a pointer to the data buffer. */
5c6c0e51 292static uint8_t *scsi_get_buf(SCSIRequest *req)
2cc977e2 293{
5c6c0e51
HR
294 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
295
2cc977e2
TS
296 return r->buf;
297}
298
2cc977e2
TS
299/* Execute a scsi command. Returns the length of the data expected by the
300 command. This will be Positive for data transfers from the device
301 (eg. disk reads), negative for transfers to the device (eg. disk writes),
302 and zero if the command does not transfer any data. */
303
5c6c0e51 304static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
2cc977e2 305{
5c6c0e51 306 SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
8869e103 307 SCSIDevice *s = r->req.dev;
2cc977e2
TS
308 int ret;
309
aa2b1e89 310#ifdef DEBUG_SCSI
2e144aa7 311 DPRINTF("Command: data=0x%02x", cmd[0]);
aa2b1e89
BK
312 {
313 int i;
314 for (i = 1; i < r->req.cmd.len; i++) {
315 printf(" 0x%02x", cmd[i]);
316 }
317 printf("\n");
318 }
319#endif
2cc977e2 320
2ec749cb 321 if (r->req.cmd.xfer == 0) {
1c3381af 322 g_free(r->buf);
2cc977e2
TS
323 r->buflen = 0;
324 r->buf = NULL;
c9501c95
PB
325 /* The request is used as the AIO opaque value, so add a ref. */
326 scsi_req_ref(&r->req);
4be74634
MA
327 ret = execute_command(s->conf.blk, r, SG_DXFER_NONE,
328 scsi_command_complete);
a1f0cce2 329 if (ret < 0) {
fa0d653b 330 scsi_command_complete_noio(r, ret);
a1f0cce2 331 return 0;
2cc977e2
TS
332 }
333 return 0;
334 }
335
2ec749cb 336 if (r->buflen != r->req.cmd.xfer) {
1c3381af 337 g_free(r->buf);
7267c094 338 r->buf = g_malloc(r->req.cmd.xfer);
2ec749cb 339 r->buflen = r->req.cmd.xfer;
2cc977e2
TS
340 }
341
342 memset(r->buf, 0, r->buflen);
2ec749cb 343 r->len = r->req.cmd.xfer;
97a06435 344 if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
2cc977e2 345 r->len = 0;
5c6c0e51 346 return -r->req.cmd.xfer;
ad2d30f7 347 } else {
5c6c0e51 348 return r->req.cmd.xfer;
2cc977e2 349 }
2cc977e2
TS
350}
351
9fd7e859
PB
352static int read_naa_id(const uint8_t *p, uint64_t *p_wwn)
353{
354 int i;
355
356 if ((p[1] & 0xF) == 3) {
357 /* NAA designator type */
358 if (p[3] != 8) {
359 return -EINVAL;
360 }
361 *p_wwn = ldq_be_p(p + 4);
362 return 0;
363 }
364
365 if ((p[1] & 0xF) == 8) {
366 /* SCSI name string designator type */
367 if (p[3] < 20 || memcmp(&p[4], "naa.", 4)) {
368 return -EINVAL;
369 }
370 if (p[3] > 20 && p[24] != ',') {
371 return -EINVAL;
372 }
373 *p_wwn = 0;
374 for (i = 8; i < 24; i++) {
95a5befc 375 char c = qemu_toupper(p[i]);
9fd7e859
PB
376 c -= (c >= '0' && c <= '9' ? '0' : 'A' - 10);
377 *p_wwn = (*p_wwn << 4) | c;
378 }
379 return 0;
380 }
381
382 return -EINVAL;
383}
384
385void scsi_generic_read_device_identification(SCSIDevice *s)
386{
387 uint8_t cmd[6];
388 uint8_t buf[250];
389 uint8_t sensebuf[8];
390 sg_io_hdr_t io_header;
391 int ret;
392 int i, len;
393
394 memset(cmd, 0, sizeof(cmd));
395 memset(buf, 0, sizeof(buf));
396 cmd[0] = INQUIRY;
397 cmd[1] = 1;
398 cmd[2] = 0x83;
399 cmd[4] = sizeof(buf);
400
401 memset(&io_header, 0, sizeof(io_header));
402 io_header.interface_id = 'S';
403 io_header.dxfer_direction = SG_DXFER_FROM_DEV;
404 io_header.dxfer_len = sizeof(buf);
405 io_header.dxferp = buf;
406 io_header.cmdp = cmd;
407 io_header.cmd_len = sizeof(cmd);
408 io_header.mx_sb_len = sizeof(sensebuf);
409 io_header.sbp = sensebuf;
410 io_header.timeout = 6000; /* XXX */
411
412 ret = blk_ioctl(s->conf.blk, SG_IO, &io_header);
413 if (ret < 0 || io_header.driver_status || io_header.host_status) {
414 return;
415 }
416
417 len = MIN((buf[2] << 8) | buf[3], sizeof(buf) - 4);
418 for (i = 0; i + 3 <= len; ) {
419 const uint8_t *p = &buf[i + 4];
420 uint64_t wwn;
421
422 if (i + (p[3] + 4) > len) {
423 break;
424 }
425
426 if ((p[1] & 0x10) == 0) {
427 /* Associated with the logical unit */
428 if (read_naa_id(p, &wwn) == 0) {
429 s->wwn = wwn;
430 }
431 } else if ((p[1] & 0x10) == 0x10) {
432 /* Associated with the target port */
433 if (read_naa_id(p, &wwn) == 0) {
434 s->port_wwn = wwn;
435 }
436 }
437
438 i += p[3] + 4;
439 }
440}
441
4be74634 442static int get_stream_blocksize(BlockBackend *blk)
89c0f643
AJ
443{
444 uint8_t cmd[6];
445 uint8_t buf[12];
446 uint8_t sensebuf[8];
447 sg_io_hdr_t io_header;
448 int ret;
449
450 memset(cmd, 0, sizeof(cmd));
451 memset(buf, 0, sizeof(buf));
452 cmd[0] = MODE_SENSE;
453 cmd[4] = sizeof(buf);
454
455 memset(&io_header, 0, sizeof(io_header));
456 io_header.interface_id = 'S';
457 io_header.dxfer_direction = SG_DXFER_FROM_DEV;
458 io_header.dxfer_len = sizeof(buf);
459 io_header.dxferp = buf;
460 io_header.cmdp = cmd;
461 io_header.cmd_len = sizeof(cmd);
462 io_header.mx_sb_len = sizeof(sensebuf);
463 io_header.sbp = sensebuf;
464 io_header.timeout = 6000; /* XXX */
465
4be74634 466 ret = blk_ioctl(blk, SG_IO, &io_header);
fe0ed712 467 if (ret < 0 || io_header.driver_status || io_header.host_status) {
89c0f643 468 return -1;
fe0ed712 469 }
89c0f643
AJ
470 return (buf[9] << 16) | (buf[10] << 8) | buf[11];
471}
472
f8b6d672
BK
473static void scsi_generic_reset(DeviceState *dev)
474{
b9eea3e6 475 SCSIDevice *s = SCSI_DEVICE(dev);
f8b6d672 476
8869e103 477 scsi_device_purge_requests(s, SENSE_CODE(RESET));
f8b6d672
BK
478}
479
a818a4b6 480static void scsi_generic_realize(SCSIDevice *s, Error **errp)
2cc977e2 481{
6ee143a0 482 int rc;
2cc977e2 483 int sg_version;
2cc977e2 484 struct sg_scsi_id scsiid;
d9bcd6f7 485 Error *local_err = NULL;
2cc977e2 486
4be74634 487 if (!s->conf.blk) {
a818a4b6
FZ
488 error_setg(errp, "drive property not set");
489 return;
d52affa7 490 }
2cc977e2 491
4be74634 492 if (blk_get_on_error(s->conf.blk, 0) != BLOCKDEV_ON_ERROR_ENOSPC) {
a818a4b6
FZ
493 error_setg(errp, "Device doesn't support drive option werror");
494 return;
620f862e 495 }
4be74634 496 if (blk_get_on_error(s->conf.blk, 1) != BLOCKDEV_ON_ERROR_REPORT) {
a818a4b6
FZ
497 error_setg(errp, "Device doesn't support drive option rerror");
498 return;
620f862e
MA
499 }
500
2cc977e2 501 /* check we are using a driver managing SG_IO (version 3 and after */
4be74634 502 rc = blk_ioctl(s->conf.blk, SG_GET_VERSION_NUM, &sg_version);
6ee143a0 503 if (rc < 0) {
a818a4b6
FZ
504 error_setg(errp, "cannot get SG_IO version number: %s. "
505 "Is this a SCSI device?",
506 strerror(-rc));
507 return;
98392453
RS
508 }
509 if (sg_version < 30000) {
a818a4b6
FZ
510 error_setg(errp, "scsi generic interface too old");
511 return;
d52affa7 512 }
2cc977e2
TS
513
514 /* get LUN of the /dev/sg? */
4be74634 515 if (blk_ioctl(s->conf.blk, SG_GET_SCSI_ID, &scsiid)) {
a818a4b6
FZ
516 error_setg(errp, "SG_GET_SCSI_ID ioctl failed");
517 return;
d52affa7 518 }
d9bcd6f7
FZ
519 blkconf_apply_backend_options(&s->conf,
520 blk_is_read_only(s->conf.blk),
521 true, &local_err);
522 if (local_err) {
523 error_propagate(errp, local_err);
524 return;
525 }
2cc977e2
TS
526
527 /* define device state */
8869e103
PB
528 s->type = scsiid.scsi_type;
529 DPRINTF("device type %d\n", s->type);
28b77657 530
9b6eef8a
PB
531 switch (s->type) {
532 case TYPE_TAPE:
4be74634 533 s->blocksize = get_stream_blocksize(s->conf.blk);
8869e103
PB
534 if (s->blocksize == -1) {
535 s->blocksize = 0;
536 }
9b6eef8a
PB
537 break;
538
539 /* Make a guess for block devices, we'll fix it when the guest sends.
540 * READ CAPACITY. If they don't, they likely would assume these sizes
541 * anyway. (TODO: they could also send MODE SENSE).
542 */
543 case TYPE_ROM:
544 case TYPE_WORM:
545 s->blocksize = 2048;
546 break;
547 default:
548 s->blocksize = 512;
549 break;
89c0f643 550 }
8869e103
PB
551
552 DPRINTF("block size %d\n", s->blocksize);
9fd7e859
PB
553
554 scsi_generic_read_device_identification(s);
d52affa7 555}
2cc977e2 556
765d1525 557const SCSIReqOps scsi_generic_req_ops = {
8dbd4574 558 .size = sizeof(SCSIGenericReq),
12010e7b
PB
559 .free_req = scsi_free_request,
560 .send_command = scsi_send_command,
561 .read_data = scsi_read_data,
562 .write_data = scsi_write_data,
12010e7b 563 .get_buf = scsi_get_buf,
56b1fc48
PB
564 .load_request = scsi_generic_load_request,
565 .save_request = scsi_generic_save_request,
8dbd4574
PB
566};
567
568static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
63db0f0e 569 uint8_t *buf, void *hba_private)
8dbd4574 570{
9be38598 571 return scsi_req_alloc(&scsi_generic_req_ops, d, tag, lun, hba_private);
8dbd4574
PB
572}
573
39bffca2 574static Property scsi_generic_properties[] = {
4be74634 575 DEFINE_PROP_DRIVE("drive", SCSIDevice, conf.blk),
d9bcd6f7 576 DEFINE_PROP_BOOL("share-rw", SCSIDevice, conf.share_rw, false),
39bffca2
AL
577 DEFINE_PROP_END_OF_LIST(),
578};
579
3e7e180a
PB
580static int scsi_generic_parse_cdb(SCSIDevice *dev, SCSICommand *cmd,
581 uint8_t *buf, void *hba_private)
582{
583 return scsi_bus_parse_cdb(dev, cmd, buf, hba_private);
584}
585
b9eea3e6
AL
586static void scsi_generic_class_initfn(ObjectClass *klass, void *data)
587{
39bffca2 588 DeviceClass *dc = DEVICE_CLASS(klass);
b9eea3e6
AL
589 SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
590
a818a4b6 591 sc->realize = scsi_generic_realize;
b9eea3e6 592 sc->alloc_req = scsi_new_request;
3e7e180a 593 sc->parse_cdb = scsi_generic_parse_cdb;
39bffca2
AL
594 dc->fw_name = "disk";
595 dc->desc = "pass through generic scsi device (/dev/sg*)";
596 dc->reset = scsi_generic_reset;
597 dc->props = scsi_generic_properties;
56b1fc48 598 dc->vmsd = &vmstate_scsi_device;
b9eea3e6
AL
599}
600
8c43a6f0 601static const TypeInfo scsi_generic_info = {
39bffca2
AL
602 .name = "scsi-generic",
603 .parent = TYPE_SCSI_DEVICE,
604 .instance_size = sizeof(SCSIDevice),
605 .class_init = scsi_generic_class_initfn,
d52affa7 606};
2cc977e2 607
83f7d43a 608static void scsi_generic_register_types(void)
d52affa7 609{
39bffca2 610 type_register_static(&scsi_generic_info);
2cc977e2 611}
83f7d43a
AF
612
613type_init(scsi_generic_register_types)
d52affa7 614
2cc977e2 615#endif /* __linux__ */
This page took 1.01179 seconds and 4 git commands to generate.