scsi-generic.c 13.7 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/block-backend.h"
18
#include "sysemu/blockdev.h"
19

20
#ifdef __linux__
21 22 23 24

//#define DEBUG_SCSI

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

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

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

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

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

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

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

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

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

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

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

140
    scsi_req_complete(&r->req, status);
141
done:
142
    scsi_req_unref(&r->req);
143 144
}

145
static int execute_command(BlockBackend *blk,
146
                           SCSIGenericReq *r, int direction,
147
                           BlockCompletionFunc *complete)
148 149 150 151 152
{
    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;
153 154
    r->io_header.cmdp = r->req.cmd.buf;
    r->io_header.cmd_len = r->req.cmd.len;
155 156
    r->io_header.mx_sb_len = sizeof(r->req.sense);
    r->io_header.sbp = r->req.sense;
157 158 159 160
    r->io_header.timeout = MAX_UINT;
    r->io_header.usr_ptr = r;
    r->io_header.flags |= SG_FLAG_DIRECT_IO;

161
    r->req.aiocb = blk_aio_ioctl(blk, SG_IO, &r->io_header, complete, r);
162 163 164
    if (r->req.aiocb == NULL) {
        return -EIO;
    }
165 166 167 168 169 170

    return 0;
}

static void scsi_read_complete(void * opaque, int ret)
{
171
    SCSIGenericReq *r = (SCSIGenericReq *)opaque;
172
    SCSIDevice *s = r->req.dev;
173 174
    int len;

175
    r->req.aiocb = NULL;
176
    if (ret || r->req.io_canceled) {
177 178 179 180
        scsi_command_complete(r, ret);
        return;
    }
    len = r->io_header.dxfer_len - r->io_header.resid;
181
    DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, len);
182 183

    r->len = -1;
184
    if (len == 0) {
A
aurel32 已提交
185
        scsi_command_complete(r, 0);
186
    } else {
187
        /* Snoop READ CAPACITY output to set the blocksize.  */
188 189
        if (r->req.cmd.buf[0] == READ_CAPACITY_10 &&
            (ldl_be_p(&r->buf[0]) != 0xffffffffU || s->max_lba == 0)) {
190
            s->blocksize = ldl_be_p(&r->buf[4]);
191
            s->max_lba = ldl_be_p(&r->buf[0]) & 0xffffffffULL;
192 193 194
        } 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 已提交
195
            s->max_lba = ldq_be_p(&r->buf[0]);
196
        }
197
        blk_set_guest_block_size(s->conf.blk, s->blocksize);
198

P
Paolo Bonzini 已提交
199
        scsi_req_data(&r->req, len);
200
        scsi_req_unref(&r->req);
201
    }
202 203 204
}

/* Read more data from scsi device into buffer.  */
205
static void scsi_read_data(SCSIRequest *req)
206
{
207
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
208
    SCSIDevice *s = r->req.dev;
209 210
    int ret;

211
    DPRINTF("scsi_read_data 0x%x\n", req->tag);
212 213 214

    /* The request is used as the AIO opaque value, so add a ref.  */
    scsi_req_ref(&r->req);
215 216 217 218 219
    if (r->len == -1) {
        scsi_command_complete(r, 0);
        return;
    }

220 221
    ret = execute_command(s->conf.blk, r, SG_DXFER_FROM_DEV,
                          scsi_read_complete);
222 223
    if (ret < 0) {
        scsi_command_complete(r, ret);
224 225 226 227 228
    }
}

static void scsi_write_complete(void * opaque, int ret)
{
229
    SCSIGenericReq *r = (SCSIGenericReq *)opaque;
230
    SCSIDevice *s = r->req.dev;
231 232

    DPRINTF("scsi_write_complete() ret = %d\n", ret);
233
    r->req.aiocb = NULL;
234
    if (ret || r->req.io_canceled) {
235 236 237 238
        scsi_command_complete(r, ret);
        return;
    }

239
    if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 &&
240 241 242
        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 已提交
243 244
    }

245 246 247 248 249
    scsi_command_complete(r, ret);
}

