Statistics
| Branch: | Revision:

root / hw / scsi-disk.c @ ef816d83

History | View | Annotate | Download (31.7 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 a917d384 pbrook
 *
11 a917d384 pbrook
 * Note that this file only handles the SCSI architecture model and device
12 1d4db89c balrog
 * commands.  Emulation of interface/link layer protocols is handled by
13 1d4db89c balrog
 * the host adapter emulator.
14 2e5d83bb pbrook
 */
15 2e5d83bb pbrook
16 fa879c64 aliguori
#include <qemu-common.h>
17 fa879c64 aliguori
#include <sysemu.h>
18 2e5d83bb pbrook
//#define DEBUG_SCSI
19 2e5d83bb pbrook
20 2e5d83bb pbrook
#ifdef DEBUG_SCSI
21 001faf32 Blue Swirl
#define DPRINTF(fmt, ...) \
22 001faf32 Blue Swirl
do { printf("scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
23 2e5d83bb pbrook
#else
24 001faf32 Blue Swirl
#define DPRINTF(fmt, ...) do {} while(0)
25 2e5d83bb pbrook
#endif
26 2e5d83bb pbrook
27 001faf32 Blue Swirl
#define BADF(fmt, ...) \
28 001faf32 Blue Swirl
do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
29 2e5d83bb pbrook
30 87ecb68b pbrook
#include "qemu-common.h"
31 87ecb68b pbrook
#include "block.h"
32 87ecb68b pbrook
#include "scsi-disk.h"
33 2e5d83bb pbrook
34 2e5d83bb pbrook
#define SENSE_NO_SENSE        0
35 1aacf348 pbrook
#define SENSE_NOT_READY       2
36 4d611c9a pbrook
#define SENSE_HARDWARE_ERROR  4
37 2e5d83bb pbrook
#define SENSE_ILLEGAL_REQUEST 5
38 2e5d83bb pbrook
39 22864256 blueswir1
#define STATUS_GOOD            0
40 22864256 blueswir1
#define STATUS_CHECK_CONDITION 2
41 22864256 blueswir1
42 f0f72ffe aurel32
#define SCSI_DMA_BUF_SIZE    131072
43 57575058 balrog
#define SCSI_MAX_INQUIRY_LEN 256
44 a917d384 pbrook
45 ea8a5d7f aliguori
#define SCSI_REQ_STATUS_RETRY 0x01
46 ea8a5d7f aliguori
47 d52affa7 Gerd Hoffmann
typedef struct SCSIDiskState SCSIDiskState;
48 d52affa7 Gerd Hoffmann
49 a917d384 pbrook
typedef struct SCSIRequest {
50 d52affa7 Gerd Hoffmann
    SCSIBus *bus;
51 d52affa7 Gerd Hoffmann
    SCSIDiskState *dev;
52 2e5d83bb pbrook
    uint32_t tag;
53 e035b43d aliguori
    /* ??? We should probably keep track of whether the data transfer is
54 2e5d83bb pbrook
       a read or a write.  Currently we rely on the host getting it right.  */
55 a917d384 pbrook
    /* Both sector and sector_count are in terms of qemu 512 byte blocks.  */
56 e035b43d aliguori
    uint64_t sector;
57 e035b43d aliguori
    uint32_t sector_count;
58 c87c0672 aliguori
    struct iovec iov;
59 c87c0672 aliguori
    QEMUIOVector qiov;
60 4d611c9a pbrook
    BlockDriverAIOCB *aiocb;
61 a917d384 pbrook
    struct SCSIRequest *next;
62 ea8a5d7f aliguori
    uint32_t status;
63 a917d384 pbrook
} SCSIRequest;
64 a917d384 pbrook
65 d52affa7 Gerd Hoffmann
struct SCSIDiskState
66 a917d384 pbrook
{
67 d52affa7 Gerd Hoffmann
    SCSIDevice qdev;
68 d52affa7 Gerd Hoffmann
    DriveInfo *dinfo;
69 a917d384 pbrook
    SCSIRequest *requests;
70 a917d384 pbrook
    /* The qemu block layer uses a fixed 512 byte sector size.
71 a917d384 pbrook
       This is the number of 512 byte blocks in a single scsi sector.  */
72 a917d384 pbrook
    int cluster_size;
73 274fb0e1 aliguori
    uint64_t max_lba;
74 a917d384 pbrook
    int sense;
75 fa879c64 aliguori
    char drive_serial_str[21];
76 213189ab Markus Armbruster
    QEMUBH *bh;
77 2e5d83bb pbrook
};
78 2e5d83bb pbrook
79 a917d384 pbrook
/* Global pool of SCSIRequest structures.  */
80 a917d384 pbrook
static SCSIRequest *free_requests = NULL;
81 a917d384 pbrook
82 d52affa7 Gerd Hoffmann
static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag)
83 2e5d83bb pbrook
{
84 d52affa7 Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
85 a917d384 pbrook
    SCSIRequest *r;
86 a917d384 pbrook
87 a917d384 pbrook
    if (free_requests) {
88 a917d384 pbrook
        r = free_requests;
89 a917d384 pbrook
        free_requests = r->next;
90 a917d384 pbrook
    } else {
91 a917d384 pbrook
        r = qemu_malloc(sizeof(SCSIRequest));
92 c87c0672 aliguori
        r->iov.iov_base = qemu_memalign(512, SCSI_DMA_BUF_SIZE);
93 a917d384 pbrook
    }
94 d52affa7 Gerd Hoffmann
    r->bus = scsi_bus_from_device(d);
95 a917d384 pbrook
    r->dev = s;
96 a917d384 pbrook
    r->tag = tag;
97 a917d384 pbrook
    r->sector_count = 0;
98 c87c0672 aliguori
    r->iov.iov_len = 0;
99 a917d384 pbrook
    r->aiocb = NULL;
100 ea8a5d7f aliguori
    r->status = 0;
101 a917d384 pbrook
102 a917d384 pbrook
    r->next = s->requests;
103 a917d384 pbrook
    s->requests = r;
104 a917d384 pbrook
    return r;
105 2e5d83bb pbrook
}
106 2e5d83bb pbrook
107 a917d384 pbrook
static void scsi_remove_request(SCSIRequest *r)
108 4d611c9a pbrook
{
109 a917d384 pbrook
    SCSIRequest *last;
110 d52affa7 Gerd Hoffmann
    SCSIDiskState *s = r->dev;
111 a917d384 pbrook
112 a917d384 pbrook
    if (s->requests == r) {
113 a917d384 pbrook
        s->requests = r->next;
114 a917d384 pbrook
    } else {
115 a917d384 pbrook
        last = s->requests;
116 a917d384 pbrook
        while (last && last->next != r)
117 a917d384 pbrook
            last = last->next;
118 a917d384 pbrook
        if (last) {
119 a917d384 pbrook
            last->next = r->next;
120 a917d384 pbrook
        } else {
121 a917d384 pbrook
            BADF("Orphaned request\n");
122 a917d384 pbrook
        }
123 a917d384 pbrook
    }
124 a917d384 pbrook
    r->next = free_requests;
125 a917d384 pbrook
    free_requests = r;
126 4d611c9a pbrook
}
127 4d611c9a pbrook
128 d52affa7 Gerd Hoffmann
static SCSIRequest *scsi_find_request(SCSIDiskState *s, uint32_t tag)
129 4d611c9a pbrook
{
130 a917d384 pbrook
    SCSIRequest *r;
131 4d611c9a pbrook
132 a917d384 pbrook
    r = s->requests;
133 a917d384 pbrook
    while (r && r->tag != tag)
134 a917d384 pbrook
        r = r->next;
135 4d611c9a pbrook
136 a917d384 pbrook
    return r;
137 a917d384 pbrook
}
138 a917d384 pbrook
139 a917d384 pbrook
/* Helper function for command completion.  */
140 22864256 blueswir1
static void scsi_command_complete(SCSIRequest *r, int status, int sense)
141 a917d384 pbrook
{
142 d52affa7 Gerd Hoffmann
    SCSIDiskState *s = r->dev;
143 a917d384 pbrook
    uint32_t tag;
144 22864256 blueswir1
    DPRINTF("Command complete tag=0x%x status=%d sense=%d\n", r->tag, status, sense);
145 a917d384 pbrook
    s->sense = sense;
146 a917d384 pbrook
    tag = r->tag;
147 a917d384 pbrook
    scsi_remove_request(r);
148 d52affa7 Gerd Hoffmann
    r->bus->complete(r->bus, SCSI_REASON_DONE, tag, status);
149 4d611c9a pbrook
}
150 4d611c9a pbrook
151 4d611c9a pbrook
/* Cancel a pending data transfer.  */
152 8ccc2ace ths
static void scsi_cancel_io(SCSIDevice *d, uint32_t tag)
153 4d611c9a pbrook
{
154 d52affa7 Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
155 a917d384 pbrook
    SCSIRequest *r;
156 a917d384 pbrook
    DPRINTF("Cancel tag=0x%x\n", tag);
157 a917d384 pbrook
    r = scsi_find_request(s, tag);
158 a917d384 pbrook
    if (r) {
159 a917d384 pbrook
        if (r->aiocb)
160 a917d384 pbrook
            bdrv_aio_cancel(r->aiocb);
161 a917d384 pbrook
        r->aiocb = NULL;
162 a917d384 pbrook
        scsi_remove_request(r);
163 a917d384 pbrook
    }
164 a917d384 pbrook
}
165 a917d384 pbrook
166 a917d384 pbrook
static void scsi_read_complete(void * opaque, int ret)
167 a917d384 pbrook
{
168 a917d384 pbrook
    SCSIRequest *r = (SCSIRequest *)opaque;
169 a917d384 pbrook
170 a917d384 pbrook
    if (ret) {
171 a917d384 pbrook
        DPRINTF("IO error\n");
172 d52affa7 Gerd Hoffmann
        r->bus->complete(r->bus, SCSI_REASON_DATA, r->tag, 0);
173 22864256 blueswir1
        scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_NO_SENSE);
174 4d611c9a pbrook
        return;
175 4d611c9a pbrook
    }
176 0bf9e31a Blue Swirl
    DPRINTF("Data ready tag=0x%x len=%" PRId64 "\n", r->tag, r->iov.iov_len);
177 a917d384 pbrook
178 d52affa7 Gerd Hoffmann
    r->bus->complete(r->bus, SCSI_REASON_DATA, r->tag, r->iov.iov_len);
179 4d611c9a pbrook
}
180 4d611c9a pbrook
181 a917d384 pbrook
/* Read more data from scsi device into buffer.  */
182 8ccc2ace ths
static void scsi_read_data(SCSIDevice *d, uint32_t tag)
183 2e5d83bb pbrook
{
184 d52affa7 Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
185 a917d384 pbrook
    SCSIRequest *r;
186 2e5d83bb pbrook
    uint32_t n;
187 2e5d83bb pbrook
188 a917d384 pbrook
    r = scsi_find_request(s, tag);
189 a917d384 pbrook
    if (!r) {
190 a917d384 pbrook
        BADF("Bad read tag 0x%x\n", tag);
191 b1fa7164 blueswir1
        /* ??? This is the wrong error.  */
192 22864256 blueswir1
        scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
193 a917d384 pbrook
        return;
194 2e5d83bb pbrook
    }
195 a917d384 pbrook
    if (r->sector_count == (uint32_t)-1) {
196 0bf9e31a Blue Swirl
        DPRINTF("Read buf_len=%" PRId64 "\n", r->iov.iov_len);
197 a917d384 pbrook
        r->sector_count = 0;
198 d52affa7 Gerd Hoffmann
        r->bus->complete(r->bus, SCSI_REASON_DATA, r->tag, r->iov.iov_len);
199 a917d384 pbrook
        return;
200 2e5d83bb pbrook
    }
201 a917d384 pbrook
    DPRINTF("Read sector_count=%d\n", r->sector_count);
202 a917d384 pbrook
    if (r->sector_count == 0) {
203 22864256 blueswir1
        scsi_command_complete(r, STATUS_GOOD, SENSE_NO_SENSE);
204 a917d384 pbrook
        return;
205 2e5d83bb pbrook
    }
206 2e5d83bb pbrook
207 a917d384 pbrook
    n = r->sector_count;
208 a917d384 pbrook
    if (n > SCSI_DMA_BUF_SIZE / 512)
209 a917d384 pbrook
        n = SCSI_DMA_BUF_SIZE / 512;
210 a917d384 pbrook
211 c87c0672 aliguori
    r->iov.iov_len = n * 512;
212 c87c0672 aliguori
    qemu_iovec_init_external(&r->qiov, &r->iov, 1);
213 d52affa7 Gerd Hoffmann
    r->aiocb = bdrv_aio_readv(s->dinfo->bdrv, r->sector, &r->qiov, n,
214 c87c0672 aliguori
                              scsi_read_complete, r);
215 a917d384 pbrook
    if (r->aiocb == NULL)
216 22864256 blueswir1
        scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
217 a917d384 pbrook
    r->sector += n;
218 a917d384 pbrook
    r->sector_count -= n;
219 2e5d83bb pbrook
}
220 2e5d83bb pbrook
221 ea8a5d7f aliguori
static int scsi_handle_write_error(SCSIRequest *r, int error)
222 ea8a5d7f aliguori
{
223 d52affa7 Gerd Hoffmann
    BlockInterfaceErrorAction action = drive_get_onerror(r->dev->dinfo->bdrv);
224 ea8a5d7f aliguori
225 ea8a5d7f aliguori
    if (action == BLOCK_ERR_IGNORE)
226 ea8a5d7f aliguori
        return 0;
227 ea8a5d7f aliguori
228 ea8a5d7f aliguori
    if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC)
229 ea8a5d7f aliguori
            || action == BLOCK_ERR_STOP_ANY) {
230 ea8a5d7f aliguori
        r->status |= SCSI_REQ_STATUS_RETRY;
231 ea8a5d7f aliguori
        vm_stop(0);
232 ea8a5d7f aliguori
    } else {
233 ea8a5d7f aliguori
        scsi_command_complete(r, STATUS_CHECK_CONDITION,
234 ea8a5d7f aliguori
                SENSE_HARDWARE_ERROR);
235 ea8a5d7f aliguori
    }
