Statistics
| Branch: | Revision:

root / hw / scsi-disk.c @ 380f640f

History | View | Annotate | Download (31.2 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 fa879c64 aliguori
#include <qemu-common.h>
23 fa879c64 aliguori
#include <sysemu.h>
24 2e5d83bb pbrook
//#define DEBUG_SCSI
25 2e5d83bb pbrook
26 2e5d83bb pbrook
#ifdef DEBUG_SCSI
27 001faf32 Blue Swirl
#define DPRINTF(fmt, ...) \
28 001faf32 Blue Swirl
do { printf("scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
29 2e5d83bb pbrook
#else
30 001faf32 Blue Swirl
#define DPRINTF(fmt, ...) do {} while(0)
31 2e5d83bb pbrook
#endif
32 2e5d83bb pbrook
33 001faf32 Blue Swirl
#define BADF(fmt, ...) \
34 001faf32 Blue Swirl
do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
35 2e5d83bb pbrook
36 87ecb68b pbrook
#include "qemu-common.h"
37 87ecb68b pbrook
#include "block.h"
38 43b443b6 Gerd Hoffmann
#include "scsi.h"
39 0d65e1f8 Gerd Hoffmann
#include "scsi-defs.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 ea8a5d7f aliguori
#define SCSI_REQ_STATUS_RETRY 0x01
45 ea8a5d7f aliguori
46 d52affa7 Gerd Hoffmann
typedef struct SCSIDiskState SCSIDiskState;
47 d52affa7 Gerd Hoffmann
48 4c41d2ef Gerd Hoffmann
typedef struct SCSIDiskReq {
49 4c41d2ef Gerd Hoffmann
    SCSIRequest req;
50 e035b43d aliguori
    /* ??? We should probably keep track of whether the data transfer is
51 2e5d83bb pbrook
       a read or a write.  Currently we rely on the host getting it right.  */
52 a917d384 pbrook
    /* Both sector and sector_count are in terms of qemu 512 byte blocks.  */
53 e035b43d aliguori
    uint64_t sector;
54 e035b43d aliguori
    uint32_t sector_count;
55 c87c0672 aliguori
    struct iovec iov;
56 c87c0672 aliguori
    QEMUIOVector qiov;
57 ea8a5d7f aliguori
    uint32_t status;
58 4c41d2ef Gerd Hoffmann
} SCSIDiskReq;
59 a917d384 pbrook
60 d52affa7 Gerd Hoffmann
struct SCSIDiskState
61 a917d384 pbrook
{
62 d52affa7 Gerd Hoffmann
    SCSIDevice qdev;
63 a917d384 pbrook
    /* The qemu block layer uses a fixed 512 byte sector size.
64 a917d384 pbrook
       This is the number of 512 byte blocks in a single scsi sector.  */
65 a917d384 pbrook
    int cluster_size;
66 274fb0e1 aliguori
    uint64_t max_lba;
67 213189ab Markus Armbruster
    QEMUBH *bh;
68 383b4d9b Gerd Hoffmann
    char *version;
69 2e5d83bb pbrook
};
70 2e5d83bb pbrook
71 89b08ae1 Gerd Hoffmann
static SCSIDiskReq *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun)
72 2e5d83bb pbrook
{
73 89b08ae1 Gerd Hoffmann
    SCSIRequest *req;
74 4c41d2ef Gerd Hoffmann
    SCSIDiskReq *r;
75 a917d384 pbrook
76 89b08ae1 Gerd Hoffmann
    req = scsi_req_alloc(sizeof(SCSIDiskReq), d, tag, lun);
77 89b08ae1 Gerd Hoffmann
    r = DO_UPCAST(SCSIDiskReq, req, req);
78 9af99d98 Gerd Hoffmann
    r->iov.iov_base = qemu_memalign(512, SCSI_DMA_BUF_SIZE);
79 a917d384 pbrook
    return r;
80 2e5d83bb pbrook
}
81 2e5d83bb pbrook
82 4c41d2ef Gerd Hoffmann
static void scsi_remove_request(SCSIDiskReq *r)
83 4d611c9a pbrook
{
84 f8a83245 Herve Poussineau
    qemu_vfree(r->iov.iov_base);
85 89b08ae1 Gerd Hoffmann
    scsi_req_free(&r->req);
86 4d611c9a pbrook
}
87 4d611c9a pbrook
88 4c41d2ef Gerd Hoffmann
static SCSIDiskReq *scsi_find_request(SCSIDiskState *s, uint32_t tag)
89 4d611c9a pbrook
{
90 89b08ae1 Gerd Hoffmann
    return DO_UPCAST(SCSIDiskReq, req, scsi_req_find(&s->qdev, tag));
91 a917d384 pbrook
}
92 a917d384 pbrook
93 ed3a34a3 Gerd Hoffmann
static void scsi_req_set_status(SCSIRequest *req, int status, int sense_code)
94 ed3a34a3 Gerd Hoffmann
{
95 ed3a34a3 Gerd Hoffmann
    req->status = status;
96 ed3a34a3 Gerd Hoffmann
    scsi_dev_set_sense(req->dev, sense_code);
97 ed3a34a3 Gerd Hoffmann
}
98 ed3a34a3 Gerd Hoffmann
99 a917d384 pbrook
/* Helper function for command completion.  */
100 4c41d2ef Gerd Hoffmann
static void scsi_command_complete(SCSIDiskReq *r, int status, int sense)
101 a917d384 pbrook
{
102 4c41d2ef Gerd Hoffmann
    DPRINTF("Command complete tag=0x%x status=%d sense=%d\n",
103 4c41d2ef Gerd Hoffmann
            r->req.tag, status, sense);
104 ed3a34a3 Gerd Hoffmann
    scsi_req_set_status(&r->req, status, sense);
105 ed3a34a3 Gerd Hoffmann
    scsi_req_complete(&r->req);
106 89b08ae1 Gerd Hoffmann
    scsi_remove_request(r);
107 4d611c9a pbrook
}
108 4d611c9a pbrook
109 4d611c9a pbrook
/* Cancel a pending data transfer.  */
110 8ccc2ace ths
static void scsi_cancel_io(SCSIDevice *d, uint32_t tag)
111 4d611c9a pbrook
{
112 d52affa7 Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
113 4c41d2ef Gerd Hoffmann
    SCSIDiskReq *r;
114 a917d384 pbrook
    DPRINTF("Cancel tag=0x%x\n", tag);
115 a917d384 pbrook
    r = scsi_find_request(s, tag);
116 a917d384 pbrook
    if (r) {
117 4c41d2ef Gerd Hoffmann
        if (r->req.aiocb)
118 4c41d2ef Gerd Hoffmann
            bdrv_aio_cancel(r->req.aiocb);
119 4c41d2ef Gerd Hoffmann
        r->req.aiocb = NULL;
120 a917d384 pbrook
        scsi_remove_request(r);
121 a917d384 pbrook
    }
122 a917d384 pbrook
}
123 a917d384 pbrook
124 a917d384 pbrook
static void scsi_read_complete(void * opaque, int ret)
125 a917d384 pbrook
{
126 4c41d2ef Gerd Hoffmann
    SCSIDiskReq *r = (SCSIDiskReq *)opaque;
127 a917d384 pbrook
128 a917d384 pbrook
    if (ret) {
129 a917d384 pbrook
        DPRINTF("IO error\n");
130 4c41d2ef Gerd Hoffmann
        r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, 0);
131 0d65e1f8 Gerd Hoffmann
        scsi_command_complete(r, CHECK_CONDITION, NO_SENSE);
132 4d611c9a pbrook
        return;
133 4d611c9a pbrook
    }
134 4c41d2ef Gerd Hoffmann
    DPRINTF("Data ready tag=0x%x len=%" PRId64 "\n", r->req.tag, r->iov.iov_len);
135 a917d384 pbrook
136 4c41d2ef Gerd Hoffmann
    r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, r->iov.iov_len);
137 4d611c9a pbrook
}
138 4d611c9a pbrook
139 a917d384 pbrook
/* Read more data from scsi device into buffer.  */
140 8ccc2ace ths
static void scsi_read_data(SCSIDevice *d, uint32_t tag)
141 2e5d83bb pbrook
{
142 d52affa7 Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
143 4c41d2ef Gerd Hoffmann
    SCSIDiskReq *r;
144 2e5d83bb pbrook
    uint32_t n;
145 2e5d83bb pbrook
146 a917d384 pbrook
    r = scsi_find_request(s, tag);
147 a917d384 pbrook
    if (!r) {
148 a917d384 pbrook
        BADF("Bad read tag 0x%x\n", tag);
149 b1fa7164 blueswir1
        /* ??? This is the wrong error.  */
150 0d65e1f8 Gerd Hoffmann
        scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR);
151 a917d384 pbrook
        return;
152 2e5d83bb pbrook
    }
153 a917d384 pbrook
    if (r->sector_count == (uint32_t)-1) {
154 0bf9e31a Blue Swirl
        DPRINTF("Read buf_len=%" PRId64 "\n", r->iov.iov_len);
155 a917d384 pbrook
        r->sector_count = 0;
156 4c41d2ef Gerd Hoffmann
        r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, r->iov.iov_len);
157 a917d384 pbrook
        return;
158 2e5d83bb pbrook
    }
159 a917d384 pbrook
    DPRINTF("Read sector_count=%d\n", r->sector_count);
160 a917d384 pbrook
    if (r->sector_count == 0) {
161 0d65e1f8 Gerd Hoffmann
        scsi_command_complete(r, GOOD, NO_SENSE);
162 a917d384 pbrook
        return;
163 2e5d83bb pbrook
    }
164 2e5d83bb pbrook
165 a917d384 pbrook
    n = r->sector_count;
166 a917d384 pbrook
    if (n > SCSI_DMA_BUF_SIZE / 512)
167 a917d384 pbrook
        n = SCSI_DMA_BUF_SIZE / 512;
