Statistics
| Branch: | Revision:

root / hw / scsi-generic.c @ f2e17508

History | View | Annotate | Download (14.7 kB)

1 2cc977e2 ths
/*
2 2cc977e2 ths
 * Generic SCSI Device support
3 2cc977e2 ths
 *
4 2cc977e2 ths
 * Copyright (c) 2007 Bull S.A.S.
5 2cc977e2 ths
 * Based on code by Paul Brook
6 2cc977e2 ths
 * Based on code by Fabrice Bellard
7 2cc977e2 ths
 *
8 2cc977e2 ths
 * Written by Laurent Vivier <Laurent.Vivier@bull.net>
9 2cc977e2 ths
 *
10 2cc977e2 ths
 * This code is licenced under the LGPL.
11 2cc977e2 ths
 *
12 2cc977e2 ths
 */
13 2cc977e2 ths
14 2cc977e2 ths
#include "qemu-common.h"
15 2cc977e2 ths
#include "block.h"
16 43b443b6 Gerd Hoffmann
#include "scsi.h"
17 2cc977e2 ths
18 d52affa7 Gerd Hoffmann
#ifdef __linux__
19 2cc977e2 ths
20 2cc977e2 ths
//#define DEBUG_SCSI
21 2cc977e2 ths
22 2cc977e2 ths
#ifdef DEBUG_SCSI
23 001faf32 Blue Swirl
#define DPRINTF(fmt, ...) \
24 001faf32 Blue Swirl
do { printf("scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
25 2cc977e2 ths
#else
26 001faf32 Blue Swirl
#define DPRINTF(fmt, ...) do {} while(0)
27 2cc977e2 ths
#endif
28 2cc977e2 ths
29 001faf32 Blue Swirl
#define BADF(fmt, ...) \
30 001faf32 Blue Swirl
do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
31 2cc977e2 ths
32 2cc977e2 ths
#include <stdio.h>
33 2cc977e2 ths
#include <sys/types.h>
34 2cc977e2 ths
#include <sys/stat.h>
35 2cc977e2 ths
#include <unistd.h>
36 2cc977e2 ths
#include <scsi/sg.h>
37 0d65e1f8 Gerd Hoffmann
#include "scsi-defs.h"
38 2cc977e2 ths
39 a9dd6843 aliguori
#define SCSI_SENSE_BUF_SIZE 96
40 2cc977e2 ths
41 2cc977e2 ths
#define SG_ERR_DRIVER_TIMEOUT 0x06
42 2cc977e2 ths
#define SG_ERR_DRIVER_SENSE 0x08
43 2cc977e2 ths
44 2cc977e2 ths
#ifndef MAX_UINT
45 2cc977e2 ths
#define MAX_UINT ((unsigned int)-1)
46 2cc977e2 ths
#endif
47 2cc977e2 ths
48 d52affa7 Gerd Hoffmann
typedef struct SCSIGenericState SCSIGenericState;
49 d52affa7 Gerd Hoffmann
50 4c41d2ef Gerd Hoffmann
typedef struct SCSIGenericReq {
51 4c41d2ef Gerd Hoffmann
    SCSIRequest req;
52 2cc977e2 ths
    uint8_t *buf;
53 2cc977e2 ths
    int buflen;
54 2cc977e2 ths
    int len;
55 2cc977e2 ths
    sg_io_hdr_t io_header;
56 4c41d2ef Gerd Hoffmann
} SCSIGenericReq;
57 2cc977e2 ths
58 d52affa7 Gerd Hoffmann
struct SCSIGenericState
59 2cc977e2 ths
{
60 d52affa7 Gerd Hoffmann
    SCSIDevice qdev;
61 2cc977e2 ths
    int lun;
62 2cc977e2 ths
    int driver_status;
63 2cc977e2 ths
    uint8_t sensebuf[SCSI_SENSE_BUF_SIZE];
64 89c0f643 aurel32
    uint8_t senselen;
65 2cc977e2 ths
};
66 2cc977e2 ths
67 89b08ae1 Gerd Hoffmann
static SCSIGenericReq *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun)
68 2cc977e2 ths
{
69 89b08ae1 Gerd Hoffmann
    SCSIRequest *req;
70 2cc977e2 ths
71 89b08ae1 Gerd Hoffmann
    req = scsi_req_alloc(sizeof(SCSIGenericReq), d, tag, lun);
72 89b08ae1 Gerd Hoffmann
    return DO_UPCAST(SCSIGenericReq, req, req);
73 2cc977e2 ths
}
74 2cc977e2 ths
75 4c41d2ef Gerd Hoffmann
static void scsi_remove_request(SCSIGenericReq *r)
76 2cc977e2 ths
{
77 9af99d98 Gerd Hoffmann
    qemu_free(r->buf);
78 89b08ae1 Gerd Hoffmann
    scsi_req_free(&r->req);
79 2cc977e2 ths
}
80 2cc977e2 ths
81 4c41d2ef Gerd Hoffmann
static SCSIGenericReq *scsi_find_request(SCSIGenericState *s, uint32_t tag)
82 2cc977e2 ths
{
83 89b08ae1 Gerd Hoffmann
    return DO_UPCAST(SCSIGenericReq, req, scsi_req_find(&s->qdev, tag));
84 2cc977e2 ths
}
85 2cc977e2 ths
86 2cc977e2 ths
/* Helper function for command completion.  */
87 2cc977e2 ths
static void scsi_command_complete(void *opaque, int ret)
88 2cc977e2 ths
{
89 4c41d2ef Gerd Hoffmann
    SCSIGenericReq *r = (SCSIGenericReq *)opaque;
90 4c41d2ef Gerd Hoffmann
    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev);
91 2cc977e2 ths
92 2cc977e2 ths
    s->driver_status = r->io_header.driver_status;
93 89c0f643 aurel32
    if (s->driver_status & SG_ERR_DRIVER_SENSE)
94 89c0f643 aurel32
        s->senselen = r->io_header.sb_len_wr;
95 89c0f643 aurel32
96 2cc977e2 ths
    if (ret != 0)
97 ed3a34a3 Gerd Hoffmann
        r->req.status = BUSY << 1;
98 2cc977e2 ths
    else {
99 2cc977e2 ths
        if (s->driver_status & SG_ERR_DRIVER_TIMEOUT) {
100 ed3a34a3 Gerd Hoffmann
            r->req.status = BUSY << 1;
101 2cc977e2 ths
            BADF("Driver Timeout\n");
102 89c0f643 aurel32
        } else if (r->io_header.status)
103 ed3a34a3 Gerd Hoffmann
            r->req.status = r->io_header.status;
104 89c0f643 aurel32
        else if (s->driver_status & SG_ERR_DRIVER_SENSE)
105 ed3a34a3 Gerd Hoffmann
            r->req.status = CHECK_CONDITION << 1;
106 2cc977e2 ths
        else
107 ed3a34a3 Gerd Hoffmann
            r->req.status = GOOD << 1;
108 2cc977e2 ths
    }
109 89c0f643 aurel32
    DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
110 ed3a34a3 Gerd Hoffmann
            r, r->req.tag, r->req.status);
