Statistics
| Branch: | Revision:

root / hw / scsi-generic.c @ 17786d52

History | View | Annotate | Download (15.6 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 43b443b6 Gerd Hoffmann
#include "scsi.h"
17 2446333c Blue Swirl
#include "blockdev.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 aa2b1e89 Bernhard Kohl
        DPRINTF("IO error ret %d\n", ret);
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 aa2b1e89 Bernhard Kohl
        DPRINTF("block size %d\n", s->qdev.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 aa2b1e89 Bernhard Kohl
    DPRINTF("Command: lun=%d tag=0x%x len %zd data=0x%02x", lun, tag,
355 aa2b1e89 Bernhard Kohl
            r->req.cmd.xfer, cmd[0]);
356 aa2b1e89 Bernhard Kohl
357 aa2b1e89 Bernhard Kohl
#ifdef DEBUG_SCSI
358 aa2b1e89 Bernhard Kohl
    {
359 aa2b1e89 Bernhard Kohl
        int i;
360 aa2b1e89 Bernhard Kohl
        for (i = 1; i < r->req.cmd.len; i++) {
361 aa2b1e89 Bernhard Kohl
            printf(" 0x%02x", cmd[i]);
362 aa2b1e89 Bernhard Kohl
        }
363 aa2b1e89 Bernhard Kohl
        printf("\n");
364 aa2b1e89 Bernhard Kohl
    }
365 aa2b1e89 Bernhard Kohl
#endif
366 2cc977e2 ths
367 2ec749cb Gerd Hoffmann
    if (r->req.cmd.xfer == 0) {
368 2cc977e2 ths
        if (r->buf != NULL)
369 e3c916e6 Jean-Christophe DUBOIS
            qemu_free(r->buf);
370 2cc977e2 ths
        r->buflen = 0;
371 2cc977e2 ths
        r->buf = NULL;
372 428c149b Christoph Hellwig
        ret = execute_command(s->bs, r, SG_DXFER_NONE, scsi_command_complete);
373 2cc977e2 ths
        if (ret == -1) {
374 2cc977e2 ths
            scsi_command_complete(r, -EINVAL);
375 2cc977e2 ths
            return 0;
376 2cc977e2 ths
        }
377 2cc977e2 ths
        return 0;
378 2cc977e2 ths
    }
379 2cc977e2 ths
380 2ec749cb Gerd Hoffmann
    if (r->buflen != r->req.cmd.xfer) {
381 2cc977e2 ths
        if (r->buf != NULL)
382 e3c916e6 Jean-Christophe DUBOIS
            qemu_free(r->buf);
383 2ec749cb Gerd Hoffmann
        r->buf = qemu_malloc(r->req.cmd.xfer);
384 2ec749cb Gerd Hoffmann
        r->buflen = r->req.cmd.xfer;
385 2cc977e2 ths
    }
386 2cc977e2 ths
387 2cc977e2 ths
    memset(r->buf, 0, r->buflen);
388 2ec749cb Gerd Hoffmann
    r->len = r->req.cmd.xfer;
389 97a06435 Gerd Hoffmann
    if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
390 2cc977e2 ths
        r->len = 0;
391 2ec749cb Gerd Hoffmann
        return -r->req.cmd.xfer;
392 2cc977e2 ths
    }
393 2cc977e2 ths
394 2ec749cb Gerd Hoffmann
    return r->req.cmd.xfer;
395 2cc977e2 ths
}
396 2cc977e2 ths
397 2cc977e2 ths
static int get_blocksize(BlockDriverState *bdrv)
398 2cc977e2 ths
{
399 2cc977e2 ths
    uint8_t cmd[10];
400 2cc977e2 ths
    uint8_t buf[8];
401 2cc977e2 ths
    uint8_t sensebuf[8];
402 2cc977e2 ths
    sg_io_hdr_t io_header;
403 2cc977e2 ths
    int ret;
404 2cc977e2 ths
405 4f26a486 aliguori
    memset(cmd, 0, sizeof(cmd));
406 4f26a486 aliguori
    memset(buf, 0, sizeof(buf));
407 2cc977e2 ths
    cmd[0] = READ_CAPACITY;
408 2cc977e2 ths
409 2cc977e2 ths
    memset(&io_header, 0, sizeof(io_header));
410 2cc977e2 ths
    io_header.interface_id = 'S';
411 2cc977e2 ths
    io_header.dxfer_direction = SG_DXFER_FROM_DEV;
412 2cc977e2 ths
    io_header.dxfer_len = sizeof(buf);
413 2cc977e2 ths
    io_header.dxferp = buf;
414 2cc977e2 ths
    io_header.cmdp = cmd;
415 2cc977e2 ths
    io_header.cmd_len = sizeof(cmd);
416 2cc977e2 ths
    io_header.mx_sb_len = sizeof(sensebuf);
417 2cc977e2 ths
    io_header.sbp = sensebuf;
418 2cc977e2 ths
    io_header.timeout = 6000; /* XXX */
419 2cc977e2 ths
420 221f715d aliguori
    ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
421 7d780669 aliguori
    if (ret < 0)
422 2cc977e2 ths
        return -1;
423 2cc977e2 ths
424 2cc977e2 ths
    return (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
425 2cc977e2 ths
}
426 2cc977e2 ths
427 89c0f643 aurel32
static int get_stream_blocksize(BlockDriverState *bdrv)
428 89c0f643 aurel32
{
429 89c0f643 aurel32
    uint8_t cmd[6];
430 89c0f643 aurel32
    uint8_t buf[12];
431 89c0f643 aurel32
    uint8_t sensebuf[8];
432 89c0f643 aurel32
    sg_io_hdr_t io_header;
433 89c0f643 aurel32
    int ret;
434 89c0f643 aurel32
435 89c0f643 aurel32
    memset(cmd, 0, sizeof(cmd));
436 89c0f643 aurel32
    memset(buf, 0, sizeof(buf));
437 89c0f643 aurel32
    cmd[0] = MODE_SENSE;
438 89c0f643 aurel32
    cmd[4] = sizeof(buf);
439 89c0f643 aurel32
440 89c0f643 aurel32
    memset(&io_header, 0, sizeof(io_header));
441 89c0f643 aurel32
    io_header.interface_id = 'S';
442 89c0f643 aurel32
    io_header.dxfer_direction = SG_DXFER_FROM_DEV;
443 89c0f643 aurel32
    io_header.dxfer_len = sizeof(buf);
444 89c0f643 aurel32
    io_header.dxferp = buf;
445 89c0f643 aurel32
    io_header.cmdp = cmd;
446 89c0f643 aurel32
    io_header.cmd_len = sizeof(cmd);
447 89c0f643 aurel32
    io_header.mx_sb_len = sizeof(sensebuf);
448 89c0f643 aurel32
    io_header.sbp = sensebuf;
449 89c0f643 aurel32
    io_header.timeout = 6000; /* XXX */
450 89c0f643 aurel32
451 221f715d aliguori
    ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
452 7d780669 aliguori
    if (ret < 0)
453 89c0f643 aurel32
        return -1;
454 89c0f643 aurel32
455 89c0f643 aurel32
    return (buf[9] << 16) | (buf[10] << 8) | buf[11];
456 89c0f643 aurel32
}
457 89c0f643 aurel32
458 f8b6d672 Bernhard Kohl
static void scsi_generic_purge_requests(SCSIGenericState *s)
459 2cc977e2 ths
{
460 9af99d98 Gerd Hoffmann
    SCSIGenericReq *r;
461 2cc977e2 ths
462 9af99d98 Gerd Hoffmann
    while (!QTAILQ_EMPTY(&s->qdev.requests)) {
463 9af99d98 Gerd Hoffmann
        r = DO_UPCAST(SCSIGenericReq, req, QTAILQ_FIRST(&s->qdev.requests));
464 f8b6d672 Bernhard Kohl
        if (r->req.aiocb) {
465 f8b6d672 Bernhard Kohl
            bdrv_aio_cancel(r->req.aiocb);
466 f8b6d672 Bernhard Kohl
        }
467 9af99d98 Gerd Hoffmann
        scsi_remove_request(r);
468 2cc977e2 ths
    }
469 f8b6d672 Bernhard Kohl
}
470 f8b6d672 Bernhard Kohl
471 f8b6d672 Bernhard Kohl
static void scsi_generic_reset(DeviceState *dev)
472 f8b6d672 Bernhard Kohl
{
473 f8b6d672 Bernhard Kohl
    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev.qdev, dev);
474 f8b6d672 Bernhard Kohl
475 f8b6d672 Bernhard Kohl
    scsi_generic_purge_requests(s);
476 f8b6d672 Bernhard Kohl
}
477 f8b6d672 Bernhard Kohl
478 f8b6d672 Bernhard Kohl
static void scsi_destroy(SCSIDevice *d)
479 f8b6d672 Bernhard Kohl
{
480 f8b6d672 Bernhard Kohl
    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
481 f8b6d672 Bernhard Kohl
482 f8b6d672 Bernhard Kohl
    scsi_generic_purge_requests(s);
483 f8b6cc00 Markus Armbruster
    blockdev_mark_auto_del(s->qdev.conf.bs);
484 2cc977e2 ths
}
485 2cc977e2 ths
486 d52affa7 Gerd Hoffmann
static int scsi_generic_initfn(SCSIDevice *dev)
487 2cc977e2 ths
{
488 d52affa7 Gerd Hoffmann
    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, dev);
