Statistics
| Branch: | Revision:

root / hw / scsi-disk.c @ fc4f0754

History | View | Annotate | Download (39.7 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 a917d384 pbrook
    command = buf[0];
988 3f4cb3d3 blueswir1
    outbuf = (uint8_t *)r->iov.iov_base;
989 2e5d83bb pbrook
    is_write = 0;
990 a917d384 pbrook
    DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]);
991 2dd791b6 Hannes Reinecke
992 2dd791b6 Hannes Reinecke
    if (scsi_req_parse(&r->req, buf) != 0) {
993 a917d384 pbrook
        BADF("Unsupported command length, command %x\n", command);
994 a1f0cce2 Hannes Reinecke
        scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_OPCODE));
995 a1f0cce2 Hannes Reinecke
        return 0;
996 2e5d83bb pbrook
    }
997 2e5d83bb pbrook
#ifdef DEBUG_SCSI
998 2e5d83bb pbrook
    {
999 2e5d83bb pbrook
        int i;
1000 2dd791b6 Hannes Reinecke
        for (i = 1; i < r->req.cmd.len; i++) {
1001 2e5d83bb pbrook
            printf(" 0x%02x", buf[i]);
1002 2e5d83bb pbrook
        }
1003 2e5d83bb pbrook
        printf("\n");
1004 2e5d83bb pbrook
    }
1005 2e5d83bb pbrook
#endif
1006 aa5dbdc1 Gerd Hoffmann
1007 5c6c0e51 Hannes Reinecke
    if (req->lun || buf[1] >> 5) {
1008 2e5d83bb pbrook
        /* Only LUN 0 supported.  */
1009 5c6c0e51 Hannes Reinecke
        DPRINTF("Unimplemented LUN %d\n", req->lun ? req->lun : buf[1] >> 5);
1010 a1f0cce2 Hannes Reinecke
        if (command != REQUEST_SENSE && command != INQUIRY) {
1011 a1f0cce2 Hannes Reinecke
            scsi_command_complete(r, CHECK_CONDITION,
1012 a1f0cce2 Hannes Reinecke
                                  SENSE_CODE(LUN_NOT_SUPPORTED));
1013 a1f0cce2 Hannes Reinecke
            return 0;
1014 a1f0cce2 Hannes Reinecke
        }
1015 2e5d83bb pbrook
    }