236 ea8a5d7f aliguori
237 ea8a5d7f aliguori
    return 1;
238 ea8a5d7f aliguori
}
239 ea8a5d7f aliguori
240 4d611c9a pbrook
static void scsi_write_complete(void * opaque, int ret)
241 4d611c9a pbrook
{
242 a917d384 pbrook
    SCSIRequest *r = (SCSIRequest *)opaque;
243 a917d384 pbrook
    uint32_t len;
244 ea8a5d7f aliguori
    uint32_t n;
245 ea8a5d7f aliguori
246 ea8a5d7f aliguori
    r->aiocb = NULL;
247 4d611c9a pbrook
248 4d611c9a pbrook
    if (ret) {
249 ea8a5d7f aliguori
        if (scsi_handle_write_error(r, -ret))
250 ea8a5d7f aliguori
            return;
251 4d611c9a pbrook
    }
252 4d611c9a pbrook
253 c87c0672 aliguori
    n = r->iov.iov_len / 512;
254 ea8a5d7f aliguori
    r->sector += n;
255 ea8a5d7f aliguori
    r->sector_count -= n;
256 a917d384 pbrook
    if (r->sector_count == 0) {
257 22864256 blueswir1
        scsi_command_complete(r, STATUS_GOOD, SENSE_NO_SENSE);
258 a917d384 pbrook
    } else {
259 a917d384 pbrook
        len = r->sector_count * 512;
260 a917d384 pbrook
        if (len > SCSI_DMA_BUF_SIZE) {
261 a917d384 pbrook
            len = SCSI_DMA_BUF_SIZE;
262 a917d384 pbrook
        }
263 c87c0672 aliguori
        r->iov.iov_len = len;
264 a917d384 pbrook
        DPRINTF("Write complete tag=0x%x more=%d\n", r->tag, len);
265 d52affa7 Gerd Hoffmann
        r->bus->complete(r->bus, SCSI_REASON_DATA, r->tag, len);
266 4d611c9a pbrook
    }
267 4d611c9a pbrook
}
268 4d611c9a pbrook
269 ea8a5d7f aliguori
static void scsi_write_request(SCSIRequest *r)
270 ea8a5d7f aliguori
{
271 d52affa7 Gerd Hoffmann
    SCSIDiskState *s = r->dev;
272 ea8a5d7f aliguori
    uint32_t n;
273 ea8a5d7f aliguori
274 c87c0672 aliguori
    n = r->iov.iov_len / 512;
275 ea8a5d7f aliguori
    if (n) {
276 c87c0672 aliguori
        qemu_iovec_init_external(&r->qiov, &r->iov, 1);
277 d52affa7 Gerd Hoffmann
        r->aiocb = bdrv_aio_writev(s->dinfo->bdrv, r->sector, &r->qiov, n,
278 c87c0672 aliguori
                                   scsi_write_complete, r);
279 ea8a5d7f aliguori
        if (r->aiocb == NULL)
280 ea8a5d7f aliguori
            scsi_command_complete(r, STATUS_CHECK_CONDITION,
281 ea8a5d7f aliguori
                                  SENSE_HARDWARE_ERROR);
282 ea8a5d7f aliguori
    } else {
283 ea8a5d7f aliguori
        /* Invoke completion routine to fetch data from host.  */
284 ea8a5d7f aliguori
        scsi_write_complete(r, 0);
285 ea8a5d7f aliguori
    }
286 ea8a5d7f aliguori
}
287 ea8a5d7f aliguori
288 4d611c9a pbrook
/* Write data to a scsi device.  Returns nonzero on failure.
289 4d611c9a pbrook
   The transfer may complete asynchronously.  */
