Statistics
| Branch: | Revision:

root / hw / scsi-generic.c @ 81b1008d

History | View | Annotate | Download (13.1 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 8e31bf38 Matthew Fernandez
 * This code is licensed 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
};
64 2cc977e2 ths
65 ad2d30f7 Paolo Bonzini
static void scsi_free_request(SCSIRequest *req)
66 2cc977e2 ths
{
67 ad2d30f7 Paolo Bonzini
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
68 ad2d30f7 Paolo Bonzini
69 7267c094 Anthony Liguori
    g_free(r->buf);
70 2cc977e2 ths
}
71 2cc977e2 ths
72 2cc977e2 ths
/* Helper function for command completion.  */
73 2cc977e2 ths
static void scsi_command_complete(void *opaque, int ret)
74 2cc977e2 ths
{
75 682a9b21 Paolo Bonzini
    int status;
76 4c41d2ef Gerd Hoffmann
    SCSIGenericReq *r = (SCSIGenericReq *)opaque;
77 2cc977e2 ths
78 d33e0ce2 Paolo Bonzini
    r->req.aiocb = NULL;
79 b45ef674 Paolo Bonzini
    if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE)
80 b45ef674 Paolo Bonzini
        r->req.sense_len = r->io_header.sb_len_wr;
81 89c0f643 aurel32
82 a1f0cce2 Hannes Reinecke
    if (ret != 0) {
83 a1f0cce2 Hannes Reinecke
        switch (ret) {
84 2e7cc4d6 Paolo Bonzini
        case -EDOM:
85 682a9b21 Paolo Bonzini
            status = TASK_SET_FULL;
86 2e7cc4d6 Paolo Bonzini
            break;
87 a1f0cce2 Hannes Reinecke
        case -ENOMEM:
88 682a9b21 Paolo Bonzini
            status = CHECK_CONDITION;
89 b45ef674 Paolo Bonzini
            scsi_req_build_sense(&r->req, SENSE_CODE(TARGET_FAILURE));
90 a1f0cce2 Hannes Reinecke
            break;
91 a1f0cce2 Hannes Reinecke
        default:
92 682a9b21 Paolo Bonzini
            status = CHECK_CONDITION;
93 b45ef674 Paolo Bonzini
            scsi_req_build_sense(&r->req, SENSE_CODE(IO_ERROR));
94 a1f0cce2 Hannes Reinecke
            break;
95 a1f0cce2 Hannes Reinecke
        }
96 a1f0cce2 Hannes Reinecke
    } else {
97 b45ef674 Paolo Bonzini
        if (r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT) {
98 682a9b21 Paolo Bonzini
            status = BUSY;
99 2cc977e2 ths
            BADF("Driver Timeout\n");
100 682a9b21 Paolo Bonzini
        } else if (r->io_header.status) {
101 682a9b21 Paolo Bonzini
            status = r->io_header.status;
102 b45ef674 Paolo Bonzini
        } else if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
103 682a9b21 Paolo Bonzini
            status = CHECK_CONDITION;
104 682a9b21 Paolo Bonzini
        } else {
105 682a9b21 Paolo Bonzini
            status = GOOD;
106 682a9b21 Paolo Bonzini
        }
107 2cc977e2 ths
    }
108 89c0f643 aurel32
    DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
109 682a9b21 Paolo Bonzini
            r, r->req.tag, status);
110 ed3a34a3 Gerd Hoffmann
111 682a9b21 Paolo Bonzini
    scsi_req_complete(&r->req, status);
112 2cc977e2 ths
}
113 2cc977e2 ths
114 2cc977e2 ths
/* Cancel a pending data transfer.  */
115 5c6c0e51 Hannes Reinecke
static void scsi_cancel_io(SCSIRequest *req)
116 2cc977e2 ths
{
117 5c6c0e51 Hannes Reinecke
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
118 5c6c0e51 Hannes Reinecke
119 5c6c0e51 Hannes Reinecke
    DPRINTF("Cancel tag=0x%x\n", req->tag);
120 5c6c0e51 Hannes Reinecke
    if (r->req.aiocb) {
121 5c6c0e51 Hannes Reinecke
        bdrv_aio_cancel(r->req.aiocb);
122 2cc977e2 ths
    }
123 5c6c0e51 Hannes Reinecke
    r->req.aiocb = NULL;
124 2cc977e2 ths
}
125 2cc977e2 ths
126 2cc977e2 ths
static int execute_command(BlockDriverState *bdrv,
127 4c41d2ef Gerd Hoffmann
                           SCSIGenericReq *r, int direction,
128 2cc977e2 ths
                           BlockDriverCompletionFunc *complete)