1016 a917d384 pbrook
    switch (command) {
1017 ebf46023 Gerd Hoffmann
    case TEST_UNIT_READY:
1018 51ad87c9 Gerd Hoffmann
    case REQUEST_SENSE:
1019 0b06c059 Gerd Hoffmann
    case INQUIRY:
1020 ebddfcbe Gerd Hoffmann
    case MODE_SENSE:
1021 ebddfcbe Gerd Hoffmann
    case MODE_SENSE_10:
1022 3d53ba18 Gerd Hoffmann
    case RESERVE:
1023 3d53ba18 Gerd Hoffmann
    case RESERVE_10:
1024 3d53ba18 Gerd Hoffmann
    case RELEASE:
1025 3d53ba18 Gerd Hoffmann
    case RELEASE_10:
1026 8d3628ff Gerd Hoffmann
    case START_STOP:
1027 c68b9f34 Gerd Hoffmann
    case ALLOW_MEDIUM_REMOVAL:
1028 e7e25e32 Gerd Hoffmann
    case READ_CAPACITY:
1029 fc903943 Gerd Hoffmann
    case SYNCHRONIZE_CACHE:
1030 02880f43 Gerd Hoffmann
    case READ_TOC:
1031 38215553 Gerd Hoffmann
    case GET_CONFIGURATION:
1032 5dd90e2a Gerd Hoffmann
    case SERVICE_ACTION_IN:
1033 39ec9a50 Gerd Hoffmann
    case REPORT_LUNS:
1034 88f8a5ed Gerd Hoffmann
    case VERIFY:
1035 ebef0bbb Bernhard Kohl
    case REZERO_UNIT:
1036 8af7a3ab Kevin Wolf
        rc = scsi_disk_emulate_command(r, outbuf);
1037 8af7a3ab Kevin Wolf
        if (rc < 0) {
1038 0b06c059 Gerd Hoffmann
            return 0;
1039 aa5dbdc1 Gerd Hoffmann
        }
1040 8af7a3ab Kevin Wolf
1041 8af7a3ab Kevin Wolf
        r->iov.iov_len = rc;
1042 0b06c059 Gerd Hoffmann
        break;
1043 ebf46023 Gerd Hoffmann
    case READ_6:
1044 ebf46023 Gerd Hoffmann
    case READ_10:
1045 bd536cf3 Gerd Hoffmann
    case READ_12:
1046 bd536cf3 Gerd Hoffmann
    case READ_16:
1047 5c6c0e51 Hannes Reinecke
        len = r->req.cmd.xfer / s->qdev.blocksize;
1048 2dd791b6 Hannes Reinecke
        DPRINTF("Read (sector %" PRId64 ", count %d)\n", r->req.cmd.lba, len);
1049 2dd791b6 Hannes Reinecke
        if (r->req.cmd.lba > s->max_lba)
1050 274fb0e1 aliguori
            goto illegal_lba;
1051 2dd791b6 Hannes Reinecke
        r->sector = r->req.cmd.lba * s->cluster_size;
1052 a917d384 pbrook
        r->sector_count = len * s->cluster_size;
1053 2e5d83bb pbrook
        break;
1054 ebf46023 Gerd Hoffmann
    case WRITE_6:
1055 ebf46023 Gerd Hoffmann
    case WRITE_10:
1056 bd536cf3 Gerd Hoffmann
    case WRITE_12:
1057 bd536cf3 Gerd Hoffmann
    case WRITE_16:
1058 ebef0bbb Bernhard Kohl
    case WRITE_VERIFY:
1059 ebef0bbb Bernhard Kohl
    case WRITE_VERIFY_12:
1060 ebef0bbb Bernhard Kohl
    case WRITE_VERIFY_16:
1061 5c6c0e51 Hannes Reinecke
        len = r->req.cmd.xfer / s->qdev.blocksize;
1062 ebef0bbb Bernhard Kohl
        DPRINTF("Write %s(sector %" PRId64 ", count %d)\n",
1063 2dd791b6 Hannes Reinecke
                (command & 0xe) == 0xe ? "And Verify " : "",
1064 2dd791b6 Hannes Reinecke
                r->req.cmd.lba, len);
1065 2dd791b6 Hannes Reinecke
        if (r->req.cmd.lba > s->max_lba)
1066 274fb0e1 aliguori
            goto illegal_lba;
1067 2dd791b6 Hannes Reinecke
        r->sector = r->req.cmd.lba * s->cluster_size;
1068 a917d384 pbrook
        r->sector_count = len * s->cluster_size;
1069 2e5d83bb pbrook
        is_write = 1;
1070 2e5d83bb pbrook
        break;
1071 ebef0bbb Bernhard Kohl
    case MODE_SELECT:
1072 2dd791b6 Hannes Reinecke
        DPRINTF("Mode Select(6) (len %lu)\n", (long)r->req.cmd.xfer);
1073 ebef0bbb Bernhard Kohl
        /* We don't support mode parameter changes.
1074 ebef0bbb Bernhard Kohl
           Allow the mode parameter header + block descriptors only. */
1075 2dd791b6 Hannes Reinecke
        if (r->req.cmd.xfer > 12) {
1076 ebef0bbb Bernhard Kohl
            goto fail;
1077 ebef0bbb Bernhard Kohl
        }
1078 ebef0bbb Bernhard Kohl
        break;
1079 ebef0bbb Bernhard Kohl
    case MODE_SELECT_10:
1080 2dd791b6 Hannes Reinecke
        DPRINTF("Mode Select(10) (len %lu)\n", (long)r->req.cmd.xfer);
1081 ebef0bbb Bernhard Kohl
        /* We don't support mode parameter changes.
1082 ebef0bbb Bernhard Kohl
           Allow the mode parameter header + block descriptors only. */
1083 2dd791b6 Hannes Reinecke
        if (r->req.cmd.xfer > 16) {
1084 ebef0bbb Bernhard Kohl
            goto fail;
1085 ebef0bbb Bernhard Kohl
        }
1086 ebef0bbb Bernhard Kohl
        break;
1087 ebef0bbb Bernhard Kohl
    case SEEK_6:
1088 ebef0bbb Bernhard Kohl
    case SEEK_10:
1089 2dd791b6 Hannes Reinecke
        DPRINTF("Seek(%d) (sector %" PRId64 ")\n", command == SEEK_6 ? 6 : 10,
1090 2dd791b6 Hannes Reinecke
                r->req.cmd.lba);
1091 2dd791b6 Hannes Reinecke
        if (r->req.cmd.lba > s->max_lba) {
1092 ebef0bbb Bernhard Kohl
            goto illegal_lba;
1093 ebef0bbb Bernhard Kohl
        }
1094 ebef0bbb Bernhard Kohl
        break;
1095 ea3bd56f Christoph Hellwig
    case WRITE_SAME_16:
1096 5c6c0e51 Hannes Reinecke
        len = r->req.cmd.xfer / s->qdev.blocksize;
1097 ea3bd56f Christoph Hellwig
1098 ea3bd56f Christoph Hellwig
        DPRINTF("WRITE SAME(16) (sector %" PRId64 ", count %d)\n",
1099 ea3bd56f Christoph Hellwig
                r->req.cmd.lba, len);
1100 ea3bd56f Christoph Hellwig
1101 ea3bd56f Christoph Hellwig
        if (r->req.cmd.lba > s->max_lba) {
1102 ea3bd56f Christoph Hellwig
            goto illegal_lba;
1103 ea3bd56f Christoph Hellwig
        }
1104 ea3bd56f Christoph Hellwig
1105 ea3bd56f Christoph Hellwig
        /*
1106 ea3bd56f Christoph Hellwig
         * We only support WRITE SAME with the unmap bit set for now.
1107 ea3bd56f Christoph Hellwig
         */
1108 ea3bd56f Christoph Hellwig
        if (!(buf[1] & 0x8)) {
1109 ea3bd56f Christoph Hellwig
            goto fail;
1110 ea3bd56f Christoph Hellwig
        }
1111 ea3bd56f Christoph Hellwig
1112 ea3bd56f Christoph Hellwig
        rc = bdrv_discard(s->bs, r->req.cmd.lba * s->cluster_size,
1113 ea3bd56f Christoph Hellwig
                          len * s->cluster_size);
1114 ea3bd56f Christoph Hellwig
        if (rc < 0) {
1115 ea3bd56f Christoph Hellwig
            /* XXX: better error code ?*/
1116 ea3bd56f Christoph Hellwig
            goto fail;
1117 ea3bd56f Christoph Hellwig
        }
1118 ea3bd56f Christoph Hellwig
1119 ea3bd56f Christoph Hellwig
        break;
1120 2e5d83bb pbrook
    default:
1121 2dd791b6 Hannes Reinecke
        DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
1122 a1f0cce2 Hannes Reinecke
        scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_OPCODE));