290 8ccc2ace ths
static int scsi_write_data(SCSIDevice *d, uint32_t tag)
291 2e5d83bb pbrook
{
292 d52affa7 Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
293 a917d384 pbrook
    SCSIRequest *r;
294 2e5d83bb pbrook
295 a917d384 pbrook
    DPRINTF("Write data tag=0x%x\n", tag);
296 a917d384 pbrook
    r = scsi_find_request(s, tag);
297 a917d384 pbrook
    if (!r) {
298 a917d384 pbrook
        BADF("Bad write tag 0x%x\n", tag);
299 22864256 blueswir1
        scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
300 2e5d83bb pbrook
        return 1;
301 2e5d83bb pbrook
    }
302 ea8a5d7f aliguori
303 a917d384 pbrook
    if (r->aiocb)
304 a917d384 pbrook
        BADF("Data transfer already in progress\n");
305 ea8a5d7f aliguori
306 ea8a5d7f aliguori
    scsi_write_request(r);
307 2e5d83bb pbrook
308 a917d384 pbrook
    return 0;
309 a917d384 pbrook
}
310 2e5d83bb pbrook
311 213189ab Markus Armbruster
static void scsi_dma_restart_bh(void *opaque)
312 ea8a5d7f aliguori
{
313 d52affa7 Gerd Hoffmann
    SCSIDiskState *s = opaque;
314 ea8a5d7f aliguori
    SCSIRequest *r = s->requests;
315 213189ab Markus Armbruster
316 213189ab Markus Armbruster
    qemu_bh_delete(s->bh);
317 213189ab Markus Armbruster
    s->bh = NULL;
318 ea8a5d7f aliguori
319 ea8a5d7f aliguori
    while (r) {
320 ea8a5d7f aliguori
        if (r->status & SCSI_REQ_STATUS_RETRY) {
321 ea8a5d7f aliguori
            r->status &= ~SCSI_REQ_STATUS_RETRY;
322 ea8a5d7f aliguori
            scsi_write_request(r); 
323 ea8a5d7f aliguori
        }
324 ea8a5d7f aliguori
        r = r->next;
325 ea8a5d7f aliguori
    }
326 ea8a5d7f aliguori
}
327 ea8a5d7f aliguori
328 213189ab Markus Armbruster
static void scsi_dma_restart_cb(void *opaque, int running, int reason)
329 213189ab Markus Armbruster
{
330 d52affa7 Gerd Hoffmann
    SCSIDiskState *s = opaque;
331 213189ab Markus Armbruster
332 213189ab Markus Armbruster
    if (!running)
333 213189ab Markus Armbruster
        return;
334 213189ab Markus Armbruster
335 213189ab Markus Armbruster
    if (!s->bh) {
336 213189ab Markus Armbruster
        s->bh = qemu_bh_new(scsi_dma_restart_bh, s);
337 213189ab Markus Armbruster
        qemu_bh_schedule(s->bh);
338 213189ab Markus Armbruster
    }
339 213189ab Markus Armbruster
}
340 213189ab Markus Armbruster
341 a917d384 pbrook
/* Return a pointer to the data buffer.  */
342 8ccc2ace ths
static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag)
343 a917d384 pbrook
{
344 d52affa7 Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
345 a917d384 pbrook
    SCSIRequest *r;
346 2e5d83bb pbrook
347 a917d384 pbrook
    r = scsi_find_request(s, tag);
348 a917d384 pbrook
    if (!r) {
349 a917d384 pbrook
        BADF("Bad buffer tag 0x%x\n", tag);
350 a917d384 pbrook
        return NULL;
351 4d611c9a pbrook
    }
352 3f4cb3d3 blueswir1
    return (uint8_t *)r->iov.iov_base;
353 2e5d83bb pbrook
}
354 2e5d83bb pbrook
355 2e5d83bb pbrook
/* Execute a scsi command.  Returns the length of the data expected by the
356 2e5d83bb pbrook
   command.  This will be Positive for data transfers from the device
357 2e5d83bb pbrook
   (eg. disk reads), negative for transfers to the device (eg. disk writes),
358 2e5d83bb pbrook
   and zero if the command does not transfer any data.  */
359 2e5d83bb pbrook
360 8ccc2ace ths
static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
361 8ccc2ace ths
                                 uint8_t *buf, int lun)
362 2e5d83bb pbrook
{
363 d52affa7 Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
364 96b8f136 ths
    uint64_t nb_sectors;
365 86106e59 aliguori
    uint64_t lba;
366 2e5d83bb pbrook
    uint32_t len;
367 2e5d83bb pbrook
    int cmdlen;
368 2e5d83bb pbrook
    int is_write;
369 a917d384 pbrook
    uint8_t command;
370 a917d384 pbrook
    uint8_t *outbuf;
371 a917d384 pbrook
    SCSIRequest *r;
372 a917d384 pbrook
373 a917d384 pbrook
    command = buf[0];
374 a917d384 pbrook
    r = scsi_find_request(s, tag);
375 a917d384 pbrook
    if (r) {
376 a917d384 pbrook
        BADF("Tag 0x%x already in use\n", tag);
377 8ccc2ace ths
        scsi_cancel_io(d, tag);
378 a917d384 pbrook
    }
379 a917d384 pbrook
    /* ??? Tags are not unique for different luns.  We only implement a
380 a917d384 pbrook
       single lun, so this should not matter.  */
381 d52affa7 Gerd Hoffmann
    r = scsi_new_request(d, tag);
382 3f4cb3d3 blueswir1
    outbuf = (uint8_t *)r->iov.iov_base;
383 2e5d83bb pbrook
    is_write = 0;
384 a917d384 pbrook
    DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]);
385 a917d384 pbrook
    switch (command >> 5) {
386 2e5d83bb pbrook
    case 0:
387 86106e59 aliguori
        lba = (uint64_t) buf[3] | ((uint64_t) buf[2] << 8) |
388 86106e59 aliguori
              (((uint64_t) buf[1] & 0x1f) << 16);
389 2e5d83bb pbrook
        len = buf[4];
390 2e5d83bb pbrook
        cmdlen = 6;
391 2e5d83bb pbrook
        break;
392 2e5d83bb pbrook
    case 1:
393 2e5d83bb pbrook
    case 2:
394 86106e59 aliguori
        lba = (uint64_t) buf[5] | ((uint64_t) buf[4] << 8) |
395 86106e59 aliguori
              ((uint64_t) buf[3] << 16) | ((uint64_t) buf[2] << 24);
396 2e5d83bb pbrook
        len = buf[8] | (buf[7] << 8);
397 2e5d83bb pbrook
        cmdlen = 10;
398 2e5d83bb pbrook
        break;
399 2e5d83bb pbrook
    case 4:
400 86106e59 aliguori
        lba = (uint64_t) buf[9] | ((uint64_t) buf[8] << 8) |
401 86106e59 aliguori
              ((uint64_t) buf[7] << 16) | ((uint64_t) buf[6] << 24) |
402 86106e59 aliguori
              ((uint64_t) buf[5] << 32) | ((uint64_t) buf[4] << 40) |
403 86106e59 aliguori
              ((uint64_t) buf[3] << 48) | ((uint64_t) buf[2] << 56);
404 2e5d83bb pbrook
        len = buf[13] | (buf[12] << 8) | (buf[11] << 16) | (buf[10] << 24);
405 2e5d83bb pbrook
        cmdlen = 16;
406 2e5d83bb pbrook
        break;
407 2e5d83bb pbrook
    case 5:
408 86106e59 aliguori
        lba = (uint64_t) buf[5] | ((uint64_t) buf[4] << 8) |
409 86106e59 aliguori
              ((uint64_t) buf[3] << 16) | ((uint64_t) buf[2] << 24);
410 2e5d83bb pbrook
        len = buf[9] | (buf[8] << 8) | (buf[7] << 16) | (buf[6] << 24);
411 2e5d83bb pbrook
        cmdlen = 12;
412 2e5d83bb pbrook
        break;
413 2e5d83bb pbrook
    default:
414 a917d384 pbrook
        BADF("Unsupported command length, command %x\n", command);
415 2e5d83bb pbrook
        goto fail;
416 2e5d83bb pbrook
    }