111 ed3a34a3 Gerd Hoffmann
112 ed3a34a3 Gerd Hoffmann
    scsi_req_complete(&r->req);
113 89b08ae1 Gerd Hoffmann
    scsi_remove_request(r);
114 2cc977e2 ths
}
115 2cc977e2 ths
116 2cc977e2 ths
/* Cancel a pending data transfer.  */
117 2cc977e2 ths
static void scsi_cancel_io(SCSIDevice *d, uint32_t tag)
118 2cc977e2 ths
{
119 2cc977e2 ths
    DPRINTF("scsi_cancel_io 0x%x\n", tag);
120 d52affa7 Gerd Hoffmann
    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
121 4c41d2ef Gerd Hoffmann
    SCSIGenericReq *r;
122 2cc977e2 ths
    DPRINTF("Cancel tag=0x%x\n", tag);
123 2cc977e2 ths
    r = scsi_find_request(s, tag);
124 2cc977e2 ths
    if (r) {
125 4c41d2ef Gerd Hoffmann
        if (r->req.aiocb)
126 4c41d2ef Gerd Hoffmann
            bdrv_aio_cancel(r->req.aiocb);
127 4c41d2ef Gerd Hoffmann
        r->req.aiocb = NULL;
128 2cc977e2 ths
        scsi_remove_request(r);
129 2cc977e2 ths
    }
130 2cc977e2 ths
}
131 2cc977e2 ths
132 2cc977e2 ths
static int execute_command(BlockDriverState *bdrv,
133 4c41d2ef Gerd Hoffmann
                           SCSIGenericReq *r, int direction,
134 2cc977e2 ths
                           BlockDriverCompletionFunc *complete)
135 2cc977e2 ths
{
136 4c41d2ef Gerd Hoffmann
    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev);
137 4c41d2ef Gerd Hoffmann
138 2cc977e2 ths
    r->io_header.interface_id = 'S';
139 2cc977e2 ths
    r->io_header.dxfer_direction = direction;