129 2cc977e2 ths
{
130 2cc977e2 ths
    r->io_header.interface_id = 'S';
131 2cc977e2 ths
    r->io_header.dxfer_direction = direction;
132 2cc977e2 ths
    r->io_header.dxferp = r->buf;
133 2cc977e2 ths
    r->io_header.dxfer_len = r->buflen;
134 29362ebe Gerd Hoffmann
    r->io_header.cmdp = r->req.cmd.buf;
135 29362ebe Gerd Hoffmann
    r->io_header.cmd_len = r->req.cmd.len;
136 b45ef674 Paolo Bonzini
    r->io_header.mx_sb_len = sizeof(r->req.sense);
137 b45ef674 Paolo Bonzini
    r->io_header.sbp = r->req.sense;
138 2cc977e2 ths
    r->io_header.timeout = MAX_UINT;
139 2cc977e2 ths
    r->io_header.usr_ptr = r;
140 2cc977e2 ths
    r->io_header.flags |= SG_FLAG_DIRECT_IO;
141 2cc977e2 ths
142 4c41d2ef Gerd Hoffmann
    r->req.aiocb = bdrv_aio_ioctl(bdrv, SG_IO, &r->io_header, complete, r);
143 4c41d2ef Gerd Hoffmann
    if (r->req.aiocb == NULL) {
144 2cc977e2 ths
        BADF("execute_command: read failed !\n");
145 a1f0cce2 Hannes Reinecke
        return -ENOMEM;
146 2cc977e2 ths
    }
147 2cc977e2 ths
148 2cc977e2 ths
    return 0;
149 2cc977e2 ths
}
150 2cc977e2 ths
151 2cc977e2 ths
static void scsi_read_complete(void * opaque, int ret)
152 2cc977e2 ths
{
153 4c41d2ef Gerd Hoffmann
    SCSIGenericReq *r = (SCSIGenericReq *)opaque;
154 2cc977e2 ths
    int len;
155 2cc977e2 ths
156 d33e0ce2 Paolo Bonzini
    r->req.aiocb = NULL;
157 2cc977e2 ths
    if (ret) {
158 aa2b1e89 Bernhard Kohl
        DPRINTF("IO error ret %d\n", ret);
159 2cc977e2 ths
        scsi_command_complete(r, ret);
160 2cc977e2 ths
        return;
161 2cc977e2 ths
    }
162 2cc977e2 ths
    len = r->io_header.dxfer_len - r->io_header.resid;
163 4c41d2ef Gerd Hoffmann
    DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, len);
164 2cc977e2 ths
165 2cc977e2 ths
    r->len = -1;
166 40f16dd1 Paolo Bonzini
    if (len == 0) {
167 89c0f643 aurel32
        scsi_command_complete(r, 0);
168 40f16dd1 Paolo Bonzini
    } else {
169 ab9adc88 Paolo Bonzini
        scsi_req_data(&r->req, len);
170 40f16dd1 Paolo Bonzini
    }
171 2cc977e2 ths
}
172 2cc977e2 ths
173 2cc977e2 ths
/* Read more data from scsi device into buffer.  */
174 5c6c0e51 Hannes Reinecke
static void scsi_read_data(SCSIRequest *req)
175 2cc977e2 ths
{
176 5c6c0e51 Hannes Reinecke
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
177 5c6c0e51 Hannes Reinecke
    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev);
178 2cc977e2 ths
    int ret;
179 2cc977e2 ths
180 5c6c0e51 Hannes Reinecke
    DPRINTF("scsi_read_data 0x%x\n", req->tag);
181 2cc977e2 ths
    if (r->len == -1) {
182 2cc977e2 ths
        scsi_command_complete(r, 0);
183 2cc977e2 ths
        return;
184 2cc977e2 ths
    }
185 2cc977e2 ths
186 428c149b Christoph Hellwig
    ret = execute_command(s->bs, r, SG_DXFER_FROM_DEV, scsi_read_complete);
