Statistics
| Branch: | Revision:

root / hw / scsi-generic.c @ 26ca8c06

History | View | Annotate | Download (14.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 1de7afc9 Paolo Bonzini
#include "qemu/error-report.h"
16 43b443b6 Gerd Hoffmann
#include "scsi.h"
17 9c17d615 Paolo Bonzini
#include "sysemu/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 a3b16e71 Paolo Bonzini
#define SG_ERR_DRIVER_TIMEOUT  0x06
43 a3b16e71 Paolo Bonzini
#define SG_ERR_DRIVER_SENSE    0x08
44 a3b16e71 Paolo Bonzini
45 a3b16e71 Paolo Bonzini
#define SG_ERR_DID_OK          0x00
46 a3b16e71 Paolo Bonzini
#define SG_ERR_DID_NO_CONNECT  0x01
47 a3b16e71 Paolo Bonzini
#define SG_ERR_DID_BUS_BUSY    0x02
48 a3b16e71 Paolo Bonzini
#define SG_ERR_DID_TIME_OUT    0x03
49 2cc977e2 ths
50 2cc977e2 ths
#ifndef MAX_UINT
51 2cc977e2 ths
#define MAX_UINT ((unsigned int)-1)
52 2cc977e2 ths
#endif
53 2cc977e2 ths
54 4c41d2ef Gerd Hoffmann
typedef struct SCSIGenericReq {
55 4c41d2ef Gerd Hoffmann
    SCSIRequest req;
56 2cc977e2 ths
    uint8_t *buf;
57 2cc977e2 ths
    int buflen;
58 2cc977e2 ths
    int len;
59 2cc977e2 ths
    sg_io_hdr_t io_header;
60 4c41d2ef Gerd Hoffmann
} SCSIGenericReq;
61 2cc977e2 ths
62 56b1fc48 Paolo Bonzini
static void scsi_generic_save_request(QEMUFile *f, SCSIRequest *req)
63 56b1fc48 Paolo Bonzini
{
64 56b1fc48 Paolo Bonzini
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
65 56b1fc48 Paolo Bonzini
66 56b1fc48 Paolo Bonzini
    qemu_put_sbe32s(f, &r->buflen);
67 56b1fc48 Paolo Bonzini
    if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) {
68 56b1fc48 Paolo Bonzini
        assert(!r->req.sg);
69 56b1fc48 Paolo Bonzini
        qemu_put_buffer(f, r->buf, r->req.cmd.xfer);
70 56b1fc48 Paolo Bonzini
    }
71 56b1fc48 Paolo Bonzini
}
72 56b1fc48 Paolo Bonzini
73 56b1fc48 Paolo Bonzini
static void scsi_generic_load_request(QEMUFile *f, SCSIRequest *req)
74 56b1fc48 Paolo Bonzini
{
75 56b1fc48 Paolo Bonzini
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
76 56b1fc48 Paolo Bonzini
77 56b1fc48 Paolo Bonzini
    qemu_get_sbe32s(f, &r->buflen);
78 56b1fc48 Paolo Bonzini
    if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) {
79 56b1fc48 Paolo Bonzini
        assert(!r->req.sg);
80 56b1fc48 Paolo Bonzini
        qemu_get_buffer(f, r->buf, r->req.cmd.xfer);
81 56b1fc48 Paolo Bonzini
    }
82 56b1fc48 Paolo Bonzini
}
83 56b1fc48 Paolo Bonzini
84 ad2d30f7 Paolo Bonzini
static void scsi_free_request(SCSIRequest *req)
85 2cc977e2 ths
{
86 ad2d30f7 Paolo Bonzini
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
87 ad2d30f7 Paolo Bonzini
88 7267c094 Anthony Liguori
    g_free(r->buf);
89 2cc977e2 ths
}
90 2cc977e2 ths
91 2cc977e2 ths
/* Helper function for command completion.  */
92 2cc977e2 ths
static void scsi_command_complete(void *opaque, int ret)
93 2cc977e2 ths
{
94 682a9b21 Paolo Bonzini
    int status;
95 4c41d2ef Gerd Hoffmann
    SCSIGenericReq *r = (SCSIGenericReq *)opaque;
96 2cc977e2 ths
97 d33e0ce2 Paolo Bonzini
    r->req.aiocb = NULL;
98 a3b16e71 Paolo Bonzini
    if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
99 b45ef674 Paolo Bonzini
        r->req.sense_len = r->io_header.sb_len_wr;
100 a3b16e71 Paolo Bonzini
    }
