Statistics
| Branch: | Revision:

root / hw / scsi-disk.c @ c5d6edc3

History | View | Annotate | Download (13.3 kB)

1 2e5d83bb pbrook
/*
2 2e5d83bb pbrook
 * SCSI Device emulation
3 2e5d83bb pbrook
 *
4 2e5d83bb pbrook
 * Copyright (c) 2006 CodeSourcery.
5 2e5d83bb pbrook
 * Based on code by Fabrice Bellard
6 2e5d83bb pbrook
 *
7 2e5d83bb pbrook
 * Written by Paul Brook
8 2e5d83bb pbrook
 *
9 2e5d83bb pbrook
 * This code is licenced under the LGPL.
10 2e5d83bb pbrook
 */
11 2e5d83bb pbrook
12 2e5d83bb pbrook
//#define DEBUG_SCSI
13 2e5d83bb pbrook
14 2e5d83bb pbrook
#ifdef DEBUG_SCSI
15 2e5d83bb pbrook
#define DPRINTF(fmt, args...) \
16 2e5d83bb pbrook
do { printf("scsi-disk: " fmt , ##args); } while (0)
17 2e5d83bb pbrook
#else
18 2e5d83bb pbrook
#define DPRINTF(fmt, args...) do {} while(0)
19 2e5d83bb pbrook
#endif
20 2e5d83bb pbrook
21 2e5d83bb pbrook
#define BADF(fmt, args...) \
22 2e5d83bb pbrook
do { fprintf(stderr, "scsi-disk: " fmt , ##args); } while (0)
23 2e5d83bb pbrook
24 2e5d83bb pbrook
#include "vl.h"
25 2e5d83bb pbrook
26 2e5d83bb pbrook
#define SENSE_NO_SENSE        0
27 2e5d83bb pbrook
#define SENSE_ILLEGAL_REQUEST 5
28 2e5d83bb pbrook
29 2e5d83bb pbrook
struct SCSIDevice
30 2e5d83bb pbrook
{
31 2e5d83bb pbrook
    int command;
32 2e5d83bb pbrook
    uint32_t tag;
33 2e5d83bb pbrook
    BlockDriverState *bdrv;
34 7c22dd52 pbrook
    /* The qemu block layer uses a fixed 512 byte sector size.
35 7c22dd52 pbrook
       This is the number of 512 byte blocks in a single scsi sector.  */
36 7c22dd52 pbrook
    int cluster_size;
37 2e5d83bb pbrook
    /* When transfering data buf_pos and buf_len contain a partially
38 2e5d83bb pbrook
       transferred block of data (or response to a command), and
39 7c22dd52 pbrook
       sector/sector_count identify any remaining sectors.
40 7c22dd52 pbrook
       Both sector and sector_count are in terms of qemu 512 byte blocks.  */
41 2e5d83bb pbrook
    /* ??? We should probably keep track of whether the data trasfer is
42 2e5d83bb pbrook
       a read or a write.  Currently we rely on the host getting it right.  */
43 2e5d83bb pbrook
    int sector;
44 2e5d83bb pbrook
    int sector_count;
45 2e5d83bb pbrook
    int buf_pos;
46 2e5d83bb pbrook
    int buf_len;
47 2e5d83bb pbrook
    int sense;
48 7c22dd52 pbrook
    char buf[512];
49 2e5d83bb pbrook
    scsi_completionfn completion;
50 2e5d83bb pbrook
    void *opaque;
51 2e5d83bb pbrook
};
52 2e5d83bb pbrook
53 2e5d83bb pbrook
static void scsi_command_complete(SCSIDevice *s, int sense)
54 2e5d83bb pbrook
{
55 2e5d83bb pbrook
    s->sense = sense;
56 0fc5c15a pbrook
    s->completion(s->opaque, s->tag, sense);
57 2e5d83bb pbrook
}
58 2e5d83bb pbrook
59 2e5d83bb pbrook
/* Read data from a scsi device.  Returns nonzero on failure.  */
60 2e5d83bb pbrook
int scsi_read_data(SCSIDevice *s, uint8_t *data, uint32_t len)
61 2e5d83bb pbrook
{
62 2e5d83bb pbrook
    uint32_t n;
63 2e5d83bb pbrook
64 2e5d83bb pbrook
    DPRINTF("Read %d (%d/%d)\n", len, s->buf_len, s->sector_count);
65 2e5d83bb pbrook
    if (s->buf_len == 0 && s->sector_count == 0)
66 2e5d83bb pbrook
        return 1;
67 2e5d83bb pbrook
68 2e5d83bb pbrook
    if (s->buf_len) {
69 2e5d83bb pbrook
        n = s->buf_len;
70 2e5d83bb pbrook
        if (n > len)
71 2e5d83bb pbrook
            n = len;
72 2e5d83bb pbrook
        memcpy(data, s->buf + s->buf_pos, n);
73 2e5d83bb pbrook
        s->buf_pos += n;
74 2e5d83bb pbrook
        s->buf_len -= n;
75 2e5d83bb pbrook
        data += n;
76 2e5d83bb pbrook
        len -= n;
77 2e5d83bb pbrook
        if (s->buf_len == 0)
78 2e5d83bb pbrook
            s->buf_pos = 0;
79 2e5d83bb pbrook
    }
80 2e5d83bb pbrook
81 7c22dd52 pbrook
    n = len / 512;
82 2e5d83bb pbrook
    if (n > s->sector_count)
83 2e5d83bb pbrook
      n = s->sector_count;
84 2e5d83bb pbrook
85 2e5d83bb pbrook
    if (n != 0) {
86 2e5d83bb pbrook
        bdrv_read(s->bdrv, s->sector, data, n);
87 7c22dd52 pbrook
        data += n * 512;
88 7c22dd52 pbrook
        len -= n * 512;
89 2e5d83bb pbrook
        s->sector += n;
90 2e5d83bb pbrook
        s->sector_count -= n;
91 2e5d83bb pbrook
    }
92 2e5d83bb pbrook
93 2e5d83bb pbrook
    if (len && s->sector_count) {
94 cac782d4 pbrook
        bdrv_read(s->bdrv, s->sector, s->buf, 1);
95 2e5d83bb pbrook
        s->sector++;
96 2e5d83bb pbrook
        s->sector_count--;
97 2e5d83bb pbrook
        s->buf_pos = 0;
98 7c22dd52 pbrook
        s->buf_len = 512;
99 2e5d83bb pbrook
        /* Recurse to complete the partial read.  */
100 2e5d83bb pbrook
        return scsi_read_data(s, data, len);
101 2e5d83bb pbrook
    }
102 2e5d83bb pbrook
103 2e5d83bb pbrook
    if (len != 0)
104 2e5d83bb pbrook
        return 1;
105 2e5d83bb pbrook
106 2e5d83bb pbrook
    if (s->buf_len == 0 && s->sector_count == 0)
107 2e5d83bb pbrook
        scsi_command_complete(s, SENSE_NO_SENSE);
108 2e5d83bb pbrook
109 2e5d83bb pbrook
    return 0;
110 2e5d83bb pbrook
}
111 2e5d83bb pbrook
112 2e5d83bb pbrook
/* Read data to a scsi device.  Returns nonzero on failure.  */
113 2e5d83bb pbrook
int scsi_write_data(SCSIDevice *s, uint8_t *data, uint32_t len)
114 2e5d83bb pbrook
{
115 2e5d83bb pbrook
    uint32_t n;
116 2e5d83bb pbrook
117 2e5d83bb pbrook
    DPRINTF("Write %d (%d/%d)\n", len, s->buf_len, s->sector_count);
118 2e5d83bb pbrook
    if (s->buf_pos != 0) {
119 2e5d83bb pbrook
        BADF("Bad state on write\n");
120 2e5d83bb pbrook
        return 1;
121 2e5d83bb pbrook
    }
122 2e5d83bb pbrook
123 2e5d83bb pbrook
    if (s->sector_count == 0)
124 2e5d83bb pbrook
        return 1;
125 2e5d83bb pbrook
126 7c22dd52 pbrook
    if (s->buf_len != 0 || len < 512) {
127 7c22dd52 pbrook
        n = 512 - s->buf_len;
128 2e5d83bb pbrook
        if (n > len)
129 2e5d83bb pbrook
            n = len;
130 2e5d83bb pbrook
131 2e5d83bb pbrook
        memcpy(s->buf + s->buf_len, data, n);
132 2e5d83bb pbrook
        data += n;
133 2e5d83bb pbrook
        s->buf_len += n;
134 2e5d83bb pbrook
        len -= n;
135 7c22dd52 pbrook
        if (s->buf_len == 512) {
136 2e5d83bb pbrook
            /* A full sector has been accumulated. Write it to disk.  */
137 2e5d83bb pbrook
            bdrv_write(s->bdrv, s->sector, s->buf, 1);
138 2e5d83bb pbrook
            s->buf_len = 0;
139 2e5d83bb pbrook
            s->sector++;
140 2e5d83bb pbrook
            s->sector_count--;
141 2e5d83bb pbrook
        }
142 2e5d83bb pbrook
    }
143 2e5d83bb pbrook
144 7c22dd52 pbrook
    n = len / 512;
145 2e5d83bb pbrook
    if (n > s->sector_count)
146 2e5d83bb pbrook
        n = s->sector_count;
147 2e5d83bb pbrook
148 2e5d83bb pbrook
    if (n != 0) {
149 2e5d83bb pbrook
        bdrv_write(s->bdrv, s->sector, data, n);
150 7c22dd52 pbrook
        data += n * 512;
151 7c22dd52 pbrook
        len -= n * 512;
152 2e5d83bb pbrook
        s->sector += n;
153 2e5d83bb pbrook
        s->sector_count -= n;
154 2e5d83bb pbrook
    }
155 2e5d83bb pbrook
156 7c22dd52 pbrook
    if (len >= 512)
157 2e5d83bb pbrook
        return 1;
158 2e5d83bb pbrook
159 2e5d83bb pbrook
    if (len && s->sector_count) {
160 2e5d83bb pbrook
        /* Recurse to complete the partial write.  */
161 2e5d83bb pbrook
        return scsi_write_data(s, data, len);
162 2e5d83bb pbrook
    }
163 2e5d83bb pbrook
164 2e5d83bb pbrook
    if (len != 0)
165 2e5d83bb pbrook
        return 1;
166 2e5d83bb pbrook
167 2e5d83bb pbrook
    if (s->sector_count == 0)
168 2e5d83bb pbrook
        scsi_command_complete(s, SENSE_NO_SENSE);
169 2e5d83bb pbrook
170 2e5d83bb pbrook
    return 0;
171 2e5d83bb pbrook
}
172 2e5d83bb pbrook
173 2e5d83bb pbrook
/* Execute a scsi command.  Returns the length of the data expected by the
174 2e5d83bb pbrook
   command.  This will be Positive for data transfers from the device
175 2e5d83bb pbrook
   (eg. disk reads), negative for transfers to the device (eg. disk writes),
176 2e5d83bb pbrook
   and zero if the command does not transfer any data.  */
177 2e5d83bb pbrook
178 0fc5c15a pbrook
int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun)
179 2e5d83bb pbrook
{
180 2e5d83bb pbrook
    int64_t nb_sectors;
181 2e5d83bb pbrook
    uint32_t lba;
182 2e5d83bb pbrook
    uint32_t len;
183 2e5d83bb pbrook
    int cmdlen;
184 2e5d83bb pbrook
    int is_write;
185 2e5d83bb pbrook
186 2e5d83bb pbrook
    s->command = buf[0];
187 2e5d83bb pbrook
    s->tag = tag;
188 2e5d83bb pbrook
    s->sector_count = 0;
189 2e5d83bb pbrook
    s->buf_pos = 0;
190 2e5d83bb pbrook
    s->buf_len = 0;
191 2e5d83bb pbrook
    is_write = 0;
192 2e5d83bb pbrook
    DPRINTF("Command: 0x%02x", buf[0]);
193 2e5d83bb pbrook
    switch (s->command >> 5) {
194 2e5d83bb pbrook
    case 0:
195 2e5d83bb pbrook
        lba = buf[3] | (buf[2] << 8) | ((buf[1] & 0x1f) << 16);
196 2e5d83bb pbrook
        len = buf[4];
197 2e5d83bb pbrook
        cmdlen = 6;
198 2e5d83bb pbrook
        break;
199 2e5d83bb pbrook
    case 1:
200 2e5d83bb pbrook
    case 2:
201 2e5d83bb pbrook
        lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24);
202 2e5d83bb pbrook
        len = buf[8] | (buf[7] << 8);
203 2e5d83bb pbrook
        cmdlen = 10;
204 2e5d83bb pbrook
        break;
205 2e5d83bb pbrook
    case 4:
206 2e5d83bb pbrook
        lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24);
207 2e5d83bb pbrook
        len = buf[13] | (buf[12] << 8) | (buf[11] << 16) | (buf[10] << 24);
208 2e5d83bb pbrook
        cmdlen = 16;
209 2e5d83bb pbrook
        break;
210 2e5d83bb pbrook
    case 5:
211 2e5d83bb pbrook
        lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24);
212 2e5d83bb pbrook
        len = buf[9] | (buf[8] << 8) | (buf[7] << 16) | (buf[6] << 24);
213 2e5d83bb pbrook
        cmdlen = 12;
214 2e5d83bb pbrook
        break;
215 2e5d83bb pbrook
    default:
216 17acfe32 pbrook
        BADF("Unsupported command length, command %x\n", s->command);
217 2e5d83bb pbrook
        goto fail;
218 2e5d83bb pbrook
    }
219 2e5d83bb pbrook
#ifdef DEBUG_SCSI
220 2e5d83bb pbrook
    {
221 2e5d83bb pbrook
        int i;
222 2e5d83bb pbrook
        for (i = 1; i < cmdlen; i++) {
223 2e5d83bb pbrook
            printf(" 0x%02x", buf[i]);
224 2e5d83bb pbrook
        }
225 2e5d83bb pbrook
        printf("\n");
226 2e5d83bb pbrook
    }
227 2e5d83bb pbrook
#endif
228 0fc5c15a pbrook
    if (lun || buf[1] >> 5) {
229 2e5d83bb pbrook
        /* Only LUN 0 supported.  */
230 0fc5c15a pbrook
        DPRINTF("Unimplemented LUN %d\n", lun ? lun : buf[1] >> 5);
231 2e5d83bb pbrook
        goto fail;
232 2e5d83bb pbrook
    }
233 2e5d83bb pbrook
    switch (s->command) {
234 2e5d83bb pbrook
    case 0x0:
235 2e5d83bb pbrook
        DPRINTF("Test Unit Ready\n");
236 2e5d83bb pbrook
        break;
237 2e5d83bb pbrook
    case 0x03:
238 2e5d83bb pbrook
        DPRINTF("Request Sense (len %d)\n", len);
239 2e5d83bb pbrook
        if (len < 4)
240 2e5d83bb pbrook
            goto fail;
241 2e5d83bb pbrook
        memset(buf, 0, 4);
242 2e5d83bb pbrook
        s->buf[0] = 0xf0;
243 2e5d83bb pbrook
        s->buf[1] = 0;
244 2e5d83bb pbrook
        s->buf[2] = s->sense;
245 2e5d83bb pbrook
        s->buf_len = 4;
246 2e5d83bb pbrook
        break;
247 2e5d83bb pbrook
    case 0x12:
248 7d8406be pbrook
        DPRINTF("Inquiry (len %d)\n", len);
249 2e5d83bb pbrook
        if (len < 36) {
250 2e5d83bb pbrook
            BADF("Inquiry buffer too small (%d)\n", len);
251 2e5d83bb pbrook
        }
252 2e5d83bb pbrook
        memset(s->buf, 0, 36);
253 2e5d83bb pbrook
        if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) {
254 2e5d83bb pbrook
            s->buf[0] = 5;
255 2e5d83bb pbrook
            s->buf[1] = 0x80;
256 7d8406be pbrook
            memcpy(&s->buf[16], "QEMU CD-ROM    ", 16);
257 2e5d83bb pbrook
        } else {
258 2e5d83bb pbrook
            s->buf[0] = 0;
259 2e5d83bb pbrook
            memcpy(&s->buf[16], "QEMU HARDDISK  ", 16);
260 2e5d83bb pbrook
        }
261 2e5d83bb pbrook
        memcpy(&s->buf[8], "QEMU   ", 8);
262 7d8406be pbrook
        memcpy(&s->buf[32], QEMU_VERSION, 4);
263 17acfe32 pbrook
        /* Identify device as SCSI-3 rev 1.
264 17acfe32 pbrook
           Some later commands are also implemented. */
265 17acfe32 pbrook
        s->buf[2] = 3;
266 2e5d83bb pbrook
        s->buf[3] = 2; /* Format 2 */
267 2e5d83bb pbrook
        s->buf[4] = 32;
268 2e5d83bb pbrook
        s->buf_len = 36;
269 2e5d83bb pbrook
        break;
270 2e5d83bb pbrook
    case 0x16:
271 2e5d83bb pbrook
        DPRINTF("Reserve(6)\n");
272 2e5d83bb pbrook
        if (buf[1] & 1)
273 2e5d83bb pbrook
            goto fail;
274 2e5d83bb pbrook
        break;
275 2e5d83bb pbrook
    case 0x17:
276 2e5d83bb pbrook
        DPRINTF("Release(6)\n");
277 2e5d83bb pbrook
        if (buf[1] & 1)
278 2e5d83bb pbrook
            goto fail;
279 2e5d83bb pbrook
        break;
280 2e5d83bb pbrook
    case 0x1a:
281 7d8406be pbrook
    case 0x5a:
282 17acfe32 pbrook
        {
283 17acfe32 pbrook
            char *p;
284 17acfe32 pbrook
            int page;
285 17acfe32 pbrook
286 17acfe32 pbrook
            page = buf[2] & 0x3f;
287 17acfe32 pbrook
            DPRINTF("Mode Sense (page %d, len %d)\n", page, len);
288 17acfe32 pbrook
            p = s->buf;
289 17acfe32 pbrook
            memset(p, 0, 4);
290 7d8406be pbrook
            s->buf[1] = 0; /* Default media type.  */
291 7d8406be pbrook
            s->buf[3] = 0; /* Block descriptor length.  */
292 17acfe32 pbrook
            if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) {
293 17acfe32 pbrook
                s->buf[2] = 0x80; /* Readonly.  */
294 17acfe32 pbrook
            }
295 17acfe32 pbrook
            p += 4;
296 17acfe32 pbrook
            if ((page == 8 || page == 0x3f)) {
297 17acfe32 pbrook
                /* Caching page.  */
298 17acfe32 pbrook
                p[0] = 8;
299 17acfe32 pbrook
                p[1] = 0x12;
300 17acfe32 pbrook
                p[2] = 4; /* WCE */
301 17acfe32 pbrook
                p += 19;
302 17acfe32 pbrook
            }
303 17acfe32 pbrook
            if ((page == 0x3f || page == 0x2a)
304 17acfe32 pbrook
                    && (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM)) {
305 17acfe32 pbrook
                /* CD Capabilities and Mechanical Status page. */
306 17acfe32 pbrook
                p[0] = 0x2a;
307 17acfe32 pbrook
                p[1] = 0x14;
308 17acfe32 pbrook
                p[2] = 3; // CD-R & CD-RW read
309 17acfe32 pbrook
                p[3] = 0; // Writing not supported
310 17acfe32 pbrook
                p[4] = 0x7f; /* Audio, composite, digital out,
311 17acfe32 pbrook
                                         mode 2 form 1&2, multi session */
312 17acfe32 pbrook
                p[5] = 0xff; /* CD DA, DA accurate, RW supported,
313 17acfe32 pbrook
                                         RW corrected, C2 errors, ISRC,
314 17acfe32 pbrook
                                         UPC, Bar code */
315 17acfe32 pbrook
                p[6] = 0x2d | (bdrv_is_locked(s->bdrv)? 2 : 0);
316 17acfe32 pbrook
                /* Locking supported, jumper present, eject, tray */
317 17acfe32 pbrook
                p[7] = 0; /* no volume & mute control, no
318 17acfe32 pbrook
                                      changer */
319 17acfe32 pbrook
                p[8] = (50 * 176) >> 8; // 50x read speed
320 17acfe32 pbrook
                p[9] = (50 * 176) & 0xff;
321 17acfe32 pbrook
                p[10] = 0 >> 8; // No volume
322 17acfe32 pbrook
                p[11] = 0 & 0xff;
323 17acfe32 pbrook
                p[12] = 2048 >> 8; // 2M buffer
324 17acfe32 pbrook
                p[13] = 2048 & 0xff;
325 17acfe32 pbrook
                p[14] = (16 * 176) >> 8; // 16x read speed current
326 17acfe32 pbrook
                p[15] = (16 * 176) & 0xff;
327 17acfe32 pbrook
                p[18] = (16 * 176) >> 8; // 16x write speed
328 17acfe32 pbrook
                p[19] = (16 * 176) & 0xff;
329 17acfe32 pbrook
                p[20] = (16 * 176) >> 8; // 16x write speed current
330 17acfe32 pbrook
                p[21] = (16 * 176) & 0xff;
331 17acfe32 pbrook
                p += 21;
332 17acfe32 pbrook
            }
333 17acfe32 pbrook
            s->buf_len = p - s->buf;
334 17acfe32 pbrook
            s->buf[0] = s->buf_len - 4;
335 17acfe32 pbrook
            if (s->buf_len > len)
336 17acfe32 pbrook
                s->buf_len = len;
337 7d8406be pbrook
        }