417 2e5d83bb pbrook
#ifdef DEBUG_SCSI
418 2e5d83bb pbrook
    {
419 2e5d83bb pbrook
        int i;
420 2e5d83bb pbrook
        for (i = 1; i < cmdlen; i++) {
421 2e5d83bb pbrook
            printf(" 0x%02x", buf[i]);
422 2e5d83bb pbrook
        }
423 2e5d83bb pbrook
        printf("\n");
424 2e5d83bb pbrook
    }
425 2e5d83bb pbrook
#endif
426 0fc5c15a pbrook
    if (lun || buf[1] >> 5) {
427 2e5d83bb pbrook
        /* Only LUN 0 supported.  */
428 0fc5c15a pbrook
        DPRINTF("Unimplemented LUN %d\n", lun ? lun : buf[1] >> 5);
429 22864256 blueswir1
        if (command != 0x03 && command != 0x12) /* REQUEST SENSE and INQUIRY */
430 22864256 blueswir1
            goto fail;
431 2e5d83bb pbrook
    }
432 a917d384 pbrook
    switch (command) {
433 2e5d83bb pbrook
    case 0x0:
434 2e5d83bb pbrook
        DPRINTF("Test Unit Ready\n");
435 d52affa7 Gerd Hoffmann
        if (!bdrv_is_inserted(s->dinfo->bdrv))
436 58a2c436 blueswir1
            goto notready;
437 2e5d83bb pbrook
        break;
438 2e5d83bb pbrook
    case 0x03:
439 2e5d83bb pbrook
        DPRINTF("Request Sense (len %d)\n", len);
440 2e5d83bb pbrook
        if (len < 4)
441 2e5d83bb pbrook
            goto fail;
442 67cd24a8 ths
        memset(outbuf, 0, 4);
443 c87c0672 aliguori
        r->iov.iov_len = 4;
444 ed6a9b30 blueswir1
        if (s->sense == SENSE_NOT_READY && len >= 18) {
445 ed6a9b30 blueswir1
            memset(outbuf, 0, 18);
446 c87c0672 aliguori
            r->iov.iov_len = 18;
447 ed6a9b30 blueswir1
            outbuf[7] = 10;
448 ed6a9b30 blueswir1
            /* asc 0x3a, ascq 0: Medium not present */
449 ed6a9b30 blueswir1
            outbuf[12] = 0x3a;
450 ed6a9b30 blueswir1
            outbuf[13] = 0;
451 ed6a9b30 blueswir1
        }
452 a917d384 pbrook
        outbuf[0] = 0xf0;
453 a917d384 pbrook
        outbuf[1] = 0;
454 a917d384 pbrook
        outbuf[2] = s->sense;
455 2e5d83bb pbrook
        break;
456 2e5d83bb pbrook
    case 0x12:
457 7d8406be pbrook
        DPRINTF("Inquiry (len %d)\n", len);
458 1d4db89c balrog
        if (buf[1] & 0x2) {
459 1d4db89c balrog
            /* Command support data - optional, not implemented */
460 1d4db89c balrog
            BADF("optional INQUIRY command support request not implemented\n");
461 1d4db89c balrog
            goto fail;
462 1d4db89c balrog
        }
463 1d4db89c balrog
        else if (buf[1] & 0x1) {
464 1d4db89c balrog
            /* Vital product data */
465 1d4db89c balrog
            uint8_t page_code = buf[2];
466 1d4db89c balrog
            if (len < 4) {
467 1d4db89c balrog
                BADF("Error: Inquiry (EVPD[%02X]) buffer size %d is "
468 1d4db89c balrog
                     "less than 4\n", page_code, len);
469 1d4db89c balrog
                goto fail;
470 1d4db89c balrog
            }
471 1d4db89c balrog
472 1d4db89c balrog
            switch (page_code) {
473 1d4db89c balrog
                case 0x00:
474 1d4db89c balrog
                    {
475 1d4db89c balrog
                        /* Supported page codes, mandatory */
476 1d4db89c balrog
                        DPRINTF("Inquiry EVPD[Supported pages] "
477 1d4db89c balrog
                                "buffer size %d\n", len);
478 1d4db89c balrog
479 c87c0672 aliguori
                        r->iov.iov_len = 0;
480 1d4db89c balrog
481 d52affa7 Gerd Hoffmann
                        if (bdrv_get_type_hint(s->dinfo->bdrv) == BDRV_TYPE_CDROM) {
482 c87c0672 aliguori
                            outbuf[r->iov.iov_len++] = 5;
483 1d4db89c balrog
                        } else {
484 c87c0672 aliguori
                            outbuf[r->iov.iov_len++] = 0;
485 1d4db89c balrog
                        }
486 1d4db89c balrog
487 c87c0672 aliguori
                        outbuf[r->iov.iov_len++] = 0x00; // this page
488 c87c0672 aliguori
                        outbuf[r->iov.iov_len++] = 0x00;
489 c87c0672 aliguori
                        outbuf[r->iov.iov_len++] = 3;    // number of pages
490 c87c0672 aliguori
                        outbuf[r->iov.iov_len++] = 0x00; // list of supported pages (this page)
491 c87c0672 aliguori
                        outbuf[r->iov.iov_len++] = 0x80; // unit serial number
492 c87c0672 aliguori
                        outbuf[r->iov.iov_len++] = 0x83; // device identification
493 1d4db89c balrog
                    }
494 1d4db89c balrog
                    break;
495 1d4db89c balrog
                case 0x80:
496 1d4db89c balrog
                    {
497 fa879c64 aliguori
                        int l;
498 fa879c64 aliguori
499 1d4db89c balrog
                        /* Device serial number, optional */
500 1d4db89c balrog
                        if (len < 4) {
501 1d4db89c balrog
                            BADF("Error: EVPD[Serial number] Inquiry buffer "
502 1d4db89c balrog
                                 "size %d too small, %d needed\n", len, 4);
503 1d4db89c balrog
                            goto fail;
504 1d4db89c balrog
                        }
505 1d4db89c balrog
506 1d4db89c balrog
                        DPRINTF("Inquiry EVPD[Serial number] buffer size %d\n", len);
507 fa879c64 aliguori
                        l = MIN(len, strlen(s->drive_serial_str));
508 1d4db89c balrog
509 c87c0672 aliguori
                        r->iov.iov_len = 0;
510 1d4db89c balrog
511 1d4db89c balrog
                        /* Supported page codes */
512 d52affa7 Gerd Hoffmann
                        if (bdrv_get_type_hint(s->dinfo->bdrv) == BDRV_TYPE_CDROM) {
513 c87c0672 aliguori
                            outbuf[r->iov.iov_len++] = 5;
514 1d4db89c balrog
                        } else {
515 c87c0672 aliguori
                            outbuf[r->iov.iov_len++] = 0;
516 1d4db89c balrog
                        }
517 1d4db89c balrog
518 c87c0672 aliguori
                        outbuf[r->iov.iov_len++] = 0x80; // this page
519 c87c0672 aliguori
                        outbuf[r->iov.iov_len++] = 0x00;
520 c87c0672 aliguori
                        outbuf[r->iov.iov_len++] = l;
521 c87c0672 aliguori
                        memcpy(&outbuf[r->iov.iov_len], s->drive_serial_str, l);
522 c87c0672 aliguori
                        r->iov.iov_len += l;
523 1d4db89c balrog
                    }
524 1d4db89c balrog
525 1d4db89c balrog
                    break;
526 1d4db89c balrog
                case 0x83:
527 1d4db89c balrog
                    {
528 1d4db89c balrog
                        /* Device identification page, mandatory */
529 1d4db89c balrog
                        int max_len = 255 - 8;
530 d52affa7 Gerd Hoffmann
                        int id_len = strlen(bdrv_get_device_name(s->dinfo->bdrv));
531 1d4db89c balrog
                        if (id_len > max_len)
532 1d4db89c balrog
                            id_len = max_len;
533 1d4db89c balrog
534 1d4db89c balrog
                        DPRINTF("Inquiry EVPD[Device identification] "
535 1d4db89c balrog
                                "buffer size %d\n", len);
536 c87c0672 aliguori
                        r->iov.iov_len = 0;
537 d52affa7 Gerd Hoffmann
                        if (bdrv_get_type_hint(s->dinfo->bdrv) == BDRV_TYPE_CDROM) {
538 c87c0672 aliguori
                            outbuf[r->iov.iov_len++] = 5;
539 1d4db89c balrog
                        } else {
540 c87c0672 aliguori
                            outbuf[r->iov.iov_len++] = 0;
541 1d4db89c balrog
                        }
542 1d4db89c balrog
543 c87c0672 aliguori
                        outbuf[r->iov.iov_len++] = 0x83; // this page
544 c87c0672 aliguori
                        outbuf[r->iov.iov_len++] = 0x00;
545 c87c0672 aliguori
                        outbuf[r->iov.iov_len++] = 3 + id_len;
546 1d4db89c balrog
547 c87c0672 aliguori
                        outbuf[r->iov.iov_len++] = 0x2; // ASCII
548 c87c0672 aliguori
                        outbuf[r->iov.iov_len++] = 0;   // not officially assigned
549 c87c0672 aliguori
                        outbuf[r->iov.iov_len++] = 0;   // reserved
550 c87c0672 aliguori
                        outbuf[r->iov.iov_len++] = id_len; // length of data following
551 1d4db89c balrog
552 c87c0672 aliguori
                        memcpy(&outbuf[r->iov.iov_len],
553 d52affa7 Gerd Hoffmann
                               bdrv_get_device_name(s->dinfo->bdrv), id_len);
554 c87c0672 aliguori
                        r->iov.iov_len += id_len;
555 1d4db89c balrog
                    }
556 1d4db89c balrog
                    break;
557 1d4db89c balrog
                default:
558 1d4db89c balrog
                    BADF("Error: unsupported Inquiry (EVPD[%02X]) "
559 1d4db89c balrog
                         "buffer size %d\n", page_code, len);
560 1d4db89c balrog
                    goto fail;
561 1d4db89c balrog
            }
562 1d4db89c balrog
            /* done with EVPD */
563 1d4db89c balrog
            break;
564 1d4db89c balrog
        }
565 1d4db89c balrog
        else {
566 1d4db89c balrog
            /* Standard INQUIRY data */
567 1d4db89c balrog
            if (buf[2] != 0) {
568 1d4db89c balrog
                BADF("Error: Inquiry (STANDARD) page or code "
569 1d4db89c balrog
                     "is non-zero [%02X]\n", buf[2]);
570 1d4db89c balrog
                goto fail;
571 1d4db89c balrog
            }
572 1d4db89c balrog
573 1d4db89c balrog
            /* PAGE CODE == 0 */
574 1d4db89c balrog
            if (len < 5) {
575 1d4db89c balrog
                BADF("Error: Inquiry (STANDARD) buffer size %d "
576 1d4db89c balrog
                     "is less than 5\n", len);
577 1d4db89c balrog
                goto fail;
578 1d4db89c balrog
            }
579 1d4db89c balrog
580 1d4db89c balrog
            if (len < 36) {
581 1d4db89c balrog
                BADF("Error: Inquiry (STANDARD) buffer size %d "
582 1d4db89c balrog
                     "is less than 36 (TODO: only 5 required)\n", len);
583 1d4db89c balrog
            }
584 2e5d83bb pbrook
        }
585 57575058 balrog
586 57575058 balrog
        if(len > SCSI_MAX_INQUIRY_LEN)
587 57575058 balrog
            len = SCSI_MAX_INQUIRY_LEN;
588 57575058 balrog
589 57575058 balrog
        memset(outbuf, 0, len);
590 22864256 blueswir1
591 22864256 blueswir1
        if (lun || buf[1] >> 5) {
592 22864256 blueswir1
            outbuf[0] = 0x7f;        /* LUN not supported */
593 d52affa7 Gerd Hoffmann
        } else if (bdrv_get_type_hint(s->dinfo->bdrv) == BDRV_TYPE_CDROM) {
594 a917d384 pbrook
            outbuf[0] = 5;
595 a917d384 pbrook
            outbuf[1] = 0x80;
596 a917d384 pbrook
            memcpy(&outbuf[16], "QEMU CD-ROM    ", 16);
597 2e5d83bb pbrook
        } else {
598 a917d384 pbrook
            outbuf[0] = 0;
599 a917d384 pbrook
            memcpy(&outbuf[16], "QEMU HARDDISK  ", 16);
600 2e5d83bb pbrook
        }
601 a917d384 pbrook
        memcpy(&outbuf[8], "QEMU   ", 8);
602 a917d384 pbrook
        memcpy(&outbuf[32], QEMU_VERSION, 4);
603 17acfe32 pbrook
        /* Identify device as SCSI-3 rev 1.
604 17acfe32 pbrook
           Some later commands are also implemented. */
605 a917d384 pbrook
        outbuf[2] = 3;
606 a917d384 pbrook
        outbuf[3] = 2; /* Format 2 */
607 57575058 balrog
        outbuf[4] = len - 5; /* Additional Length = (Len - 1) - 4 */
608 a917d384 pbrook
        /* Sync data transfer and TCQ.  */
609 d52affa7 Gerd Hoffmann
        outbuf[7] = 0x10 | (r->bus->tcq ? 0x02 : 0);
610 c87c0672 aliguori
        r->iov.iov_len = len;
611 2e5d83bb pbrook
        break;
612 2e5d83bb pbrook
    case 0x16:
613 2e5d83bb pbrook
        DPRINTF("Reserve(6)\n");
614 2e5d83bb pbrook
        if (buf[1] & 1)
615 2e5d83bb pbrook
            goto fail;
616 2e5d83bb pbrook
        break;
617 2e5d83bb pbrook
    case 0x17:
618 2e5d83bb pbrook
        DPRINTF("Release(6)\n");
619 2e5d83bb pbrook
        if (buf[1] & 1)
620 2e5d83bb pbrook
            goto fail;
621 2e5d83bb pbrook
        break;
622 2e5d83bb pbrook
    case 0x1a:
623 7d8406be pbrook
    case 0x5a:
624 17acfe32 pbrook
        {
625 a917d384 pbrook
            uint8_t *p;
626 17acfe32 pbrook
            int page;
627 17acfe32 pbrook
628 17acfe32 pbrook
            page = buf[2] & 0x3f;
629 17acfe32 pbrook
            DPRINTF("Mode Sense (page %d, len %d)\n", page, len);
630 a917d384 pbrook
            p = outbuf;
631 17acfe32 pbrook
            memset(p, 0, 4);
632 a917d384 pbrook
            outbuf[1] = 0; /* Default media type.  */
633 a917d384 pbrook
            outbuf[3] = 0; /* Block descriptor length.  */
634 d52affa7 Gerd Hoffmann
            if (bdrv_get_type_hint(s->dinfo->bdrv) == BDRV_TYPE_CDROM) {
635 a917d384 pbrook
                outbuf[2] = 0x80; /* Readonly.  */
636 17acfe32 pbrook
            }
637 17acfe32 pbrook
            p += 4;
638 5e65a310 blueswir1
            if (page == 4) {
639 5e65a310 blueswir1
                int cylinders, heads, secs;
640 5e65a310 blueswir1
641 5e65a310 blueswir1
                /* Rigid disk device geometry page. */
642 5e65a310 blueswir1
                p[0] = 4;
643 5e65a310 blueswir1
                p[1] = 0x16;
644 5e65a310 blueswir1
                /* if a geometry hint is available, use it */
645 d52affa7 Gerd Hoffmann
                bdrv_get_geometry_hint(s->dinfo->bdrv, &cylinders, &heads, &secs);
646 5e65a310 blueswir1
                p[2] = (cylinders >> 16) & 0xff;
647 5e65a310 blueswir1
                p[3] = (cylinders >> 8) & 0xff;
648 5e65a310 blueswir1
                p[4] = cylinders & 0xff;
649 5e65a310 blueswir1
                p[5] = heads & 0xff;
650 5e65a310 blueswir1
                /* Write precomp start cylinder, disabled */
651 5e65a310 blueswir1
                p[6] = (cylinders >> 16) & 0xff;
652 5e65a310 blueswir1
                p[7] = (cylinders >> 8) & 0xff;
653 5e65a310 blueswir1
                p[8] = cylinders & 0xff;
654 5e65a310 blueswir1
                /* Reduced current start cylinder, disabled */
655 5e65a310 blueswir1
                p[9] = (cylinders >> 16) & 0xff;
656 5e65a310 blueswir1
                p[10] = (cylinders >> 8) & 0xff;
657 5e65a310 blueswir1
                p[11] = cylinders & 0xff;
658 5e65a310 blueswir1
                /* Device step rate [ns], 200ns */
659 5e65a310 blueswir1
                p[12] = 0;
660 5e65a310 blueswir1
                p[13] = 200;
661 5e65a310 blueswir1
                /* Landing zone cylinder */
662 5e65a310 blueswir1
                p[14] = 0xff;
663 5e65a310 blueswir1
                p[15] =  0xff;
664 5e65a310 blueswir1
                p[16] = 0xff;
665 5e65a310 blueswir1
                /* Medium rotation rate [rpm], 5400 rpm */
666 5e65a310 blueswir1
                p[20] = (5400 >> 8) & 0xff;
667 5e65a310 blueswir1
                p[21] = 5400 & 0xff;
668 5e65a310 blueswir1
                p += 0x16;
669 5e65a310 blueswir1
            } else if (page == 5) {
670 5e65a310 blueswir1
                int cylinders, heads, secs;
671 5e65a310 blueswir1
672 5e65a310 blueswir1
                /* Flexible disk device geometry page. */
673 5e65a310 blueswir1
                p[0] = 5;
674 5e65a310 blueswir1
                p[1] = 0x1e;
675 5e65a310 blueswir1
                /* Transfer rate [kbit/s], 5Mbit/s */
676 5e65a310 blueswir1
                p[2] = 5000 >> 8;
677 5e65a310 blueswir1
                p[3] = 5000 & 0xff;
678 5e65a310 blueswir1
                /* if a geometry hint is available, use it */
679 d52affa7 Gerd Hoffmann
                bdrv_get_geometry_hint(s->dinfo->bdrv, &cylinders, &heads, &secs);
680 5e65a310 blueswir1
                p[4] = heads & 0xff;
681 5e65a310 blueswir1
                p[5] = secs & 0xff;
682 5e65a310 blueswir1
                p[6] = s->cluster_size * 2;
683 5e65a310 blueswir1
                p[8] = (cylinders >> 8) & 0xff;
684 5e65a310 blueswir1
                p[9] = cylinders & 0xff;
685 5e65a310 blueswir1
                /* Write precomp start cylinder, disabled */
686 5e65a310 blueswir1
                p[10] = (cylinders >> 8) & 0xff;
687 5e65a310 blueswir1
                p[11] = cylinders & 0xff;
688 5e65a310 blueswir1
                /* Reduced current start cylinder, disabled */
689 5e65a310 blueswir1
                p[12] = (cylinders >> 8) & 0xff;
690 5e65a310 blueswir1
                p[13] = cylinders & 0xff;
691 5e65a310 blueswir1
                /* Device step rate [100us], 100us */
692 5e65a310 blueswir1
                p[14] = 0;
693 5e65a310 blueswir1
                p[15] = 1;
694 5e65a310 blueswir1
                /* Device step pulse width [us], 1us */
695 5e65a310 blueswir1
                p[16] = 1;
696 5e65a310 blueswir1
                /* Device head settle delay [100us], 100us */
697 5e65a310 blueswir1
                p[17] = 0;
698 5e65a310 blueswir1
                p[18] = 1;
699 5e65a310 blueswir1
                /* Motor on delay [0.1s], 0.1s */
700 5e65a310 blueswir1
                p[19] = 1;
701 5e65a310 blueswir1
                /* Motor off delay [0.1s], 0.1s */
702 5e65a310 blueswir1
                p[20] = 1;
703 5e65a310 blueswir1
                /* Medium rotation rate [rpm], 5400 rpm */
704 5e65a310 blueswir1
                p[28] = (5400 >> 8) & 0xff;
705 5e65a310 blueswir1
                p[29] = 5400 & 0xff;
706 5e65a310 blueswir1
                p += 0x1e;
707 5e65a310 blueswir1
            } else if ((page == 8 || page == 0x3f)) {
708 17acfe32 pbrook
                /* Caching page.  */
709 67cd24a8 ths
                memset(p,0,20);
710 17acfe32 pbrook
                p[0] = 8;
711 17acfe32 pbrook
                p[1] = 0x12;
712 e900a7b7 Christoph Hellwig
                if (bdrv_enable_write_cache(s->dinfo->bdrv)) {
713 e900a7b7 Christoph Hellwig
                     p[2] = 4; /* WCE */
714 e900a7b7 Christoph Hellwig
                }
715 67cd24a8 ths
                p += 20;
716 17acfe32 pbrook
            }
717 17acfe32 pbrook
            if ((page == 0x3f || page == 0x2a)
718 d52affa7 Gerd Hoffmann
                    && (bdrv_get_type_hint(s->dinfo->bdrv) == BDRV_TYPE_CDROM)) {
719 17acfe32 pbrook
                /* CD Capabilities and Mechanical Status page. */
720 17acfe32 pbrook
                p[0] = 0x2a;
721 17acfe32 pbrook
                p[1] = 0x14;
722 17acfe32 pbrook
                p[2] = 3; // CD-R & CD-RW read
723 17acfe32 pbrook
                p[3] = 0; // Writing not supported
724 17acfe32 pbrook
                p[4] = 0x7f; /* Audio, composite, digital out,
725 17acfe32 pbrook
                                         mode 2 form 1&2, multi session */
726 17acfe32 pbrook
                p[5] = 0xff; /* CD DA, DA accurate, RW supported,
727 17acfe32 pbrook
                                         RW corrected, C2 errors, ISRC,
728 17acfe32 pbrook
                                         UPC, Bar code */
729 d52affa7 Gerd Hoffmann
                p[6] = 0x2d | (bdrv_is_locked(s->dinfo->bdrv)? 2 : 0);
730 17acfe32 pbrook
                /* Locking supported, jumper present, eject, tray */
731 17acfe32 pbrook
                p[7] = 0; /* no volume & mute control, no
732 17acfe32 pbrook
                                      changer */
733 17acfe32 pbrook
                p[8] = (50 * 176) >> 8; // 50x read speed
734 17acfe32 pbrook
                p[9] = (50 * 176) & 0xff;
735 17acfe32 pbrook
                p[10] = 0 >> 8; // No volume
736 17acfe32 pbrook
                p[11] = 0 & 0xff;
737 17acfe32 pbrook
                p[12] = 2048 >> 8; // 2M buffer
738 17acfe32 pbrook
                p[13] = 2048 & 0xff;
739 17acfe32 pbrook
                p[14] = (16 * 176) >> 8; // 16x read speed current
740 17acfe32 pbrook
                p[15] = (16 * 176) & 0xff;
741 17acfe32 pbrook
                p[18] = (16 * 176) >> 8; // 16x write speed
742 17acfe32 pbrook
                p[19] = (16 * 176) & 0xff;
743 17acfe32 pbrook
                p[20] = (16 * 176) >> 8; // 16x write speed current
744 17acfe32 pbrook
                p[21] = (16 * 176) & 0xff;
745 67cd24a8 ths
                p += 22;
746 17acfe32 pbrook
            }
747 c87c0672 aliguori
            r->iov.iov_len = p - outbuf;
748 c87c0672 aliguori
            outbuf[0] = r->iov.iov_len - 4;
749 c87c0672 aliguori
            if (r->iov.iov_len > len)
750 c87c0672 aliguori
                r->iov.iov_len = len;
751 7d8406be pbrook
        }
752 17acfe32 pbrook
        break;
753 17acfe32 pbrook
    case 0x1b:
754 17acfe32 pbrook
        DPRINTF("Start Stop Unit\n");
755 d52affa7 Gerd Hoffmann
        if (bdrv_get_type_hint(s->dinfo->bdrv) == BDRV_TYPE_CDROM &&
756 b2056c16 blueswir1
            (buf[4] & 2))
757 b2056c16 blueswir1
            /* load/eject medium */
758 d52affa7 Gerd Hoffmann
            bdrv_eject(s->dinfo->bdrv, !(buf[4] & 1));
759 17acfe32 pbrook
        break;
760 17acfe32 pbrook
    case 0x1e:
761 17acfe32 pbrook
        DPRINTF("Prevent Allow Medium Removal (prevent = %d)\n", buf[4] & 3);
762 d52affa7 Gerd Hoffmann
        bdrv_set_locked(s->dinfo->bdrv, buf[4] & 1);
763 2e5d83bb pbrook
        break;
764 2e5d83bb pbrook
    case 0x25:
765 2e5d83bb pbrook
        DPRINTF("Read Capacity\n");
766 2e5d83bb pbrook
        /* The normal LEN field for this command is zero.  */
767 a917d384 pbrook
        memset(outbuf, 0, 8);
768 d52affa7 Gerd Hoffmann
        bdrv_get_geometry(s->dinfo->bdrv, &nb_sectors);
769 c1c0438c aliguori
        nb_sectors /= s->cluster_size;
770 51c1ebb1 pbrook
        /* Returned value is the address of the last sector.  */
771 51c1ebb1 pbrook
        if (nb_sectors) {
772 51c1ebb1 pbrook
            nb_sectors--;
773 274fb0e1 aliguori
            /* Remember the new size for read/write sanity checking. */
774 274fb0e1 aliguori
            s->max_lba = nb_sectors;
775 e035b43d aliguori
            /* Clip to 2TB, instead of returning capacity modulo 2TB. */
776 e035b43d aliguori
            if (nb_sectors > UINT32_MAX)
777 e035b43d aliguori
                nb_sectors = UINT32_MAX;
778 a917d384 pbrook
            outbuf[0] = (nb_sectors >> 24) & 0xff;
779 a917d384 pbrook
            outbuf[1] = (nb_sectors >> 16) & 0xff;
780 a917d384 pbrook
            outbuf[2] = (nb_sectors >> 8) & 0xff;
781 a917d384 pbrook
            outbuf[3] = nb_sectors & 0xff;
782 a917d384 pbrook
            outbuf[4] = 0;
783 a917d384 pbrook
            outbuf[5] = 0;
784 a917d384 pbrook
            outbuf[6] = s->cluster_size * 2;
785 a917d384 pbrook
            outbuf[7] = 0;
786 c87c0672 aliguori
            r->iov.iov_len = 8;
787 51c1ebb1 pbrook
        } else {
788 58a2c436 blueswir1
        notready:
789 22864256 blueswir1
            scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_NOT_READY);
790 35f1df84 pbrook
            return 0;
791 51c1ebb1 pbrook
        }
