Statistics
| Branch: | Revision:

root / hw / scsi-disk.c @ 32059220

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