Statistics
| Branch: | Revision:

root / hw / scsi-disk.c @ e44089c7

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