Statistics
| Branch: | Revision:

root / hw / scsi-generic.c @ 0200db65

History | View | Annotate | Download (12.9 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 a9dd6843 aliguori
    case REWIND:
248 a9dd6843 aliguori
    case START_STOP:
249 2ec749cb Gerd Hoffmann
        if (req->dev->type == TYPE_TAPE) {
250 2ec749cb Gerd Hoffmann
            /* force IMMED, otherwise qemu waits end of command */
251 2ec749cb Gerd Hoffmann
            req->cmd.buf[1] = 0x01;
252 2ec749cb Gerd Hoffmann
        }
253 a9dd6843 aliguori
        break;
254 a9dd6843 aliguori
    }
255 a9dd6843 aliguori
}
256 a9dd6843 aliguori
257 2cc977e2 ths
/* Execute a scsi command.  Returns the length of the data expected by the
258 2cc977e2 ths
   command.  This will be Positive for data transfers from the device
259 2cc977e2 ths
   (eg. disk reads), negative for transfers to the device (eg. disk writes),
260 2cc977e2 ths
   and zero if the command does not transfer any data.  */
261 2cc977e2 ths
262 5c6c0e51 Hannes Reinecke
static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
263 2cc977e2 ths
{
264 5c6c0e51 Hannes Reinecke
    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, req->dev);
265 5c6c0e51 Hannes Reinecke
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
266 2cc977e2 ths
    int ret;
267 2cc977e2 ths
268 2ec749cb Gerd Hoffmann
    scsi_req_fixup(&r->req);
269 2ec749cb Gerd Hoffmann
270 aa2b1e89 Bernhard Kohl
    DPRINTF("Command: lun=%d tag=0x%x len %zd data=0x%02x", lun, tag,
271 aa2b1e89 Bernhard Kohl
            r->req.cmd.xfer, cmd[0]);
272 aa2b1e89 Bernhard Kohl
273 aa2b1e89 Bernhard Kohl
#ifdef DEBUG_SCSI
274 aa2b1e89 Bernhard Kohl
    {
275 aa2b1e89 Bernhard Kohl
        int i;
276 aa2b1e89 Bernhard Kohl
        for (i = 1; i < r->req.cmd.len; i++) {
277 aa2b1e89 Bernhard Kohl
            printf(" 0x%02x", cmd[i]);
278 aa2b1e89 Bernhard Kohl
        }
279 aa2b1e89 Bernhard Kohl
        printf("\n");
280 aa2b1e89 Bernhard Kohl
    }
281 aa2b1e89 Bernhard Kohl
#endif
282 2cc977e2 ths
283 2ec749cb Gerd Hoffmann
    if (r->req.cmd.xfer == 0) {
284 2cc977e2 ths
        if (r->buf != NULL)
285 7267c094 Anthony Liguori
            g_free(r->buf);
286 2cc977e2 ths
        r->buflen = 0;
287 2cc977e2 ths
        r->buf = NULL;
288 428c149b Christoph Hellwig
        ret = execute_command(s->bs, r, SG_DXFER_NONE, scsi_command_complete);
289 a1f0cce2 Hannes Reinecke
        if (ret < 0) {
290 a1f0cce2 Hannes Reinecke
            scsi_command_complete(r, ret);
291 a1f0cce2 Hannes Reinecke
            return 0;
292 2cc977e2 ths
        }
293 2cc977e2 ths
        return 0;
294 2cc977e2 ths
    }
295 2cc977e2 ths
296 2ec749cb Gerd Hoffmann
    if (r->buflen != r->req.cmd.xfer) {
297 2cc977e2 ths
        if (r->buf != NULL)
298 7267c094 Anthony Liguori
            g_free(r->buf);
299 7267c094 Anthony Liguori
        r->buf = g_malloc(r->req.cmd.xfer);
300 2ec749cb Gerd Hoffmann
        r->buflen = r->req.cmd.xfer;
301 2cc977e2 ths
    }
302 2cc977e2 ths
303 2cc977e2 ths
    memset(r->buf, 0, r->buflen);
304 2ec749cb Gerd Hoffmann
    r->len = r->req.cmd.xfer;
305 97a06435 Gerd Hoffmann
    if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
306 2cc977e2 ths
        r->len = 0;
307 5c6c0e51 Hannes Reinecke
        return -r->req.cmd.xfer;
