Statistics
| Branch: | Revision:

root / hw / scsi-generic.c @ 6a58a3a6

History | View | Annotate | Download (12 kB)

1
/*
2
 * Generic SCSI Device support
3
 *
4
 * Copyright (c) 2007 Bull S.A.S.
5
 * Based on code by Paul Brook
6
 * Based on code by Fabrice Bellard
7
 *
8
 * Written by Laurent Vivier <Laurent.Vivier@bull.net>
9
 *
10
 * This code is licensed under the LGPL.
11
 *
12
 */
13

    
14
#include "qemu-common.h"
15
#include "qemu-error.h"
16
#include "scsi.h"
17
#include "blockdev.h"
18

    
19
#ifdef __linux__
20

    
21
//#define DEBUG_SCSI
22

    
23
#ifdef DEBUG_SCSI
24
#define DPRINTF(fmt, ...) \
25
do { printf("scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
26
#else
27
#define DPRINTF(fmt, ...) do {} while(0)
28
#endif
29

    
30
#define BADF(fmt, ...) \
31
do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
32

    
33
#include <stdio.h>
34
#include <sys/types.h>
35
#include <sys/stat.h>
36
#include <unistd.h>
37
#include <scsi/sg.h>
38
#include "scsi-defs.h"
39

    
40
#define SCSI_SENSE_BUF_SIZE 96
41

    
42
#define SG_ERR_DRIVER_TIMEOUT 0x06
43
#define SG_ERR_DRIVER_SENSE 0x08
44

    
45
#ifndef MAX_UINT
46
#define MAX_UINT ((unsigned int)-1)
47
#endif
48

    
49
typedef struct SCSIGenericReq {
50
    SCSIRequest req;
51
    uint8_t *buf;
52
    int buflen;
53
    int len;
54
    sg_io_hdr_t io_header;
55
} SCSIGenericReq;
56

    
57
static void scsi_free_request(SCSIRequest *req)
58
{
59
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
60

    
61
    g_free(r->buf);
62
}
63

    
64
/* Helper function for command completion.  */
65
static void scsi_command_complete(void *opaque, int ret)
66
{
67
    int status;
68
    SCSIGenericReq *r = (SCSIGenericReq *)opaque;
69

    
70
    r->req.aiocb = NULL;
71
    if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE)
72
        r->req.sense_len = r->io_header.sb_len_wr;
73

    
74
    if (ret != 0) {
75
        switch (ret) {
76
        case -EDOM:
77
            status = TASK_SET_FULL;
78
            break;
79
        case -ENOMEM:
80
            status = CHECK_CONDITION;
81
            scsi_req_build_sense(&r->req, SENSE_CODE(TARGET_FAILURE));
82
            break;
83
        default:
84
            status = CHECK_CONDITION;
85
            scsi_req_build_sense(&r->req, SENSE_CODE(IO_ERROR));
86
            break;
87
        }
88
    } else {
89
        if (r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT) {
90
            status = BUSY;
91
            BADF("Driver Timeout\n");
92
        } else if (r->io_header.status) {
93
            status = r->io_header.status;
94
        } else if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
95
            status = CHECK_CONDITION;
96
        } else {
97
            status = GOOD;
98
        }
99
    }
100
    DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
101
            r, r->req.tag, status);
102

    
103
    scsi_req_complete(&r->req, status);
104
}
105

    
106
/* Cancel a pending data transfer.  */
107
static void scsi_cancel_io(SCSIRequest *req)
108
{
109
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
110

    
111
    DPRINTF("Cancel tag=0x%x\n", req->tag);
112
    if (r->req.aiocb) {
113
        bdrv_aio_cancel(r->req.aiocb);
114
    }
115
    r->req.aiocb = NULL;
116
}
117

    
118
static int execute_command(BlockDriverState *bdrv,
119
                           SCSIGenericReq *r, int direction,
120
                           BlockDriverCompletionFunc *complete)