101 89c0f643 aurel32
102 a1f0cce2 Hannes Reinecke
    if (ret != 0) {
103 a1f0cce2 Hannes Reinecke
        switch (ret) {
104 2e7cc4d6 Paolo Bonzini
        case -EDOM:
105 682a9b21 Paolo Bonzini
            status = TASK_SET_FULL;
106 2e7cc4d6 Paolo Bonzini
            break;
107 a1f0cce2 Hannes Reinecke
        case -ENOMEM:
108 682a9b21 Paolo Bonzini
            status = CHECK_CONDITION;
109 b45ef674 Paolo Bonzini
            scsi_req_build_sense(&r->req, SENSE_CODE(TARGET_FAILURE));
110 a1f0cce2 Hannes Reinecke
            break;
111 a1f0cce2 Hannes Reinecke
        default:
112 682a9b21 Paolo Bonzini
            status = CHECK_CONDITION;
113 b45ef674 Paolo Bonzini
            scsi_req_build_sense(&r->req, SENSE_CODE(IO_ERROR));
114 a1f0cce2 Hannes Reinecke
            break;
115 a1f0cce2 Hannes Reinecke
        }
116 a1f0cce2 Hannes Reinecke
    } else {
117 a3b16e71 Paolo Bonzini
        if (r->io_header.host_status == SG_ERR_DID_NO_CONNECT ||
118 a3b16e71 Paolo Bonzini
            r->io_header.host_status == SG_ERR_DID_BUS_BUSY ||
119 a3b16e71 Paolo Bonzini
            r->io_header.host_status == SG_ERR_DID_TIME_OUT ||
120 a3b16e71 Paolo Bonzini
            (r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT)) {
121 682a9b21 Paolo Bonzini
            status = BUSY;
122 2cc977e2 ths
            BADF("Driver Timeout\n");
123 a3b16e71 Paolo Bonzini
        } else if (r->io_header.host_status) {
124 a3b16e71 Paolo Bonzini
            status = CHECK_CONDITION;
125 a3b16e71 Paolo Bonzini
            scsi_req_build_sense(&r->req, SENSE_CODE(I_T_NEXUS_LOSS));
126 682a9b21 Paolo Bonzini
        } else if (r->io_header.status) {
127 682a9b21 Paolo Bonzini
            status = r->io_header.status;
128 b45ef674 Paolo Bonzini
        } else if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
129 682a9b21 Paolo Bonzini
            status = CHECK_CONDITION;
130 682a9b21 Paolo Bonzini
        } else {
131 682a9b21 Paolo Bonzini
            status = GOOD;
132 682a9b21 Paolo Bonzini
        }
133 2cc977e2 ths
    }
134 89c0f643 aurel32
    DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
135 682a9b21 Paolo Bonzini
            r, r->req.tag, status);
136 ed3a34a3 Gerd Hoffmann
137 682a9b21 Paolo Bonzini
    scsi_req_complete(&r->req, status);
138 c9501c95 Paolo Bonzini
    if (!r->req.io_canceled) {
139 c9501c95 Paolo Bonzini
        scsi_req_unref(&r->req);
140 c9501c95 Paolo Bonzini
    }
