Statistics
| Branch: | Revision:

root / hw / scsi-disk.c @ e6e055c9

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