Statistics
| Branch: | Revision:

root / hw / scsi-disk.c @ 39ec9a50

History | View | Annotate | Download (30.4 kB)

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