scsi-generic.c 14.3 KB
Newer Older
1 2 3 4 5 6 7 8 9
/*
 * Generic SCSI Device support
 *
 * Copyright (c) 2007 Bull S.A.S.
 * Based on code by Paul Brook
 * Based on code by Fabrice Bellard
 *
 * Written by Laurent Vivier <Laurent.Vivier@bull.net>
 *
M
Matthew Fernandez 已提交
10
 * This code is licensed under the LGPL.
11 12 13 14
 *
 */

#include "qemu-common.h"
15
#include "qemu/error-report.h"
P
Paolo Bonzini 已提交
16
#include "hw/scsi/scsi.h"
17
#include "sysemu/blockdev.h"
18

19
#ifdef __linux__
20 21 22 23

//#define DEBUG_SCSI

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

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

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <scsi/sg.h>
P
Paolo Bonzini 已提交
38
#include "block/scsi.h"
39

40
#define SCSI_SENSE_BUF_SIZE 96
41

P
Paolo Bonzini 已提交
42 43 44 45 46 47 48
#define SG_ERR_DRIVER_TIMEOUT  0x06
#define SG_ERR_DRIVER_SENSE    0x08

#define SG_ERR_DID_OK          0x00
#define SG_ERR_DID_NO_CONNECT  0x01
#define SG_ERR_DID_BUS_BUSY    0x02
#define SG_ERR_DID_TIME_OUT    0x03
49 50 51 52 53

#ifndef MAX_UINT
#define MAX_UINT ((unsigned int)-1)
#endif

54 55
typedef struct SCSIGenericReq {
    SCSIRequest req;
56 57 58 59
    uint8_t *buf;
    int buflen;
    int len;
    sg_io_hdr_t io_header;
60
} SCSIGenericReq;
61

62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
static void scsi_generic_save_request(QEMUFile *f, SCSIRequest *req)
{
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);

    qemu_put_sbe32s(f, &r->buflen);
    if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) {
        assert(!r->req.sg);
        qemu_put_buffer(f, r->buf, r->req.cmd.xfer);
    }
}

static void scsi_generic_load_request(QEMUFile *f, SCSIRequest *req)
{
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);

    qemu_get_sbe32s(f, &r->buflen);
    if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) {
        assert(!r->req.sg);
        qemu_get_buffer(f, r->buf, r->req.cmd.xfer);
    }
}

P
Paolo Bonzini 已提交
84
static void scsi_free_request(SCSIRequest *req)
85
{
P
Paolo Bonzini 已提交
86 87
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);

88
    g_free(r->buf);
89 90 91 92 93
}

/* Helper function for command completion.  */
static void scsi_command_complete(void *opaque, int ret)
{
94
    int status;
95
    SCSIGenericReq *r = (SCSIGenericReq *)opaque;
96

97
    r->req.aiocb = NULL;
P
Paolo Bonzini 已提交
98
    if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
99
        r->req.sense_len = r->io_header.sb_len_wr;
P
Paolo Bonzini 已提交
100
    }
A
aurel32 已提交
101

102 103
    if (ret != 0) {
        switch (ret) {
P
Paolo Bonzini 已提交
104
        case -EDOM:
105
            status = TASK_SET_FULL;
P
Paolo Bonzini 已提交
106
            break;
107
        case -ENOMEM:
108
            status = CHECK_CONDITION;
109
            scsi_req_build_sense(&r->req, SENSE_CODE(TARGET_FAILURE));
110 111
            break;
        default:
112
            status = CHECK_CONDITION;
113
            scsi_req_build_sense(&r->req, SENSE_CODE(IO_ERROR));
114 115 116
            break;
        }
    } else {
P
Paolo Bonzini 已提交
117 118 119 120
        if (r->io_header.host_status == SG_ERR_DID_NO_CONNECT ||
            r->io_header.host_status == SG_ERR_DID_BUS_BUSY ||
            r->io_header.host_status == SG_ERR_DID_TIME_OUT ||
            (r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT)) {
121
            status = BUSY;
122
            BADF("Driver Timeout\n");
P
Paolo Bonzini 已提交
123 124 125
        } else if (r->io_header.host_status) {
            status = CHECK_CONDITION;
            scsi_req_build_sense(&r->req, SENSE_CODE(I_T_NEXUS_LOSS));
126 127
        } else if (r->io_header.status) {
            status = r->io_header.status;
128
        } else if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
129 130 131 132
            status = CHECK_CONDITION;
        } else {
            status = GOOD;
        }
133
    }
A
aurel32 已提交
134
    DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
135
            r, r->req.tag, status);
G
Gerd Hoffmann 已提交
136

137
    scsi_req_complete(&r->req, status);
138 139 140
    if (!r->req.io_canceled) {
        scsi_req_unref(&r->req);
    }