/* Write data to a scsi device.  Returns nonzero on failure.
   The transfer may complete asynchronously.  */
250
static void scsi_write_data(SCSIRequest *req)
251
{
252
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
253
    SCSIDevice *s = r->req.dev;
254 255
    int ret;

256
    DPRINTF("scsi_write_data 0x%x\n", req->tag);
257 258
    if (r->len == 0) {
        r->len = r->buflen;
P
Paolo Bonzini 已提交
259
        scsi_req_data(&r->req, r->len);
260
        return;
261 262
    }

263 264
    /* The request is used as the AIO opaque value, so add a ref.  */
    scsi_req_ref(&r->req);
265
    ret = execute_command(s->conf.blk, r, SG_DXFER_TO_DEV, scsi_write_complete);
266 267
    if (ret < 0) {
        scsi_command_complete(r, ret);
268 269 270 271
    }
}

/* Return a pointer to the data buffer.  */
272
static uint8_t *scsi_get_buf(SCSIRequest *req)
273
{
274 275
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);

276 277 278 279 280 281 282 283
    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.  */

284
static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
285
{
286
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
287
    SCSIDevice *s = r->req.dev;
288 289
    int ret;

290 291 292 293 294 295 296 297 298
#ifdef DEBUG_SCSI
    {
        int i;
        for (i = 1; i < r->req.cmd.len; i++) {
            printf(" 0x%02x", cmd[i]);
        }
        printf("\n");
    }
#endif
299

300
    if (r->req.cmd.xfer == 0) {
301
        if (r->buf != NULL)
302
            g_free(r->buf);
303 304
        r->buflen = 0;
        r->buf = NULL;
305 306
        /* The request is used as the AIO opaque value, so add a ref.  */
        scsi_req_ref(&r->req);
307 308
        ret = execute_command(s->conf.blk, r, SG_DXFER_NONE,
                              scsi_command_complete);
309 310 311
        if (ret < 0) {
            scsi_command_complete(r, ret);
            return 0;
312 313 314 315
        }
        return 0;
    }

316
    if (r->buflen != r->req.cmd.xfer) {
317
        if (r->buf != NULL)
318 319
            g_free(r->buf);
        r->buf = g_malloc(r->req.cmd.xfer);
320
        r->buflen = r->req.cmd.xfer;
321 322 323
    }

    memset(r->buf, 0, r->buflen);
324
    r->len = r->req.cmd.xfer;
G
Gerd Hoffmann 已提交
325
    if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
326
        r->len = 0;
327
        return -r->req.cmd.xfer;
P
Paolo Bonzini 已提交
328
    } else {
329
        return r->req.cmd.xfer;
330 331 332
    }
}

333
static int get_stream_blocksize(BlockBackend *blk)
A
aurel32 已提交
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
{
    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 */

357
    ret = blk_ioctl(blk, SG_IO, &io_header);
358
    if (ret < 0 || io_header.driver_status || io_header.host_status) {
A
aurel32 已提交
359
        return -1;
360
    }
A
aurel32 已提交
361 362 363
    return (buf[9] << 16) | (buf[10] << 8) | buf[11];
}

364 365
static void scsi_generic_reset(DeviceState *dev)
{
366
    SCSIDevice *s = SCSI_DEVICE(dev);
367

368
    scsi_device_purge_requests(s, SENSE_CODE(RESET));
369 370
}