168 a917d384 pbrook
169 c87c0672 aliguori
    r->iov.iov_len = n * 512;
170 c87c0672 aliguori
    qemu_iovec_init_external(&r->qiov, &r->iov, 1);
171 251882b7 Gerd Hoffmann
    r->req.aiocb = bdrv_aio_readv(s->qdev.dinfo->bdrv, r->sector, &r->qiov, n,
172 c87c0672 aliguori
                              scsi_read_complete, r);
173 4c41d2ef Gerd Hoffmann
    if (r->req.aiocb == NULL)
174 0d65e1f8 Gerd Hoffmann
        scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR);
175 a917d384 pbrook
    r->sector += n;
176 a917d384 pbrook
    r->sector_count -= n;
177 2e5d83bb pbrook
}
178 2e5d83bb pbrook
179 4c41d2ef Gerd Hoffmann
static int scsi_handle_write_error(SCSIDiskReq *r, int error)
180 ea8a5d7f aliguori
{
181 4c41d2ef Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
182 f7850099 Kevin Wolf
    BlockInterfaceErrorAction action =
183 f7850099 Kevin Wolf
        drive_get_on_error(s->qdev.dinfo->bdrv, 0);
184 ea8a5d7f aliguori
185 380f640f Luiz Capitulino
    if (action == BLOCK_ERR_IGNORE) {
186 380f640f Luiz Capitulino
        bdrv_mon_event(s->qdev.dinfo->bdrv, BDRV_ACTION_IGNORE, 0);
187 ea8a5d7f aliguori
        return 0;
188 380f640f Luiz Capitulino
    }
189 ea8a5d7f aliguori
190 ea8a5d7f aliguori
    if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC)
191 ea8a5d7f aliguori
            || action == BLOCK_ERR_STOP_ANY) {
192 ea8a5d7f aliguori
        r->status |= SCSI_REQ_STATUS_RETRY;
193 ea8a5d7f aliguori
        vm_stop(0);
194 380f640f Luiz Capitulino
        bdrv_mon_event(s->qdev.dinfo->bdrv, BDRV_ACTION_STOP, 0);
195 ea8a5d7f aliguori
    } else {
196 0d65e1f8 Gerd Hoffmann
        scsi_command_complete(r, CHECK_CONDITION,
197 0d65e1f8 Gerd Hoffmann
                HARDWARE_ERROR);
198 380f640f Luiz Capitulino
        bdrv_mon_event(s->qdev.dinfo->bdrv, BDRV_ACTION_REPORT, 0);
199 ea8a5d7f aliguori
    }
200 ea8a5d7f aliguori
201 ea8a5d7f aliguori
    return 1;
202 ea8a5d7f aliguori
}
203 ea8a5d7f aliguori
204 4d611c9a pbrook
static void scsi_write_complete(void * opaque, int ret)
205 4d611c9a pbrook
{
206 4c41d2ef Gerd Hoffmann
    SCSIDiskReq *r = (SCSIDiskReq *)opaque;
207 a917d384 pbrook
    uint32_t len;
208 ea8a5d7f aliguori
    uint32_t n;
209 ea8a5d7f aliguori
210 4c41d2ef Gerd Hoffmann
    r->req.aiocb = NULL;
211 4d611c9a pbrook
212 4d611c9a pbrook
    if (ret) {
213 ea8a5d7f aliguori
        if (scsi_handle_write_error(r, -ret))
214 ea8a5d7f aliguori
            return;
215 4d611c9a pbrook
    }
216 4d611c9a pbrook
217 c87c0672 aliguori
    n = r->iov.iov_len / 512;
218 ea8a5d7f aliguori
    r->sector += n;
219 ea8a5d7f aliguori
    r->sector_count -= n;
220 a917d384 pbrook
    if (r->sector_count == 0) {
221 0d65e1f8 Gerd Hoffmann
        scsi_command_complete(r, GOOD, NO_SENSE);
222 a917d384 pbrook
    } else {
223 a917d384 pbrook
        len = r->sector_count * 512;
224 a917d384 pbrook
        if (len > SCSI_DMA_BUF_SIZE) {
225 a917d384 pbrook
            len = SCSI_DMA_BUF_SIZE;
226 a917d384 pbrook
        }
227 c87c0672 aliguori
        r->iov.iov_len = len;
228 4c41d2ef Gerd Hoffmann
        DPRINTF("Write complete tag=0x%x more=%d\n", r->req.tag, len);
229 4c41d2ef Gerd Hoffmann
        r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, len);
230 4d611c9a pbrook
    }
231 4d611c9a pbrook
}
232 4d611c9a pbrook
233 4c41d2ef Gerd Hoffmann
static void scsi_write_request(SCSIDiskReq *r)
234 ea8a5d7f aliguori
{
235 4c41d2ef Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
236 ea8a5d7f aliguori
    uint32_t n;
237 ea8a5d7f aliguori
238 c87c0672 aliguori
    n = r->iov.iov_len / 512;
239 ea8a5d7f aliguori
    if (n) {
240 c87c0672 aliguori
        qemu_iovec_init_external(&r->qiov, &r->iov, 1);
241 251882b7 Gerd Hoffmann
        r->req.aiocb = bdrv_aio_writev(s->qdev.dinfo->bdrv, r->sector, &r->qiov, n,
242 c87c0672 aliguori
                                   scsi_write_complete, r);
243 4c41d2ef Gerd Hoffmann
        if (r->req.aiocb == NULL)
244 0d65e1f8 Gerd Hoffmann
            scsi_command_complete(r, CHECK_CONDITION,
245 0d65e1f8 Gerd Hoffmann
                                  HARDWARE_ERROR);
246 ea8a5d7f aliguori
    } else {
247 ea8a5d7f aliguori
        /* Invoke completion routine to fetch data from host.  */
248 ea8a5d7f aliguori
        scsi_write_complete(r, 0);
249 ea8a5d7f aliguori
    }
250 ea8a5d7f aliguori
}
251 ea8a5d7f aliguori
252 4d611c9a pbrook
/* Write data to a scsi device.  Returns nonzero on failure.
253 4d611c9a pbrook
   The transfer may complete asynchronously.  */
254 8ccc2ace ths
static int scsi_write_data(SCSIDevice *d, uint32_t tag)
255 2e5d83bb pbrook
{
256 d52affa7 Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
257 4c41d2ef Gerd Hoffmann
    SCSIDiskReq *r;
258 2e5d83bb pbrook
259 a917d384 pbrook
    DPRINTF("Write data tag=0x%x\n", tag);
260 a917d384 pbrook
    r = scsi_find_request(s, tag);
261 a917d384 pbrook
    if (!r) {
262 a917d384 pbrook
        BADF("Bad write tag 0x%x\n", tag);
263 0d65e1f8 Gerd Hoffmann
        scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR);
264 2e5d83bb pbrook
        return 1;
265 2e5d83bb pbrook
    }
266 ea8a5d7f aliguori
267 4c41d2ef Gerd Hoffmann
    if (r->req.aiocb)
268 a917d384 pbrook
        BADF("Data transfer already in progress\n");
269 ea8a5d7f aliguori
270 ea8a5d7f aliguori
    scsi_write_request(r);
271 2e5d83bb pbrook
272 a917d384 pbrook
    return 0;