1123 a1f0cce2 Hannes Reinecke
        return 0;
1124 2e5d83bb pbrook
    fail:
1125 a1f0cce2 Hannes Reinecke
        scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_FIELD));
1126 2dd791b6 Hannes Reinecke
        return 0;
1127 274fb0e1 aliguori
    illegal_lba:
1128 a1f0cce2 Hannes Reinecke
        scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(LBA_OUT_OF_RANGE));
1129 274fb0e1 aliguori
        return 0;
1130 2e5d83bb pbrook
    }
1131 c87c0672 aliguori
    if (r->sector_count == 0 && r->iov.iov_len == 0) {
1132 a1f0cce2 Hannes Reinecke
        scsi_command_complete(r, GOOD, SENSE_CODE(NO_SENSE));
1133 a917d384 pbrook
    }
1134 c87c0672 aliguori
    len = r->sector_count * 512 + r->iov.iov_len;
1135 a917d384 pbrook
    if (is_write) {
1136 ad2d30f7 Paolo Bonzini
        len = -len;
1137 a917d384 pbrook
    } else {
1138 a917d384 pbrook
        if (!r->sector_count)
1139 a917d384 pbrook
            r->sector_count = -1;
1140 2e5d83bb pbrook
    }
1141 ad2d30f7 Paolo Bonzini
    return len;
1142 2e5d83bb pbrook
}
1143 2e5d83bb pbrook
1144 e9447f35 Jan Kiszka
static void scsi_disk_reset(DeviceState *dev)
1145 e9447f35 Jan Kiszka
{
1146 e9447f35 Jan Kiszka
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev.qdev, dev);
1147 e9447f35 Jan Kiszka
    uint64_t nb_sectors;
1148 e9447f35 Jan Kiszka
1149 c557e889 Paolo Bonzini
    scsi_device_purge_requests(&s->qdev);
1150 e9447f35 Jan Kiszka
1151 e9447f35 Jan Kiszka
    bdrv_get_geometry(s->bs, &nb_sectors);
