Statistics
| Branch: | Revision:

root / hw / scsi-disk.c @ 7d0d6950

History | View | Annotate | Download (32.8 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 43b443b6 Gerd Hoffmann
#include "scsi.h"
37 0d65e1f8 Gerd Hoffmann
#include "scsi-defs.h"
38 666daa68 Markus Armbruster
#include "sysemu.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 a0fef654 Markus Armbruster
    char *serial;
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 3e94cb02 Jan Kiszka
    r->req.aiocb = NULL;
130 3e94cb02 Jan Kiszka
131 a917d384 pbrook
    if (ret) {
132 a917d384 pbrook
        DPRINTF("IO error\n");
133 4c41d2ef Gerd Hoffmann
        r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, 0);
134 0d65e1f8 Gerd Hoffmann
        scsi_command_complete(r, CHECK_CONDITION, NO_SENSE);
135 4d611c9a pbrook
        return;
136 4d611c9a pbrook
    }
137 4c41d2ef Gerd Hoffmann
    DPRINTF("Data ready tag=0x%x len=%" PRId64 "\n", r->req.tag, r->iov.iov_len);
138 a917d384 pbrook
139 4c41d2ef Gerd Hoffmann
    r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, r->iov.iov_len);
140 4d611c9a pbrook
}
141 4d611c9a pbrook
142 a917d384 pbrook
/* Read more data from scsi device into buffer.  */
143 8ccc2ace ths
static void scsi_read_data(SCSIDevice *d, uint32_t tag)
144 2e5d83bb pbrook
{
145 d52affa7 Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
146 4c41d2ef Gerd Hoffmann
    SCSIDiskReq *r;
147 2e5d83bb pbrook
    uint32_t n;
148 2e5d83bb pbrook
149 a917d384 pbrook
    r = scsi_find_request(s, tag);
150 a917d384 pbrook
    if (!r) {
151 a917d384 pbrook
        BADF("Bad read tag 0x%x\n", tag);
152 b1fa7164 blueswir1
        /* ??? This is the wrong error.  */
153 0d65e1f8 Gerd Hoffmann
        scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR);
154 a917d384 pbrook
        return;
155 2e5d83bb pbrook
    }
156 a917d384 pbrook
    if (r->sector_count == (uint32_t)-1) {
157 0bf9e31a Blue Swirl
        DPRINTF("Read buf_len=%" PRId64 "\n", r->iov.iov_len);
158 a917d384 pbrook
        r->sector_count = 0;
159 4c41d2ef Gerd Hoffmann
        r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, r->iov.iov_len);
160 a917d384 pbrook
        return;
161 2e5d83bb pbrook
    }
162 a917d384 pbrook
    DPRINTF("Read sector_count=%d\n", r->sector_count);
163 a917d384 pbrook
    if (r->sector_count == 0) {
164 0d65e1f8 Gerd Hoffmann
        scsi_command_complete(r, GOOD, NO_SENSE);
165 a917d384 pbrook
        return;
166 2e5d83bb pbrook
    }
167 2e5d83bb pbrook
168 a917d384 pbrook
    n = r->sector_count;
169 a917d384 pbrook
    if (n > SCSI_DMA_BUF_SIZE / 512)
170 a917d384 pbrook
        n = SCSI_DMA_BUF_SIZE / 512;
171 a917d384 pbrook
172 c87c0672 aliguori
    r->iov.iov_len = n * 512;
173 c87c0672 aliguori
    qemu_iovec_init_external(&r->qiov, &r->iov, 1);
174 428c149b Christoph Hellwig
    r->req.aiocb = bdrv_aio_readv(s->bs, r->sector, &r->qiov, n,
175 c87c0672 aliguori
                              scsi_read_complete, r);
176 4c41d2ef Gerd Hoffmann
    if (r->req.aiocb == NULL)
177 0d65e1f8 Gerd Hoffmann
        scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR);
178 a917d384 pbrook
    r->sector += n;
179 a917d384 pbrook
    r->sector_count -= n;