792 2e5d83bb pbrook
        break;
793 2e5d83bb pbrook
    case 0x08:
794 2e5d83bb pbrook
    case 0x28:
795 86106e59 aliguori
    case 0x88:
796 0bf9e31a Blue Swirl
        DPRINTF("Read (sector %" PRId64 ", count %d)\n", lba, len);
797 274fb0e1 aliguori
        if (lba > s->max_lba)
798 274fb0e1 aliguori
            goto illegal_lba;
799 a917d384 pbrook
        r->sector = lba * s->cluster_size;
800 a917d384 pbrook
        r->sector_count = len * s->cluster_size;
801 2e5d83bb pbrook
        break;
802 2e5d83bb pbrook
    case 0x0a:
803 2e5d83bb pbrook
    case 0x2a:
804 86106e59 aliguori
    case 0x8a:
805 0bf9e31a Blue Swirl
        DPRINTF("Write (sector %" PRId64 ", count %d)\n", lba, len);
806 274fb0e1 aliguori
        if (lba > s->max_lba)
807 274fb0e1 aliguori
            goto illegal_lba;
808 a917d384 pbrook
        r->sector = lba * s->cluster_size;
809 a917d384 pbrook
        r->sector_count = len * s->cluster_size;
810 2e5d83bb pbrook
        is_write = 1;