141 2cc977e2 ths
}
142 2cc977e2 ths
143 2cc977e2 ths
/* Cancel a pending data transfer.  */
144 5c6c0e51 Hannes Reinecke
static void scsi_cancel_io(SCSIRequest *req)
145 2cc977e2 ths
{
146 5c6c0e51 Hannes Reinecke
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
147 5c6c0e51 Hannes Reinecke
148 5c6c0e51 Hannes Reinecke
    DPRINTF("Cancel tag=0x%x\n", req->tag);
149 5c6c0e51 Hannes Reinecke
    if (r->req.aiocb) {
150 5c6c0e51 Hannes Reinecke
        bdrv_aio_cancel(r->req.aiocb);
151 c9501c95 Paolo Bonzini
152 c9501c95 Paolo Bonzini
        /* This reference was left in by scsi_*_data.  We take ownership of
153 c9501c95 Paolo Bonzini
         * it independent of whether bdrv_aio_cancel completes the request
154 c9501c95 Paolo Bonzini
         * or not.  */
155 c9501c95 Paolo Bonzini
        scsi_req_unref(&r->req);
156 2cc977e2 ths
    }
157 5c6c0e51 Hannes Reinecke
    r->req.aiocb = NULL;
158 2cc977e2 ths
}
159 2cc977e2 ths
160 2cc977e2 ths
static int execute_command(BlockDriverState *bdrv,
161 4c41d2ef Gerd Hoffmann
                           SCSIGenericReq *r, int direction,
162 2cc977e2 ths
                           BlockDriverCompletionFunc *complete)
163 2cc977e2 ths
{
164 2cc977e2 ths
    r->io_header.interface_id = 'S';
165 2cc977e2 ths
    r->io_header.dxfer_direction = direction;
166 2cc977e2 ths
    r->io_header.dxferp = r->buf;
167 2cc977e2 ths
    r->io_header.dxfer_len = r->buflen;
168 29362ebe Gerd Hoffmann
    r->io_header.cmdp = r->req.cmd.buf;
169 29362ebe Gerd Hoffmann
    r->io_header.cmd_len = r->req.cmd.len;
170 b45ef674 Paolo Bonzini
    r->io_header.mx_sb_len = sizeof(r->req.sense);
171 b45ef674 Paolo Bonzini
    r->io_header.sbp = r->req.sense;
172 2cc977e2 ths
    r->io_header.timeout = MAX_UINT;
173 2cc977e2 ths
    r->io_header.usr_ptr = r;
174 2cc977e2 ths
    r->io_header.flags |= SG_FLAG_DIRECT_IO;
175 2cc977e2 ths
176 4c41d2ef Gerd Hoffmann
    r->req.aiocb = bdrv_aio_ioctl(bdrv, SG_IO, &r->io_header, complete, r);
177 2cc977e2 ths
178 2cc977e2 ths
    return 0;
179 2cc977e2 ths
}
180 2cc977e2 ths
181 2cc977e2 ths
static void scsi_read_complete(void * opaque, int ret)
182 2cc977e2 ths
{
183 4c41d2ef Gerd Hoffmann
    SCSIGenericReq *r = (SCSIGenericReq *)opaque;
184 9b6eef8a Paolo Bonzini
    SCSIDevice *s = r->req.dev;
185 2cc977e2 ths
    int len;
186 2cc977e2 ths
187 d33e0ce2 Paolo Bonzini
    r->req.aiocb = NULL;
188 2cc977e2 ths
    if (ret) {
189 aa2b1e89 Bernhard Kohl
        DPRINTF("IO error ret %d\n", ret);
190 2cc977e2 ths
        scsi_command_complete(r, ret);
191 2cc977e2 ths
        return;
192 2cc977e2 ths
    }
193 2cc977e2 ths
    len = r->io_header.dxfer_len - r->io_header.resid;
194 4c41d2ef Gerd Hoffmann
    DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, len);
195 2cc977e2 ths
196 2cc977e2 ths
    r->len = -1;