338 17acfe32 pbrook
        break;
339 17acfe32 pbrook
    case 0x1b:
340 17acfe32 pbrook
        DPRINTF("Start Stop Unit\n");
341 17acfe32 pbrook
        break;
342 17acfe32 pbrook
    case 0x1e:
343 17acfe32 pbrook
        DPRINTF("Prevent Allow Medium Removal (prevent = %d)\n", buf[4] & 3);
344 17acfe32 pbrook
        bdrv_set_locked(s->bdrv, buf[4] & 1);
345 2e5d83bb pbrook
        break;
346 2e5d83bb pbrook
    case 0x25:
347 2e5d83bb pbrook
        DPRINTF("Read Capacity\n");
348 2e5d83bb pbrook
        /* The normal LEN field for this command is zero.  */
349 2e5d83bb pbrook
        memset(s->buf, 0, 8);
350 2e5d83bb pbrook
        bdrv_get_geometry(s->bdrv, &nb_sectors);
351 2e5d83bb pbrook
        s->buf[0] = (nb_sectors >> 24) & 0xff;
352 2e5d83bb pbrook
        s->buf[1] = (nb_sectors >> 16) & 0xff;
353 2e5d83bb pbrook
        s->buf[2] = (nb_sectors >> 8) & 0xff;
354 2e5d83bb pbrook
        s->buf[3] = nb_sectors & 0xff;