141 142 143
}

/* Cancel a pending data transfer.  */
144
static void scsi_cancel_io(SCSIRequest *req)
145
{
146 147 148 149 150
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);

    DPRINTF("Cancel tag=0x%x\n", req->tag);
    if (r->req.aiocb) {
        bdrv_aio_cancel(r->req.aiocb);
151 152 153 154 155

        /* This reference was left in by scsi_*_data.  We take ownership of
         * it independent of whether bdrv_aio_cancel completes the request
         * or not.  */
        scsi_req_unref(&r->req);
156
    }
157
    r->req.aiocb = NULL;
158 159 160
}

static int execute_command(BlockDriverState *bdrv,
161
                           SCSIGenericReq *r, int direction,
162 163 164 165 166 167
			   BlockDriverCompletionFunc *complete)
{
    r->io_header.interface_id = 'S';
    r->io_header.dxfer_direction = direction;
    r->io_header.dxferp = r->buf;
    r->io_header.dxfer_len = r->buflen;
168 169
    r->io_header.cmdp = r->req.cmd.buf;
    r->io_header.cmd_len = r->req.cmd.len;
170 171
    r->io_header.mx_sb_len = sizeof(r->req.sense);
    r->io_header.sbp = r->req.sense;
172 173 174 175
    r->io_header.timeout = MAX_UINT;
    r->io_header.usr_ptr = r;
    r->io_header.flags |= SG_FLAG_DIRECT_IO;

176
    r->req.aiocb = bdrv_aio_ioctl(bdrv, SG_IO, &r->io_header, complete, r);
177 178 179
    if (r->req.aiocb == NULL) {
        return -EIO;
    }
180 181 182 183 184 185

    return 0;
}

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

190
    r->req.aiocb = NULL;
191
    if (ret) {
192
        DPRINTF("IO error ret %d\n", ret);
193 194 195 196
        scsi_command_complete(r, ret);
        return;
    }
    len = r->io_header.dxfer_len - r->io_header.resid;
197
    DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, len);
198 199

    r->len = -1;
200
    if (len == 0) {
A
aurel32 已提交
201
        scsi_command_complete(r, 0);
202
    } else {
203
        /* Snoop READ CAPACITY output to set the blocksize.  */
204 205
        if (r->req.cmd.buf[0] == READ_CAPACITY_10 &&
            (ldl_be_p(&r->buf[0]) != 0xffffffffU || s->max_lba == 0)) {
206
            s->blocksize = ldl_be_p(&r->buf[4]);
207
            s->max_lba = ldl_be_p(&r->buf[0]) & 0xffffffffULL;
208 209 210
        } else if (r->req.cmd.buf[0] == SERVICE_ACTION_IN_16 &&
                   (r->req.cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) {
            s->blocksize = ldl_be_p(&r->buf[8]);
P
Paolo Bonzini 已提交
211
            s->max_lba = ldq_be_p(&r->buf[0]);
212 213 214
        }
        bdrv_set_buffer_alignment(s->conf.bs, s->blocksize);

P
Paolo Bonzini 已提交
215
        scsi_req_data(&r->req, len);
216 217 218
        if (!r->req.io_canceled) {
            scsi_req_unref(&r->req);
        }
219
    }
220 221 222
}

/* Read more data from scsi device into buffer.  */
223
static void scsi_read_data(SCSIRequest *req)
224
{
225
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
226
    SCSIDevice *s = r->req.dev;
227 228
    int ret;

229
    DPRINTF("scsi_read_data 0x%x\n", req->tag);
230 231 232

    /* The request is used as the AIO opaque value, so add a ref.  */
    scsi_req_ref(&r->req);
233 234 235 236 237
    if (r->len == -1) {
        scsi_command_complete(r, 0);
        return;
    }

238
    ret = execute_command(s->conf.bs, r, SG_DXFER_FROM_DEV, scsi_read_complete);
239 240
    if (ret < 0) {
        scsi_command_complete(r, ret);
241 242 243 244 245
    }
}

static void scsi_write_complete(void * opaque, int ret)
{
246
    SCSIGenericReq *r = (SCSIGenericReq *)opaque;
247
    SCSIDevice *s = r->req.dev;
248 249

    DPRINTF("scsi_write_complete() ret = %d\n", ret);
250
    r->req.aiocb = NULL;
251 252 253 254 255 256
    if (ret) {
        DPRINTF("IO error\n");
        scsi_command_complete(r, ret);
        return;
    }

257
    if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 &&
258 259 260
        s->type == TYPE_TAPE) {
        s->blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
        DPRINTF("block size %d\n", s->blocksize);
A
aurel32 已提交
261 262
    }

263 264 265 266 267
    scsi_command_complete(r, ret);
}

