~ubuntu-branches/ubuntu/saucy/qemu/saucy-proposed

« back to all changes in this revision

Viewing changes to hw/scsi/scsi-generic.c

  • Committer: Package Import Robot
  • Author(s): Serge Hallyn
  • Date: 2013-05-28 08:18:30 UTC
  • mfrom: (1.8.2) (10.1.37 sid)
  • Revision ID: package-import@ubuntu.com-20130528081830-87xl2z9fq516a814
Tags: 1.5.0+dfsg-2ubuntu1
* Merge 1.5.0+dfs-2 from debian unstable.  Remaining changes:
  - debian/control
    * update maintainer
    * remove libiscsi, usb-redir, vde, vnc-jpeg, and libssh2-1-dev
      from build-deps
    * enable rbd
    * add qemu-system and qemu-common B/R to qemu-keymaps
    * add D:udev, R:qemu, R:qemu-common and B:qemu-common to
      qemu-system-common
    * qemu-system-arm, qemu-system-ppc, qemu-system-sparc:
      - add qemu-kvm to Provides
      - add qemu-common, qemu-kvm, kvm to B/R
      - remove openbios-sparc from qemu-system-sparc D
    * qemu-system-x86:
      - add qemu-common to Breaks/Replaces.
      - add cpu-checker to Recommends.
    * qemu-user: add B/R:qemu-kvm
    * qemu-kvm:
      - add armhf armel powerpc sparc to Architecture
      - C/R/P: qemu-kvm-spice
    * add qemu-common package
    * drop qemu-slof which is not packaged in ubuntu
  - add qemu-system-common.links for tap ifup/down scripts and OVMF link.
  - qemu-system-x86.links:
    * remove pxe rom links which are in kvm-ipxe
    * add symlink for kvm.1 manpage
  - debian/rules
    * add kvm-spice symlink to qemu-kvm
    * call dh_installmodules for qemu-system-x86
    * update dh_installinit to install upstart script
    * run dh_installman (Closes: #709241) (cherrypicked from 1.5.0+dfsg-2)
  - Add qemu-utils.links for kvm-* symlinks.
  - Add qemu-system-x86.qemu-kvm.upstart and .default
  - Add qemu-system-x86.modprobe to set nesting=1
  - Add qemu-system-common.preinst to add kvm group
  - qemu-system-common.postinst: remove bad group acl if there, then have
    udev relabel /dev/kvm.
  - Dropped patches:
    * 0001-fix-wrong-output-with-info-chardev-for-tcp-socket.patch
  - Kept patches:
    * expose_vms_qemu64cpu.patch - updated
    * gridcentric patch - updated
    * linaro arm patches from qemu-linaro rebasing branch

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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-report.h"
 
16
#include "hw/scsi/scsi.h"
 
17
#include "sysemu/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 "block/scsi.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
#define SG_ERR_DID_OK          0x00
 
46
#define SG_ERR_DID_NO_CONNECT  0x01
 
47
#define SG_ERR_DID_BUS_BUSY    0x02
 
48
#define SG_ERR_DID_TIME_OUT    0x03
 
49
 
 
50
#ifndef MAX_UINT
 
51
#define MAX_UINT ((unsigned int)-1)
 
52
#endif
 
53
 
 
54
typedef struct SCSIGenericReq {
 
55
    SCSIRequest req;
 
56
    uint8_t *buf;
 
57
    int buflen;
 
58
    int len;
 
59
    sg_io_hdr_t io_header;
 
60
} SCSIGenericReq;
 
61
 
 
62
static void scsi_generic_save_request(QEMUFile *f, SCSIRequest *req)
 
63
{
 
64
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
 
65
 
 
66
    qemu_put_sbe32s(f, &r->buflen);
 
67
    if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) {
 
68
        assert(!r->req.sg);
 
69
        qemu_put_buffer(f, r->buf, r->req.cmd.xfer);
 
70
    }
 
71
}
 
72
 
 
73
static void scsi_generic_load_request(QEMUFile *f, SCSIRequest *req)
 
74
{
 
75
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
 
76
 
 
77
    qemu_get_sbe32s(f, &r->buflen);
 
78
    if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) {
 
79
        assert(!r->req.sg);
 
80
        qemu_get_buffer(f, r->buf, r->req.cmd.xfer);
 
81
    }
 
82
}
 
83
 
 
84
static void scsi_free_request(SCSIRequest *req)
 
85
{
 
86
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
 
87
 
 
88
    g_free(r->buf);
 
89
}
 
