Statistics
| Branch: | Revision:

root / hw / scsi-disk.c @ 845f85fa

History | View | Annotate | Download (40.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 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 b443ae67 Markus Armbruster
typedef enum { SCSI_HD, SCSI_CD } SCSIDriveKind;
63 b443ae67 Markus Armbruster
64 d52affa7 Gerd Hoffmann
struct SCSIDiskState
65 a917d384 pbrook
{
66 d52affa7 Gerd Hoffmann
    SCSIDevice qdev;
67 428c149b Christoph Hellwig
    BlockDriverState *bs;
68 a917d384 pbrook
    /* The qemu block layer uses a fixed 512 byte sector size.
69 a917d384 pbrook
       This is the number of 512 byte blocks in a single scsi sector.  */
70 a917d384 pbrook
    int cluster_size;
71 419e691f Stefan Hajnoczi
    uint32_t removable;
72 274fb0e1 aliguori
    uint64_t max_lba;
73 213189ab Markus Armbruster
    QEMUBH *bh;
74 383b4d9b Gerd Hoffmann
    char *version;
75 a0fef654 Markus Armbruster
    char *serial;
76 a6d96eb7 Hannes Reinecke
    SCSISense sense;
77 b443ae67 Markus Armbruster
    SCSIDriveKind drive_kind;
78 2e5d83bb pbrook
};
79 2e5d83bb pbrook
80 5dba48a8 Kevin Wolf
static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type);
81 78ced65e Kevin Wolf
static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf);
82 5dba48a8 Kevin Wolf
83 5c6c0e51 Hannes Reinecke
static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag,
84 72aef731 Christoph Hellwig
        uint32_t lun)
85 2e5d83bb pbrook
{
86 5c6c0e51 Hannes Reinecke
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
87 89b08ae1 Gerd Hoffmann
    SCSIRequest *req;
88 4c41d2ef Gerd Hoffmann
    SCSIDiskReq *r;
89 a917d384 pbrook
90 72aef731 Christoph Hellwig
    req = scsi_req_alloc(sizeof(SCSIDiskReq), &s->qdev, tag, lun);
91 89b08ae1 Gerd Hoffmann
    r = DO_UPCAST(SCSIDiskReq, req, req);
92 72aef731 Christoph Hellwig
    r->iov.iov_base = qemu_blockalign(s->bs, SCSI_DMA_BUF_SIZE);
93 5c6c0e51 Hannes Reinecke
    return req;
94 2e5d83bb pbrook
}
95 2e5d83bb pbrook
96 ad2d30f7 Paolo Bonzini
static void scsi_free_request(SCSIRequest *req)
97 4d611c9a pbrook
{
98 ad2d30f7 Paolo Bonzini
    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
99 ad2d30f7 Paolo Bonzini
100 f8a83245 Herve Poussineau
    qemu_vfree(r->iov.iov_base);
101 4d611c9a pbrook
}
102 4d611c9a pbrook
103 a6d96eb7 Hannes Reinecke
static void scsi_disk_clear_sense(SCSIDiskState *s)
104 ed3a34a3 Gerd Hoffmann
{
105 a6d96eb7 Hannes Reinecke
    memset(&s->sense, 0, sizeof(s->sense));
106 a6d96eb7 Hannes Reinecke
}
107 a6d96eb7 Hannes Reinecke
108 a1f0cce2 Hannes Reinecke
static void scsi_req_set_status(SCSIDiskReq *r, int status, SCSISense sense)
109 a6d96eb7 Hannes Reinecke
{
110 a6d96eb7 Hannes Reinecke
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
111 a6d96eb7 Hannes Reinecke
112 a6d96eb7 Hannes Reinecke
    r->req.status = status;
113 a1f0cce2 Hannes Reinecke
    s->sense = sense;
114 ed3a34a3 Gerd Hoffmann
}
115 ed3a34a3 Gerd Hoffmann
116 a917d384 pbrook
/* Helper function for command completion.  */
117 a1f0cce2 Hannes Reinecke
static void scsi_command_complete(SCSIDiskReq *r, int status, SCSISense sense)
118 a917d384 pbrook
{
119 a1f0cce2 Hannes Reinecke
    DPRINTF("Command complete tag=0x%x status=%d sense=%d/%d/%d\n",
120 a1f0cce2 Hannes Reinecke
            r->req.tag, status, sense.key, sense.asc, sense.ascq);
121 a6d96eb7 Hannes Reinecke
    scsi_req_set_status(r, status, sense);
122 ed3a34a3 Gerd Hoffmann
    scsi_req_complete(&r->req);
123 4d611c9a pbrook
}
124 4d611c9a pbrook
125 4d611c9a pbrook
/* Cancel a pending data transfer.  */
126 5c6c0e51 Hannes Reinecke
static void scsi_cancel_io(SCSIRequest *req)
127 4d611c9a pbrook
{
128 5c6c0e51 Hannes Reinecke
    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
129 5c6c0e51 Hannes Reinecke
130 5c6c0e51 Hannes Reinecke
    DPRINTF("Cancel tag=0x%x\n", req->tag);
131 5c6c0e51 Hannes Reinecke
    if (r->req.aiocb) {
132 5c6c0e51 Hannes Reinecke
        bdrv_aio_cancel(r->req.aiocb);
133 a917d384 pbrook
    }
134 5c6c0e51 Hannes Reinecke
    r->req.aiocb = NULL;
135 a917d384 pbrook
}
136 a917d384 pbrook
137 a917d384 pbrook
static void scsi_read_complete(void * opaque, int ret)
138 a917d384 pbrook
{
139 4c41d2ef Gerd Hoffmann
    SCSIDiskReq *r = (SCSIDiskReq *)opaque;
140 5dba48a8 Kevin Wolf
    int n;
141 a917d384 pbrook
142 3e94cb02 Jan Kiszka
    r->req.aiocb = NULL;
143 3e94cb02 Jan Kiszka
144 a917d384 pbrook
    if (ret) {
145 5dba48a8 Kevin Wolf
        if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_READ)) {
146 5dba48a8 Kevin Wolf
            return;
147 5dba48a8 Kevin Wolf
        }
148 4d611c9a pbrook
    }
149 5dba48a8 Kevin Wolf
150 aa2b1e89 Bernhard Kohl
    DPRINTF("Data ready tag=0x%x len=%zd\n", r->req.tag, r->iov.iov_len);
151 a917d384 pbrook
152 5dba48a8 Kevin Wolf
    n = r->iov.iov_len / 512;
153 5dba48a8 Kevin Wolf
    r->sector += n;
154 5dba48a8 Kevin Wolf
    r->sector_count -= n;
155 ab9adc88 Paolo Bonzini
    scsi_req_data(&r->req, r->iov.iov_len);
156 4d611c9a pbrook
}
157 4d611c9a pbrook
158 5dba48a8 Kevin Wolf
159 5c6c0e51 Hannes Reinecke
/* Read more data from scsi device into buffer.  */
160 5c6c0e51 Hannes Reinecke
static void scsi_read_data(SCSIRequest *req)
161 2e5d83bb pbrook
{
162 5c6c0e51 Hannes Reinecke
    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
163 5dba48a8 Kevin Wolf
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
164 2e5d83bb pbrook
    uint32_t n;
165 2e5d83bb pbrook
166 a917d384 pbrook
    if (r->sector_count == (uint32_t)-1) {
167 aa2b1e89 Bernhard Kohl
        DPRINTF("Read buf_len=%zd\n", r->iov.iov_len);
168 a917d384 pbrook
        r->sector_count = 0;
169 ab9adc88 Paolo Bonzini
        scsi_req_data(&r->req, r->iov.iov_len);
170 a917d384 pbrook
        return;
171 2e5d83bb pbrook
    }
172 a917d384 pbrook
    DPRINTF("Read sector_count=%d\n", r->sector_count);
173 a917d384 pbrook
    if (r->sector_count == 0) {
174 a1f0cce2 Hannes Reinecke
        scsi_command_complete(r, GOOD, SENSE_CODE(NO_SENSE));
175 a917d384 pbrook
        return;
176 2e5d83bb pbrook
    }
177 2e5d83bb pbrook
178 6fa2c95f Stefan Hajnoczi
    /* No data transfer may already be in progress */
179 6fa2c95f Stefan Hajnoczi
    assert(r->req.aiocb == NULL);
180 6fa2c95f Stefan Hajnoczi
181 efb9ee02 Hannes Reinecke
    if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
182 efb9ee02 Hannes Reinecke
        DPRINTF("Data transfer direction invalid\n");
183 efb9ee02 Hannes Reinecke
        scsi_read_complete(r, -EINVAL);
184 efb9ee02 Hannes Reinecke
        return;
185 efb9ee02 Hannes Reinecke
    }
