Statistics
| Branch: | Revision:

root / hw / scsi-disk.c @ b4b784fe

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