90
 
 
91
/* Helper function for command completion.  */
 
92
static void scsi_command_complete(void *opaque, int ret)
 
93
{
 
94
    int status;
 
95
    SCSIGenericReq *r = (SCSIGenericReq *)opaque;
 
96
 
 
97
    r->req.aiocb = NULL;
 
98
    if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
 
99
        r->req.sense_len = r->io_header.sb_len_wr;
 
100
    }
 
101
 
 
102
    if (ret != 0) {
 
103
        switch (ret) {
 
104
        case -EDOM:
 
105
            status = TASK_SET_FULL;
 
106
            break;
 
107
        case -ENOMEM:
 
108
            status = CHECK_CONDITION;
 
109
            scsi_req_build_sense(&r->req, SENSE_CODE(TARGET_FAILURE));
 
110
            break;
 
111
        default:
 
112
            status = CHECK_CONDITION;
 
113
            scsi_req_build_sense(&r->req, SENSE_CODE(IO_ERROR));
 
114
            break;
 
115
        }
 
116
    } else {
 
117
        if (r->io_header.host_status == SG_ERR_DID_NO_CONNECT ||
 
118
            r->io_header.host_status == SG_ERR_DID_BUS_BUSY ||
 
119
            r->io_header.host_status == SG_ERR_DID_TIME_OUT ||
 
120
            (r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT)) {
 
121
            status = BUSY;
 
122
            BADF("Driver Timeout\n");
 
123
        } else if (r->io_header.host_status) {
 
124
            status = CHECK_CONDITION;
 
125
            scsi_req_build_sense(&r->req, SENSE_CODE(I_T_NEXUS_LOSS));
 
126
        } else if (r->io_header.status) {
 
127
            status = r->io_header.status;
 
128
        } else if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
 
129
            status = CHECK_CONDITION;
 
130
        } else {
 
131
            status = GOOD;
 
132
        }
 
133
    }
 
134
    DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
 
135
            r, r->req.tag, status);
 
136
 
 
137
    scsi_req_complete(&r->req, status);
 
138
    if (!r->req.io_canceled) {
 
139
        scsi_req_unref(&r->req);
 
140
    }
 
141
}
 
142
 
 
143
/* Cancel a pending data transfer.  */
 
144
static void scsi_cancel_io(SCSIRequest *req)
 
