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

P
Paolo Bonzini 已提交
40 41 42 43 44 45 46
#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
47 48 49 50 51

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

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

60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
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 已提交
82
static void scsi_free_request(SCSIRequest *req)
83
{
P
Paolo Bonzini 已提交
84 85
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);

86
    g_free(r->buf);
87 88 89 90 91
}

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

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

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

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

/* Cancel a pending data transfer.  */
142
static void scsi_cancel_io(SCSIRequest *req)
143
{
144 145 146 147 148
    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);
149 150 151 152 153

        /* 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);
154
    }
155
    r->req.aiocb = NULL;
156 157 158
}

static int execute_command(BlockDriverState *bdrv,
159
                           SCSIGenericReq *r, int direction,
160 161 162 163 164 165
			   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;
166 167
    r->io_header.cmdp = r->req.cmd.buf;
    r->io_header.cmd_len = r->req.cmd.len;
168 169
    r->io_header.mx_sb_len = sizeof(r->req.sense);
    r->io_header.sbp = r->req.sense;
170 171 172 173
    r->io_header.timeout = MAX_UINT;
    r->io_header.usr_ptr = r;
    r->io_header.flags |= SG_FLAG_DIRECT_IO;

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

    return 0;
}

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

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

    r->len = -1;
198
    if (len == 0) {
A
aurel32 已提交
199
        scsi_command_complete(r, 0);
200
    } else {
201
        /* Snoop READ CAPACITY output to set the blocksize.  */
202 203
        if (r->req.cmd.buf[0] == READ_CAPACITY_10 &&
            (ldl_be_p(&r->buf[0]) != 0xffffffffU || s->max_lba == 0)) {
204
            s->blocksize = ldl_be_p(&r->buf[4]);
205
            s->max_lba = ldl_be_p(&r->buf[0]) & 0xffffffffULL;
206 207 208
        } 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 已提交
209
            s->max_lba = ldq_be_p(&r->buf[0]);
210
        }
211
        bdrv_set_guest_block_size(s->conf.bs, s->blocksize);
212

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

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

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

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

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

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

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

255
    if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 &&
256 257 258
        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 已提交
259 260
    }

261 262 263 264 265
    scsi_command_complete(r, ret);
}

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

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

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

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

292 293 294 295 296 297 298 299
    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.  */

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

306 307 308 309 310 311 312 313 314 315 316 317
    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
318

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

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

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

A
aurel32 已提交
351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374
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 */

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

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

386
    scsi_device_purge_requests(s, SENSE_CODE(RESET));
387 388
}

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

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

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

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

415
    /* check we are using a driver managing SG_IO (version 3 and after */
416 417 418 419 420
    rc = bdrv_ioctl(s->conf.bs, SG_GET_VERSION_NUM, &sg_version);
    if (rc < 0) {
        error_report("cannot get SG_IO version number: %s.  "
                     "Is this a SCSI device?",
                     strerror(-rc));
421 422 423
        return -1;
    }
    if (sg_version < 30000) {
424
        error_report("scsi generic interface too old");
425 426
        return -1;
    }
427 428

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

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

441 442
    switch (s->type) {
    case TYPE_TAPE:
443 444 445 446
        s->blocksize = get_stream_blocksize(s->conf.bs);
        if (s->blocksize == -1) {
            s->blocksize = 0;
        }
447 448 449 450 451 452 453 454 455 456 457 458 459
        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 已提交
460
    }
461 462

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

P
Paolo Bonzini 已提交
466
const SCSIReqOps scsi_generic_req_ops = {
P
Paolo Bonzini 已提交
467
    .size         = sizeof(SCSIGenericReq),
468 469 470 471 472 473
    .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,
474 475
    .load_request = scsi_generic_load_request,
    .save_request = scsi_generic_save_request,
P
Paolo Bonzini 已提交
476 477 478
};

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

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

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

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

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

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

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

type_init(scsi_generic_register_types)
521

522
#endif /* __linux__ */