308 ad2d30f7 Paolo Bonzini
    } else {
309 5c6c0e51 Hannes Reinecke
        return r->req.cmd.xfer;
310 2cc977e2 ths
    }
311 2cc977e2 ths
}
312 2cc977e2 ths
313 2cc977e2 ths
static int get_blocksize(BlockDriverState *bdrv)
314 2cc977e2 ths
{
315 2cc977e2 ths
    uint8_t cmd[10];
316 2cc977e2 ths
    uint8_t buf[8];
317 2cc977e2 ths
    uint8_t sensebuf[8];
318 2cc977e2 ths
    sg_io_hdr_t io_header;
319 2cc977e2 ths
    int ret;
320 2cc977e2 ths
321 4f26a486 aliguori
    memset(cmd, 0, sizeof(cmd));
322 4f26a486 aliguori
    memset(buf, 0, sizeof(buf));
323 5e30a07d Hannes Reinecke
    cmd[0] = READ_CAPACITY_10;
324 2cc977e2 ths
325 2cc977e2 ths
    memset(&io_header, 0, sizeof(io_header));
326 2cc977e2 ths
    io_header.interface_id = 'S';
327 2cc977e2 ths
    io_header.dxfer_direction = SG_DXFER_FROM_DEV;
328 2cc977e2 ths
    io_header.dxfer_len = sizeof(buf);
329 2cc977e2 ths
    io_header.dxferp = buf;
330 2cc977e2 ths
    io_header.cmdp = cmd;
331 2cc977e2 ths
    io_header.cmd_len = sizeof(cmd);
332 2cc977e2 ths
    io_header.mx_sb_len = sizeof(sensebuf);
333 2cc977e2 ths
    io_header.sbp = sensebuf;
334 2cc977e2 ths
    io_header.timeout = 6000; /* XXX */
335 2cc977e2 ths
336 221f715d aliguori
    ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
337 7d780669 aliguori
    if (ret < 0)
338 2cc977e2 ths
        return -1;
339 2cc977e2 ths
340 2cc977e2 ths
    return (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
341 2cc977e2 ths
}
342 2cc977e2 ths
343 89c0f643 aurel32
static int get_stream_blocksize(BlockDriverState *bdrv)
344 89c0f643 aurel32
{
345 89c0f643 aurel32
    uint8_t cmd[6];
346 89c0f643 aurel32
    uint8_t buf[12];
347 89c0f643 aurel32
    uint8_t sensebuf[8];
348 89c0f643 aurel32
    sg_io_hdr_t io_header;
349 89c0f643 aurel32
    int ret;
350 89c0f643 aurel32
351 89c0f643 aurel32
    memset(cmd, 0, sizeof(cmd));
352 89c0f643 aurel32
    memset(buf, 0, sizeof(buf));
353 89c0f643 aurel32
    cmd[0] = MODE_SENSE;
354 89c0f643 aurel32
    cmd[4] = sizeof(buf);
355 89c0f643 aurel32
356 89c0f643 aurel32
    memset(&io_header, 0, sizeof(io_header));
357 89c0f643 aurel32
    io_header.interface_id = 'S';
358 89c0f643 aurel32
    io_header.dxfer_direction = SG_DXFER_FROM_DEV;
359 89c0f643 aurel32
    io_header.dxfer_len = sizeof(buf);
360 89c0f643 aurel32
    io_header.dxferp = buf;
361 89c0f643 aurel32
    io_header.cmdp = cmd;
362 89c0f643 aurel32
    io_header.cmd_len = sizeof(cmd);
363 89c0f643 aurel32
    io_header.mx_sb_len = sizeof(sensebuf);
364 89c0f643 aurel32
    io_header.sbp = sensebuf;
365 89c0f643 aurel32
    io_header.timeout = 6000; /* XXX */
366 89c0f643 aurel32
367 221f715d aliguori
    ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
368 7d780669 aliguori
    if (ret < 0)
369 89c0f643 aurel32
        return -1;
370 89c0f643 aurel32
371 89c0f643 aurel32
    return (buf[9] << 16) | (buf[10] << 8) | buf[11];
372 89c0f643 aurel32
}
373 89c0f643 aurel32
374 f8b6d672 Bernhard Kohl
static void scsi_generic_reset(DeviceState *dev)
375 f8b6d672 Bernhard Kohl
{
376 f8b6d672 Bernhard Kohl
    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev.qdev, dev);
377 f8b6d672 Bernhard Kohl
378 c7b48872 Paolo Bonzini
    scsi_device_purge_requests(&s->qdev, SENSE_CODE(RESET));
379 f8b6d672 Bernhard Kohl
}
380 f8b6d672 Bernhard Kohl
381 f8b6d672 Bernhard Kohl
static void scsi_destroy(SCSIDevice *d)
382 f8b6d672 Bernhard Kohl
{
383 f8b6d672 Bernhard Kohl
    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
384 f8b6d672 Bernhard Kohl
385 c7b48872 Paolo Bonzini
    scsi_device_purge_requests(&s->qdev, SENSE_CODE(NO_SENSE));
386 f8b6cc00 Markus Armbruster
    blockdev_mark_auto_del(s->qdev.conf.bs);
387 2cc977e2 ths
}
388 2cc977e2 ths
389 d52affa7 Gerd Hoffmann
static int scsi_generic_initfn(SCSIDevice *dev)
390 2cc977e2 ths
{
391 d52affa7 Gerd Hoffmann
    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, dev);