811 2e5d83bb pbrook
        break;
812 7d8406be pbrook
    case 0x35:
813 0bf9e31a Blue Swirl
        DPRINTF("Synchronise cache (sector %" PRId64 ", count %d)\n", lba, len);
814 d52affa7 Gerd Hoffmann
        bdrv_flush(s->dinfo->bdrv);
815 7d8406be pbrook
        break;
816 2e5d83bb pbrook
    case 0x43:
817 2e5d83bb pbrook
        {
818 7c22dd52 pbrook
            int start_track, format, msf, toclen;
819 2e5d83bb pbrook
820 2e5d83bb pbrook
            msf = buf[1] & 2;
821 2e5d83bb pbrook
            format = buf[2] & 0xf;
822 2e5d83bb pbrook
            start_track = buf[6];
823 d52affa7 Gerd Hoffmann
            bdrv_get_geometry(s->dinfo->bdrv, &nb_sectors);
824 2e5d83bb pbrook
            DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1);
825 ee16b24a blueswir1
            nb_sectors /= s->cluster_size;
826 2e5d83bb pbrook
            switch(format) {
827 2e5d83bb pbrook
            case 0:
828 a917d384 pbrook
                toclen = cdrom_read_toc(nb_sectors, outbuf, msf, start_track);
829 2e5d83bb pbrook
                break;
830 2e5d83bb pbrook
            case 1:
831 2e5d83bb pbrook
                /* multi session : only a single session defined */
832 7c22dd52 pbrook
                toclen = 12;
833 a917d384 pbrook
                memset(outbuf, 0, 12);
834 a917d384 pbrook
                outbuf[1] = 0x0a;
835 a917d384 pbrook
                outbuf[2] = 0x01;
836 a917d384 pbrook
                outbuf[3] = 0x01;
837 2e5d83bb pbrook
                break;
838 2e5d83bb pbrook
            case 2:
839 a917d384 pbrook
                toclen = cdrom_read_toc_raw(nb_sectors, outbuf, msf, start_track);
840 2e5d83bb pbrook
                break;
841 2e5d83bb pbrook
            default:
842 7c22dd52 pbrook
                goto error_cmd;
843 7c22dd52 pbrook
            }