/* Write data to a scsi device.  Returns nonzero on failure.
   The transfer may complete asynchronously.  */
268
static void scsi_write_data(SCSIRequest *req)
269
{
270
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
271
    SCSIDevice *s = r->req.dev;
272 273
    int ret;

274
    DPRINTF("scsi_write_data 0x%x\n", req->tag);
275 276
    if (r->len == 0) {
        r->len = r->buflen;
P
Paolo Bonzini 已提交
277
        scsi_req_data(&r->req, r->len);
278
        return;
279 280
    }

281 282
    /* The request is used as the AIO opaque value, so add a ref.  */
    scsi_req_ref(&r->req);
283
    ret = execute_command(s->conf.bs, r, SG_DXFER_TO_DEV, scsi_write_complete);
284 285
    if (ret < 0) {
        scsi_command_complete(r, ret);
286 287 288 289
    }
}

/* Return a pointer to the data buffer.  */
290
static uint8_t *scsi_get_buf(SCSIRequest *req)
291
{
292 293
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);

294 295 296 297 298 299 300 301
    return r->buf;
}

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

302
static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
303
{
304
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
305
    SCSIDevice *s = r->req.dev;
306 307
    int ret;

308 309 310 311 312 313 314 315 316 317 318 319
    DPRINTF("Command: lun=%d tag=0x%x len %zd data=0x%02x", lun, tag,
            r->req.cmd.xfer, cmd[0]);

#ifdef DEBUG_SCSI
    {
        int i;
        for (i = 1; i < r->req.cmd.len; i++) {
            printf(" 0x%02x", cmd[i]);
        }
        printf("\n");
    }
#endif
320

321
    if (r->req.cmd.xfer == 0) {
322
        if (r->buf != NULL)
323
            g_free(r->buf);
324 325
        r->buflen = 0;
        r->buf = NULL;
326 327
        /* The request is used as the AIO opaque value, so add a ref.  */
        scsi_req_ref(&r->req);
328
        ret = execute_command(s->conf.bs, r, SG_DXFER_NONE, scsi_command_complete);
329 330 331
        if (ret < 0) {
            scsi_command_complete(r, ret);
            return 0;
332 333 334 335
        }
        return 0;
    }

336
    if (r->buflen != r->req.cmd.xfer) {
337
        if (r->buf != NULL)
338 339
            g_free(r->buf);
        r->buf = g_malloc(r->req.cmd.xfer);
340
        r->buflen = r->req.cmd.xfer;
341 342 343
    }

    memset(r->buf, 0, r->buflen);
344
    r->len = r->req.cmd.xfer;
G
Gerd Hoffmann 已提交
345
    if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
346
        r->len = 0;
347
        return -r->req.cmd.xfer;
P
Paolo Bonzini 已提交
348
    } else {
349
        return r->req.cmd.xfer;
350 351 352
    }
}

A
aurel32 已提交
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376
static int get_stream_blocksize(BlockDriverState *bdrv)
{
    uint8_t cmd[6];
    uint8_t buf[12];
    uint8_t sensebuf[8];
    sg_io_hdr_t io_header;
    int ret;

    memset(cmd, 0, sizeof(cmd));
    memset(buf, 0, sizeof(buf));
    cmd[0] = MODE_SENSE;
    cmd[4] = sizeof(buf);

    memset(&io_header, 0, sizeof(io_header));
    io_header.interface_id = 'S';
    io_header.dxfer_direction = SG_DXFER_FROM_DEV;
    io_header.dxfer_len = sizeof(buf);
    io_header.dxferp = buf;
    io_header.cmdp = cmd;
    io_header.cmd_len = sizeof(cmd);
    io_header.mx_sb_len = sizeof(sensebuf);
    io_header.sbp = sensebuf;
    io_header.timeout = 6000; /* XXX */

377
    ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
378
    if (ret < 0 || io_header.driver_status || io_header.host_status) {
A
aurel32 已提交
379
        return -1;
380
    }
A
aurel32 已提交
381 382 383
    return (buf[9] << 16) | (buf[10] << 8) | buf[11];
}

384 385
static void scsi_generic_reset(DeviceState *dev)
{
386
    SCSIDevice *s = SCSI_DEVICE(dev);
387

388
    scsi_device_purge_requests(s, SENSE_CODE(RESET));
389 390
}

391
static void scsi_destroy(SCSIDevice *s)
392
{
393 394
    scsi_device_purge_requests(s, SENSE_CODE(NO_SENSE));
    blockdev_mark_auto_del(s->conf.bs);
395 396
}