187 a1f0cce2 Hannes Reinecke
    if (ret < 0) {
188 a1f0cce2 Hannes Reinecke
        scsi_command_complete(r, ret);
189 2cc977e2 ths
        return;
190 2cc977e2 ths
    }
191 2cc977e2 ths
}
192 2cc977e2 ths
193 2cc977e2 ths
static void scsi_write_complete(void * opaque, int ret)
194 2cc977e2 ths
{
195 4c41d2ef Gerd Hoffmann
    SCSIGenericReq *r = (SCSIGenericReq *)opaque;
196 4c41d2ef Gerd Hoffmann
    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev);
197 2cc977e2 ths
198 2cc977e2 ths
    DPRINTF("scsi_write_complete() ret = %d\n", ret);
199 d33e0ce2 Paolo Bonzini
    r->req.aiocb = NULL;
200 2cc977e2 ths
    if (ret) {
201 2cc977e2 ths
        DPRINTF("IO error\n");
202 2cc977e2 ths
        scsi_command_complete(r, ret);
203 2cc977e2 ths
        return;
204 2cc977e2 ths
    }
205 2cc977e2 ths
206 29362ebe Gerd Hoffmann
    if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 &&
207 91376656 Gerd Hoffmann
        s->qdev.type == TYPE_TAPE) {
208 b07995e3 Gerd Hoffmann
        s->qdev.blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
209 aa2b1e89 Bernhard Kohl
        DPRINTF("block size %d\n", s->qdev.blocksize);
210 89c0f643 aurel32
    }
211 89c0f643 aurel32
212 2cc977e2 ths
    scsi_command_complete(r, ret);
213 2cc977e2 ths
}
214 2cc977e2 ths
215 2cc977e2 ths
/* Write data to a scsi device.  Returns nonzero on failure.
216 2cc977e2 ths
   The transfer may complete asynchronously.  */
217 42741212 Paolo Bonzini
static void scsi_write_data(SCSIRequest *req)
218 2cc977e2 ths
{
219 5c6c0e51 Hannes Reinecke
    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, req->dev);
220 5c6c0e51 Hannes Reinecke
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
221 2cc977e2 ths
    int ret;
222 2cc977e2 ths
223 5c6c0e51 Hannes Reinecke
    DPRINTF("scsi_write_data 0x%x\n", req->tag);
224 2cc977e2 ths
    if (r->len == 0) {
225 2cc977e2 ths
        r->len = r->buflen;
226 ab9adc88 Paolo Bonzini
        scsi_req_data(&r->req, r->len);
227 42741212 Paolo Bonzini
        return;
228 2cc977e2 ths
    }
229 2cc977e2 ths
230 428c149b Christoph Hellwig
    ret = execute_command(s->bs, r, SG_DXFER_TO_DEV, scsi_write_complete);
231 a1f0cce2 Hannes Reinecke
    if (ret < 0) {
232 a1f0cce2 Hannes Reinecke
        scsi_command_complete(r, ret);
233 2cc977e2 ths
    }
234 2cc977e2 ths
}
235 2cc977e2 ths
236 2cc977e2 ths
/* Return a pointer to the data buffer.  */
237 5c6c0e51 Hannes Reinecke
static uint8_t *scsi_get_buf(SCSIRequest *req)
238 2cc977e2 ths
{
239 5c6c0e51 Hannes Reinecke
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
240 5c6c0e51 Hannes Reinecke
241 2cc977e2 ths
    return r->buf;
242 2cc977e2 ths
}
243 2cc977e2 ths
244 2ec749cb Gerd Hoffmann
static void scsi_req_fixup(SCSIRequest *req)
245 2cc977e2 ths
{
246 2ec749cb Gerd Hoffmann
    switch(req->cmd.buf[0]) {
247 2cc977e2 ths
    case WRITE_10:
248 2ec749cb Gerd Hoffmann
        req->cmd.buf[1] &= ~0x08;        /* disable FUA */
249 2cc977e2 ths
        break;
250 2cc977e2 ths
    case READ_10:
251 2ec749cb Gerd Hoffmann
        req->cmd.buf[1] &= ~0x08;        /* disable FUA */
252 a9dd6843 aliguori
        break;
253 a9dd6843 aliguori
    case REWIND:
254 a9dd6843 aliguori
    case START_STOP:
255 2ec749cb Gerd Hoffmann
        if (req->dev->type == TYPE_TAPE) {
256 2ec749cb Gerd Hoffmann
            /* force IMMED, otherwise qemu waits end of command */
257 2ec749cb Gerd Hoffmann
            req->cmd.buf[1] = 0x01;
258 2ec749cb Gerd Hoffmann
        }
259 a9dd6843 aliguori
        break;
260 a9dd6843 aliguori
    }
261 a9dd6843 aliguori
}
262 a9dd6843 aliguori
263 2cc977e2 ths
/* Execute a scsi command.  Returns the length of the data expected by the
264 2cc977e2 ths
   command.  This will be Positive for data transfers from the device
265 2cc977e2 ths
   (eg. disk reads), negative for transfers to the device (eg. disk writes),
266 2cc977e2 ths
   and zero if the command does not transfer any data.  */