1152 e9447f35 Jan Kiszka
    nb_sectors /= s->cluster_size;
1153 e9447f35 Jan Kiszka
    if (nb_sectors) {
1154 e9447f35 Jan Kiszka
        nb_sectors--;
1155 e9447f35 Jan Kiszka
    }
1156 e9447f35 Jan Kiszka
    s->max_lba = nb_sectors;
1157 e9447f35 Jan Kiszka
}
1158 e9447f35 Jan Kiszka
1159 e9447f35 Jan Kiszka
static void scsi_destroy(SCSIDevice *dev)
1160 e9447f35 Jan Kiszka
{
1161 e9447f35 Jan Kiszka
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
1162 e9447f35 Jan Kiszka
1163 c557e889 Paolo Bonzini
    scsi_device_purge_requests(&s->qdev);
1164 f8b6cc00 Markus Armbruster
    blockdev_mark_auto_del(s->qdev.conf.bs);
1165 56a14938 Gerd Hoffmann
}
1166 56a14938 Gerd Hoffmann
1167 b443ae67 Markus Armbruster
static int scsi_initfn(SCSIDevice *dev, SCSIDriveKind kind)
1168 2e5d83bb pbrook
{
1169 d52affa7 Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
1170 f8b6cc00 Markus Armbruster
    DriveInfo *dinfo;
1171 2e5d83bb pbrook
1172 f8b6cc00 Markus Armbruster
    if (!s->qdev.conf.bs) {
1173 1ecda02b Markus Armbruster
        error_report("scsi-disk: drive property not set");
1174 d52affa7 Gerd Hoffmann
        return -1;
1175 d52affa7 Gerd Hoffmann
    }
1176 f8b6cc00 Markus Armbruster
    s->bs = s->qdev.conf.bs;
1177 b443ae67 Markus Armbruster
    s->drive_kind = kind;
1178 d52affa7 Gerd Hoffmann
1179 b443ae67 Markus Armbruster
    if (kind == SCSI_HD && !bdrv_is_inserted(s->bs)) {
1180 98f28ad7 Markus Armbruster
        error_report("Device needs media, but drive is empty");
1181 98f28ad7 Markus Armbruster
        return -1;
1182 98f28ad7 Markus Armbruster
    }
1183 98f28ad7 Markus Armbruster
1184 a0fef654 Markus Armbruster
    if (!s->serial) {
1185 f8b6cc00 Markus Armbruster
        /* try to fall back to value set with legacy -drive serial=... */
1186 f8b6cc00 Markus Armbruster
        dinfo = drive_get_by_blockdev(s->bs);
1187 f8b6cc00 Markus Armbruster
        s->serial = qemu_strdup(*dinfo->serial ? dinfo->serial : "0");
1188 a0fef654 Markus Armbruster
    }
1189 a0fef654 Markus Armbruster
1190 552fee93 Markus Armbruster
    if (!s->version) {
1191 552fee93 Markus Armbruster
        s->version = qemu_strdup(QEMU_VERSION);
1192 552fee93 Markus Armbruster
    }
1193 552fee93 Markus Armbruster
1194 32bb404a Markus Armbruster
    if (bdrv_is_sg(s->bs)) {
1195 1ecda02b Markus Armbruster
        error_report("scsi-disk: unwanted /dev/sg*");
1196 32bb404a Markus Armbruster
        return -1;
1197 32bb404a Markus Armbruster
    }
1198 32bb404a Markus Armbruster
1199 b443ae67 Markus Armbruster
    if (kind == SCSI_CD) {
1200 8cfacf07 Christoph Hellwig
        s->qdev.blocksize = 2048;
1201 2e5d83bb pbrook
    } else {
1202 8cfacf07 Christoph Hellwig
        s->qdev.blocksize = s->qdev.conf.logical_block_size;
1203 2e5d83bb pbrook
    }
1204 8cfacf07 Christoph Hellwig
    s->cluster_size = s->qdev.blocksize / 512;
1205 73fdb1e1 Christoph Hellwig
    s->bs->buffer_alignment = s->qdev.blocksize;
1206 8cfacf07 Christoph Hellwig
1207 91376656 Gerd Hoffmann
    s->qdev.type = TYPE_DISK;
1208 ea8a5d7f aliguori
    qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s);
1209 b443ae67 Markus Armbruster
    bdrv_set_removable(s->bs, kind == SCSI_CD);