273 a917d384 pbrook
}
274 2e5d83bb pbrook
275 213189ab Markus Armbruster
static void scsi_dma_restart_bh(void *opaque)
276 ea8a5d7f aliguori
{
277 d52affa7 Gerd Hoffmann
    SCSIDiskState *s = opaque;
278 9af99d98 Gerd Hoffmann
    SCSIRequest *req;
279 9af99d98 Gerd Hoffmann
    SCSIDiskReq *r;
280 213189ab Markus Armbruster
281 213189ab Markus Armbruster
    qemu_bh_delete(s->bh);
282 213189ab Markus Armbruster
    s->bh = NULL;
283 ea8a5d7f aliguori
284 9af99d98 Gerd Hoffmann
    QTAILQ_FOREACH(req, &s->qdev.requests, next) {
285 9af99d98 Gerd Hoffmann
        r = DO_UPCAST(SCSIDiskReq, req, req);
286 ea8a5d7f aliguori
        if (r->status & SCSI_REQ_STATUS_RETRY) {
287 ea8a5d7f aliguori
            r->status &= ~SCSI_REQ_STATUS_RETRY;
288 ea8a5d7f aliguori
            scsi_write_request(r); 
289 ea8a5d7f aliguori
        }
290 ea8a5d7f aliguori
    }
291 ea8a5d7f aliguori
}
292 ea8a5d7f aliguori
293 213189ab Markus Armbruster
static void scsi_dma_restart_cb(void *opaque, int running, int reason)
294 213189ab Markus Armbruster
{
295 d52affa7 Gerd Hoffmann
    SCSIDiskState *s = opaque;
296 213189ab Markus Armbruster
297 213189ab Markus Armbruster
    if (!running)
298 213189ab Markus Armbruster
        return;
299 213189ab Markus Armbruster
300 213189ab Markus Armbruster
    if (!s->bh) {
301 213189ab Markus Armbruster
        s->bh = qemu_bh_new(scsi_dma_restart_bh, s);
302 213189ab Markus Armbruster
        qemu_bh_schedule(s->bh);
303 213189ab Markus Armbruster
    }
304 213189ab Markus Armbruster
}
305 213189ab Markus Armbruster
306 a917d384 pbrook
/* Return a pointer to the data buffer.  */
307 8ccc2ace ths
static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag)
308 a917d384 pbrook
{
309 d52affa7 Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
310 4c41d2ef Gerd Hoffmann
    SCSIDiskReq *r;
311 2e5d83bb pbrook
312 a917d384 pbrook
    r = scsi_find_request(s, tag);
313 a917d384 pbrook
    if (!r) {
314 a917d384 pbrook
        BADF("Bad buffer tag 0x%x\n", tag);
315 a917d384 pbrook
        return NULL;
316 4d611c9a pbrook
    }
317 3f4cb3d3 blueswir1
    return (uint8_t *)r->iov.iov_base;
318 2e5d83bb pbrook
}
319 2e5d83bb pbrook
320 0b06c059 Gerd Hoffmann
static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
321 0b06c059 Gerd Hoffmann
{
322 0b06c059 Gerd Hoffmann
    BlockDriverState *bdrv = req->dev->dinfo->bdrv;
323 383b4d9b Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
324 0b06c059 Gerd Hoffmann
    int buflen = 0;
325 0b06c059 Gerd Hoffmann
326 0b06c059 Gerd Hoffmann
    if (req->cmd.buf[1] & 0x2) {
327 0b06c059 Gerd Hoffmann
        /* Command support data - optional, not implemented */
328 0b06c059 Gerd Hoffmann
        BADF("optional INQUIRY command support request not implemented\n");
329 0b06c059 Gerd Hoffmann
        return -1;
330 0b06c059 Gerd Hoffmann
    }
331 0b06c059 Gerd Hoffmann
332 0b06c059 Gerd Hoffmann
    if (req->cmd.buf[1] & 0x1) {
333 0b06c059 Gerd Hoffmann
        /* Vital product data */
334 0b06c059 Gerd Hoffmann
        uint8_t page_code = req->cmd.buf[2];
335 0b06c059 Gerd Hoffmann
        if (req->cmd.xfer < 4) {
336 0b06c059 Gerd Hoffmann
            BADF("Error: Inquiry (EVPD[%02X]) buffer size %zd is "
337 0b06c059 Gerd Hoffmann
                 "less than 4\n", page_code, req->cmd.xfer);
338 0b06c059 Gerd Hoffmann
            return -1;
339 0b06c059 Gerd Hoffmann
        }
340 0b06c059 Gerd Hoffmann
341 0b06c059 Gerd Hoffmann
        if (bdrv_get_type_hint(bdrv) == BDRV_TYPE_CDROM) {
342 0b06c059 Gerd Hoffmann
            outbuf[buflen++] = 5;
343 0b06c059 Gerd Hoffmann
        } else {
344 0b06c059 Gerd Hoffmann
            outbuf[buflen++] = 0;
345 0b06c059 Gerd Hoffmann
        }
346 0b06c059 Gerd Hoffmann
        outbuf[buflen++] = page_code ; // this page
347 0b06c059 Gerd Hoffmann
        outbuf[buflen++] = 0x00;
348 0b06c059 Gerd Hoffmann
349 0b06c059 Gerd Hoffmann
        switch (page_code) {
350 0b06c059 Gerd Hoffmann
        case 0x00: /* Supported page codes, mandatory */
351 0b06c059 Gerd Hoffmann
            DPRINTF("Inquiry EVPD[Supported pages] "
352 0b06c059 Gerd Hoffmann
                    "buffer size %zd\n", req->cmd.xfer);
353 0b06c059 Gerd Hoffmann
            outbuf[buflen++] = 3;    // number of pages
354 0b06c059 Gerd Hoffmann
            outbuf[buflen++] = 0x00; // list of supported pages (this page)
355 0b06c059 Gerd Hoffmann
            outbuf[buflen++] = 0x80; // unit serial number
356 0b06c059 Gerd Hoffmann
            outbuf[buflen++] = 0x83; // device identification
357 0b06c059 Gerd Hoffmann
            break;
358 0b06c059 Gerd Hoffmann
359 0b06c059 Gerd Hoffmann
        case 0x80: /* Device serial number, optional */
360 0b06c059 Gerd Hoffmann
        {
361 407f879a Blue Swirl
            const char *serial = req->dev->dinfo->serial ?
362 407f879a Blue Swirl
                req->dev->dinfo->serial : "0";
363 0b06c059 Gerd Hoffmann
            int l = strlen(serial);
364 0b06c059 Gerd Hoffmann
365 0b06c059 Gerd Hoffmann
            if (l > req->cmd.xfer)
366 0b06c059 Gerd Hoffmann
                l = req->cmd.xfer;
367 0b06c059 Gerd Hoffmann
            if (l > 20)
368 0b06c059 Gerd Hoffmann
                l = 20;
369 0b06c059 Gerd Hoffmann
370 0b06c059 Gerd Hoffmann
            DPRINTF("Inquiry EVPD[Serial number] "
371 0b06c059 Gerd Hoffmann
                    "buffer size %zd\n", req->cmd.xfer);
372 0b06c059 Gerd Hoffmann
            outbuf[buflen++] = l;
373 0b06c059 Gerd Hoffmann
            memcpy(outbuf+buflen, serial, l);
374 0b06c059 Gerd Hoffmann
            buflen += l;
375 0b06c059 Gerd Hoffmann
            break;
376 0b06c059 Gerd Hoffmann
        }
377 0b06c059 Gerd Hoffmann
378 0b06c059 Gerd Hoffmann
        case 0x83: /* Device identification page, mandatory */
379 0b06c059 Gerd Hoffmann
        {
380 0b06c059 Gerd Hoffmann
            int max_len = 255 - 8;
381 0b06c059 Gerd Hoffmann
            int id_len = strlen(bdrv_get_device_name(bdrv));
382 0b06c059 Gerd Hoffmann
383 0b06c059 Gerd Hoffmann
            if (id_len > max_len)
384 0b06c059 Gerd Hoffmann
                id_len = max_len;
385 0b06c059 Gerd Hoffmann
            DPRINTF("Inquiry EVPD[Device identification] "
386 0b06c059 Gerd Hoffmann
                    "buffer size %zd\n", req->cmd.xfer);
387 0b06c059 Gerd Hoffmann
388 0b06c059 Gerd Hoffmann
            outbuf[buflen++] = 3 + id_len;
389 0b06c059 Gerd Hoffmann
            outbuf[buflen++] = 0x2; // ASCII
390 0b06c059 Gerd Hoffmann
            outbuf[buflen++] = 0;   // not officially assigned
391 0b06c059 Gerd Hoffmann
            outbuf[buflen++] = 0;   // reserved
392 0b06c059 Gerd Hoffmann
            outbuf[buflen++] = id_len; // length of data following
393 0b06c059 Gerd Hoffmann
394 0b06c059 Gerd Hoffmann
            memcpy(outbuf+buflen, bdrv_get_device_name(bdrv), id_len);
395 0b06c059 Gerd Hoffmann
            buflen += id_len;
396 0b06c059 Gerd Hoffmann
            break;
397 0b06c059 Gerd Hoffmann
        }
398 0b06c059 Gerd Hoffmann
        default:
399 0b06c059 Gerd Hoffmann
            BADF("Error: unsupported Inquiry (EVPD[%02X]) "
400 0b06c059 Gerd Hoffmann
                 "buffer size %zd\n", page_code, req->cmd.xfer);
401 0b06c059 Gerd Hoffmann
            return -1;
402 0b06c059 Gerd Hoffmann
        }
403 0b06c059 Gerd Hoffmann
        /* done with EVPD */
404 0b06c059 Gerd Hoffmann
        return buflen;
405 0b06c059 Gerd Hoffmann
    }
406 0b06c059 Gerd Hoffmann
407 0b06c059 Gerd Hoffmann
    /* Standard INQUIRY data */
408 0b06c059 Gerd Hoffmann
    if (req->cmd.buf[2] != 0) {
409 0b06c059 Gerd Hoffmann
        BADF("Error: Inquiry (STANDARD) page or code "
410 0b06c059 Gerd Hoffmann
             "is non-zero [%02X]\n", req->cmd.buf[2]);
411 0b06c059 Gerd Hoffmann
        return -1;
412 0b06c059 Gerd Hoffmann
    }
413 0b06c059 Gerd Hoffmann
414 0b06c059 Gerd Hoffmann
    /* PAGE CODE == 0 */
415 0b06c059 Gerd Hoffmann
    if (req->cmd.xfer < 5) {
416 0b06c059 Gerd Hoffmann
        BADF("Error: Inquiry (STANDARD) buffer size %zd "
417 0b06c059 Gerd Hoffmann
             "is less than 5\n", req->cmd.xfer);
418 0b06c059 Gerd Hoffmann
        return -1;
419 0b06c059 Gerd Hoffmann
    }
420 0b06c059 Gerd Hoffmann
421 0b06c059 Gerd Hoffmann
    buflen = req->cmd.xfer;
422 0b06c059 Gerd Hoffmann
    if (buflen > SCSI_MAX_INQUIRY_LEN)
423 0b06c059 Gerd Hoffmann
        buflen = SCSI_MAX_INQUIRY_LEN;
424 0b06c059 Gerd Hoffmann
425 0b06c059 Gerd Hoffmann
    memset(outbuf, 0, buflen);
426 0b06c059 Gerd Hoffmann
427 0b06c059 Gerd Hoffmann
    if (req->lun || req->cmd.buf[1] >> 5) {
428 0b06c059 Gerd Hoffmann
        outbuf[0] = 0x7f;        /* LUN not supported */
429 0b06c059 Gerd Hoffmann
        return buflen;
430 0b06c059 Gerd Hoffmann
    }
431 0b06c059 Gerd Hoffmann
432 0b06c059 Gerd Hoffmann
    if (bdrv_get_type_hint(bdrv) == BDRV_TYPE_CDROM) {
433 0b06c059 Gerd Hoffmann
        outbuf[0] = 5;
434 0b06c059 Gerd Hoffmann
        outbuf[1] = 0x80;
435 550fe6c6 Laszlo Ast
        memcpy(&outbuf[16], "QEMU CD-ROM     ", 16);
436 0b06c059 Gerd Hoffmann
    } else {
437 0b06c059 Gerd Hoffmann
        outbuf[0] = 0;
438 550fe6c6 Laszlo Ast
        memcpy(&outbuf[16], "QEMU HARDDISK   ", 16);
439 0b06c059 Gerd Hoffmann
    }
440 550fe6c6 Laszlo Ast
    memcpy(&outbuf[8], "QEMU    ", 8);
441 383b4d9b Gerd Hoffmann
    memcpy(&outbuf[32], s->version ? s->version : QEMU_VERSION, 4);
442 0b06c059 Gerd Hoffmann
    /* Identify device as SCSI-3 rev 1.
443 0b06c059 Gerd Hoffmann
       Some later commands are also implemented. */
444 0b06c059 Gerd Hoffmann
    outbuf[2] = 3;
445 0b06c059 Gerd Hoffmann
    outbuf[3] = 2; /* Format 2 */
446 ad3cea42 Artyom Tarasenko
447 ad3cea42 Artyom Tarasenko
    if (buflen > 36) {
448 ad3cea42 Artyom Tarasenko
        outbuf[4] = buflen - 5; /* Additional Length = (Len - 1) - 4 */
449 ad3cea42 Artyom Tarasenko
    } else {
450 ad3cea42 Artyom Tarasenko
        /* If the allocation length of CDB is too small,
451 ad3cea42 Artyom Tarasenko
               the additional length is not adjusted */
452 ad3cea42 Artyom Tarasenko
        outbuf[4] = 36 - 5;
453 ad3cea42 Artyom Tarasenko
    }
454 ad3cea42 Artyom Tarasenko
455 0b06c059 Gerd Hoffmann
    /* Sync data transfer and TCQ.  */
456 0b06c059 Gerd Hoffmann
    outbuf[7] = 0x10 | (req->bus->tcq ? 0x02 : 0);
457 0b06c059 Gerd Hoffmann
    return buflen;
458 0b06c059 Gerd Hoffmann
}
459 0b06c059 Gerd Hoffmann
460 ebddfcbe Gerd Hoffmann
static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p)
461 ebddfcbe Gerd Hoffmann
{
462 ebddfcbe Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
463 ebddfcbe Gerd Hoffmann
    BlockDriverState *bdrv = req->dev->dinfo->bdrv;
464 ebddfcbe Gerd Hoffmann
    int cylinders, heads, secs;
465 ebddfcbe Gerd Hoffmann
466 ebddfcbe Gerd Hoffmann
    switch (page) {
467 ebddfcbe Gerd Hoffmann
    case 4: /* Rigid disk device geometry page. */
468 ebddfcbe Gerd Hoffmann
        p[0] = 4;
469 ebddfcbe Gerd Hoffmann
        p[1] = 0x16;
470 ebddfcbe Gerd Hoffmann
        /* if a geometry hint is available, use it */
471 ebddfcbe Gerd Hoffmann
        bdrv_get_geometry_hint(bdrv, &cylinders, &heads, &secs);
472 ebddfcbe Gerd Hoffmann
        p[2] = (cylinders >> 16) & 0xff;
473 ebddfcbe Gerd Hoffmann
        p[3] = (cylinders >> 8) & 0xff;
474 ebddfcbe Gerd Hoffmann
        p[4] = cylinders & 0xff;
475 ebddfcbe Gerd Hoffmann
        p[5] = heads & 0xff;
476 ebddfcbe Gerd Hoffmann
        /* Write precomp start cylinder, disabled */
477 ebddfcbe Gerd Hoffmann
        p[6] = (cylinders >> 16) & 0xff;
478 ebddfcbe Gerd Hoffmann
        p[7] = (cylinders >> 8) & 0xff;
479 ebddfcbe Gerd Hoffmann
        p[8] = cylinders & 0xff;
480 ebddfcbe Gerd Hoffmann
        /* Reduced current start cylinder, disabled */
481 ebddfcbe Gerd Hoffmann
        p[9] = (cylinders >> 16) & 0xff;
482 ebddfcbe Gerd Hoffmann
        p[10] = (cylinders >> 8) & 0xff;
483 ebddfcbe Gerd Hoffmann
        p[11] = cylinders & 0xff;
484 ebddfcbe Gerd Hoffmann
        /* Device step rate [ns], 200ns */
485 ebddfcbe Gerd Hoffmann
        p[12] = 0;
486 ebddfcbe Gerd Hoffmann
        p[13] = 200;
487 ebddfcbe Gerd Hoffmann
        /* Landing zone cylinder */
488 ebddfcbe Gerd Hoffmann
        p[14] = 0xff;
489 ebddfcbe Gerd Hoffmann
        p[15] =  0xff;
490 ebddfcbe Gerd Hoffmann
        p[16] = 0xff;
491 ebddfcbe Gerd Hoffmann
        /* Medium rotation rate [rpm], 5400 rpm */
492 ebddfcbe Gerd Hoffmann
        p[20] = (5400 >> 8) & 0xff;
493 ebddfcbe Gerd Hoffmann
        p[21] = 5400 & 0xff;
494 ebddfcbe Gerd Hoffmann
        return 0x16;
495 ebddfcbe Gerd Hoffmann
496 ebddfcbe Gerd Hoffmann
    case 5: /* Flexible disk device geometry page. */
497 ebddfcbe Gerd Hoffmann
        p[0] = 5;
498 ebddfcbe Gerd Hoffmann
        p[1] = 0x1e;
499 ebddfcbe Gerd Hoffmann
        /* Transfer rate [kbit/s], 5Mbit/s */
500 ebddfcbe Gerd Hoffmann
        p[2] = 5000 >> 8;
501 ebddfcbe Gerd Hoffmann
        p[3] = 5000 & 0xff;
502 ebddfcbe Gerd Hoffmann
        /* if a geometry hint is available, use it */
503 ebddfcbe Gerd Hoffmann
        bdrv_get_geometry_hint(bdrv, &cylinders, &heads, &secs);
504 ebddfcbe Gerd Hoffmann
        p[4] = heads & 0xff;
505 ebddfcbe Gerd Hoffmann
        p[5] = secs & 0xff;
506 ebddfcbe Gerd Hoffmann
        p[6] = s->cluster_size * 2;
507 ebddfcbe Gerd Hoffmann
        p[8] = (cylinders >> 8) & 0xff;
508 ebddfcbe Gerd Hoffmann
        p[9] = cylinders & 0xff;
509 ebddfcbe Gerd Hoffmann
        /* Write precomp start cylinder, disabled */
510 ebddfcbe Gerd Hoffmann
        p[10] = (cylinders >> 8) & 0xff;
511 ebddfcbe Gerd Hoffmann
        p[11] = cylinders & 0xff;
512 ebddfcbe Gerd Hoffmann
        /* Reduced current start cylinder, disabled */
513 ebddfcbe Gerd Hoffmann
        p[12] = (cylinders >> 8) & 0xff;
514 ebddfcbe Gerd Hoffmann
        p[13] = cylinders & 0xff;
515 ebddfcbe Gerd Hoffmann
        /* Device step rate [100us], 100us */
516 ebddfcbe Gerd Hoffmann
        p[14] = 0;
517 ebddfcbe Gerd Hoffmann
        p[15] = 1;
518 ebddfcbe Gerd Hoffmann
        /* Device step pulse width [us], 1us */
519 ebddfcbe Gerd Hoffmann
        p[16] = 1;
520 ebddfcbe Gerd Hoffmann
        /* Device head settle delay [100us], 100us */
521 ebddfcbe Gerd Hoffmann
        p[17] = 0;
522 ebddfcbe Gerd Hoffmann
        p[18] = 1;
523 ebddfcbe Gerd Hoffmann
        /* Motor on delay [0.1s], 0.1s */
524 ebddfcbe Gerd Hoffmann
        p[19] = 1;
525 ebddfcbe Gerd Hoffmann
        /* Motor off delay [0.1s], 0.1s */
526 ebddfcbe Gerd Hoffmann
        p[20] = 1;
527 ebddfcbe Gerd Hoffmann
        /* Medium rotation rate [rpm], 5400 rpm */
528 ebddfcbe Gerd Hoffmann
        p[28] = (5400 >> 8) & 0xff;
529 ebddfcbe Gerd Hoffmann
        p[29] = 5400 & 0xff;
530 ebddfcbe Gerd Hoffmann
        return 0x1e;
531 ebddfcbe Gerd Hoffmann
532 ebddfcbe Gerd Hoffmann
    case 8: /* Caching page.  */
533 ebddfcbe Gerd Hoffmann
        p[0] = 8;
534 ebddfcbe Gerd Hoffmann
        p[1] = 0x12;
535 ebddfcbe Gerd Hoffmann
        if (bdrv_enable_write_cache(s->qdev.dinfo->bdrv)) {
536 ebddfcbe Gerd Hoffmann
            p[2] = 4; /* WCE */
537 ebddfcbe Gerd Hoffmann
        }
538 ebddfcbe Gerd Hoffmann
        return 20;
539 ebddfcbe Gerd Hoffmann
540 ebddfcbe Gerd Hoffmann
    case 0x2a: /* CD Capabilities and Mechanical Status page. */
541 ebddfcbe Gerd Hoffmann
        if (bdrv_get_type_hint(bdrv) != BDRV_TYPE_CDROM)
542 ebddfcbe Gerd Hoffmann
            return 0;
543 ebddfcbe Gerd Hoffmann
        p[0] = 0x2a;
544 ebddfcbe Gerd Hoffmann
        p[1] = 0x14;
545 ebddfcbe Gerd Hoffmann
        p[2] = 3; // CD-R & CD-RW read
546 ebddfcbe Gerd Hoffmann
        p[3] = 0; // Writing not supported
547 ebddfcbe Gerd Hoffmann
        p[4] = 0x7f; /* Audio, composite, digital out,
548 ebddfcbe Gerd Hoffmann
                        mode 2 form 1&2, multi session */
549 ebddfcbe Gerd Hoffmann
        p[5] = 0xff; /* CD DA, DA accurate, RW supported,
550 ebddfcbe Gerd Hoffmann
                        RW corrected, C2 errors, ISRC,
551 ebddfcbe Gerd Hoffmann
                        UPC, Bar code */
552 ebddfcbe Gerd Hoffmann
        p[6] = 0x2d | (bdrv_is_locked(s->qdev.dinfo->bdrv)? 2 : 0);
553 ebddfcbe Gerd Hoffmann
        /* Locking supported, jumper present, eject, tray */
554 ebddfcbe Gerd Hoffmann
        p[7] = 0; /* no volume & mute control, no
555 ebddfcbe Gerd Hoffmann
                     changer */
556 ebddfcbe Gerd Hoffmann
        p[8] = (50 * 176) >> 8; // 50x read speed
557 ebddfcbe Gerd Hoffmann
        p[9] = (50 * 176) & 0xff;
558 ebddfcbe Gerd Hoffmann
        p[10] = 0 >> 8; // No volume
559 ebddfcbe Gerd Hoffmann
        p[11] = 0 & 0xff;
560 ebddfcbe Gerd Hoffmann
        p[12] = 2048 >> 8; // 2M buffer
561 ebddfcbe Gerd Hoffmann
        p[13] = 2048 & 0xff;
562 ebddfcbe Gerd Hoffmann
        p[14] = (16 * 176) >> 8; // 16x read speed current
563 ebddfcbe Gerd Hoffmann
        p[15] = (16 * 176) & 0xff;
564 ebddfcbe Gerd Hoffmann
        p[18] = (16 * 176) >> 8; // 16x write speed
565 ebddfcbe Gerd Hoffmann
        p[19] = (16 * 176) & 0xff;
566 ebddfcbe Gerd Hoffmann
        p[20] = (16 * 176) >> 8; // 16x write speed current
567 ebddfcbe Gerd Hoffmann
        p[21] = (16 * 176) & 0xff;
568 ebddfcbe Gerd Hoffmann
        return 22;
569 ebddfcbe Gerd Hoffmann
570 ebddfcbe Gerd Hoffmann
    default:
571 ebddfcbe Gerd Hoffmann
        return 0;
572 ebddfcbe Gerd Hoffmann
    }
573 ebddfcbe Gerd Hoffmann
}
574 ebddfcbe Gerd Hoffmann
575 ebddfcbe Gerd Hoffmann
static int scsi_disk_emulate_mode_sense(SCSIRequest *req, uint8_t *outbuf)
576 ebddfcbe Gerd Hoffmann
{
577 ebddfcbe Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
578 ebddfcbe Gerd Hoffmann
    BlockDriverState *bdrv = req->dev->dinfo->bdrv;
579 ebddfcbe Gerd Hoffmann
    uint64_t nb_sectors;
580 ebddfcbe Gerd Hoffmann
    int page, dbd, buflen;
581 ebddfcbe Gerd Hoffmann
    uint8_t *p;
582 ebddfcbe Gerd Hoffmann
583 ebddfcbe Gerd Hoffmann
    dbd = req->cmd.buf[1]  & 0x8;
584 ebddfcbe Gerd Hoffmann
    page = req->cmd.buf[2] & 0x3f;
585 ebddfcbe Gerd Hoffmann
    DPRINTF("Mode Sense (page %d, len %zd)\n", page, req->cmd.xfer);
586 ebddfcbe Gerd Hoffmann
    memset(outbuf, 0, req->cmd.xfer);
587 ebddfcbe Gerd Hoffmann
    p = outbuf;
588 ebddfcbe Gerd Hoffmann
589 ebddfcbe Gerd Hoffmann
    p[1] = 0; /* Default media type.  */
590 ebddfcbe Gerd Hoffmann
    p[3] = 0; /* Block descriptor length.  */
591 ebddfcbe Gerd Hoffmann
    if (bdrv_get_type_hint(bdrv) == BDRV_TYPE_CDROM ||
592 ebddfcbe Gerd Hoffmann
        bdrv_is_read_only(bdrv)) {
593 ebddfcbe Gerd Hoffmann
        p[2] = 0x80; /* Readonly.  */
594 ebddfcbe Gerd Hoffmann
    }
595 ebddfcbe Gerd Hoffmann
    p += 4;
596 ebddfcbe Gerd Hoffmann
597 ebddfcbe Gerd Hoffmann
    bdrv_get_geometry(bdrv, &nb_sectors);
598 ebddfcbe Gerd Hoffmann
    if ((~dbd) & nb_sectors) {
599 ebddfcbe Gerd Hoffmann
        outbuf[3] = 8; /* Block descriptor length  */
600 ebddfcbe Gerd Hoffmann
        nb_sectors /= s->cluster_size;
601 ebddfcbe Gerd Hoffmann
        nb_sectors--;
602 ebddfcbe Gerd Hoffmann
        if (nb_sectors > 0xffffff)
603 ebddfcbe Gerd Hoffmann
            nb_sectors = 0xffffff;
604 ebddfcbe Gerd Hoffmann
        p[0] = 0; /* media density code */
605 ebddfcbe Gerd Hoffmann
        p[1] = (nb_sectors >> 16) & 0xff;
606 ebddfcbe Gerd Hoffmann
        p[2] = (nb_sectors >> 8) & 0xff;
607 ebddfcbe Gerd Hoffmann
        p[3] = nb_sectors & 0xff;
608 ebddfcbe Gerd Hoffmann
        p[4] = 0; /* reserved */
609 ebddfcbe Gerd Hoffmann
        p[5] = 0; /* bytes 5-7 are the sector size in bytes */
610 ebddfcbe Gerd Hoffmann
        p[6] = s->cluster_size * 2;
611 ebddfcbe Gerd Hoffmann
        p[7] = 0;
612 ebddfcbe Gerd Hoffmann
        p += 8;
613 ebddfcbe Gerd Hoffmann
    }
614 ebddfcbe Gerd Hoffmann
615 ebddfcbe Gerd Hoffmann
    switch (page) {
616 ebddfcbe Gerd Hoffmann
    case 0x04:
617 ebddfcbe Gerd Hoffmann
    case 0x05:
618 ebddfcbe Gerd Hoffmann
    case 0x08:
619 ebddfcbe Gerd Hoffmann
    case 0x2a:
620 ebddfcbe Gerd Hoffmann
        p += mode_sense_page(req, page, p);
621 ebddfcbe Gerd Hoffmann
        break;
622 ebddfcbe Gerd Hoffmann
    case 0x3f:
623 ebddfcbe Gerd Hoffmann
        p += mode_sense_page(req, 0x08, p);
624 ebddfcbe Gerd Hoffmann
        p += mode_sense_page(req, 0x2a, p);
625 ebddfcbe Gerd Hoffmann
        break;
626 ebddfcbe Gerd Hoffmann
    }
627 ebddfcbe Gerd Hoffmann
628 ebddfcbe Gerd Hoffmann
    buflen = p - outbuf;
629 ebddfcbe Gerd Hoffmann
    outbuf[0] = buflen - 4;
630 ebddfcbe Gerd Hoffmann
    if (buflen > req->cmd.xfer)
631 ebddfcbe Gerd Hoffmann
        buflen = req->cmd.xfer;
632 ebddfcbe Gerd Hoffmann
    return buflen;
633 ebddfcbe Gerd Hoffmann
}
634 ebddfcbe Gerd Hoffmann
635 02880f43 Gerd Hoffmann
static int scsi_disk_emulate_read_toc(SCSIRequest *req, uint8_t *outbuf)
636 02880f43 Gerd Hoffmann
{
637 02880f43 Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
638 02880f43 Gerd Hoffmann
    BlockDriverState *bdrv = req->dev->dinfo->bdrv;
639 02880f43 Gerd Hoffmann
    int start_track, format, msf, toclen;
640 02880f43 Gerd Hoffmann
    uint64_t nb_sectors;
641 02880f43 Gerd Hoffmann
642 02880f43 Gerd Hoffmann
    msf = req->cmd.buf[1] & 2;
643 02880f43 Gerd Hoffmann
    format = req->cmd.buf[2] & 0xf;
644 02880f43 Gerd Hoffmann
    start_track = req->cmd.buf[6];
645 02880f43 Gerd Hoffmann
    bdrv_get_geometry(bdrv, &nb_sectors);
646 02880f43 Gerd Hoffmann
    DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1);