197 40f16dd1 Paolo Bonzini
    if (len == 0) {
198 89c0f643 aurel32
        scsi_command_complete(r, 0);
199 40f16dd1 Paolo Bonzini
    } else {
200 9b6eef8a Paolo Bonzini
        /* Snoop READ CAPACITY output to set the blocksize.  */
201 9b6eef8a Paolo Bonzini
        if (r->req.cmd.buf[0] == READ_CAPACITY_10) {
202 9b6eef8a Paolo Bonzini
            s->blocksize = ldl_be_p(&r->buf[4]);
203 7877903a Paolo Bonzini
            s->max_lba = ldl_be_p(&r->buf[0]);
204 9b6eef8a Paolo Bonzini
        } else if (r->req.cmd.buf[0] == SERVICE_ACTION_IN_16 &&
205 9b6eef8a Paolo Bonzini
                   (r->req.cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) {
206 9b6eef8a Paolo Bonzini
            s->blocksize = ldl_be_p(&r->buf[8]);
207 7877903a Paolo Bonzini
            s->max_lba = ldq_be_p(&r->buf[0]);
208 9b6eef8a Paolo Bonzini
        }
209 9b6eef8a Paolo Bonzini
        bdrv_set_buffer_alignment(s->conf.bs, s->blocksize);
210 9b6eef8a Paolo Bonzini
211 ab9adc88 Paolo Bonzini
        scsi_req_data(&r->req, len);
212 c9501c95 Paolo Bonzini
        if (!r->req.io_canceled) {
213 c9501c95 Paolo Bonzini
            scsi_req_unref(&r->req);
214 c9501c95 Paolo Bonzini
        }
215 40f16dd1 Paolo Bonzini
    }
216 2cc977e2 ths
}
217 2cc977e2 ths
218 2cc977e2 ths
/* Read more data from scsi device into buffer.  */
219 5c6c0e51 Hannes Reinecke
static void scsi_read_data(SCSIRequest *req)
220 2cc977e2 ths
{
221 5c6c0e51 Hannes Reinecke
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
222 8869e103 Paolo Bonzini
    SCSIDevice *s = r->req.dev;
223 2cc977e2 ths
    int ret;
224 2cc977e2 ths
225 5c6c0e51 Hannes Reinecke
    DPRINTF("scsi_read_data 0x%x\n", req->tag);
226 c9501c95 Paolo Bonzini
227 c9501c95 Paolo Bonzini
    /* The request is used as the AIO opaque value, so add a ref.  */
228 c9501c95 Paolo Bonzini
    scsi_req_ref(&r->req);
229 2cc977e2 ths
    if (r->len == -1) {
230 2cc977e2 ths
        scsi_command_complete(r, 0);
231 2cc977e2 ths
        return;
232 2cc977e2 ths
    }
233 2cc977e2 ths
234 8869e103 Paolo Bonzini
    ret = execute_command(s->conf.bs, r, SG_DXFER_FROM_DEV, scsi_read_complete);
235 a1f0cce2 Hannes Reinecke
    if (ret < 0) {
236 a1f0cce2 Hannes Reinecke
        scsi_command_complete(r, ret);
237 2cc977e2 ths
    }
238 2cc977e2 ths
}
239 2cc977e2 ths
240 2cc977e2 ths
static void scsi_write_complete(void * opaque, int ret)
241 2cc977e2 ths
{
242 4c41d2ef Gerd Hoffmann
    SCSIGenericReq *r = (SCSIGenericReq *)opaque;
243 8869e103 Paolo Bonzini
    SCSIDevice *s = r->req.dev;
244 2cc977e2 ths
245 2cc977e2 ths
    DPRINTF("scsi_write_complete() ret = %d\n", ret);
246 d33e0ce2 Paolo Bonzini
    r->req.aiocb = NULL;
247 2cc977e2 ths
    if (ret) {
248 2cc977e2 ths
        DPRINTF("IO error\n");
249 2cc977e2 ths
        scsi_command_complete(r, ret);
250 2cc977e2 ths
        return;
251 2cc977e2 ths
    }
252 2cc977e2 ths
253 29362ebe Gerd Hoffmann
    if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 &&
254 8869e103 Paolo Bonzini
        s->type == TYPE_TAPE) {
255 8869e103 Paolo Bonzini
        s->blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
256 8869e103 Paolo Bonzini
        DPRINTF("block size %d\n", s->blocksize);
257 89c0f643 aurel32
    }
258 89c0f643 aurel32
259 2cc977e2 ths
    scsi_command_complete(r, ret);
