Statistics
| Branch: | Revision:

root / hw / scsi-disk.c @ cdae5cfb

History | View | Annotate | Download (36.2 kB)

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