Statistics
| Branch: | Revision:

root / hw / scsi-disk.c @ c557e889

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