145
{
 
146
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
 
147
 
 
148
    DPRINTF("Cancel tag=0x%x\n", req->tag);
 
149
    if (r->req.aiocb) {
 
150
        bdrv_aio_cancel(r->req.aiocb);
 
151
 
 
152
        /* This reference was left in by scsi_*_data.  We take ownership of
 
153
         * it independent of whether bdrv_aio_cancel completes the request
 
154
         * or not.  */
 
155
        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
                           BlockDriverCompletionFunc *complete)
 
163
{
 
164
    r->io_header.interface_id = 'S';
 
165
    r->io_header.dxfer_direction = direction;
 
166
    r->io_header.dxferp = r->buf;
 
167
    r->io_header.dxfer_len = r->buflen;
 
168
    r->io_header.cmdp = r->req.cmd.buf;
 
169
    r->io_header.cmd_len = r->req.cmd.len;
 
170
    r->io_header.mx_sb_len = sizeof(r->req.sense);
 
171
    r->io_header.sbp = r->req.sense;
 
172
    r->io_header.timeout = MAX_UINT;
 
173
    r->io_header.usr_ptr = r;
 
174
    r->io_header.flags |= SG_FLAG_DIRECT_IO;
 
175
 
 
176
    r->req.aiocb = bdrv_aio_ioctl(bdrv, SG_IO, &r->io_header, complete, r);
 
177
 
 
178
    return 0;
 
179
}
 
180
 
 
181
static void scsi_read_complete(void * opaque, int ret)
 
182
{
 
183
    SCSIGenericReq *r = (SCSIGenericReq *)opaque;
 
184
    SCSIDevice *s = r->req.dev;
 
185
    int len;
 
186
 
 
187
    r->req.aiocb = NULL;
 
188
    if (ret) {
 
189
        DPRINTF("IO error ret %d\n", ret);
 
190
        scsi_command_complete(r, ret);
 
191
        return;
 
192
    }
 
193
    len = r->io_header.dxfer_len - r->io_header.resid;
 
194
    DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, len);
 
195
 
 
196
    r->len = -1;
 
197
    if (len == 0) {
 
198
        scsi_command_complete(r, 0);
 
199
    } else {
 
200
        /* Snoop READ CAPACITY output to set the blocksize.  */
 
201
        if (r->req.cmd.buf[0] == READ_CAPACITY_10) {
 
202
            s->blocksize = ldl_be_p(&r->buf[4]);
 
203
            s->max_lba = ldl_be_p(&r->buf[0]);
 
204
        } else if (r->req.cmd.buf[0] == SERVICE_ACTION_IN_16 &&
 
205
                   (r->req.cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) {
 
206
            s->blocksize = ldl_be_p(&r->buf[8]);
 
207
            s->max_lba = ldq_be_p(&r->buf[0]);
 
208
        }
 
209
        bdrv_set_buffer_alignment(s->conf.bs, s->blocksize);
 
210
 
 
211
        scsi_req_data(&r->req, len);
 
212
        if (!r->req.io_canceled) {
 
213
            scsi_req_unref(&r->req);
 
214
        }
 
215
    }
 
216
}
 
217
 
 
218
/* Read more data from scsi device into buffer.  */
 
219
static void scsi_read_data(SCSIRequest *req)
 
220
{
 
221
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
 
222
    SCSIDevice *s = r->req.dev;
 
223
    int ret;
 
224
 
 
225
    DPRINTF("scsi_read_data 0x%x\n", req->tag);
 
226
 
 
227
    /* The request is used as the AIO opaque value, so add a ref.  */
 
228
    scsi_req_ref(&r->req);
 
229
    if (r->len == -1) {
 
230
        scsi_command_complete(r, 0);
 
231
        return;
 
232
    }
 
233
 
 
234
    ret = execute_command(s->conf.bs, r, SG_DXFER_FROM_DEV, scsi_read_complete);
 
235
    if (ret < 0) {
 
236
        scsi_command_complete(r, ret);
 
237
    }
 
238
}
 
239
 
 
240
static void scsi_write_complete(void * opaque, int ret)
 
241
{
 
242
    SCSIGenericReq *r = (SCSIGenericReq *)opaque;
 
243
    SCSIDevice *s = r->req.dev;
 
244
 
 
245
    DPRINTF("scsi_write_complete() ret = %d\n", ret);
 
246
    r->req.aiocb = NULL;
 
247
    if (ret) {
 
248
        DPRINTF("IO error\n");
 
249
        scsi_command_complete(r, ret);
 
250
        return;
 
251
    }
 
252
 
 
253
    if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 &&
 
254
        s->type == TYPE_TAPE) {
 
255
        s->blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
 
256
        DPRINTF("block size %d\n", s->blocksize);
 
257
    }
 
258
 
 
259
    scsi_command_complete(r, ret);
 
260
}
 
261
 
 
262
/* Write data to a scsi device.  Returns nonzero on failure.
 
263
   The transfer may complete asynchronously.  */
 
264
static void scsi_write_data(SCSIRequest *req)
 
265
{
 
266
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
 
267
    SCSIDevice *s = r->req.dev;
 
268
    int ret;
 
269
 
 
270
    DPRINTF("scsi_write_data 0x%x\n", req->tag);
 
271
    if (r->len == 0) {
 
272
        r->len = r->buflen;
 
273
        scsi_req_data(&r->req, r->len);
 
274
        return;
 
275
    }
 
276
 
 
277
    /* The request is used as the AIO opaque value, so add a ref.  */
 
278
    scsi_req_ref(&r->req);
 
279
    ret = execute_command(s->conf.bs, r, SG_DXFER_TO_DEV, scsi_write_complete);
 
280
    if (ret < 0) {
 
281
        scsi_command_complete(r, ret);
 
282
    }
 
283
}
 
284
 
 
285
/* Return a pointer to the data buffer.  */
 
286
static uint8_t *scsi_get_buf(SCSIRequest *req)
 
287
{
 
288
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
 
289
 
 
290
    return r->buf;
 
291
}
 
292
 
 
293
/* Execute a scsi command.  Returns the length of the data expected by the
 
294
   command.  This will be Positive for data transfers from the device
 
295
   (eg. disk reads), negative for transfers to the device (eg. disk writes),
 
296
   and zero if the command does not transfer any data.  */
 
297
 
 
298
static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
 
