scsi-generic.c 13.9 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
}

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

95 96
    assert(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 146 147 148 149 150 151 152 153
static void scsi_command_complete(void *opaque, int ret)
{
    SCSIGenericReq *r = (SCSIGenericReq *)opaque;

    assert(r->req.aiocb != NULL);
    r->req.aiocb = NULL;
    scsi_command_complete_noio(r, ret);
}

154
static int execute_command(BlockBackend *blk,
155
                           SCSIGenericReq *r, int direction,
156
                           BlockCompletionFunc *complete)
157 158 159 160 161
{
    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;
162 163
    r->io_header.cmdp = r->req.cmd.buf;
    r->io_header.cmd_len = r->req.cmd.len;
164 165
    r->io_header.mx_sb_len = sizeof(r->req.sense);
    r->io_header.sbp = r->req.sense;
166 167 168 169
    r->io_header.timeout = MAX_UINT;
    r->io_header.usr_ptr = r;
    r->io_header.flags |= SG_FLAG_DIRECT_IO;

170
    r->req.aiocb = blk_aio_ioctl(blk, SG_IO, &r->io_header, complete, r);
171 172 173
    if (r->req.aiocb == NULL) {
        return -EIO;
    }
174 175 176 177 178 179

    return 0;
}

static void scsi_read_complete(void * opaque, int ret)
{
180
    SCSIGenericReq *r = (SCSIGenericReq *)opaque;
181
    SCSIDevice *s = r->req.dev;
182 183
    int len;

184
    assert(r->req.aiocb != NULL);
185
    r->req.aiocb = NULL;
186

187
    if (ret || r->req.io_canceled) {
188
        scsi_command_complete_noio(r, ret);
189 190
        return;
    }
191

192
    len = r->io_header.dxfer_len - r->io_header.resid;
193
    DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, len);
194 195

    r->len = -1;
196
    if (len == 0) {
197 198 199
        scsi_command_complete_noio(r, 0);
        return;
    }
200

201 202 203 204 205 206 207 208 209
    /* Snoop READ CAPACITY output to set the blocksize.  */
    if (r->req.cmd.buf[0] == READ_CAPACITY_10 &&
        (ldl_be_p(&r->buf[0]) != 0xffffffffU || s->max_lba == 0)) {
        s->blocksize = ldl_be_p(&r->buf[4]);
        s->max_lba = ldl_be_p(&r->buf[0]) & 0xffffffffULL;
    } 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]);
        s->max_lba = ldq_be_p(&r->buf[0]);
210
    }
211 212 213 214
    blk_set_guest_block_size(s->conf.blk, s->blocksize);

    scsi_req_data(&r->req, len);
    scsi_req_unref(&r->req);
215 216 217
}

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

224
    DPRINTF("scsi_read_data 0x%x\n", req->tag);
225 226 227

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

233 234
    ret = execute_command(s->conf.blk, r, SG_DXFER_FROM_DEV,
                          scsi_read_complete);
235
    if (ret < 0) {
236
        scsi_command_complete_noio(r, ret);
237 238 239 240 241
    }
}

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

    DPRINTF("scsi_write_complete() ret = %d\n", ret);
246 247

    assert(r->req.aiocb != NULL);
248
    r->req.aiocb = NULL;
249

250
    if (ret || r->req.io_canceled) {
251
        scsi_command_complete_noio(r, ret);
252 253 254
        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
    scsi_command_complete_noio(r, ret);
262 263 264 265
}

/* 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.blk, r, SG_DXFER_TO_DEV, scsi_write_complete);
282
    if (ret < 0) {
283
        scsi_command_complete_noio(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
#ifdef DEBUG_SCSI
    {
        int i;
        for (i = 1; i < r->req.cmd.len; i++) {
            printf(" 0x%02x", cmd[i]);
        }
        printf("\n");
    }
#endif
315

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

331
    if (r->buflen != r->req.cmd.xfer) {
332
        g_free(r->buf);
333
        r->buf = g_malloc(r->req.cmd.xfer);
334
        r->buflen = r->req.cmd.xfer;
335 336 337
    }

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

347
static int get_stream_blocksize(BlockBackend *blk)
A
aurel32 已提交
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
{
    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 */

371
    ret = blk_ioctl(blk, SG_IO, &io_header);
372
    if (ret < 0 || io_header.driver_status || io_header.host_status) {
A
aurel32 已提交
373
        return -1;
374
    }
