Statistics
| Branch: | Revision:

root / hw / scsi-disk.c @ 0986ac3b

History | View | Annotate | Download (13.3 kB)

1
/*
2
 * SCSI Device emulation
3
 *
4
 * Copyright (c) 2006 CodeSourcery.
5
 * Based on code by Fabrice Bellard
6
 *
7
 * Written by Paul Brook
8
 *
9
 * This code is licenced under the LGPL.
10
 */
11

    
12
//#define DEBUG_SCSI
13

    
14
#ifdef DEBUG_SCSI
15
#define DPRINTF(fmt, args...) \
16
do { printf("scsi-disk: " fmt , ##args); } while (0)
17
#else
18
#define DPRINTF(fmt, args...) do {} while(0)
19
#endif
20

    
21
#define BADF(fmt, args...) \
22
do { fprintf(stderr, "scsi-disk: " fmt , ##args); } while (0)
23

    
24
#include "vl.h"
25

    
26
#define SENSE_NO_SENSE        0
27
#define SENSE_ILLEGAL_REQUEST 5
28

    
29
struct SCSIDevice
30
{
31
    int command;
32
    uint32_t tag;
33
    BlockDriverState *bdrv;
34
    /* The qemu block layer uses a fixed 512 byte sector size.
35
       This is the number of 512 byte blocks in a single scsi sector.  */
36
    int cluster_size;
37
    /* When transfering data buf_pos and buf_len contain a partially
38
       transferred block of data (or response to a command), and
39
       sector/sector_count identify any remaining sectors.
40
       Both sector and sector_count are in terms of qemu 512 byte blocks.  */
41
    /* ??? We should probably keep track of whether the data trasfer is
42
       a read or a write.  Currently we rely on the host getting it right.  */
43
    int sector;
44
    int sector_count;
45
    int buf_pos;
46
    int buf_len;
47
    int sense;
48
    char buf[512];
49
    scsi_completionfn completion;
50
    void *opaque;
51
};
52

    
53
static void scsi_command_complete(SCSIDevice *s, int sense)
54
{
55
    s->sense = sense;
56
    s->completion(s->opaque, s->tag, sense);
57
}
58

    
59
/* Read data from a scsi device.  Returns nonzero on failure.  */
60
int scsi_read_data(SCSIDevice *s, uint8_t *data, uint32_t len)
61
{
62
    uint32_t n;
63

    
64
    DPRINTF("Read %d (%d/%d)\n", len, s->buf_len, s->sector_count);
65
    if (s->buf_len == 0 && s->sector_count == 0)
66
        return 1;
67

    
68
    if (s->buf_len) {
69
        n = s->buf_len;
70
        if (n > len)
71
            n = len;
72
        memcpy(data, s->buf + s->buf_pos, n);
73
        s->buf_pos += n;
74
        s->buf_len -= n;
75
        data += n;
76
        len -= n;
77
        if (s->buf_len == 0)
78
            s->buf_pos = 0;
79
    }
80

    
81
    n = len / 512;
82
    if (n > s->sector_count)
83
      n = s->sector_count;
84

    
85
    if (n != 0) {
86
        bdrv_read(s->bdrv, s->sector, data, n);
87
        data += n * 512;
88
        len -= n * 512;
89
        s->sector += n;
90
        s->sector_count -= n;
91
    }
92

    
93
    if (len && s->sector_count) {
94
        bdrv_read(s->bdrv, s->sector, s->buf, 1);
95
        s->sector++;
96
        s->sector_count--;
97
        s->buf_pos = 0;
98
        s->buf_len = 512;
99
        /* Recurse to complete the partial read.  */
100
        return scsi_read_data(s, data, len);
101
    }
102

    
103
    if (len != 0)
104
        return 1;
105

    
106
    if (s->buf_len == 0 && s->sector_count == 0)
107
        scsi_command_complete(s, SENSE_NO_SENSE);
108

    
109
    return 0;
110
}
111

    
112
/* Read data to a scsi device.  Returns nonzero on failure.  */
113
int scsi_write_data(SCSIDevice *s, uint8_t *data, uint32_t len)
114
{
115
    uint32_t n;
116

    
117
    DPRINTF("Write %d (%d/%d)\n", len, s->buf_len, s->sector_count);
118
    if (s->buf_pos != 0) {
119
        BADF("Bad state on write\n");
120
        return 1;
121
    }
122

    
123
    if (s->sector_count == 0)
124
        return 1;
125

    
126
    if (s->buf_len != 0 || len < 512) {
127
        n = 512 - s->buf_len;
128
        if (n > len)
129
            n = len;
130

    
131
        memcpy(s->buf + s->buf_len, data, n);
132
        data += n;
133
        s->buf_len += n;
134
        len -= n;
135
        if (s->buf_len == 512) {
136
            /* A full sector has been accumulated. Write it to disk.  */
137
            bdrv_write(s->bdrv, s->sector, s->buf, 1);
138
            s->buf_len = 0;
139
            s->sector++;
140
            s->sector_count--;
141
        }
142
    }
143

    
144
    n = len / 512;
145
    if (n > s->sector_count)
146
        n = s->sector_count;
147

    
148
    if (n != 0) {
149
        bdrv_write(s->bdrv, s->sector, data, n);
150
        data += n * 512;
151
        len -= n * 512;
152
        s->sector += n;
153
        s->sector_count -= n;
154
    }
155

    
156
    if (len >= 512)
157
        return 1;
158

    
159
    if (len && s->sector_count) {
160
        /* Recurse to complete the partial write.  */
161
        return scsi_write_data(s, data, len);
162
    }
163

    
164
    if (len != 0)
165
        return 1;
166

    
167
    if (s->sector_count == 0)
168
        scsi_command_complete(s, SENSE_NO_SENSE);
169

    
170
    return 0;
171
}
172

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

    
178
int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun)
179
{
180
    int64_t nb_sectors;
181
    uint32_t lba;
182
    uint32_t len;
183
    int cmdlen;
184
    int is_write;
185

    
186
    s->command = buf[0];
187
    s->tag = tag;
188
    s->sector_count = 0;
189
    s->buf_pos = 0;
190
    s->buf_len = 0;
191
    is_write = 0;
192
    DPRINTF("Command: 0x%02x", buf[0]);
193
    switch (s->command >> 5) {
194
    case 0:
195
        lba = buf[3] | (buf[2] << 8) | ((buf[1] & 0x1f) << 16);
196
        len = buf[4];
197
        cmdlen = 6;
198
        break;
199
    case 1:
200
    case 2:
201
        lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24);
202
        len = buf[8] | (buf[7] << 8);
203
        cmdlen = 10;
204
        break;
205
    case 4:
206
        lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24);
207
        len = buf[13] | (buf[12] << 8) | (buf[11] << 16) | (buf[10] << 24);
208
        cmdlen = 16;
209
        break;
210
    case 5:
211
        lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24);
212
        len = buf[9] | (buf[8] << 8) | (buf[7] << 16) | (buf[6] << 24);
213
        cmdlen = 12;
214
        break;
215
    default:
216
        BADF("Unsupported command length, command %x\n", s->command);
217
        goto fail;
218
    }
219
#ifdef DEBUG_SCSI
220
    {
221
        int i;
222
        for (i = 1; i < cmdlen; i++) {
223
            printf(" 0x%02x", buf[i]);
224
        }
225
        printf("\n");
226
    }
227
#endif
228
    if (lun || buf[1] >> 5) {
229
        /* Only LUN 0 supported.  */
230
        DPRINTF("Unimplemented LUN %d\n", lun ? lun : buf[1] >> 5);
231
        goto fail;
232
    }
233
    switch (s->command) {
234
    case 0x0:
235
        DPRINTF("Test Unit Ready\n");
236
        break;
237
    case 0x03:
238
        DPRINTF("Request Sense (len %d)\n", len);
239
        if (len < 4)
240
            goto fail;
241
        memset(buf, 0, 4);
242
        s->buf[0] = 0xf0;
243
        s->buf[1] = 0;
244
        s->buf[2] = s->sense;
245
        s->buf_len = 4;
246
        break;
247
    case 0x12:
248
        DPRINTF("Inquiry (len %d)\n", len);
249
        if (len < 36) {
250
            BADF("Inquiry buffer too small (%d)\n", len);
251
        }
252
        memset(s->buf, 0, 36);
253
        if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) {
254
            s->buf[0] = 5;
255
            s->buf[1] = 0x80;
256
            memcpy(&s->buf[16], "QEMU CD-ROM    ", 16);
257
        } else {
258
            s->buf[0] = 0;
259
            memcpy(&s->buf[16], "QEMU HARDDISK  ", 16);
260
        }
261
        memcpy(&s->buf[8], "QEMU   ", 8);
262
        memcpy(&s->buf[32], QEMU_VERSION, 4);
263
        /* Identify device as SCSI-3 rev 1.
264
           Some later commands are also implemented. */
265
        s->buf[2] = 3;
266
        s->buf[3] = 2; /* Format 2 */
267
        s->buf[4] = 32;
268
        s->buf_len = 36;
269
        break;
270
    case 0x16:
271
        DPRINTF("Reserve(6)\n");
272
        if (buf[1] & 1)
273
            goto fail;
274
        break;
275
    case 0x17:
276
        DPRINTF("Release(6)\n");
277
        if (buf[1] & 1)
278
            goto fail;
279
        break;
280
    case 0x1a:
281
    case 0x5a:
282
        {
283
            char *p;
284
            int page;
285

    
286
            page = buf[2] & 0x3f;
287
            DPRINTF("Mode Sense (page %d, len %d)\n", page, len);
288
            p = s->buf;
289
            memset(p, 0, 4);
290
            s->buf[1] = 0; /* Default media type.  */
291
            s->buf[3] = 0; /* Block descriptor length.  */
292
            if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) {
293
                s->buf[2] = 0x80; /* Readonly.  */
294
            }
295
            p += 4;
296
            if ((page == 8 || page == 0x3f)) {
297
                /* Caching page.  */
298
                p[0] = 8;
299
                p[1] = 0x12;
300
                p[2] = 4; /* WCE */
301
                p += 19;
302
            }
303
            if ((page == 0x3f || page == 0x2a)
304
                    && (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM)) {
305
                /* CD Capabilities and Mechanical Status page. */
306
                p[0] = 0x2a;
307
                p[1] = 0x14;
308
                p[2] = 3; // CD-R & CD-RW read
309
                p[3] = 0; // Writing not supported
310
                p[4] = 0x7f; /* Audio, composite, digital out,
311
                                         mode 2 form 1&2, multi session */
312
                p[5] = 0xff; /* CD DA, DA accurate, RW supported,
313
                                         RW corrected, C2 errors, ISRC,
314
                                         UPC, Bar code */
315
                p[6] = 0x2d | (bdrv_is_locked(s->bdrv)? 2 : 0);
316
                /* Locking supported, jumper present, eject, tray */
317
                p[7] = 0; /* no volume & mute control, no
318
                                      changer */
319
                p[8] = (50 * 176) >> 8; // 50x read speed
320
                p[9] = (50 * 176) & 0xff;
321
                p[10] = 0 >> 8; // No volume
322
                p[11] = 0 & 0xff;
323
                p[12] = 2048 >> 8; // 2M buffer
324
                p[13] = 2048 & 0xff;
325
                p[14] = (16 * 176) >> 8; // 16x read speed current
326
                p[15] = (16 * 176) & 0xff;
327
                p[18] = (16 * 176) >> 8; // 16x write speed
328
                p[19] = (16 * 176) & 0xff;
329
                p[20] = (16 * 176) >> 8; // 16x write speed current
330
                p[21] = (16 * 176) & 0xff;
331
                p += 21;
332
            }
333
            s->buf_len = p - s->buf;
334
            s->buf[0] = s->buf_len - 4;
335
            if (s->buf_len > len)
336
                s->buf_len = len;
337
        }