489 2cc977e2 ths
    int sg_version;
490 2cc977e2 ths
    struct sg_scsi_id scsiid;
491 2cc977e2 ths
492 f8b6cc00 Markus Armbruster
    if (!s->qdev.conf.bs) {
493 1ecda02b Markus Armbruster
        error_report("scsi-generic: drive property not set");
494 d52affa7 Gerd Hoffmann
        return -1;
495 d52affa7 Gerd Hoffmann
    }
496 f8b6cc00 Markus Armbruster
    s->bs = s->qdev.conf.bs;
497 2cc977e2 ths
498 d52affa7 Gerd Hoffmann
    /* check we are really using a /dev/sg* file */
499 428c149b Christoph Hellwig
    if (!bdrv_is_sg(s->bs)) {
500 1ecda02b Markus Armbruster
        error_report("scsi-generic: not /dev/sg*");
501 d52affa7 Gerd Hoffmann
        return -1;
502 d52affa7 Gerd Hoffmann
    }
503 2cc977e2 ths
504 620f862e Markus Armbruster
    if (bdrv_get_on_error(s->bs, 0) != BLOCK_ERR_STOP_ENOSPC) {
505 620f862e Markus Armbruster
        error_report("Device doesn't support drive option werror");
506 620f862e Markus Armbruster
        return -1;
507 620f862e Markus Armbruster
    }