186 efb9ee02 Hannes Reinecke
187 a917d384 pbrook
    n = r->sector_count;
188 a917d384 pbrook
    if (n > SCSI_DMA_BUF_SIZE / 512)
189 a917d384 pbrook
        n = SCSI_DMA_BUF_SIZE / 512;
190 a917d384 pbrook
191 c87c0672 aliguori
    r->iov.iov_len = n * 512;
192 c87c0672 aliguori
    qemu_iovec_init_external(&r->qiov, &r->iov, 1);
193 428c149b Christoph Hellwig
    r->req.aiocb = bdrv_aio_readv(s->bs, r->sector, &r->qiov, n,
194 c87c0672 aliguori
                              scsi_read_complete, r);
195 d33ea50a Kevin Wolf
    if (r->req.aiocb == NULL) {
196 d33ea50a Kevin Wolf
        scsi_read_complete(r, -EIO);
197 d33ea50a Kevin Wolf
    }
198 2e5d83bb pbrook
}
199 2e5d83bb pbrook
200 5dba48a8 Kevin Wolf
static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type)
201 5dba48a8 Kevin Wolf
{
202 5dba48a8 Kevin Wolf
    int is_read = (type == SCSI_REQ_STATUS_RETRY_READ);
203 4c41d2ef Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
204 5dba48a8 Kevin Wolf
    BlockErrorAction action = bdrv_get_on_error(s->bs, is_read);
205 ea8a5d7f aliguori
206 380f640f Luiz Capitulino
    if (action == BLOCK_ERR_IGNORE) {
207 5dba48a8 Kevin Wolf
        bdrv_mon_event(s->bs, BDRV_ACTION_IGNORE, is_read);
208 ea8a5d7f aliguori
        return 0;
209 380f640f Luiz Capitulino
    }
210 ea8a5d7f aliguori
211 ea8a5d7f aliguori
    if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC)
212 ea8a5d7f aliguori
            || action == BLOCK_ERR_STOP_ANY) {
213 5dba48a8 Kevin Wolf
214 5dba48a8 Kevin Wolf
        type &= SCSI_REQ_STATUS_RETRY_TYPE_MASK;
215 5dba48a8 Kevin Wolf
        r->status |= SCSI_REQ_STATUS_RETRY | type;
216 5dba48a8 Kevin Wolf
217 5dba48a8 Kevin Wolf
        bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read);
218 e07bbac5 Jan Kiszka
        vm_stop(VMSTOP_DISKFULL);
219 ea8a5d7f aliguori
    } else {
220 5dba48a8 Kevin Wolf
        if (type == SCSI_REQ_STATUS_RETRY_READ) {
221 ab9adc88 Paolo Bonzini
            scsi_req_data(&r->req, 0);
222 5dba48a8 Kevin Wolf
        }
223 efb9ee02 Hannes Reinecke
        switch (error) {
224 efb9ee02 Hannes Reinecke
        case ENOMEM:
225 a1f0cce2 Hannes Reinecke
            scsi_command_complete(r, CHECK_CONDITION,
226 a1f0cce2 Hannes Reinecke
                                  SENSE_CODE(TARGET_FAILURE));
227 efb9ee02 Hannes Reinecke
            break;
228 efb9ee02 Hannes Reinecke
        case EINVAL:
229 efb9ee02 Hannes Reinecke
            scsi_command_complete(r, CHECK_CONDITION,
230 efb9ee02 Hannes Reinecke
                                  SENSE_CODE(INVALID_FIELD));
231 efb9ee02 Hannes Reinecke
            break;
232 efb9ee02 Hannes Reinecke
        default:
233 a1f0cce2 Hannes Reinecke
            scsi_command_complete(r, CHECK_CONDITION,
234 a1f0cce2 Hannes Reinecke
                                  SENSE_CODE(IO_ERROR));
235 efb9ee02 Hannes Reinecke
            break;
236 a1f0cce2 Hannes Reinecke
        }
237 5dba48a8 Kevin Wolf
        bdrv_mon_event(s->bs, BDRV_ACTION_REPORT, is_read);
238 ea8a5d7f aliguori
    }
239 ea8a5d7f aliguori
    return 1;
240 ea8a5d7f aliguori
}
241 ea8a5d7f aliguori
242 4d611c9a pbrook
static void scsi_write_complete(void * opaque, int ret)
243 4d611c9a pbrook
{
244 4c41d2ef Gerd Hoffmann
    SCSIDiskReq *r = (SCSIDiskReq *)opaque;
245 a917d384 pbrook
    uint32_t len;
246 ea8a5d7f aliguori
    uint32_t n;
247 ea8a5d7f aliguori
248 4c41d2ef Gerd Hoffmann
    r->req.aiocb = NULL;
249 4d611c9a pbrook
250 4d611c9a pbrook
    if (ret) {
251 5dba48a8 Kevin Wolf
        if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_WRITE)) {
252 ea8a5d7f aliguori
            return;
253 5dba48a8 Kevin Wolf
        }
254 4d611c9a pbrook
    }
255 4d611c9a pbrook
256 c87c0672 aliguori
    n = r->iov.iov_len / 512;
257 ea8a5d7f aliguori
    r->sector += n;
258 ea8a5d7f aliguori
    r->sector_count -= n;
259 a917d384 pbrook
    if (r->sector_count == 0) {
260 a1f0cce2 Hannes Reinecke
        scsi_command_complete(r, GOOD, SENSE_CODE(NO_SENSE));
261 a917d384 pbrook
    } else {
262 a917d384 pbrook
        len = r->sector_count * 512;
263 a917d384 pbrook
        if (len > SCSI_DMA_BUF_SIZE) {
264 a917d384 pbrook
            len = SCSI_DMA_BUF_SIZE;
265 a917d384 pbrook
        }
266 c87c0672 aliguori
        r->iov.iov_len = len;
267 4c41d2ef Gerd Hoffmann
        DPRINTF("Write complete tag=0x%x more=%d\n", r->req.tag, len);
268 ab9adc88 Paolo Bonzini
        scsi_req_data(&r->req, len);
269 4d611c9a pbrook
    }