338
        break;
339
    case 0x1b:
340
        DPRINTF("Start Stop Unit\n");
341
        break;
342
    case 0x1e:
343
        DPRINTF("Prevent Allow Medium Removal (prevent = %d)\n", buf[4] & 3);
344
        bdrv_set_locked(s->bdrv, buf[4] & 1);
345
        break;
346
    case 0x25:
347
        DPRINTF("Read Capacity\n");
348
        /* The normal LEN field for this command is zero.  */
349
        memset(s->buf, 0, 8);
350
        bdrv_get_geometry(s->bdrv, &nb_sectors);
351
        s->buf[0] = (nb_sectors >> 24) & 0xff;
352
        s->buf[1] = (nb_sectors >> 16) & 0xff;
353
        s->buf[2] = (nb_sectors >> 8) & 0xff;
354
        s->buf[3] = nb_sectors & 0xff;
355
        s->buf[4] = 0;
356
        s->buf[5] = 0;
357
        s->buf[6] = s->cluster_size * 2;
358
        s->buf[7] = 0;
359
        s->buf_len = 8;
360
        break;
361
    case 0x08:
362
    case 0x28:
363
        DPRINTF("Read (sector %d, count %d)\n", lba, len);
364
        s->sector = lba * s->cluster_size;
365
        s->sector_count = len * s->cluster_size;