844 7c22dd52 pbrook
            if (toclen > 0) {
845 7c22dd52 pbrook
                if (len > toclen)
846 7c22dd52 pbrook
                  len = toclen;
847 c87c0672 aliguori
                r->iov.iov_len = len;
848 7c22dd52 pbrook
                break;
849 2e5d83bb pbrook
            }
850 7c22dd52 pbrook
        error_cmd:
851 7c22dd52 pbrook
            DPRINTF("Read TOC error\n");
852 7c22dd52 pbrook
            goto fail;
853 2e5d83bb pbrook
        }
854 17acfe32 pbrook
    case 0x46:
855 17acfe32 pbrook
        DPRINTF("Get Configuration (rt %d, maxlen %d)\n", buf[1] & 3, len);
856 a917d384 pbrook
        memset(outbuf, 0, 8);
857 1235fc06 ths
        /* ??? This should probably return much more information.  For now
858 17acfe32 pbrook
           just return the basic header indicating the CD-ROM profile.  */
859 a917d384 pbrook
        outbuf[7] = 8; // CD-ROM
860 c87c0672 aliguori
        r->iov.iov_len = 8;
861 17acfe32 pbrook
        break;
862 2e5d83bb pbrook
    case 0x56:
863 2e5d83bb pbrook
        DPRINTF("Reserve(10)\n");
864 2e5d83bb pbrook
        if (buf[1] & 3)
865 2e5d83bb pbrook
            goto fail;
866 2e5d83bb pbrook
        break;
867 2e5d83bb pbrook
    case 0x57:
868 2e5d83bb pbrook
        DPRINTF("Release(10)\n");
869 2e5d83bb pbrook
        if (buf[1] & 3)
870 2e5d83bb pbrook
            goto fail;
871 2e5d83bb pbrook
        break;
