Statistics
| Branch: | Revision:

root / hw / scsi-disk.c @ 66c80e75

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