Statistics
| Branch: | Revision:

root / hw / scsi-disk.c @ 94d3f98a

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