647 02880f43 Gerd Hoffmann
    nb_sectors /= s->cluster_size;
648 02880f43 Gerd Hoffmann
    switch (format) {
649 02880f43 Gerd Hoffmann
    case 0:
650 02880f43 Gerd Hoffmann
        toclen = cdrom_read_toc(nb_sectors, outbuf, msf, start_track);
651 02880f43 Gerd Hoffmann
        break;
652 02880f43 Gerd Hoffmann
    case 1:
653 02880f43 Gerd Hoffmann
        /* multi session : only a single session defined */
654 02880f43 Gerd Hoffmann
        toclen = 12;
655 02880f43 Gerd Hoffmann
        memset(outbuf, 0, 12);
656 02880f43 Gerd Hoffmann
        outbuf[1] = 0x0a;
657 02880f43 Gerd Hoffmann
        outbuf[2] = 0x01;
658 02880f43 Gerd Hoffmann
        outbuf[3] = 0x01;
659 02880f43 Gerd Hoffmann
        break;
660 02880f43 Gerd Hoffmann
    case 2:
661 02880f43 Gerd Hoffmann
        toclen = cdrom_read_toc_raw(nb_sectors, outbuf, msf, start_track);
662 02880f43 Gerd Hoffmann
        break;
663 02880f43 Gerd Hoffmann
    default:
664 02880f43 Gerd Hoffmann
        return -1;
665 02880f43 Gerd Hoffmann
    }
