]> git.proxmox.com Git - qemu.git/blame - hw/scsi-generic.c
scsi: move type from SCSIGenericState to SCSIDevice
[qemu.git] / hw / 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 *
10 * This code is licenced under the LGPL.
11 *
12 */
13
14#include "qemu-common.h"
15#include "block.h"
43b443b6 16#include "scsi.h"
2cc977e2 17
d52affa7 18#ifdef __linux__
2cc977e2
TS
19
20//#define DEBUG_SCSI
21
22#ifdef DEBUG_SCSI
001faf32
BS
23#define DPRINTF(fmt, ...) \
24do { printf("scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
2cc977e2 25#else
001faf32 26#define DPRINTF(fmt, ...) do {} while(0)
2cc977e2
TS
27#endif
28
001faf32
BS
29#define BADF(fmt, ...) \
30do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
2cc977e2
TS
31
32#include <stdio.h>
33#include <sys/types.h>
34#include <sys/stat.h>
35#include <unistd.h>
36#include <scsi/sg.h>
0d65e1f8 37#include "scsi-defs.h"
2cc977e2 38
a9dd6843 39#define SCSI_SENSE_BUF_SIZE 96
2cc977e2
TS
40
41#define SG_ERR_DRIVER_TIMEOUT 0x06
42#define SG_ERR_DRIVER_SENSE 0x08
43
44#ifndef MAX_UINT
45#define MAX_UINT ((unsigned int)-1)
46#endif
47
d52affa7
GH
48typedef struct SCSIGenericState SCSIGenericState;
49
4c41d2ef
GH
50typedef struct SCSIGenericReq {
51 SCSIRequest req;
2cc977e2
TS
52 uint8_t *buf;
53 int buflen;
54 int len;
55 sg_io_hdr_t io_header;
4c41d2ef 56} SCSIGenericReq;
2cc977e2 57
d52affa7 58struct SCSIGenericState
2cc977e2 59{
d52affa7 60 SCSIDevice qdev;
d52affa7 61 DriveInfo *dinfo;
2cc977e2 62 int lun;
2cc977e2
TS
63 int driver_status;
64 uint8_t sensebuf[SCSI_SENSE_BUF_SIZE];
89c0f643 65 uint8_t senselen;
2cc977e2
TS
66};
67
89b08ae1 68static SCSIGenericReq *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun)
2cc977e2 69{
89b08ae1 70 SCSIRequest *req;
2cc977e2 71
89b08ae1
GH
72 req = scsi_req_alloc(sizeof(SCSIGenericReq), d, tag, lun);
73 return DO_UPCAST(SCSIGenericReq, req, req);
2cc977e2
TS
74}
75
4c41d2ef 76static void scsi_remove_request(SCSIGenericReq *r)
2cc977e2 77{
9af99d98 78 qemu_free(r->buf);
89b08ae1 79 scsi_req_free(&r->req);
2cc977e2
TS
80}
81
4c41d2ef 82static SCSIGenericReq *scsi_find_request(SCSIGenericState *s, uint32_t tag)
2cc977e2 83{
89b08ae1 84 return DO_UPCAST(SCSIGenericReq, req, scsi_req_find(&s->qdev, tag));
2cc977e2
TS
85}
86
87/* Helper function for command completion. */
88static void scsi_command_complete(void *opaque, int ret)
89{
4c41d2ef
GH
90 SCSIGenericReq *r = (SCSIGenericReq *)opaque;
91 SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev);
2cc977e2 92 uint32_t tag;
89c0f643 93 int status;
2cc977e2
TS
94
95 s->driver_status = r->io_header.driver_status;
89c0f643
AJ
96 if (s->driver_status & SG_ERR_DRIVER_SENSE)
97 s->senselen = r->io_header.sb_len_wr;
98
2cc977e2 99 if (ret != 0)
89c0f643 100 status = BUSY << 1;
2cc977e2
TS
101 else {
102 if (s->driver_status & SG_ERR_DRIVER_TIMEOUT) {
89c0f643 103 status = BUSY << 1;
2cc977e2 104 BADF("Driver Timeout\n");
89c0f643
AJ
105 } else if (r->io_header.status)
106 status = r->io_header.status;
107 else if (s->driver_status & SG_ERR_DRIVER_SENSE)
108 status = CHECK_CONDITION << 1;
2cc977e2 109 else
89c0f643 110 status = GOOD << 1;
2cc977e2 111 }
89c0f643 112 DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
4c41d2ef
GH
113 r, r->req.tag, status);
114 tag = r->req.tag;
4c41d2ef 115 r->req.bus->complete(r->req.bus, SCSI_REASON_DONE, tag, status);
89b08ae1 116 scsi_remove_request(r);
2cc977e2
TS
117}
118
119/* Cancel a pending data transfer. */
120static void scsi_cancel_io(SCSIDevice *d, uint32_t tag)
121{
122 DPRINTF("scsi_cancel_io 0x%x\n", tag);
d52affa7 123 SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
4c41d2ef 124 SCSIGenericReq *r;
2cc977e2
TS
125 DPRINTF("Cancel tag=0x%x\n", tag);
126 r = scsi_find_request(s, tag);
127 if (r) {
4c41d2ef
GH
128 if (r->req.aiocb)
129 bdrv_aio_cancel(r->req.aiocb);
130 r->req.aiocb = NULL;
2cc977e2
TS
131 scsi_remove_request(r);
132 }
133}
134
135static int execute_command(BlockDriverState *bdrv,
4c41d2ef 136 SCSIGenericReq *r, int direction,
2cc977e2
TS
137 BlockDriverCompletionFunc *complete)
138{
4c41d2ef
GH
139 SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev);
140
2cc977e2
TS
141 r->io_header.interface_id = 'S';
142 r->io_header.dxfer_direction = direction;
143 r->io_header.dxferp = r->buf;
144 r->io_header.dxfer_len = r->buflen;
29362ebe
GH
145 r->io_header.cmdp = r->req.cmd.buf;
146 r->io_header.cmd_len = r->req.cmd.len;
4c41d2ef
GH
147 r->io_header.mx_sb_len = sizeof(s->sensebuf);
148 r->io_header.sbp = s->sensebuf;
2cc977e2
TS
149 r->io_header.timeout = MAX_UINT;
150 r->io_header.usr_ptr = r;
151 r->io_header.flags |= SG_FLAG_DIRECT_IO;
152
4c41d2ef
GH
153 r->req.aiocb = bdrv_aio_ioctl(bdrv, SG_IO, &r->io_header, complete, r);
154 if (r->req.aiocb == NULL) {
2cc977e2
TS
155 BADF("execute_command: read failed !\n");
156 return -1;
157 }
158
159 return 0;
160}
161
162static void scsi_read_complete(void * opaque, int ret)
163{
4c41d2ef 164 SCSIGenericReq *r = (SCSIGenericReq *)opaque;
2cc977e2
TS
165 int len;
166
167 if (ret) {
168 DPRINTF("IO error\n");
169 scsi_command_complete(r, ret);
170 return;
171 }
172 len = r->io_header.dxfer_len - r->io_header.resid;
4c41d2ef 173 DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, len);
2cc977e2
TS
174
175 r->len = -1;
4c41d2ef 176 r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, len);
89c0f643
AJ
177 if (len == 0)
178 scsi_command_complete(r, 0);
2cc977e2
TS
179}
180
181/* Read more data from scsi device into buffer. */
182static void scsi_read_data(SCSIDevice *d, uint32_t tag)
183{
d52affa7 184 SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
4c41d2ef 185 SCSIGenericReq *r;
2cc977e2
TS
186 int ret;
187
188 DPRINTF("scsi_read_data 0x%x\n", tag);
189 r = scsi_find_request(s, tag);
190 if (!r) {
191 BADF("Bad read tag 0x%x\n", tag);
192 /* ??? This is the wrong error. */
193 scsi_command_complete(r, -EINVAL);
194 return;
195 }
196
197 if (r->len == -1) {
198 scsi_command_complete(r, 0);
199 return;
200 }
201
29362ebe 202 if (r->req.cmd.buf[0] == REQUEST_SENSE && s->driver_status & SG_ERR_DRIVER_SENSE)
2cc977e2 203 {
89c0f643
AJ
204 s->senselen = MIN(r->len, s->senselen);
205 memcpy(r->buf, s->sensebuf, s->senselen);
2cc977e2 206 r->io_header.driver_status = 0;
89c0f643
AJ
207 r->io_header.status = 0;
208 r->io_header.dxfer_len = s->senselen;
2cc977e2 209 r->len = -1;
4c41d2ef 210 DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, s->senselen);
a9dd6843
AL
211 DPRINTF("Sense: %d %d %d %d %d %d %d %d\n",
212 r->buf[0], r->buf[1], r->buf[2], r->buf[3],
213 r->buf[4], r->buf[5], r->buf[6], r->buf[7]);
4c41d2ef 214 r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, s->senselen);
2cc977e2
TS
215 return;
216 }
217
d52affa7 218 ret = execute_command(s->dinfo->bdrv, r, SG_DXFER_FROM_DEV, scsi_read_complete);
2cc977e2
TS
219 if (ret == -1) {
220 scsi_command_complete(r, -EINVAL);
221 return;
222 }
223}
224
225static void scsi_write_complete(void * opaque, int ret)
226{
4c41d2ef
GH
227 SCSIGenericReq *r = (SCSIGenericReq *)opaque;
228 SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev);
2cc977e2
TS
229
230 DPRINTF("scsi_write_complete() ret = %d\n", ret);
231 if (ret) {
232 DPRINTF("IO error\n");
233 scsi_command_complete(r, ret);
234 return;
235 }
236
29362ebe 237 if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 &&
91376656 238 s->qdev.type == TYPE_TAPE) {
b07995e3 239 s->qdev.blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
4c41d2ef 240 DPRINTF("block size %d\n", s->blocksize);
89c0f643
AJ
241 }
242
2cc977e2
TS
243 scsi_command_complete(r, ret);
244}
245
246/* Write data to a scsi device. Returns nonzero on failure.
247 The transfer may complete asynchronously. */
248static int scsi_write_data(SCSIDevice *d, uint32_t tag)
249{
d52affa7 250 SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
4c41d2ef 251 SCSIGenericReq *r;
2cc977e2
TS
252 int ret;
253
254 DPRINTF("scsi_write_data 0x%x\n", tag);
255 r = scsi_find_request(s, tag);
256 if (!r) {
257 BADF("Bad write tag 0x%x\n", tag);
258 /* ??? This is the wrong error. */
259 scsi_command_complete(r, -EINVAL);
260 return 0;
261 }
262
263 if (r->len == 0) {
264 r->len = r->buflen;
4c41d2ef 265 r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, r->len);
2cc977e2
TS
266 return 0;
267 }
268
d52affa7 269 ret = execute_command(s->dinfo->bdrv, r, SG_DXFER_TO_DEV, scsi_write_complete);
2cc977e2
TS
270 if (ret == -1) {
271 scsi_command_complete(r, -EINVAL);
272 return 1;
273 }
274
275 return 0;
276}
277
278/* Return a pointer to the data buffer. */
279static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag)
280{
d52affa7 281 SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
4c41d2ef 282 SCSIGenericReq *r;
2cc977e2
TS
283 r = scsi_find_request(s, tag);
284 if (!r) {
285 BADF("Bad buffer tag 0x%x\n", tag);
286 return NULL;
287 }
288 return r->buf;
289}
290
291static int scsi_length(uint8_t *cmd, int blocksize, int *cmdlen, uint32_t *len)
292{
293 switch (cmd[0] >> 5) {
294 case 0:
295 *len = cmd[4];
296 *cmdlen = 6;
72ecb8d9
AL
297 /* length 0 means 256 blocks */
298 if (*len == 0)
299 *len = 256;
2cc977e2
TS
300 break;
301 case 1:
302 case 2:
303 *len = cmd[8] | (cmd[7] << 8);
304 *cmdlen = 10;
305 break;
306 case 4:
307 *len = cmd[13] | (cmd[12] << 8) | (cmd[11] << 16) | (cmd[10] << 24);
308 *cmdlen = 16;
309 break;
310 case 5:
311 *len = cmd[9] | (cmd[8] << 8) | (cmd[7] << 16) | (cmd[6] << 24);
312 *cmdlen = 12;
313 break;
314 default:
315 return -1;
316 }
317
318 switch(cmd[0]) {
319 case TEST_UNIT_READY:
320 case REZERO_UNIT:
321 case START_STOP:
322 case SEEK_6:
323 case WRITE_FILEMARKS:
324 case SPACE:
325 case ERASE:
326 case ALLOW_MEDIUM_REMOVAL:
327 case VERIFY:
328 case SEEK_10:
329 case SYNCHRONIZE_CACHE:
330 case LOCK_UNLOCK_CACHE:
331 case LOAD_UNLOAD:
332 case SET_CD_SPEED:
333 case SET_LIMITS:
334 case WRITE_LONG:
335 case MOVE_MEDIUM:
336 case UPDATE_BLOCK:
337 *len = 0;
338 break;
339 case MODE_SENSE:
340 break;
341 case WRITE_SAME:
342 *len = 1;
343 break;
344 case READ_CAPACITY:
345 *len = 8;
346 break;
347 case READ_BLOCK_LIMITS:
348 *len = 6;
349 break;
350 case READ_POSITION:
351 *len = 20;
352 break;
353 case SEND_VOLUME_TAG:
354 *len *= 40;
355 break;
356 case MEDIUM_SCAN:
357 *len *= 8;
358 break;
359 case WRITE_10:
360 cmd[1] &= ~0x08; /* disable FUA */
361 case WRITE_VERIFY:
362 case WRITE_6:
363 case WRITE_12:
364 case WRITE_VERIFY_12:
365 *len *= blocksize;
366 break;
367 case READ_10:
368 cmd[1] &= ~0x08; /* disable FUA */
369 case READ_6:
370 case READ_REVERSE:
371 case RECOVER_BUFFERED_DATA:
372 case READ_12:
373 *len *= blocksize;
374 break;
89c0f643
AJ
375 case INQUIRY:
376 *len = cmd[4] | (cmd[3] << 8);
377 break;
2cc977e2
TS
378 }
379 return 0;
380}
381
a9dd6843
AL
382static int scsi_stream_length(uint8_t *cmd, int blocksize, int *cmdlen, uint32_t *len)
383{
384 switch(cmd[0]) {
385 /* stream commands */
386 case READ_6:
387 case READ_REVERSE:
388 case RECOVER_BUFFERED_DATA:
389 case WRITE_6:
390 *cmdlen = 6;
391 *len = cmd[4] | (cmd[3] << 8) | (cmd[2] << 16);
392 if (cmd[1] & 0x01) /* fixed */
393 *len *= blocksize;
394 break;
395 case REWIND:
396 case START_STOP:
397 *cmdlen = 6;
398 *len = 0;
399 cmd[1] = 0x01; /* force IMMED, otherwise qemu waits end of command */
400 break;
401 /* generic commands */
402 default:
403 return scsi_length(cmd, blocksize, cmdlen, len);
404 }
405 return 0;
406}
407
2cc977e2
TS
408static int is_write(int command)
409{
410 switch (command) {
411 case COPY:
412 case COPY_VERIFY:
413 case COMPARE:
414 case CHANGE_DEFINITION:
415 case LOG_SELECT:
416 case MODE_SELECT:
417 case MODE_SELECT_10:
418 case SEND_DIAGNOSTIC:
419 case WRITE_BUFFER:
420 case FORMAT_UNIT:
421 case REASSIGN_BLOCKS:
422 case RESERVE:
423 case SEARCH_EQUAL:
424 case SEARCH_HIGH:
425 case SEARCH_LOW:
426 case WRITE_6:
427 case WRITE_10:
428 case WRITE_VERIFY:
429 case UPDATE_BLOCK:
430 case WRITE_LONG:
431 case WRITE_SAME:
432 case SEARCH_HIGH_12:
433 case SEARCH_EQUAL_12:
434 case SEARCH_LOW_12:
435 case WRITE_12:
436 case WRITE_VERIFY_12:
437 case SET_WINDOW:
438 case MEDIUM_SCAN:
439 case SEND_VOLUME_TAG:
440 case WRITE_LONG_2:
441 return 1;
442 }
443 return 0;
444}
445
446/* Execute a scsi command. Returns the length of the data expected by the
447 command. This will be Positive for data transfers from the device
448 (eg. disk reads), negative for transfers to the device (eg. disk writes),
449 and zero if the command does not transfer any data. */
450
451static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
452 uint8_t *cmd, int lun)
453{
d52affa7 454 SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
37e828b4
AJ
455 uint32_t len=0;
456 int cmdlen=0;
4c41d2ef 457 SCSIGenericReq *r;
d52affa7 458 SCSIBus *bus;
2cc977e2
TS
459 int ret;
460
91376656 461 if (s->qdev.type == TYPE_TAPE) {
b07995e3 462 if (scsi_stream_length(cmd, s->qdev.blocksize, &cmdlen, &len) == -1) {
a9dd6843
AL
463 BADF("Unsupported command length, command %x\n", cmd[0]);
464 return 0;
465 }
466 } else {
b07995e3 467 if (scsi_length(cmd, s->qdev.blocksize, &cmdlen, &len) == -1) {
a9dd6843
AL
468 BADF("Unsupported command length, command %x\n", cmd[0]);
469 return 0;
470 }
2cc977e2
TS
471 }
472
473 DPRINTF("Command: lun=%d tag=0x%x data=0x%02x len %d\n", lun, tag,
474 cmd[0], len);
475
89c0f643
AJ
476 if (cmd[0] != REQUEST_SENSE &&
477 (lun != s->lun || (cmd[1] >> 5) != s->lun)) {
478 DPRINTF("Unimplemented LUN %d\n", lun ? lun : cmd[1] >> 5);
479
480 s->sensebuf[0] = 0x70;
481 s->sensebuf[1] = 0x00;
482 s->sensebuf[2] = ILLEGAL_REQUEST;
483 s->sensebuf[3] = 0x00;
484 s->sensebuf[4] = 0x00;
485 s->sensebuf[5] = 0x00;
486 s->sensebuf[6] = 0x00;
487 s->senselen = 7;
488 s->driver_status = SG_ERR_DRIVER_SENSE;
d52affa7
GH
489 bus = scsi_bus_from_device(d);
490 bus->complete(bus, SCSI_REASON_DONE, tag, CHECK_CONDITION << 1);
89c0f643
AJ
491 return 0;
492 }
493
2cc977e2
TS
494 r = scsi_find_request(s, tag);
495 if (r) {
496 BADF("Tag 0x%x already in use %p\n", tag, r);
497 scsi_cancel_io(d, tag);
498 }
89b08ae1 499 r = scsi_new_request(d, tag, lun);
2cc977e2 500
29362ebe
GH
501 memcpy(r->req.cmd.buf, cmd, cmdlen);
502 r->req.cmd.len = cmdlen;
2cc977e2
TS
503
504 if (len == 0) {
505 if (r->buf != NULL)
e3c916e6 506 qemu_free(r->buf);
2cc977e2
TS
507 r->buflen = 0;
508 r->buf = NULL;
d52affa7 509 ret = execute_command(s->dinfo->bdrv, r, SG_DXFER_NONE, scsi_command_complete);
2cc977e2
TS
510 if (ret == -1) {
511 scsi_command_complete(r, -EINVAL);
512 return 0;
513 }
514 return 0;
515 }
516
517 if (r->buflen != len) {
518 if (r->buf != NULL)
e3c916e6 519 qemu_free(r->buf);
2cc977e2
TS
520 r->buf = qemu_malloc(len);
521 r->buflen = len;
522 }
523
524 memset(r->buf, 0, r->buflen);
525 r->len = len;
526 if (is_write(cmd[0])) {
527 r->len = 0;
528 return -len;
529 }
530
531 return len;
532}
533
534static int get_blocksize(BlockDriverState *bdrv)
535{
536 uint8_t cmd[10];
537 uint8_t buf[8];
538 uint8_t sensebuf[8];
539 sg_io_hdr_t io_header;
540 int ret;
541
4f26a486
AL
542 memset(cmd, 0, sizeof(cmd));
543 memset(buf, 0, sizeof(buf));
2cc977e2
TS
544 cmd[0] = READ_CAPACITY;
545
546 memset(&io_header, 0, sizeof(io_header));
547 io_header.interface_id = 'S';
548 io_header.dxfer_direction = SG_DXFER_FROM_DEV;
549 io_header.dxfer_len = sizeof(buf);
550 io_header.dxferp = buf;
551 io_header.cmdp = cmd;
552 io_header.cmd_len = sizeof(cmd);
553 io_header.mx_sb_len = sizeof(sensebuf);
554 io_header.sbp = sensebuf;
555 io_header.timeout = 6000; /* XXX */
556
221f715d 557 ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
7d780669 558 if (ret < 0)
2cc977e2
TS
559 return -1;
560
561 return (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
562}
563
89c0f643
AJ
564static int get_stream_blocksize(BlockDriverState *bdrv)
565{
566 uint8_t cmd[6];
567 uint8_t buf[12];
568 uint8_t sensebuf[8];
569 sg_io_hdr_t io_header;
570 int ret;
571
572 memset(cmd, 0, sizeof(cmd));
573 memset(buf, 0, sizeof(buf));
574 cmd[0] = MODE_SENSE;
575 cmd[4] = sizeof(buf);
576
577 memset(&io_header, 0, sizeof(io_header));
578 io_header.interface_id = 'S';
579 io_header.dxfer_direction = SG_DXFER_FROM_DEV;
580 io_header.dxfer_len = sizeof(buf);
581 io_header.dxferp = buf;
582 io_header.cmdp = cmd;
583 io_header.cmd_len = sizeof(cmd);
584 io_header.mx_sb_len = sizeof(sensebuf);
585 io_header.sbp = sensebuf;
586 io_header.timeout = 6000; /* XXX */
587
221f715d 588 ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
7d780669 589 if (ret < 0)
89c0f643
AJ
590 return -1;
591
592 return (buf[9] << 16) | (buf[10] << 8) | buf[11];
593}
594
2cc977e2
TS
595static void scsi_destroy(SCSIDevice *d)
596{
d52affa7 597 SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
9af99d98 598 SCSIGenericReq *r;
2cc977e2 599
9af99d98
GH
600 while (!QTAILQ_EMPTY(&s->qdev.requests)) {
601 r = DO_UPCAST(SCSIGenericReq, req, QTAILQ_FIRST(&s->qdev.requests));
602 scsi_remove_request(r);
2cc977e2 603 }
56a14938 604 drive_uninit(s->dinfo);
2cc977e2
TS
605}
606
d52affa7 607static int scsi_generic_initfn(SCSIDevice *dev)
2cc977e2 608{
d52affa7 609 SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, dev);
2cc977e2 610 int sg_version;
2cc977e2
TS
611 struct sg_scsi_id scsiid;
612
d52affa7
GH
613 if (!s->dinfo || !s->dinfo->bdrv) {
614 qemu_error("scsi-generic: drive property not set\n");
615 return -1;
616 }
2cc977e2 617
d52affa7
GH
618 /* check we are really using a /dev/sg* file */
619 if (!bdrv_is_sg(s->dinfo->bdrv)) {
620 qemu_error("scsi-generic: not /dev/sg*\n");
621 return -1;
622 }
2cc977e2
TS
623
624 /* check we are using a driver managing SG_IO (version 3 and after */
d52affa7
GH
625 if (bdrv_ioctl(s->dinfo->bdrv, SG_GET_VERSION_NUM, &sg_version) < 0 ||
626 sg_version < 30000) {
627 qemu_error("scsi-generic: scsi generic interface too old\n");
628 return -1;
629 }
2cc977e2
TS
630
631 /* get LUN of the /dev/sg? */
d52affa7
GH
632 if (bdrv_ioctl(s->dinfo->bdrv, SG_GET_SCSI_ID, &scsiid)) {
633 qemu_error("scsi-generic: SG_GET_SCSI_ID ioctl failed\n");
634 return -1;
635 }
2cc977e2
TS
636
637 /* define device state */
2cc977e2 638 s->lun = scsiid.lun;
89c0f643 639 DPRINTF("LUN %d\n", s->lun);
91376656
GH
640 s->qdev.type = scsiid.scsi_type;
641 DPRINTF("device type %d\n", s->qdev.type);
642 if (s->qdev.type == TYPE_TAPE) {
b07995e3
GH
643 s->qdev.blocksize = get_stream_blocksize(s->dinfo->bdrv);
644 if (s->qdev.blocksize == -1)
645 s->qdev.blocksize = 0;
89c0f643 646 } else {
b07995e3 647 s->qdev.blocksize = get_blocksize(s->dinfo->bdrv);
89c0f643 648 /* removable media returns 0 if not present */
b07995e3 649 if (s->qdev.blocksize <= 0) {
91376656 650 if (s->qdev.type == TYPE_ROM || s->qdev.type == TYPE_WORM)
b07995e3 651 s->qdev.blocksize = 2048;
89c0f643 652 else
b07995e3 653 s->qdev.blocksize = 512;
89c0f643
AJ
654 }
655 }
b07995e3 656 DPRINTF("block size %d\n", s->qdev.blocksize);
2cc977e2
TS
657 s->driver_status = 0;
658 memset(s->sensebuf, 0, sizeof(s->sensebuf));
d52affa7
GH
659 return 0;
660}
2cc977e2 661
d52affa7
GH
662static SCSIDeviceInfo scsi_generic_info = {
663 .qdev.name = "scsi-generic",
664 .qdev.desc = "pass through generic scsi device (/dev/sg*)",
665 .qdev.size = sizeof(SCSIGenericState),
666 .init = scsi_generic_initfn,
667 .destroy = scsi_destroy,
668 .send_command = scsi_send_command,
669 .read_data = scsi_read_data,
670 .write_data = scsi_write_data,
671 .cancel_io = scsi_cancel_io,
672 .get_buf = scsi_get_buf,
673 .qdev.props = (Property[]) {
674 DEFINE_PROP_DRIVE("drive", SCSIGenericState, dinfo),
675 DEFINE_PROP_END_OF_LIST(),
676 },
677};
2cc977e2 678
d52affa7
GH
679static void scsi_generic_register_devices(void)
680{
681 scsi_qdev_register(&scsi_generic_info);
2cc977e2 682}
d52affa7
GH
683device_init(scsi_generic_register_devices)
684
2cc977e2 685#endif /* __linux__ */