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