1210 1ca4d09a Gleb Natapov
    add_boot_device_path(s->qdev.conf.bootindex, &dev->qdev, ",0");
1211 d52affa7 Gerd Hoffmann
    return 0;
1212 d52affa7 Gerd Hoffmann
}
1213 d52affa7 Gerd Hoffmann
1214 b443ae67 Markus Armbruster
static int scsi_hd_initfn(SCSIDevice *dev)
1215 b443ae67 Markus Armbruster
{
1216 b443ae67 Markus Armbruster
    return scsi_initfn(dev, SCSI_HD);
1217 b443ae67 Markus Armbruster
}
1218 b443ae67 Markus Armbruster
1219 b443ae67 Markus Armbruster
static int scsi_cd_initfn(SCSIDevice *dev)
1220 b443ae67 Markus Armbruster
{
1221 b443ae67 Markus Armbruster
    return scsi_initfn(dev, SCSI_CD);
1222 b443ae67 Markus Armbruster
}
1223 b443ae67 Markus Armbruster
1224 b443ae67 Markus Armbruster
static int scsi_disk_initfn(SCSIDevice *dev)
1225 b443ae67 Markus Armbruster
{
1226 b443ae67 Markus Armbruster
    SCSIDriveKind kind;
1227 95b5edcd Markus Armbruster
    DriveInfo *dinfo;
1228 b443ae67 Markus Armbruster
1229 b443ae67 Markus Armbruster
    if (!dev->conf.bs) {
1230 b443ae67 Markus Armbruster
        kind = SCSI_HD;         /* will die in scsi_initfn() */
1231 b443ae67 Markus Armbruster
    } else {
1232 95b5edcd Markus Armbruster
        dinfo = drive_get_by_blockdev(dev->conf.bs);
1233 95b5edcd Markus Armbruster
        kind = dinfo->media_cd ? SCSI_CD : SCSI_HD;
1234 b443ae67 Markus Armbruster
    }
1235 b443ae67 Markus Armbruster
1236 b443ae67 Markus Armbruster
    return scsi_initfn(dev, kind);
1237 b443ae67 Markus Armbruster
}
1238 b443ae67 Markus Armbruster
1239 b443ae67 Markus Armbruster
#define DEFINE_SCSI_DISK_PROPERTIES()                           \
1240 b443ae67 Markus Armbruster
    DEFINE_BLOCK_PROPERTIES(SCSIDiskState, qdev.conf),          \
1241 b443ae67 Markus Armbruster
    DEFINE_PROP_STRING("ver",  SCSIDiskState, version),         \
1242 b443ae67 Markus Armbruster
    DEFINE_PROP_STRING("serial",  SCSIDiskState, serial)
