Statistics
| Branch: | Revision:

root / hw / scsi-disk.c @ 0fc5c15a

History | View | Annotate | Download (10.6 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\n");
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 CDROM     ", 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
        s->buf[2] = 3; /* SCSI-3 */
263
        s->buf[3] = 2; /* Format 2 */
264
        s->buf[4] = 32;
265
        s->buf_len = 36;
266
        break;
267
    case 0x16:
268
        DPRINTF("Reserve(6)\n");
269
        if (buf[1] & 1)
270
            goto fail;
271
        break;
272
    case 0x17:
273
        DPRINTF("Release(6)\n");
274
        if (buf[1] & 1)
275
            goto fail;
276
        break;
277
    case 0x1a:
278
        DPRINTF("Mode Sense(6) (page %d, len %d)\n", buf[2], len);
279
        memset(s->buf, 0, 4);
280
        s->buf[0] = 0x16; /* Mode data length (4 + 0x12).  */
281
        s->buf[1] = 0; /* Default media type.  */
282
        s->buf[2] = 0; /* Write enabled.  */
283
        s->buf[3] = 0; /* Block descriptor length.  */
284
        /* Caching page.  */
285
        s->buf[4 + 0] = 8;
286
        s->buf[4 + 1] = 0x12;
287
        s->buf[4 + 2] = 4; /* WCE */
288
        if (len > 0x16)
289
            len = 0x16;
290
        s->buf_len = len;
291
        break;
292
    case 0x25:
293
        DPRINTF("Read Capacity\n");
294
        /* The normal LEN field for this command is zero.  */
295
        memset(s->buf, 0, 8);
296
        bdrv_get_geometry(s->bdrv, &nb_sectors);
297
        s->buf[0] = (nb_sectors >> 24) & 0xff;
298
        s->buf[1] = (nb_sectors >> 16) & 0xff;
299
        s->buf[2] = (nb_sectors >> 8) & 0xff;
300
        s->buf[3] = nb_sectors & 0xff;
301
        s->buf[4] = 0;
302
        s->buf[5] = 0;
303
        s->buf[6] = s->cluster_size * 2;
304
        s->buf[7] = 0;
305
        s->buf_len = 8;
306
        break;
307
    case 0x08:
308
    case 0x28:
309
        DPRINTF("Read (sector %d, count %d)\n", lba, len);
310
        s->sector = lba * s->cluster_size;
311
        s->sector_count = len * s->cluster_size;
312
        break;
313
    case 0x0a:
314
    case 0x2a:
315
        DPRINTF("Write (sector %d, count %d)\n", lba, len);
316
        s->sector = lba * s->cluster_size;
317
        s->sector_count = len * s->cluster_size;
318
        is_write = 1;
319
        break;
320
    case 0x43:
321
        {
322
            int start_track, format, msf, toclen;
323

    
324
            msf = buf[1] & 2;
325
            format = buf[2] & 0xf;
326
            start_track = buf[6];
327
            bdrv_get_geometry(s->bdrv, &nb_sectors);
328
            DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1);
329
            switch(format) {
330
            case 0:
331
                toclen = cdrom_read_toc(nb_sectors, s->buf, msf, start_track);
332
                break;
333
            case 1:
334
                /* multi session : only a single session defined */
335
                toclen = 12;
336
                memset(s->buf, 0, 12);
337
                s->buf[1] = 0x0a;
338
                s->buf[2] = 0x01;
339
                s->buf[3] = 0x01;
340
                break;
341
            case 2:
342
                toclen = cdrom_read_toc_raw(nb_sectors, s->buf, msf, start_track);
343
                break;
344
            default:
345
                goto error_cmd;
346
            }
347
            if (toclen > 0) {
348
                if (len > toclen)
349
                  len = toclen;
350
                s->buf_len = len;
351
                break;
352
            }
353
        error_cmd:
354
            DPRINTF("Read TOC error\n");
355
            goto fail;
356
        }
357
    case 0x56:
358
        DPRINTF("Reserve(10)\n");
359
        if (buf[1] & 3)
360
            goto fail;
361
        break;
362
    case 0x57:
363
        DPRINTF("Release(10)\n");
364
        if (buf[1] & 3)
365
            goto fail;
366
        break;
367
    case 0xa0:
368
        DPRINTF("Report LUNs (len %d)\n", len);
369
        if (len < 16)
370
            goto fail;
371
        memset(s->buf, 0, 16);
372
        s->buf[3] = 8;
373
        s->buf_len = 16;
374
        break;
375
    default:
376
        DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
377
    fail:
378
        scsi_command_complete(s, SENSE_ILLEGAL_REQUEST);
379
        return 0;
380
    }
381
    if (s->sector_count == 0 && s->buf_len == 0) {
382
        scsi_command_complete(s, SENSE_NO_SENSE);
383
    }
384
    len = s->sector_count * 512 + s->buf_len;
385
    return is_write ? -len : len;
386
}
387

    
388
void scsi_disk_destroy(SCSIDevice *s)
389
{
390
    bdrv_close(s->bdrv);
391
    qemu_free(s);
392
}
393

    
394
SCSIDevice *scsi_disk_init(BlockDriverState *bdrv,
395
                           scsi_completionfn completion,
396
                           void *opaque)
397
{
398
    SCSIDevice *s;
399

    
400
    s = (SCSIDevice *)qemu_mallocz(sizeof(SCSIDevice));
401
    s->bdrv = bdrv;
402
    s->completion = completion;
403
    s->opaque = opaque;
404
    if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) {
405
        s->cluster_size = 4;
406
    } else {
407
        s->cluster_size = 1;
408
    }
409

    
410
    return s;
411
}
412