267 2cc977e2 ths
268 5c6c0e51 Hannes Reinecke
static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
269 2cc977e2 ths
{
270 5c6c0e51 Hannes Reinecke
    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, req->dev);
271 5c6c0e51 Hannes Reinecke
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
272 2cc977e2 ths
    int ret;
273 2cc977e2 ths
274 2ec749cb Gerd Hoffmann
    scsi_req_fixup(&r->req);
275 2ec749cb Gerd Hoffmann
276 aa2b1e89 Bernhard Kohl
    DPRINTF("Command: lun=%d tag=0x%x len %zd data=0x%02x", lun, tag,
277 aa2b1e89 Bernhard Kohl
            r->req.cmd.xfer, cmd[0]);
278 aa2b1e89 Bernhard Kohl
279 aa2b1e89 Bernhard Kohl
#ifdef DEBUG_SCSI
280 aa2b1e89 Bernhard Kohl
    {
281 aa2b1e89 Bernhard Kohl
        int i;
282 aa2b1e89 Bernhard Kohl
        for (i = 1; i < r->req.cmd.len; i++) {
283 aa2b1e89 Bernhard Kohl
            printf(" 0x%02x", cmd[i]);
284 aa2b1e89 Bernhard Kohl
        }
285 aa2b1e89 Bernhard Kohl
        printf("\n");
286 aa2b1e89 Bernhard Kohl
    }
287 aa2b1e89 Bernhard Kohl
#endif
288 2cc977e2 ths
289 2ec749cb Gerd Hoffmann
    if (r->req.cmd.xfer == 0) {
290 2cc977e2 ths
        if (r->buf != NULL)
291 7267c094 Anthony Liguori
            g_free(r->buf);
292 2cc977e2 ths
        r->buflen = 0;
293 2cc977e2 ths
        r->buf = NULL;
294 428c149b Christoph Hellwig
        ret = execute_command(s->bs, r, SG_DXFER_NONE, scsi_command_complete);
295 a1f0cce2 Hannes Reinecke
        if (ret < 0) {
296 a1f0cce2 Hannes Reinecke
            scsi_command_complete(r, ret);
297 a1f0cce2 Hannes Reinecke
            return 0;
298 2cc977e2 ths
        }
299 2cc977e2 ths
        return 0;
300 2cc977e2 ths
    }
301 2cc977e2 ths
302 2ec749cb Gerd Hoffmann
    if (r->buflen != r->req.cmd.xfer) {
303 2cc977e2 ths
        if (r->buf != NULL)
304 7267c094 Anthony Liguori
            g_free(r->buf);
305 7267c094 Anthony Liguori
        r->buf = g_malloc(r->req.cmd.xfer);
306 2ec749cb Gerd Hoffmann
        r->buflen = r->req.cmd.xfer;
307 2cc977e2 ths
    }
308 2cc977e2 ths
309 2cc977e2 ths
    memset(r->buf, 0, r->buflen);
310 2ec749cb Gerd Hoffmann
    r->len = r->req.cmd.xfer;
311 97a06435 Gerd Hoffmann
    if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
312 2cc977e2 ths
        r->len = 0;
313 5c6c0e51 Hannes Reinecke
        return -r->req.cmd.xfer;
314 ad2d30f7 Paolo Bonzini
    } else {
315 5c6c0e51 Hannes Reinecke
        return r->req.cmd.xfer;
316 2cc977e2 ths
    }