355 2e5d83bb pbrook
        s->buf[4] = 0;
356 2e5d83bb pbrook
        s->buf[5] = 0;
357 7c22dd52 pbrook
        s->buf[6] = s->cluster_size * 2;
358 7c22dd52 pbrook
        s->buf[7] = 0;
359 2e5d83bb pbrook
        s->buf_len = 8;
360 2e5d83bb pbrook
        break;
361 2e5d83bb pbrook
    case 0x08:
362 2e5d83bb pbrook
    case 0x28:
363 2e5d83bb pbrook
        DPRINTF("Read (sector %d, count %d)\n", lba, len);
364 7c22dd52 pbrook
        s->sector = lba * s->cluster_size;
365 7c22dd52 pbrook
        s->sector_count = len * s->cluster_size;
366 2e5d83bb pbrook
        break;
367 2e5d83bb pbrook
    case 0x0a:
368 2e5d83bb pbrook
    case 0x2a:
369 2e5d83bb pbrook
        DPRINTF("Write (sector %d, count %d)\n", lba, len);
370 7c22dd52 pbrook
        s->sector = lba * s->cluster_size;
371 7c22dd52 pbrook
        s->sector_count = len * s->cluster_size;
372 2e5d83bb pbrook
        is_write = 1;
373 2e5d83bb pbrook
        break;