508 620f862e Markus Armbruster
    if (bdrv_get_on_error(s->bs, 1) != BLOCK_ERR_REPORT) {
509 620f862e Markus Armbruster
        error_report("Device doesn't support drive option rerror");
510 620f862e Markus Armbruster
        return -1;
511 620f862e Markus Armbruster
    }
512 620f862e Markus Armbruster
513 2cc977e2 ths
    /* check we are using a driver managing SG_IO (version 3 and after */
514 428c149b Christoph Hellwig
    if (bdrv_ioctl(s->bs, SG_GET_VERSION_NUM, &sg_version) < 0 ||
515 d52affa7 Gerd Hoffmann
        sg_version < 30000) {
516 1ecda02b Markus Armbruster
        error_report("scsi-generic: scsi generic interface too old");
517 d52affa7 Gerd Hoffmann
        return -1;
518 d52affa7 Gerd Hoffmann
    }
519 2cc977e2 ths
520 2cc977e2 ths
    /* get LUN of the /dev/sg? */
521 428c149b Christoph Hellwig
    if (bdrv_ioctl(s->bs, SG_GET_SCSI_ID, &scsiid)) {
522 1ecda02b Markus Armbruster
        error_report("scsi-generic: SG_GET_SCSI_ID ioctl failed");
523 d52affa7 Gerd Hoffmann
        return -1;
524 d52affa7 Gerd Hoffmann
    }
525 2cc977e2 ths
526 2cc977e2 ths
    /* define device state */