317 2cc977e2 ths
}
318 2cc977e2 ths
319 2cc977e2 ths
static int get_blocksize(BlockDriverState *bdrv)
320 2cc977e2 ths
{
321 2cc977e2 ths
    uint8_t cmd[10];
322 2cc977e2 ths
    uint8_t buf[8];
323 2cc977e2 ths
    uint8_t sensebuf[8];
324 2cc977e2 ths
    sg_io_hdr_t io_header;
325 2cc977e2 ths
    int ret;
326 2cc977e2 ths
327 4f26a486 aliguori
    memset(cmd, 0, sizeof(cmd));
328 4f26a486 aliguori
    memset(buf, 0, sizeof(buf));
329 5e30a07d Hannes Reinecke
    cmd[0] = READ_CAPACITY_10;
330 2cc977e2 ths
331 2cc977e2 ths
    memset(&io_header, 0, sizeof(io_header));
332 2cc977e2 ths
    io_header.interface_id = 'S';
333 2cc977e2 ths
    io_header.dxfer_direction = SG_DXFER_FROM_DEV;
334 2cc977e2 ths
    io_header.dxfer_len = sizeof(buf);
335 2cc977e2 ths
    io_header.dxferp = buf;
336 2cc977e2 ths
    io_header.cmdp = cmd;
337 2cc977e2 ths
    io_header.cmd_len = sizeof(cmd);
338 2cc977e2 ths
    io_header.mx_sb_len = sizeof(sensebuf);
339 2cc977e2 ths
    io_header.sbp = sensebuf;
340 2cc977e2 ths
    io_header.timeout = 6000; /* XXX */
341 2cc977e2 ths
342 221f715d aliguori
    ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
343 7d780669 aliguori
    if (ret < 0)
344 2cc977e2 ths
        return -1;
345 2cc977e2 ths
346 2cc977e2 ths
    return (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
347 2cc977e2 ths
}
348 2cc977e2 ths
349 89c0f643 aurel32
static int get_stream_blocksize(BlockDriverState *bdrv)
350 89c0f643 aurel32
{
351 89c0f643 aurel32
    uint8_t cmd[6];
352 89c0f643 aurel32
    uint8_t buf[12];
353 89c0f643 aurel32
    uint8_t sensebuf[8];
354 89c0f643 aurel32
    sg_io_hdr_t io_header;
355 89c0f643 aurel32
    int ret;
356 89c0f643 aurel32
357 89c0f643 aurel32
    memset(cmd, 0, sizeof(cmd));
358 89c0f643 aurel32
    memset(buf, 0, sizeof(buf));
359 89c0f643 aurel32
    cmd[0] = MODE_SENSE;
360 89c0f643 aurel32
    cmd[4] = sizeof(buf);
361 89c0f643 aurel32
362 89c0f643 aurel32
    memset(&io_header, 0, sizeof(io_header));
363 89c0f643 aurel32
    io_header.interface_id = 'S';
364 89c0f643 aurel32
    io_header.dxfer_direction = SG_DXFER_FROM_DEV;
365 89c0f643 aurel32
    io_header.dxfer_len = sizeof(buf);
366 89c0f643 aurel32
    io_header.dxferp = buf;
367 89c0f643 aurel32
    io_header.cmdp = cmd;
368 89c0f643 aurel32
    io_header.cmd_len = sizeof(cmd);
369 89c0f643 aurel32
    io_header.mx_sb_len = sizeof(sensebuf);
370 89c0f643 aurel32
    io_header.sbp = sensebuf;
371 89c0f643 aurel32
    io_header.timeout = 6000; /* XXX */
372 89c0f643 aurel32
373 221f715d aliguori
    ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
374 7d780669 aliguori
    if (ret < 0)
375 89c0f643 aurel32
        return -1;
376 89c0f643 aurel32
377 89c0f643 aurel32
    return (buf[9] << 16) | (buf[10] << 8) | buf[11];
378 89c0f643 aurel32
}
379 89c0f643 aurel32
380 f8b6d672 Bernhard Kohl
static void scsi_generic_reset(DeviceState *dev)
381 f8b6d672 Bernhard Kohl
{
382 f8b6d672 Bernhard Kohl
    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev.qdev, dev);
383 f8b6d672 Bernhard Kohl
384 c7b48872 Paolo Bonzini
    scsi_device_purge_requests(&s->qdev, SENSE_CODE(RESET));
385 f8b6d672 Bernhard Kohl
}
386 f8b6d672 Bernhard Kohl
387 f8b6d672 Bernhard Kohl
static void scsi_destroy(SCSIDevice *d)
388 f8b6d672 Bernhard Kohl
{
389 f8b6d672 Bernhard Kohl
    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
390 f8b6d672 Bernhard Kohl
391 c7b48872 Paolo Bonzini
    scsi_device_purge_requests(&s->qdev, SENSE_CODE(NO_SENSE));
392 f8b6cc00 Markus Armbruster
    blockdev_mark_auto_del(s->qdev.conf.bs);
393 2cc977e2 ths
}
394 2cc977e2 ths
395 d52affa7 Gerd Hoffmann
static int scsi_generic_initfn(SCSIDevice *dev)
396 2cc977e2 ths
{
397 d52affa7 Gerd Hoffmann
    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, dev);