260 2cc977e2 ths
}
261 2cc977e2 ths
262 2cc977e2 ths
/* Write data to a scsi device.  Returns nonzero on failure.
263 2cc977e2 ths
   The transfer may complete asynchronously.  */
264 42741212 Paolo Bonzini
static void scsi_write_data(SCSIRequest *req)
265 2cc977e2 ths
{
266 5c6c0e51 Hannes Reinecke
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
267 8869e103 Paolo Bonzini
    SCSIDevice *s = r->req.dev;
268 2cc977e2 ths
    int ret;
269 2cc977e2 ths
270 5c6c0e51 Hannes Reinecke
    DPRINTF("scsi_write_data 0x%x\n", req->tag);
271 2cc977e2 ths
    if (r->len == 0) {
272 2cc977e2 ths
        r->len = r->buflen;
273 ab9adc88 Paolo Bonzini
        scsi_req_data(&r->req, r->len);
274 42741212 Paolo Bonzini
        return;
275 2cc977e2 ths
    }
276 2cc977e2 ths
277 c9501c95 Paolo Bonzini
    /* The request is used as the AIO opaque value, so add a ref.  */
278 c9501c95 Paolo Bonzini
    scsi_req_ref(&r->req);
279 8869e103 Paolo Bonzini
    ret = execute_command(s->conf.bs, r, SG_DXFER_TO_DEV, scsi_write_complete);
280 a1f0cce2 Hannes Reinecke
    if (ret < 0) {
281 a1f0cce2 Hannes Reinecke
        scsi_command_complete(r, ret);
282 2cc977e2 ths
    }
283 2cc977e2 ths
}
284 2cc977e2 ths
285 2cc977e2 ths
/* Return a pointer to the data buffer.  */
286 5c6c0e51 Hannes Reinecke
static uint8_t *scsi_get_buf(SCSIRequest *req)
287 2cc977e2 ths
{
288 5c6c0e51 Hannes Reinecke
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
289 5c6c0e51 Hannes Reinecke
290 2cc977e2 ths
    return r->buf;
291 2cc977e2 ths
}
292 2cc977e2 ths
293 2cc977e2 ths
/* Execute a scsi command.  Returns the length of the data expected by the
294 2cc977e2 ths
   command.  This will be Positive for data transfers from the device
295 2cc977e2 ths
   (eg. disk reads), negative for transfers to the device (eg. disk writes),
296 2cc977e2 ths
   and zero if the command does not transfer any data.  */