666 02880f43 Gerd Hoffmann
    if (toclen > req->cmd.xfer)
667 02880f43 Gerd Hoffmann
        toclen = req->cmd.xfer;
668 02880f43 Gerd Hoffmann
    return toclen;
669 02880f43 Gerd Hoffmann
}
670 02880f43 Gerd Hoffmann
671 aa5dbdc1 Gerd Hoffmann
static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf)
672 aa5dbdc1 Gerd Hoffmann
{
673 e7e25e32 Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
674 aa5dbdc1 Gerd Hoffmann
    BlockDriverState *bdrv = req->dev->dinfo->bdrv;
675 e7e25e32 Gerd Hoffmann
    uint64_t nb_sectors;
676 aa5dbdc1 Gerd Hoffmann
    int buflen = 0;
677 aa5dbdc1 Gerd Hoffmann
678 aa5dbdc1 Gerd Hoffmann
    switch (req->cmd.buf[0]) {
679 aa5dbdc1 Gerd Hoffmann
    case TEST_UNIT_READY:
680 aa5dbdc1 Gerd Hoffmann
        if (!bdrv_is_inserted(bdrv))
681 aa5dbdc1 Gerd Hoffmann
            goto not_ready;
682 aa5dbdc1 Gerd Hoffmann
        break;
683 51ad87c9 Gerd Hoffmann
    case REQUEST_SENSE:
684 51ad87c9 Gerd Hoffmann
        if (req->cmd.xfer < 4)
685 51ad87c9 Gerd Hoffmann
            goto illegal_request;
686 51ad87c9 Gerd Hoffmann
        memset(outbuf, 0, 4);
687 51ad87c9 Gerd Hoffmann
        buflen = 4;
688 51ad87c9 Gerd Hoffmann
        if (req->dev->sense.key == NOT_READY && req->cmd.xfer >= 18) {
689 51ad87c9 Gerd Hoffmann
            memset(outbuf, 0, 18);
690 51ad87c9 Gerd Hoffmann
            buflen = 18;
691 51ad87c9 Gerd Hoffmann
            outbuf[7] = 10;
692 51ad87c9 Gerd Hoffmann
            /* asc 0x3a, ascq 0: Medium not present */
693 51ad87c9 Gerd Hoffmann
            outbuf[12] = 0x3a;
694 51ad87c9 Gerd Hoffmann
            outbuf[13] = 0;
695 51ad87c9 Gerd Hoffmann
        }
696 51ad87c9 Gerd Hoffmann
        outbuf[0] = 0xf0;
697 51ad87c9 Gerd Hoffmann
        outbuf[1] = 0;
698 51ad87c9 Gerd Hoffmann
        outbuf[2] = req->dev->sense.key;
699 51ad87c9 Gerd Hoffmann
        scsi_dev_clear_sense(req->dev);
700 51ad87c9 Gerd Hoffmann
        break;
701 0b06c059 Gerd Hoffmann
    case INQUIRY:
702 0b06c059 Gerd Hoffmann
        buflen = scsi_disk_emulate_inquiry(req, outbuf);
703 0b06c059 Gerd Hoffmann
        if (buflen < 0)
704 0b06c059 Gerd Hoffmann
            goto illegal_request;
705 0b06c059 Gerd Hoffmann
        break;
706 ebddfcbe Gerd Hoffmann
    case MODE_SENSE:
707 ebddfcbe Gerd Hoffmann
    case MODE_SENSE_10:
708 ebddfcbe Gerd Hoffmann
        buflen = scsi_disk_emulate_mode_sense(req, outbuf);
709 ebddfcbe Gerd Hoffmann
        if (buflen < 0)
710 ebddfcbe Gerd Hoffmann
            goto illegal_request;
711 ebddfcbe Gerd Hoffmann
        break;
712 02880f43 Gerd Hoffmann
    case READ_TOC:
713 02880f43 Gerd Hoffmann
        buflen = scsi_disk_emulate_read_toc(req, outbuf);
714 02880f43 Gerd Hoffmann
        if (buflen < 0)
715 02880f43 Gerd Hoffmann
            goto illegal_request;
716 02880f43 Gerd Hoffmann
        break;
717 3d53ba18 Gerd Hoffmann
    case RESERVE:
718 3d53ba18 Gerd Hoffmann
        if (req->cmd.buf[1] & 1)
719 3d53ba18 Gerd Hoffmann
            goto illegal_request;
720 3d53ba18 Gerd Hoffmann
        break;
721 3d53ba18 Gerd Hoffmann
    case RESERVE_10:
722 3d53ba18 Gerd Hoffmann
        if (req->cmd.buf[1] & 3)
723 3d53ba18 Gerd Hoffmann
            goto illegal_request;
724 3d53ba18 Gerd Hoffmann
        break;
725 3d53ba18 Gerd Hoffmann
    case RELEASE:
726 3d53ba18 Gerd Hoffmann
        if (req->cmd.buf[1] & 1)
727 3d53ba18 Gerd Hoffmann
            goto illegal_request;
728 3d53ba18 Gerd Hoffmann
        break;
729 3d53ba18 Gerd Hoffmann
    case RELEASE_10:
730 3d53ba18 Gerd Hoffmann
        if (req->cmd.buf[1] & 3)
731 3d53ba18 Gerd Hoffmann
            goto illegal_request;
732 3d53ba18 Gerd Hoffmann
        break;
733 8d3628ff Gerd Hoffmann
    case START_STOP:
734 8d3628ff Gerd Hoffmann
        if (bdrv_get_type_hint(bdrv) == BDRV_TYPE_CDROM && (req->cmd.buf[4] & 2)) {
735 8d3628ff Gerd Hoffmann
            /* load/eject medium */
736 8d3628ff Gerd Hoffmann
            bdrv_eject(bdrv, !(req->cmd.buf[4] & 1));
737 8d3628ff Gerd Hoffmann
        }
738 8d3628ff Gerd Hoffmann
        break;
739 c68b9f34 Gerd Hoffmann
    case ALLOW_MEDIUM_REMOVAL:
740 c68b9f34 Gerd Hoffmann
        bdrv_set_locked(bdrv, req->cmd.buf[4] & 1);
741 c68b9f34 Gerd Hoffmann
        break;
742 e7e25e32 Gerd Hoffmann
    case READ_CAPACITY:
743 e7e25e32 Gerd Hoffmann
        /* The normal LEN field for this command is zero.  */
744 e7e25e32 Gerd Hoffmann
        memset(outbuf, 0, 8);
745 e7e25e32 Gerd Hoffmann
        bdrv_get_geometry(bdrv, &nb_sectors);
746 e7e25e32 Gerd Hoffmann
        if (!nb_sectors)
747 e7e25e32 Gerd Hoffmann
            goto not_ready;
748 e7e25e32 Gerd Hoffmann
        nb_sectors /= s->cluster_size;
749 e7e25e32 Gerd Hoffmann
        /* Returned value is the address of the last sector.  */
750 e7e25e32 Gerd Hoffmann
        nb_sectors--;
751 e7e25e32 Gerd Hoffmann
        /* Remember the new size for read/write sanity checking. */
752 e7e25e32 Gerd Hoffmann
        s->max_lba = nb_sectors;
753 e7e25e32 Gerd Hoffmann
        /* Clip to 2TB, instead of returning capacity modulo 2TB. */
754 e7e25e32 Gerd Hoffmann
        if (nb_sectors > UINT32_MAX)
755 e7e25e32 Gerd Hoffmann
            nb_sectors = UINT32_MAX;
756 e7e25e32 Gerd Hoffmann
        outbuf[0] = (nb_sectors >> 24) & 0xff;
757 e7e25e32 Gerd Hoffmann
        outbuf[1] = (nb_sectors >> 16) & 0xff;
758 e7e25e32 Gerd Hoffmann
        outbuf[2] = (nb_sectors >> 8) & 0xff;
759 e7e25e32 Gerd Hoffmann
        outbuf[3] = nb_sectors & 0xff;
760 e7e25e32 Gerd Hoffmann
        outbuf[4] = 0;
761 e7e25e32 Gerd Hoffmann
        outbuf[5] = 0;
762 e7e25e32 Gerd Hoffmann
        outbuf[6] = s->cluster_size * 2;
763 e7e25e32 Gerd Hoffmann
        outbuf[7] = 0;
764 e7e25e32 Gerd Hoffmann
        buflen = 8;
765 e7e25e32 Gerd Hoffmann
        break;
766 fc903943 Gerd Hoffmann
    case SYNCHRONIZE_CACHE:
767 fc903943 Gerd Hoffmann
        bdrv_flush(bdrv);
768 fc903943 Gerd Hoffmann
        break;
769 38215553 Gerd Hoffmann
    case GET_CONFIGURATION:
770 38215553 Gerd Hoffmann
        memset(outbuf, 0, 8);
771 38215553 Gerd Hoffmann
        /* ??? This should probably return much more information.  For now
772 38215553 Gerd Hoffmann
           just return the basic header indicating the CD-ROM profile.  */
773 38215553 Gerd Hoffmann
        outbuf[7] = 8; // CD-ROM
774 38215553 Gerd Hoffmann
        buflen = 8;
775 38215553 Gerd Hoffmann
        break;
776 5dd90e2a Gerd Hoffmann
    case SERVICE_ACTION_IN:
777 5dd90e2a Gerd Hoffmann
        /* Service Action In subcommands. */
778 5dd90e2a Gerd Hoffmann
        if ((req->cmd.buf[1] & 31) == 0x10) {
779 5dd90e2a Gerd Hoffmann
            DPRINTF("SAI READ CAPACITY(16)\n");
780 5dd90e2a Gerd Hoffmann
            memset(outbuf, 0, req->cmd.xfer);
781 5dd90e2a Gerd Hoffmann
            bdrv_get_geometry(bdrv, &nb_sectors);
782 5dd90e2a Gerd Hoffmann
            if (!nb_sectors)
783 5dd90e2a Gerd Hoffmann
                goto not_ready;
784 5dd90e2a Gerd Hoffmann
            nb_sectors /= s->cluster_size;
785 5dd90e2a Gerd Hoffmann
            /* Returned value is the address of the last sector.  */
786 5dd90e2a Gerd Hoffmann
            nb_sectors--;
787 5dd90e2a Gerd Hoffmann
            /* Remember the new size for read/write sanity checking. */
788 5dd90e2a Gerd Hoffmann
            s->max_lba = nb_sectors;
789 5dd90e2a Gerd Hoffmann
            outbuf[0] = (nb_sectors >> 56) & 0xff;
790 5dd90e2a Gerd Hoffmann
            outbuf[1] = (nb_sectors >> 48) & 0xff;
791 5dd90e2a Gerd Hoffmann
            outbuf[2] = (nb_sectors >> 40) & 0xff;
792 5dd90e2a Gerd Hoffmann
            outbuf[3] = (nb_sectors >> 32) & 0xff;
793 5dd90e2a Gerd Hoffmann
            outbuf[4] = (nb_sectors >> 24) & 0xff;
794 5dd90e2a Gerd Hoffmann
            outbuf[5] = (nb_sectors >> 16) & 0xff;
795 5dd90e2a Gerd Hoffmann
            outbuf[6] = (nb_sectors >> 8) & 0xff;
796 5dd90e2a Gerd Hoffmann
            outbuf[7] = nb_sectors & 0xff;
797 5dd90e2a Gerd Hoffmann
            outbuf[8] = 0;
798 5dd90e2a Gerd Hoffmann
            outbuf[9] = 0;
799 5dd90e2a Gerd Hoffmann
            outbuf[10] = s->cluster_size * 2;
800 5dd90e2a Gerd Hoffmann
            outbuf[11] = 0;
801 5dd90e2a Gerd Hoffmann
            /* Protection, exponent and lowest lba field left blank. */
802 5dd90e2a Gerd Hoffmann
            buflen = req->cmd.xfer;
803 5dd90e2a Gerd Hoffmann
            break;
804 5dd90e2a Gerd Hoffmann
        }
805 5dd90e2a Gerd Hoffmann
        DPRINTF("Unsupported Service Action In\n");
806 5dd90e2a Gerd Hoffmann
        goto illegal_request;
807 39ec9a50 Gerd Hoffmann
    case REPORT_LUNS:
808 39ec9a50 Gerd Hoffmann
        if (req->cmd.xfer < 16)
809 39ec9a50 Gerd Hoffmann
            goto illegal_request;
810 39ec9a50 Gerd Hoffmann
        memset(outbuf, 0, 16);
811 39ec9a50 Gerd Hoffmann
        outbuf[3] = 8;
812 39ec9a50 Gerd Hoffmann
        buflen = 16;
813 39ec9a50 Gerd Hoffmann
        break;
814 88f8a5ed Gerd Hoffmann
    case VERIFY:
815 88f8a5ed Gerd Hoffmann
        break;
816 aa5dbdc1 Gerd Hoffmann
    default:
817 aa5dbdc1 Gerd Hoffmann
        goto illegal_request;
818 aa5dbdc1 Gerd Hoffmann
    }
819 aa5dbdc1 Gerd Hoffmann
    scsi_req_set_status(req, GOOD, NO_SENSE);
820 aa5dbdc1 Gerd Hoffmann
    return buflen;
821 aa5dbdc1 Gerd Hoffmann
822 aa5dbdc1 Gerd Hoffmann
not_ready:
823 aa5dbdc1 Gerd Hoffmann
    scsi_req_set_status(req, CHECK_CONDITION, NOT_READY);
824 aa5dbdc1 Gerd Hoffmann
    return 0;
825 aa5dbdc1 Gerd Hoffmann
826 aa5dbdc1 Gerd Hoffmann
illegal_request:
827 aa5dbdc1 Gerd Hoffmann
    scsi_req_set_status(req, CHECK_CONDITION, ILLEGAL_REQUEST);
828 aa5dbdc1 Gerd Hoffmann
    return 0;
829 aa5dbdc1 Gerd Hoffmann
}
830 aa5dbdc1 Gerd Hoffmann
831 2e5d83bb pbrook
/* Execute a scsi command.  Returns the length of the data expected by the
832 2e5d83bb pbrook
   command.  This will be Positive for data transfers from the device
833 2e5d83bb pbrook
   (eg. disk reads), negative for transfers to the device (eg. disk writes),
834 2e5d83bb pbrook
   and zero if the command does not transfer any data.  */