270 4d611c9a pbrook
}
271 4d611c9a pbrook
272 42741212 Paolo Bonzini
static void scsi_write_data(SCSIRequest *req)
273 ea8a5d7f aliguori
{
274 5c6c0e51 Hannes Reinecke
    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
275 4c41d2ef Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
276 ea8a5d7f aliguori
    uint32_t n;
277 ea8a5d7f aliguori
278 6fa2c95f Stefan Hajnoczi
    /* No data transfer may already be in progress */
279 6fa2c95f Stefan Hajnoczi
    assert(r->req.aiocb == NULL);
280 6fa2c95f Stefan Hajnoczi
281 efb9ee02 Hannes Reinecke
    if (r->req.cmd.mode != SCSI_XFER_TO_DEV) {
282 efb9ee02 Hannes Reinecke
        DPRINTF("Data transfer direction invalid\n");
283 efb9ee02 Hannes Reinecke
        scsi_write_complete(r, -EINVAL);
284 42741212 Paolo Bonzini
        return;
285 efb9ee02 Hannes Reinecke
    }
286 efb9ee02 Hannes Reinecke
287 c87c0672 aliguori
    n = r->iov.iov_len / 512;
288 ea8a5d7f aliguori
    if (n) {
289 c87c0672 aliguori
        qemu_iovec_init_external(&r->qiov, &r->iov, 1);
290 428c149b Christoph Hellwig
        r->req.aiocb = bdrv_aio_writev(s->bs, r->sector, &r->qiov, n,
291 c87c0672 aliguori
                                   scsi_write_complete, r);
292 d33ea50a Kevin Wolf
        if (r->req.aiocb == NULL) {
293 a1f0cce2 Hannes Reinecke
            scsi_write_complete(r, -ENOMEM);
294 d33ea50a Kevin Wolf
        }
295 ea8a5d7f aliguori
    } else {
296 ea8a5d7f aliguori
        /* Invoke completion routine to fetch data from host.  */
297 ea8a5d7f aliguori
        scsi_write_complete(r, 0);
298 ea8a5d7f aliguori
    }
299 a917d384 pbrook
}
300 2e5d83bb pbrook
301 213189ab Markus Armbruster
static void scsi_dma_restart_bh(void *opaque)
302 ea8a5d7f aliguori
{
303 d52affa7 Gerd Hoffmann
    SCSIDiskState *s = opaque;
304 9af99d98 Gerd Hoffmann
    SCSIRequest *req;
305 9af99d98 Gerd Hoffmann
    SCSIDiskReq *r;
306 213189ab Markus Armbruster
307 213189ab Markus Armbruster
    qemu_bh_delete(s->bh);
308 213189ab Markus Armbruster
    s->bh = NULL;
309 ea8a5d7f aliguori
310 9af99d98 Gerd Hoffmann
    QTAILQ_FOREACH(req, &s->qdev.requests, next) {
311 9af99d98 Gerd Hoffmann
        r = DO_UPCAST(SCSIDiskReq, req, req);
312 ea8a5d7f aliguori
        if (r->status & SCSI_REQ_STATUS_RETRY) {
313 5dba48a8 Kevin Wolf
            int status = r->status;
314 78ced65e Kevin Wolf
            int ret;
315 78ced65e Kevin Wolf
316 5dba48a8 Kevin Wolf
            r->status &=
317 5dba48a8 Kevin Wolf
                ~(SCSI_REQ_STATUS_RETRY | SCSI_REQ_STATUS_RETRY_TYPE_MASK);
318 5dba48a8 Kevin Wolf
319 5dba48a8 Kevin Wolf
            switch (status & SCSI_REQ_STATUS_RETRY_TYPE_MASK) {
320 5dba48a8 Kevin Wolf
            case SCSI_REQ_STATUS_RETRY_READ:
321 5c6c0e51 Hannes Reinecke
                scsi_read_data(&r->req);
322 5dba48a8 Kevin Wolf
                break;
323 5dba48a8 Kevin Wolf
            case SCSI_REQ_STATUS_RETRY_WRITE:
324 5c6c0e51 Hannes Reinecke
                scsi_write_data(&r->req);
325 5dba48a8 Kevin Wolf
                break;
326 78ced65e Kevin Wolf
            case SCSI_REQ_STATUS_RETRY_FLUSH:
327 78ced65e Kevin Wolf
                ret = scsi_disk_emulate_command(r, r->iov.iov_base);
328 78ced65e Kevin Wolf
                if (ret == 0) {
329 a1f0cce2 Hannes Reinecke
                    scsi_command_complete(r, GOOD, SENSE_CODE(NO_SENSE));
330 78ced65e Kevin Wolf
                }
331 5dba48a8 Kevin Wolf
            }
332 ea8a5d7f aliguori
        }
333 ea8a5d7f aliguori
    }
334 ea8a5d7f aliguori
}
335 ea8a5d7f aliguori
336 213189ab Markus Armbruster
static void scsi_dma_restart_cb(void *opaque, int running, int reason)
337 213189ab Markus Armbruster
{
338 d52affa7 Gerd Hoffmann
    SCSIDiskState *s = opaque;
339 213189ab Markus Armbruster
340 213189ab Markus Armbruster
    if (!running)
341 213189ab Markus Armbruster
        return;
342 213189ab Markus Armbruster
343 213189ab Markus Armbruster
    if (!s->bh) {
344 213189ab Markus Armbruster
        s->bh = qemu_bh_new(scsi_dma_restart_bh, s);
345 213189ab Markus Armbruster
        qemu_bh_schedule(s->bh);
346 213189ab Markus Armbruster
    }
347 213189ab Markus Armbruster
}
348 213189ab Markus Armbruster
349 a917d384 pbrook
/* Return a pointer to the data buffer.  */
350 5c6c0e51 Hannes Reinecke
static uint8_t *scsi_get_buf(SCSIRequest *req)
351 a917d384 pbrook
{
352 5c6c0e51 Hannes Reinecke
    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
353 2e5d83bb pbrook
354 3f4cb3d3 blueswir1
    return (uint8_t *)r->iov.iov_base;
355 2e5d83bb pbrook
}
356 2e5d83bb pbrook
357 74382217 Hannes Reinecke
/* Copy sense information into the provided buffer */
358 74382217 Hannes Reinecke
static int scsi_get_sense(SCSIRequest *req, uint8_t *outbuf, int len)
359 74382217 Hannes Reinecke
{
360 74382217 Hannes Reinecke
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
361 74382217 Hannes Reinecke
362 74382217 Hannes Reinecke
    return scsi_build_sense(s->sense, outbuf, len, len > 14);
363 74382217 Hannes Reinecke
}
364 74382217 Hannes Reinecke
365 0b06c059 Gerd Hoffmann
static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
366 0b06c059 Gerd Hoffmann
{
367 383b4d9b Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
368 0b06c059 Gerd Hoffmann
    int buflen = 0;
369 0b06c059 Gerd Hoffmann
370 0b06c059 Gerd Hoffmann
    if (req->cmd.buf[1] & 0x2) {
371 0b06c059 Gerd Hoffmann
        /* Command support data - optional, not implemented */
372 0b06c059 Gerd Hoffmann
        BADF("optional INQUIRY command support request not implemented\n");
373 0b06c059 Gerd Hoffmann
        return -1;
374 0b06c059 Gerd Hoffmann
    }
375 0b06c059 Gerd Hoffmann
376 0b06c059 Gerd Hoffmann
    if (req->cmd.buf[1] & 0x1) {
377 0b06c059 Gerd Hoffmann
        /* Vital product data */
378 0b06c059 Gerd Hoffmann
        uint8_t page_code = req->cmd.buf[2];
379 0b06c059 Gerd Hoffmann
        if (req->cmd.xfer < 4) {
380 0b06c059 Gerd Hoffmann
            BADF("Error: Inquiry (EVPD[%02X]) buffer size %zd is "
381 0b06c059 Gerd Hoffmann
                 "less than 4\n", page_code, req->cmd.xfer);
382 0b06c059 Gerd Hoffmann
            return -1;
383 0b06c059 Gerd Hoffmann
        }
384 0b06c059 Gerd Hoffmann
385 b443ae67 Markus Armbruster
        if (s->drive_kind == SCSI_CD) {
386 0b06c059 Gerd Hoffmann
            outbuf[buflen++] = 5;
387 0b06c059 Gerd Hoffmann
        } else {
388 0b06c059 Gerd Hoffmann
            outbuf[buflen++] = 0;
389 0b06c059 Gerd Hoffmann
        }
390 0b06c059 Gerd Hoffmann
        outbuf[buflen++] = page_code ; // this page
391 0b06c059 Gerd Hoffmann
        outbuf[buflen++] = 0x00;
392 0b06c059 Gerd Hoffmann
393 0b06c059 Gerd Hoffmann
        switch (page_code) {
394 0b06c059 Gerd Hoffmann
        case 0x00: /* Supported page codes, mandatory */
395 39d98982 Hannes Reinecke
        {
396 39d98982 Hannes Reinecke
            int pages;
397 0b06c059 Gerd Hoffmann
            DPRINTF("Inquiry EVPD[Supported pages] "
398 0b06c059 Gerd Hoffmann
                    "buffer size %zd\n", req->cmd.xfer);
399 39d98982 Hannes Reinecke
            pages = buflen++;
400 0b06c059 Gerd Hoffmann
            outbuf[buflen++] = 0x00; // list of supported pages (this page)
401 0b06c059 Gerd Hoffmann
            outbuf[buflen++] = 0x80; // unit serial number
402 0b06c059 Gerd Hoffmann
            outbuf[buflen++] = 0x83; // device identification
403 b443ae67 Markus Armbruster
            if (s->drive_kind == SCSI_HD) {
404 ea3bd56f Christoph Hellwig
                outbuf[buflen++] = 0xb0; // block limits
405 ea3bd56f Christoph Hellwig
                outbuf[buflen++] = 0xb2; // thin provisioning
406 39d98982 Hannes Reinecke
            }
407 39d98982 Hannes Reinecke
            outbuf[pages] = buflen - pages - 1; // number of pages
408 0b06c059 Gerd Hoffmann
            break;
409 39d98982 Hannes Reinecke
        }
410 0b06c059 Gerd Hoffmann
        case 0x80: /* Device serial number, optional */
411 0b06c059 Gerd Hoffmann
        {
412 a0fef654 Markus Armbruster
            int l = strlen(s->serial);
413 0b06c059 Gerd Hoffmann
414 0b06c059 Gerd Hoffmann
            if (l > req->cmd.xfer)
415 0b06c059 Gerd Hoffmann
                l = req->cmd.xfer;
416 0b06c059 Gerd Hoffmann
            if (l > 20)
417 0b06c059 Gerd Hoffmann
                l = 20;
418 0b06c059 Gerd Hoffmann
419 0b06c059 Gerd Hoffmann
            DPRINTF("Inquiry EVPD[Serial number] "
420 0b06c059 Gerd Hoffmann
                    "buffer size %zd\n", req->cmd.xfer);
421 0b06c059 Gerd Hoffmann
            outbuf[buflen++] = l;
422 a0fef654 Markus Armbruster
            memcpy(outbuf+buflen, s->serial, l);
423 0b06c059 Gerd Hoffmann
            buflen += l;
424 0b06c059 Gerd Hoffmann
            break;
425 0b06c059 Gerd Hoffmann
        }
426 0b06c059 Gerd Hoffmann
427 0b06c059 Gerd Hoffmann
        case 0x83: /* Device identification page, mandatory */
428 0b06c059 Gerd Hoffmann
        {
429 0b06c059 Gerd Hoffmann
            int max_len = 255 - 8;
430 428c149b Christoph Hellwig
            int id_len = strlen(bdrv_get_device_name(s->bs));
431 0b06c059 Gerd Hoffmann
432 0b06c059 Gerd Hoffmann
            if (id_len > max_len)
433 0b06c059 Gerd Hoffmann
                id_len = max_len;
434 0b06c059 Gerd Hoffmann
            DPRINTF("Inquiry EVPD[Device identification] "
435 0b06c059 Gerd Hoffmann
                    "buffer size %zd\n", req->cmd.xfer);
436 0b06c059 Gerd Hoffmann
437 39d98982 Hannes Reinecke
            outbuf[buflen++] = 4 + id_len;
438 0b06c059 Gerd Hoffmann
            outbuf[buflen++] = 0x2; // ASCII
439 0b06c059 Gerd Hoffmann
            outbuf[buflen++] = 0;   // not officially assigned
440 0b06c059 Gerd Hoffmann
            outbuf[buflen++] = 0;   // reserved
441 0b06c059 Gerd Hoffmann
            outbuf[buflen++] = id_len; // length of data following
442 0b06c059 Gerd Hoffmann
443 428c149b Christoph Hellwig
            memcpy(outbuf+buflen, bdrv_get_device_name(s->bs), id_len);
444 0b06c059 Gerd Hoffmann
            buflen += id_len;
445 0b06c059 Gerd Hoffmann
            break;
446 0b06c059 Gerd Hoffmann
        }
447 ea3bd56f Christoph Hellwig
        case 0xb0: /* block limits */
448 ee3659e3 Christoph Hellwig
        {
449 ea3bd56f Christoph Hellwig
            unsigned int unmap_sectors =
450 ea3bd56f Christoph Hellwig
                    s->qdev.conf.discard_granularity / s->qdev.blocksize;
451 8cfacf07 Christoph Hellwig
            unsigned int min_io_size =
452 8cfacf07 Christoph Hellwig
                    s->qdev.conf.min_io_size / s->qdev.blocksize;
453 8cfacf07 Christoph Hellwig
            unsigned int opt_io_size =
454 8cfacf07 Christoph Hellwig
                    s->qdev.conf.opt_io_size / s->qdev.blocksize;
455 ee3659e3 Christoph Hellwig
456 b443ae67 Markus Armbruster
            if (s->drive_kind == SCSI_CD) {
457 39d98982 Hannes Reinecke
                DPRINTF("Inquiry (EVPD[%02X] not supported for CDROM\n",
458 39d98982 Hannes Reinecke
                        page_code);
459 39d98982 Hannes Reinecke
                return -1;
460 39d98982 Hannes Reinecke
            }
461 ee3659e3 Christoph Hellwig
            /* required VPD size with unmap support */
462 ee3659e3 Christoph Hellwig
            outbuf[3] = buflen = 0x3c;
463 ee3659e3 Christoph Hellwig
464 ee3659e3 Christoph Hellwig
            memset(outbuf + 4, 0, buflen - 4);
465 ee3659e3 Christoph Hellwig
466 ee3659e3 Christoph Hellwig
            /* optimal transfer length granularity */
467 ee3659e3 Christoph Hellwig
            outbuf[6] = (min_io_size >> 8) & 0xff;
468 ee3659e3 Christoph Hellwig
            outbuf[7] = min_io_size & 0xff;
469 ee3659e3 Christoph Hellwig
470 ee3659e3 Christoph Hellwig
            /* optimal transfer length */
471 ee3659e3 Christoph Hellwig
            outbuf[12] = (opt_io_size >> 24) & 0xff;
472 ee3659e3 Christoph Hellwig
            outbuf[13] = (opt_io_size >> 16) & 0xff;
473 ee3659e3 Christoph Hellwig
            outbuf[14] = (opt_io_size >> 8) & 0xff;
474 ee3659e3 Christoph Hellwig
            outbuf[15] = opt_io_size & 0xff;
475 ea3bd56f Christoph Hellwig
476 ea3bd56f Christoph Hellwig
            /* optimal unmap granularity */
477 ea3bd56f Christoph Hellwig
            outbuf[28] = (unmap_sectors >> 24) & 0xff;
478 ea3bd56f Christoph Hellwig
            outbuf[29] = (unmap_sectors >> 16) & 0xff;
479 ea3bd56f Christoph Hellwig
            outbuf[30] = (unmap_sectors >> 8) & 0xff;
480 ea3bd56f Christoph Hellwig
            outbuf[31] = unmap_sectors & 0xff;
481 ea3bd56f Christoph Hellwig
            break;
482 ea3bd56f Christoph Hellwig
        }
483 ea3bd56f Christoph Hellwig
        case 0xb2: /* thin provisioning */
484 ea3bd56f Christoph Hellwig
        {
485 ea3bd56f Christoph Hellwig
            outbuf[3] = buflen = 8;
486 ea3bd56f Christoph Hellwig
            outbuf[4] = 0;
487 ea3bd56f Christoph Hellwig
            outbuf[5] = 0x40; /* write same with unmap supported */
488 ea3bd56f Christoph Hellwig
            outbuf[6] = 0;
489 ea3bd56f Christoph Hellwig
            outbuf[7] = 0;
490 ee3659e3 Christoph Hellwig
            break;
491 ee3659e3 Christoph Hellwig
        }
492 0b06c059 Gerd Hoffmann
        default:
493 0b06c059 Gerd Hoffmann
            BADF("Error: unsupported Inquiry (EVPD[%02X]) "
494 0b06c059 Gerd Hoffmann
                 "buffer size %zd\n", page_code, req->cmd.xfer);
495 0b06c059 Gerd Hoffmann
            return -1;
496 0b06c059 Gerd Hoffmann
        }
497 0b06c059 Gerd Hoffmann
        /* done with EVPD */
498 0b06c059 Gerd Hoffmann
        return buflen;
499 0b06c059 Gerd Hoffmann
    }
500 0b06c059 Gerd Hoffmann
501 0b06c059 Gerd Hoffmann
    /* Standard INQUIRY data */
502 0b06c059 Gerd Hoffmann
    if (req->cmd.buf[2] != 0) {
503 0b06c059 Gerd Hoffmann
        BADF("Error: Inquiry (STANDARD) page or code "
504 0b06c059 Gerd Hoffmann
             "is non-zero [%02X]\n", req->cmd.buf[2]);
505 0b06c059 Gerd Hoffmann
        return -1;
506 0b06c059 Gerd Hoffmann
    }
507 0b06c059 Gerd Hoffmann
508 0b06c059 Gerd Hoffmann
    /* PAGE CODE == 0 */
509 0b06c059 Gerd Hoffmann
    if (req->cmd.xfer < 5) {
510 0b06c059 Gerd Hoffmann
        BADF("Error: Inquiry (STANDARD) buffer size %zd "
511 0b06c059 Gerd Hoffmann
             "is less than 5\n", req->cmd.xfer);
512 0b06c059 Gerd Hoffmann
        return -1;
513 0b06c059 Gerd Hoffmann
    }
514 0b06c059 Gerd Hoffmann
515 0b06c059 Gerd Hoffmann
    buflen = req->cmd.xfer;
516 0b06c059 Gerd Hoffmann
    if (buflen > SCSI_MAX_INQUIRY_LEN)
517 0b06c059 Gerd Hoffmann
        buflen = SCSI_MAX_INQUIRY_LEN;
518 0b06c059 Gerd Hoffmann
519 0b06c059 Gerd Hoffmann
    memset(outbuf, 0, buflen);
520 0b06c059 Gerd Hoffmann
521 1455084e Paolo Bonzini
    if (req->lun) {
522 0b06c059 Gerd Hoffmann
        outbuf[0] = 0x7f;        /* LUN not supported */
523 0b06c059 Gerd Hoffmann
        return buflen;
524 0b06c059 Gerd Hoffmann
    }
525 0b06c059 Gerd Hoffmann
526 b443ae67 Markus Armbruster
    if (s->drive_kind == SCSI_CD) {
527 0b06c059 Gerd Hoffmann
        outbuf[0] = 5;
528 0b06c059 Gerd Hoffmann
        outbuf[1] = 0x80;
529 550fe6c6 Laszlo Ast
        memcpy(&outbuf[16], "QEMU CD-ROM     ", 16);
530 0b06c059 Gerd Hoffmann
    } else {
531 0b06c059 Gerd Hoffmann
        outbuf[0] = 0;
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 b443ae67 Markus Armbruster
        if (s->drive_kind != SCSI_CD)
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 aa5dbdc1 Gerd Hoffmann
        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 0b06c059 Gerd Hoffmann
        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 b443ae67 Markus Armbruster
        if (s->drive_kind == SCSI_CD && (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 8d3628ff Gerd Hoffmann
        break;
878 c68b9f34 Gerd Hoffmann
    case ALLOW_MEDIUM_REMOVAL:
879 428c149b Christoph Hellwig
        bdrv_set_locked(s->bs, req->cmd.buf[4] & 1);
880 c68b9f34 Gerd Hoffmann
        break;
881 e7e25e32 Gerd Hoffmann
    case READ_CAPACITY:
882 e7e25e32 Gerd Hoffmann
        /* The normal LEN field for this command is zero.  */
883 e7e25e32 Gerd Hoffmann
        memset(outbuf, 0, 8);
884 428c149b Christoph Hellwig
        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 e7e25e32 Gerd Hoffmann
        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 88f8a5ed Gerd Hoffmann
    case VERIFY:
967 88f8a5ed Gerd Hoffmann
        break;
968 ebef0bbb Bernhard Kohl
    case REZERO_UNIT:
969 ebef0bbb Bernhard Kohl
        DPRINTF("Rezero Unit\n");
970 ebef0bbb Bernhard Kohl
        if (!bdrv_is_inserted(s->bs)) {
971 ebef0bbb Bernhard Kohl
            goto not_ready;
972 ebef0bbb Bernhard Kohl
        }
973 ebef0bbb Bernhard Kohl
        break;
974 aa5dbdc1 Gerd Hoffmann
    default:
975 a1f0cce2 Hannes Reinecke
        scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_OPCODE));
976 a1f0cce2 Hannes Reinecke
        return -1;
977 aa5dbdc1 Gerd Hoffmann
    }
978 a1f0cce2 Hannes Reinecke
    scsi_req_set_status(r, GOOD, SENSE_CODE(NO_SENSE));
979 aa5dbdc1 Gerd Hoffmann
    return buflen;
980 aa5dbdc1 Gerd Hoffmann
981 aa5dbdc1 Gerd Hoffmann
not_ready:
982 a1f0cce2 Hannes Reinecke
    if (!bdrv_is_inserted(s->bs)) {
983 a1f0cce2 Hannes Reinecke
        scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(NO_MEDIUM));
984 a1f0cce2 Hannes Reinecke
    } else {
985 a1f0cce2 Hannes Reinecke
        scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(LUN_NOT_READY));
