Statistics
| Branch: | Revision:

root / hw / scsi-disk.c @ 281a26b1

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