Statistics
| Branch: | Revision:

root / hw / scsi-disk.c @ 2be24aaa

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