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