121
{
122
    r->io_header.interface_id = 'S';
123
    r->io_header.dxfer_direction = direction;
124
    r->io_header.dxferp = r->buf;
125
    r->io_header.dxfer_len = r->buflen;
126
    r->io_header.cmdp = r->req.cmd.buf;
127
    r->io_header.cmd_len = r->req.cmd.len;
128
    r->io_header.mx_sb_len = sizeof(r->req.sense);
129
    r->io_header.sbp = r->req.sense;
130
    r->io_header.timeout = MAX_UINT;
131
    r->io_header.usr_ptr = r;
132
    r->io_header.flags |= SG_FLAG_DIRECT_IO;
133

    
134
    r->req.aiocb = bdrv_aio_ioctl(bdrv, SG_IO, &r->io_header, complete, r);
135
    if (r->req.aiocb == NULL) {
136
        BADF("execute_command: read failed !\n");
137
        return -ENOMEM;
138
    }
139

    
140
    return 0;
141
}
142

    
143
static void scsi_read_complete(void * opaque, int ret)
144
{
145
    SCSIGenericReq *r = (SCSIGenericReq *)opaque;
146
    int len;
147

    
148
    r->req.aiocb = NULL;
149
    if (ret) {
150
        DPRINTF("IO error ret %d\n", ret);
151
        scsi_command_complete(r, ret);
152
        return;
153
    }
154
    len = r->io_header.dxfer_len - r->io_header.resid;
155
    DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, len);
156

    
157
    r->len = -1;
158
    if (len == 0) {
159
        scsi_command_complete(r, 0);
160
    } else {
161
        scsi_req_data(&r->req, len);
162
    }
163
}
164

    
165
/* Read more data from scsi device into buffer.  */
166
static void scsi_read_data(SCSIRequest *req)
167
{
168
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
169
    SCSIDevice *s = r->req.dev;
170
    int ret;
171

    
172
    DPRINTF("scsi_read_data 0x%x\n", req->tag);
173
    if (r->len == -1) {
174
        scsi_command_complete(r, 0);
175
        return;
176
    }
177

    
178
    ret = execute_command(s->conf.bs, r, SG_DXFER_FROM_DEV, scsi_read_complete);
179
    if (ret < 0) {
180
        scsi_command_complete(r, ret);
181
    }
182
}
183

    
184
static void scsi_write_complete(void * opaque, int ret)
185
{
186
    SCSIGenericReq *r = (SCSIGenericReq *)opaque;
187
    SCSIDevice *s = r->req.dev;
188

    
189
    DPRINTF("scsi_write_complete() ret = %d\n", ret);
190
    r->req.aiocb = NULL;
191
    if (ret) {
192
        DPRINTF("IO error\n");
193
        scsi_command_complete(r, ret);
194
        return;
195
    }
196

    
197
    if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 &&
198
        s->type == TYPE_TAPE) {
199
        s->blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
200
        DPRINTF("block size %d\n", s->blocksize);
201
    }
202

    
203
    scsi_command_complete(r, ret);
204
}
205

    
206
/* Write data to a scsi device.  Returns nonzero on failure.
207
   The transfer may complete asynchronously.  */
208
static void scsi_write_data(SCSIRequest *req)
209
{
210
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
211
    SCSIDevice *s = r->req.dev;
212
    int ret;
213

    
214
    DPRINTF("scsi_write_data 0x%x\n", req->tag);
215
    if (r->len == 0) {
216
        r->len = r->buflen;
217
        scsi_req_data(&r->req, r->len);
218
        return;
219
    }
220

    
221
    ret = execute_command(s->conf.bs, r, SG_DXFER_TO_DEV, scsi_write_complete);
222
    if (ret < 0) {
223
        scsi_command_complete(r, ret);
224
    }
225
}
226

    
227
/* Return a pointer to the data buffer.  */
228
static uint8_t *scsi_get_buf(SCSIRequest *req)
229
{
230
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
231

    
232
    return r->buf;
233
}
234

    
235
/* Execute a scsi command.  Returns the length of the data expected by the
236
   command.  This will be Positive for data transfers from the device
237
   (eg. disk reads), negative for transfers to the device (eg. disk writes),
238
   and zero if the command does not transfer any data.  */