371
static void scsi_generic_realize(SCSIDevice *s, Error **errp)
372
{
373
    int rc;
374 375 376
    int sg_version;
    struct sg_scsi_id scsiid;

377
    if (!s->conf.blk) {
378 379
        error_setg(errp, "drive property not set");
        return;
380
    }
381

382
    if (blk_get_on_error(s->conf.blk, 0) != BLOCKDEV_ON_ERROR_ENOSPC) {
383 384
        error_setg(errp, "Device doesn't support drive option werror");
        return;
385
    }
386
    if (blk_get_on_error(s->conf.blk, 1) != BLOCKDEV_ON_ERROR_REPORT) {
387 388
        error_setg(errp, "Device doesn't support drive option rerror");
        return;
389 390
    }

391
    /* check we are using a driver managing SG_IO (version 3 and after */
392
    rc = blk_ioctl(s->conf.blk, SG_GET_VERSION_NUM, &sg_version);
393
    if (rc < 0) {
394 395 396 397
        error_setg(errp, "cannot get SG_IO version number: %s.  "
                         "Is this a SCSI device?",
                         strerror(-rc));
        return;
398 399
    }
    if (sg_version < 30000) {
400 401
        error_setg(errp, "scsi generic interface too old");
        return;
402
    }
403 404

    /* get LUN of the /dev/sg? */
405
    if (blk_ioctl(s->conf.blk, SG_GET_SCSI_ID, &scsiid)) {
406 407
        error_setg(errp, "SG_GET_SCSI_ID ioctl failed");
        return;
408
    }
409 410

    /* define device state */
411 412
    s->type = scsiid.scsi_type;
    DPRINTF("device type %d\n", s->type);
P
Paolo Bonzini 已提交
413

414 415
    switch (s->type) {
    case TYPE_TAPE:
416
        s->blocksize = get_stream_blocksize(s->conf.blk);
417 418 419
        if (s->blocksize == -1) {
            s->blocksize = 0;
        }
420 421 422 423 424 425 426 427 428 429 430 431 432
        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 已提交
433
    }
434 435

    DPRINTF("block size %d\n", s->blocksize);
436
}
437

P
Paolo Bonzini 已提交
438
const SCSIReqOps scsi_generic_req_ops = {
P
Paolo Bonzini 已提交
439
    .size         = sizeof(SCSIGenericReq),
440 441 442 443 444
    .free_req     = scsi_free_request,
    .send_command = scsi_send_command,
    .read_data    = scsi_read_data,
    .write_data   = scsi_write_data,
    .get_buf      = scsi_get_buf,
445 446
    .load_request = scsi_generic_load_request,
    .save_request = scsi_generic_save_request,
P
Paolo Bonzini 已提交
447 448 449
};

static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
P
Paolo Bonzini 已提交
450
                                     uint8_t *buf, void *hba_private)
P
Paolo Bonzini 已提交
451 452 453 454 455 456 457
{
    SCSIRequest *req;

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

458
static Property scsi_generic_properties[] = {
459
    DEFINE_PROP_DRIVE("drive", SCSIDevice, conf.blk),
460 461 462
    DEFINE_PROP_END_OF_LIST(),
};

463 464 465 466 467 468
static int scsi_generic_parse_cdb(SCSIDevice *dev, SCSICommand *cmd,
                                  uint8_t *buf, void *hba_private)
{
    return scsi_bus_parse_cdb(dev, cmd, buf, hba_private);
}

469 470
static void scsi_generic_class_initfn(ObjectClass *klass, void *data)
{
471
    DeviceClass *dc = DEVICE_CLASS(klass);
472 473
    SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);

474
    sc->realize      = scsi_generic_realize;
475
    sc->alloc_req    = scsi_new_request;
476
    sc->parse_cdb    = scsi_generic_parse_cdb;
477 478 479 480
    dc->fw_name = "disk";
    dc->desc = "pass through generic scsi device (/dev/sg*)";
    dc->reset = scsi_generic_reset;
    dc->props = scsi_generic_properties;
481
    dc->vmsd  = &vmstate_scsi_device;
482 483
}

484
static const TypeInfo scsi_generic_info = {
485 486 487 488
    .name          = "scsi-generic",
    .parent        = TYPE_SCSI_DEVICE,
    .instance_size = sizeof(SCSIDevice),
    .class_init    = scsi_generic_class_initfn,
489
};
490

A
Andreas Färber 已提交
491
static void scsi_generic_register_types(void)
492
{
493
    type_register_static(&scsi_generic_info);
494
}
A
Andreas Färber 已提交
495 496

type_init(scsi_generic_register_types)
497

498
#endif /* __linux__ */