374 7d8406be pbrook
    case 0x35:
375 7d8406be pbrook
        DPRINTF("Syncronise cache (sector %d, count %d)\n", lba, len);
376 7a6cba61 pbrook
        bdrv_flush(s->bdrv);
377 7d8406be pbrook
        break;
378 2e5d83bb pbrook
    case 0x43:
379 2e5d83bb pbrook
        {
380 7c22dd52 pbrook
            int start_track, format, msf, toclen;
381 2e5d83bb pbrook
382 2e5d83bb pbrook
            msf = buf[1] & 2;
383 2e5d83bb pbrook
            format = buf[2] & 0xf;
384 2e5d83bb pbrook
            start_track = buf[6];
385 2e5d83bb pbrook
            bdrv_get_geometry(s->bdrv, &nb_sectors);
386 2e5d83bb pbrook
            DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1);
387 2e5d83bb pbrook
            switch(format) {
388 2e5d83bb pbrook
            case 0:
389 7c22dd52 pbrook
                toclen = cdrom_read_toc(nb_sectors, s->buf, msf, start_track);
390 2e5d83bb pbrook
                break;
391 2e5d83bb pbrook
            case 1:
392 2e5d83bb pbrook
                /* multi session : only a single session defined */
393 7c22dd52 pbrook
                toclen = 12;
394 2e5d83bb pbrook
                memset(s->buf, 0, 12);
395 2e5d83bb pbrook
                s->buf[1] = 0x0a;
396 2e5d83bb pbrook
                s->buf[2] = 0x01;
397 2e5d83bb pbrook
                s->buf[3] = 0x01;
398 2e5d83bb pbrook
                break;
399 2e5d83bb pbrook
            case 2:
400 7c22dd52 pbrook
                toclen = cdrom_read_toc_raw(nb_sectors, s->buf, msf, start_track);
401 2e5d83bb pbrook
                break;
402 2e5d83bb pbrook
            default:
403 7c22dd52 pbrook
                goto error_cmd;
404 7c22dd52 pbrook
            }