366
        break;
367
    case 0x0a:
368
    case 0x2a:
369
        DPRINTF("Write (sector %d, count %d)\n", lba, len);
370
        s->sector = lba * s->cluster_size;
371
        s->sector_count = len * s->cluster_size;
372
        is_write = 1;
373
        break;
374
    case 0x35:
375
        DPRINTF("Syncronise cache (sector %d, count %d)\n", lba, len);
376
        bdrv_flush(s->bdrv);
377
        break;
378
    case 0x43:
379
        {
380
            int start_track, format, msf, toclen;
381

    
382
            msf = buf[1] & 2;
383
            format = buf[2] & 0xf;
384
            start_track = buf[6];
385
            bdrv_get_geometry(s->bdrv, &nb_sectors);
386
            DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1);
387
            switch(format) {
388
            case 0:
389
                toclen = cdrom_read_toc(nb_sectors, s->buf, msf, start_track);
390
                break;
391
            case 1:
392
                /* multi session : only a single session defined */
393
                toclen = 12;
394
                memset(s->buf, 0, 12);
395
                s->buf[1] = 0x0a;
396
                s->buf[2] = 0x01;
397
                s->buf[3] = 0x01;
398
                break;
399
            case 2:
400
                toclen = cdrom_read_toc_raw(nb_sectors, s->buf, msf, start_track);
401
                break;
402
            default:
403
                goto error_cmd;
404
            }