527 2cc977e2 ths
    s->lun = scsiid.lun;
528 89c0f643 aurel32
    DPRINTF("LUN %d\n", s->lun);
529 91376656 Gerd Hoffmann
    s->qdev.type = scsiid.scsi_type;
530 91376656 Gerd Hoffmann
    DPRINTF("device type %d\n", s->qdev.type);
531 91376656 Gerd Hoffmann
    if (s->qdev.type == TYPE_TAPE) {
532 428c149b Christoph Hellwig
        s->qdev.blocksize = get_stream_blocksize(s->bs);
533 b07995e3 Gerd Hoffmann
        if (s->qdev.blocksize == -1)
534 b07995e3 Gerd Hoffmann
            s->qdev.blocksize = 0;
535 89c0f643 aurel32
    } else {
536 428c149b Christoph Hellwig
        s->qdev.blocksize = get_blocksize(s->bs);
537 89c0f643 aurel32
        /* removable media returns 0 if not present */
538 b07995e3 Gerd Hoffmann
        if (s->qdev.blocksize <= 0) {
539 91376656 Gerd Hoffmann
            if (s->qdev.type == TYPE_ROM || s->qdev.type  == TYPE_WORM)
540 b07995e3 Gerd Hoffmann
                s->qdev.blocksize = 2048;
541 89c0f643 aurel32
            else
542 b07995e3 Gerd Hoffmann
                s->qdev.blocksize = 512;
543 89c0f643 aurel32
        }
544 89c0f643 aurel32
    }
545 b07995e3 Gerd Hoffmann
    DPRINTF("block size %d\n", s->qdev.blocksize);
546 2cc977e2 ths
    s->driver_status = 0;
547 2cc977e2 ths
    memset(s->sensebuf, 0, sizeof(s->sensebuf));
548 7d0d6950 Markus Armbruster
    bdrv_set_removable(s->bs, 0);
549 d52affa7 Gerd Hoffmann
    return 0;
550 d52affa7 Gerd Hoffmann
}
551 2cc977e2 ths
552 d52affa7 Gerd Hoffmann
static SCSIDeviceInfo scsi_generic_info = {
553 d52affa7 Gerd Hoffmann
    .qdev.name    = "scsi-generic",
554 d52affa7 Gerd Hoffmann
    .qdev.desc    = "pass through generic scsi device (/dev/sg*)",
555 d52affa7 Gerd Hoffmann
    .qdev.size    = sizeof(SCSIGenericState),
556 f8b6d672 Bernhard Kohl
    .qdev.reset   = scsi_generic_reset,
557 d52affa7 Gerd Hoffmann
    .init         = scsi_generic_initfn,
558 d52affa7 Gerd Hoffmann
    .destroy      = scsi_destroy,
559 d52affa7 Gerd Hoffmann
    .send_command = scsi_send_command,
560 d52affa7 Gerd Hoffmann
    .read_data    = scsi_read_data,
561 d52affa7 Gerd Hoffmann
    .write_data   = scsi_write_data,
562 d52affa7 Gerd Hoffmann
    .cancel_io    = scsi_cancel_io,
563 d52affa7 Gerd Hoffmann
    .get_buf      = scsi_get_buf,
564 d52affa7 Gerd Hoffmann
    .qdev.props   = (Property[]) {
565 428c149b Christoph Hellwig
        DEFINE_BLOCK_PROPERTIES(SCSIGenericState, qdev.conf),
566 d52affa7 Gerd Hoffmann
        DEFINE_PROP_END_OF_LIST(),
567 d52affa7 Gerd Hoffmann
    },
568 d52affa7 Gerd Hoffmann
};
569 2cc977e2 ths
570 d52affa7 Gerd Hoffmann
static void scsi_generic_register_devices(void)
571 d52affa7 Gerd Hoffmann
{
572 d52affa7 Gerd Hoffmann
    scsi_qdev_register(&scsi_generic_info);
573 2cc977e2 ths
}
574 d52affa7 Gerd Hoffmann
device_init(scsi_generic_register_devices)
575 d52affa7 Gerd Hoffmann
576 2cc977e2 ths
#endif /* __linux__ */