835 2e5d83bb pbrook
836 8ccc2ace ths
static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
837 8ccc2ace ths
                                 uint8_t *buf, int lun)
838 2e5d83bb pbrook
{
839 d52affa7 Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
840 86106e59 aliguori
    uint64_t lba;
841 2e5d83bb pbrook
    uint32_t len;
842 2e5d83bb pbrook
    int cmdlen;
843 2e5d83bb pbrook
    int is_write;
844 a917d384 pbrook
    uint8_t command;
845 a917d384 pbrook
    uint8_t *outbuf;
846 4c41d2ef Gerd Hoffmann
    SCSIDiskReq *r;
847 aa5dbdc1 Gerd Hoffmann
    int rc;
848 a917d384 pbrook
849 a917d384 pbrook
    command = buf[0];
850 a917d384 pbrook
    r = scsi_find_request(s, tag);
851 a917d384 pbrook
    if (r) {
852 a917d384 pbrook
        BADF("Tag 0x%x already in use\n", tag);
853 8ccc2ace ths
        scsi_cancel_io(d, tag);
854 a917d384 pbrook
    }
855 a917d384 pbrook
    /* ??? Tags are not unique for different luns.  We only implement a
856 a917d384 pbrook
       single lun, so this should not matter.  */
857 89b08ae1 Gerd Hoffmann
    r = scsi_new_request(d, tag, lun);
858 3f4cb3d3 blueswir1
    outbuf = (uint8_t *)r->iov.iov_base;
859 2e5d83bb pbrook
    is_write = 0;
860 a917d384 pbrook
    DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]);