986 a1f0cce2 Hannes Reinecke
    }
987 8af7a3ab Kevin Wolf
    return -1;
988 aa5dbdc1 Gerd Hoffmann
989 aa5dbdc1 Gerd Hoffmann
illegal_request:
990 a1f0cce2 Hannes Reinecke
    scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_FIELD));
991 8af7a3ab Kevin Wolf
    return -1;
992 aa5dbdc1 Gerd Hoffmann
}
993 aa5dbdc1 Gerd Hoffmann
994 2e5d83bb pbrook
/* Execute a scsi command.  Returns the length of the data expected by the
995 2e5d83bb pbrook
   command.  This will be Positive for data transfers from the device
996 2e5d83bb pbrook
   (eg. disk reads), negative for transfers to the device (eg. disk writes),
997 2e5d83bb pbrook
   and zero if the command does not transfer any data.  */
998 2e5d83bb pbrook
999 5c6c0e51 Hannes Reinecke
static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
1000 2e5d83bb pbrook
{
1001 5c6c0e51 Hannes Reinecke
    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
1002 5c6c0e51 Hannes Reinecke
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
1003 ad2d30f7 Paolo Bonzini
    int32_t len;
1004 a917d384 pbrook
    uint8_t command;
1005 a917d384 pbrook
    uint8_t *outbuf;
1006 aa5dbdc1 Gerd Hoffmann
    int rc;
1007 a917d384 pbrook
1008 a917d384 pbrook
    command = buf[0];
1009 3f4cb3d3 blueswir1
    outbuf = (uint8_t *)r->iov.iov_base;
1010 a917d384 pbrook
    DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]);