872 86106e59 aliguori
    case 0x9e:
873 86106e59 aliguori
        /* Service Action In subcommands. */
874 86106e59 aliguori
        if ((buf[1] & 31) == 0x10) {
875 86106e59 aliguori
            DPRINTF("SAI READ CAPACITY(16)\n");
876 86106e59 aliguori
            memset(outbuf, 0, len);
877 d52affa7 Gerd Hoffmann
            bdrv_get_geometry(s->dinfo->bdrv, &nb_sectors);
878 c1c0438c aliguori
            nb_sectors /= s->cluster_size;
879 86106e59 aliguori
            /* Returned value is the address of the last sector.  */
880 86106e59 aliguori
            if (nb_sectors) {
881 86106e59 aliguori
                nb_sectors--;
882 274fb0e1 aliguori
                /* Remember the new size for read/write sanity checking. */
883 274fb0e1 aliguori
                s->max_lba = nb_sectors;
884 86106e59 aliguori
                outbuf[0] = (nb_sectors >> 56) & 0xff;
885 86106e59 aliguori
                outbuf[1] = (nb_sectors >> 48) & 0xff;
886 86106e59 aliguori
                outbuf[2] = (nb_sectors >> 40) & 0xff;
887 86106e59 aliguori
                outbuf[3] = (nb_sectors >> 32) & 0xff;
888 86106e59 aliguori
                outbuf[4] = (nb_sectors >> 24) & 0xff;
889 86106e59 aliguori
                outbuf[5] = (nb_sectors >> 16) & 0xff;
890 86106e59 aliguori
                outbuf[6] = (nb_sectors >> 8) & 0xff;
891 86106e59 aliguori
                outbuf[7] = nb_sectors & 0xff;
892 86106e59 aliguori
                outbuf[8] = 0;
893 86106e59 aliguori
                outbuf[9] = 0;
894 86106e59 aliguori
                outbuf[10] = s->cluster_size * 2;
895 86106e59 aliguori
                outbuf[11] = 0;
896 86106e59 aliguori
                /* Protection, exponent and lowest lba field left blank. */
897 c87c0672 aliguori
                r->iov.iov_len = len;
898 86106e59 aliguori
            } else {
899 86106e59 aliguori
                scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_NOT_READY);
900 86106e59 aliguori
                return 0;
901 86106e59 aliguori
            }
902 86106e59 aliguori
            break;
903 86106e59 aliguori
        }
904 86106e59 aliguori
        DPRINTF("Unsupported Service Action In\n");
905 86106e59 aliguori
        goto fail;
906 2e5d83bb pbrook
    case 0xa0:
907 2e5d83bb pbrook
        DPRINTF("Report LUNs (len %d)\n", len);
908 2e5d83bb pbrook
        if (len < 16)
909 2e5d83bb pbrook
            goto fail;
910 a917d384 pbrook
        memset(outbuf, 0, 16);
911 a917d384 pbrook
        outbuf[3] = 8;
912 c87c0672 aliguori
        r->iov.iov_len = 16;
913 2e5d83bb pbrook
        break;
914 22864256 blueswir1
    case 0x2f:
915 0bf9e31a Blue Swirl
        DPRINTF("Verify (sector %" PRId64 ", count %d)\n", lba, len);
916 22864256 blueswir1
        break;
917 2e5d83bb pbrook
    default:
918 2e5d83bb pbrook
        DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
919 2e5d83bb pbrook
    fail:
920 22864256 blueswir1
        scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_ILLEGAL_REQUEST);
921 2e5d83bb pbrook
        return 0;
922 274fb0e1 aliguori
    illegal_lba:
923 274fb0e1 aliguori
        scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
924 274fb0e1 aliguori
        return 0;
925 2e5d83bb pbrook
    }
926 c87c0672 aliguori
    if (r->sector_count == 0 && r->iov.iov_len == 0) {
927 22864256 blueswir1
        scsi_command_complete(r, STATUS_GOOD, SENSE_NO_SENSE);
928 a917d384 pbrook
    }
929 c87c0672 aliguori
    len = r->sector_count * 512 + r->iov.iov_len;
930 a917d384 pbrook
    if (is_write) {
931 a917d384 pbrook
        return -len;
932 a917d384 pbrook
    } else {
933 a917d384 pbrook
        if (!r->sector_count)
934 a917d384 pbrook
            r->sector_count = -1;
935 a917d384 pbrook
        return len;
936 2e5d83bb pbrook
    }
937 2e5d83bb pbrook
}
938 2e5d83bb pbrook
939 d52affa7 Gerd Hoffmann
static int scsi_disk_initfn(SCSIDevice *dev)
940 2e5d83bb pbrook
{
941 d52affa7 Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
942 274fb0e1 aliguori
    uint64_t nb_sectors;
943 2e5d83bb pbrook
944 d52affa7 Gerd Hoffmann
    if (!s->dinfo || !s->dinfo->bdrv) {
945 d52affa7 Gerd Hoffmann
        qemu_error("scsi-disk: drive property not set\n");
946 d52affa7 Gerd Hoffmann
        return -1;
947 d52affa7 Gerd Hoffmann
    }
948 d52affa7 Gerd Hoffmann
949 d52affa7 Gerd Hoffmann
    if (bdrv_get_type_hint(s->dinfo->bdrv) == BDRV_TYPE_CDROM) {
950 7c22dd52 pbrook
        s->cluster_size = 4;
951 2e5d83bb pbrook
    } else {
952 7c22dd52 pbrook
        s->cluster_size = 1;
953 2e5d83bb pbrook
    }
954 d52affa7 Gerd Hoffmann
    bdrv_get_geometry(s->dinfo->bdrv, &nb_sectors);
955 274fb0e1 aliguori
    nb_sectors /= s->cluster_size;
956 274fb0e1 aliguori
    if (nb_sectors)
957 274fb0e1 aliguori
        nb_sectors--;
958 274fb0e1 aliguori
    s->max_lba = nb_sectors;
959 d52affa7 Gerd Hoffmann
    strncpy(s->drive_serial_str, drive_get_serial(s->dinfo->bdrv),
960 fa879c64 aliguori
            sizeof(s->drive_serial_str));
961 fa879c64 aliguori
    if (strlen(s->drive_serial_str) == 0)
962 00766a4e blueswir1
        pstrcpy(s->drive_serial_str, sizeof(s->drive_serial_str), "0");
963 ea8a5d7f aliguori
    qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s);
964 d52affa7 Gerd Hoffmann
    return 0;
965 d52affa7 Gerd Hoffmann
}
966 d52affa7 Gerd Hoffmann
967 d52affa7 Gerd Hoffmann
static SCSIDeviceInfo scsi_disk_info = {
968 d52affa7 Gerd Hoffmann
    .qdev.name    = "scsi-disk",
969 d52affa7 Gerd Hoffmann
    .qdev.desc    = "virtual scsi disk or cdrom",
970 d52affa7 Gerd Hoffmann
    .qdev.size    = sizeof(SCSIDiskState),
971 d52affa7 Gerd Hoffmann
    .init         = scsi_disk_initfn,
972 d52affa7 Gerd Hoffmann
    .send_command = scsi_send_command,
973 d52affa7 Gerd Hoffmann
    .read_data    = scsi_read_data,
974 d52affa7 Gerd Hoffmann
    .write_data   = scsi_write_data,
975 d52affa7 Gerd Hoffmann
    .cancel_io    = scsi_cancel_io,
976 d52affa7 Gerd Hoffmann
    .get_buf      = scsi_get_buf,
977 d52affa7 Gerd Hoffmann
    .qdev.props   = (Property[]) {
978 d52affa7 Gerd Hoffmann
        DEFINE_PROP_DRIVE("drive", SCSIDiskState, dinfo),
979 d52affa7 Gerd Hoffmann
        DEFINE_PROP_END_OF_LIST(),
980 d52affa7 Gerd Hoffmann
    },
981 d52affa7 Gerd Hoffmann
};
982 d52affa7 Gerd Hoffmann
983 d52affa7 Gerd Hoffmann
static void scsi_disk_register_devices(void)
984 d52affa7 Gerd Hoffmann
{
985 d52affa7 Gerd Hoffmann
    scsi_qdev_register(&scsi_disk_info);
986 8ccc2ace ths
}
987 d52affa7 Gerd Hoffmann
device_init(scsi_disk_register_devices)