398 2cc977e2 ths
    int sg_version;
399 2cc977e2 ths
    struct sg_scsi_id scsiid;
400 2cc977e2 ths
401 f8b6cc00 Markus Armbruster
    if (!s->qdev.conf.bs) {
402 1ecda02b Markus Armbruster
        error_report("scsi-generic: drive property not set");
403 d52affa7 Gerd Hoffmann
        return -1;
404 d52affa7 Gerd Hoffmann
    }
405 f8b6cc00 Markus Armbruster
    s->bs = s->qdev.conf.bs;
406 2cc977e2 ths
407 d52affa7 Gerd Hoffmann
    /* check we are really using a /dev/sg* file */
408 428c149b Christoph Hellwig
    if (!bdrv_is_sg(s->bs)) {
409 1ecda02b Markus Armbruster
        error_report("scsi-generic: not /dev/sg*");
410 d52affa7 Gerd Hoffmann
        return -1;
411 d52affa7 Gerd Hoffmann
    }
412 2cc977e2 ths
413 620f862e Markus Armbruster
    if (bdrv_get_on_error(s->bs, 0) != BLOCK_ERR_STOP_ENOSPC) {
414 620f862e Markus Armbruster
        error_report("Device doesn't support drive option werror");
415 620f862e Markus Armbruster
        return -1;
416 620f862e Markus Armbruster
    }
417 620f862e Markus Armbruster
    if (bdrv_get_on_error(s->bs, 1) != BLOCK_ERR_REPORT) {
418 620f862e Markus Armbruster
        error_report("Device doesn't support drive option rerror");
419 620f862e Markus Armbruster
        return -1;
420 620f862e Markus Armbruster
    }
421 620f862e Markus Armbruster
422 2cc977e2 ths
    /* check we are using a driver managing SG_IO (version 3 and after */
423 428c149b Christoph Hellwig
    if (bdrv_ioctl(s->bs, SG_GET_VERSION_NUM, &sg_version) < 0 ||
424 d52affa7 Gerd Hoffmann
        sg_version < 30000) {
425 1ecda02b Markus Armbruster
        error_report("scsi-generic: scsi generic interface too old");
426 d52affa7 Gerd Hoffmann
        return -1;
427 d52affa7 Gerd Hoffmann
    }
428 2cc977e2 ths
429 2cc977e2 ths
    /* get LUN of the /dev/sg? */
430 428c149b Christoph Hellwig
    if (bdrv_ioctl(s->bs, SG_GET_SCSI_ID, &scsiid)) {
431 1ecda02b Markus Armbruster
        error_report("scsi-generic: SG_GET_SCSI_ID ioctl failed");
432 d52affa7 Gerd Hoffmann
        return -1;
433 d52affa7 Gerd Hoffmann
    }
434 2cc977e2 ths
435 2cc977e2 ths
    /* define device state */
436 91376656 Gerd Hoffmann
    s->qdev.type = scsiid.scsi_type;
437 91376656 Gerd Hoffmann
    DPRINTF("device type %d\n", s->qdev.type);
