Statistics
| Branch: | Revision:

root / hw / scsi-disk.c @ ab9adc88

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