239

    
240
static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
241
{
242
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
243
    SCSIDevice *s = r->req.dev;
244
    int ret;
245

    
246
    DPRINTF("Command: lun=%d tag=0x%x len %zd data=0x%02x", lun, tag,
247
            r->req.cmd.xfer, cmd[0]);
248

    
249
#ifdef DEBUG_SCSI
250
    {
251
        int i;
252
        for (i = 1; i < r->req.cmd.len; i++) {
253
            printf(" 0x%02x", cmd[i]);
254
        }
255
        printf("\n");
256
    }
257
#endif
258

    
259
    if (r->req.cmd.xfer == 0) {
260
        if (r->buf != NULL)
261
            g_free(r->buf);
262
        r->buflen = 0;
263
        r->buf = NULL;
264
        ret = execute_command(s->conf.bs, r, SG_DXFER_NONE, scsi_command_complete);
265
        if (ret < 0) {
266
            scsi_command_complete(r, ret);
267
            return 0;
268
        }
269
        return 0;
270
    }
271

    
272
    if (r->buflen != r->req.cmd.xfer) {
273
        if (r->buf != NULL)
274
            g_free(r->buf);
275
        r->buf = g_malloc(r->req.cmd.xfer);
276
        r->buflen = r->req.cmd.xfer;
277
    }
278

    
279
    memset(r->buf, 0, r->buflen);
280
    r->len = r->req.cmd.xfer;
281
    if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
282
        r->len = 0;
283
        return -r->req.cmd.xfer;
284
    } else {
285
        return r->req.cmd.xfer;
286
    }