1011 2dd791b6 Hannes Reinecke
1012 2dd791b6 Hannes Reinecke
    if (scsi_req_parse(&r->req, buf) != 0) {
1013 a917d384 pbrook
        BADF("Unsupported command length, command %x\n", command);
1014 a1f0cce2 Hannes Reinecke
        scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_OPCODE));
1015 a1f0cce2 Hannes Reinecke
        return 0;
1016 2e5d83bb pbrook
    }
1017 2e5d83bb pbrook
#ifdef DEBUG_SCSI
1018 2e5d83bb pbrook
    {
1019 2e5d83bb pbrook
        int i;
1020 2dd791b6 Hannes Reinecke
        for (i = 1; i < r->req.cmd.len; i++) {
1021 2e5d83bb pbrook
            printf(" 0x%02x", buf[i]);
1022 2e5d83bb pbrook
        }
1023 2e5d83bb pbrook
        printf("\n");
1024 2e5d83bb pbrook
    }
1025 2e5d83bb pbrook
#endif
1026 aa5dbdc1 Gerd Hoffmann
1027 1455084e Paolo Bonzini
    if (req->lun) {
1028 2e5d83bb pbrook
        /* Only LUN 0 supported.  */
1029 1455084e Paolo Bonzini
        DPRINTF("Unimplemented LUN %d\n", req->lun);
1030 a1f0cce2 Hannes Reinecke
        if (command != REQUEST_SENSE && command != INQUIRY) {
1031 a1f0cce2 Hannes Reinecke
            scsi_command_complete(r, CHECK_CONDITION,
1032 a1f0cce2 Hannes Reinecke
                                  SENSE_CODE(LUN_NOT_SUPPORTED));
1033 a1f0cce2 Hannes Reinecke
            return 0;
1034 a1f0cce2 Hannes Reinecke
        }
1035 2e5d83bb pbrook
    }