180 2e5d83bb pbrook
}
181 2e5d83bb pbrook
182 4c41d2ef Gerd Hoffmann
static int scsi_handle_write_error(SCSIDiskReq *r, int error)
183 ea8a5d7f aliguori
{
184 4c41d2ef Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
185 abd7f68d Markus Armbruster
    BlockErrorAction action = bdrv_get_on_error(s->bs, 0);
186 ea8a5d7f aliguori
187 380f640f Luiz Capitulino
    if (action == BLOCK_ERR_IGNORE) {
188 428c149b Christoph Hellwig
        bdrv_mon_event(s->bs, BDRV_ACTION_IGNORE, 0);
189 ea8a5d7f aliguori
        return 0;
190 380f640f Luiz Capitulino
    }
191 ea8a5d7f aliguori
192 ea8a5d7f aliguori
    if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC)
193 ea8a5d7f aliguori
            || action == BLOCK_ERR_STOP_ANY) {
194 ea8a5d7f aliguori
        r->status |= SCSI_REQ_STATUS_RETRY;
195 428c149b Christoph Hellwig
        bdrv_mon_event(s->bs, BDRV_ACTION_STOP, 0);
196 554a310b Luiz Capitulino
        vm_stop(0);
197 ea8a5d7f aliguori
    } else {
198 0d65e1f8 Gerd Hoffmann
        scsi_command_complete(r, CHECK_CONDITION,
199 0d65e1f8 Gerd Hoffmann
                HARDWARE_ERROR);
200 428c149b Christoph Hellwig
        bdrv_mon_event(s->bs, BDRV_ACTION_REPORT, 0);
201 ea8a5d7f aliguori
    }
202 ea8a5d7f aliguori
203 ea8a5d7f aliguori
    return 1;
204 ea8a5d7f aliguori
}
205 ea8a5d7f aliguori
206 4d611c9a pbrook
static void scsi_write_complete(void * opaque, int ret)
207 4d611c9a pbrook
{
208 4c41d2ef Gerd Hoffmann
    SCSIDiskReq *r = (SCSIDiskReq *)opaque;
209 a917d384 pbrook
    uint32_t len;
210 ea8a5d7f aliguori
    uint32_t n;
211 ea8a5d7f aliguori
212 4c41d2ef Gerd Hoffmann
    r->req.aiocb = NULL;
213 4d611c9a pbrook
214 4d611c9a pbrook
    if (ret) {
215 ea8a5d7f aliguori
        if (scsi_handle_write_error(r, -ret))
216 ea8a5d7f aliguori
            return;
217 4d611c9a pbrook
    }
218 4d611c9a pbrook
219 c87c0672 aliguori
    n = r->iov.iov_len / 512;
220 ea8a5d7f aliguori
    r->sector += n;
221 ea8a5d7f aliguori
    r->sector_count -= n;
222 a917d384 pbrook
    if (r->sector_count == 0) {
223 0d65e1f8 Gerd Hoffmann
        scsi_command_complete(r, GOOD, NO_SENSE);
224 a917d384 pbrook
    } else {
225 a917d384 pbrook
        len = r->sector_count * 512;
226 a917d384 pbrook
        if (len > SCSI_DMA_BUF_SIZE) {
227 a917d384 pbrook
            len = SCSI_DMA_BUF_SIZE;
228 a917d384 pbrook
        }
229 c87c0672 aliguori
        r->iov.iov_len = len;
230 4c41d2ef Gerd Hoffmann
        DPRINTF("Write complete tag=0x%x more=%d\n", r->req.tag, len);
231 4c41d2ef Gerd Hoffmann
        r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, len);
232 4d611c9a pbrook
    }
233 4d611c9a pbrook
}
234 4d611c9a pbrook
235 4c41d2ef Gerd Hoffmann
static void scsi_write_request(SCSIDiskReq *r)
236 ea8a5d7f aliguori
{
237 4c41d2ef Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
238 ea8a5d7f aliguori
    uint32_t n;
239 ea8a5d7f aliguori
240 c87c0672 aliguori
    n = r->iov.iov_len / 512;
241 ea8a5d7f aliguori
    if (n) {
242 c87c0672 aliguori
        qemu_iovec_init_external(&r->qiov, &r->iov, 1);
243 428c149b Christoph Hellwig
        r->req.aiocb = bdrv_aio_writev(s->bs, r->sector, &r->qiov, n,
244 c87c0672 aliguori
                                   scsi_write_complete, r);
245 4c41d2ef Gerd Hoffmann
        if (r->req.aiocb == NULL)
246 0d65e1f8 Gerd Hoffmann
            scsi_command_complete(r, CHECK_CONDITION,
247 0d65e1f8 Gerd Hoffmann
                                  HARDWARE_ERROR);
248 ea8a5d7f aliguori
    } else {
249 ea8a5d7f aliguori
        /* Invoke completion routine to fetch data from host.  */
250 ea8a5d7f aliguori
        scsi_write_complete(r, 0);
251 ea8a5d7f aliguori
    }
252 ea8a5d7f aliguori
}
253 ea8a5d7f aliguori
254 4d611c9a pbrook
/* Write data to a scsi device.  Returns nonzero on failure.
255 4d611c9a pbrook
   The transfer may complete asynchronously.  */