1243 b443ae67 Markus Armbruster
1244 b443ae67 Markus Armbruster
static SCSIDeviceInfo scsi_disk_info[] = {
1245 b443ae67 Markus Armbruster
    {
1246 b443ae67 Markus Armbruster
        .qdev.name    = "scsi-hd",
1247 b443ae67 Markus Armbruster
        .qdev.fw_name = "disk",
1248 b443ae67 Markus Armbruster
        .qdev.desc    = "virtual SCSI disk",
1249 b443ae67 Markus Armbruster
        .qdev.size    = sizeof(SCSIDiskState),
1250 b443ae67 Markus Armbruster
        .qdev.reset   = scsi_disk_reset,
1251 b443ae67 Markus Armbruster
        .init         = scsi_hd_initfn,
1252 b443ae67 Markus Armbruster
        .destroy      = scsi_destroy,
1253 5c6c0e51 Hannes Reinecke
        .alloc_req    = scsi_new_request,
1254 ad2d30f7 Paolo Bonzini
        .free_req     = scsi_free_request,
1255 b443ae67 Markus Armbruster
        .send_command = scsi_send_command,
1256 b443ae67 Markus Armbruster
        .read_data    = scsi_read_data,
1257 b443ae67 Markus Armbruster
        .write_data   = scsi_write_data,
1258 b443ae67 Markus Armbruster
        .cancel_io    = scsi_cancel_io,
1259 b443ae67 Markus Armbruster
        .get_buf      = scsi_get_buf,
1260 b443ae67 Markus Armbruster
        .qdev.props   = (Property[]) {
1261 b443ae67 Markus Armbruster
            DEFINE_SCSI_DISK_PROPERTIES(),
1262 b443ae67 Markus Armbruster
            DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false),
1263 b443ae67 Markus Armbruster
            DEFINE_PROP_END_OF_LIST(),
1264 b443ae67 Markus Armbruster
        }
1265 b443ae67 Markus Armbruster
    },{
1266 b443ae67 Markus Armbruster
        .qdev.name    = "scsi-cd",
1267 b443ae67 Markus Armbruster
        .qdev.fw_name = "disk",
1268 b443ae67 Markus Armbruster
        .qdev.desc    = "virtual SCSI CD-ROM",
1269 b443ae67 Markus Armbruster
        .qdev.size    = sizeof(SCSIDiskState),
1270 b443ae67 Markus Armbruster
        .qdev.reset   = scsi_disk_reset,
1271 b443ae67 Markus Armbruster
        .init         = scsi_cd_initfn,
1272 b443ae67 Markus Armbruster
        .destroy      = scsi_destroy,
1273 5c6c0e51 Hannes Reinecke
        .alloc_req    = scsi_new_request,
1274 ad2d30f7 Paolo Bonzini
        .free_req     = scsi_free_request,
1275 b443ae67 Markus Armbruster
        .send_command = scsi_send_command,
1276 b443ae67 Markus Armbruster
        .read_data    = scsi_read_data,
1277 b443ae67 Markus Armbruster
        .write_data   = scsi_write_data,
1278 b443ae67 Markus Armbruster
        .cancel_io    = scsi_cancel_io,
1279 b443ae67 Markus Armbruster
        .get_buf      = scsi_get_buf,
1280 b443ae67 Markus Armbruster
        .qdev.props   = (Property[]) {
1281 b443ae67 Markus Armbruster
            DEFINE_SCSI_DISK_PROPERTIES(),
1282 b443ae67 Markus Armbruster
            DEFINE_PROP_END_OF_LIST(),
1283 b443ae67 Markus Armbruster
        },
1284 b443ae67 Markus Armbruster
    },{
1285 b443ae67 Markus Armbruster
        .qdev.name    = "scsi-disk", /* legacy -device scsi-disk */
1286 b443ae67 Markus Armbruster
        .qdev.fw_name = "disk",
1287 b443ae67 Markus Armbruster
        .qdev.desc    = "virtual SCSI disk or CD-ROM (legacy)",
1288 b443ae67 Markus Armbruster
        .qdev.size    = sizeof(SCSIDiskState),
1289 b443ae67 Markus Armbruster
        .qdev.reset   = scsi_disk_reset,
1290 b443ae67 Markus Armbruster
        .init         = scsi_disk_initfn,
1291 b443ae67 Markus Armbruster
        .destroy      = scsi_destroy,
1292 5c6c0e51 Hannes Reinecke
        .alloc_req    = scsi_new_request,
1293 ad2d30f7 Paolo Bonzini
        .free_req     = scsi_free_request,
1294 b443ae67 Markus Armbruster
        .send_command = scsi_send_command,
1295 b443ae67 Markus Armbruster
        .read_data    = scsi_read_data,
1296 b443ae67 Markus Armbruster
        .write_data   = scsi_write_data,
1297 b443ae67 Markus Armbruster
        .cancel_io    = scsi_cancel_io,
1298 b443ae67 Markus Armbruster
        .get_buf      = scsi_get_buf,
1299 b443ae67 Markus Armbruster
        .qdev.props   = (Property[]) {
1300 b443ae67 Markus Armbruster
            DEFINE_SCSI_DISK_PROPERTIES(),
1301 b443ae67 Markus Armbruster
            DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false),
1302 b443ae67 Markus Armbruster
            DEFINE_PROP_END_OF_LIST(),
1303 b443ae67 Markus Armbruster
        }
1304 b443ae67 Markus Armbruster
    }
1305 d52affa7 Gerd Hoffmann
};
1306 d52affa7 Gerd Hoffmann
1307 d52affa7 Gerd Hoffmann
static void scsi_disk_register_devices(void)
1308 d52affa7 Gerd Hoffmann
{
1309 b443ae67 Markus Armbruster
    int i;
1310 b443ae67 Markus Armbruster
1311 b443ae67 Markus Armbruster
    for (i = 0; i < ARRAY_SIZE(scsi_disk_info); i++) {
1312 b443ae67 Markus Armbruster
        scsi_qdev_register(&scsi_disk_info[i]);
1313 b443ae67 Markus Armbruster
    }
1314 8ccc2ace ths
}
1315 d52affa7 Gerd Hoffmann
device_init(scsi_disk_register_devices)