140 2cc977e2 ths
    r->io_header.dxferp = r->buf;
141 2cc977e2 ths
    r->io_header.dxfer_len = r->buflen;
142 29362ebe Gerd Hoffmann
    r->io_header.cmdp = r->req.cmd.buf;
143 29362ebe Gerd Hoffmann
    r->io_header.cmd_len = r->req.cmd.len;
144 4c41d2ef Gerd Hoffmann
    r->io_header.mx_sb_len = sizeof(s->sensebuf);
145 4c41d2ef Gerd Hoffmann
    r->io_header.sbp = s->sensebuf;
146 2cc977e2 ths
    r->io_header.timeout = MAX_UINT;
147 2cc977e2 ths
    r->io_header.usr_ptr = r;
148 2cc977e2 ths
    r->io_header.flags |= SG_FLAG_DIRECT_IO;
149 2cc977e2 ths
150 4c41d2ef Gerd Hoffmann
    r->req.aiocb = bdrv_aio_ioctl(bdrv, SG_IO, &r->io_header, complete, r);
151 4c41d2ef Gerd Hoffmann
    if (r->req.aiocb == NULL) {
152 2cc977e2 ths
        BADF("execute_command: read failed !\n");
153 2cc977e2 ths
        return -1;
154 2cc977e2 ths
    }
155 2cc977e2 ths
156 2cc977e2 ths
    return 0;
157 2cc977e2 ths
}
158 2cc977e2 ths
159 2cc977e2 ths
static void scsi_read_complete(void * opaque, int ret)
160 2cc977e2 ths
{
161 4c41d2ef Gerd Hoffmann
    SCSIGenericReq *r = (SCSIGenericReq *)opaque;
162 2cc977e2 ths
    int len;
163 2cc977e2 ths
164 2cc977e2 ths
    if (ret) {
165 2cc977e2 ths
        DPRINTF("IO error\n");
166 2cc977e2 ths
        scsi_command_complete(r, ret);
167 2cc977e2 ths
        return;
168 2cc977e2 ths
    }
169 2cc977e2 ths
    len = r->io_header.dxfer_len - r->io_header.resid;
170 4c41d2ef Gerd Hoffmann
    DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, len);
171 2cc977e2 ths
172 2cc977e2 ths
    r->len = -1;
173 4c41d2ef Gerd Hoffmann
    r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, len);
174 89c0f643 aurel32
    if (len == 0)
175 89c0f643 aurel32
        scsi_command_complete(r, 0);
176 2cc977e2 ths
}
177 2cc977e2 ths
178 2cc977e2 ths
/* Read more data from scsi device into buffer.  */
179 2cc977e2 ths
static void scsi_read_data(SCSIDevice *d, uint32_t tag)
180 2cc977e2 ths
{
181 d52affa7 Gerd Hoffmann
    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
182 4c41d2ef Gerd Hoffmann
    SCSIGenericReq *r;
183 2cc977e2 ths
    int ret;
184 2cc977e2 ths
185 2cc977e2 ths
    DPRINTF("scsi_read_data 0x%x\n", tag);
186 2cc977e2 ths
    r = scsi_find_request(s, tag);
187 2cc977e2 ths
    if (!r) {
188 2cc977e2 ths
        BADF("Bad read tag 0x%x\n", tag);
189 2cc977e2 ths
        /* ??? This is the wrong error.  */
190 2cc977e2 ths
        scsi_command_complete(r, -EINVAL);
191 2cc977e2 ths
        return;
192 2cc977e2 ths
    }
193 2cc977e2 ths
194 2cc977e2 ths
    if (r->len == -1) {
195 2cc977e2 ths
        scsi_command_complete(r, 0);
196 2cc977e2 ths
        return;
197 2cc977e2 ths
    }
198 2cc977e2 ths
199 29362ebe Gerd Hoffmann
    if (r->req.cmd.buf[0] == REQUEST_SENSE && s->driver_status & SG_ERR_DRIVER_SENSE)
200 2cc977e2 ths
    {
201 89c0f643 aurel32
        s->senselen = MIN(r->len, s->senselen);
202 89c0f643 aurel32
        memcpy(r->buf, s->sensebuf, s->senselen);
203 2cc977e2 ths
        r->io_header.driver_status = 0;
204 89c0f643 aurel32
        r->io_header.status = 0;
205 89c0f643 aurel32
        r->io_header.dxfer_len  = s->senselen;
206 2cc977e2 ths
        r->len = -1;
207 4c41d2ef Gerd Hoffmann
        DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, s->senselen);
208 a9dd6843 aliguori
        DPRINTF("Sense: %d %d %d %d %d %d %d %d\n",
209 a9dd6843 aliguori
                r->buf[0], r->buf[1], r->buf[2], r->buf[3],
210 a9dd6843 aliguori
                r->buf[4], r->buf[5], r->buf[6], r->buf[7]);
211 4c41d2ef Gerd Hoffmann
        r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, s->senselen);