299
{
 
300
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
 
301
    SCSIDevice *s = r->req.dev;
 
302
    int ret;
 
303
 
 
304
    DPRINTF("Command: lun=%d tag=0x%x len %zd data=0x%02x", lun, tag,
 
305
            r->req.cmd.xfer, cmd[0]);
 
306
 
 
307
#ifdef DEBUG_SCSI
 
308
    {
 
309
        int i;
 
310
        for (i = 1; i < r->req.cmd.len; i++) {
 
311
            printf(" 0x%02x", cmd[i]);
 
312
        }
 
313
        printf("\n");
 
314
    }
 
315
#endif
 
316
 
 
317
    if (r->req.cmd.xfer == 0) {
 
318
        if (r->buf != NULL)
 
319
            g_free(r->buf);
 
320
        r->buflen = 0;
 
321
        r->buf = NULL;
 
322
        /* The request is used as the AIO opaque value, so add a ref.  */
 
323
        scsi_req_ref(&r->req);
 
324
        ret = execute_command(s->conf.bs, r, SG_DXFER_NONE, scsi_command_complete);
 
325
        if (ret < 0) {
 
326
            scsi_command_complete(r, ret);
 
327
            return 0;
 
328
        }
 
329
        return 0;
 
330
    }
 
331
 
 
332
    if (r->buflen != r->req.cmd.xfer) {
 
333
        if (r->buf != NULL)
 
334
            g_free(r->buf);
 
335
        r->buf = g_malloc(r->req.cmd.xfer);
 
336
        r->buflen = r->req.cmd.xfer;
 
337
    }
 
338
 
 
339
    memset(r->buf, 0, r->buflen);
 
340
    r->len = r->req.cmd.xfer;
 
341
    if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
 
342
        r->len = 0;
 
343
        return -r->req.cmd.xfer;
 
344
    } else {
 
345
        return r->req.cmd.xfer;
 
346
    }
 
347
}
 
348
 
 
349
static int get_stream_blocksize(BlockDriverState *bdrv)
 
350
{
 
351
    uint8_t cmd[6];
 
352
    uint8_t buf[12];
 
353
    uint8_t sensebuf[8];
 
354
    sg_io_hdr_t io_header;
 
355
    int ret;
 
356
 
 
357
    memset(cmd, 0, sizeof(cmd));
 
358
    memset(buf, 0, sizeof(buf));
 
359
    cmd[0] = MODE_SENSE;
 
360
    cmd[4] = sizeof(buf);
 
361
 
 
362
    memset(&io_header, 0, sizeof(io_header));
 
363
    io_header.interface_id = 'S';
 
364
    io_header.dxfer_direction = SG_DXFER_FROM_DEV;
 
365
    io_header.dxfer_len = sizeof(buf);
 
366
    io_header.dxferp = buf;
 
367
    io_header.cmdp = cmd;
 
368
    io_header.cmd_len = sizeof(cmd);
 
369
    io_header.mx_sb_len = sizeof(sensebuf);
 
370
    io_header.sbp = sensebuf;
 
371
    io_header.timeout = 6000; /* XXX */
 
372
 
 
373
    ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
 
374
    if (ret < 0 || io_header.driver_status || io_header.host_status) {
 
375
        return -1;
 
376
    }
 
377
    return (buf[9] << 16) | (buf[10] << 8) | buf[11];
 
378
}
 
379
 
 
380
static void scsi_generic_reset(DeviceState *dev)
 
381
{
 
382
    SCSIDevice *s = SCSI_DEVICE(dev);
 
383
 
 
384
    scsi_device_purge_requests(s, SENSE_CODE(RESET));
 
385
}
 
386
 
 
387
static void scsi_destroy(SCSIDevice *s)
 
388
{
 
389
    scsi_device_purge_requests(s, SENSE_CODE(NO_SENSE));
 
390
    blockdev_mark_auto_del(s->conf.bs);
 
391
}
 
392
 
 
393
static int scsi_generic_initfn(SCSIDevice *s)
 