405 7c22dd52 pbrook
            if (toclen > 0) {
406 7c22dd52 pbrook
                if (len > toclen)
407 7c22dd52 pbrook
                  len = toclen;
408 7c22dd52 pbrook
                s->buf_len = len;
409 7c22dd52 pbrook
                break;
410 2e5d83bb pbrook
            }
411 7c22dd52 pbrook
        error_cmd:
412 7c22dd52 pbrook
            DPRINTF("Read TOC error\n");
413 7c22dd52 pbrook
            goto fail;
414 2e5d83bb pbrook
        }
415 17acfe32 pbrook
    case 0x46:
416 17acfe32 pbrook
        DPRINTF("Get Configuration (rt %d, maxlen %d)\n", buf[1] & 3, len);
417 17acfe32 pbrook
        memset(s->buf, 0, 8);
418 17acfe32 pbrook
        /* ??? This shoud probably return much more information.  For now
419 17acfe32 pbrook
           just return the basic header indicating the CD-ROM profile.  */
420 17acfe32 pbrook
        s->buf[7] = 8; // CD-ROM
421 17acfe32 pbrook
        s->buf_len = 8;
422 17acfe32 pbrook
        break;
423 2e5d83bb pbrook
    case 0x56:
424 2e5d83bb pbrook
        DPRINTF("Reserve(10)\n");