405
            if (toclen > 0) {
406
                if (len > toclen)
407
                  len = toclen;
408
                s->buf_len = len;
409
                break;
410
            }
411
        error_cmd:
412
            DPRINTF("Read TOC error\n");
413
            goto fail;
414
        }
415
    case 0x46:
416
        DPRINTF("Get Configuration (rt %d, maxlen %d)\n", buf[1] & 3, len);
417
        memset(s->buf, 0, 8);
418
        /* ??? This shoud probably return much more information.  For now
419
           just return the basic header indicating the CD-ROM profile.  */
420
        s->buf[7] = 8; // CD-ROM
421
        s->buf_len = 8;
422
        break;
423
    case 0x56:
424
        DPRINTF("Reserve(10)\n");
425
        if (buf[1] & 3)
426
            goto fail;
427
        break;
428
    case 0x57:
429
        DPRINTF("Release(10)\n");
430
        if (buf[1] & 3)
431
            goto fail;
432
        break;
433
    case 0xa0:
434
        DPRINTF("Report LUNs (len %d)\n", len);
435
        if (len < 16)
436
            goto fail;
437
        memset(s->buf, 0, 16);
438
        s->buf[3] = 8;
439
        s->buf_len = 16;
440
        break;
441
    default:
442
        DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
443
    fail:
444
        scsi_command_complete(s, SENSE_ILLEGAL_REQUEST);
445
        return 0;
446
    }
447
    if (s->sector_count == 0 && s->buf_len == 0) {
448
        scsi_command_complete(s, SENSE_NO_SENSE);
449
    }
450
    len = s->sector_count * 512 + s->buf_len;
451
    return is_write ? -len : len;
452
}
453

    
454
void scsi_disk_destroy(SCSIDevice *s)
455
{
456
    bdrv_close(s->bdrv);
457
    qemu_free(s);
458
}
459

    
460
SCSIDevice *scsi_disk_init(BlockDriverState *bdrv,
461
                           scsi_completionfn completion,
462
                           void *opaque)
463
{
464
    SCSIDevice *s;
465

    
466
    s = (SCSIDevice *)qemu_mallocz(sizeof(SCSIDevice));
467
    s->bdrv = bdrv;
468
    s->completion = completion;
469
    s->opaque = opaque;
470
    if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) {
471
        s->cluster_size = 4;
472
    } else {
473
        s->cluster_size = 1;
474
    }
475

    
476
    return s;
477
}
478