438 91376656 Gerd Hoffmann
    if (s->qdev.type == TYPE_TAPE) {
439 428c149b Christoph Hellwig
        s->qdev.blocksize = get_stream_blocksize(s->bs);
440 b07995e3 Gerd Hoffmann
        if (s->qdev.blocksize == -1)
441 b07995e3 Gerd Hoffmann
            s->qdev.blocksize = 0;
442 89c0f643 aurel32
    } else {
443 428c149b Christoph Hellwig
        s->qdev.blocksize = get_blocksize(s->bs);
444 89c0f643 aurel32
        /* removable media returns 0 if not present */
445 b07995e3 Gerd Hoffmann
        if (s->qdev.blocksize <= 0) {
446 91376656 Gerd Hoffmann
            if (s->qdev.type == TYPE_ROM || s->qdev.type  == TYPE_WORM)
447 b07995e3 Gerd Hoffmann
                s->qdev.blocksize = 2048;
448 89c0f643 aurel32
            else
449 b07995e3 Gerd Hoffmann
                s->qdev.blocksize = 512;
450 89c0f643 aurel32
        }
451 89c0f643 aurel32
    }
452 b07995e3 Gerd Hoffmann
    DPRINTF("block size %d\n", s->qdev.blocksize);
453 7d0d6950 Markus Armbruster
    bdrv_set_removable(s->bs, 0);
454 d52affa7 Gerd Hoffmann
    return 0;
455 d52affa7 Gerd Hoffmann
}
456 2cc977e2 ths
457 8dbd4574 Paolo Bonzini
static SCSIReqOps scsi_generic_req_ops = {
458 8dbd4574 Paolo Bonzini
    .size         = sizeof(SCSIGenericReq),
459 12010e7b Paolo Bonzini
    .free_req     = scsi_free_request,
460 12010e7b Paolo Bonzini
    .send_command = scsi_send_command,
461 12010e7b Paolo Bonzini
    .read_data    = scsi_read_data,
462 12010e7b Paolo Bonzini
    .write_data   = scsi_write_data,
463 12010e7b Paolo Bonzini
    .cancel_io    = scsi_cancel_io,
464 12010e7b Paolo Bonzini
    .get_buf      = scsi_get_buf,
465 8dbd4574 Paolo Bonzini
};
466 8dbd4574 Paolo Bonzini
467 8dbd4574 Paolo Bonzini
static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
468 8dbd4574 Paolo Bonzini
                                     void *hba_private)
469 8dbd4574 Paolo Bonzini
{
470 8dbd4574 Paolo Bonzini
    SCSIRequest *req;
471 8dbd4574 Paolo Bonzini
472 8dbd4574 Paolo Bonzini
    req = scsi_req_alloc(&scsi_generic_req_ops, d, tag, lun, hba_private);
473 8dbd4574 Paolo Bonzini
    return req;
474 8dbd4574 Paolo Bonzini
}
475 8dbd4574 Paolo Bonzini
476 d52affa7 Gerd Hoffmann
static SCSIDeviceInfo scsi_generic_info = {
477 d52affa7 Gerd Hoffmann
    .qdev.name    = "scsi-generic",
478 d52affa7 Gerd Hoffmann
    .qdev.desc    = "pass through generic scsi device (/dev/sg*)",
479 d52affa7 Gerd Hoffmann
    .qdev.size    = sizeof(SCSIGenericState),
480 f8b6d672 Bernhard Kohl
    .qdev.reset   = scsi_generic_reset,
481 d52affa7 Gerd Hoffmann
    .init         = scsi_generic_initfn,
482 d52affa7 Gerd Hoffmann
    .destroy      = scsi_destroy,
483 5c6c0e51 Hannes Reinecke
    .alloc_req    = scsi_new_request,
484 d52affa7 Gerd Hoffmann
    .qdev.props   = (Property[]) {
485 428c149b Christoph Hellwig
        DEFINE_BLOCK_PROPERTIES(SCSIGenericState, qdev.conf),
486 d52affa7 Gerd Hoffmann
        DEFINE_PROP_END_OF_LIST(),
487 d52affa7 Gerd Hoffmann
    },
488 d52affa7 Gerd Hoffmann
};
489 2cc977e2 ths
490 d52affa7 Gerd Hoffmann
static void scsi_generic_register_devices(void)
491 d52affa7 Gerd Hoffmann
{
492 d52affa7 Gerd Hoffmann
    scsi_qdev_register(&scsi_generic_info);
493 2cc977e2 ths
}
494 d52affa7 Gerd Hoffmann
device_init(scsi_generic_register_devices)
495 d52affa7 Gerd Hoffmann
496 2cc977e2 ths
#endif /* __linux__ */