425 2e5d83bb pbrook
        if (buf[1] & 3)
426 2e5d83bb pbrook
            goto fail;
427 2e5d83bb pbrook
        break;
428 2e5d83bb pbrook
    case 0x57:
429 2e5d83bb pbrook
        DPRINTF("Release(10)\n");
430 2e5d83bb pbrook
        if (buf[1] & 3)
431 2e5d83bb pbrook
            goto fail;
432 2e5d83bb pbrook
        break;
433 2e5d83bb pbrook
    case 0xa0:
434 2e5d83bb pbrook
        DPRINTF("Report LUNs (len %d)\n", len);
435 2e5d83bb pbrook
        if (len < 16)
436 2e5d83bb pbrook
            goto fail;
437 2e5d83bb pbrook
        memset(s->buf, 0, 16);
438 2e5d83bb pbrook
        s->buf[3] = 8;
439 2e5d83bb pbrook
        s->buf_len = 16;
440 2e5d83bb pbrook
        break;
441 2e5d83bb pbrook
    default:
442 2e5d83bb pbrook
        DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
443 2e5d83bb pbrook
    fail:
444 2e5d83bb pbrook
        scsi_command_complete(s, SENSE_ILLEGAL_REQUEST);
445 2e5d83bb pbrook
        return 0;