297 2cc977e2 ths
298 5c6c0e51 Hannes Reinecke
static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
299 2cc977e2 ths
{
300 5c6c0e51 Hannes Reinecke
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
301 8869e103 Paolo Bonzini
    SCSIDevice *s = r->req.dev;
302 2cc977e2 ths
    int ret;
303 2cc977e2 ths
304 aa2b1e89 Bernhard Kohl
    DPRINTF("Command: lun=%d tag=0x%x len %zd data=0x%02x", lun, tag,
305 aa2b1e89 Bernhard Kohl
            r->req.cmd.xfer, cmd[0]);
306 aa2b1e89 Bernhard Kohl
307 aa2b1e89 Bernhard Kohl
#ifdef DEBUG_SCSI
308 aa2b1e89 Bernhard Kohl
    {
309 aa2b1e89 Bernhard Kohl
        int i;
310 aa2b1e89 Bernhard Kohl
        for (i = 1; i < r->req.cmd.len; i++) {
311 aa2b1e89 Bernhard Kohl
            printf(" 0x%02x", cmd[i]);
312 aa2b1e89 Bernhard Kohl
        }
313 aa2b1e89 Bernhard Kohl
        printf("\n");
314 aa2b1e89 Bernhard Kohl
    }
315 aa2b1e89 Bernhard Kohl
#endif
316 2cc977e2 ths
317 2ec749cb Gerd Hoffmann
    if (r->req.cmd.xfer == 0) {
318 2cc977e2 ths
        if (r->buf != NULL)
319 7267c094 Anthony Liguori
            g_free(r->buf);
320 2cc977e2 ths
        r->buflen = 0;
321 2cc977e2 ths
        r->buf = NULL;
322 c9501c95 Paolo Bonzini
        /* The request is used as the AIO opaque value, so add a ref.  */
323 c9501c95 Paolo Bonzini
        scsi_req_ref(&r->req);
324 8869e103 Paolo Bonzini
        ret = execute_command(s->conf.bs, r, SG_DXFER_NONE, scsi_command_complete);
325 a1f0cce2 Hannes Reinecke
        if (ret < 0) {
326 a1f0cce2 Hannes Reinecke
            scsi_command_complete(r, ret);
327 a1f0cce2 Hannes Reinecke
            return 0;
328 2cc977e2 ths
        }
329 2cc977e2 ths
        return 0;
330 2cc977e2 ths
    }
331 2cc977e2 ths
332 2ec749cb Gerd Hoffmann
    if (r->buflen != r->req.cmd.xfer) {
333 2cc977e2 ths
        if (r->buf != NULL)
334 7267c094 Anthony Liguori
            g_free(r->buf);
335 7267c094 Anthony Liguori
        r->buf = g_malloc(r->req.cmd.xfer);
336 2ec749cb Gerd Hoffmann
        r->buflen = r->req.cmd.xfer;
337 2cc977e2 ths
    }
338 2cc977e2 ths
339 2cc977e2 ths
    memset(r->buf, 0, r->buflen);
340 2ec749cb Gerd Hoffmann
    r->len = r->req.cmd.xfer;
341 97a06435 Gerd Hoffmann
    if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
342 2cc977e2 ths
        r->len = 0;
343 5c6c0e51 Hannes Reinecke
        return -r->req.cmd.xfer;
344 ad2d30f7 Paolo Bonzini
    } else {
345 5c6c0e51 Hannes Reinecke
        return r->req.cmd.xfer;
346 2cc977e2 ths
    }
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 fe0ed712 Paolo Bonzini
    if (ret < 0 || io_header.driver_status || io_header.host_status) {
375 89c0f643 aurel32
        return -1;
376 fe0ed712 Paolo Bonzini
    }
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 b9eea3e6 Anthony Liguori
    SCSIDevice *s = SCSI_DEVICE(dev);
383 f8b6d672 Bernhard Kohl
384 8869e103 Paolo Bonzini
    scsi_device_purge_requests(s, SENSE_CODE(RESET));
