Statistics
| Branch: | Revision:

root / hw / scsi-generic.c @ 295587f7

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