256 8ccc2ace ths
static int scsi_write_data(SCSIDevice *d, uint32_t tag)
257 2e5d83bb pbrook
{
258 d52affa7 Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
259 4c41d2ef Gerd Hoffmann
    SCSIDiskReq *r;
260 2e5d83bb pbrook
261 a917d384 pbrook
    DPRINTF("Write data tag=0x%x\n", tag);
262 a917d384 pbrook
    r = scsi_find_request(s, tag);
263 a917d384 pbrook
    if (!r) {
264 a917d384 pbrook
        BADF("Bad write tag 0x%x\n", tag);
265 0d65e1f8 Gerd Hoffmann
        scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR);
266 2e5d83bb pbrook
        return 1;
267 2e5d83bb pbrook
    }
268 ea8a5d7f aliguori
269 4c41d2ef Gerd Hoffmann
    if (r->req.aiocb)
270 a917d384 pbrook
        BADF("Data transfer already in progress\n");
271 ea8a5d7f aliguori
272 ea8a5d7f aliguori
    scsi_write_request(r);
273 2e5d83bb pbrook
274 a917d384 pbrook
    return 0;
275 a917d384 pbrook
}
276 2e5d83bb pbrook
277 213189ab Markus Armbruster
static void scsi_dma_restart_bh(void *opaque)
278 ea8a5d7f aliguori
{
279 d52affa7 Gerd Hoffmann
    SCSIDiskState *s = opaque;
280 9af99d98 Gerd Hoffmann
    SCSIRequest *req;
281 9af99d98 Gerd Hoffmann
    SCSIDiskReq *r;
282 213189ab Markus Armbruster
283 213189ab Markus Armbruster
    qemu_bh_delete(s->bh);
284 213189ab Markus Armbruster
    s->bh = NULL;
285 ea8a5d7f aliguori
286 9af99d98 Gerd Hoffmann
    QTAILQ_FOREACH(req, &s->qdev.requests, next) {
287 9af99d98 Gerd Hoffmann
        r = DO_UPCAST(SCSIDiskReq, req, req);
288 ea8a5d7f aliguori
        if (r->status & SCSI_REQ_STATUS_RETRY) {
289 ea8a5d7f aliguori
            r->status &= ~SCSI_REQ_STATUS_RETRY;
290 ea8a5d7f aliguori
            scsi_write_request(r); 
291 ea8a5d7f aliguori
        }
292 ea8a5d7f aliguori
    }
293 ea8a5d7f aliguori
}
294 ea8a5d7f aliguori
295 213189ab Markus Armbruster
static void scsi_dma_restart_cb(void *opaque, int running, int reason)
296 213189ab Markus Armbruster
{
297 d52affa7 Gerd Hoffmann
    SCSIDiskState *s = opaque;
298 213189ab Markus Armbruster
299 213189ab Markus Armbruster
    if (!running)
300 213189ab Markus Armbruster
        return;
301 213189ab Markus Armbruster
302 213189ab Markus Armbruster
    if (!s->bh) {
303 213189ab Markus Armbruster
        s->bh = qemu_bh_new(scsi_dma_restart_bh, s);
304 213189ab Markus Armbruster
        qemu_bh_schedule(s->bh);
305 213189ab Markus Armbruster
    }
306 213189ab Markus Armbruster
}
307 213189ab Markus Armbruster
308 a917d384 pbrook
/* Return a pointer to the data buffer.  */
309 8ccc2ace ths
static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag)
310 a917d384 pbrook
{
311 d52affa7 Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
312 4c41d2ef Gerd Hoffmann
    SCSIDiskReq *r;
313 2e5d83bb pbrook
314 a917d384 pbrook
    r = scsi_find_request(s, tag);
315 a917d384 pbrook
    if (!r) {
316 a917d384 pbrook
        BADF("Bad buffer tag 0x%x\n", tag);
317 a917d384 pbrook
        return NULL;
318 4d611c9a pbrook
    }
319 3f4cb3d3 blueswir1
    return (uint8_t *)r->iov.iov_base;
320 2e5d83bb pbrook
}
321 2e5d83bb pbrook
322 0b06c059 Gerd Hoffmann
static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
323 0b06c059 Gerd Hoffmann
{
324 383b4d9b Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
325 0b06c059 Gerd Hoffmann
    int buflen = 0;
326 0b06c059 Gerd Hoffmann
327 0b06c059 Gerd Hoffmann
    if (req->cmd.buf[1] & 0x2) {
328 0b06c059 Gerd Hoffmann
        /* Command support data - optional, not implemented */
329 0b06c059 Gerd Hoffmann
        BADF("optional INQUIRY command support request not implemented\n");
330 0b06c059 Gerd Hoffmann
        return -1;
331 0b06c059 Gerd Hoffmann
    }
332 0b06c059 Gerd Hoffmann
333 0b06c059 Gerd Hoffmann
    if (req->cmd.buf[1] & 0x1) {
334 0b06c059 Gerd Hoffmann
        /* Vital product data */
335 0b06c059 Gerd Hoffmann
        uint8_t page_code = req->cmd.buf[2];
336 0b06c059 Gerd Hoffmann
        if (req->cmd.xfer < 4) {
337 0b06c059 Gerd Hoffmann
            BADF("Error: Inquiry (EVPD[%02X]) buffer size %zd is "
338 0b06c059 Gerd Hoffmann
                 "less than 4\n", page_code, req->cmd.xfer);
339 0b06c059 Gerd Hoffmann
            return -1;
340 0b06c059 Gerd Hoffmann
        }
341 0b06c059 Gerd Hoffmann
342 428c149b Christoph Hellwig
        if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) {
343 0b06c059 Gerd Hoffmann
            outbuf[buflen++] = 5;
344 0b06c059 Gerd Hoffmann
        } else {
345 0b06c059 Gerd Hoffmann
            outbuf[buflen++] = 0;
346 0b06c059 Gerd Hoffmann
        }
347 0b06c059 Gerd Hoffmann
        outbuf[buflen++] = page_code ; // this page
348 0b06c059 Gerd Hoffmann
        outbuf[buflen++] = 0x00;
349 0b06c059 Gerd Hoffmann
350 0b06c059 Gerd Hoffmann
        switch (page_code) {
351 0b06c059 Gerd Hoffmann
        case 0x00: /* Supported page codes, mandatory */
352 0b06c059 Gerd Hoffmann
            DPRINTF("Inquiry EVPD[Supported pages] "
353 0b06c059 Gerd Hoffmann
                    "buffer size %zd\n", req->cmd.xfer);
354 ee3659e3 Christoph Hellwig
            outbuf[buflen++] = 4;    // number of pages
355 0b06c059 Gerd Hoffmann
            outbuf[buflen++] = 0x00; // list of supported pages (this page)
356 0b06c059 Gerd Hoffmann
            outbuf[buflen++] = 0x80; // unit serial number
357 0b06c059 Gerd Hoffmann
            outbuf[buflen++] = 0x83; // device identification
358 ee3659e3 Christoph Hellwig
            outbuf[buflen++] = 0xb0; // block device characteristics
359 0b06c059 Gerd Hoffmann
            break;
360 0b06c059 Gerd Hoffmann
361 0b06c059 Gerd Hoffmann
        case 0x80: /* Device serial number, optional */
362 0b06c059 Gerd Hoffmann
        {
363 a0fef654 Markus Armbruster
            int l = strlen(s->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 a0fef654 Markus Armbruster
            memcpy(outbuf+buflen, s->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 8cfacf07 Christoph Hellwig
            unsigned int min_io_size =
401 8cfacf07 Christoph Hellwig
                    s->qdev.conf.min_io_size / s->qdev.blocksize;
402 8cfacf07 Christoph Hellwig
            unsigned int opt_io_size =
403 8cfacf07 Christoph Hellwig
                    s->qdev.conf.opt_io_size / s->qdev.blocksize;
404 ee3659e3 Christoph Hellwig
405 ee3659e3 Christoph Hellwig
            /* required VPD size with unmap support */
406 ee3659e3 Christoph Hellwig
            outbuf[3] = buflen = 0x3c;
407 ee3659e3 Christoph Hellwig
408 ee3659e3 Christoph Hellwig
            memset(outbuf + 4, 0, buflen - 4);
409 ee3659e3 Christoph Hellwig
410 ee3659e3 Christoph Hellwig
            /* optimal transfer length granularity */
411 ee3659e3 Christoph Hellwig
            outbuf[6] = (min_io_size >> 8) & 0xff;
412 ee3659e3 Christoph Hellwig
            outbuf[7] = min_io_size & 0xff;
413 ee3659e3 Christoph Hellwig
414 ee3659e3 Christoph Hellwig
            /* optimal transfer length */
415 ee3659e3 Christoph Hellwig
            outbuf[12] = (opt_io_size >> 24) & 0xff;
416 ee3659e3 Christoph Hellwig
            outbuf[13] = (opt_io_size >> 16) & 0xff;
417 ee3659e3 Christoph Hellwig
            outbuf[14] = (opt_io_size >> 8) & 0xff;
418 ee3659e3 Christoph Hellwig
            outbuf[15] = opt_io_size & 0xff;
419 ee3659e3 Christoph Hellwig
            break;
420 ee3659e3 Christoph Hellwig
        }
421 0b06c059 Gerd Hoffmann
        default:
422 0b06c059 Gerd Hoffmann
            BADF("Error: unsupported Inquiry (EVPD[%02X]) "
423 0b06c059 Gerd Hoffmann
                 "buffer size %zd\n", page_code, req->cmd.xfer);
424 0b06c059 Gerd Hoffmann
            return -1;
425 0b06c059 Gerd Hoffmann
        }
426 0b06c059 Gerd Hoffmann
        /* done with EVPD */
427 0b06c059 Gerd Hoffmann
        return buflen;
428 0b06c059 Gerd Hoffmann
    }
429 0b06c059 Gerd Hoffmann
430 0b06c059 Gerd Hoffmann
    /* Standard INQUIRY data */
431 0b06c059 Gerd Hoffmann
    if (req->cmd.buf[2] != 0) {
432 0b06c059 Gerd Hoffmann
        BADF("Error: Inquiry (STANDARD) page or code "
433 0b06c059 Gerd Hoffmann
             "is non-zero [%02X]\n", req->cmd.buf[2]);
434 0b06c059 Gerd Hoffmann
        return -1;
435 0b06c059 Gerd Hoffmann
    }
436 0b06c059 Gerd Hoffmann
437 0b06c059 Gerd Hoffmann
    /* PAGE CODE == 0 */
438 0b06c059 Gerd Hoffmann
    if (req->cmd.xfer < 5) {
439 0b06c059 Gerd Hoffmann
        BADF("Error: Inquiry (STANDARD) buffer size %zd "
440 0b06c059 Gerd Hoffmann
             "is less than 5\n", req->cmd.xfer);
441 0b06c059 Gerd Hoffmann
        return -1;
442 0b06c059 Gerd Hoffmann
    }
443 0b06c059 Gerd Hoffmann
444 0b06c059 Gerd Hoffmann
    buflen = req->cmd.xfer;
445 0b06c059 Gerd Hoffmann
    if (buflen > SCSI_MAX_INQUIRY_LEN)
446 0b06c059 Gerd Hoffmann
        buflen = SCSI_MAX_INQUIRY_LEN;
447 0b06c059 Gerd Hoffmann
448 0b06c059 Gerd Hoffmann
    memset(outbuf, 0, buflen);
449 0b06c059 Gerd Hoffmann
450 0b06c059 Gerd Hoffmann
    if (req->lun || req->cmd.buf[1] >> 5) {
451 0b06c059 Gerd Hoffmann
        outbuf[0] = 0x7f;        /* LUN not supported */
452 0b06c059 Gerd Hoffmann
        return buflen;
453 0b06c059 Gerd Hoffmann
    }
454 0b06c059 Gerd Hoffmann
455 428c149b Christoph Hellwig
    if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) {
456 0b06c059 Gerd Hoffmann
        outbuf[0] = 5;
457 0b06c059 Gerd Hoffmann
        outbuf[1] = 0x80;
458 550fe6c6 Laszlo Ast
        memcpy(&outbuf[16], "QEMU CD-ROM     ", 16);
459 0b06c059 Gerd Hoffmann
    } else {
460 0b06c059 Gerd Hoffmann
        outbuf[0] = 0;
461 550fe6c6 Laszlo Ast
        memcpy(&outbuf[16], "QEMU HARDDISK   ", 16);
462 0b06c059 Gerd Hoffmann
    }
463 550fe6c6 Laszlo Ast
    memcpy(&outbuf[8], "QEMU    ", 8);
464 314b1811 Gerd Hoffmann
    memset(&outbuf[32], 0, 4);
465 552fee93 Markus Armbruster
    memcpy(&outbuf[32], s->version, MIN(4, strlen(s->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 e9447f35 Jan Kiszka
static void scsi_disk_purge_requests(SCSIDiskState *s)
1014 56a14938 Gerd Hoffmann
{
1015 9af99d98 Gerd Hoffmann
    SCSIDiskReq *r;
1016 56a14938 Gerd Hoffmann
1017 9af99d98 Gerd Hoffmann
    while (!QTAILQ_EMPTY(&s->qdev.requests)) {
1018 9af99d98 Gerd Hoffmann
        r = DO_UPCAST(SCSIDiskReq, req, QTAILQ_FIRST(&s->qdev.requests));
1019 e9447f35 Jan Kiszka
        if (r->req.aiocb) {
1020 e9447f35 Jan Kiszka
            bdrv_aio_cancel(r->req.aiocb);
1021 e9447f35 Jan Kiszka
        }
1022 9af99d98 Gerd Hoffmann
        scsi_remove_request(r);
1023 9af99d98 Gerd Hoffmann
    }
1024 e9447f35 Jan Kiszka
}
1025 e9447f35 Jan Kiszka
1026 e9447f35 Jan Kiszka
static void scsi_disk_reset(DeviceState *dev)
1027 e9447f35 Jan Kiszka
{
1028 e9447f35 Jan Kiszka
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev.qdev, dev);
1029 e9447f35 Jan Kiszka
    uint64_t nb_sectors;
1030 e9447f35 Jan Kiszka
1031 e9447f35 Jan Kiszka
    scsi_disk_purge_requests(s);
1032 e9447f35 Jan Kiszka
1033 e9447f35 Jan Kiszka
    bdrv_get_geometry(s->bs, &nb_sectors);
1034 e9447f35 Jan Kiszka
    nb_sectors /= s->cluster_size;
1035 e9447f35 Jan Kiszka
    if (nb_sectors) {
1036 e9447f35 Jan Kiszka
        nb_sectors--;
1037 e9447f35 Jan Kiszka
    }
1038 e9447f35 Jan Kiszka
    s->max_lba = nb_sectors;
1039 e9447f35 Jan Kiszka
}
1040 e9447f35 Jan Kiszka
1041 e9447f35 Jan Kiszka
static void scsi_destroy(SCSIDevice *dev)
1042 e9447f35 Jan Kiszka
{
1043 e9447f35 Jan Kiszka
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
1044 e9447f35 Jan Kiszka
1045 e9447f35 Jan Kiszka
    scsi_disk_purge_requests(s);
1046 f8b6cc00 Markus Armbruster
    blockdev_mark_auto_del(s->qdev.conf.bs);
1047 56a14938 Gerd Hoffmann
}
1048 56a14938 Gerd Hoffmann
1049 d52affa7 Gerd Hoffmann
static int scsi_disk_initfn(SCSIDevice *dev)
1050 2e5d83bb pbrook
{
1051 d52affa7 Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
1052 7d0d6950 Markus Armbruster
    int is_cd;
1053 f8b6cc00 Markus Armbruster
    DriveInfo *dinfo;
1054 2e5d83bb pbrook
1055 f8b6cc00 Markus Armbruster
    if (!s->qdev.conf.bs) {
1056 1ecda02b Markus Armbruster
        error_report("scsi-disk: drive property not set");
1057 d52affa7 Gerd Hoffmann
        return -1;
1058 d52affa7 Gerd Hoffmann
    }
1059 f8b6cc00 Markus Armbruster
    s->bs = s->qdev.conf.bs;
1060 7d0d6950 Markus Armbruster
    is_cd = bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM;
1061 d52affa7 Gerd Hoffmann
1062 a0fef654 Markus Armbruster
    if (!s->serial) {
1063 f8b6cc00 Markus Armbruster
        /* try to fall back to value set with legacy -drive serial=... */
1064 f8b6cc00 Markus Armbruster
        dinfo = drive_get_by_blockdev(s->bs);
1065 f8b6cc00 Markus Armbruster
        s->serial = qemu_strdup(*dinfo->serial ? dinfo->serial : "0");
1066 a0fef654 Markus Armbruster
    }
1067 a0fef654 Markus Armbruster
1068 552fee93 Markus Armbruster
    if (!s->version) {
1069 552fee93 Markus Armbruster
        s->version = qemu_strdup(QEMU_VERSION);
1070 552fee93 Markus Armbruster
    }
1071 552fee93 Markus Armbruster
1072 32bb404a Markus Armbruster
    if (bdrv_is_sg(s->bs)) {
1073 1ecda02b Markus Armbruster
        error_report("scsi-disk: unwanted /dev/sg*");
1074 32bb404a Markus Armbruster
        return -1;
1075 32bb404a Markus Armbruster
    }
1076 32bb404a Markus Armbruster
1077 7d0d6950 Markus Armbruster
    if (is_cd) {
1078 8cfacf07 Christoph Hellwig
        s->qdev.blocksize = 2048;
1079 2e5d83bb pbrook
    } else {
1080 8cfacf07 Christoph Hellwig
        s->qdev.blocksize = s->qdev.conf.logical_block_size;
1081 2e5d83bb pbrook
    }
1082 8cfacf07 Christoph Hellwig
    s->cluster_size = s->qdev.blocksize / 512;
1083 8cfacf07 Christoph Hellwig
1084 91376656 Gerd Hoffmann
    s->qdev.type = TYPE_DISK;
1085 ea8a5d7f aliguori
    qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s);
1086 7d0d6950 Markus Armbruster
    bdrv_set_removable(s->bs, is_cd);
1087 d52affa7 Gerd Hoffmann
    return 0;
1088 d52affa7 Gerd Hoffmann
}
1089 d52affa7 Gerd Hoffmann
1090 d52affa7 Gerd Hoffmann
static SCSIDeviceInfo scsi_disk_info = {
1091 d52affa7 Gerd Hoffmann
    .qdev.name    = "scsi-disk",
1092 d52affa7 Gerd Hoffmann
    .qdev.desc    = "virtual scsi disk or cdrom",
1093 d52affa7 Gerd Hoffmann
    .qdev.size    = sizeof(SCSIDiskState),
1094 e9447f35 Jan Kiszka
    .qdev.reset   = scsi_disk_reset,
1095 d52affa7 Gerd Hoffmann
    .init         = scsi_disk_initfn,
1096 56a14938 Gerd Hoffmann
    .destroy      = scsi_destroy,
1097 d52affa7 Gerd Hoffmann
    .send_command = scsi_send_command,
1098 d52affa7 Gerd Hoffmann
    .read_data    = scsi_read_data,
1099 d52affa7 Gerd Hoffmann
    .write_data   = scsi_write_data,
1100 d52affa7 Gerd Hoffmann
    .cancel_io    = scsi_cancel_io,
1101 d52affa7 Gerd Hoffmann
    .get_buf      = scsi_get_buf,
1102 d52affa7 Gerd Hoffmann
    .qdev.props   = (Property[]) {
1103 428c149b Christoph Hellwig
        DEFINE_BLOCK_PROPERTIES(SCSIDiskState, qdev.conf),
1104 383b4d9b Gerd Hoffmann
        DEFINE_PROP_STRING("ver",  SCSIDiskState, version),
1105 a0fef654 Markus Armbruster
        DEFINE_PROP_STRING("serial",  SCSIDiskState, serial),
1106 d52affa7 Gerd Hoffmann
        DEFINE_PROP_END_OF_LIST(),
1107 d52affa7 Gerd Hoffmann
    },
1108 d52affa7 Gerd Hoffmann
};
1109 d52affa7 Gerd Hoffmann
1110 d52affa7 Gerd Hoffmann
static void scsi_disk_register_devices(void)
1111 d52affa7 Gerd Hoffmann
{
1112 d52affa7 Gerd Hoffmann
    scsi_qdev_register(&scsi_disk_info);
1113 8ccc2ace ths
}
1114 d52affa7 Gerd Hoffmann
device_init(scsi_disk_register_devices)