212 2cc977e2 ths
        return;
213 2cc977e2 ths
    }
214 2cc977e2 ths
215 251882b7 Gerd Hoffmann
    ret = execute_command(s->qdev.dinfo->bdrv, r, SG_DXFER_FROM_DEV, scsi_read_complete);
216 2cc977e2 ths
    if (ret == -1) {
217 2cc977e2 ths
        scsi_command_complete(r, -EINVAL);
218 2cc977e2 ths
        return;
219 2cc977e2 ths
    }
220 2cc977e2 ths
}
221 2cc977e2 ths
222 2cc977e2 ths
static void scsi_write_complete(void * opaque, int ret)
223 2cc977e2 ths
{
224 4c41d2ef Gerd Hoffmann
    SCSIGenericReq *r = (SCSIGenericReq *)opaque;
225 4c41d2ef Gerd Hoffmann
    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev);
226 2cc977e2 ths
227 2cc977e2 ths
    DPRINTF("scsi_write_complete() ret = %d\n", ret);
228 2cc977e2 ths
    if (ret) {
229 2cc977e2 ths
        DPRINTF("IO error\n");
230 2cc977e2 ths
        scsi_command_complete(r, ret);
231 2cc977e2 ths
        return;
232 2cc977e2 ths
    }
233 2cc977e2 ths
234 29362ebe Gerd Hoffmann
    if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 &&
235 91376656 Gerd Hoffmann
        s->qdev.type == TYPE_TAPE) {
236 b07995e3 Gerd Hoffmann
        s->qdev.blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
237 4c41d2ef Gerd Hoffmann
        DPRINTF("block size %d\n", s->blocksize);
238 89c0f643 aurel32
    }
239 89c0f643 aurel32
240 2cc977e2 ths
    scsi_command_complete(r, ret);
241 2cc977e2 ths
}
242 2cc977e2 ths
243 2cc977e2 ths
/* Write data to a scsi device.  Returns nonzero on failure.
244 2cc977e2 ths
   The transfer may complete asynchronously.  */
245 2cc977e2 ths
static int scsi_write_data(SCSIDevice *d, uint32_t tag)
246 2cc977e2 ths
{
247 d52affa7 Gerd Hoffmann
    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
248 4c41d2ef Gerd Hoffmann
    SCSIGenericReq *r;
249 2cc977e2 ths
    int ret;
250 2cc977e2 ths
251 2cc977e2 ths
    DPRINTF("scsi_write_data 0x%x\n", tag);
252 2cc977e2 ths
    r = scsi_find_request(s, tag);
253 2cc977e2 ths
    if (!r) {
254 2cc977e2 ths
        BADF("Bad write tag 0x%x\n", tag);
255 2cc977e2 ths
        /* ??? This is the wrong error.  */
256 2cc977e2 ths
        scsi_command_complete(r, -EINVAL);
257 2cc977e2 ths
        return 0;
258 2cc977e2 ths
    }
259 2cc977e2 ths
260 2cc977e2 ths
    if (r->len == 0) {
261 2cc977e2 ths
        r->len = r->buflen;
262 4c41d2ef Gerd Hoffmann
        r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, r->len);
263 2cc977e2 ths
        return 0;
264 2cc977e2 ths
    }
265 2cc977e2 ths
266 251882b7 Gerd Hoffmann
    ret = execute_command(s->qdev.dinfo->bdrv, r, SG_DXFER_TO_DEV, scsi_write_complete);
267 2cc977e2 ths
    if (ret == -1) {
268 2cc977e2 ths
        scsi_command_complete(r, -EINVAL);
269 2cc977e2 ths
        return 1;
270 2cc977e2 ths
    }
271 2cc977e2 ths
272 2cc977e2 ths
    return 0;