385 f8b6d672 Bernhard Kohl
}
386 f8b6d672 Bernhard Kohl
387 8869e103 Paolo Bonzini
static void scsi_destroy(SCSIDevice *s)
388 f8b6d672 Bernhard Kohl
{
389 8869e103 Paolo Bonzini
    scsi_device_purge_requests(s, SENSE_CODE(NO_SENSE));
390 8869e103 Paolo Bonzini
    blockdev_mark_auto_del(s->conf.bs);
391 2cc977e2 ths
}
392 2cc977e2 ths
393 8869e103 Paolo Bonzini
static int scsi_generic_initfn(SCSIDevice *s)
394 2cc977e2 ths
{
395 2cc977e2 ths
    int sg_version;
396 2cc977e2 ths
    struct sg_scsi_id scsiid;
397 2cc977e2 ths
398 8869e103 Paolo Bonzini
    if (!s->conf.bs) {
399 6a84cb1f Markus Armbruster
        error_report("drive property not set");
400 d52affa7 Gerd Hoffmann
        return -1;
401 d52affa7 Gerd Hoffmann
    }
402 2cc977e2 ths
403 92aa5c6d Paolo Bonzini
    if (bdrv_get_on_error(s->conf.bs, 0) != BLOCKDEV_ON_ERROR_ENOSPC) {
404 620f862e Markus Armbruster
        error_report("Device doesn't support drive option werror");
405 620f862e Markus Armbruster
        return -1;
406 620f862e Markus Armbruster
    }
407 92aa5c6d Paolo Bonzini
    if (bdrv_get_on_error(s->conf.bs, 1) != BLOCKDEV_ON_ERROR_REPORT) {
408 620f862e Markus Armbruster
        error_report("Device doesn't support drive option rerror");
409 620f862e Markus Armbruster
        return -1;
410 620f862e Markus Armbruster
    }
411 620f862e Markus Armbruster
412 2cc977e2 ths
    /* check we are using a driver managing SG_IO (version 3 and after */
413 98392453 Ronnie Sahlberg
    if (bdrv_ioctl(s->conf.bs, SG_GET_VERSION_NUM, &sg_version) < 0) {
414 98392453 Ronnie Sahlberg
        error_report("scsi generic interface not supported");
415 98392453 Ronnie Sahlberg
        return -1;
416 98392453 Ronnie Sahlberg
    }
417 98392453 Ronnie Sahlberg
    if (sg_version < 30000) {
418 6a84cb1f Markus Armbruster
        error_report("scsi generic interface too old");
419 d52affa7 Gerd Hoffmann
        return -1;
420 d52affa7 Gerd Hoffmann
    }
421 2cc977e2 ths
422 2cc977e2 ths
    /* get LUN of the /dev/sg? */
423 8869e103 Paolo Bonzini
    if (bdrv_ioctl(s->conf.bs, SG_GET_SCSI_ID, &scsiid)) {
424 6a84cb1f Markus Armbruster
        error_report("SG_GET_SCSI_ID ioctl failed");
425 d52affa7 Gerd Hoffmann
        return -1;
426 d52affa7 Gerd Hoffmann
    }
427 2cc977e2 ths
428 2cc977e2 ths
    /* define device state */
429 8869e103 Paolo Bonzini
    s->type = scsiid.scsi_type;
430 8869e103 Paolo Bonzini
    DPRINTF("device type %d\n", s->type);
431 28b77657 Paolo Bonzini
    if (s->type == TYPE_DISK || s->type == TYPE_ROM) {
432 28b77657 Paolo Bonzini
        add_boot_device_path(s->conf.bootindex, &s->qdev, NULL);
433 28b77657 Paolo Bonzini
    }
434 28b77657 Paolo Bonzini
435 9b6eef8a Paolo Bonzini
    switch (s->type) {
436 9b6eef8a Paolo Bonzini
    case TYPE_TAPE:
437 8869e103 Paolo Bonzini
        s->blocksize = get_stream_blocksize(s->conf.bs);
438 8869e103 Paolo Bonzini
        if (s->blocksize == -1) {
439 8869e103 Paolo Bonzini
            s->blocksize = 0;
440 8869e103 Paolo Bonzini
        }
441 9b6eef8a Paolo Bonzini
        break;
442 9b6eef8a Paolo Bonzini
443 9b6eef8a Paolo Bonzini
        /* Make a guess for block devices, we'll fix it when the guest sends.
444 9b6eef8a Paolo Bonzini
         * READ CAPACITY.  If they don't, they likely would assume these sizes
445 9b6eef8a Paolo Bonzini
         * anyway. (TODO: they could also send MODE SENSE).
446 9b6eef8a Paolo Bonzini
         */
447 9b6eef8a Paolo Bonzini
    case TYPE_ROM:
448 9b6eef8a Paolo Bonzini
    case TYPE_WORM:
449 9b6eef8a Paolo Bonzini
        s->blocksize = 2048;
450 9b6eef8a Paolo Bonzini
        break;
451 9b6eef8a Paolo Bonzini
    default:
452 9b6eef8a Paolo Bonzini
        s->blocksize = 512;
453 9b6eef8a Paolo Bonzini
        break;
454 89c0f643 aurel32
    }
455 8869e103 Paolo Bonzini
456 8869e103 Paolo Bonzini
    DPRINTF("block size %d\n", s->blocksize);
457 d52affa7 Gerd Hoffmann
    return 0;
458 d52affa7 Gerd Hoffmann
}
459 2cc977e2 ths
460 765d1525 Paolo Bonzini
const SCSIReqOps scsi_generic_req_ops = {
461 8dbd4574 Paolo Bonzini
    .size         = sizeof(SCSIGenericReq),
462 12010e7b Paolo Bonzini
    .free_req     = scsi_free_request,
463 12010e7b Paolo Bonzini
    .send_command = scsi_send_command,
464 12010e7b Paolo Bonzini
    .read_data    = scsi_read_data,
465 12010e7b Paolo Bonzini
    .write_data   = scsi_write_data,
466 12010e7b Paolo Bonzini
    .cancel_io    = scsi_cancel_io,
467 12010e7b Paolo Bonzini
    .get_buf      = scsi_get_buf,
468 56b1fc48 Paolo Bonzini
    .load_request = scsi_generic_load_request,
469 56b1fc48 Paolo Bonzini
    .save_request = scsi_generic_save_request,
470 8dbd4574 Paolo Bonzini
};
471 8dbd4574 Paolo Bonzini
472 8dbd4574 Paolo Bonzini
static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
473 63db0f0e Paolo Bonzini
                                     uint8_t *buf, void *hba_private)
