Statistics
| Branch: | Revision:

root / hw / scsi-generic.c @ 8e31bf38

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