Statistics
| Branch: | Revision:

root / hw / scsi-disk.c @ a1f0cce2

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