1036 a917d384 pbrook
    switch (command) {
1037 ebf46023 Gerd Hoffmann
    case TEST_UNIT_READY:
1038 51ad87c9 Gerd Hoffmann
    case REQUEST_SENSE:
1039 0b06c059 Gerd Hoffmann
    case INQUIRY:
1040 ebddfcbe Gerd Hoffmann
    case MODE_SENSE:
1041 ebddfcbe Gerd Hoffmann
    case MODE_SENSE_10:
1042 3d53ba18 Gerd Hoffmann
    case RESERVE:
1043 3d53ba18 Gerd Hoffmann
    case RESERVE_10:
1044 3d53ba18 Gerd Hoffmann
    case RELEASE:
1045 3d53ba18 Gerd Hoffmann
    case RELEASE_10:
1046 8d3628ff Gerd Hoffmann
    case START_STOP:
1047 c68b9f34 Gerd Hoffmann
    case ALLOW_MEDIUM_REMOVAL:
1048 e7e25e32 Gerd Hoffmann
    case READ_CAPACITY:
1049 fc903943 Gerd Hoffmann
    case SYNCHRONIZE_CACHE:
1050 02880f43 Gerd Hoffmann
    case READ_TOC:
1051 38215553 Gerd Hoffmann
    case GET_CONFIGURATION:
1052 5dd90e2a Gerd Hoffmann
    case SERVICE_ACTION_IN:
1053 39ec9a50 Gerd Hoffmann
    case REPORT_LUNS:
1054 88f8a5ed Gerd Hoffmann
    case VERIFY:
1055 ebef0bbb Bernhard Kohl
    case REZERO_UNIT:
1056 8af7a3ab Kevin Wolf
        rc = scsi_disk_emulate_command(r, outbuf);
1057 8af7a3ab Kevin Wolf
        if (rc < 0) {
1058 0b06c059 Gerd Hoffmann
            return 0;
1059 aa5dbdc1 Gerd Hoffmann
        }
1060 8af7a3ab Kevin Wolf
1061 8af7a3ab Kevin Wolf
        r->iov.iov_len = rc;
1062 0b06c059 Gerd Hoffmann
        break;
1063 ebf46023 Gerd Hoffmann
    case READ_6:
1064 ebf46023 Gerd Hoffmann
    case READ_10:
1065 bd536cf3 Gerd Hoffmann
    case READ_12:
1066 bd536cf3 Gerd Hoffmann
    case READ_16:
1067 5c6c0e51 Hannes Reinecke
        len = r->req.cmd.xfer / s->qdev.blocksize;
1068 2dd791b6 Hannes Reinecke
        DPRINTF("Read (sector %" PRId64 ", count %d)\n", r->req.cmd.lba, len);
1069 2dd791b6 Hannes Reinecke
        if (r->req.cmd.lba > s->max_lba)
1070 274fb0e1 aliguori
            goto illegal_lba;
1071 2dd791b6 Hannes Reinecke
        r->sector = r->req.cmd.lba * s->cluster_size;
1072 a917d384 pbrook
        r->sector_count = len * s->cluster_size;
1073 2e5d83bb pbrook
        break;
1074 ebf46023 Gerd Hoffmann
    case WRITE_6:
1075 ebf46023 Gerd Hoffmann
    case WRITE_10:
1076 bd536cf3 Gerd Hoffmann
    case WRITE_12:
1077 bd536cf3 Gerd Hoffmann
    case WRITE_16:
1078 ebef0bbb Bernhard Kohl
    case WRITE_VERIFY:
1079 ebef0bbb Bernhard Kohl
    case WRITE_VERIFY_12:
1080 ebef0bbb Bernhard Kohl
    case WRITE_VERIFY_16:
1081 5c6c0e51 Hannes Reinecke
        len = r->req.cmd.xfer / s->qdev.blocksize;
1082 ebef0bbb Bernhard Kohl
        DPRINTF("Write %s(sector %" PRId64 ", count %d)\n",
1083 2dd791b6 Hannes Reinecke
                (command & 0xe) == 0xe ? "And Verify " : "",
1084 2dd791b6 Hannes Reinecke
                r->req.cmd.lba, len);
1085 2dd791b6 Hannes Reinecke
        if (r->req.cmd.lba > s->max_lba)
1086 274fb0e1 aliguori
            goto illegal_lba;
1087 2dd791b6 Hannes Reinecke
        r->sector = r->req.cmd.lba * s->cluster_size;
1088 a917d384 pbrook
        r->sector_count = len * s->cluster_size;
1089 2e5d83bb pbrook
        break;
1090 ebef0bbb Bernhard Kohl
    case MODE_SELECT:
1091 2dd791b6 Hannes Reinecke
        DPRINTF("Mode Select(6) (len %lu)\n", (long)r->req.cmd.xfer);
1092 ebef0bbb Bernhard Kohl
        /* We don't support mode parameter changes.
1093 ebef0bbb Bernhard Kohl
           Allow the mode parameter header + block descriptors only. */
1094 2dd791b6 Hannes Reinecke
        if (r->req.cmd.xfer > 12) {
1095 ebef0bbb Bernhard Kohl
            goto fail;
1096 ebef0bbb Bernhard Kohl
        }
1097 ebef0bbb Bernhard Kohl
        break;
1098 ebef0bbb Bernhard Kohl
    case MODE_SELECT_10:
1099 2dd791b6 Hannes Reinecke
        DPRINTF("Mode Select(10) (len %lu)\n", (long)r->req.cmd.xfer);
1100 ebef0bbb Bernhard Kohl
        /* We don't support mode parameter changes.
1101 ebef0bbb Bernhard Kohl
           Allow the mode parameter header + block descriptors only. */
1102 2dd791b6 Hannes Reinecke
        if (r->req.cmd.xfer > 16) {
1103 ebef0bbb Bernhard Kohl
            goto fail;
1104 ebef0bbb Bernhard Kohl
        }
1105 ebef0bbb Bernhard Kohl
        break;
1106 ebef0bbb Bernhard Kohl
    case SEEK_6:
1107 ebef0bbb Bernhard Kohl
    case SEEK_10:
1108 2dd791b6 Hannes Reinecke
        DPRINTF("Seek(%d) (sector %" PRId64 ")\n", command == SEEK_6 ? 6 : 10,
1109 2dd791b6 Hannes Reinecke
                r->req.cmd.lba);
1110 2dd791b6 Hannes Reinecke
        if (r->req.cmd.lba > s->max_lba) {
1111 ebef0bbb Bernhard Kohl
            goto illegal_lba;
1112 ebef0bbb Bernhard Kohl
        }
1113 ebef0bbb Bernhard Kohl
        break;
1114 ea3bd56f Christoph Hellwig
    case WRITE_SAME_16:
1115 5c6c0e51 Hannes Reinecke
        len = r->req.cmd.xfer / s->qdev.blocksize;
1116 ea3bd56f Christoph Hellwig
1117 ea3bd56f Christoph Hellwig
        DPRINTF("WRITE SAME(16) (sector %" PRId64 ", count %d)\n",
1118 ea3bd56f Christoph Hellwig
                r->req.cmd.lba, len);
1119 ea3bd56f Christoph Hellwig
1120 ea3bd56f Christoph Hellwig
        if (r->req.cmd.lba > s->max_lba) {
1121 ea3bd56f Christoph Hellwig
            goto illegal_lba;
1122 ea3bd56f Christoph Hellwig
        }
1123 ea3bd56f Christoph Hellwig
1124 ea3bd56f Christoph Hellwig
        /*
1125 ea3bd56f Christoph Hellwig
         * We only support WRITE SAME with the unmap bit set for now.
1126 ea3bd56f Christoph Hellwig
         */
1127 ea3bd56f Christoph Hellwig
        if (!(buf[1] & 0x8)) {
1128 ea3bd56f Christoph Hellwig
            goto fail;
1129 ea3bd56f Christoph Hellwig
        }
1130 ea3bd56f Christoph Hellwig
1131 ea3bd56f Christoph Hellwig
        rc = bdrv_discard(s->bs, r->req.cmd.lba * s->cluster_size,
1132 ea3bd56f Christoph Hellwig
                          len * s->cluster_size);
1133 ea3bd56f Christoph Hellwig
        if (rc < 0) {
1134 ea3bd56f Christoph Hellwig
            /* XXX: better error code ?*/
1135 ea3bd56f Christoph Hellwig
            goto fail;
1136 ea3bd56f Christoph Hellwig
        }
1137 ea3bd56f Christoph Hellwig
1138 ea3bd56f Christoph Hellwig
        break;
1139 2e5d83bb pbrook
    default:
1140 2dd791b6 Hannes Reinecke
        DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
1141 a1f0cce2 Hannes Reinecke
        scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_OPCODE));