392 2cc977e2 ths
    int sg_version;
393 2cc977e2 ths
    struct sg_scsi_id scsiid;
394 2cc977e2 ths
395 f8b6cc00 Markus Armbruster
    if (!s->qdev.conf.bs) {
396 1ecda02b Markus Armbruster
        error_report("scsi-generic: drive property not set");
397 d52affa7 Gerd Hoffmann
        return -1;
398 d52affa7 Gerd Hoffmann
    }
399 f8b6cc00 Markus Armbruster
    s->bs = s->qdev.conf.bs;
400 2cc977e2 ths
401 d52affa7 Gerd Hoffmann
    /* check we are really using a /dev/sg* file */
402 428c149b Christoph Hellwig
    if (!bdrv_is_sg(s->bs)) {
403 1ecda02b Markus Armbruster
        error_report("scsi-generic: not /dev/sg*");
404 d52affa7 Gerd Hoffmann
        return -1;
405 d52affa7 Gerd Hoffmann
    }
406 2cc977e2 ths
407 620f862e Markus Armbruster
    if (bdrv_get_on_error(s->bs, 0) != BLOCK_ERR_STOP_ENOSPC) {
408 620f862e Markus Armbruster
        error_report("Device doesn't support drive option werror");
409 620f862e Markus Armbruster
        return -1;
410 620f862e Markus Armbruster
    }
411 620f862e Markus Armbruster
    if (bdrv_get_on_error(s->bs, 1) != BLOCK_ERR_REPORT) {
412 620f862e Markus Armbruster
        error_report("Device doesn't support drive option rerror");
413 620f862e Markus Armbruster
        return -1;
414 620f862e Markus Armbruster
    }
415 620f862e Markus Armbruster
416 2cc977e2 ths
    /* check we are using a driver managing SG_IO (version 3 and after */
417 428c149b Christoph Hellwig
    if (bdrv_ioctl(s->bs, SG_GET_VERSION_NUM, &sg_version) < 0 ||
418 d52affa7 Gerd Hoffmann
        sg_version < 30000) {
419 1ecda02b Markus Armbruster
        error_report("scsi-generic: scsi generic interface too old");
420 d52affa7 Gerd Hoffmann
        return -1;
421 d52affa7 Gerd Hoffmann
    }
422 2cc977e2 ths
423 2cc977e2 ths
    /* get LUN of the /dev/sg? */
424 428c149b Christoph Hellwig
    if (bdrv_ioctl(s->bs, SG_GET_SCSI_ID, &scsiid)) {
425 1ecda02b Markus Armbruster
        error_report("scsi-generic: SG_GET_SCSI_ID ioctl failed");
426 d52affa7 Gerd Hoffmann
        return -1;
427 d52affa7 Gerd Hoffmann
    }
428 2cc977e2 ths
429 2cc977e2 ths
    /* define device state */
430 91376656 Gerd Hoffmann
    s->qdev.type = scsiid.scsi_type;
431 91376656 Gerd Hoffmann
    DPRINTF("device type %d\n", s->qdev.type);