394
{
 
395
    int sg_version;
 
396
    struct sg_scsi_id scsiid;
 
397
 
 
398
    if (!s->conf.bs) {
 
399
        error_report("drive property not set");
 
400
        return -1;
 
401
    }
 
402
 
 
403
    if (bdrv_get_on_error(s->conf.bs, 0) != BLOCKDEV_ON_ERROR_ENOSPC) {
 
404
        error_report("Device doesn't support drive option werror");
 
405
        return -1;
 
406
    }
 
407
    if (bdrv_get_on_error(s->conf.bs, 1) != BLOCKDEV_ON_ERROR_REPORT) {
 
408
        error_report("Device doesn't support drive option rerror");
 
409
        return -1;
 
410
    }
 
411
 
 
412
    /* check we are using a driver managing SG_IO (version 3 and after */
 
413
    if (bdrv_ioctl(s->conf.bs, SG_GET_VERSION_NUM, &sg_version) < 0) {
 
414
        error_report("scsi generic interface not supported");
 
415
        return -1;
 
416
    }
 
417
    if (sg_version < 30000) {
 
418
        error_report("scsi generic interface too old");
 
419
        return -1;
 
420
    }
 
421
 
 
422
    /* get LUN of the /dev/sg? */
 
423
    if (bdrv_ioctl(s->conf.bs, SG_GET_SCSI_ID, &scsiid)) {
 
424
        error_report("SG_GET_SCSI_ID ioctl failed");
 
425
        return -1;
 
426
    }
 
427
 
 
428
    /* define device state */
 
429
    s->type = scsiid.scsi_type;
 
430
    DPRINTF("device type %d\n", s->type);
 
431
    if (s->type == TYPE_DISK || s->type == TYPE_ROM) {
 
432
        add_boot_device_path(s->conf.bootindex, &s->qdev, NULL);
 
433
    }
 
434
 
 
435
    switch (s->type) {
 
436
    case TYPE_TAPE:
 
437
        s->blocksize = get_stream_blocksize(s->conf.bs);
 
438
        if (s->blocksize == -1) {
 
439
            s->blocksize = 0;
 
440
        }
 
441
        break;
 
442
 
 
443
        /* Make a guess for block devices, we'll fix it when the guest sends.
 
444
         * READ CAPACITY.  If they don't, they likely would assume these sizes
 
445
         * anyway. (TODO: they could also send MODE SENSE).
 
446
         */
 
447
    case TYPE_ROM:
 
448
    case TYPE_WORM:
 
449
        s->blocksize = 2048;
 
450
        break;
 
451
    default:
 
452
        s->blocksize = 512;
 
453
        break;
 
454
    }
 
455
 
 
456
    DPRINTF("block size %d\n", s->blocksize);
 
457
    return 0;
 
458
}
 
459
 
 
460
const SCSIReqOps scsi_generic_req_ops = {
 
461
    .size         = sizeof(SCSIGenericReq),
 
462
    .free_req     = scsi_free_request,
 
463
    .send_command = scsi_send_command,
 
464
    .read_data    = scsi_read_data,
 
465
    .write_data   = scsi_write_data,
 
466
    .cancel_io    = scsi_cancel_io,
 
467
    .get_buf      = scsi_get_buf,
 
468
    .load_request = scsi_generic_load_request,
 
469
    .save_request = scsi_generic_save_request,
 
470
};
 
471
 
 
472
static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
 
473
                                     uint8_t *buf, void *hba_private)
 
474
{
 
475
    SCSIRequest *req;
 
476
 
 
477
    req = scsi_req_alloc(&scsi_generic_req_ops, d, tag, lun, hba_private);
 
478
    return req;
 
479
}
 
480
 
 
481
static Property scsi_generic_properties[] = {
 
482
    DEFINE_PROP_DRIVE("drive", SCSIDevice, conf.bs),
 
483
    DEFINE_PROP_INT32("bootindex", SCSIDevice, conf.bootindex, -1),
 
484
    DEFINE_PROP_END_OF_LIST(),
 
485
};
 
486
 
 
487
static void scsi_generic_class_initfn(ObjectClass *klass, void *data)
 
488
{
 
489
    DeviceClass *dc = DEVICE_CLASS(klass);
 
490
    SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
 
491
 
 
492
    sc->init         = scsi_generic_initfn;
 
493
    sc->destroy      = scsi_destroy;
 
494
    sc->alloc_req    = scsi_new_request;
 
495
    dc->fw_name = "disk";
 
496
    dc->desc = "pass through generic scsi device (/dev/sg*)";
 
497
    dc->reset = scsi_generic_reset;
 
498
    dc->props = scsi_generic_properties;
 
499
    dc->vmsd  = &vmstate_scsi_device;
 
500
}
 
501
 
 
502
static const TypeInfo scsi_generic_info = {
 
503
    .name          = "scsi-generic",
 
504
    .parent        = TYPE_SCSI_DEVICE,
 
505
    .instance_size = sizeof(SCSIDevice),
 
506
    .class_init    = scsi_generic_class_initfn,
 
507
};
 
508
 
 
509
static void scsi_generic_register_types(void)
 
510
{
 
511
    type_register_static(&scsi_generic_info);
 
512
}
 
513
 
 
514
type_init(scsi_generic_register_types)
 
515
 
 
516
#endif /* __linux__ */