1142 a1f0cce2 Hannes Reinecke
        return 0;
1143 2e5d83bb pbrook
    fail:
1144 a1f0cce2 Hannes Reinecke
        scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_FIELD));
1145 2dd791b6 Hannes Reinecke
        return 0;
1146 274fb0e1 aliguori
    illegal_lba:
1147 a1f0cce2 Hannes Reinecke
        scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(LBA_OUT_OF_RANGE));
1148 274fb0e1 aliguori
        return 0;
1149 2e5d83bb pbrook
    }
1150 c87c0672 aliguori
    if (r->sector_count == 0 && r->iov.iov_len == 0) {
1151 a1f0cce2 Hannes Reinecke
        scsi_command_complete(r, GOOD, SENSE_CODE(NO_SENSE));
1152 a917d384 pbrook
    }
1153 c87c0672 aliguori
    len = r->sector_count * 512 + r->iov.iov_len;
1154 efb9ee02 Hannes Reinecke
    if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
1155 efb9ee02 Hannes Reinecke
        return -len;
1156 a917d384 pbrook
    } else {
1157 a917d384 pbrook
        if (!r->sector_count)
1158 a917d384 pbrook
            r->sector_count = -1;
1159 efb9ee02 Hannes Reinecke
        return len;
1160 2e5d83bb pbrook
    }
1161 2e5d83bb pbrook
}
1162 2e5d83bb pbrook
1163 e9447f35 Jan Kiszka
static void scsi_disk_reset(DeviceState *dev)
1164 e9447f35 Jan Kiszka
{
1165 e9447f35 Jan Kiszka
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev.qdev, dev);
1166 e9447f35 Jan Kiszka
    uint64_t nb_sectors;
1167 e9447f35 Jan Kiszka
1168 c557e889 Paolo Bonzini
    scsi_device_purge_requests(&s->qdev);
1169 e9447f35 Jan Kiszka
1170 e9447f35 Jan Kiszka
    bdrv_get_geometry(s->bs, &nb_sectors);
1171 e9447f35 Jan Kiszka
    nb_sectors /= s->cluster_size;
1172 e9447f35 Jan Kiszka
    if (nb_sectors) {
1173 e9447f35 Jan Kiszka
        nb_sectors--;
1174 e9447f35 Jan Kiszka
    }
1175 e9447f35 Jan Kiszka
    s->max_lba = nb_sectors;
1176 e9447f35 Jan Kiszka
}
1177 e9447f35 Jan Kiszka
1178 e9447f35 Jan Kiszka
static void scsi_destroy(SCSIDevice *dev)
1179 e9447f35 Jan Kiszka
{
1180 e9447f35 Jan Kiszka
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
1181 e9447f35 Jan Kiszka
1182 c557e889 Paolo Bonzini
    scsi_device_purge_requests(&s->qdev);
1183 f8b6cc00 Markus Armbruster
    blockdev_mark_auto_del(s->qdev.conf.bs);
1184 56a14938 Gerd Hoffmann
}
1185 56a14938 Gerd Hoffmann
1186 b443ae67 Markus Armbruster
static int scsi_initfn(SCSIDevice *dev, SCSIDriveKind kind)
1187 2e5d83bb pbrook
{
1188 d52affa7 Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
1189 f8b6cc00 Markus Armbruster
    DriveInfo *dinfo;
1190 2e5d83bb pbrook
1191 f8b6cc00 Markus Armbruster
    if (!s->qdev.conf.bs) {
1192 1ecda02b Markus Armbruster
        error_report("scsi-disk: drive property not set");
1193 d52affa7 Gerd Hoffmann
        return -1;
1194 d52affa7 Gerd Hoffmann
    }
1195 f8b6cc00 Markus Armbruster
    s->bs = s->qdev.conf.bs;
1196 b443ae67 Markus Armbruster
    s->drive_kind = kind;
1197 d52affa7 Gerd Hoffmann
1198 b443ae67 Markus Armbruster
    if (kind == SCSI_HD && !bdrv_is_inserted(s->bs)) {
1199 98f28ad7 Markus Armbruster
        error_report("Device needs media, but drive is empty");
1200 98f28ad7 Markus Armbruster
        return -1;
1201 98f28ad7 Markus Armbruster
    }
1202 98f28ad7 Markus Armbruster
1203 a0fef654 Markus Armbruster
    if (!s->serial) {
1204 f8b6cc00 Markus Armbruster
        /* try to fall back to value set with legacy -drive serial=... */
1205 f8b6cc00 Markus Armbruster
        dinfo = drive_get_by_blockdev(s->bs);
1206 f8b6cc00 Markus Armbruster
        s->serial = qemu_strdup(*dinfo->serial ? dinfo->serial : "0");
1207 a0fef654 Markus Armbruster
    }
1208 a0fef654 Markus Armbruster
1209 552fee93 Markus Armbruster
    if (!s->version) {
1210 552fee93 Markus Armbruster
        s->version = qemu_strdup(QEMU_VERSION);
1211 552fee93 Markus Armbruster
    }
1212 552fee93 Markus Armbruster
1213 32bb404a Markus Armbruster
    if (bdrv_is_sg(s->bs)) {
1214 1ecda02b Markus Armbruster
        error_report("scsi-disk: unwanted /dev/sg*");
1215 32bb404a Markus Armbruster
        return -1;
1216 32bb404a Markus Armbruster
    }
1217 32bb404a Markus Armbruster
1218 b443ae67 Markus Armbruster
    if (kind == SCSI_CD) {
1219 8cfacf07 Christoph Hellwig
        s->qdev.blocksize = 2048;
1220 2e5d83bb pbrook
    } else {
1221 8cfacf07 Christoph Hellwig
        s->qdev.blocksize = s->qdev.conf.logical_block_size;
1222 2e5d83bb pbrook
    }
1223 8cfacf07 Christoph Hellwig
    s->cluster_size = s->qdev.blocksize / 512;
1224 73fdb1e1 Christoph Hellwig
    s->bs->buffer_alignment = s->qdev.blocksize;
1225 8cfacf07 Christoph Hellwig
1226 91376656 Gerd Hoffmann
    s->qdev.type = TYPE_DISK;
1227 ea8a5d7f aliguori
    qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s);
1228 b443ae67 Markus Armbruster
    bdrv_set_removable(s->bs, kind == SCSI_CD);
1229 1ca4d09a Gleb Natapov
    add_boot_device_path(s->qdev.conf.bootindex, &dev->qdev, ",0");
1230 d52affa7 Gerd Hoffmann
    return 0;