432 91376656 Gerd Hoffmann
    if (s->qdev.type == TYPE_TAPE) {
433 428c149b Christoph Hellwig
        s->qdev.blocksize = get_stream_blocksize(s->bs);
434 b07995e3 Gerd Hoffmann
        if (s->qdev.blocksize == -1)
435 b07995e3 Gerd Hoffmann
            s->qdev.blocksize = 0;
436 89c0f643 aurel32
    } else {
437 428c149b Christoph Hellwig
        s->qdev.blocksize = get_blocksize(s->bs);
438 89c0f643 aurel32
        /* removable media returns 0 if not present */
439 b07995e3 Gerd Hoffmann
        if (s->qdev.blocksize <= 0) {
440 91376656 Gerd Hoffmann
            if (s->qdev.type == TYPE_ROM || s->qdev.type  == TYPE_WORM)
441 b07995e3 Gerd Hoffmann
                s->qdev.blocksize = 2048;
442 89c0f643 aurel32
            else
443 b07995e3 Gerd Hoffmann
                s->qdev.blocksize = 512;
444 89c0f643 aurel32
        }
445 89c0f643 aurel32
    }
446 b07995e3 Gerd Hoffmann
    DPRINTF("block size %d\n", s->qdev.blocksize);
447 d52affa7 Gerd Hoffmann
    return 0;
448 d52affa7 Gerd Hoffmann
}
449 2cc977e2 ths
450 8dbd4574 Paolo Bonzini
static SCSIReqOps scsi_generic_req_ops = {
451 8dbd4574 Paolo Bonzini
    .size         = sizeof(SCSIGenericReq),
452 12010e7b Paolo Bonzini
    .free_req     = scsi_free_request,
453 12010e7b Paolo Bonzini
    .send_command = scsi_send_command,
454 12010e7b Paolo Bonzini
    .read_data    = scsi_read_data,
455 12010e7b Paolo Bonzini
    .write_data   = scsi_write_data,
456 12010e7b Paolo Bonzini
    .cancel_io    = scsi_cancel_io,
457 12010e7b Paolo Bonzini
    .get_buf      = scsi_get_buf,
458 8dbd4574 Paolo Bonzini
};
459 8dbd4574 Paolo Bonzini
460 8dbd4574 Paolo Bonzini
static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
461 8dbd4574 Paolo Bonzini
                                     void *hba_private)
462 8dbd4574 Paolo Bonzini
{
463 8dbd4574 Paolo Bonzini
    SCSIRequest *req;
464 8dbd4574 Paolo Bonzini
465 8dbd4574 Paolo Bonzini
    req = scsi_req_alloc(&scsi_generic_req_ops, d, tag, lun, hba_private);
466 8dbd4574 Paolo Bonzini
    return req;
467 8dbd4574 Paolo Bonzini
}
468 8dbd4574 Paolo Bonzini
469 d52affa7 Gerd Hoffmann
static SCSIDeviceInfo scsi_generic_info = {
470 d52affa7 Gerd Hoffmann
    .qdev.name    = "scsi-generic",
471 d52affa7 Gerd Hoffmann
    .qdev.desc    = "pass through generic scsi device (/dev/sg*)",
472 d52affa7 Gerd Hoffmann
    .qdev.size    = sizeof(SCSIGenericState),
473 f8b6d672 Bernhard Kohl
    .qdev.reset   = scsi_generic_reset,
474 d52affa7 Gerd Hoffmann
    .init         = scsi_generic_initfn,
475 d52affa7 Gerd Hoffmann
    .destroy      = scsi_destroy,
476 5c6c0e51 Hannes Reinecke
    .alloc_req    = scsi_new_request,
477 d52affa7 Gerd Hoffmann
    .qdev.props   = (Property[]) {
478 428c149b Christoph Hellwig
        DEFINE_BLOCK_PROPERTIES(SCSIGenericState, qdev.conf),
479 d52affa7 Gerd Hoffmann
        DEFINE_PROP_END_OF_LIST(),
480 d52affa7 Gerd Hoffmann
    },
481 d52affa7 Gerd Hoffmann
};
482 2cc977e2 ths
483 d52affa7 Gerd Hoffmann
static void scsi_generic_register_devices(void)
484 d52affa7 Gerd Hoffmann
{
485 d52affa7 Gerd Hoffmann
    scsi_qdev_register(&scsi_generic_info);
486 2cc977e2 ths
}
487 d52affa7 Gerd Hoffmann
device_init(scsi_generic_register_devices)
488 d52affa7 Gerd Hoffmann
489 2cc977e2 ths
#endif /* __linux__ */