273 2cc977e2 ths
}
274 2cc977e2 ths
275 2cc977e2 ths
/* Return a pointer to the data buffer.  */
276 2cc977e2 ths
static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag)
277 2cc977e2 ths
{
278 d52affa7 Gerd Hoffmann
    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
279 4c41d2ef Gerd Hoffmann
    SCSIGenericReq *r;
280 2cc977e2 ths
    r = scsi_find_request(s, tag);
281 2cc977e2 ths
    if (!r) {
282 2cc977e2 ths
        BADF("Bad buffer tag 0x%x\n", tag);
283 2cc977e2 ths
        return NULL;
284 2cc977e2 ths
    }
285 2cc977e2 ths
    return r->buf;
286 2cc977e2 ths
}
287 2cc977e2 ths
288 2ec749cb Gerd Hoffmann
static void scsi_req_fixup(SCSIRequest *req)
289 2cc977e2 ths
{
290 2ec749cb Gerd Hoffmann
    switch(req->cmd.buf[0]) {
291 2cc977e2 ths
    case WRITE_10:
292 2ec749cb Gerd Hoffmann
        req->cmd.buf[1] &= ~0x08;        /* disable FUA */
293 2cc977e2 ths
        break;
294 2cc977e2 ths
    case READ_10:
295 2ec749cb Gerd Hoffmann
        req->cmd.buf[1] &= ~0x08;        /* disable FUA */
296 a9dd6843 aliguori
        break;
297 a9dd6843 aliguori
    case REWIND:
298 a9dd6843 aliguori
    case START_STOP:
299 2ec749cb Gerd Hoffmann
        if (req->dev->type == TYPE_TAPE) {
300 2ec749cb Gerd Hoffmann
            /* force IMMED, otherwise qemu waits end of command */
301 2ec749cb Gerd Hoffmann
            req->cmd.buf[1] = 0x01;
302 2ec749cb Gerd Hoffmann
        }
303 a9dd6843 aliguori
        break;
304 a9dd6843 aliguori
    }
305 a9dd6843 aliguori
}
306 a9dd6843 aliguori
307 2cc977e2 ths
/* Execute a scsi command.  Returns the length of the data expected by the
308 2cc977e2 ths
   command.  This will be Positive for data transfers from the device
309 2cc977e2 ths
   (eg. disk reads), negative for transfers to the device (eg. disk writes),
310 2cc977e2 ths
   and zero if the command does not transfer any data.  */
311 2cc977e2 ths
312 2cc977e2 ths
static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
313 2cc977e2 ths
                                 uint8_t *cmd, int lun)
314 2cc977e2 ths
{
315 d52affa7 Gerd Hoffmann
    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
316 4c41d2ef Gerd Hoffmann
    SCSIGenericReq *r;
317 d52affa7 Gerd Hoffmann
    SCSIBus *bus;
318 2cc977e2 ths
    int ret;
319 2cc977e2 ths
320 89c0f643 aurel32
    if (cmd[0] != REQUEST_SENSE &&
321 89c0f643 aurel32
        (lun != s->lun || (cmd[1] >> 5) != s->lun)) {
322 89c0f643 aurel32
        DPRINTF("Unimplemented LUN %d\n", lun ? lun : cmd[1] >> 5);
323 89c0f643 aurel32
324 89c0f643 aurel32
        s->sensebuf[0] = 0x70;
325 89c0f643 aurel32
        s->sensebuf[1] = 0x00;
326 89c0f643 aurel32
        s->sensebuf[2] = ILLEGAL_REQUEST;
327 89c0f643 aurel32
        s->sensebuf[3] = 0x00;
328 89c0f643 aurel32
        s->sensebuf[4] = 0x00;
329 89c0f643 aurel32
        s->sensebuf[5] = 0x00;
330 89c0f643 aurel32
        s->sensebuf[6] = 0x00;
331 89c0f643 aurel32
        s->senselen = 7;
332 89c0f643 aurel32
        s->driver_status = SG_ERR_DRIVER_SENSE;
333 d52affa7 Gerd Hoffmann
        bus = scsi_bus_from_device(d);
334 d52affa7 Gerd Hoffmann
        bus->complete(bus, SCSI_REASON_DONE, tag, CHECK_CONDITION << 1);
335 89c0f643 aurel32
        return 0;
336 89c0f643 aurel32
    }
337 89c0f643 aurel32
338 2cc977e2 ths
    r = scsi_find_request(s, tag);
339 2cc977e2 ths
    if (r) {
340 2cc977e2 ths
        BADF("Tag 0x%x already in use %p\n", tag, r);
341 2cc977e2 ths
        scsi_cancel_io(d, tag);
342 2cc977e2 ths
    }
343 89b08ae1 Gerd Hoffmann
    r = scsi_new_request(d, tag, lun);
344 2cc977e2 ths
345 2ec749cb Gerd Hoffmann
    if (-1 == scsi_req_parse(&r->req, cmd)) {
346 2ec749cb Gerd Hoffmann
        BADF("Unsupported command length, command %x\n", cmd[0]);
347 2ec749cb Gerd Hoffmann
        scsi_remove_request(r);
348 2ec749cb Gerd Hoffmann
        return 0;
349 2ec749cb Gerd Hoffmann
    }
350 2ec749cb Gerd Hoffmann
    scsi_req_fixup(&r->req);
351 2ec749cb Gerd Hoffmann
352 2ec749cb Gerd Hoffmann
    DPRINTF("Command: lun=%d tag=0x%x data=0x%02x len %d\n", lun, tag,
353 2ec749cb Gerd Hoffmann
            cmd[0], r->req.cmd.xfer);
354 2cc977e2 ths
355 2ec749cb Gerd Hoffmann
    if (r->req.cmd.xfer == 0) {
356 2cc977e2 ths
        if (r->buf != NULL)
357 e3c916e6 Jean-Christophe DUBOIS
            qemu_free(r->buf);
358 2cc977e2 ths
        r->buflen = 0;
359 2cc977e2 ths
        r->buf = NULL;
360 251882b7 Gerd Hoffmann
        ret = execute_command(s->qdev.dinfo->bdrv, r, SG_DXFER_NONE, scsi_command_complete);
361 2cc977e2 ths
        if (ret == -1) {
362 2cc977e2 ths
            scsi_command_complete(r, -EINVAL);
363 2cc977e2 ths
            return 0;
364 2cc977e2 ths
        }
365 2cc977e2 ths
        return 0;
366 2cc977e2 ths
    }
367 2cc977e2 ths
368 2ec749cb Gerd Hoffmann
    if (r->buflen != r->req.cmd.xfer) {
369 2cc977e2 ths
        if (r->buf != NULL)
370 e3c916e6 Jean-Christophe DUBOIS
            qemu_free(r->buf);
371 2ec749cb Gerd Hoffmann
        r->buf = qemu_malloc(r->req.cmd.xfer);
372 2ec749cb Gerd Hoffmann
        r->buflen = r->req.cmd.xfer;
373 2cc977e2 ths
    }
374 2cc977e2 ths
375 2cc977e2 ths
    memset(r->buf, 0, r->buflen);
376 2ec749cb Gerd Hoffmann
    r->len = r->req.cmd.xfer;
377 97a06435 Gerd Hoffmann
    if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
378 2cc977e2 ths
        r->len = 0;
379 2ec749cb Gerd Hoffmann
        return -r->req.cmd.xfer;
380 2cc977e2 ths
    }