446 2e5d83bb pbrook
    }
447 2e5d83bb pbrook
    if (s->sector_count == 0 && s->buf_len == 0) {
448 2e5d83bb pbrook
        scsi_command_complete(s, SENSE_NO_SENSE);
449 2e5d83bb pbrook
    }
450 7c22dd52 pbrook
    len = s->sector_count * 512 + s->buf_len;
451 2e5d83bb pbrook
    return is_write ? -len : len;
452 2e5d83bb pbrook
}
453 2e5d83bb pbrook
454 2e5d83bb pbrook
void scsi_disk_destroy(SCSIDevice *s)
455 2e5d83bb pbrook
{
456 2e5d83bb pbrook
    bdrv_close(s->bdrv);
457 2e5d83bb pbrook
    qemu_free(s);
458 2e5d83bb pbrook
}
459 2e5d83bb pbrook
460 2e5d83bb pbrook
SCSIDevice *scsi_disk_init(BlockDriverState *bdrv,
461 2e5d83bb pbrook
                           scsi_completionfn completion,
462 2e5d83bb pbrook
                           void *opaque)
463 2e5d83bb pbrook
{
464 2e5d83bb pbrook
    SCSIDevice *s;
465 2e5d83bb pbrook
466 2e5d83bb pbrook
    s = (SCSIDevice *)qemu_mallocz(sizeof(SCSIDevice));
467 2e5d83bb pbrook
    s->bdrv = bdrv;
468 2e5d83bb pbrook
    s->completion = completion;
469 2e5d83bb pbrook
    s->opaque = opaque;
470 2e5d83bb pbrook
    if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) {
471 7c22dd52 pbrook
        s->cluster_size = 4;
472 2e5d83bb pbrook
    } else {
473 7c22dd52 pbrook
        s->cluster_size = 1;
474 2e5d83bb pbrook
    }
475 2e5d83bb pbrook
476 2e5d83bb pbrook
    return s;
477 2e5d83bb pbrook
}