287
}
288

    
289
static int get_blocksize(BlockDriverState *bdrv)
290
{
291
    uint8_t cmd[10];
292
    uint8_t buf[8];
293
    uint8_t sensebuf[8];
294
    sg_io_hdr_t io_header;
295
    int ret;
296

    
297
    memset(cmd, 0, sizeof(cmd));
298
    memset(buf, 0, sizeof(buf));
299
    cmd[0] = READ_CAPACITY_10;
300

    
301
    memset(&io_header, 0, sizeof(io_header));
302
    io_header.interface_id = 'S';
303
    io_header.dxfer_direction = SG_DXFER_FROM_DEV;
304
    io_header.dxfer_len = sizeof(buf);
305
    io_header.dxferp = buf;
306
    io_header.cmdp = cmd;
307
    io_header.cmd_len = sizeof(cmd);
308
    io_header.mx_sb_len = sizeof(sensebuf);
309
    io_header.sbp = sensebuf;
310
    io_header.timeout = 6000; /* XXX */
311

    
312
    ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
313
    if (ret < 0)
314
        return -1;
315

    
316
    return (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
317
}
318

    
319
static int get_stream_blocksize(BlockDriverState *bdrv)
320
{
321
    uint8_t cmd[6];
322
    uint8_t buf[12];
323
    uint8_t sensebuf[8];
324
    sg_io_hdr_t io_header;
325
    int ret;
326

    
327
    memset(cmd, 0, sizeof(cmd));
328
    memset(buf, 0, sizeof(buf));
329
    cmd[0] = MODE_SENSE;
330
    cmd[4] = sizeof(buf);
331

    
332
    memset(&io_header, 0, sizeof(io_header));
333
    io_header.interface_id = 'S';
334
    io_header.dxfer_direction = SG_DXFER_FROM_DEV;
335
    io_header.dxfer_len = sizeof(buf);
336
    io_header.dxferp = buf;
337
    io_header.cmdp = cmd;
338
    io_header.cmd_len = sizeof(cmd);
339
    io_header.mx_sb_len = sizeof(sensebuf);
340
    io_header.sbp = sensebuf;
341
    io_header.timeout = 6000; /* XXX */
342

    
343
    ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
344
    if (ret < 0)
345
        return -1;
346

    
347
    return (buf[9] << 16) | (buf[10] << 8) | buf[11];
348
}
349

    
350
static void scsi_generic_reset(DeviceState *dev)
351
{
352
    SCSIDevice *s = DO_UPCAST(SCSIDevice, qdev, dev);
353

    
354
    scsi_device_purge_requests(s, SENSE_CODE(RESET));
355
}
356

    
357
static void scsi_destroy(SCSIDevice *s)
358
{
359
    scsi_device_purge_requests(s, SENSE_CODE(NO_SENSE));
360
    blockdev_mark_auto_del(s->conf.bs);
361
}
362

    
363
static int scsi_generic_initfn(SCSIDevice *s)
364
{
365
    int sg_version;
366
    struct sg_scsi_id scsiid;
367

    
368
    if (!s->conf.bs) {
369
        error_report("scsi-generic: drive property not set");
370
        return -1;
371
    }
372

    
373
    /* check we are really using a /dev/sg* file */
374
    if (!bdrv_is_sg(s->conf.bs)) {
375
        error_report("scsi-generic: not /dev/sg*");
376
        return -1;
377
    }
378

    
379
    if (bdrv_get_on_error(s->conf.bs, 0) != BLOCK_ERR_STOP_ENOSPC) {
380
        error_report("Device doesn't support drive option werror");
381
        return -1;
382
    }
383
    if (bdrv_get_on_error(s->conf.bs, 1) != BLOCK_ERR_REPORT) {
384
        error_report("Device doesn't support drive option rerror");
385
        return -1;
386
    }
387

    
388
    /* check we are using a driver managing SG_IO (version 3 and after */
389
    if (bdrv_ioctl(s->conf.bs, SG_GET_VERSION_NUM, &sg_version) < 0 ||
390
        sg_version < 30000) {
391
        error_report("scsi-generic: scsi generic interface too old");
392
        return -1;
393
    }
394

    
395
    /* get LUN of the /dev/sg? */
396
    if (bdrv_ioctl(s->conf.bs, SG_GET_SCSI_ID, &scsiid)) {
397
        error_report("scsi-generic: SG_GET_SCSI_ID ioctl failed");
398
        return -1;
399
    }
400

    
401
    /* define device state */
402
    s->type = scsiid.scsi_type;
403
    DPRINTF("device type %d\n", s->type);
404
    if (s->type == TYPE_TAPE) {
405
        s->blocksize = get_stream_blocksize(s->conf.bs);
406
        if (s->blocksize == -1) {
407
            s->blocksize = 0;
408
        }
409
    } else {
410
        s->blocksize = get_blocksize(s->conf.bs);
411
        /* removable media returns 0 if not present */
412
        if (s->blocksize <= 0) {
413
            if (s->type == TYPE_ROM || s->type  == TYPE_WORM) {
414
                s->blocksize = 2048;
415
            } else {
416
                s->blocksize = 512;
417
            }
418
        }
419
    }
420

    
421
    DPRINTF("block size %d\n", s->blocksize);
422
    return 0;
423
}
424

    
425
static SCSIReqOps scsi_generic_req_ops = {
426
    .size         = sizeof(SCSIGenericReq),
427
    .free_req     = scsi_free_request,
428
    .send_command = scsi_send_command,
429
    .read_data    = scsi_read_data,
430
    .write_data   = scsi_write_data,
431
    .cancel_io    = scsi_cancel_io,
432
    .get_buf      = scsi_get_buf,
433
};
434

    
435
static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
436
                                     void *hba_private)
437
{
438
    SCSIRequest *req;
439

    
440
    req = scsi_req_alloc(&scsi_generic_req_ops, d, tag, lun, hba_private);
441
    return req;
442
}
443

    
444
static SCSIDeviceInfo scsi_generic_info = {
445
    .qdev.name    = "scsi-generic",
446
    .qdev.desc    = "pass through generic scsi device (/dev/sg*)",
447
    .qdev.size    = sizeof(SCSIDevice),
448
    .qdev.reset   = scsi_generic_reset,
449
    .init         = scsi_generic_initfn,
450
    .destroy      = scsi_destroy,
451
    .alloc_req    = scsi_new_request,
452
    .qdev.props   = (Property[]) {
453
        DEFINE_BLOCK_PROPERTIES(SCSIDevice, conf),
454
        DEFINE_PROP_END_OF_LIST(),
455
    },
456
};
457

    
458
static void scsi_generic_register_devices(void)
459
{
460
    scsi_qdev_register(&scsi_generic_info);
461
}
462
device_init(scsi_generic_register_devices)
463

    
464
#endif /* __linux__ */