381 2cc977e2 ths
382 2ec749cb Gerd Hoffmann
    return r->req.cmd.xfer;
383 2cc977e2 ths
}
384 2cc977e2 ths
385 2cc977e2 ths
static int get_blocksize(BlockDriverState *bdrv)
386 2cc977e2 ths
{
387 2cc977e2 ths
    uint8_t cmd[10];
388 2cc977e2 ths
    uint8_t buf[8];
389 2cc977e2 ths
    uint8_t sensebuf[8];
390 2cc977e2 ths
    sg_io_hdr_t io_header;
391 2cc977e2 ths
    int ret;
392 2cc977e2 ths
393 4f26a486 aliguori
    memset(cmd, 0, sizeof(cmd));
394 4f26a486 aliguori
    memset(buf, 0, sizeof(buf));
395 2cc977e2 ths
    cmd[0] = READ_CAPACITY;
396 2cc977e2 ths
397 2cc977e2 ths
    memset(&io_header, 0, sizeof(io_header));
398 2cc977e2 ths
    io_header.interface_id = 'S';
399 2cc977e2 ths
    io_header.dxfer_direction = SG_DXFER_FROM_DEV;
400 2cc977e2 ths
    io_header.dxfer_len = sizeof(buf);
401 2cc977e2 ths
    io_header.dxferp = buf;
402 2cc977e2 ths
    io_header.cmdp = cmd;
403 2cc977e2 ths
    io_header.cmd_len = sizeof(cmd);
404 2cc977e2 ths
    io_header.mx_sb_len = sizeof(sensebuf);
405 2cc977e2 ths
    io_header.sbp = sensebuf;
406 2cc977e2 ths
    io_header.timeout = 6000; /* XXX */
407 2cc977e2 ths
408 221f715d aliguori
    ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
409 7d780669 aliguori
    if (ret < 0)
410 2cc977e2 ths
        return -1;
411 2cc977e2 ths
412 2cc977e2 ths
    return (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
413 2cc977e2 ths
}
414 2cc977e2 ths
415 89c0f643 aurel32
static int get_stream_blocksize(BlockDriverState *bdrv)
416 89c0f643 aurel32
{
417 89c0f643 aurel32
    uint8_t cmd[6];
418 89c0f643 aurel32
    uint8_t buf[12];
419 89c0f643 aurel32
    uint8_t sensebuf[8];
420 89c0f643 aurel32
    sg_io_hdr_t io_header;
421 89c0f643 aurel32
    int ret;
422 89c0f643 aurel32
423 89c0f643 aurel32
    memset(cmd, 0, sizeof(cmd));
424 89c0f643 aurel32
    memset(buf, 0, sizeof(buf));
425 89c0f643 aurel32
    cmd[0] = MODE_SENSE;
426 89c0f643 aurel32
    cmd[4] = sizeof(buf);
427 89c0f643 aurel32
428 89c0f643 aurel32
    memset(&io_header, 0, sizeof(io_header));
429 89c0f643 aurel32
    io_header.interface_id = 'S';
430 89c0f643 aurel32
    io_header.dxfer_direction = SG_DXFER_FROM_DEV;
431 89c0f643 aurel32
    io_header.dxfer_len = sizeof(buf);
432 89c0f643 aurel32
    io_header.dxferp = buf;
433 89c0f643 aurel32
    io_header.cmdp = cmd;
434 89c0f643 aurel32
    io_header.cmd_len = sizeof(cmd);
435 89c0f643 aurel32
    io_header.mx_sb_len = sizeof(sensebuf);
436 89c0f643 aurel32
    io_header.sbp = sensebuf;
437 89c0f643 aurel32
    io_header.timeout = 6000; /* XXX */
438 89c0f643 aurel32
439 221f715d aliguori
    ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
440 7d780669 aliguori
    if (ret < 0)
441 89c0f643 aurel32
        return -1;
442 89c0f643 aurel32
443 89c0f643 aurel32
    return (buf[9] << 16) | (buf[10] << 8) | buf[11];
444 89c0f643 aurel32
}
445 89c0f643 aurel32
446 2cc977e2 ths
static void scsi_destroy(SCSIDevice *d)
447 2cc977e2 ths
{
448 d52affa7 Gerd Hoffmann
    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
449 9af99d98 Gerd Hoffmann
    SCSIGenericReq *r;
450 2cc977e2 ths
451 9af99d98 Gerd Hoffmann
    while (!QTAILQ_EMPTY(&s->qdev.requests)) {
452 9af99d98 Gerd Hoffmann
        r = DO_UPCAST(SCSIGenericReq, req, QTAILQ_FIRST(&s->qdev.requests));
453 9af99d98 Gerd Hoffmann
        scsi_remove_request(r);
454 2cc977e2 ths
    }
455 251882b7 Gerd Hoffmann
    drive_uninit(s->qdev.dinfo);
456 2cc977e2 ths
}
457 2cc977e2 ths
458 d52affa7 Gerd Hoffmann
static int scsi_generic_initfn(SCSIDevice *dev)
459 2cc977e2 ths
{
460 d52affa7 Gerd Hoffmann
    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, dev);
461 2cc977e2 ths
    int sg_version;
462 2cc977e2 ths
    struct sg_scsi_id scsiid;
463 2cc977e2 ths
464 251882b7 Gerd Hoffmann
    if (!s->qdev.dinfo || !s->qdev.dinfo->bdrv) {
465 d52affa7 Gerd Hoffmann
        qemu_error("scsi-generic: drive property not set\n");
466 d52affa7 Gerd Hoffmann
        return -1;
467 d52affa7 Gerd Hoffmann
    }
468 2cc977e2 ths
469 d52affa7 Gerd Hoffmann
    /* check we are really using a /dev/sg* file */
470 251882b7 Gerd Hoffmann
    if (!bdrv_is_sg(s->qdev.dinfo->bdrv)) {
471 d52affa7 Gerd Hoffmann
        qemu_error("scsi-generic: not /dev/sg*\n");
472 d52affa7 Gerd Hoffmann
        return -1;
473 d52affa7 Gerd Hoffmann
    }
474 2cc977e2 ths
475 2cc977e2 ths
    /* check we are using a driver managing SG_IO (version 3 and after */
476 251882b7 Gerd Hoffmann
    if (bdrv_ioctl(s->qdev.dinfo->bdrv, SG_GET_VERSION_NUM, &sg_version) < 0 ||
477 d52affa7 Gerd Hoffmann
        sg_version < 30000) {
478 d52affa7 Gerd Hoffmann
        qemu_error("scsi-generic: scsi generic interface too old\n");
479 d52affa7 Gerd Hoffmann
        return -1;
480 d52affa7 Gerd Hoffmann
    }
481 2cc977e2 ths
482 2cc977e2 ths
    /* get LUN of the /dev/sg? */
483 251882b7 Gerd Hoffmann
    if (bdrv_ioctl(s->qdev.dinfo->bdrv, SG_GET_SCSI_ID, &scsiid)) {
484 d52affa7 Gerd Hoffmann
        qemu_error("scsi-generic: SG_GET_SCSI_ID ioctl failed\n");
485 d52affa7 Gerd Hoffmann
        return -1;
486 d52affa7 Gerd Hoffmann
    }
487 2cc977e2 ths
488 2cc977e2 ths
    /* define device state */
489 2cc977e2 ths
    s->lun = scsiid.lun;
490 89c0f643 aurel32
    DPRINTF("LUN %d\n", s->lun);
491 91376656 Gerd Hoffmann
    s->qdev.type = scsiid.scsi_type;
492 91376656 Gerd Hoffmann
    DPRINTF("device type %d\n", s->qdev.type);
493 91376656 Gerd Hoffmann
    if (s->qdev.type == TYPE_TAPE) {
494 251882b7 Gerd Hoffmann
        s->qdev.blocksize = get_stream_blocksize(s->qdev.dinfo->bdrv);
495 b07995e3 Gerd Hoffmann
        if (s->qdev.blocksize == -1)
496 b07995e3 Gerd Hoffmann
            s->qdev.blocksize = 0;
497 89c0f643 aurel32
    } else {
498 251882b7 Gerd Hoffmann
        s->qdev.blocksize = get_blocksize(s->qdev.dinfo->bdrv);
499 89c0f643 aurel32
        /* removable media returns 0 if not present */
500 b07995e3 Gerd Hoffmann
        if (s->qdev.blocksize <= 0) {
501 91376656 Gerd Hoffmann
            if (s->qdev.type == TYPE_ROM || s->qdev.type  == TYPE_WORM)
502 b07995e3 Gerd Hoffmann
                s->qdev.blocksize = 2048;
503 89c0f643 aurel32
            else
504 b07995e3 Gerd Hoffmann
                s->qdev.blocksize = 512;
505 89c0f643 aurel32
        }
506 89c0f643 aurel32
    }
507 b07995e3 Gerd Hoffmann
    DPRINTF("block size %d\n", s->qdev.blocksize);
508 2cc977e2 ths
    s->driver_status = 0;
509 2cc977e2 ths
    memset(s->sensebuf, 0, sizeof(s->sensebuf));
510 d52affa7 Gerd Hoffmann
    return 0;
511 d52affa7 Gerd Hoffmann
}
512 2cc977e2 ths
513 d52affa7 Gerd Hoffmann
static SCSIDeviceInfo scsi_generic_info = {
514 d52affa7 Gerd Hoffmann
    .qdev.name    = "scsi-generic",
515 d52affa7 Gerd Hoffmann
    .qdev.desc    = "pass through generic scsi device (/dev/sg*)",
516 d52affa7 Gerd Hoffmann
    .qdev.size    = sizeof(SCSIGenericState),
517 d52affa7 Gerd Hoffmann
    .init         = scsi_generic_initfn,
518 d52affa7 Gerd Hoffmann
    .destroy      = scsi_destroy,
519 d52affa7 Gerd Hoffmann
    .send_command = scsi_send_command,
520 d52affa7 Gerd Hoffmann
    .read_data    = scsi_read_data,
521 d52affa7 Gerd Hoffmann
    .write_data   = scsi_write_data,
522 d52affa7 Gerd Hoffmann
    .cancel_io    = scsi_cancel_io,
523 d52affa7 Gerd Hoffmann
    .get_buf      = scsi_get_buf,
524 d52affa7 Gerd Hoffmann
    .qdev.props   = (Property[]) {
525 251882b7 Gerd Hoffmann
        DEFINE_PROP_DRIVE("drive", SCSIGenericState, qdev.dinfo),
526 d52affa7 Gerd Hoffmann
        DEFINE_PROP_END_OF_LIST(),
527 d52affa7 Gerd Hoffmann
    },
528 d52affa7 Gerd Hoffmann
};
529 2cc977e2 ths
530 d52affa7 Gerd Hoffmann
static void scsi_generic_register_devices(void)
531 d52affa7 Gerd Hoffmann
{
532 d52affa7 Gerd Hoffmann
    scsi_qdev_register(&scsi_generic_info);
533 2cc977e2 ths
}
534 d52affa7 Gerd Hoffmann
device_init(scsi_generic_register_devices)
535 d52affa7 Gerd Hoffmann
536 2cc977e2 ths
#endif /* __linux__ */