861 a917d384 pbrook
    switch (command >> 5) {
862 2e5d83bb pbrook
    case 0:
863 86106e59 aliguori
        lba = (uint64_t) buf[3] | ((uint64_t) buf[2] << 8) |
864 86106e59 aliguori
              (((uint64_t) buf[1] & 0x1f) << 16);
865 2e5d83bb pbrook
        len = buf[4];
866 2e5d83bb pbrook
        cmdlen = 6;
867 2e5d83bb pbrook
        break;
868 2e5d83bb pbrook
    case 1:
869 2e5d83bb pbrook
    case 2:
870 86106e59 aliguori
        lba = (uint64_t) buf[5] | ((uint64_t) buf[4] << 8) |
871 86106e59 aliguori
              ((uint64_t) buf[3] << 16) | ((uint64_t) buf[2] << 24);
872 2e5d83bb pbrook
        len = buf[8] | (buf[7] << 8);
873 2e5d83bb pbrook
        cmdlen = 10;
874 2e5d83bb pbrook
        break;
875 2e5d83bb pbrook
    case 4:
876 86106e59 aliguori
        lba = (uint64_t) buf[9] | ((uint64_t) buf[8] << 8) |
877 86106e59 aliguori
              ((uint64_t) buf[7] << 16) | ((uint64_t) buf[6] << 24) |
878 86106e59 aliguori
              ((uint64_t) buf[5] << 32) | ((uint64_t) buf[4] << 40) |
879 86106e59 aliguori
              ((uint64_t) buf[3] << 48) | ((uint64_t) buf[2] << 56);
880 2e5d83bb pbrook
        len = buf[13] | (buf[12] << 8) | (buf[11] << 16) | (buf[10] << 24);
881 2e5d83bb pbrook
        cmdlen = 16;
882 2e5d83bb pbrook
        break;
883 2e5d83bb pbrook
    case 5:
884 86106e59 aliguori
        lba = (uint64_t) buf[5] | ((uint64_t) buf[4] << 8) |
885 86106e59 aliguori
              ((uint64_t) buf[3] << 16) | ((uint64_t) buf[2] << 24);
886 2e5d83bb pbrook
        len = buf[9] | (buf[8] << 8) | (buf[7] << 16) | (buf[6] << 24);
887 2e5d83bb pbrook
        cmdlen = 12;
888 2e5d83bb pbrook
        break;
889 2e5d83bb pbrook
    default:
890 a917d384 pbrook
        BADF("Unsupported command length, command %x\n", command);
891 2e5d83bb pbrook
        goto fail;
892 2e5d83bb pbrook
    }
893 2e5d83bb pbrook
#ifdef DEBUG_SCSI
894 2e5d83bb pbrook
    {
895 2e5d83bb pbrook
        int i;
896 2e5d83bb pbrook
        for (i = 1; i < cmdlen; i++) {
897 2e5d83bb pbrook
            printf(" 0x%02x", buf[i]);
898 2e5d83bb pbrook
        }
899 2e5d83bb pbrook
        printf("\n");
900 2e5d83bb pbrook
    }
901 2e5d83bb pbrook
#endif
902 aa5dbdc1 Gerd Hoffmann
903 aa5dbdc1 Gerd Hoffmann
    if (scsi_req_parse(&r->req, buf) != 0) {
904 aa5dbdc1 Gerd Hoffmann
        BADF("Unsupported command length, command %x\n", command);
905 aa5dbdc1 Gerd Hoffmann
        goto fail;
906 aa5dbdc1 Gerd Hoffmann
    }
907 aa5dbdc1 Gerd Hoffmann
    assert(r->req.cmd.len == cmdlen);
908 aa5dbdc1 Gerd Hoffmann
    assert(r->req.cmd.lba == lba);
909 aa5dbdc1 Gerd Hoffmann
910 0fc5c15a pbrook
    if (lun || buf[1] >> 5) {
911 2e5d83bb pbrook
        /* Only LUN 0 supported.  */
912 0fc5c15a pbrook
        DPRINTF("Unimplemented LUN %d\n", lun ? lun : buf[1] >> 5);
913 ebf46023 Gerd Hoffmann
        if (command != REQUEST_SENSE && command != INQUIRY)
914 22864256 blueswir1
            goto fail;
915 2e5d83bb pbrook
    }