474 8dbd4574 Paolo Bonzini
{
475 8dbd4574 Paolo Bonzini
    SCSIRequest *req;
476 8dbd4574 Paolo Bonzini
477 8dbd4574 Paolo Bonzini
    req = scsi_req_alloc(&scsi_generic_req_ops, d, tag, lun, hba_private);
478 8dbd4574 Paolo Bonzini
    return req;
479 8dbd4574 Paolo Bonzini
}
480 8dbd4574 Paolo Bonzini
481 39bffca2 Anthony Liguori
static Property scsi_generic_properties[] = {
482 0f1da449 Paolo Bonzini
    DEFINE_PROP_DRIVE("drive", SCSIDevice, conf.bs),
483 0f1da449 Paolo Bonzini
    DEFINE_PROP_INT32("bootindex", SCSIDevice, conf.bootindex, -1),
484 39bffca2 Anthony Liguori
    DEFINE_PROP_END_OF_LIST(),
485 39bffca2 Anthony Liguori
};
486 39bffca2 Anthony Liguori
487 b9eea3e6 Anthony Liguori
static void scsi_generic_class_initfn(ObjectClass *klass, void *data)
488 b9eea3e6 Anthony Liguori
{
489 39bffca2 Anthony Liguori
    DeviceClass *dc = DEVICE_CLASS(klass);
490 b9eea3e6 Anthony Liguori
    SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
491 b9eea3e6 Anthony Liguori
492 b9eea3e6 Anthony Liguori
    sc->init         = scsi_generic_initfn;
493 b9eea3e6 Anthony Liguori
    sc->destroy      = scsi_destroy;
494 b9eea3e6 Anthony Liguori
    sc->alloc_req    = scsi_new_request;
495 39bffca2 Anthony Liguori
    dc->fw_name = "disk";
496 39bffca2 Anthony Liguori
    dc->desc = "pass through generic scsi device (/dev/sg*)";
497 39bffca2 Anthony Liguori
    dc->reset = scsi_generic_reset;
498 39bffca2 Anthony Liguori
    dc->props = scsi_generic_properties;
499 56b1fc48 Paolo Bonzini
    dc->vmsd  = &vmstate_scsi_device;
500 b9eea3e6 Anthony Liguori
}
501 b9eea3e6 Anthony Liguori
502 8c43a6f0 Andreas Färber
static const TypeInfo scsi_generic_info = {
503 39bffca2 Anthony Liguori
    .name          = "scsi-generic",
504 39bffca2 Anthony Liguori
    .parent        = TYPE_SCSI_DEVICE,
505 39bffca2 Anthony Liguori
    .instance_size = sizeof(SCSIDevice),
506 39bffca2 Anthony Liguori
    .class_init    = scsi_generic_class_initfn,
507 d52affa7 Gerd Hoffmann
};
508 2cc977e2 ths
509 83f7d43a Andreas Färber
static void scsi_generic_register_types(void)
510 d52affa7 Gerd Hoffmann
{
511 39bffca2 Anthony Liguori
    type_register_static(&scsi_generic_info);
512 2cc977e2 ths
}
513 83f7d43a Andreas Färber
514 83f7d43a Andreas Färber
type_init(scsi_generic_register_types)
515 d52affa7 Gerd Hoffmann
516 2cc977e2 ths
#endif /* __linux__ */