397
static int scsi_generic_initfn(SCSIDevice *s)
398 399 400 401
{
    int sg_version;
    struct sg_scsi_id scsiid;

402
    if (!s->conf.bs) {
403
        error_report("drive property not set");
404 405
        return -1;
    }
406

407
    if (bdrv_get_on_error(s->conf.bs, 0) != BLOCKDEV_ON_ERROR_ENOSPC) {
408 409 410
        error_report("Device doesn't support drive option werror");
        return -1;
    }
411
    if (bdrv_get_on_error(s->conf.bs, 1) != BLOCKDEV_ON_ERROR_REPORT) {
412 413 414 415
        error_report("Device doesn't support drive option rerror");
        return -1;
    }

416
    /* check we are using a driver managing SG_IO (version 3 and after */
417 418 419 420 421
    if (bdrv_ioctl(s->conf.bs, SG_GET_VERSION_NUM, &sg_version) < 0) {
        error_report("scsi generic interface not supported");
        return -1;
    }
    if (sg_version < 30000) {
422
        error_report("scsi generic interface too old");
423 424
        return -1;
    }
425 426

    /* get LUN of the /dev/sg? */
427
    if (bdrv_ioctl(s->conf.bs, SG_GET_SCSI_ID, &scsiid)) {
428
        error_report("SG_GET_SCSI_ID ioctl failed");
429 430
        return -1;
    }
431 432

    /* define device state */
433 434
    s->type = scsiid.scsi_type;
    DPRINTF("device type %d\n", s->type);
P
Paolo Bonzini 已提交
435 436 437 438
    if (s->type == TYPE_DISK || s->type == TYPE_ROM) {
        add_boot_device_path(s->conf.bootindex, &s->qdev, NULL);
    }

439 440
    switch (s->type) {
    case TYPE_TAPE:
441 442 443 444
        s->blocksize = get_stream_blocksize(s->conf.bs);
        if (s->blocksize == -1) {
            s->blocksize = 0;
        }
445 446 447 448 449 450 451 452 453 454 455 456 457
        break;

        /* Make a guess for block devices, we'll fix it when the guest sends.
         * READ CAPACITY.  If they don't, they likely would assume these sizes
         * anyway. (TODO: they could also send MODE SENSE).
         */
    case TYPE_ROM:
    case TYPE_WORM:
        s->blocksize = 2048;
        break;
    default:
        s->blocksize = 512;
        break;
A
aurel32 已提交
458
    }
459 460

    DPRINTF("block size %d\n", s->blocksize);
461 462
    return 0;
}
463

P
Paolo Bonzini 已提交
464
const SCSIReqOps scsi_generic_req_ops = {
P
Paolo Bonzini 已提交
465
    .size         = sizeof(SCSIGenericReq),
466 467 468 469 470 471
    .free_req     = scsi_free_request,
    .send_command = scsi_send_command,
    .read_data    = scsi_read_data,
    .write_data   = scsi_write_data,
    .cancel_io    = scsi_cancel_io,
    .get_buf      = scsi_get_buf,
472 473
    .load_request = scsi_generic_load_request,
    .save_request = scsi_generic_save_request,
P
Paolo Bonzini 已提交
474 475 476
};

static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
P
Paolo Bonzini 已提交
477
                                     uint8_t *buf, void *hba_private)
P
Paolo Bonzini 已提交
478 479 480 481 482 483 484
{
    SCSIRequest *req;

    req = scsi_req_alloc(&scsi_generic_req_ops, d, tag, lun, hba_private);
    return req;
}

485
static Property scsi_generic_properties[] = {
486 487
    DEFINE_PROP_DRIVE("drive", SCSIDevice, conf.bs),
    DEFINE_PROP_INT32("bootindex", SCSIDevice, conf.bootindex, -1),
488 489 490
    DEFINE_PROP_END_OF_LIST(),
};

491 492
static void scsi_generic_class_initfn(ObjectClass *klass, void *data)
{
493
    DeviceClass *dc = DEVICE_CLASS(klass);
494 495 496 497 498
    SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);

    sc->init         = scsi_generic_initfn;
    sc->destroy      = scsi_destroy;
    sc->alloc_req    = scsi_new_request;
499 500 501 502
    dc->fw_name = "disk";
    dc->desc = "pass through generic scsi device (/dev/sg*)";
    dc->reset = scsi_generic_reset;
    dc->props = scsi_generic_properties;
503
    dc->vmsd  = &vmstate_scsi_device;
504 505
}

506
static const TypeInfo scsi_generic_info = {
507 508 509 510
    .name          = "scsi-generic",
    .parent        = TYPE_SCSI_DEVICE,
    .instance_size = sizeof(SCSIDevice),
    .class_init    = scsi_generic_class_initfn,
511
};
512

A
Andreas Färber 已提交
513
static void scsi_generic_register_types(void)
514
{
515
    type_register_static(&scsi_generic_info);
516
}
A
Andreas Färber 已提交
517 518

type_init(scsi_generic_register_types)
519

520
#endif /* __linux__ */