916 a917d384 pbrook
    switch (command) {
917 ebf46023 Gerd Hoffmann
    case TEST_UNIT_READY:
918 51ad87c9 Gerd Hoffmann
    case REQUEST_SENSE:
919 0b06c059 Gerd Hoffmann
    case INQUIRY:
920 ebddfcbe Gerd Hoffmann
    case MODE_SENSE:
921 ebddfcbe Gerd Hoffmann
    case MODE_SENSE_10:
922 3d53ba18 Gerd Hoffmann
    case RESERVE:
923 3d53ba18 Gerd Hoffmann
    case RESERVE_10:
924 3d53ba18 Gerd Hoffmann
    case RELEASE:
925 3d53ba18 Gerd Hoffmann
    case RELEASE_10:
926 8d3628ff Gerd Hoffmann
    case START_STOP:
927 c68b9f34 Gerd Hoffmann
    case ALLOW_MEDIUM_REMOVAL:
928 e7e25e32 Gerd Hoffmann
    case READ_CAPACITY:
929 fc903943 Gerd Hoffmann
    case SYNCHRONIZE_CACHE:
930 02880f43 Gerd Hoffmann
    case READ_TOC:
931 38215553 Gerd Hoffmann
    case GET_CONFIGURATION:
932 5dd90e2a Gerd Hoffmann
    case SERVICE_ACTION_IN:
933 39ec9a50 Gerd Hoffmann
    case REPORT_LUNS:
934 88f8a5ed Gerd Hoffmann
    case VERIFY:
935 aa5dbdc1 Gerd Hoffmann
        rc = scsi_disk_emulate_command(&r->req, outbuf);
936 aa5dbdc1 Gerd Hoffmann
        if (rc > 0) {
937 aa5dbdc1 Gerd Hoffmann
            r->iov.iov_len = rc;
938 aa5dbdc1 Gerd Hoffmann
        } else {
939 aa5dbdc1 Gerd Hoffmann
            scsi_req_complete(&r->req);
940 aa5dbdc1 Gerd Hoffmann
            scsi_remove_request(r);
941 0b06c059 Gerd Hoffmann
            return 0;
942 aa5dbdc1 Gerd Hoffmann
        }
943 0b06c059 Gerd Hoffmann
        break;
944 ebf46023 Gerd Hoffmann
    case READ_6:
945 ebf46023 Gerd Hoffmann
    case READ_10:
946 bd536cf3 Gerd Hoffmann
    case READ_12:
947 bd536cf3 Gerd Hoffmann
    case READ_16:
948 0bf9e31a Blue Swirl
        DPRINTF("Read (sector %" PRId64 ", count %d)\n", lba, len);
949 274fb0e1 aliguori
        if (lba > s->max_lba)
950 274fb0e1 aliguori
            goto illegal_lba;
951 a917d384 pbrook
        r->sector = lba * s->cluster_size;
952 a917d384 pbrook
        r->sector_count = len * s->cluster_size;
953 2e5d83bb pbrook
        break;
954 ebf46023 Gerd Hoffmann
    case WRITE_6:
955 ebf46023 Gerd Hoffmann
    case WRITE_10:
956 bd536cf3 Gerd Hoffmann
    case WRITE_12:
957 bd536cf3 Gerd Hoffmann
    case WRITE_16:
958 0bf9e31a Blue Swirl
        DPRINTF("Write (sector %" PRId64 ", count %d)\n", lba, len);
959 274fb0e1 aliguori
        if (lba > s->max_lba)
960 274fb0e1 aliguori
            goto illegal_lba;
961 a917d384 pbrook
        r->sector = lba * s->cluster_size;
962 a917d384 pbrook
        r->sector_count = len * s->cluster_size;
963 2e5d83bb pbrook
        is_write = 1;
964 2e5d83bb pbrook
        break;
965 2e5d83bb pbrook
    default:
966 2e5d83bb pbrook
        DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
967 2e5d83bb pbrook
    fail:
968 0d65e1f8 Gerd Hoffmann
        scsi_command_complete(r, CHECK_CONDITION, ILLEGAL_REQUEST);
969 2e5d83bb pbrook
        return 0;
970 274fb0e1 aliguori
    illegal_lba:
971 0d65e1f8 Gerd Hoffmann
        scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR);
972 274fb0e1 aliguori
        return 0;
973 2e5d83bb pbrook
    }
974 c87c0672 aliguori
    if (r->sector_count == 0 && r->iov.iov_len == 0) {
975 0d65e1f8 Gerd Hoffmann
        scsi_command_complete(r, GOOD, NO_SENSE);
976 a917d384 pbrook
    }
977 c87c0672 aliguori
    len = r->sector_count * 512 + r->iov.iov_len;
978 a917d384 pbrook
    if (is_write) {
979 a917d384 pbrook
        return -len;
980 a917d384 pbrook
    } else {
981 a917d384 pbrook
        if (!r->sector_count)
982 a917d384 pbrook
            r->sector_count = -1;
983 a917d384 pbrook
        return len;
984 2e5d83bb pbrook
    }
985 2e5d83bb pbrook
}
986 2e5d83bb pbrook
987 56a14938 Gerd Hoffmann
static void scsi_destroy(SCSIDevice *dev)
988 56a14938 Gerd Hoffmann
{
989 56a14938 Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
990 9af99d98 Gerd Hoffmann
    SCSIDiskReq *r;
991 56a14938 Gerd Hoffmann
992 9af99d98 Gerd Hoffmann
    while (!QTAILQ_EMPTY(&s->qdev.requests)) {
993 9af99d98 Gerd Hoffmann
        r = DO_UPCAST(SCSIDiskReq, req, QTAILQ_FIRST(&s->qdev.requests));
994 9af99d98 Gerd Hoffmann
        scsi_remove_request(r);
995 9af99d98 Gerd Hoffmann
    }
996 251882b7 Gerd Hoffmann
    drive_uninit(s->qdev.dinfo);
997 56a14938 Gerd Hoffmann
}
998 56a14938 Gerd Hoffmann
999 d52affa7 Gerd Hoffmann
static int scsi_disk_initfn(SCSIDevice *dev)
1000 2e5d83bb pbrook
{
1001 d52affa7 Gerd Hoffmann
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
1002 274fb0e1 aliguori
    uint64_t nb_sectors;
1003 2e5d83bb pbrook
1004 251882b7 Gerd Hoffmann
    if (!s->qdev.dinfo || !s->qdev.dinfo->bdrv) {
1005 d52affa7 Gerd Hoffmann
        qemu_error("scsi-disk: drive property not set\n");
1006 d52affa7 Gerd Hoffmann
        return -1;
1007 d52affa7 Gerd Hoffmann
    }
1008 d52affa7 Gerd Hoffmann
1009 251882b7 Gerd Hoffmann
    if (bdrv_get_type_hint(s->qdev.dinfo->bdrv) == BDRV_TYPE_CDROM) {
1010 7c22dd52 pbrook
        s->cluster_size = 4;
1011 2e5d83bb pbrook
    } else {
1012 7c22dd52 pbrook
        s->cluster_size = 1;
1013 2e5d83bb pbrook
    }
1014 b07995e3 Gerd Hoffmann
    s->qdev.blocksize = 512 * s->cluster_size;
1015 91376656 Gerd Hoffmann
    s->qdev.type = TYPE_DISK;
1016 251882b7 Gerd Hoffmann
    bdrv_get_geometry(s->qdev.dinfo->bdrv, &nb_sectors);
1017 274fb0e1 aliguori
    nb_sectors /= s->cluster_size;
1018 274fb0e1 aliguori
    if (nb_sectors)
1019 274fb0e1 aliguori
        nb_sectors--;
1020 274fb0e1 aliguori
    s->max_lba = nb_sectors;
1021 ea8a5d7f aliguori
    qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s);
1022 d52affa7 Gerd Hoffmann
    return 0;
1023 d52affa7 Gerd Hoffmann
}
1024 d52affa7 Gerd Hoffmann
1025 d52affa7 Gerd Hoffmann
static SCSIDeviceInfo scsi_disk_info = {
1026 d52affa7 Gerd Hoffmann
    .qdev.name    = "scsi-disk",
1027 d52affa7 Gerd Hoffmann
    .qdev.desc    = "virtual scsi disk or cdrom",
1028 d52affa7 Gerd Hoffmann
    .qdev.size    = sizeof(SCSIDiskState),
1029 d52affa7 Gerd Hoffmann
    .init         = scsi_disk_initfn,
1030 56a14938 Gerd Hoffmann
    .destroy      = scsi_destroy,
1031 d52affa7 Gerd Hoffmann
    .send_command = scsi_send_command,
1032 d52affa7 Gerd Hoffmann
    .read_data    = scsi_read_data,
1033 d52affa7 Gerd Hoffmann
    .write_data   = scsi_write_data,
1034 d52affa7 Gerd Hoffmann
    .cancel_io    = scsi_cancel_io,
1035 d52affa7 Gerd Hoffmann
    .get_buf      = scsi_get_buf,
1036 d52affa7 Gerd Hoffmann
    .qdev.props   = (Property[]) {
1037 251882b7 Gerd Hoffmann
        DEFINE_PROP_DRIVE("drive", SCSIDiskState, qdev.dinfo),
1038 383b4d9b Gerd Hoffmann
        DEFINE_PROP_STRING("ver",  SCSIDiskState, version),
1039 d52affa7 Gerd Hoffmann
        DEFINE_PROP_END_OF_LIST(),
1040 d52affa7 Gerd Hoffmann
    },
1041 d52affa7 Gerd Hoffmann
};
1042 d52affa7 Gerd Hoffmann
1043 d52affa7 Gerd Hoffmann
static void scsi_disk_register_devices(void)
1044 d52affa7 Gerd Hoffmann
{
1045 d52affa7 Gerd Hoffmann
    scsi_qdev_register(&scsi_disk_info);
1046 8ccc2ace ths
}
1047 d52affa7 Gerd Hoffmann
device_init(scsi_disk_register_devices)