Statistics
| Branch: | Revision:

root / hw / scsi-disk.c @ 3e1c0c9a

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