A
aurel32 已提交
375 376 377
    return (buf[9] << 16) | (buf[10] << 8) | buf[11];
}

378 379
static void scsi_generic_reset(DeviceState *dev)
{
380
    SCSIDevice *s = SCSI_DEVICE(dev);
381

382
    scsi_device_purge_requests(s, SENSE_CODE(RESET));
383 384
}

385
static void scsi_generic_realize(SCSIDevice *s, Error **errp)
386
{
387
    int rc;
388 389 390
    int sg_version;
    struct sg_scsi_id scsiid;

391
    if (!s->conf.blk) {
392 393
        error_setg(errp, "drive property not set");
        return;
394
    }
395

396
    if (blk_get_on_error(s->conf.blk, 0) != BLOCKDEV_ON_ERROR_ENOSPC) {
397 398
        error_setg(errp, "Device doesn't support drive option werror");
        return;
399
    }
400
    if (blk_get_on_error(s->conf.blk, 1) != BLOCKDEV_ON_ERROR_REPORT) {
401 402
        error_setg(errp, "Device doesn't support drive option rerror");
        return;
403 404
    }

405
    /* check we are using a driver managing SG_IO (version 3 and after */
406
    rc = blk_ioctl(s->conf.blk, SG_GET_VERSION_NUM, &sg_version);
407
    if (rc < 0) {
408 409 410 411
        error_setg(errp, "cannot get SG_IO version number: %s.  "
                         "Is this a SCSI device?",
                         strerror(-rc));
        return;
412 413
    }
    if (sg_version < 30000) {
414 415
        error_setg(errp, "scsi generic interface too old");
        return;
416
    }
417 418

    /* get LUN of the /dev/sg? */
419
    if (blk_ioctl(s->conf.blk, SG_GET_SCSI_ID, &scsiid)) {
420 421
        error_setg(errp, "SG_GET_SCSI_ID ioctl failed");
        return;
422
    }
423 424

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

428 429
    switch (s->type) {
    case TYPE_TAPE:
430
        s->blocksize = get_stream_blocksize(s->conf.blk);
431 432 433
        if (s->blocksize == -1) {
            s->blocksize = 0;
        }
434 435 436 437 438 439 440 441 442 443 444 445 446
        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 已提交
447
    }
448 449

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

P
Paolo Bonzini 已提交
452
const SCSIReqOps scsi_generic_req_ops = {
P
Paolo Bonzini 已提交
453
    .size         = sizeof(SCSIGenericReq),
454 455 456 457 458
    .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,
459 460
    .load_request = scsi_generic_load_request,
    .save_request = scsi_generic_save_request,
P
Paolo Bonzini 已提交
461 462 463
};

static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
P
Paolo Bonzini 已提交
464
                                     uint8_t *buf, void *hba_private)
P
Paolo Bonzini 已提交
465 466 467 468 469 470 471
{
    SCSIRequest *req;

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

472
static Property scsi_generic_properties[] = {
473
    DEFINE_PROP_DRIVE("drive", SCSIDevice, conf.blk),
474 475 476
    DEFINE_PROP_END_OF_LIST(),
};

477 478 479 480 481 482
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);
}

483 484
static void scsi_generic_class_initfn(ObjectClass *klass, void *data)
{
485
    DeviceClass *dc = DEVICE_CLASS(klass);
486 487
    SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);

488
    sc->realize      = scsi_generic_realize;
489
    sc->alloc_req    = scsi_new_request;
490
    sc->parse_cdb    = scsi_generic_parse_cdb;
491 492 493 494
    dc->fw_name = "disk";
    dc->desc = "pass through generic scsi device (/dev/sg*)";
    dc->reset = scsi_generic_reset;
    dc->props = scsi_generic_properties;
495
    dc->vmsd  = &vmstate_scsi_device;
496 497
}

498
static const TypeInfo scsi_generic_info = {
499 500 501 502
    .name          = "scsi-generic",
    .parent        = TYPE_SCSI_DEVICE,
    .instance_size = sizeof(SCSIDevice),
    .class_init    = scsi_generic_class_initfn,
503
};
504

A
Andreas Färber 已提交
505
static void scsi_generic_register_types(void)
506
{
507
    type_register_static(&scsi_generic_info);
508
}
A
Andreas Färber 已提交
509 510

type_init(scsi_generic_register_types)
511

512
#endif /* __linux__ */