Statistics
| Branch: | Revision:

root / hw / scsi-disk.c @ 2446333c

History | View | Annotate | Download (33.1 kB)

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