1231 d52affa7 Gerd Hoffmann
}
1232 d52affa7 Gerd Hoffmann
1233 b443ae67 Markus Armbruster
static int scsi_hd_initfn(SCSIDevice *dev)
1234 b443ae67 Markus Armbruster
{
1235 b443ae67 Markus Armbruster
    return scsi_initfn(dev, SCSI_HD);
1236 b443ae67 Markus Armbruster
}
1237 b443ae67 Markus Armbruster
1238 b443ae67 Markus Armbruster
static int scsi_cd_initfn(SCSIDevice *dev)
1239 b443ae67 Markus Armbruster
{
1240 b443ae67 Markus Armbruster
    return scsi_initfn(dev, SCSI_CD);
1241 b443ae67 Markus Armbruster
}
1242 b443ae67 Markus Armbruster
1243 b443ae67 Markus Armbruster
static int scsi_disk_initfn(SCSIDevice *dev)
1244 b443ae67 Markus Armbruster
{
1245 b443ae67 Markus Armbruster
    SCSIDriveKind kind;
1246 95b5edcd Markus Armbruster
    DriveInfo *dinfo;
1247 b443ae67 Markus Armbruster
1248 b443ae67 Markus Armbruster
    if (!dev->conf.bs) {
1249 b443ae67 Markus Armbruster
        kind = SCSI_HD;         /* will die in scsi_initfn() */
1250 b443ae67 Markus Armbruster
    } else {
1251 95b5edcd Markus Armbruster
        dinfo = drive_get_by_blockdev(dev->conf.bs);
1252 95b5edcd Markus Armbruster
        kind = dinfo->media_cd ? SCSI_CD : SCSI_HD;
1253 b443ae67 Markus Armbruster
    }
1254 b443ae67 Markus Armbruster
1255 b443ae67 Markus Armbruster
    return scsi_initfn(dev, kind);
1256 b443ae67 Markus Armbruster
}
1257 b443ae67 Markus Armbruster
1258 b443ae67 Markus Armbruster
#define DEFINE_SCSI_DISK_PROPERTIES()                           \
1259 b443ae67 Markus Armbruster
    DEFINE_BLOCK_PROPERTIES(SCSIDiskState, qdev.conf),          \
1260 b443ae67 Markus Armbruster
    DEFINE_PROP_STRING("ver",  SCSIDiskState, version),         \
1261 b443ae67 Markus Armbruster
    DEFINE_PROP_STRING("serial",  SCSIDiskState, serial)
1262 b443ae67 Markus Armbruster
1263 b443ae67 Markus Armbruster
static SCSIDeviceInfo scsi_disk_info[] = {
1264 b443ae67 Markus Armbruster
    {
1265 b443ae67 Markus Armbruster
        .qdev.name    = "scsi-hd",
1266 b443ae67 Markus Armbruster
        .qdev.fw_name = "disk",
1267 b443ae67 Markus Armbruster
        .qdev.desc    = "virtual SCSI disk",
1268 b443ae67 Markus Armbruster
        .qdev.size    = sizeof(SCSIDiskState),
1269 b443ae67 Markus Armbruster
        .qdev.reset   = scsi_disk_reset,
1270 b443ae67 Markus Armbruster
        .init         = scsi_hd_initfn,
1271 b443ae67 Markus Armbruster
        .destroy      = scsi_destroy,
1272 5c6c0e51 Hannes Reinecke
        .alloc_req    = scsi_new_request,
1273 ad2d30f7 Paolo Bonzini
        .free_req     = scsi_free_request,
1274 b443ae67 Markus Armbruster
        .send_command = scsi_send_command,
1275 b443ae67 Markus Armbruster
        .read_data    = scsi_read_data,
1276 b443ae67 Markus Armbruster
        .write_data   = scsi_write_data,
1277 b443ae67 Markus Armbruster
        .cancel_io    = scsi_cancel_io,
1278 b443ae67 Markus Armbruster
        .get_buf      = scsi_get_buf,
1279 74382217 Hannes Reinecke
        .get_sense    = scsi_get_sense,
1280 b443ae67 Markus Armbruster
        .qdev.props   = (Property[]) {
1281 b443ae67 Markus Armbruster
            DEFINE_SCSI_DISK_PROPERTIES(),
1282 b443ae67 Markus Armbruster
            DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false),
1283 b443ae67 Markus Armbruster
            DEFINE_PROP_END_OF_LIST(),
1284 b443ae67 Markus Armbruster
        }
1285 b443ae67 Markus Armbruster
    },{
1286 b443ae67 Markus Armbruster
        .qdev.name    = "scsi-cd",
1287 b443ae67 Markus Armbruster
        .qdev.fw_name = "disk",
1288 b443ae67 Markus Armbruster
        .qdev.desc    = "virtual SCSI CD-ROM",
1289 b443ae67 Markus Armbruster
        .qdev.size    = sizeof(SCSIDiskState),
1290 b443ae67 Markus Armbruster
        .qdev.reset   = scsi_disk_reset,
1291 b443ae67 Markus Armbruster
        .init         = scsi_cd_initfn,
1292 b443ae67 Markus Armbruster
        .destroy      = scsi_destroy,
1293 5c6c0e51 Hannes Reinecke
        .alloc_req    = scsi_new_request,
1294 ad2d30f7 Paolo Bonzini
        .free_req     = scsi_free_request,
1295 b443ae67 Markus Armbruster
        .send_command = scsi_send_command,
1296 b443ae67 Markus Armbruster
        .read_data    = scsi_read_data,
1297 b443ae67 Markus Armbruster
        .write_data   = scsi_write_data,
1298 b443ae67 Markus Armbruster
        .cancel_io    = scsi_cancel_io,
1299 b443ae67 Markus Armbruster
        .get_buf      = scsi_get_buf,
1300 74382217 Hannes Reinecke
        .get_sense    = scsi_get_sense,
1301 b443ae67 Markus Armbruster
        .qdev.props   = (Property[]) {
1302 b443ae67 Markus Armbruster
            DEFINE_SCSI_DISK_PROPERTIES(),
1303 b443ae67 Markus Armbruster
            DEFINE_PROP_END_OF_LIST(),
1304 b443ae67 Markus Armbruster
        },
1305 b443ae67 Markus Armbruster
    },{
1306 b443ae67 Markus Armbruster
        .qdev.name    = "scsi-disk", /* legacy -device scsi-disk */
1307 b443ae67 Markus Armbruster
        .qdev.fw_name = "disk",
1308 b443ae67 Markus Armbruster
        .qdev.desc    = "virtual SCSI disk or CD-ROM (legacy)",
1309 b443ae67 Markus Armbruster
        .qdev.size    = sizeof(SCSIDiskState),
1310 b443ae67 Markus Armbruster
        .qdev.reset   = scsi_disk_reset,
1311 b443ae67 Markus Armbruster
        .init         = scsi_disk_initfn,
1312 b443ae67 Markus Armbruster
        .destroy      = scsi_destroy,
1313 5c6c0e51 Hannes Reinecke
        .alloc_req    = scsi_new_request,
1314 ad2d30f7 Paolo Bonzini
        .free_req     = scsi_free_request,
1315 b443ae67 Markus Armbruster
        .send_command = scsi_send_command,
1316 b443ae67 Markus Armbruster
        .read_data    = scsi_read_data,
1317 b443ae67 Markus Armbruster
        .write_data   = scsi_write_data,
1318 b443ae67 Markus Armbruster
        .cancel_io    = scsi_cancel_io,
1319 b443ae67 Markus Armbruster
        .get_buf      = scsi_get_buf,
1320 74382217 Hannes Reinecke
        .get_sense    = scsi_get_sense,
1321 b443ae67 Markus Armbruster
        .qdev.props   = (Property[]) {
1322 b443ae67 Markus Armbruster
            DEFINE_SCSI_DISK_PROPERTIES(),
1323 b443ae67 Markus Armbruster
            DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false),
1324 b443ae67 Markus Armbruster
            DEFINE_PROP_END_OF_LIST(),
1325 b443ae67 Markus Armbruster
        }
1326 b443ae67 Markus Armbruster
    }
1327 d52affa7 Gerd Hoffmann
};
1328 d52affa7 Gerd Hoffmann
1329 d52affa7 Gerd Hoffmann
static void scsi_disk_register_devices(void)
1330 d52affa7 Gerd Hoffmann
{
1331 b443ae67 Markus Armbruster
    int i;
1332 b443ae67 Markus Armbruster
1333 b443ae67 Markus Armbruster
    for (i = 0; i < ARRAY_SIZE(scsi_disk_info); i++) {
1334 b443ae67 Markus Armbruster
        scsi_qdev_register(&scsi_disk_info[i]);
1335 b443ae67 Markus Armbruster
    }
1336 8ccc2ace ths
}
1337 d52affa7 Gerd Hoffmann
device_init(scsi_disk_register_devices)