root / hw / scsi-disk.c @ bc927e48
History | View | Annotate | Download (73.9 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 | 8e31bf38 | Matthew Fernandez | * This code is licensed under the LGPL.
|
16 | a917d384 | pbrook | *
|
17 | a917d384 | pbrook | * Note that this file only handles the SCSI architecture model and device
|
18 | 1d4db89c | balrog | * commands. Emulation of interface/link layer protocols is handled by
|
19 | 1d4db89c | balrog | * the host adapter emulator.
|
20 | 2e5d83bb | pbrook | */
|
21 | 2e5d83bb | pbrook | |
22 | 2e5d83bb | pbrook | //#define DEBUG_SCSI
|
23 | 2e5d83bb | pbrook | |
24 | 2e5d83bb | pbrook | #ifdef DEBUG_SCSI
|
25 | 001faf32 | Blue Swirl | #define DPRINTF(fmt, ...) \
|
26 | 001faf32 | Blue Swirl | do { printf("scsi-disk: " fmt , ## __VA_ARGS__); } while (0) |
27 | 2e5d83bb | pbrook | #else
|
28 | 001faf32 | Blue Swirl | #define DPRINTF(fmt, ...) do {} while(0) |
29 | 2e5d83bb | pbrook | #endif
|
30 | 2e5d83bb | pbrook | |
31 | 87ecb68b | pbrook | #include "qemu-common.h" |
32 | 2f792016 | Markus Armbruster | #include "qemu-error.h" |
33 | 43b443b6 | Gerd Hoffmann | #include "scsi.h" |
34 | 0d65e1f8 | Gerd Hoffmann | #include "scsi-defs.h" |
35 | 666daa68 | Markus Armbruster | #include "sysemu.h" |
36 | 2446333c | Blue Swirl | #include "blockdev.h" |
37 | 9db1c0f7 | Markus Armbruster | #include "hw/block-common.h" |
38 | 5d0d2467 | Paolo Bonzini | #include "dma.h" |
39 | 22864256 | blueswir1 | |
40 | 336a6915 | Paolo Bonzini | #ifdef __linux
|
41 | 336a6915 | Paolo Bonzini | #include <scsi/sg.h> |
42 | 336a6915 | Paolo Bonzini | #endif
|
43 | 336a6915 | Paolo Bonzini | |
44 | f0f72ffe | aurel32 | #define SCSI_DMA_BUF_SIZE 131072 |
45 | 57575058 | balrog | #define SCSI_MAX_INQUIRY_LEN 256 |
46 | 380feaff | Paolo Bonzini | #define SCSI_MAX_MODE_LEN 256 |
47 | a917d384 | pbrook | |
48 | d52affa7 | Gerd Hoffmann | typedef struct SCSIDiskState SCSIDiskState; |
49 | d52affa7 | Gerd Hoffmann | |
50 | 4c41d2ef | Gerd Hoffmann | typedef struct SCSIDiskReq { |
51 | 4c41d2ef | Gerd Hoffmann | SCSIRequest req; |
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 | 7285477a | Paolo Bonzini | uint32_t buflen; |
56 | a0e66a69 | Paolo Bonzini | bool started;
|
57 | c87c0672 | aliguori | struct iovec iov;
|
58 | c87c0672 | aliguori | QEMUIOVector qiov; |
59 | a597e79c | Christoph Hellwig | BlockAcctCookie acct; |
60 | 4c41d2ef | Gerd Hoffmann | } SCSIDiskReq; |
61 | a917d384 | pbrook | |
62 | bfe3d7ac | Paolo Bonzini | #define SCSI_DISK_F_REMOVABLE 0 |
63 | da8365db | Paolo Bonzini | #define SCSI_DISK_F_DPOFUA 1 |
64 | bfe3d7ac | Paolo Bonzini | |
65 | d52affa7 | Gerd Hoffmann | struct SCSIDiskState
|
66 | a917d384 | pbrook | { |
67 | d52affa7 | Gerd Hoffmann | SCSIDevice qdev; |
68 | bfe3d7ac | Paolo Bonzini | uint32_t features; |
69 | 8a9c16f6 | Paolo Bonzini | bool media_changed;
|
70 | 3c2f7c12 | Paolo Bonzini | bool media_event;
|
71 | 4480de19 | Paolo Bonzini | bool eject_request;
|
72 | 27395add | Paolo Bonzini | uint64_t wwn; |
73 | 213189ab | Markus Armbruster | QEMUBH *bh; |
74 | 383b4d9b | Gerd Hoffmann | char *version;
|
75 | a0fef654 | Markus Armbruster | char *serial;
|
76 | 353815aa | Dmitry Fleytman | char *vendor;
|
77 | 353815aa | Dmitry Fleytman | char *product;
|
78 | ece0d5e9 | Markus Armbruster | bool tray_open;
|
79 | 81b1008d | Markus Armbruster | bool tray_locked;
|
80 | 2e5d83bb | pbrook | }; |
81 | 2e5d83bb | pbrook | |
82 | 71544d30 | Paolo Bonzini | static int scsi_handle_rw_error(SCSIDiskReq *r, int error); |
83 | 5dba48a8 | Kevin Wolf | |
84 | ad2d30f7 | Paolo Bonzini | static void scsi_free_request(SCSIRequest *req) |
85 | 4d611c9a | pbrook | { |
86 | ad2d30f7 | Paolo Bonzini | SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); |
87 | ad2d30f7 | Paolo Bonzini | |
88 | 7285477a | Paolo Bonzini | if (r->iov.iov_base) {
|
89 | 7285477a | Paolo Bonzini | qemu_vfree(r->iov.iov_base); |
90 | 7285477a | Paolo Bonzini | } |
91 | 4d611c9a | pbrook | } |
92 | 4d611c9a | pbrook | |
93 | b45ef674 | Paolo Bonzini | /* Helper function for command completion with sense. */
|
94 | b45ef674 | Paolo Bonzini | static void scsi_check_condition(SCSIDiskReq *r, SCSISense sense) |
95 | ed3a34a3 | Gerd Hoffmann | { |
96 | 02fa69b6 | Blue Swirl | DPRINTF("Command complete tag=0x%x sense=%d/%d/%d\n",
|
97 | 02fa69b6 | Blue Swirl | r->req.tag, sense.key, sense.asc, sense.ascq); |
98 | b45ef674 | Paolo Bonzini | scsi_req_build_sense(&r->req, sense); |
99 | b45ef674 | Paolo Bonzini | scsi_req_complete(&r->req, CHECK_CONDITION); |
100 | 4d611c9a | pbrook | } |
101 | 4d611c9a | pbrook | |
102 | 4d611c9a | pbrook | /* Cancel a pending data transfer. */
|
103 | 5c6c0e51 | Hannes Reinecke | static void scsi_cancel_io(SCSIRequest *req) |
104 | 4d611c9a | pbrook | { |
105 | 5c6c0e51 | Hannes Reinecke | SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); |
106 | 5c6c0e51 | Hannes Reinecke | |
107 | 5c6c0e51 | Hannes Reinecke | DPRINTF("Cancel tag=0x%x\n", req->tag);
|
108 | 5c6c0e51 | Hannes Reinecke | if (r->req.aiocb) {
|
109 | 5c6c0e51 | Hannes Reinecke | bdrv_aio_cancel(r->req.aiocb); |
110 | c7bae6a7 | Paolo Bonzini | |
111 | c7bae6a7 | Paolo Bonzini | /* This reference was left in by scsi_*_data. We take ownership of
|
112 | c7bae6a7 | Paolo Bonzini | * it the moment scsi_req_cancel is called, independent of whether
|
113 | c7bae6a7 | Paolo Bonzini | * bdrv_aio_cancel completes the request or not. */
|
114 | c7bae6a7 | Paolo Bonzini | scsi_req_unref(&r->req); |
115 | a917d384 | pbrook | } |
116 | 5c6c0e51 | Hannes Reinecke | r->req.aiocb = NULL;
|
117 | a917d384 | pbrook | } |
118 | a917d384 | pbrook | |
119 | 43b978b9 | Paolo Bonzini | static uint32_t scsi_init_iovec(SCSIDiskReq *r, size_t size)
|
120 | 103b40f5 | Paolo Bonzini | { |
121 | 7285477a | Paolo Bonzini | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); |
122 | 7285477a | Paolo Bonzini | |
123 | 7285477a | Paolo Bonzini | if (!r->iov.iov_base) {
|
124 | 43b978b9 | Paolo Bonzini | r->buflen = size; |
125 | 44740c38 | Paolo Bonzini | r->iov.iov_base = qemu_blockalign(s->qdev.conf.bs, r->buflen); |
126 | 7285477a | Paolo Bonzini | } |
127 | 7285477a | Paolo Bonzini | r->iov.iov_len = MIN(r->sector_count * 512, r->buflen);
|
128 | 103b40f5 | Paolo Bonzini | qemu_iovec_init_external(&r->qiov, &r->iov, 1);
|
129 | 103b40f5 | Paolo Bonzini | return r->qiov.size / 512; |
130 | 103b40f5 | Paolo Bonzini | } |
131 | 103b40f5 | Paolo Bonzini | |
132 | 43b978b9 | Paolo Bonzini | static void scsi_disk_save_request(QEMUFile *f, SCSIRequest *req) |
133 | 43b978b9 | Paolo Bonzini | { |
134 | 43b978b9 | Paolo Bonzini | SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); |
135 | 43b978b9 | Paolo Bonzini | |
136 | 43b978b9 | Paolo Bonzini | qemu_put_be64s(f, &r->sector); |
137 | 43b978b9 | Paolo Bonzini | qemu_put_be32s(f, &r->sector_count); |
138 | 43b978b9 | Paolo Bonzini | qemu_put_be32s(f, &r->buflen); |
139 | 18eef3bc | Gerd Hoffmann | if (r->buflen) {
|
140 | 18eef3bc | Gerd Hoffmann | if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
|
141 | 18eef3bc | Gerd Hoffmann | qemu_put_buffer(f, r->iov.iov_base, r->iov.iov_len); |
142 | 18eef3bc | Gerd Hoffmann | } else if (!req->retry) { |
143 | 18eef3bc | Gerd Hoffmann | uint32_t len = r->iov.iov_len; |
144 | 18eef3bc | Gerd Hoffmann | qemu_put_be32s(f, &len); |
145 | 18eef3bc | Gerd Hoffmann | qemu_put_buffer(f, r->iov.iov_base, r->iov.iov_len); |
146 | 18eef3bc | Gerd Hoffmann | } |
147 | 43b978b9 | Paolo Bonzini | } |
148 | 43b978b9 | Paolo Bonzini | } |
149 | 43b978b9 | Paolo Bonzini | |
150 | 43b978b9 | Paolo Bonzini | static void scsi_disk_load_request(QEMUFile *f, SCSIRequest *req) |
151 | 43b978b9 | Paolo Bonzini | { |
152 | 43b978b9 | Paolo Bonzini | SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); |
153 | 43b978b9 | Paolo Bonzini | |
154 | 43b978b9 | Paolo Bonzini | qemu_get_be64s(f, &r->sector); |
155 | 43b978b9 | Paolo Bonzini | qemu_get_be32s(f, &r->sector_count); |
156 | 43b978b9 | Paolo Bonzini | qemu_get_be32s(f, &r->buflen); |
157 | 43b978b9 | Paolo Bonzini | if (r->buflen) {
|
158 | 43b978b9 | Paolo Bonzini | scsi_init_iovec(r, r->buflen); |
159 | 43b978b9 | Paolo Bonzini | if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
|
160 | 43b978b9 | Paolo Bonzini | qemu_get_buffer(f, r->iov.iov_base, r->iov.iov_len); |
161 | 18eef3bc | Gerd Hoffmann | } else if (!r->req.retry) { |
162 | 18eef3bc | Gerd Hoffmann | uint32_t len; |
163 | 18eef3bc | Gerd Hoffmann | qemu_get_be32s(f, &len); |
164 | 18eef3bc | Gerd Hoffmann | r->iov.iov_len = len; |
165 | 18eef3bc | Gerd Hoffmann | assert(r->iov.iov_len <= r->buflen); |
166 | 18eef3bc | Gerd Hoffmann | qemu_get_buffer(f, r->iov.iov_base, r->iov.iov_len); |
167 | 43b978b9 | Paolo Bonzini | } |
168 | 43b978b9 | Paolo Bonzini | } |
169 | 43b978b9 | Paolo Bonzini | |
170 | 43b978b9 | Paolo Bonzini | qemu_iovec_init_external(&r->qiov, &r->iov, 1);
|
171 | 43b978b9 | Paolo Bonzini | } |
172 | 43b978b9 | Paolo Bonzini | |
173 | c1b35247 | Paolo Bonzini | static void scsi_aio_complete(void *opaque, int ret) |
174 | 5d0d2467 | Paolo Bonzini | { |
175 | 5d0d2467 | Paolo Bonzini | SCSIDiskReq *r = (SCSIDiskReq *)opaque; |
176 | 5d0d2467 | Paolo Bonzini | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); |
177 | 5d0d2467 | Paolo Bonzini | |
178 | 46e3f30e | Paolo Bonzini | assert(r->req.aiocb != NULL);
|
179 | 46e3f30e | Paolo Bonzini | r->req.aiocb = NULL;
|
180 | 5d0d2467 | Paolo Bonzini | bdrv_acct_done(s->qdev.conf.bs, &r->acct); |
181 | 5d0d2467 | Paolo Bonzini | |
182 | 80624c93 | Paolo Bonzini | if (ret < 0) { |
183 | 5d0d2467 | Paolo Bonzini | if (scsi_handle_rw_error(r, -ret)) {
|
184 | 5d0d2467 | Paolo Bonzini | goto done;
|
185 | 5d0d2467 | Paolo Bonzini | } |
186 | 5d0d2467 | Paolo Bonzini | } |
187 | 5d0d2467 | Paolo Bonzini | |
188 | 5d0d2467 | Paolo Bonzini | scsi_req_complete(&r->req, GOOD); |
189 | 5d0d2467 | Paolo Bonzini | |
190 | 5d0d2467 | Paolo Bonzini | done:
|
191 | b8aba8d7 | Paolo Bonzini | if (!r->req.io_canceled) {
|
192 | b8aba8d7 | Paolo Bonzini | scsi_req_unref(&r->req); |
193 | b8aba8d7 | Paolo Bonzini | } |
194 | 5d0d2467 | Paolo Bonzini | } |
195 | 5d0d2467 | Paolo Bonzini | |
196 | 7e8c49c5 | Paolo Bonzini | static bool scsi_is_cmd_fua(SCSICommand *cmd) |
197 | 7e8c49c5 | Paolo Bonzini | { |
198 | 7e8c49c5 | Paolo Bonzini | switch (cmd->buf[0]) { |
199 | 7e8c49c5 | Paolo Bonzini | case READ_10:
|
200 | 7e8c49c5 | Paolo Bonzini | case READ_12:
|
201 | 7e8c49c5 | Paolo Bonzini | case READ_16:
|
202 | 7e8c49c5 | Paolo Bonzini | case WRITE_10:
|
203 | 7e8c49c5 | Paolo Bonzini | case WRITE_12:
|
204 | 7e8c49c5 | Paolo Bonzini | case WRITE_16:
|
205 | 7e8c49c5 | Paolo Bonzini | return (cmd->buf[1] & 8) != 0; |
206 | 7e8c49c5 | Paolo Bonzini | |
207 | 7f64f8e2 | Paolo Bonzini | case VERIFY_10:
|
208 | 7f64f8e2 | Paolo Bonzini | case VERIFY_12:
|
209 | 7f64f8e2 | Paolo Bonzini | case VERIFY_16:
|
210 | 7e8c49c5 | Paolo Bonzini | case WRITE_VERIFY_10:
|
211 | 7e8c49c5 | Paolo Bonzini | case WRITE_VERIFY_12:
|
212 | 7e8c49c5 | Paolo Bonzini | case WRITE_VERIFY_16:
|
213 | 7e8c49c5 | Paolo Bonzini | return true; |
214 | 7e8c49c5 | Paolo Bonzini | |
215 | 7e8c49c5 | Paolo Bonzini | case READ_6:
|
216 | 7e8c49c5 | Paolo Bonzini | case WRITE_6:
|
217 | 7e8c49c5 | Paolo Bonzini | default:
|
218 | 7e8c49c5 | Paolo Bonzini | return false; |
219 | 7e8c49c5 | Paolo Bonzini | } |
220 | 7e8c49c5 | Paolo Bonzini | } |
221 | 7e8c49c5 | Paolo Bonzini | |
222 | 7e8c49c5 | Paolo Bonzini | static void scsi_write_do_fua(SCSIDiskReq *r) |
223 | 7e8c49c5 | Paolo Bonzini | { |
224 | 7e8c49c5 | Paolo Bonzini | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); |
225 | 7e8c49c5 | Paolo Bonzini | |
226 | 7e8c49c5 | Paolo Bonzini | if (scsi_is_cmd_fua(&r->req.cmd)) {
|
227 | 7e8c49c5 | Paolo Bonzini | bdrv_acct_start(s->qdev.conf.bs, &r->acct, 0, BDRV_ACCT_FLUSH);
|
228 | c1b35247 | Paolo Bonzini | r->req.aiocb = bdrv_aio_flush(s->qdev.conf.bs, scsi_aio_complete, r); |
229 | 7e8c49c5 | Paolo Bonzini | return;
|
230 | 7e8c49c5 | Paolo Bonzini | } |
231 | 7e8c49c5 | Paolo Bonzini | |
232 | 7e8c49c5 | Paolo Bonzini | scsi_req_complete(&r->req, GOOD); |
233 | 7e8c49c5 | Paolo Bonzini | if (!r->req.io_canceled) {
|
234 | 7e8c49c5 | Paolo Bonzini | scsi_req_unref(&r->req); |
235 | 7e8c49c5 | Paolo Bonzini | } |
236 | 7e8c49c5 | Paolo Bonzini | } |
237 | 7e8c49c5 | Paolo Bonzini | |
238 | b77912a7 | Paolo Bonzini | static void scsi_dma_complete(void *opaque, int ret) |
239 | a917d384 | pbrook | { |
240 | 4c41d2ef | Gerd Hoffmann | SCSIDiskReq *r = (SCSIDiskReq *)opaque; |
241 | a597e79c | Christoph Hellwig | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); |
242 | a917d384 | pbrook | |
243 | 46e3f30e | Paolo Bonzini | assert(r->req.aiocb != NULL);
|
244 | 46e3f30e | Paolo Bonzini | r->req.aiocb = NULL;
|
245 | 46e3f30e | Paolo Bonzini | bdrv_acct_done(s->qdev.conf.bs, &r->acct); |
246 | a597e79c | Christoph Hellwig | |
247 | 80624c93 | Paolo Bonzini | if (ret < 0) { |
248 | 71544d30 | Paolo Bonzini | if (scsi_handle_rw_error(r, -ret)) {
|
249 | c7bae6a7 | Paolo Bonzini | goto done;
|
250 | 5dba48a8 | Kevin Wolf | } |
251 | 4d611c9a | pbrook | } |
252 | 5dba48a8 | Kevin Wolf | |
253 | b77912a7 | Paolo Bonzini | r->sector += r->sector_count; |
254 | b77912a7 | Paolo Bonzini | r->sector_count = 0;
|
255 | 7e8c49c5 | Paolo Bonzini | if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
|
256 | 7e8c49c5 | Paolo Bonzini | scsi_write_do_fua(r); |
257 | 7e8c49c5 | Paolo Bonzini | return;
|
258 | 7e8c49c5 | Paolo Bonzini | } else {
|
259 | 7e8c49c5 | Paolo Bonzini | scsi_req_complete(&r->req, GOOD); |
260 | 7e8c49c5 | Paolo Bonzini | } |
261 | c7bae6a7 | Paolo Bonzini | |
262 | c7bae6a7 | Paolo Bonzini | done:
|
263 | c7bae6a7 | Paolo Bonzini | if (!r->req.io_canceled) {
|
264 | c7bae6a7 | Paolo Bonzini | scsi_req_unref(&r->req); |
265 | c7bae6a7 | Paolo Bonzini | } |
266 | 4d611c9a | pbrook | } |
267 | 4d611c9a | pbrook | |
268 | b77912a7 | Paolo Bonzini | static void scsi_read_complete(void * opaque, int ret) |
269 | 0a4ac106 | Paolo Bonzini | { |
270 | 0a4ac106 | Paolo Bonzini | SCSIDiskReq *r = (SCSIDiskReq *)opaque; |
271 | 0a4ac106 | Paolo Bonzini | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); |
272 | b77912a7 | Paolo Bonzini | int n;
|
273 | 0a4ac106 | Paolo Bonzini | |
274 | 46e3f30e | Paolo Bonzini | assert(r->req.aiocb != NULL);
|
275 | 46e3f30e | Paolo Bonzini | r->req.aiocb = NULL;
|
276 | 46e3f30e | Paolo Bonzini | bdrv_acct_done(s->qdev.conf.bs, &r->acct); |
277 | 0a4ac106 | Paolo Bonzini | |
278 | 0a4ac106 | Paolo Bonzini | if (ret < 0) { |
279 | 71544d30 | Paolo Bonzini | if (scsi_handle_rw_error(r, -ret)) {
|
280 | c7bae6a7 | Paolo Bonzini | goto done;
|
281 | 0a4ac106 | Paolo Bonzini | } |
282 | 0a4ac106 | Paolo Bonzini | } |
283 | 0a4ac106 | Paolo Bonzini | |
284 | b77912a7 | Paolo Bonzini | DPRINTF("Data ready tag=0x%x len=%zd\n", r->req.tag, r->qiov.size);
|
285 | b77912a7 | Paolo Bonzini | |
286 | b77912a7 | Paolo Bonzini | n = r->qiov.size / 512;
|
287 | b77912a7 | Paolo Bonzini | r->sector += n; |
288 | b77912a7 | Paolo Bonzini | r->sector_count -= n; |
289 | b77912a7 | Paolo Bonzini | scsi_req_data(&r->req, r->qiov.size); |
290 | c7bae6a7 | Paolo Bonzini | |
291 | c7bae6a7 | Paolo Bonzini | done:
|
292 | c7bae6a7 | Paolo Bonzini | if (!r->req.io_canceled) {
|
293 | c7bae6a7 | Paolo Bonzini | scsi_req_unref(&r->req); |
294 | c7bae6a7 | Paolo Bonzini | } |
295 | 0a4ac106 | Paolo Bonzini | } |
296 | 5dba48a8 | Kevin Wolf | |
297 | ac668426 | Paolo Bonzini | /* Actually issue a read to the block device. */
|
298 | ac668426 | Paolo Bonzini | static void scsi_do_read(void *opaque, int ret) |
299 | ac668426 | Paolo Bonzini | { |
300 | ac668426 | Paolo Bonzini | SCSIDiskReq *r = opaque; |
301 | ac668426 | Paolo Bonzini | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); |
302 | ac668426 | Paolo Bonzini | uint32_t n; |
303 | ac668426 | Paolo Bonzini | |
304 | ac668426 | Paolo Bonzini | if (r->req.aiocb != NULL) { |
305 | ac668426 | Paolo Bonzini | r->req.aiocb = NULL;
|
306 | ac668426 | Paolo Bonzini | bdrv_acct_done(s->qdev.conf.bs, &r->acct); |
307 | ac668426 | Paolo Bonzini | } |
308 | ac668426 | Paolo Bonzini | |
309 | ac668426 | Paolo Bonzini | if (ret < 0) { |
310 | ac668426 | Paolo Bonzini | if (scsi_handle_rw_error(r, -ret)) {
|
311 | ac668426 | Paolo Bonzini | goto done;
|
312 | ac668426 | Paolo Bonzini | } |
313 | ac668426 | Paolo Bonzini | } |
314 | ac668426 | Paolo Bonzini | |
315 | 31e8fd86 | Paolo Bonzini | if (r->req.io_canceled) {
|
316 | 31e8fd86 | Paolo Bonzini | return;
|
317 | 31e8fd86 | Paolo Bonzini | } |
318 | 31e8fd86 | Paolo Bonzini | |
319 | 31e8fd86 | Paolo Bonzini | /* The request is used as the AIO opaque value, so add a ref. */
|
320 | 31e8fd86 | Paolo Bonzini | scsi_req_ref(&r->req); |
321 | 31e8fd86 | Paolo Bonzini | |
322 | ac668426 | Paolo Bonzini | if (r->req.sg) {
|
323 | ac668426 | Paolo Bonzini | dma_acct_start(s->qdev.conf.bs, &r->acct, r->req.sg, BDRV_ACCT_READ); |
324 | ac668426 | Paolo Bonzini | r->req.resid -= r->req.sg->size; |
325 | ac668426 | Paolo Bonzini | r->req.aiocb = dma_bdrv_read(s->qdev.conf.bs, r->req.sg, r->sector, |
326 | ac668426 | Paolo Bonzini | scsi_dma_complete, r); |
327 | ac668426 | Paolo Bonzini | } else {
|
328 | ac668426 | Paolo Bonzini | n = scsi_init_iovec(r, SCSI_DMA_BUF_SIZE); |
329 | ac668426 | Paolo Bonzini | bdrv_acct_start(s->qdev.conf.bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ); |
330 | ac668426 | Paolo Bonzini | r->req.aiocb = bdrv_aio_readv(s->qdev.conf.bs, r->sector, &r->qiov, n, |
331 | ac668426 | Paolo Bonzini | scsi_read_complete, r); |
332 | ac668426 | Paolo Bonzini | } |
333 | ac668426 | Paolo Bonzini | |
334 | ac668426 | Paolo Bonzini | done:
|
335 | ac668426 | Paolo Bonzini | if (!r->req.io_canceled) {
|
336 | ac668426 | Paolo Bonzini | scsi_req_unref(&r->req); |
337 | ac668426 | Paolo Bonzini | } |
338 | ac668426 | Paolo Bonzini | } |
339 | ac668426 | Paolo Bonzini | |
340 | 5c6c0e51 | Hannes Reinecke | /* Read more data from scsi device into buffer. */
|
341 | 5c6c0e51 | Hannes Reinecke | static void scsi_read_data(SCSIRequest *req) |
342 | 2e5d83bb | pbrook | { |
343 | 5c6c0e51 | Hannes Reinecke | SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); |
344 | 5dba48a8 | Kevin Wolf | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); |
345 | ac668426 | Paolo Bonzini | bool first;
|
346 | 2e5d83bb | pbrook | |
347 | a917d384 | pbrook | DPRINTF("Read sector_count=%d\n", r->sector_count);
|
348 | a917d384 | pbrook | if (r->sector_count == 0) { |
349 | b45ef674 | Paolo Bonzini | /* This also clears the sense buffer for REQUEST SENSE. */
|
350 | b45ef674 | Paolo Bonzini | scsi_req_complete(&r->req, GOOD); |
351 | a917d384 | pbrook | return;
|
352 | 2e5d83bb | pbrook | } |
353 | 2e5d83bb | pbrook | |
354 | 6fa2c95f | Stefan Hajnoczi | /* No data transfer may already be in progress */
|
355 | 6fa2c95f | Stefan Hajnoczi | assert(r->req.aiocb == NULL);
|
356 | 6fa2c95f | Stefan Hajnoczi | |
357 | c7bae6a7 | Paolo Bonzini | /* The request is used as the AIO opaque value, so add a ref. */
|
358 | c7bae6a7 | Paolo Bonzini | scsi_req_ref(&r->req); |
359 | efb9ee02 | Hannes Reinecke | if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
|
360 | efb9ee02 | Hannes Reinecke | DPRINTF("Data transfer direction invalid\n");
|
361 | efb9ee02 | Hannes Reinecke | scsi_read_complete(r, -EINVAL); |
362 | efb9ee02 | Hannes Reinecke | return;
|
363 | efb9ee02 | Hannes Reinecke | } |
364 | efb9ee02 | Hannes Reinecke | |
365 | a1aff5bf | Markus Armbruster | if (s->tray_open) {
|
366 | a1aff5bf | Markus Armbruster | scsi_read_complete(r, -ENOMEDIUM); |
367 | c7bae6a7 | Paolo Bonzini | return;
|
368 | a1aff5bf | Markus Armbruster | } |
369 | c7bae6a7 | Paolo Bonzini | |
370 | ac668426 | Paolo Bonzini | first = !r->started; |
371 | a0e66a69 | Paolo Bonzini | r->started = true;
|
372 | ac668426 | Paolo Bonzini | if (first && scsi_is_cmd_fua(&r->req.cmd)) {
|
373 | ac668426 | Paolo Bonzini | bdrv_acct_start(s->qdev.conf.bs, &r->acct, 0, BDRV_ACCT_FLUSH);
|
374 | ac668426 | Paolo Bonzini | r->req.aiocb = bdrv_aio_flush(s->qdev.conf.bs, scsi_do_read, r); |
375 | 5d0d2467 | Paolo Bonzini | } else {
|
376 | ac668426 | Paolo Bonzini | scsi_do_read(r, 0);
|
377 | 5d0d2467 | Paolo Bonzini | } |
378 | 2e5d83bb | pbrook | } |
379 | 2e5d83bb | pbrook | |
380 | c7bae6a7 | Paolo Bonzini | /*
|
381 | c7bae6a7 | Paolo Bonzini | * scsi_handle_rw_error has two return values. 0 means that the error
|
382 | c7bae6a7 | Paolo Bonzini | * must be ignored, 1 means that the error has been processed and the
|
383 | c7bae6a7 | Paolo Bonzini | * caller should not do anything else for this request. Note that
|
384 | c7bae6a7 | Paolo Bonzini | * scsi_handle_rw_error always manages its reference counts, independent
|
385 | c7bae6a7 | Paolo Bonzini | * of the return value.
|
386 | c7bae6a7 | Paolo Bonzini | */
|
387 | 71544d30 | Paolo Bonzini | static int scsi_handle_rw_error(SCSIDiskReq *r, int error) |
388 | 5dba48a8 | Kevin Wolf | { |
389 | 1ceee0d5 | Paolo Bonzini | bool is_read = (r->req.cmd.xfer == SCSI_XFER_FROM_DEV);
|
390 | 4c41d2ef | Gerd Hoffmann | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); |
391 | 3e1caa5f | Paolo Bonzini | BlockErrorAction action = bdrv_get_error_action(s->qdev.conf.bs, is_read, error); |
392 | ea8a5d7f | aliguori | |
393 | 3e1caa5f | Paolo Bonzini | if (action == BDRV_ACTION_REPORT) {
|
394 | efb9ee02 | Hannes Reinecke | switch (error) {
|
395 | 7e218df5 | Paolo Bonzini | case ENOMEDIUM:
|
396 | 7e218df5 | Paolo Bonzini | scsi_check_condition(r, SENSE_CODE(NO_MEDIUM)); |
397 | 7e218df5 | Paolo Bonzini | break;
|
398 | efb9ee02 | Hannes Reinecke | case ENOMEM:
|
399 | b45ef674 | Paolo Bonzini | scsi_check_condition(r, SENSE_CODE(TARGET_FAILURE)); |
400 | efb9ee02 | Hannes Reinecke | break;
|
401 | efb9ee02 | Hannes Reinecke | case EINVAL:
|
402 | b45ef674 | Paolo Bonzini | scsi_check_condition(r, SENSE_CODE(INVALID_FIELD)); |
403 | efb9ee02 | Hannes Reinecke | break;
|
404 | efb9ee02 | Hannes Reinecke | default:
|
405 | b45ef674 | Paolo Bonzini | scsi_check_condition(r, SENSE_CODE(IO_ERROR)); |
406 | efb9ee02 | Hannes Reinecke | break;
|
407 | a1f0cce2 | Hannes Reinecke | } |
408 | ea8a5d7f | aliguori | } |
409 | 3e1caa5f | Paolo Bonzini | bdrv_error_action(s->qdev.conf.bs, action, is_read, error); |
410 | 3e1caa5f | Paolo Bonzini | if (action == BDRV_ACTION_STOP) {
|
411 | 3e1caa5f | Paolo Bonzini | scsi_req_retry(&r->req); |
412 | 3e1caa5f | Paolo Bonzini | } |
413 | 3e1caa5f | Paolo Bonzini | return action != BDRV_ACTION_IGNORE;
|
414 | ea8a5d7f | aliguori | } |
415 | ea8a5d7f | aliguori | |
416 | 4d611c9a | pbrook | static void scsi_write_complete(void * opaque, int ret) |
417 | 4d611c9a | pbrook | { |
418 | 4c41d2ef | Gerd Hoffmann | SCSIDiskReq *r = (SCSIDiskReq *)opaque; |
419 | a597e79c | Christoph Hellwig | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); |
420 | ea8a5d7f | aliguori | uint32_t n; |
421 | ea8a5d7f | aliguori | |
422 | 8e321cc6 | Paolo Bonzini | if (r->req.aiocb != NULL) { |
423 | 8e321cc6 | Paolo Bonzini | r->req.aiocb = NULL;
|
424 | 44740c38 | Paolo Bonzini | bdrv_acct_done(s->qdev.conf.bs, &r->acct); |
425 | 8e321cc6 | Paolo Bonzini | } |
426 | a597e79c | Christoph Hellwig | |
427 | 80624c93 | Paolo Bonzini | if (ret < 0) { |
428 | 71544d30 | Paolo Bonzini | if (scsi_handle_rw_error(r, -ret)) {
|
429 | c7bae6a7 | Paolo Bonzini | goto done;
|
430 | 5dba48a8 | Kevin Wolf | } |
431 | 4d611c9a | pbrook | } |
432 | 4d611c9a | pbrook | |
433 | 103b40f5 | Paolo Bonzini | n = r->qiov.size / 512;
|
434 | ea8a5d7f | aliguori | r->sector += n; |
435 | ea8a5d7f | aliguori | r->sector_count -= n; |
436 | a917d384 | pbrook | if (r->sector_count == 0) { |
437 | 7e8c49c5 | Paolo Bonzini | scsi_write_do_fua(r); |
438 | 7e8c49c5 | Paolo Bonzini | return;
|
439 | a917d384 | pbrook | } else {
|
440 | 43b978b9 | Paolo Bonzini | scsi_init_iovec(r, SCSI_DMA_BUF_SIZE); |
441 | 79fb50bb | Paolo Bonzini | DPRINTF("Write complete tag=0x%x more=%zd\n", r->req.tag, r->qiov.size);
|
442 | 103b40f5 | Paolo Bonzini | scsi_req_data(&r->req, r->qiov.size); |
443 | 4d611c9a | pbrook | } |
444 | c7bae6a7 | Paolo Bonzini | |
445 | c7bae6a7 | Paolo Bonzini | done:
|
446 | c7bae6a7 | Paolo Bonzini | if (!r->req.io_canceled) {
|
447 | c7bae6a7 | Paolo Bonzini | scsi_req_unref(&r->req); |
448 | c7bae6a7 | Paolo Bonzini | } |
449 | 4d611c9a | pbrook | } |
450 | 4d611c9a | pbrook | |
451 | 42741212 | Paolo Bonzini | static void scsi_write_data(SCSIRequest *req) |
452 | ea8a5d7f | aliguori | { |
453 | 5c6c0e51 | Hannes Reinecke | SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); |
454 | 4c41d2ef | Gerd Hoffmann | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); |
455 | ea8a5d7f | aliguori | uint32_t n; |
456 | ea8a5d7f | aliguori | |
457 | 6fa2c95f | Stefan Hajnoczi | /* No data transfer may already be in progress */
|
458 | 6fa2c95f | Stefan Hajnoczi | assert(r->req.aiocb == NULL);
|
459 | 6fa2c95f | Stefan Hajnoczi | |
460 | c7bae6a7 | Paolo Bonzini | /* The request is used as the AIO opaque value, so add a ref. */
|
461 | c7bae6a7 | Paolo Bonzini | scsi_req_ref(&r->req); |
462 | efb9ee02 | Hannes Reinecke | if (r->req.cmd.mode != SCSI_XFER_TO_DEV) {
|
463 | efb9ee02 | Hannes Reinecke | DPRINTF("Data transfer direction invalid\n");
|
464 | efb9ee02 | Hannes Reinecke | scsi_write_complete(r, -EINVAL); |
465 | 42741212 | Paolo Bonzini | return;
|
466 | efb9ee02 | Hannes Reinecke | } |
467 | efb9ee02 | Hannes Reinecke | |
468 | 5d0d2467 | Paolo Bonzini | if (!r->req.sg && !r->qiov.size) {
|
469 | 5d0d2467 | Paolo Bonzini | /* Called for the first time. Ask the driver to send us more data. */
|
470 | a0e66a69 | Paolo Bonzini | r->started = true;
|
471 | 5d0d2467 | Paolo Bonzini | scsi_write_complete(r, 0);
|
472 | 5d0d2467 | Paolo Bonzini | return;
|
473 | 5d0d2467 | Paolo Bonzini | } |
474 | 5d0d2467 | Paolo Bonzini | if (s->tray_open) {
|
475 | 5d0d2467 | Paolo Bonzini | scsi_write_complete(r, -ENOMEDIUM); |
476 | 5d0d2467 | Paolo Bonzini | return;
|
477 | 5d0d2467 | Paolo Bonzini | } |
478 | 5d0d2467 | Paolo Bonzini | |
479 | 7f64f8e2 | Paolo Bonzini | if (r->req.cmd.buf[0] == VERIFY_10 || r->req.cmd.buf[0] == VERIFY_12 || |
480 | 7f64f8e2 | Paolo Bonzini | r->req.cmd.buf[0] == VERIFY_16) {
|
481 | 7f64f8e2 | Paolo Bonzini | if (r->req.sg) {
|
482 | 7f64f8e2 | Paolo Bonzini | scsi_dma_complete(r, 0);
|
483 | 7f64f8e2 | Paolo Bonzini | } else {
|
484 | 7f64f8e2 | Paolo Bonzini | scsi_write_complete(r, 0);
|
485 | 7f64f8e2 | Paolo Bonzini | } |
486 | 7f64f8e2 | Paolo Bonzini | return;
|
487 | 7f64f8e2 | Paolo Bonzini | } |
488 | 7f64f8e2 | Paolo Bonzini | |
489 | 5d0d2467 | Paolo Bonzini | if (r->req.sg) {
|
490 | 5d0d2467 | Paolo Bonzini | dma_acct_start(s->qdev.conf.bs, &r->acct, r->req.sg, BDRV_ACCT_WRITE); |
491 | 5d0d2467 | Paolo Bonzini | r->req.resid -= r->req.sg->size; |
492 | 5d0d2467 | Paolo Bonzini | r->req.aiocb = dma_bdrv_write(s->qdev.conf.bs, r->req.sg, r->sector, |
493 | 5d0d2467 | Paolo Bonzini | scsi_dma_complete, r); |
494 | 5d0d2467 | Paolo Bonzini | } else {
|
495 | 5d0d2467 | Paolo Bonzini | n = r->qiov.size / 512;
|
496 | 44740c38 | Paolo Bonzini | bdrv_acct_start(s->qdev.conf.bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_WRITE); |
497 | 44740c38 | Paolo Bonzini | r->req.aiocb = bdrv_aio_writev(s->qdev.conf.bs, r->sector, &r->qiov, n, |
498 | 103b40f5 | Paolo Bonzini | scsi_write_complete, r); |
499 | ea8a5d7f | aliguori | } |
500 | a917d384 | pbrook | } |
501 | 2e5d83bb | pbrook | |
502 | a917d384 | pbrook | /* Return a pointer to the data buffer. */
|
503 | 5c6c0e51 | Hannes Reinecke | static uint8_t *scsi_get_buf(SCSIRequest *req)
|
504 | a917d384 | pbrook | { |
505 | 5c6c0e51 | Hannes Reinecke | SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); |
506 | 2e5d83bb | pbrook | |
507 | 3f4cb3d3 | blueswir1 | return (uint8_t *)r->iov.iov_base;
|
508 | 2e5d83bb | pbrook | } |
509 | 2e5d83bb | pbrook | |
510 | 0b06c059 | Gerd Hoffmann | static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) |
511 | 0b06c059 | Gerd Hoffmann | { |
512 | 383b4d9b | Gerd Hoffmann | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); |
513 | 0b06c059 | Gerd Hoffmann | int buflen = 0; |
514 | 82579390 | Paolo Bonzini | int start;
|
515 | 0b06c059 | Gerd Hoffmann | |
516 | 0b06c059 | Gerd Hoffmann | if (req->cmd.buf[1] & 0x1) { |
517 | 0b06c059 | Gerd Hoffmann | /* Vital product data */
|
518 | 0b06c059 | Gerd Hoffmann | uint8_t page_code = req->cmd.buf[2];
|
519 | 0b06c059 | Gerd Hoffmann | |
520 | e39be482 | Paolo Bonzini | outbuf[buflen++] = s->qdev.type & 0x1f;
|
521 | 0b06c059 | Gerd Hoffmann | outbuf[buflen++] = page_code ; // this page
|
522 | 0b06c059 | Gerd Hoffmann | outbuf[buflen++] = 0x00;
|
523 | 82579390 | Paolo Bonzini | outbuf[buflen++] = 0x00;
|
524 | 82579390 | Paolo Bonzini | start = buflen; |
525 | 0b06c059 | Gerd Hoffmann | |
526 | 0b06c059 | Gerd Hoffmann | switch (page_code) {
|
527 | 0b06c059 | Gerd Hoffmann | case 0x00: /* Supported page codes, mandatory */ |
528 | 39d98982 | Hannes Reinecke | { |
529 | 0b06c059 | Gerd Hoffmann | DPRINTF("Inquiry EVPD[Supported pages] "
|
530 | 0b06c059 | Gerd Hoffmann | "buffer size %zd\n", req->cmd.xfer);
|
531 | 0b06c059 | Gerd Hoffmann | outbuf[buflen++] = 0x00; // list of supported pages (this page) |
532 | f01b5931 | Paolo Bonzini | if (s->serial) {
|
533 | 3e1c0c9a | Hannes Reinecke | outbuf[buflen++] = 0x80; // unit serial number |
534 | f01b5931 | Paolo Bonzini | } |
535 | 0b06c059 | Gerd Hoffmann | outbuf[buflen++] = 0x83; // device identification |
536 | f37bd73b | Hannes Reinecke | if (s->qdev.type == TYPE_DISK) {
|
537 | ea3bd56f | Christoph Hellwig | outbuf[buflen++] = 0xb0; // block limits |
538 | ea3bd56f | Christoph Hellwig | outbuf[buflen++] = 0xb2; // thin provisioning |
539 | 39d98982 | Hannes Reinecke | } |
540 | 0b06c059 | Gerd Hoffmann | break;
|
541 | 39d98982 | Hannes Reinecke | } |
542 | 0b06c059 | Gerd Hoffmann | case 0x80: /* Device serial number, optional */ |
543 | 0b06c059 | Gerd Hoffmann | { |
544 | 3e1c0c9a | Hannes Reinecke | int l;
|
545 | 0b06c059 | Gerd Hoffmann | |
546 | 3e1c0c9a | Hannes Reinecke | if (!s->serial) {
|
547 | 3e1c0c9a | Hannes Reinecke | DPRINTF("Inquiry (EVPD[Serial number] not supported\n");
|
548 | 3e1c0c9a | Hannes Reinecke | return -1; |
549 | 3e1c0c9a | Hannes Reinecke | } |
550 | 3e1c0c9a | Hannes Reinecke | |
551 | 3e1c0c9a | Hannes Reinecke | l = strlen(s->serial); |
552 | f01b5931 | Paolo Bonzini | if (l > 20) { |
553 | 0b06c059 | Gerd Hoffmann | l = 20;
|
554 | f01b5931 | Paolo Bonzini | } |
555 | 0b06c059 | Gerd Hoffmann | |
556 | 0b06c059 | Gerd Hoffmann | DPRINTF("Inquiry EVPD[Serial number] "
|
557 | 0b06c059 | Gerd Hoffmann | "buffer size %zd\n", req->cmd.xfer);
|
558 | a0fef654 | Markus Armbruster | memcpy(outbuf+buflen, s->serial, l); |
559 | 0b06c059 | Gerd Hoffmann | buflen += l; |
560 | 0b06c059 | Gerd Hoffmann | break;
|
561 | 0b06c059 | Gerd Hoffmann | } |
562 | 0b06c059 | Gerd Hoffmann | |
563 | 0b06c059 | Gerd Hoffmann | case 0x83: /* Device identification page, mandatory */ |
564 | 0b06c059 | Gerd Hoffmann | { |
565 | fd930791 | Paolo Bonzini | const char *str = s->serial ?: bdrv_get_device_name(s->qdev.conf.bs); |
566 | fd930791 | Paolo Bonzini | int max_len = s->serial ? 20 : 255 - 8; |
567 | fd930791 | Paolo Bonzini | int id_len = strlen(str);
|
568 | 0b06c059 | Gerd Hoffmann | |
569 | f01b5931 | Paolo Bonzini | if (id_len > max_len) {
|
570 | 0b06c059 | Gerd Hoffmann | id_len = max_len; |
571 | f01b5931 | Paolo Bonzini | } |
572 | 0b06c059 | Gerd Hoffmann | DPRINTF("Inquiry EVPD[Device identification] "
|
573 | 0b06c059 | Gerd Hoffmann | "buffer size %zd\n", req->cmd.xfer);
|
574 | 0b06c059 | Gerd Hoffmann | |
575 | 0b06c059 | Gerd Hoffmann | outbuf[buflen++] = 0x2; // ASCII |
576 | 0b06c059 | Gerd Hoffmann | outbuf[buflen++] = 0; // not officially assigned |
577 | 0b06c059 | Gerd Hoffmann | outbuf[buflen++] = 0; // reserved |
578 | 0b06c059 | Gerd Hoffmann | outbuf[buflen++] = id_len; // length of data following
|
579 | fd930791 | Paolo Bonzini | memcpy(outbuf+buflen, str, id_len); |
580 | 0b06c059 | Gerd Hoffmann | buflen += id_len; |
581 | 27395add | Paolo Bonzini | |
582 | 27395add | Paolo Bonzini | if (s->wwn) {
|
583 | 27395add | Paolo Bonzini | outbuf[buflen++] = 0x1; // Binary |
584 | 27395add | Paolo Bonzini | outbuf[buflen++] = 0x3; // NAA |
585 | 27395add | Paolo Bonzini | outbuf[buflen++] = 0; // reserved |
586 | 27395add | Paolo Bonzini | outbuf[buflen++] = 8;
|
587 | 27395add | Paolo Bonzini | stq_be_p(&outbuf[buflen], s->wwn); |
588 | 27395add | Paolo Bonzini | buflen += 8;
|
589 | 27395add | Paolo Bonzini | } |
590 | 0b06c059 | Gerd Hoffmann | break;
|
591 | 0b06c059 | Gerd Hoffmann | } |
592 | ea3bd56f | Christoph Hellwig | case 0xb0: /* block limits */ |
593 | ee3659e3 | Christoph Hellwig | { |
594 | ea3bd56f | Christoph Hellwig | unsigned int unmap_sectors = |
595 | ea3bd56f | Christoph Hellwig | s->qdev.conf.discard_granularity / s->qdev.blocksize; |
596 | 8cfacf07 | Christoph Hellwig | unsigned int min_io_size = |
597 | 8cfacf07 | Christoph Hellwig | s->qdev.conf.min_io_size / s->qdev.blocksize; |
598 | 8cfacf07 | Christoph Hellwig | unsigned int opt_io_size = |
599 | 8cfacf07 | Christoph Hellwig | s->qdev.conf.opt_io_size / s->qdev.blocksize; |
600 | ee3659e3 | Christoph Hellwig | |
601 | f37bd73b | Hannes Reinecke | if (s->qdev.type == TYPE_ROM) {
|
602 | 39d98982 | Hannes Reinecke | DPRINTF("Inquiry (EVPD[%02X] not supported for CDROM\n",
|
603 | 39d98982 | Hannes Reinecke | page_code); |
604 | 39d98982 | Hannes Reinecke | return -1; |
605 | 39d98982 | Hannes Reinecke | } |
606 | ee3659e3 | Christoph Hellwig | /* required VPD size with unmap support */
|
607 | 82579390 | Paolo Bonzini | buflen = 0x40;
|
608 | ee3659e3 | Christoph Hellwig | memset(outbuf + 4, 0, buflen - 4); |
609 | ee3659e3 | Christoph Hellwig | |
610 | ee3659e3 | Christoph Hellwig | /* optimal transfer length granularity */
|
611 | ee3659e3 | Christoph Hellwig | outbuf[6] = (min_io_size >> 8) & 0xff; |
612 | ee3659e3 | Christoph Hellwig | outbuf[7] = min_io_size & 0xff; |
613 | ee3659e3 | Christoph Hellwig | |
614 | ee3659e3 | Christoph Hellwig | /* optimal transfer length */
|
615 | ee3659e3 | Christoph Hellwig | outbuf[12] = (opt_io_size >> 24) & 0xff; |
616 | ee3659e3 | Christoph Hellwig | outbuf[13] = (opt_io_size >> 16) & 0xff; |
617 | ee3659e3 | Christoph Hellwig | outbuf[14] = (opt_io_size >> 8) & 0xff; |
618 | ee3659e3 | Christoph Hellwig | outbuf[15] = opt_io_size & 0xff; |
619 | ea3bd56f | Christoph Hellwig | |
620 | ea3bd56f | Christoph Hellwig | /* optimal unmap granularity */
|
621 | ea3bd56f | Christoph Hellwig | outbuf[28] = (unmap_sectors >> 24) & 0xff; |
622 | ea3bd56f | Christoph Hellwig | outbuf[29] = (unmap_sectors >> 16) & 0xff; |
623 | ea3bd56f | Christoph Hellwig | outbuf[30] = (unmap_sectors >> 8) & 0xff; |
624 | ea3bd56f | Christoph Hellwig | outbuf[31] = unmap_sectors & 0xff; |
625 | ea3bd56f | Christoph Hellwig | break;
|
626 | ea3bd56f | Christoph Hellwig | } |
627 | ea3bd56f | Christoph Hellwig | case 0xb2: /* thin provisioning */ |
628 | ea3bd56f | Christoph Hellwig | { |
629 | 82579390 | Paolo Bonzini | buflen = 8;
|
630 | ea3bd56f | Christoph Hellwig | outbuf[4] = 0; |
631 | 5222aaf2 | Paolo Bonzini | outbuf[5] = 0xe0; /* unmap & write_same 10/16 all supported */ |
632 | f644a290 | Ronnie Sahlberg | outbuf[6] = s->qdev.conf.discard_granularity ? 2 : 1; |
633 | ea3bd56f | Christoph Hellwig | outbuf[7] = 0; |
634 | ee3659e3 | Christoph Hellwig | break;
|
635 | ee3659e3 | Christoph Hellwig | } |
636 | 0b06c059 | Gerd Hoffmann | default:
|
637 | 0b06c059 | Gerd Hoffmann | return -1; |
638 | 0b06c059 | Gerd Hoffmann | } |
639 | 0b06c059 | Gerd Hoffmann | /* done with EVPD */
|
640 | 82579390 | Paolo Bonzini | assert(buflen - start <= 255);
|
641 | 82579390 | Paolo Bonzini | outbuf[start - 1] = buflen - start;
|
642 | 0b06c059 | Gerd Hoffmann | return buflen;
|
643 | 0b06c059 | Gerd Hoffmann | } |
644 | 0b06c059 | Gerd Hoffmann | |
645 | 0b06c059 | Gerd Hoffmann | /* Standard INQUIRY data */
|
646 | 0b06c059 | Gerd Hoffmann | if (req->cmd.buf[2] != 0) { |
647 | 0b06c059 | Gerd Hoffmann | return -1; |
648 | 0b06c059 | Gerd Hoffmann | } |
649 | 0b06c059 | Gerd Hoffmann | |
650 | 0b06c059 | Gerd Hoffmann | /* PAGE CODE == 0 */
|
651 | 0b06c059 | Gerd Hoffmann | buflen = req->cmd.xfer; |
652 | f01b5931 | Paolo Bonzini | if (buflen > SCSI_MAX_INQUIRY_LEN) {
|
653 | 0b06c059 | Gerd Hoffmann | buflen = SCSI_MAX_INQUIRY_LEN; |
654 | f01b5931 | Paolo Bonzini | } |
655 | 0b06c059 | Gerd Hoffmann | memset(outbuf, 0, buflen);
|
656 | 0b06c059 | Gerd Hoffmann | |
657 | f37bd73b | Hannes Reinecke | outbuf[0] = s->qdev.type & 0x1f; |
658 | bfe3d7ac | Paolo Bonzini | outbuf[1] = (s->features & (1 << SCSI_DISK_F_REMOVABLE)) ? 0x80 : 0; |
659 | 353815aa | Dmitry Fleytman | |
660 | 353815aa | Dmitry Fleytman | strpadcpy((char *) &outbuf[16], 16, s->product, ' '); |
661 | 353815aa | Dmitry Fleytman | strpadcpy((char *) &outbuf[8], 8, s->vendor, ' '); |
662 | 353815aa | Dmitry Fleytman | |
663 | 314b1811 | Gerd Hoffmann | memset(&outbuf[32], 0, 4); |
664 | 552fee93 | Markus Armbruster | memcpy(&outbuf[32], s->version, MIN(4, strlen(s->version))); |
665 | 99aba0c4 | Christoph Hellwig | /*
|
666 | 99aba0c4 | Christoph Hellwig | * We claim conformance to SPC-3, which is required for guests
|
667 | 99aba0c4 | Christoph Hellwig | * to ask for modern features like READ CAPACITY(16) or the
|
668 | 99aba0c4 | Christoph Hellwig | * block characteristics VPD page by default. Not all of SPC-3
|
669 | 99aba0c4 | Christoph Hellwig | * is actually implemented, but we're good enough.
|
670 | 99aba0c4 | Christoph Hellwig | */
|
671 | ee3659e3 | Christoph Hellwig | outbuf[2] = 5; |
672 | 1109c894 | Ronnie Sahlberg | outbuf[3] = 2 | 0x10; /* Format 2, HiSup */ |
673 | ad3cea42 | Artyom Tarasenko | |
674 | ad3cea42 | Artyom Tarasenko | if (buflen > 36) { |
675 | ad3cea42 | Artyom Tarasenko | outbuf[4] = buflen - 5; /* Additional Length = (Len - 1) - 4 */ |
676 | ad3cea42 | Artyom Tarasenko | } else {
|
677 | ad3cea42 | Artyom Tarasenko | /* If the allocation length of CDB is too small,
|
678 | ad3cea42 | Artyom Tarasenko | the additional length is not adjusted */
|
679 | ad3cea42 | Artyom Tarasenko | outbuf[4] = 36 - 5; |
680 | ad3cea42 | Artyom Tarasenko | } |
681 | ad3cea42 | Artyom Tarasenko | |
682 | 0b06c059 | Gerd Hoffmann | /* Sync data transfer and TCQ. */
|
683 | afd4030c | Paolo Bonzini | outbuf[7] = 0x10 | (req->bus->info->tcq ? 0x02 : 0); |
684 | 0b06c059 | Gerd Hoffmann | return buflen;
|
685 | 0b06c059 | Gerd Hoffmann | } |
686 | 0b06c059 | Gerd Hoffmann | |
687 | 430ee2f2 | Paolo Bonzini | static inline bool media_is_dvd(SCSIDiskState *s) |
688 | 430ee2f2 | Paolo Bonzini | { |
689 | 430ee2f2 | Paolo Bonzini | uint64_t nb_sectors; |
690 | 430ee2f2 | Paolo Bonzini | if (s->qdev.type != TYPE_ROM) {
|
691 | 430ee2f2 | Paolo Bonzini | return false; |
692 | 430ee2f2 | Paolo Bonzini | } |
693 | 44740c38 | Paolo Bonzini | if (!bdrv_is_inserted(s->qdev.conf.bs)) {
|
694 | 430ee2f2 | Paolo Bonzini | return false; |
695 | 430ee2f2 | Paolo Bonzini | } |
696 | 44740c38 | Paolo Bonzini | bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors); |
697 | 430ee2f2 | Paolo Bonzini | return nb_sectors > CD_MAX_SECTORS;
|
698 | 430ee2f2 | Paolo Bonzini | } |
699 | 430ee2f2 | Paolo Bonzini | |
700 | ceb792ef | Paolo Bonzini | static inline bool media_is_cd(SCSIDiskState *s) |
701 | ceb792ef | Paolo Bonzini | { |
702 | ceb792ef | Paolo Bonzini | uint64_t nb_sectors; |
703 | ceb792ef | Paolo Bonzini | if (s->qdev.type != TYPE_ROM) {
|
704 | ceb792ef | Paolo Bonzini | return false; |
705 | ceb792ef | Paolo Bonzini | } |
706 | 44740c38 | Paolo Bonzini | if (!bdrv_is_inserted(s->qdev.conf.bs)) {
|
707 | ceb792ef | Paolo Bonzini | return false; |
708 | ceb792ef | Paolo Bonzini | } |
709 | 44740c38 | Paolo Bonzini | bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors); |
710 | ceb792ef | Paolo Bonzini | return nb_sectors <= CD_MAX_SECTORS;
|
711 | ceb792ef | Paolo Bonzini | } |
712 | ceb792ef | Paolo Bonzini | |
713 | 1a4f0c3a | Paolo Bonzini | static int scsi_read_disc_information(SCSIDiskState *s, SCSIDiskReq *r, |
714 | 1a4f0c3a | Paolo Bonzini | uint8_t *outbuf) |
715 | 1a4f0c3a | Paolo Bonzini | { |
716 | 1a4f0c3a | Paolo Bonzini | uint8_t type = r->req.cmd.buf[1] & 7; |
717 | 1a4f0c3a | Paolo Bonzini | |
718 | 1a4f0c3a | Paolo Bonzini | if (s->qdev.type != TYPE_ROM) {
|
719 | 1a4f0c3a | Paolo Bonzini | return -1; |
720 | 1a4f0c3a | Paolo Bonzini | } |
721 | 1a4f0c3a | Paolo Bonzini | |
722 | 1a4f0c3a | Paolo Bonzini | /* Types 1/2 are only defined for Blu-Ray. */
|
723 | 1a4f0c3a | Paolo Bonzini | if (type != 0) { |
724 | 1a4f0c3a | Paolo Bonzini | scsi_check_condition(r, SENSE_CODE(INVALID_FIELD)); |
725 | 1a4f0c3a | Paolo Bonzini | return -1; |
726 | 1a4f0c3a | Paolo Bonzini | } |
727 | 1a4f0c3a | Paolo Bonzini | |
728 | 1a4f0c3a | Paolo Bonzini | memset(outbuf, 0, 34); |
729 | 1a4f0c3a | Paolo Bonzini | outbuf[1] = 32; |
730 | 1a4f0c3a | Paolo Bonzini | outbuf[2] = 0xe; /* last session complete, disc finalized */ |
731 | 1a4f0c3a | Paolo Bonzini | outbuf[3] = 1; /* first track on disc */ |
732 | 1a4f0c3a | Paolo Bonzini | outbuf[4] = 1; /* # of sessions */ |
733 | 1a4f0c3a | Paolo Bonzini | outbuf[5] = 1; /* first track of last session */ |
734 | 1a4f0c3a | Paolo Bonzini | outbuf[6] = 1; /* last track of last session */ |
735 | 1a4f0c3a | Paolo Bonzini | outbuf[7] = 0x20; /* unrestricted use */ |
736 | 1a4f0c3a | Paolo Bonzini | outbuf[8] = 0x00; /* CD-ROM or DVD-ROM */ |
737 | 1a4f0c3a | Paolo Bonzini | /* 9-10-11: most significant byte corresponding bytes 4-5-6 */
|
738 | 1a4f0c3a | Paolo Bonzini | /* 12-23: not meaningful for CD-ROM or DVD-ROM */
|
739 | 1a4f0c3a | Paolo Bonzini | /* 24-31: disc bar code */
|
740 | 1a4f0c3a | Paolo Bonzini | /* 32: disc application code */
|
741 | 1a4f0c3a | Paolo Bonzini | /* 33: number of OPC tables */
|
742 | 1a4f0c3a | Paolo Bonzini | |
743 | 1a4f0c3a | Paolo Bonzini | return 34; |
744 | 1a4f0c3a | Paolo Bonzini | } |
745 | 1a4f0c3a | Paolo Bonzini | |
746 | b6c251ab | Paolo Bonzini | static int scsi_read_dvd_structure(SCSIDiskState *s, SCSIDiskReq *r, |
747 | b6c251ab | Paolo Bonzini | uint8_t *outbuf) |
748 | b6c251ab | Paolo Bonzini | { |
749 | ceb792ef | Paolo Bonzini | static const int rds_caps_size[5] = { |
750 | ceb792ef | Paolo Bonzini | [0] = 2048 + 4, |
751 | ceb792ef | Paolo Bonzini | [1] = 4 + 4, |
752 | ceb792ef | Paolo Bonzini | [3] = 188 + 4, |
753 | ceb792ef | Paolo Bonzini | [4] = 2048 + 4, |
754 | ceb792ef | Paolo Bonzini | }; |
755 | ceb792ef | Paolo Bonzini | |
756 | ceb792ef | Paolo Bonzini | uint8_t media = r->req.cmd.buf[1];
|
757 | ceb792ef | Paolo Bonzini | uint8_t layer = r->req.cmd.buf[6];
|
758 | ceb792ef | Paolo Bonzini | uint8_t format = r->req.cmd.buf[7];
|
759 | ceb792ef | Paolo Bonzini | int size = -1; |
760 | ceb792ef | Paolo Bonzini | |
761 | ceb792ef | Paolo Bonzini | if (s->qdev.type != TYPE_ROM) {
|
762 | ceb792ef | Paolo Bonzini | return -1; |
763 | ceb792ef | Paolo Bonzini | } |
764 | ceb792ef | Paolo Bonzini | if (media != 0) { |
765 | ceb792ef | Paolo Bonzini | scsi_check_condition(r, SENSE_CODE(INVALID_FIELD)); |
766 | ceb792ef | Paolo Bonzini | return -1; |
767 | ceb792ef | Paolo Bonzini | } |
768 | ceb792ef | Paolo Bonzini | |
769 | ceb792ef | Paolo Bonzini | if (format != 0xff) { |
770 | 44740c38 | Paolo Bonzini | if (s->tray_open || !bdrv_is_inserted(s->qdev.conf.bs)) {
|
771 | ceb792ef | Paolo Bonzini | scsi_check_condition(r, SENSE_CODE(NO_MEDIUM)); |
772 | ceb792ef | Paolo Bonzini | return -1; |
773 | ceb792ef | Paolo Bonzini | } |
774 | ceb792ef | Paolo Bonzini | if (media_is_cd(s)) {
|
775 | ceb792ef | Paolo Bonzini | scsi_check_condition(r, SENSE_CODE(INCOMPATIBLE_FORMAT)); |
776 | ceb792ef | Paolo Bonzini | return -1; |
777 | ceb792ef | Paolo Bonzini | } |
778 | ceb792ef | Paolo Bonzini | if (format >= ARRAY_SIZE(rds_caps_size)) {
|
779 | ceb792ef | Paolo Bonzini | return -1; |
780 | ceb792ef | Paolo Bonzini | } |
781 | ceb792ef | Paolo Bonzini | size = rds_caps_size[format]; |
782 | ceb792ef | Paolo Bonzini | memset(outbuf, 0, size);
|
783 | ceb792ef | Paolo Bonzini | } |
784 | ceb792ef | Paolo Bonzini | |
785 | ceb792ef | Paolo Bonzini | switch (format) {
|
786 | ceb792ef | Paolo Bonzini | case 0x00: { |
787 | ceb792ef | Paolo Bonzini | /* Physical format information */
|
788 | ceb792ef | Paolo Bonzini | uint64_t nb_sectors; |
789 | ceb792ef | Paolo Bonzini | if (layer != 0) { |
790 | ceb792ef | Paolo Bonzini | goto fail;
|
791 | ceb792ef | Paolo Bonzini | } |
792 | 44740c38 | Paolo Bonzini | bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors); |
793 | ceb792ef | Paolo Bonzini | |
794 | ceb792ef | Paolo Bonzini | outbuf[4] = 1; /* DVD-ROM, part version 1 */ |
795 | ceb792ef | Paolo Bonzini | outbuf[5] = 0xf; /* 120mm disc, minimum rate unspecified */ |
796 | ceb792ef | Paolo Bonzini | outbuf[6] = 1; /* one layer, read-only (per MMC-2 spec) */ |
797 | ceb792ef | Paolo Bonzini | outbuf[7] = 0; /* default densities */ |
798 | ceb792ef | Paolo Bonzini | |
799 | ceb792ef | Paolo Bonzini | stl_be_p(&outbuf[12], (nb_sectors >> 2) - 1); /* end sector */ |
800 | ceb792ef | Paolo Bonzini | stl_be_p(&outbuf[16], (nb_sectors >> 2) - 1); /* l0 end sector */ |
801 | ceb792ef | Paolo Bonzini | break;
|
802 | ceb792ef | Paolo Bonzini | } |
803 | ceb792ef | Paolo Bonzini | |
804 | ceb792ef | Paolo Bonzini | case 0x01: /* DVD copyright information, all zeros */ |
805 | ceb792ef | Paolo Bonzini | break;
|
806 | ceb792ef | Paolo Bonzini | |
807 | ceb792ef | Paolo Bonzini | case 0x03: /* BCA information - invalid field for no BCA info */ |
808 | ceb792ef | Paolo Bonzini | return -1; |
809 | ceb792ef | Paolo Bonzini | |
810 | ceb792ef | Paolo Bonzini | case 0x04: /* DVD disc manufacturing information, all zeros */ |
811 | ceb792ef | Paolo Bonzini | break;
|
812 | ceb792ef | Paolo Bonzini | |
813 | ceb792ef | Paolo Bonzini | case 0xff: { /* List capabilities */ |
814 | ceb792ef | Paolo Bonzini | int i;
|
815 | ceb792ef | Paolo Bonzini | size = 4;
|
816 | ceb792ef | Paolo Bonzini | for (i = 0; i < ARRAY_SIZE(rds_caps_size); i++) { |
817 | ceb792ef | Paolo Bonzini | if (!rds_caps_size[i]) {
|
818 | ceb792ef | Paolo Bonzini | continue;
|
819 | ceb792ef | Paolo Bonzini | } |
820 | ceb792ef | Paolo Bonzini | outbuf[size] = i; |
821 | ceb792ef | Paolo Bonzini | outbuf[size + 1] = 0x40; /* Not writable, readable */ |
822 | ceb792ef | Paolo Bonzini | stw_be_p(&outbuf[size + 2], rds_caps_size[i]);
|
823 | ceb792ef | Paolo Bonzini | size += 4;
|
824 | ceb792ef | Paolo Bonzini | } |
825 | ceb792ef | Paolo Bonzini | break;
|
826 | ceb792ef | Paolo Bonzini | } |
827 | ceb792ef | Paolo Bonzini | |
828 | ceb792ef | Paolo Bonzini | default:
|
829 | ceb792ef | Paolo Bonzini | return -1; |
830 | ceb792ef | Paolo Bonzini | } |
831 | ceb792ef | Paolo Bonzini | |
832 | ceb792ef | Paolo Bonzini | /* Size of buffer, not including 2 byte size field */
|
833 | ceb792ef | Paolo Bonzini | stw_be_p(outbuf, size - 2);
|
834 | ceb792ef | Paolo Bonzini | return size;
|
835 | ceb792ef | Paolo Bonzini | |
836 | ceb792ef | Paolo Bonzini | fail:
|
837 | b6c251ab | Paolo Bonzini | return -1; |
838 | b6c251ab | Paolo Bonzini | } |
839 | b6c251ab | Paolo Bonzini | |
840 | 3c2f7c12 | Paolo Bonzini | static int scsi_event_status_media(SCSIDiskState *s, uint8_t *outbuf) |
841 | b6c251ab | Paolo Bonzini | { |
842 | 3c2f7c12 | Paolo Bonzini | uint8_t event_code, media_status; |
843 | 3c2f7c12 | Paolo Bonzini | |
844 | 3c2f7c12 | Paolo Bonzini | media_status = 0;
|
845 | 3c2f7c12 | Paolo Bonzini | if (s->tray_open) {
|
846 | 3c2f7c12 | Paolo Bonzini | media_status = MS_TRAY_OPEN; |
847 | 44740c38 | Paolo Bonzini | } else if (bdrv_is_inserted(s->qdev.conf.bs)) { |
848 | 3c2f7c12 | Paolo Bonzini | media_status = MS_MEDIA_PRESENT; |
849 | 3c2f7c12 | Paolo Bonzini | } |
850 | 3c2f7c12 | Paolo Bonzini | |
851 | 3c2f7c12 | Paolo Bonzini | /* Event notification descriptor */
|
852 | 3c2f7c12 | Paolo Bonzini | event_code = MEC_NO_CHANGE; |
853 | 4480de19 | Paolo Bonzini | if (media_status != MS_TRAY_OPEN) {
|
854 | 4480de19 | Paolo Bonzini | if (s->media_event) {
|
855 | 4480de19 | Paolo Bonzini | event_code = MEC_NEW_MEDIA; |
856 | 4480de19 | Paolo Bonzini | s->media_event = false;
|
857 | 4480de19 | Paolo Bonzini | } else if (s->eject_request) { |
858 | 4480de19 | Paolo Bonzini | event_code = MEC_EJECT_REQUESTED; |
859 | 4480de19 | Paolo Bonzini | s->eject_request = false;
|
860 | 4480de19 | Paolo Bonzini | } |
861 | 3c2f7c12 | Paolo Bonzini | } |
862 | 3c2f7c12 | Paolo Bonzini | |
863 | 3c2f7c12 | Paolo Bonzini | outbuf[0] = event_code;
|
864 | 3c2f7c12 | Paolo Bonzini | outbuf[1] = media_status;
|
865 | 3c2f7c12 | Paolo Bonzini | |
866 | 3c2f7c12 | Paolo Bonzini | /* These fields are reserved, just clear them. */
|
867 | 3c2f7c12 | Paolo Bonzini | outbuf[2] = 0; |
868 | 3c2f7c12 | Paolo Bonzini | outbuf[3] = 0; |
869 | 3c2f7c12 | Paolo Bonzini | return 4; |
870 | 3c2f7c12 | Paolo Bonzini | } |
871 | 3c2f7c12 | Paolo Bonzini | |
872 | 3c2f7c12 | Paolo Bonzini | static int scsi_get_event_status_notification(SCSIDiskState *s, SCSIDiskReq *r, |
873 | 3c2f7c12 | Paolo Bonzini | uint8_t *outbuf) |
874 | 3c2f7c12 | Paolo Bonzini | { |
875 | 3c2f7c12 | Paolo Bonzini | int size;
|
876 | 3c2f7c12 | Paolo Bonzini | uint8_t *buf = r->req.cmd.buf; |
877 | 3c2f7c12 | Paolo Bonzini | uint8_t notification_class_request = buf[4];
|
878 | 3c2f7c12 | Paolo Bonzini | if (s->qdev.type != TYPE_ROM) {
|
879 | 3c2f7c12 | Paolo Bonzini | return -1; |
880 | 3c2f7c12 | Paolo Bonzini | } |
881 | 3c2f7c12 | Paolo Bonzini | if ((buf[1] & 1) == 0) { |
882 | 3c2f7c12 | Paolo Bonzini | /* asynchronous */
|
883 | 3c2f7c12 | Paolo Bonzini | return -1; |
884 | 3c2f7c12 | Paolo Bonzini | } |
885 | 3c2f7c12 | Paolo Bonzini | |
886 | 3c2f7c12 | Paolo Bonzini | size = 4;
|
887 | 3c2f7c12 | Paolo Bonzini | outbuf[0] = outbuf[1] = 0; |
888 | 3c2f7c12 | Paolo Bonzini | outbuf[3] = 1 << GESN_MEDIA; /* supported events */ |
889 | 3c2f7c12 | Paolo Bonzini | if (notification_class_request & (1 << GESN_MEDIA)) { |
890 | 3c2f7c12 | Paolo Bonzini | outbuf[2] = GESN_MEDIA;
|
891 | 3c2f7c12 | Paolo Bonzini | size += scsi_event_status_media(s, &outbuf[size]); |
892 | 3c2f7c12 | Paolo Bonzini | } else {
|
893 | 3c2f7c12 | Paolo Bonzini | outbuf[2] = 0x80; |
894 | 3c2f7c12 | Paolo Bonzini | } |
895 | 3c2f7c12 | Paolo Bonzini | stw_be_p(outbuf, size - 4);
|
896 | 3c2f7c12 | Paolo Bonzini | return size;
|
897 | b6c251ab | Paolo Bonzini | } |
898 | b6c251ab | Paolo Bonzini | |
899 | 430ee2f2 | Paolo Bonzini | static int scsi_get_configuration(SCSIDiskState *s, uint8_t *outbuf) |
900 | b6c251ab | Paolo Bonzini | { |
901 | 430ee2f2 | Paolo Bonzini | int current;
|
902 | 430ee2f2 | Paolo Bonzini | |
903 | b6c251ab | Paolo Bonzini | if (s->qdev.type != TYPE_ROM) {
|
904 | b6c251ab | Paolo Bonzini | return -1; |
905 | b6c251ab | Paolo Bonzini | } |
906 | 430ee2f2 | Paolo Bonzini | current = media_is_dvd(s) ? MMC_PROFILE_DVD_ROM : MMC_PROFILE_CD_ROM; |
907 | 430ee2f2 | Paolo Bonzini | memset(outbuf, 0, 40); |
908 | 430ee2f2 | Paolo Bonzini | stl_be_p(&outbuf[0], 36); /* Bytes after the data length field */ |
909 | 430ee2f2 | Paolo Bonzini | stw_be_p(&outbuf[6], current);
|
910 | 430ee2f2 | Paolo Bonzini | /* outbuf[8] - outbuf[19]: Feature 0 - Profile list */
|
911 | 430ee2f2 | Paolo Bonzini | outbuf[10] = 0x03; /* persistent, current */ |
912 | 430ee2f2 | Paolo Bonzini | outbuf[11] = 8; /* two profiles */ |
913 | 430ee2f2 | Paolo Bonzini | stw_be_p(&outbuf[12], MMC_PROFILE_DVD_ROM);
|
914 | 430ee2f2 | Paolo Bonzini | outbuf[14] = (current == MMC_PROFILE_DVD_ROM);
|
915 | 430ee2f2 | Paolo Bonzini | stw_be_p(&outbuf[16], MMC_PROFILE_CD_ROM);
|
916 | 430ee2f2 | Paolo Bonzini | outbuf[18] = (current == MMC_PROFILE_CD_ROM);
|
917 | 430ee2f2 | Paolo Bonzini | /* outbuf[20] - outbuf[31]: Feature 1 - Core feature */
|
918 | 430ee2f2 | Paolo Bonzini | stw_be_p(&outbuf[20], 1); |
919 | 430ee2f2 | Paolo Bonzini | outbuf[22] = 0x08 | 0x03; /* version 2, persistent, current */ |
920 | 430ee2f2 | Paolo Bonzini | outbuf[23] = 8; |
921 | 430ee2f2 | Paolo Bonzini | stl_be_p(&outbuf[24], 1); /* SCSI */ |
922 | 430ee2f2 | Paolo Bonzini | outbuf[28] = 1; /* DBE = 1, mandatory */ |
923 | 430ee2f2 | Paolo Bonzini | /* outbuf[32] - outbuf[39]: Feature 3 - Removable media feature */
|
924 | 430ee2f2 | Paolo Bonzini | stw_be_p(&outbuf[32], 3); |
925 | 430ee2f2 | Paolo Bonzini | outbuf[34] = 0x08 | 0x03; /* version 2, persistent, current */ |
926 | 430ee2f2 | Paolo Bonzini | outbuf[35] = 4; |
927 | 430ee2f2 | Paolo Bonzini | outbuf[36] = 0x39; /* tray, load=1, eject=1, unlocked at powerup, lock=1 */ |
928 | 430ee2f2 | Paolo Bonzini | /* TODO: Random readable, CD read, DVD read, drive serial number,
|
929 | 430ee2f2 | Paolo Bonzini | power management */
|
930 | 430ee2f2 | Paolo Bonzini | return 40; |
931 | b6c251ab | Paolo Bonzini | } |
932 | b6c251ab | Paolo Bonzini | |
933 | b6c251ab | Paolo Bonzini | static int scsi_emulate_mechanism_status(SCSIDiskState *s, uint8_t *outbuf) |
934 | b6c251ab | Paolo Bonzini | { |
935 | b6c251ab | Paolo Bonzini | if (s->qdev.type != TYPE_ROM) {
|
936 | b6c251ab | Paolo Bonzini | return -1; |
937 | b6c251ab | Paolo Bonzini | } |
938 | b6c251ab | Paolo Bonzini | memset(outbuf, 0, 8); |
939 | b6c251ab | Paolo Bonzini | outbuf[5] = 1; /* CD-ROM */ |
940 | b6c251ab | Paolo Bonzini | return 8; |
941 | b6c251ab | Paolo Bonzini | } |
942 | b6c251ab | Paolo Bonzini | |
943 | cfc606da | Paolo Bonzini | static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf, |
944 | 282ab04e | Bernhard Kohl | int page_control)
|
945 | ebddfcbe | Gerd Hoffmann | { |
946 | a8f4bbe2 | Paolo Bonzini | static const int mode_sense_valid[0x3f] = { |
947 | a8f4bbe2 | Paolo Bonzini | [MODE_PAGE_HD_GEOMETRY] = (1 << TYPE_DISK),
|
948 | a8f4bbe2 | Paolo Bonzini | [MODE_PAGE_FLEXIBLE_DISK_GEOMETRY] = (1 << TYPE_DISK),
|
949 | a8f4bbe2 | Paolo Bonzini | [MODE_PAGE_CACHING] = (1 << TYPE_DISK) | (1 << TYPE_ROM), |
950 | a07c7dcd | Paolo Bonzini | [MODE_PAGE_R_W_ERROR] = (1 << TYPE_DISK) | (1 << TYPE_ROM), |
951 | a07c7dcd | Paolo Bonzini | [MODE_PAGE_AUDIO_CTL] = (1 << TYPE_ROM),
|
952 | a8f4bbe2 | Paolo Bonzini | [MODE_PAGE_CAPABILITIES] = (1 << TYPE_ROM),
|
953 | a8f4bbe2 | Paolo Bonzini | }; |
954 | ef405611 | Paolo Bonzini | |
955 | ef405611 | Paolo Bonzini | uint8_t *p = *p_outbuf + 2;
|
956 | ef405611 | Paolo Bonzini | int length;
|
957 | ebddfcbe | Gerd Hoffmann | |
958 | a8f4bbe2 | Paolo Bonzini | if ((mode_sense_valid[page] & (1 << s->qdev.type)) == 0) { |
959 | a8f4bbe2 | Paolo Bonzini | return -1; |
960 | a8f4bbe2 | Paolo Bonzini | } |
961 | a8f4bbe2 | Paolo Bonzini | |
962 | 282ab04e | Bernhard Kohl | /*
|
963 | 282ab04e | Bernhard Kohl | * If Changeable Values are requested, a mask denoting those mode parameters
|
964 | 282ab04e | Bernhard Kohl | * that are changeable shall be returned. As we currently don't support
|
965 | 282ab04e | Bernhard Kohl | * parameter changes via MODE_SELECT all bits are returned set to zero.
|
966 | 282ab04e | Bernhard Kohl | * The buffer was already menset to zero by the caller of this function.
|
967 | ef405611 | Paolo Bonzini | *
|
968 | ef405611 | Paolo Bonzini | * The offsets here are off by two compared to the descriptions in the
|
969 | ef405611 | Paolo Bonzini | * SCSI specs, because those include a 2-byte header. This is unfortunate,
|
970 | ef405611 | Paolo Bonzini | * but it is done so that offsets are consistent within our implementation
|
971 | ef405611 | Paolo Bonzini | * of MODE SENSE and MODE SELECT. MODE SELECT has to deal with both
|
972 | ef405611 | Paolo Bonzini | * 2-byte and 4-byte headers.
|
973 | 282ab04e | Bernhard Kohl | */
|
974 | ebddfcbe | Gerd Hoffmann | switch (page) {
|
975 | 67cc61e4 | Paolo Bonzini | case MODE_PAGE_HD_GEOMETRY:
|
976 | ef405611 | Paolo Bonzini | length = 0x16;
|
977 | 282ab04e | Bernhard Kohl | if (page_control == 1) { /* Changeable Values */ |
978 | cfc606da | Paolo Bonzini | break;
|
979 | 282ab04e | Bernhard Kohl | } |
980 | ebddfcbe | Gerd Hoffmann | /* if a geometry hint is available, use it */
|
981 | ef405611 | Paolo Bonzini | p[0] = (s->qdev.conf.cyls >> 16) & 0xff; |
982 | ef405611 | Paolo Bonzini | p[1] = (s->qdev.conf.cyls >> 8) & 0xff; |
983 | ef405611 | Paolo Bonzini | p[2] = s->qdev.conf.cyls & 0xff; |
984 | ef405611 | Paolo Bonzini | p[3] = s->qdev.conf.heads & 0xff; |
985 | ebddfcbe | Gerd Hoffmann | /* Write precomp start cylinder, disabled */
|
986 | ef405611 | Paolo Bonzini | p[4] = (s->qdev.conf.cyls >> 16) & 0xff; |
987 | ef405611 | Paolo Bonzini | p[5] = (s->qdev.conf.cyls >> 8) & 0xff; |
988 | ef405611 | Paolo Bonzini | p[6] = s->qdev.conf.cyls & 0xff; |
989 | ebddfcbe | Gerd Hoffmann | /* Reduced current start cylinder, disabled */
|
990 | ef405611 | Paolo Bonzini | p[7] = (s->qdev.conf.cyls >> 16) & 0xff; |
991 | ef405611 | Paolo Bonzini | p[8] = (s->qdev.conf.cyls >> 8) & 0xff; |
992 | ef405611 | Paolo Bonzini | p[9] = s->qdev.conf.cyls & 0xff; |
993 | ebddfcbe | Gerd Hoffmann | /* Device step rate [ns], 200ns */
|
994 | ef405611 | Paolo Bonzini | p[10] = 0; |
995 | ef405611 | Paolo Bonzini | p[11] = 200; |
996 | ebddfcbe | Gerd Hoffmann | /* Landing zone cylinder */
|
997 | ef405611 | Paolo Bonzini | p[12] = 0xff; |
998 | ef405611 | Paolo Bonzini | p[13] = 0xff; |
999 | ebddfcbe | Gerd Hoffmann | p[14] = 0xff; |
1000 | ebddfcbe | Gerd Hoffmann | /* Medium rotation rate [rpm], 5400 rpm */
|
1001 | ef405611 | Paolo Bonzini | p[18] = (5400 >> 8) & 0xff; |
1002 | ef405611 | Paolo Bonzini | p[19] = 5400 & 0xff; |
1003 | cfc606da | Paolo Bonzini | break;
|
1004 | ebddfcbe | Gerd Hoffmann | |
1005 | 67cc61e4 | Paolo Bonzini | case MODE_PAGE_FLEXIBLE_DISK_GEOMETRY:
|
1006 | ef405611 | Paolo Bonzini | length = 0x1e;
|
1007 | 282ab04e | Bernhard Kohl | if (page_control == 1) { /* Changeable Values */ |
1008 | cfc606da | Paolo Bonzini | break;
|
1009 | 282ab04e | Bernhard Kohl | } |
1010 | ebddfcbe | Gerd Hoffmann | /* Transfer rate [kbit/s], 5Mbit/s */
|
1011 | ef405611 | Paolo Bonzini | p[0] = 5000 >> 8; |
1012 | ef405611 | Paolo Bonzini | p[1] = 5000 & 0xff; |
1013 | ebddfcbe | Gerd Hoffmann | /* if a geometry hint is available, use it */
|
1014 | ef405611 | Paolo Bonzini | p[2] = s->qdev.conf.heads & 0xff; |
1015 | ef405611 | Paolo Bonzini | p[3] = s->qdev.conf.secs & 0xff; |
1016 | ef405611 | Paolo Bonzini | p[4] = s->qdev.blocksize >> 8; |
1017 | ef405611 | Paolo Bonzini | p[6] = (s->qdev.conf.cyls >> 8) & 0xff; |
1018 | ef405611 | Paolo Bonzini | p[7] = s->qdev.conf.cyls & 0xff; |
1019 | ef405611 | Paolo Bonzini | /* Write precomp start cylinder, disabled */
|
1020 | d252df48 | Markus Armbruster | p[8] = (s->qdev.conf.cyls >> 8) & 0xff; |
1021 | d252df48 | Markus Armbruster | p[9] = s->qdev.conf.cyls & 0xff; |
1022 | ef405611 | Paolo Bonzini | /* Reduced current start cylinder, disabled */
|
1023 | d252df48 | Markus Armbruster | p[10] = (s->qdev.conf.cyls >> 8) & 0xff; |
1024 | d252df48 | Markus Armbruster | p[11] = s->qdev.conf.cyls & 0xff; |
1025 | ebddfcbe | Gerd Hoffmann | /* Device step rate [100us], 100us */
|
1026 | ef405611 | Paolo Bonzini | p[12] = 0; |
1027 | ef405611 | Paolo Bonzini | p[13] = 1; |
1028 | ebddfcbe | Gerd Hoffmann | /* Device step pulse width [us], 1us */
|
1029 | ef405611 | Paolo Bonzini | p[14] = 1; |
1030 | ebddfcbe | Gerd Hoffmann | /* Device head settle delay [100us], 100us */
|
1031 | ef405611 | Paolo Bonzini | p[15] = 0; |
1032 | ef405611 | Paolo Bonzini | p[16] = 1; |
1033 | ebddfcbe | Gerd Hoffmann | /* Motor on delay [0.1s], 0.1s */
|
1034 | ef405611 | Paolo Bonzini | p[17] = 1; |
1035 | ebddfcbe | Gerd Hoffmann | /* Motor off delay [0.1s], 0.1s */
|
1036 | ef405611 | Paolo Bonzini | p[18] = 1; |
1037 | ebddfcbe | Gerd Hoffmann | /* Medium rotation rate [rpm], 5400 rpm */
|
1038 | ef405611 | Paolo Bonzini | p[26] = (5400 >> 8) & 0xff; |
1039 | ef405611 | Paolo Bonzini | p[27] = 5400 & 0xff; |
1040 | cfc606da | Paolo Bonzini | break;
|
1041 | ebddfcbe | Gerd Hoffmann | |
1042 | 67cc61e4 | Paolo Bonzini | case MODE_PAGE_CACHING:
|
1043 | ef405611 | Paolo Bonzini | length = 0x12;
|
1044 | 96c91bbf | Paolo Bonzini | if (page_control == 1 || /* Changeable Values */ |
1045 | 96c91bbf | Paolo Bonzini | bdrv_enable_write_cache(s->qdev.conf.bs)) { |
1046 | ef405611 | Paolo Bonzini | p[0] = 4; /* WCE */ |
1047 | ebddfcbe | Gerd Hoffmann | } |
1048 | cfc606da | Paolo Bonzini | break;
|
1049 | ebddfcbe | Gerd Hoffmann | |
1050 | a07c7dcd | Paolo Bonzini | case MODE_PAGE_R_W_ERROR:
|
1051 | ef405611 | Paolo Bonzini | length = 10;
|
1052 | 4f588b15 | Paolo Bonzini | if (page_control == 1) { /* Changeable Values */ |
1053 | 4f588b15 | Paolo Bonzini | break;
|
1054 | 4f588b15 | Paolo Bonzini | } |
1055 | ef405611 | Paolo Bonzini | p[0] = 0x80; /* Automatic Write Reallocation Enabled */ |
1056 | a07c7dcd | Paolo Bonzini | if (s->qdev.type == TYPE_ROM) {
|
1057 | ef405611 | Paolo Bonzini | p[1] = 0x20; /* Read Retry Count */ |
1058 | a07c7dcd | Paolo Bonzini | } |
1059 | a07c7dcd | Paolo Bonzini | break;
|
1060 | a07c7dcd | Paolo Bonzini | |
1061 | a07c7dcd | Paolo Bonzini | case MODE_PAGE_AUDIO_CTL:
|
1062 | ef405611 | Paolo Bonzini | length = 14;
|
1063 | a07c7dcd | Paolo Bonzini | break;
|
1064 | a07c7dcd | Paolo Bonzini | |
1065 | 67cc61e4 | Paolo Bonzini | case MODE_PAGE_CAPABILITIES:
|
1066 | ef405611 | Paolo Bonzini | length = 0x14;
|
1067 | 282ab04e | Bernhard Kohl | if (page_control == 1) { /* Changeable Values */ |
1068 | cfc606da | Paolo Bonzini | break;
|
1069 | 282ab04e | Bernhard Kohl | } |
1070 | a07c7dcd | Paolo Bonzini | |
1071 | ef405611 | Paolo Bonzini | p[0] = 0x3b; /* CD-R & CD-RW read */ |
1072 | ef405611 | Paolo Bonzini | p[1] = 0; /* Writing not supported */ |
1073 | ef405611 | Paolo Bonzini | p[2] = 0x7f; /* Audio, composite, digital out, |
1074 | ebddfcbe | Gerd Hoffmann | mode 2 form 1&2, multi session */
|
1075 | ef405611 | Paolo Bonzini | p[3] = 0xff; /* CD DA, DA accurate, RW supported, |
1076 | ebddfcbe | Gerd Hoffmann | RW corrected, C2 errors, ISRC,
|
1077 | ebddfcbe | Gerd Hoffmann | UPC, Bar code */
|
1078 | ef405611 | Paolo Bonzini | p[4] = 0x2d | (s->tray_locked ? 2 : 0); |
1079 | ebddfcbe | Gerd Hoffmann | /* Locking supported, jumper present, eject, tray */
|
1080 | ef405611 | Paolo Bonzini | p[5] = 0; /* no volume & mute control, no |
1081 | ebddfcbe | Gerd Hoffmann | changer */
|
1082 | ef405611 | Paolo Bonzini | p[6] = (50 * 176) >> 8; /* 50x read speed */ |
1083 | ef405611 | Paolo Bonzini | p[7] = (50 * 176) & 0xff; |
1084 | ef405611 | Paolo Bonzini | p[8] = 2 >> 8; /* Two volume levels */ |
1085 | ef405611 | Paolo Bonzini | p[9] = 2 & 0xff; |
1086 | ef405611 | Paolo Bonzini | p[10] = 2048 >> 8; /* 2M buffer */ |
1087 | ef405611 | Paolo Bonzini | p[11] = 2048 & 0xff; |
1088 | ef405611 | Paolo Bonzini | p[12] = (16 * 176) >> 8; /* 16x read speed current */ |
1089 | ef405611 | Paolo Bonzini | p[13] = (16 * 176) & 0xff; |
1090 | ef405611 | Paolo Bonzini | p[16] = (16 * 176) >> 8; /* 16x write speed */ |
1091 | ef405611 | Paolo Bonzini | p[17] = (16 * 176) & 0xff; |
1092 | ef405611 | Paolo Bonzini | p[18] = (16 * 176) >> 8; /* 16x write speed current */ |
1093 | ebddfcbe | Gerd Hoffmann | p[19] = (16 * 176) & 0xff; |
1094 | cfc606da | Paolo Bonzini | break;
|
1095 | ebddfcbe | Gerd Hoffmann | |
1096 | ebddfcbe | Gerd Hoffmann | default:
|
1097 | cfc606da | Paolo Bonzini | return -1; |
1098 | ebddfcbe | Gerd Hoffmann | } |
1099 | cfc606da | Paolo Bonzini | |
1100 | ef405611 | Paolo Bonzini | assert(length < 256);
|
1101 | ef405611 | Paolo Bonzini | (*p_outbuf)[0] = page;
|
1102 | ef405611 | Paolo Bonzini | (*p_outbuf)[1] = length;
|
1103 | ef405611 | Paolo Bonzini | *p_outbuf += length + 2;
|
1104 | ef405611 | Paolo Bonzini | return length + 2; |
1105 | ebddfcbe | Gerd Hoffmann | } |
1106 | ebddfcbe | Gerd Hoffmann | |
1107 | cfc606da | Paolo Bonzini | static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf) |
1108 | ebddfcbe | Gerd Hoffmann | { |
1109 | cfc606da | Paolo Bonzini | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); |
1110 | ebddfcbe | Gerd Hoffmann | uint64_t nb_sectors; |
1111 | e590ecbe | Paolo Bonzini | bool dbd;
|
1112 | e590ecbe | Paolo Bonzini | int page, buflen, ret, page_control;
|
1113 | ebddfcbe | Gerd Hoffmann | uint8_t *p; |
1114 | ce512ee1 | Bernhard Kohl | uint8_t dev_specific_param; |
1115 | ebddfcbe | Gerd Hoffmann | |
1116 | e590ecbe | Paolo Bonzini | dbd = (r->req.cmd.buf[1] & 0x8) != 0; |
1117 | cfc606da | Paolo Bonzini | page = r->req.cmd.buf[2] & 0x3f; |
1118 | cfc606da | Paolo Bonzini | page_control = (r->req.cmd.buf[2] & 0xc0) >> 6; |
1119 | aa2b1e89 | Bernhard Kohl | DPRINTF("Mode Sense(%d) (page %d, xfer %zd, page_control %d)\n",
|
1120 | cfc606da | Paolo Bonzini | (r->req.cmd.buf[0] == MODE_SENSE) ? 6 : 10, page, r->req.cmd.xfer, page_control); |
1121 | cfc606da | Paolo Bonzini | memset(outbuf, 0, r->req.cmd.xfer);
|
1122 | ebddfcbe | Gerd Hoffmann | p = outbuf; |
1123 | ebddfcbe | Gerd Hoffmann | |
1124 | e590ecbe | Paolo Bonzini | if (s->qdev.type == TYPE_DISK) {
|
1125 | da8365db | Paolo Bonzini | dev_specific_param = s->features & (1 << SCSI_DISK_F_DPOFUA) ? 0x10 : 0; |
1126 | e590ecbe | Paolo Bonzini | if (bdrv_is_read_only(s->qdev.conf.bs)) {
|
1127 | e590ecbe | Paolo Bonzini | dev_specific_param |= 0x80; /* Readonly. */ |
1128 | e590ecbe | Paolo Bonzini | } |
1129 | ce512ee1 | Bernhard Kohl | } else {
|
1130 | e590ecbe | Paolo Bonzini | /* MMC prescribes that CD/DVD drives have no block descriptors,
|
1131 | e590ecbe | Paolo Bonzini | * and defines no device-specific parameter. */
|
1132 | 6a2de0f2 | Paolo Bonzini | dev_specific_param = 0x00;
|
1133 | e590ecbe | Paolo Bonzini | dbd = true;
|
1134 | ce512ee1 | Bernhard Kohl | } |
1135 | ce512ee1 | Bernhard Kohl | |
1136 | cfc606da | Paolo Bonzini | if (r->req.cmd.buf[0] == MODE_SENSE) { |
1137 | ce512ee1 | Bernhard Kohl | p[1] = 0; /* Default media type. */ |
1138 | ce512ee1 | Bernhard Kohl | p[2] = dev_specific_param;
|
1139 | ce512ee1 | Bernhard Kohl | p[3] = 0; /* Block descriptor length. */ |
1140 | ce512ee1 | Bernhard Kohl | p += 4;
|
1141 | ce512ee1 | Bernhard Kohl | } else { /* MODE_SENSE_10 */ |
1142 | ce512ee1 | Bernhard Kohl | p[2] = 0; /* Default media type. */ |
1143 | ce512ee1 | Bernhard Kohl | p[3] = dev_specific_param;
|
1144 | ce512ee1 | Bernhard Kohl | p[6] = p[7] = 0; /* Block descriptor length. */ |
1145 | ce512ee1 | Bernhard Kohl | p += 8;
|
1146 | ebddfcbe | Gerd Hoffmann | } |
1147 | ebddfcbe | Gerd Hoffmann | |
1148 | 44740c38 | Paolo Bonzini | bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors); |
1149 | e590ecbe | Paolo Bonzini | if (!dbd && nb_sectors) {
|
1150 | cfc606da | Paolo Bonzini | if (r->req.cmd.buf[0] == MODE_SENSE) { |
1151 | ce512ee1 | Bernhard Kohl | outbuf[3] = 8; /* Block descriptor length */ |
1152 | ce512ee1 | Bernhard Kohl | } else { /* MODE_SENSE_10 */ |
1153 | ce512ee1 | Bernhard Kohl | outbuf[7] = 8; /* Block descriptor length */ |
1154 | ce512ee1 | Bernhard Kohl | } |
1155 | 69377307 | Paolo Bonzini | nb_sectors /= (s->qdev.blocksize / 512);
|
1156 | f01b5931 | Paolo Bonzini | if (nb_sectors > 0xffffff) { |
1157 | 2488b740 | Bernhard Kohl | nb_sectors = 0;
|
1158 | f01b5931 | Paolo Bonzini | } |
1159 | ebddfcbe | Gerd Hoffmann | p[0] = 0; /* media density code */ |
1160 | ebddfcbe | Gerd Hoffmann | p[1] = (nb_sectors >> 16) & 0xff; |
1161 | ebddfcbe | Gerd Hoffmann | p[2] = (nb_sectors >> 8) & 0xff; |
1162 | ebddfcbe | Gerd Hoffmann | p[3] = nb_sectors & 0xff; |
1163 | ebddfcbe | Gerd Hoffmann | p[4] = 0; /* reserved */ |
1164 | ebddfcbe | Gerd Hoffmann | p[5] = 0; /* bytes 5-7 are the sector size in bytes */ |
1165 | 69377307 | Paolo Bonzini | p[6] = s->qdev.blocksize >> 8; |
1166 | ebddfcbe | Gerd Hoffmann | p[7] = 0; |
1167 | ebddfcbe | Gerd Hoffmann | p += 8;
|
1168 | ebddfcbe | Gerd Hoffmann | } |
1169 | ebddfcbe | Gerd Hoffmann | |
1170 | cfc606da | Paolo Bonzini | if (page_control == 3) { |
1171 | cfc606da | Paolo Bonzini | /* Saved Values */
|
1172 | cfc606da | Paolo Bonzini | scsi_check_condition(r, SENSE_CODE(SAVING_PARAMS_NOT_SUPPORTED)); |
1173 | cfc606da | Paolo Bonzini | return -1; |
1174 | 282ab04e | Bernhard Kohl | } |
1175 | 282ab04e | Bernhard Kohl | |
1176 | cfc606da | Paolo Bonzini | if (page == 0x3f) { |
1177 | cfc606da | Paolo Bonzini | for (page = 0; page <= 0x3e; page++) { |
1178 | cfc606da | Paolo Bonzini | mode_sense_page(s, page, &p, page_control); |
1179 | cfc606da | Paolo Bonzini | } |
1180 | cfc606da | Paolo Bonzini | } else {
|
1181 | cfc606da | Paolo Bonzini | ret = mode_sense_page(s, page, &p, page_control); |
1182 | cfc606da | Paolo Bonzini | if (ret == -1) { |
1183 | cfc606da | Paolo Bonzini | return -1; |
1184 | cfc606da | Paolo Bonzini | } |
1185 | ebddfcbe | Gerd Hoffmann | } |
1186 | ebddfcbe | Gerd Hoffmann | |
1187 | ebddfcbe | Gerd Hoffmann | buflen = p - outbuf; |
1188 | ce512ee1 | Bernhard Kohl | /*
|
1189 | ce512ee1 | Bernhard Kohl | * The mode data length field specifies the length in bytes of the
|
1190 | ce512ee1 | Bernhard Kohl | * following data that is available to be transferred. The mode data
|
1191 | ce512ee1 | Bernhard Kohl | * length does not include itself.
|
1192 | ce512ee1 | Bernhard Kohl | */
|
1193 | cfc606da | Paolo Bonzini | if (r->req.cmd.buf[0] == MODE_SENSE) { |
1194 | ce512ee1 | Bernhard Kohl | outbuf[0] = buflen - 1; |
1195 | ce512ee1 | Bernhard Kohl | } else { /* MODE_SENSE_10 */ |
1196 | ce512ee1 | Bernhard Kohl | outbuf[0] = ((buflen - 2) >> 8) & 0xff; |
1197 | ce512ee1 | Bernhard Kohl | outbuf[1] = (buflen - 2) & 0xff; |
1198 | ce512ee1 | Bernhard Kohl | } |
1199 | ebddfcbe | Gerd Hoffmann | return buflen;
|
1200 | ebddfcbe | Gerd Hoffmann | } |
1201 | ebddfcbe | Gerd Hoffmann | |
1202 | 02880f43 | Gerd Hoffmann | static int scsi_disk_emulate_read_toc(SCSIRequest *req, uint8_t *outbuf) |
1203 | 02880f43 | Gerd Hoffmann | { |
1204 | 02880f43 | Gerd Hoffmann | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); |
1205 | 02880f43 | Gerd Hoffmann | int start_track, format, msf, toclen;
|
1206 | 02880f43 | Gerd Hoffmann | uint64_t nb_sectors; |
1207 | 02880f43 | Gerd Hoffmann | |
1208 | 02880f43 | Gerd Hoffmann | msf = req->cmd.buf[1] & 2; |
1209 | 02880f43 | Gerd Hoffmann | format = req->cmd.buf[2] & 0xf; |
1210 | 02880f43 | Gerd Hoffmann | start_track = req->cmd.buf[6];
|
1211 | 44740c38 | Paolo Bonzini | bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors); |
1212 | 02880f43 | Gerd Hoffmann | DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1); |
1213 | 69377307 | Paolo Bonzini | nb_sectors /= s->qdev.blocksize / 512;
|
1214 | 02880f43 | Gerd Hoffmann | switch (format) {
|
1215 | 02880f43 | Gerd Hoffmann | case 0: |
1216 | 02880f43 | Gerd Hoffmann | toclen = cdrom_read_toc(nb_sectors, outbuf, msf, start_track); |
1217 | 02880f43 | Gerd Hoffmann | break;
|
1218 | 02880f43 | Gerd Hoffmann | case 1: |
1219 | 02880f43 | Gerd Hoffmann | /* multi session : only a single session defined */
|
1220 | 02880f43 | Gerd Hoffmann | toclen = 12;
|
1221 | 02880f43 | Gerd Hoffmann | memset(outbuf, 0, 12); |
1222 | 02880f43 | Gerd Hoffmann | outbuf[1] = 0x0a; |
1223 | 02880f43 | Gerd Hoffmann | outbuf[2] = 0x01; |
1224 | 02880f43 | Gerd Hoffmann | outbuf[3] = 0x01; |
1225 | 02880f43 | Gerd Hoffmann | break;
|
1226 | 02880f43 | Gerd Hoffmann | case 2: |
1227 | 02880f43 | Gerd Hoffmann | toclen = cdrom_read_toc_raw(nb_sectors, outbuf, msf, start_track); |
1228 | 02880f43 | Gerd Hoffmann | break;
|
1229 | 02880f43 | Gerd Hoffmann | default:
|
1230 | 02880f43 | Gerd Hoffmann | return -1; |
1231 | 02880f43 | Gerd Hoffmann | } |
1232 | 02880f43 | Gerd Hoffmann | return toclen;
|
1233 | 02880f43 | Gerd Hoffmann | } |
1234 | 02880f43 | Gerd Hoffmann | |
1235 | 68bb01f3 | Markus Armbruster | static int scsi_disk_emulate_start_stop(SCSIDiskReq *r) |
1236 | bfd52647 | Markus Armbruster | { |
1237 | bfd52647 | Markus Armbruster | SCSIRequest *req = &r->req; |
1238 | bfd52647 | Markus Armbruster | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); |
1239 | bfd52647 | Markus Armbruster | bool start = req->cmd.buf[4] & 1; |
1240 | bfd52647 | Markus Armbruster | bool loej = req->cmd.buf[4] & 2; /* load on start, eject on !start */ |
1241 | ae5708b3 | Ronnie Sahlberg | int pwrcnd = req->cmd.buf[4] & 0xf0; |
1242 | ae5708b3 | Ronnie Sahlberg | |
1243 | ae5708b3 | Ronnie Sahlberg | if (pwrcnd) {
|
1244 | ae5708b3 | Ronnie Sahlberg | /* eject/load only happens for power condition == 0 */
|
1245 | ae5708b3 | Ronnie Sahlberg | return 0; |
1246 | ae5708b3 | Ronnie Sahlberg | } |
1247 | bfd52647 | Markus Armbruster | |
1248 | b456a71c | Paolo Bonzini | if ((s->features & (1 << SCSI_DISK_F_REMOVABLE)) && loej) { |
1249 | 68bb01f3 | Markus Armbruster | if (!start && !s->tray_open && s->tray_locked) {
|
1250 | 68bb01f3 | Markus Armbruster | scsi_check_condition(r, |
1251 | 44740c38 | Paolo Bonzini | bdrv_is_inserted(s->qdev.conf.bs) |
1252 | 68bb01f3 | Markus Armbruster | ? SENSE_CODE(ILLEGAL_REQ_REMOVAL_PREVENTED) |
1253 | 68bb01f3 | Markus Armbruster | : SENSE_CODE(NOT_READY_REMOVAL_PREVENTED)); |
1254 | 68bb01f3 | Markus Armbruster | return -1; |
1255 | fdec4404 | Markus Armbruster | } |
1256 | d88b1819 | Luiz Capitulino | |
1257 | d88b1819 | Luiz Capitulino | if (s->tray_open != !start) {
|
1258 | d88b1819 | Luiz Capitulino | bdrv_eject(s->qdev.conf.bs, !start); |
1259 | d88b1819 | Luiz Capitulino | s->tray_open = !start; |
1260 | d88b1819 | Luiz Capitulino | } |
1261 | bfd52647 | Markus Armbruster | } |
1262 | 68bb01f3 | Markus Armbruster | return 0; |
1263 | bfd52647 | Markus Armbruster | } |
1264 | bfd52647 | Markus Armbruster | |
1265 | 314a3299 | Paolo Bonzini | static void scsi_disk_emulate_read_data(SCSIRequest *req) |
1266 | 314a3299 | Paolo Bonzini | { |
1267 | 314a3299 | Paolo Bonzini | SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); |
1268 | 314a3299 | Paolo Bonzini | int buflen = r->iov.iov_len;
|
1269 | 314a3299 | Paolo Bonzini | |
1270 | 314a3299 | Paolo Bonzini | if (buflen) {
|
1271 | 79fb50bb | Paolo Bonzini | DPRINTF("Read buf_len=%d\n", buflen);
|
1272 | 314a3299 | Paolo Bonzini | r->iov.iov_len = 0;
|
1273 | 314a3299 | Paolo Bonzini | r->started = true;
|
1274 | 314a3299 | Paolo Bonzini | scsi_req_data(&r->req, buflen); |
1275 | 314a3299 | Paolo Bonzini | return;
|
1276 | 314a3299 | Paolo Bonzini | } |
1277 | 314a3299 | Paolo Bonzini | |
1278 | 314a3299 | Paolo Bonzini | /* This also clears the sense buffer for REQUEST SENSE. */
|
1279 | 314a3299 | Paolo Bonzini | scsi_req_complete(&r->req, GOOD); |
1280 | 314a3299 | Paolo Bonzini | } |
1281 | 314a3299 | Paolo Bonzini | |
1282 | 380feaff | Paolo Bonzini | static int scsi_disk_check_mode_select(SCSIDiskState *s, int page, |
1283 | 380feaff | Paolo Bonzini | uint8_t *inbuf, int inlen)
|
1284 | 380feaff | Paolo Bonzini | { |
1285 | 380feaff | Paolo Bonzini | uint8_t mode_current[SCSI_MAX_MODE_LEN]; |
1286 | 380feaff | Paolo Bonzini | uint8_t mode_changeable[SCSI_MAX_MODE_LEN]; |
1287 | 380feaff | Paolo Bonzini | uint8_t *p; |
1288 | 380feaff | Paolo Bonzini | int len, expected_len, changeable_len, i;
|
1289 | 380feaff | Paolo Bonzini | |
1290 | 380feaff | Paolo Bonzini | /* The input buffer does not include the page header, so it is
|
1291 | 380feaff | Paolo Bonzini | * off by 2 bytes.
|
1292 | 380feaff | Paolo Bonzini | */
|
1293 | 380feaff | Paolo Bonzini | expected_len = inlen + 2;
|
1294 | 380feaff | Paolo Bonzini | if (expected_len > SCSI_MAX_MODE_LEN) {
|
1295 | 380feaff | Paolo Bonzini | return -1; |
1296 | 380feaff | Paolo Bonzini | } |
1297 | 380feaff | Paolo Bonzini | |
1298 | 380feaff | Paolo Bonzini | p = mode_current; |
1299 | 380feaff | Paolo Bonzini | memset(mode_current, 0, inlen + 2); |
1300 | 380feaff | Paolo Bonzini | len = mode_sense_page(s, page, &p, 0);
|
1301 | 380feaff | Paolo Bonzini | if (len < 0 || len != expected_len) { |
1302 | 380feaff | Paolo Bonzini | return -1; |
1303 | 380feaff | Paolo Bonzini | } |
1304 | 380feaff | Paolo Bonzini | |
1305 | 380feaff | Paolo Bonzini | p = mode_changeable; |
1306 | 380feaff | Paolo Bonzini | memset(mode_changeable, 0, inlen + 2); |
1307 | 380feaff | Paolo Bonzini | changeable_len = mode_sense_page(s, page, &p, 1);
|
1308 | 380feaff | Paolo Bonzini | assert(changeable_len == len); |
1309 | 380feaff | Paolo Bonzini | |
1310 | 380feaff | Paolo Bonzini | /* Check that unchangeable bits are the same as what MODE SENSE
|
1311 | 380feaff | Paolo Bonzini | * would return.
|
1312 | 380feaff | Paolo Bonzini | */
|
1313 | 380feaff | Paolo Bonzini | for (i = 2; i < len; i++) { |
1314 | 380feaff | Paolo Bonzini | if (((mode_current[i] ^ inbuf[i - 2]) & ~mode_changeable[i]) != 0) { |
1315 | 380feaff | Paolo Bonzini | return -1; |
1316 | 380feaff | Paolo Bonzini | } |
1317 | 380feaff | Paolo Bonzini | } |
1318 | 380feaff | Paolo Bonzini | return 0; |
1319 | 380feaff | Paolo Bonzini | } |
1320 | 380feaff | Paolo Bonzini | |
1321 | 380feaff | Paolo Bonzini | static void scsi_disk_apply_mode_select(SCSIDiskState *s, int page, uint8_t *p) |
1322 | 380feaff | Paolo Bonzini | { |
1323 | 96c91bbf | Paolo Bonzini | switch (page) {
|
1324 | 96c91bbf | Paolo Bonzini | case MODE_PAGE_CACHING:
|
1325 | 96c91bbf | Paolo Bonzini | bdrv_set_enable_write_cache(s->qdev.conf.bs, (p[0] & 4) != 0); |
1326 | 96c91bbf | Paolo Bonzini | break;
|
1327 | 96c91bbf | Paolo Bonzini | |
1328 | 96c91bbf | Paolo Bonzini | default:
|
1329 | 96c91bbf | Paolo Bonzini | break;
|
1330 | 96c91bbf | Paolo Bonzini | } |
1331 | 380feaff | Paolo Bonzini | } |
1332 | 380feaff | Paolo Bonzini | |
1333 | 380feaff | Paolo Bonzini | static int mode_select_pages(SCSIDiskReq *r, uint8_t *p, int len, bool change) |
1334 | 380feaff | Paolo Bonzini | { |
1335 | 380feaff | Paolo Bonzini | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); |
1336 | 380feaff | Paolo Bonzini | |
1337 | 380feaff | Paolo Bonzini | while (len > 0) { |
1338 | 380feaff | Paolo Bonzini | int page, subpage, page_len;
|
1339 | 380feaff | Paolo Bonzini | |
1340 | 380feaff | Paolo Bonzini | /* Parse both possible formats for the mode page headers. */
|
1341 | 380feaff | Paolo Bonzini | page = p[0] & 0x3f; |
1342 | 380feaff | Paolo Bonzini | if (p[0] & 0x40) { |
1343 | 380feaff | Paolo Bonzini | if (len < 4) { |
1344 | 380feaff | Paolo Bonzini | goto invalid_param_len;
|
1345 | 380feaff | Paolo Bonzini | } |
1346 | 380feaff | Paolo Bonzini | subpage = p[1];
|
1347 | 380feaff | Paolo Bonzini | page_len = lduw_be_p(&p[2]);
|
1348 | 380feaff | Paolo Bonzini | p += 4;
|
1349 | 380feaff | Paolo Bonzini | len -= 4;
|
1350 | 380feaff | Paolo Bonzini | } else {
|
1351 | 380feaff | Paolo Bonzini | if (len < 2) { |
1352 | 380feaff | Paolo Bonzini | goto invalid_param_len;
|
1353 | 380feaff | Paolo Bonzini | } |
1354 | 380feaff | Paolo Bonzini | subpage = 0;
|
1355 | 380feaff | Paolo Bonzini | page_len = p[1];
|
1356 | 380feaff | Paolo Bonzini | p += 2;
|
1357 | 380feaff | Paolo Bonzini | len -= 2;
|
1358 | 380feaff | Paolo Bonzini | } |
1359 | 380feaff | Paolo Bonzini | |
1360 | 380feaff | Paolo Bonzini | if (subpage) {
|
1361 | 380feaff | Paolo Bonzini | goto invalid_param;
|
1362 | 380feaff | Paolo Bonzini | } |
1363 | 380feaff | Paolo Bonzini | if (page_len > len) {
|
1364 | 380feaff | Paolo Bonzini | goto invalid_param_len;
|
1365 | 380feaff | Paolo Bonzini | } |
1366 | 380feaff | Paolo Bonzini | |
1367 | 380feaff | Paolo Bonzini | if (!change) {
|
1368 | 380feaff | Paolo Bonzini | if (scsi_disk_check_mode_select(s, page, p, page_len) < 0) { |
1369 | 380feaff | Paolo Bonzini | goto invalid_param;
|
1370 | 380feaff | Paolo Bonzini | } |
1371 | 380feaff | Paolo Bonzini | } else {
|
1372 | 380feaff | Paolo Bonzini | scsi_disk_apply_mode_select(s, page, p); |
1373 | 380feaff | Paolo Bonzini | } |
1374 | 380feaff | Paolo Bonzini | |
1375 | 380feaff | Paolo Bonzini | p += page_len; |
1376 | 380feaff | Paolo Bonzini | len -= page_len; |
1377 | 380feaff | Paolo Bonzini | } |
1378 | 380feaff | Paolo Bonzini | return 0; |
1379 | 380feaff | Paolo Bonzini | |
1380 | 380feaff | Paolo Bonzini | invalid_param:
|
1381 | 380feaff | Paolo Bonzini | scsi_check_condition(r, SENSE_CODE(INVALID_PARAM)); |
1382 | 380feaff | Paolo Bonzini | return -1; |
1383 | 380feaff | Paolo Bonzini | |
1384 | 380feaff | Paolo Bonzini | invalid_param_len:
|
1385 | 380feaff | Paolo Bonzini | scsi_check_condition(r, SENSE_CODE(INVALID_PARAM_LEN)); |
1386 | 380feaff | Paolo Bonzini | return -1; |
1387 | 380feaff | Paolo Bonzini | } |
1388 | 380feaff | Paolo Bonzini | |
1389 | 380feaff | Paolo Bonzini | static void scsi_disk_emulate_mode_select(SCSIDiskReq *r, uint8_t *inbuf) |
1390 | 380feaff | Paolo Bonzini | { |
1391 | 380feaff | Paolo Bonzini | uint8_t *p = inbuf; |
1392 | 380feaff | Paolo Bonzini | int cmd = r->req.cmd.buf[0]; |
1393 | 380feaff | Paolo Bonzini | int len = r->req.cmd.xfer;
|
1394 | 380feaff | Paolo Bonzini | int hdr_len = (cmd == MODE_SELECT ? 4 : 8); |
1395 | 380feaff | Paolo Bonzini | int bd_len;
|
1396 | 380feaff | Paolo Bonzini | int pass;
|
1397 | 380feaff | Paolo Bonzini | |
1398 | 380feaff | Paolo Bonzini | /* We only support PF=1, SP=0. */
|
1399 | 380feaff | Paolo Bonzini | if ((r->req.cmd.buf[1] & 0x11) != 0x10) { |
1400 | 380feaff | Paolo Bonzini | goto invalid_field;
|
1401 | 380feaff | Paolo Bonzini | } |
1402 | 380feaff | Paolo Bonzini | |
1403 | 380feaff | Paolo Bonzini | if (len < hdr_len) {
|
1404 | 380feaff | Paolo Bonzini | goto invalid_param_len;
|
1405 | 380feaff | Paolo Bonzini | } |
1406 | 380feaff | Paolo Bonzini | |
1407 | 380feaff | Paolo Bonzini | bd_len = (cmd == MODE_SELECT ? p[3] : lduw_be_p(&p[6])); |
1408 | 380feaff | Paolo Bonzini | len -= hdr_len; |
1409 | 380feaff | Paolo Bonzini | p += hdr_len; |
1410 | 380feaff | Paolo Bonzini | if (len < bd_len) {
|
1411 | 380feaff | Paolo Bonzini | goto invalid_param_len;
|
1412 | 380feaff | Paolo Bonzini | } |
1413 | 380feaff | Paolo Bonzini | if (bd_len != 0 && bd_len != 8) { |
1414 | 380feaff | Paolo Bonzini | goto invalid_param;
|
1415 | 380feaff | Paolo Bonzini | } |
1416 | 380feaff | Paolo Bonzini | |
1417 | 380feaff | Paolo Bonzini | len -= bd_len; |
1418 | 380feaff | Paolo Bonzini | p += bd_len; |
1419 | 380feaff | Paolo Bonzini | |
1420 | 380feaff | Paolo Bonzini | /* Ensure no change is made if there is an error! */
|
1421 | 380feaff | Paolo Bonzini | for (pass = 0; pass < 2; pass++) { |
1422 | 380feaff | Paolo Bonzini | if (mode_select_pages(r, p, len, pass == 1) < 0) { |
1423 | 380feaff | Paolo Bonzini | assert(pass == 0);
|
1424 | 380feaff | Paolo Bonzini | return;
|
1425 | 380feaff | Paolo Bonzini | } |
1426 | 380feaff | Paolo Bonzini | } |
1427 | 380feaff | Paolo Bonzini | scsi_req_complete(&r->req, GOOD); |
1428 | 380feaff | Paolo Bonzini | return;
|
1429 | 380feaff | Paolo Bonzini | |
1430 | 380feaff | Paolo Bonzini | invalid_param:
|
1431 | 380feaff | Paolo Bonzini | scsi_check_condition(r, SENSE_CODE(INVALID_PARAM)); |
1432 | 380feaff | Paolo Bonzini | return;
|
1433 | 380feaff | Paolo Bonzini | |
1434 | 380feaff | Paolo Bonzini | invalid_param_len:
|
1435 | 380feaff | Paolo Bonzini | scsi_check_condition(r, SENSE_CODE(INVALID_PARAM_LEN)); |
1436 | 380feaff | Paolo Bonzini | return;
|
1437 | 380feaff | Paolo Bonzini | |
1438 | 380feaff | Paolo Bonzini | invalid_field:
|
1439 | 380feaff | Paolo Bonzini | scsi_check_condition(r, SENSE_CODE(INVALID_FIELD)); |
1440 | 380feaff | Paolo Bonzini | } |
1441 | 380feaff | Paolo Bonzini | |
1442 | 444bc908 | Paolo Bonzini | static inline bool check_lba_range(SCSIDiskState *s, |
1443 | 444bc908 | Paolo Bonzini | uint64_t sector_num, uint32_t nb_sectors) |
1444 | 444bc908 | Paolo Bonzini | { |
1445 | 444bc908 | Paolo Bonzini | /*
|
1446 | 444bc908 | Paolo Bonzini | * The first line tests that no overflow happens when computing the last
|
1447 | 444bc908 | Paolo Bonzini | * sector. The second line tests that the last accessed sector is in
|
1448 | 444bc908 | Paolo Bonzini | * range.
|
1449 | 12ca76fc | Paolo Bonzini | *
|
1450 | 12ca76fc | Paolo Bonzini | * Careful, the computations should not underflow for nb_sectors == 0,
|
1451 | 12ca76fc | Paolo Bonzini | * and a 0-block read to the first LBA beyond the end of device is
|
1452 | 12ca76fc | Paolo Bonzini | * valid.
|
1453 | 444bc908 | Paolo Bonzini | */
|
1454 | 444bc908 | Paolo Bonzini | return (sector_num <= sector_num + nb_sectors &&
|
1455 | 12ca76fc | Paolo Bonzini | sector_num + nb_sectors <= s->qdev.max_lba + 1);
|
1456 | 444bc908 | Paolo Bonzini | } |
1457 | 444bc908 | Paolo Bonzini | |
1458 | 5222aaf2 | Paolo Bonzini | typedef struct UnmapCBData { |
1459 | 5222aaf2 | Paolo Bonzini | SCSIDiskReq *r; |
1460 | 5222aaf2 | Paolo Bonzini | uint8_t *inbuf; |
1461 | 5222aaf2 | Paolo Bonzini | int count;
|
1462 | 5222aaf2 | Paolo Bonzini | } UnmapCBData; |
1463 | 5222aaf2 | Paolo Bonzini | |
1464 | 5222aaf2 | Paolo Bonzini | static void scsi_unmap_complete(void *opaque, int ret) |
1465 | 5222aaf2 | Paolo Bonzini | { |
1466 | 5222aaf2 | Paolo Bonzini | UnmapCBData *data = opaque; |
1467 | 5222aaf2 | Paolo Bonzini | SCSIDiskReq *r = data->r; |
1468 | 5222aaf2 | Paolo Bonzini | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); |
1469 | 5222aaf2 | Paolo Bonzini | uint64_t sector_num; |
1470 | 5bb0b62e | Stefan Weil | uint32_t nb_sectors; |
1471 | 5222aaf2 | Paolo Bonzini | |
1472 | 5222aaf2 | Paolo Bonzini | r->req.aiocb = NULL;
|
1473 | 5222aaf2 | Paolo Bonzini | if (ret < 0) { |
1474 | 5222aaf2 | Paolo Bonzini | if (scsi_handle_rw_error(r, -ret)) {
|
1475 | 5222aaf2 | Paolo Bonzini | goto done;
|
1476 | 5222aaf2 | Paolo Bonzini | } |
1477 | 5222aaf2 | Paolo Bonzini | } |
1478 | 5222aaf2 | Paolo Bonzini | |
1479 | 5222aaf2 | Paolo Bonzini | if (data->count > 0 && !r->req.io_canceled) { |
1480 | 5222aaf2 | Paolo Bonzini | sector_num = ldq_be_p(&data->inbuf[0]);
|
1481 | 5222aaf2 | Paolo Bonzini | nb_sectors = ldl_be_p(&data->inbuf[8]) & 0xffffffffULL; |
1482 | 444bc908 | Paolo Bonzini | if (!check_lba_range(s, sector_num, nb_sectors)) {
|
1483 | 5222aaf2 | Paolo Bonzini | scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE)); |
1484 | 5222aaf2 | Paolo Bonzini | goto done;
|
1485 | 5222aaf2 | Paolo Bonzini | } |
1486 | 5222aaf2 | Paolo Bonzini | |
1487 | 5222aaf2 | Paolo Bonzini | r->req.aiocb = bdrv_aio_discard(s->qdev.conf.bs, |
1488 | 5222aaf2 | Paolo Bonzini | sector_num * (s->qdev.blocksize / 512),
|
1489 | 5222aaf2 | Paolo Bonzini | nb_sectors * (s->qdev.blocksize / 512),
|
1490 | 5222aaf2 | Paolo Bonzini | scsi_unmap_complete, data); |
1491 | 5222aaf2 | Paolo Bonzini | data->count--; |
1492 | 5222aaf2 | Paolo Bonzini | data->inbuf += 16;
|
1493 | 5222aaf2 | Paolo Bonzini | return;
|
1494 | 5222aaf2 | Paolo Bonzini | } |
1495 | 5222aaf2 | Paolo Bonzini | |
1496 | 5222aaf2 | Paolo Bonzini | done:
|
1497 | 5222aaf2 | Paolo Bonzini | if (data->count == 0) { |
1498 | 5222aaf2 | Paolo Bonzini | scsi_req_complete(&r->req, GOOD); |
1499 | 5222aaf2 | Paolo Bonzini | } |
1500 | 5222aaf2 | Paolo Bonzini | if (!r->req.io_canceled) {
|
1501 | 5222aaf2 | Paolo Bonzini | scsi_req_unref(&r->req); |
1502 | 5222aaf2 | Paolo Bonzini | } |
1503 | 5222aaf2 | Paolo Bonzini | g_free(data); |
1504 | 5222aaf2 | Paolo Bonzini | } |
1505 | 5222aaf2 | Paolo Bonzini | |
1506 | 5222aaf2 | Paolo Bonzini | static void scsi_disk_emulate_unmap(SCSIDiskReq *r, uint8_t *inbuf) |
1507 | 5222aaf2 | Paolo Bonzini | { |
1508 | 5222aaf2 | Paolo Bonzini | uint8_t *p = inbuf; |
1509 | 5222aaf2 | Paolo Bonzini | int len = r->req.cmd.xfer;
|
1510 | 5222aaf2 | Paolo Bonzini | UnmapCBData *data; |
1511 | 5222aaf2 | Paolo Bonzini | |
1512 | 5222aaf2 | Paolo Bonzini | if (len < 8) { |
1513 | 5222aaf2 | Paolo Bonzini | goto invalid_param_len;
|
1514 | 5222aaf2 | Paolo Bonzini | } |
1515 | 5222aaf2 | Paolo Bonzini | if (len < lduw_be_p(&p[0]) + 2) { |
1516 | 5222aaf2 | Paolo Bonzini | goto invalid_param_len;
|
1517 | 5222aaf2 | Paolo Bonzini | } |
1518 | 5222aaf2 | Paolo Bonzini | if (len < lduw_be_p(&p[2]) + 8) { |
1519 | 5222aaf2 | Paolo Bonzini | goto invalid_param_len;
|
1520 | 5222aaf2 | Paolo Bonzini | } |
1521 | 5222aaf2 | Paolo Bonzini | if (lduw_be_p(&p[2]) & 15) { |
1522 | 5222aaf2 | Paolo Bonzini | goto invalid_param_len;
|
1523 | 5222aaf2 | Paolo Bonzini | } |
1524 | 5222aaf2 | Paolo Bonzini | |
1525 | 5222aaf2 | Paolo Bonzini | data = g_new0(UnmapCBData, 1);
|
1526 | 5222aaf2 | Paolo Bonzini | data->r = r; |
1527 | 5222aaf2 | Paolo Bonzini | data->inbuf = &p[8];
|
1528 | 5222aaf2 | Paolo Bonzini | data->count = lduw_be_p(&p[2]) >> 4; |
1529 | 5222aaf2 | Paolo Bonzini | |
1530 | 5222aaf2 | Paolo Bonzini | /* The matching unref is in scsi_unmap_complete, before data is freed. */
|
1531 | 5222aaf2 | Paolo Bonzini | scsi_req_ref(&r->req); |
1532 | 5222aaf2 | Paolo Bonzini | scsi_unmap_complete(data, 0);
|
1533 | 5222aaf2 | Paolo Bonzini | return;
|
1534 | 5222aaf2 | Paolo Bonzini | |
1535 | 5222aaf2 | Paolo Bonzini | invalid_param_len:
|
1536 | 5222aaf2 | Paolo Bonzini | scsi_check_condition(r, SENSE_CODE(INVALID_PARAM_LEN)); |
1537 | 5222aaf2 | Paolo Bonzini | } |
1538 | 5222aaf2 | Paolo Bonzini | |
1539 | 314a3299 | Paolo Bonzini | static void scsi_disk_emulate_write_data(SCSIRequest *req) |
1540 | 314a3299 | Paolo Bonzini | { |
1541 | af6d510d | Paolo Bonzini | SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); |
1542 | af6d510d | Paolo Bonzini | |
1543 | af6d510d | Paolo Bonzini | if (r->iov.iov_len) {
|
1544 | af6d510d | Paolo Bonzini | int buflen = r->iov.iov_len;
|
1545 | 79fb50bb | Paolo Bonzini | DPRINTF("Write buf_len=%d\n", buflen);
|
1546 | af6d510d | Paolo Bonzini | r->iov.iov_len = 0;
|
1547 | af6d510d | Paolo Bonzini | scsi_req_data(&r->req, buflen); |
1548 | af6d510d | Paolo Bonzini | return;
|
1549 | af6d510d | Paolo Bonzini | } |
1550 | af6d510d | Paolo Bonzini | |
1551 | af6d510d | Paolo Bonzini | switch (req->cmd.buf[0]) { |
1552 | af6d510d | Paolo Bonzini | case MODE_SELECT:
|
1553 | af6d510d | Paolo Bonzini | case MODE_SELECT_10:
|
1554 | af6d510d | Paolo Bonzini | /* This also clears the sense buffer for REQUEST SENSE. */
|
1555 | 380feaff | Paolo Bonzini | scsi_disk_emulate_mode_select(r, r->iov.iov_base); |
1556 | af6d510d | Paolo Bonzini | break;
|
1557 | af6d510d | Paolo Bonzini | |
1558 | 5222aaf2 | Paolo Bonzini | case UNMAP:
|
1559 | 5222aaf2 | Paolo Bonzini | scsi_disk_emulate_unmap(r, r->iov.iov_base); |
1560 | 5222aaf2 | Paolo Bonzini | break;
|
1561 | 5222aaf2 | Paolo Bonzini | |
1562 | af6d510d | Paolo Bonzini | default:
|
1563 | af6d510d | Paolo Bonzini | abort(); |
1564 | af6d510d | Paolo Bonzini | } |
1565 | 314a3299 | Paolo Bonzini | } |
1566 | 314a3299 | Paolo Bonzini | |
1567 | b08d0ea0 | Paolo Bonzini | static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
|
1568 | aa5dbdc1 | Gerd Hoffmann | { |
1569 | b08d0ea0 | Paolo Bonzini | SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); |
1570 | e7e25e32 | Gerd Hoffmann | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); |
1571 | e7e25e32 | Gerd Hoffmann | uint64_t nb_sectors; |
1572 | 7285477a | Paolo Bonzini | uint8_t *outbuf; |
1573 | af6d510d | Paolo Bonzini | int buflen;
|
1574 | aa5dbdc1 | Gerd Hoffmann | |
1575 | b08d0ea0 | Paolo Bonzini | switch (req->cmd.buf[0]) { |
1576 | b08d0ea0 | Paolo Bonzini | case INQUIRY:
|
1577 | b08d0ea0 | Paolo Bonzini | case MODE_SENSE:
|
1578 | b08d0ea0 | Paolo Bonzini | case MODE_SENSE_10:
|
1579 | b08d0ea0 | Paolo Bonzini | case RESERVE:
|
1580 | b08d0ea0 | Paolo Bonzini | case RESERVE_10:
|
1581 | b08d0ea0 | Paolo Bonzini | case RELEASE:
|
1582 | b08d0ea0 | Paolo Bonzini | case RELEASE_10:
|
1583 | b08d0ea0 | Paolo Bonzini | case START_STOP:
|
1584 | b08d0ea0 | Paolo Bonzini | case ALLOW_MEDIUM_REMOVAL:
|
1585 | b08d0ea0 | Paolo Bonzini | case GET_CONFIGURATION:
|
1586 | b08d0ea0 | Paolo Bonzini | case GET_EVENT_STATUS_NOTIFICATION:
|
1587 | b08d0ea0 | Paolo Bonzini | case MECHANISM_STATUS:
|
1588 | b08d0ea0 | Paolo Bonzini | case REQUEST_SENSE:
|
1589 | b08d0ea0 | Paolo Bonzini | break;
|
1590 | b08d0ea0 | Paolo Bonzini | |
1591 | b08d0ea0 | Paolo Bonzini | default:
|
1592 | b08d0ea0 | Paolo Bonzini | if (s->tray_open || !bdrv_is_inserted(s->qdev.conf.bs)) {
|
1593 | b08d0ea0 | Paolo Bonzini | scsi_check_condition(r, SENSE_CODE(NO_MEDIUM)); |
1594 | b08d0ea0 | Paolo Bonzini | return 0; |
1595 | b08d0ea0 | Paolo Bonzini | } |
1596 | b08d0ea0 | Paolo Bonzini | break;
|
1597 | b08d0ea0 | Paolo Bonzini | } |
1598 | b08d0ea0 | Paolo Bonzini | |
1599 | 7285477a | Paolo Bonzini | if (!r->iov.iov_base) {
|
1600 | 7285477a | Paolo Bonzini | /*
|
1601 | 7285477a | Paolo Bonzini | * FIXME: we shouldn't return anything bigger than 4k, but the code
|
1602 | 7285477a | Paolo Bonzini | * requires the buffer to be as big as req->cmd.xfer in several
|
1603 | 7285477a | Paolo Bonzini | * places. So, do not allow CDBs with a very large ALLOCATION
|
1604 | 7285477a | Paolo Bonzini | * LENGTH. The real fix would be to modify scsi_read_data and
|
1605 | 7285477a | Paolo Bonzini | * dma_buf_read, so that they return data beyond the buflen
|
1606 | 7285477a | Paolo Bonzini | * as all zeros.
|
1607 | 7285477a | Paolo Bonzini | */
|
1608 | 7285477a | Paolo Bonzini | if (req->cmd.xfer > 65536) { |
1609 | 7285477a | Paolo Bonzini | goto illegal_request;
|
1610 | 7285477a | Paolo Bonzini | } |
1611 | 7285477a | Paolo Bonzini | r->buflen = MAX(4096, req->cmd.xfer);
|
1612 | 44740c38 | Paolo Bonzini | r->iov.iov_base = qemu_blockalign(s->qdev.conf.bs, r->buflen); |
1613 | 7285477a | Paolo Bonzini | } |
1614 | 7285477a | Paolo Bonzini | |
1615 | af6d510d | Paolo Bonzini | buflen = req->cmd.xfer; |
1616 | 7285477a | Paolo Bonzini | outbuf = r->iov.iov_base; |
1617 | aa5dbdc1 | Gerd Hoffmann | switch (req->cmd.buf[0]) { |
1618 | aa5dbdc1 | Gerd Hoffmann | case TEST_UNIT_READY:
|
1619 | 9bcaf4fe | Paolo Bonzini | assert(!s->tray_open && bdrv_is_inserted(s->qdev.conf.bs)); |
1620 | 5f71d32f | Hannes Reinecke | break;
|
1621 | 0b06c059 | Gerd Hoffmann | case INQUIRY:
|
1622 | 0b06c059 | Gerd Hoffmann | buflen = scsi_disk_emulate_inquiry(req, outbuf); |
1623 | f01b5931 | Paolo Bonzini | if (buflen < 0) { |
1624 | 0b06c059 | Gerd Hoffmann | goto illegal_request;
|
1625 | f01b5931 | Paolo Bonzini | } |
1626 | 5f71d32f | Hannes Reinecke | break;
|
1627 | ebddfcbe | Gerd Hoffmann | case MODE_SENSE:
|
1628 | ebddfcbe | Gerd Hoffmann | case MODE_SENSE_10:
|
1629 | cfc606da | Paolo Bonzini | buflen = scsi_disk_emulate_mode_sense(r, outbuf); |
1630 | f01b5931 | Paolo Bonzini | if (buflen < 0) { |
1631 | ebddfcbe | Gerd Hoffmann | goto illegal_request;
|
1632 | f01b5931 | Paolo Bonzini | } |
1633 | ebddfcbe | Gerd Hoffmann | break;
|
1634 | 02880f43 | Gerd Hoffmann | case READ_TOC:
|
1635 | 02880f43 | Gerd Hoffmann | buflen = scsi_disk_emulate_read_toc(req, outbuf); |
1636 | f01b5931 | Paolo Bonzini | if (buflen < 0) { |
1637 | 02880f43 | Gerd Hoffmann | goto illegal_request;
|
1638 | f01b5931 | Paolo Bonzini | } |
1639 | 02880f43 | Gerd Hoffmann | break;
|
1640 | 3d53ba18 | Gerd Hoffmann | case RESERVE:
|
1641 | f01b5931 | Paolo Bonzini | if (req->cmd.buf[1] & 1) { |
1642 | 3d53ba18 | Gerd Hoffmann | goto illegal_request;
|
1643 | f01b5931 | Paolo Bonzini | } |
1644 | 3d53ba18 | Gerd Hoffmann | break;
|
1645 | 3d53ba18 | Gerd Hoffmann | case RESERVE_10:
|
1646 | f01b5931 | Paolo Bonzini | if (req->cmd.buf[1] & 3) { |
1647 | 3d53ba18 | Gerd Hoffmann | goto illegal_request;
|
1648 | f01b5931 | Paolo Bonzini | } |
1649 | 3d53ba18 | Gerd Hoffmann | break;
|
1650 | 3d53ba18 | Gerd Hoffmann | case RELEASE:
|
1651 | f01b5931 | Paolo Bonzini | if (req->cmd.buf[1] & 1) { |
1652 | 3d53ba18 | Gerd Hoffmann | goto illegal_request;
|
1653 | f01b5931 | Paolo Bonzini | } |
1654 | 3d53ba18 | Gerd Hoffmann | break;
|
1655 | 3d53ba18 | Gerd Hoffmann | case RELEASE_10:
|
1656 | f01b5931 | Paolo Bonzini | if (req->cmd.buf[1] & 3) { |
1657 | 3d53ba18 | Gerd Hoffmann | goto illegal_request;
|
1658 | f01b5931 | Paolo Bonzini | } |
1659 | 3d53ba18 | Gerd Hoffmann | break;
|
1660 | 8d3628ff | Gerd Hoffmann | case START_STOP:
|
1661 | 68bb01f3 | Markus Armbruster | if (scsi_disk_emulate_start_stop(r) < 0) { |
1662 | b08d0ea0 | Paolo Bonzini | return 0; |
1663 | 68bb01f3 | Markus Armbruster | } |
1664 | 5f71d32f | Hannes Reinecke | break;
|
1665 | c68b9f34 | Gerd Hoffmann | case ALLOW_MEDIUM_REMOVAL:
|
1666 | 81b1008d | Markus Armbruster | s->tray_locked = req->cmd.buf[4] & 1; |
1667 | 44740c38 | Paolo Bonzini | bdrv_lock_medium(s->qdev.conf.bs, req->cmd.buf[4] & 1); |
1668 | 5f71d32f | Hannes Reinecke | break;
|
1669 | 5e30a07d | Hannes Reinecke | case READ_CAPACITY_10:
|
1670 | e7e25e32 | Gerd Hoffmann | /* The normal LEN field for this command is zero. */
|
1671 | 5f71d32f | Hannes Reinecke | memset(outbuf, 0, 8); |
1672 | 44740c38 | Paolo Bonzini | bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors); |
1673 | f01b5931 | Paolo Bonzini | if (!nb_sectors) {
|
1674 | 9bcaf4fe | Paolo Bonzini | scsi_check_condition(r, SENSE_CODE(LUN_NOT_READY)); |
1675 | 9bcaf4fe | Paolo Bonzini | return -1; |
1676 | f01b5931 | Paolo Bonzini | } |
1677 | 7cec78b6 | Paolo Bonzini | if ((req->cmd.buf[8] & 1) == 0 && req->cmd.lba) { |
1678 | 7cec78b6 | Paolo Bonzini | goto illegal_request;
|
1679 | 7cec78b6 | Paolo Bonzini | } |
1680 | 69377307 | Paolo Bonzini | nb_sectors /= s->qdev.blocksize / 512;
|
1681 | e7e25e32 | Gerd Hoffmann | /* Returned value is the address of the last sector. */
|
1682 | e7e25e32 | Gerd Hoffmann | nb_sectors--; |
1683 | e7e25e32 | Gerd Hoffmann | /* Remember the new size for read/write sanity checking. */
|
1684 | 7877903a | Paolo Bonzini | s->qdev.max_lba = nb_sectors; |
1685 | e7e25e32 | Gerd Hoffmann | /* Clip to 2TB, instead of returning capacity modulo 2TB. */
|
1686 | f01b5931 | Paolo Bonzini | if (nb_sectors > UINT32_MAX) {
|
1687 | e7e25e32 | Gerd Hoffmann | nb_sectors = UINT32_MAX; |
1688 | f01b5931 | Paolo Bonzini | } |
1689 | e7e25e32 | Gerd Hoffmann | outbuf[0] = (nb_sectors >> 24) & 0xff; |
1690 | e7e25e32 | Gerd Hoffmann | outbuf[1] = (nb_sectors >> 16) & 0xff; |
1691 | e7e25e32 | Gerd Hoffmann | outbuf[2] = (nb_sectors >> 8) & 0xff; |
1692 | e7e25e32 | Gerd Hoffmann | outbuf[3] = nb_sectors & 0xff; |
1693 | e7e25e32 | Gerd Hoffmann | outbuf[4] = 0; |
1694 | e7e25e32 | Gerd Hoffmann | outbuf[5] = 0; |
1695 | 69377307 | Paolo Bonzini | outbuf[6] = s->qdev.blocksize >> 8; |
1696 | e7e25e32 | Gerd Hoffmann | outbuf[7] = 0; |
1697 | e7e25e32 | Gerd Hoffmann | buflen = 8;
|
1698 | 5f71d32f | Hannes Reinecke | break;
|
1699 | f3b338ef | Paolo Bonzini | case REQUEST_SENSE:
|
1700 | f3b338ef | Paolo Bonzini | /* Just return "NO SENSE". */
|
1701 | f3b338ef | Paolo Bonzini | buflen = scsi_build_sense(NULL, 0, outbuf, r->buflen, |
1702 | f3b338ef | Paolo Bonzini | (req->cmd.buf[1] & 1) == 0); |
1703 | f3b338ef | Paolo Bonzini | break;
|
1704 | b6c251ab | Paolo Bonzini | case MECHANISM_STATUS:
|
1705 | b6c251ab | Paolo Bonzini | buflen = scsi_emulate_mechanism_status(s, outbuf); |
1706 | b6c251ab | Paolo Bonzini | if (buflen < 0) { |
1707 | b6c251ab | Paolo Bonzini | goto illegal_request;
|
1708 | b6c251ab | Paolo Bonzini | } |
1709 | b6c251ab | Paolo Bonzini | break;
|
1710 | 38215553 | Gerd Hoffmann | case GET_CONFIGURATION:
|
1711 | 430ee2f2 | Paolo Bonzini | buflen = scsi_get_configuration(s, outbuf); |
1712 | b6c251ab | Paolo Bonzini | if (buflen < 0) { |
1713 | b6c251ab | Paolo Bonzini | goto illegal_request;
|
1714 | b6c251ab | Paolo Bonzini | } |
1715 | b6c251ab | Paolo Bonzini | break;
|
1716 | b6c251ab | Paolo Bonzini | case GET_EVENT_STATUS_NOTIFICATION:
|
1717 | b6c251ab | Paolo Bonzini | buflen = scsi_get_event_status_notification(s, r, outbuf); |
1718 | b6c251ab | Paolo Bonzini | if (buflen < 0) { |
1719 | b6c251ab | Paolo Bonzini | goto illegal_request;
|
1720 | b6c251ab | Paolo Bonzini | } |
1721 | b6c251ab | Paolo Bonzini | break;
|
1722 | 1a4f0c3a | Paolo Bonzini | case READ_DISC_INFORMATION:
|
1723 | 1a4f0c3a | Paolo Bonzini | buflen = scsi_read_disc_information(s, r, outbuf); |
1724 | 1a4f0c3a | Paolo Bonzini | if (buflen < 0) { |
1725 | 1a4f0c3a | Paolo Bonzini | goto illegal_request;
|
1726 | 1a4f0c3a | Paolo Bonzini | } |
1727 | 1a4f0c3a | Paolo Bonzini | break;
|
1728 | b6c251ab | Paolo Bonzini | case READ_DVD_STRUCTURE:
|
1729 | b6c251ab | Paolo Bonzini | buflen = scsi_read_dvd_structure(s, r, outbuf); |
1730 | b6c251ab | Paolo Bonzini | if (buflen < 0) { |
1731 | b6c251ab | Paolo Bonzini | goto illegal_request;
|
1732 | b6c251ab | Paolo Bonzini | } |
1733 | 38215553 | Gerd Hoffmann | break;
|
1734 | f6515262 | Paolo Bonzini | case SERVICE_ACTION_IN_16:
|
1735 | 5dd90e2a | Gerd Hoffmann | /* Service Action In subcommands. */
|
1736 | f6515262 | Paolo Bonzini | if ((req->cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) { |
1737 | 5dd90e2a | Gerd Hoffmann | DPRINTF("SAI READ CAPACITY(16)\n");
|
1738 | 5dd90e2a | Gerd Hoffmann | memset(outbuf, 0, req->cmd.xfer);
|
1739 | 44740c38 | Paolo Bonzini | bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors); |
1740 | f01b5931 | Paolo Bonzini | if (!nb_sectors) {
|
1741 | 9bcaf4fe | Paolo Bonzini | scsi_check_condition(r, SENSE_CODE(LUN_NOT_READY)); |
1742 | 9bcaf4fe | Paolo Bonzini | return -1; |
1743 | f01b5931 | Paolo Bonzini | } |
1744 | 7cec78b6 | Paolo Bonzini | if ((req->cmd.buf[14] & 1) == 0 && req->cmd.lba) { |
1745 | 7cec78b6 | Paolo Bonzini | goto illegal_request;
|
1746 | 7cec78b6 | Paolo Bonzini | } |
1747 | 69377307 | Paolo Bonzini | nb_sectors /= s->qdev.blocksize / 512;
|
1748 | 5dd90e2a | Gerd Hoffmann | /* Returned value is the address of the last sector. */
|
1749 | 5dd90e2a | Gerd Hoffmann | nb_sectors--; |
1750 | 5dd90e2a | Gerd Hoffmann | /* Remember the new size for read/write sanity checking. */
|
1751 | 7877903a | Paolo Bonzini | s->qdev.max_lba = nb_sectors; |
1752 | 5dd90e2a | Gerd Hoffmann | outbuf[0] = (nb_sectors >> 56) & 0xff; |
1753 | 5dd90e2a | Gerd Hoffmann | outbuf[1] = (nb_sectors >> 48) & 0xff; |
1754 | 5dd90e2a | Gerd Hoffmann | outbuf[2] = (nb_sectors >> 40) & 0xff; |
1755 | 5dd90e2a | Gerd Hoffmann | outbuf[3] = (nb_sectors >> 32) & 0xff; |
1756 | 5dd90e2a | Gerd Hoffmann | outbuf[4] = (nb_sectors >> 24) & 0xff; |
1757 | 5dd90e2a | Gerd Hoffmann | outbuf[5] = (nb_sectors >> 16) & 0xff; |
1758 | 5dd90e2a | Gerd Hoffmann | outbuf[6] = (nb_sectors >> 8) & 0xff; |
1759 | 5dd90e2a | Gerd Hoffmann | outbuf[7] = nb_sectors & 0xff; |
1760 | 5dd90e2a | Gerd Hoffmann | outbuf[8] = 0; |
1761 | 5dd90e2a | Gerd Hoffmann | outbuf[9] = 0; |
1762 | 69377307 | Paolo Bonzini | outbuf[10] = s->qdev.blocksize >> 8; |
1763 | 5dd90e2a | Gerd Hoffmann | outbuf[11] = 0; |
1764 | ee3659e3 | Christoph Hellwig | outbuf[12] = 0; |
1765 | ee3659e3 | Christoph Hellwig | outbuf[13] = get_physical_block_exp(&s->qdev.conf);
|
1766 | ea3bd56f | Christoph Hellwig | |
1767 | ea3bd56f | Christoph Hellwig | /* set TPE bit if the format supports discard */
|
1768 | ea3bd56f | Christoph Hellwig | if (s->qdev.conf.discard_granularity) {
|
1769 | ea3bd56f | Christoph Hellwig | outbuf[14] = 0x80; |
1770 | ea3bd56f | Christoph Hellwig | } |
1771 | ea3bd56f | Christoph Hellwig | |
1772 | 5dd90e2a | Gerd Hoffmann | /* Protection, exponent and lowest lba field left blank. */
|
1773 | 5dd90e2a | Gerd Hoffmann | buflen = req->cmd.xfer; |
1774 | 5dd90e2a | Gerd Hoffmann | break;
|
1775 | 5dd90e2a | Gerd Hoffmann | } |
1776 | 5dd90e2a | Gerd Hoffmann | DPRINTF("Unsupported Service Action In\n");
|
1777 | 5dd90e2a | Gerd Hoffmann | goto illegal_request;
|
1778 | 101aa85f | Paolo Bonzini | case SYNCHRONIZE_CACHE:
|
1779 | 101aa85f | Paolo Bonzini | /* The request is used as the AIO opaque value, so add a ref. */
|
1780 | 101aa85f | Paolo Bonzini | scsi_req_ref(&r->req); |
1781 | 101aa85f | Paolo Bonzini | bdrv_acct_start(s->qdev.conf.bs, &r->acct, 0, BDRV_ACCT_FLUSH);
|
1782 | 101aa85f | Paolo Bonzini | r->req.aiocb = bdrv_aio_flush(s->qdev.conf.bs, scsi_aio_complete, r); |
1783 | 101aa85f | Paolo Bonzini | return 0; |
1784 | 101aa85f | Paolo Bonzini | case SEEK_10:
|
1785 | 101aa85f | Paolo Bonzini | DPRINTF("Seek(10) (sector %" PRId64 ")\n", r->req.cmd.lba); |
1786 | 101aa85f | Paolo Bonzini | if (r->req.cmd.lba > s->qdev.max_lba) {
|
1787 | 101aa85f | Paolo Bonzini | goto illegal_lba;
|
1788 | 101aa85f | Paolo Bonzini | } |
1789 | 101aa85f | Paolo Bonzini | break;
|
1790 | 101aa85f | Paolo Bonzini | case MODE_SELECT:
|
1791 | 101aa85f | Paolo Bonzini | DPRINTF("Mode Select(6) (len %lu)\n", (long)r->req.cmd.xfer); |
1792 | 101aa85f | Paolo Bonzini | break;
|
1793 | 101aa85f | Paolo Bonzini | case MODE_SELECT_10:
|
1794 | 101aa85f | Paolo Bonzini | DPRINTF("Mode Select(10) (len %lu)\n", (long)r->req.cmd.xfer); |
1795 | 101aa85f | Paolo Bonzini | break;
|
1796 | 5222aaf2 | Paolo Bonzini | case UNMAP:
|
1797 | 5222aaf2 | Paolo Bonzini | DPRINTF("Unmap (len %lu)\n", (long)r->req.cmd.xfer); |
1798 | 5222aaf2 | Paolo Bonzini | break;
|
1799 | 101aa85f | Paolo Bonzini | case WRITE_SAME_10:
|
1800 | 101aa85f | Paolo Bonzini | case WRITE_SAME_16:
|
1801 | e93176d5 | Paolo Bonzini | nb_sectors = scsi_data_cdb_length(r->req.cmd.buf); |
1802 | 6a8a685c | Ronnie Sahlberg | if (bdrv_is_read_only(s->qdev.conf.bs)) {
|
1803 | 6a8a685c | Ronnie Sahlberg | scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED)); |
1804 | 6a8a685c | Ronnie Sahlberg | return 0; |
1805 | 6a8a685c | Ronnie Sahlberg | } |
1806 | 444bc908 | Paolo Bonzini | if (!check_lba_range(s, r->req.cmd.lba, nb_sectors)) {
|
1807 | 101aa85f | Paolo Bonzini | goto illegal_lba;
|
1808 | 101aa85f | Paolo Bonzini | } |
1809 | 101aa85f | Paolo Bonzini | |
1810 | 101aa85f | Paolo Bonzini | /*
|
1811 | 101aa85f | Paolo Bonzini | * We only support WRITE SAME with the unmap bit set for now.
|
1812 | 101aa85f | Paolo Bonzini | */
|
1813 | 101aa85f | Paolo Bonzini | if (!(req->cmd.buf[1] & 0x8)) { |
1814 | 101aa85f | Paolo Bonzini | goto illegal_request;
|
1815 | 101aa85f | Paolo Bonzini | } |
1816 | 101aa85f | Paolo Bonzini | |
1817 | 101aa85f | Paolo Bonzini | /* The request is used as the AIO opaque value, so add a ref. */
|
1818 | 101aa85f | Paolo Bonzini | scsi_req_ref(&r->req); |
1819 | 101aa85f | Paolo Bonzini | r->req.aiocb = bdrv_aio_discard(s->qdev.conf.bs, |
1820 | 101aa85f | Paolo Bonzini | r->req.cmd.lba * (s->qdev.blocksize / 512),
|
1821 | 101aa85f | Paolo Bonzini | nb_sectors * (s->qdev.blocksize / 512),
|
1822 | 101aa85f | Paolo Bonzini | scsi_aio_complete, r); |
1823 | 101aa85f | Paolo Bonzini | return 0; |
1824 | aa5dbdc1 | Gerd Hoffmann | default:
|
1825 | b08d0ea0 | Paolo Bonzini | DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]); |
1826 | b45ef674 | Paolo Bonzini | scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE)); |
1827 | b08d0ea0 | Paolo Bonzini | return 0; |
1828 | aa5dbdc1 | Gerd Hoffmann | } |
1829 | 314a3299 | Paolo Bonzini | assert(!r->req.aiocb); |
1830 | b08d0ea0 | Paolo Bonzini | r->iov.iov_len = MIN(buflen, req->cmd.xfer); |
1831 | b08d0ea0 | Paolo Bonzini | if (r->iov.iov_len == 0) { |
1832 | b08d0ea0 | Paolo Bonzini | scsi_req_complete(&r->req, GOOD); |
1833 | b08d0ea0 | Paolo Bonzini | } |
1834 | af6d510d | Paolo Bonzini | if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
|
1835 | af6d510d | Paolo Bonzini | assert(r->iov.iov_len == req->cmd.xfer); |
1836 | af6d510d | Paolo Bonzini | return -r->iov.iov_len;
|
1837 | af6d510d | Paolo Bonzini | } else {
|
1838 | af6d510d | Paolo Bonzini | return r->iov.iov_len;
|
1839 | af6d510d | Paolo Bonzini | } |
1840 | aa5dbdc1 | Gerd Hoffmann | |
1841 | aa5dbdc1 | Gerd Hoffmann | illegal_request:
|
1842 | cfc606da | Paolo Bonzini | if (r->req.status == -1) { |
1843 | cfc606da | Paolo Bonzini | scsi_check_condition(r, SENSE_CODE(INVALID_FIELD)); |
1844 | cfc606da | Paolo Bonzini | } |
1845 | b08d0ea0 | Paolo Bonzini | return 0; |
1846 | 101aa85f | Paolo Bonzini | |
1847 | 101aa85f | Paolo Bonzini | illegal_lba:
|
1848 | 101aa85f | Paolo Bonzini | scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE)); |
1849 | 101aa85f | Paolo Bonzini | return 0; |
1850 | aa5dbdc1 | Gerd Hoffmann | } |
1851 | aa5dbdc1 | Gerd Hoffmann | |
1852 | 2e5d83bb | pbrook | /* Execute a scsi command. Returns the length of the data expected by the
|
1853 | 2e5d83bb | pbrook | command. This will be Positive for data transfers from the device
|
1854 | 2e5d83bb | pbrook | (eg. disk reads), negative for transfers to the device (eg. disk writes),
|
1855 | 2e5d83bb | pbrook | and zero if the command does not transfer any data. */
|
1856 | 2e5d83bb | pbrook | |
1857 | b08d0ea0 | Paolo Bonzini | static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf)
|
1858 | 2e5d83bb | pbrook | { |
1859 | 5c6c0e51 | Hannes Reinecke | SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); |
1860 | 5c6c0e51 | Hannes Reinecke | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); |
1861 | e93176d5 | Paolo Bonzini | uint32_t len; |
1862 | a917d384 | pbrook | uint8_t command; |
1863 | a917d384 | pbrook | |
1864 | a917d384 | pbrook | command = buf[0];
|
1865 | aa5dbdc1 | Gerd Hoffmann | |
1866 | b08d0ea0 | Paolo Bonzini | if (s->tray_open || !bdrv_is_inserted(s->qdev.conf.bs)) {
|
1867 | b08d0ea0 | Paolo Bonzini | scsi_check_condition(r, SENSE_CODE(NO_MEDIUM)); |
1868 | b08d0ea0 | Paolo Bonzini | return 0; |
1869 | 9bcaf4fe | Paolo Bonzini | } |
1870 | 9bcaf4fe | Paolo Bonzini | |
1871 | e93176d5 | Paolo Bonzini | len = scsi_data_cdb_length(r->req.cmd.buf); |
1872 | 9bcaf4fe | Paolo Bonzini | switch (command) {
|
1873 | ebf46023 | Gerd Hoffmann | case READ_6:
|
1874 | ebf46023 | Gerd Hoffmann | case READ_10:
|
1875 | bd536cf3 | Gerd Hoffmann | case READ_12:
|
1876 | bd536cf3 | Gerd Hoffmann | case READ_16:
|
1877 | e93176d5 | Paolo Bonzini | DPRINTF("Read (sector %" PRId64 ", count %u)\n", r->req.cmd.lba, len); |
1878 | 96bdbbab | Ronnie Sahlberg | if (r->req.cmd.buf[1] & 0xe0) { |
1879 | 96bdbbab | Ronnie Sahlberg | goto illegal_request;
|
1880 | 96bdbbab | Ronnie Sahlberg | } |
1881 | 444bc908 | Paolo Bonzini | if (!check_lba_range(s, r->req.cmd.lba, len)) {
|
1882 | 274fb0e1 | aliguori | goto illegal_lba;
|
1883 | f01b5931 | Paolo Bonzini | } |
1884 | 69377307 | Paolo Bonzini | r->sector = r->req.cmd.lba * (s->qdev.blocksize / 512);
|
1885 | 69377307 | Paolo Bonzini | r->sector_count = len * (s->qdev.blocksize / 512);
|
1886 | 2e5d83bb | pbrook | break;
|
1887 | ebf46023 | Gerd Hoffmann | case WRITE_6:
|
1888 | ebf46023 | Gerd Hoffmann | case WRITE_10:
|
1889 | bd536cf3 | Gerd Hoffmann | case WRITE_12:
|
1890 | bd536cf3 | Gerd Hoffmann | case WRITE_16:
|
1891 | 5e30a07d | Hannes Reinecke | case WRITE_VERIFY_10:
|
1892 | ebef0bbb | Bernhard Kohl | case WRITE_VERIFY_12:
|
1893 | ebef0bbb | Bernhard Kohl | case WRITE_VERIFY_16:
|
1894 | 6a8a685c | Ronnie Sahlberg | if (bdrv_is_read_only(s->qdev.conf.bs)) {
|
1895 | 6a8a685c | Ronnie Sahlberg | scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED)); |
1896 | 6a8a685c | Ronnie Sahlberg | return 0; |
1897 | 6a8a685c | Ronnie Sahlberg | } |
1898 | 6a8a685c | Ronnie Sahlberg | /* fallthrough */
|
1899 | 6a8a685c | Ronnie Sahlberg | case VERIFY_10:
|
1900 | 6a8a685c | Ronnie Sahlberg | case VERIFY_12:
|
1901 | 6a8a685c | Ronnie Sahlberg | case VERIFY_16:
|
1902 | e93176d5 | Paolo Bonzini | DPRINTF("Write %s(sector %" PRId64 ", count %u)\n", |
1903 | 2dd791b6 | Hannes Reinecke | (command & 0xe) == 0xe ? "And Verify " : "", |
1904 | 2dd791b6 | Hannes Reinecke | r->req.cmd.lba, len); |
1905 | 96bdbbab | Ronnie Sahlberg | if (r->req.cmd.buf[1] & 0xe0) { |
1906 | 96bdbbab | Ronnie Sahlberg | goto illegal_request;
|
1907 | 96bdbbab | Ronnie Sahlberg | } |
1908 | 444bc908 | Paolo Bonzini | if (!check_lba_range(s, r->req.cmd.lba, len)) {
|
1909 | 274fb0e1 | aliguori | goto illegal_lba;
|
1910 | f01b5931 | Paolo Bonzini | } |
1911 | 69377307 | Paolo Bonzini | r->sector = r->req.cmd.lba * (s->qdev.blocksize / 512);
|
1912 | 69377307 | Paolo Bonzini | r->sector_count = len * (s->qdev.blocksize / 512);
|
1913 | 2e5d83bb | pbrook | break;
|
1914 | 101aa85f | Paolo Bonzini | default:
|
1915 | b08d0ea0 | Paolo Bonzini | abort(); |
1916 | 96bdbbab | Ronnie Sahlberg | illegal_request:
|
1917 | 96bdbbab | Ronnie Sahlberg | scsi_check_condition(r, SENSE_CODE(INVALID_FIELD)); |
1918 | 96bdbbab | Ronnie Sahlberg | return 0; |
1919 | 274fb0e1 | aliguori | illegal_lba:
|
1920 | b45ef674 | Paolo Bonzini | scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE)); |
1921 | 274fb0e1 | aliguori | return 0; |
1922 | 2e5d83bb | pbrook | } |
1923 | b08d0ea0 | Paolo Bonzini | if (r->sector_count == 0) { |
1924 | b45ef674 | Paolo Bonzini | scsi_req_complete(&r->req, GOOD); |
1925 | a917d384 | pbrook | } |
1926 | b08d0ea0 | Paolo Bonzini | assert(r->iov.iov_len == 0);
|
1927 | efb9ee02 | Hannes Reinecke | if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
|
1928 | b08d0ea0 | Paolo Bonzini | return -r->sector_count * 512; |
1929 | a917d384 | pbrook | } else {
|
1930 | b08d0ea0 | Paolo Bonzini | return r->sector_count * 512; |
1931 | 2e5d83bb | pbrook | } |
1932 | 2e5d83bb | pbrook | } |
1933 | 2e5d83bb | pbrook | |
1934 | e9447f35 | Jan Kiszka | static void scsi_disk_reset(DeviceState *dev) |
1935 | e9447f35 | Jan Kiszka | { |
1936 | e9447f35 | Jan Kiszka | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev.qdev, dev); |
1937 | e9447f35 | Jan Kiszka | uint64_t nb_sectors; |
1938 | e9447f35 | Jan Kiszka | |
1939 | c7b48872 | Paolo Bonzini | scsi_device_purge_requests(&s->qdev, SENSE_CODE(RESET)); |
1940 | e9447f35 | Jan Kiszka | |
1941 | 44740c38 | Paolo Bonzini | bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors); |
1942 | 69377307 | Paolo Bonzini | nb_sectors /= s->qdev.blocksize / 512;
|
1943 | e9447f35 | Jan Kiszka | if (nb_sectors) {
|
1944 | e9447f35 | Jan Kiszka | nb_sectors--; |
1945 | e9447f35 | Jan Kiszka | } |
1946 | 7877903a | Paolo Bonzini | s->qdev.max_lba = nb_sectors; |
1947 | e9447f35 | Jan Kiszka | } |
1948 | e9447f35 | Jan Kiszka | |
1949 | e9447f35 | Jan Kiszka | static void scsi_destroy(SCSIDevice *dev) |
1950 | e9447f35 | Jan Kiszka | { |
1951 | e9447f35 | Jan Kiszka | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev); |
1952 | e9447f35 | Jan Kiszka | |
1953 | c7b48872 | Paolo Bonzini | scsi_device_purge_requests(&s->qdev, SENSE_CODE(NO_SENSE)); |
1954 | f8b6cc00 | Markus Armbruster | blockdev_mark_auto_del(s->qdev.conf.bs); |
1955 | 56a14938 | Gerd Hoffmann | } |
1956 | 56a14938 | Gerd Hoffmann | |
1957 | aaebacef | Paolo Bonzini | static void scsi_disk_resize_cb(void *opaque) |
1958 | aaebacef | Paolo Bonzini | { |
1959 | aaebacef | Paolo Bonzini | SCSIDiskState *s = opaque; |
1960 | aaebacef | Paolo Bonzini | |
1961 | aaebacef | Paolo Bonzini | /* SPC lists this sense code as available only for
|
1962 | aaebacef | Paolo Bonzini | * direct-access devices.
|
1963 | aaebacef | Paolo Bonzini | */
|
1964 | aaebacef | Paolo Bonzini | if (s->qdev.type == TYPE_DISK) {
|
1965 | aaebacef | Paolo Bonzini | scsi_device_set_ua(&s->qdev, SENSE_CODE(CAPACITY_CHANGED)); |
1966 | 53200fad | Paolo Bonzini | scsi_device_report_change(&s->qdev, SENSE_CODE(CAPACITY_CHANGED)); |
1967 | aaebacef | Paolo Bonzini | } |
1968 | aaebacef | Paolo Bonzini | } |
1969 | aaebacef | Paolo Bonzini | |
1970 | 7d4b4ba5 | Markus Armbruster | static void scsi_cd_change_media_cb(void *opaque, bool load) |
1971 | 2c6942fa | Markus Armbruster | { |
1972 | 8a9c16f6 | Paolo Bonzini | SCSIDiskState *s = opaque; |
1973 | 8a9c16f6 | Paolo Bonzini | |
1974 | 8a9c16f6 | Paolo Bonzini | /*
|
1975 | 8a9c16f6 | Paolo Bonzini | * When a CD gets changed, we have to report an ejected state and
|
1976 | 8a9c16f6 | Paolo Bonzini | * then a loaded state to guests so that they detect tray
|
1977 | 8a9c16f6 | Paolo Bonzini | * open/close and media change events. Guests that do not use
|
1978 | 8a9c16f6 | Paolo Bonzini | * GET_EVENT_STATUS_NOTIFICATION to detect such tray open/close
|
1979 | 8a9c16f6 | Paolo Bonzini | * states rely on this behavior.
|
1980 | 8a9c16f6 | Paolo Bonzini | *
|
1981 | 8a9c16f6 | Paolo Bonzini | * media_changed governs the state machine used for unit attention
|
1982 | 8a9c16f6 | Paolo Bonzini | * report. media_event is used by GET EVENT STATUS NOTIFICATION.
|
1983 | 8a9c16f6 | Paolo Bonzini | */
|
1984 | 8a9c16f6 | Paolo Bonzini | s->media_changed = load; |
1985 | 8a9c16f6 | Paolo Bonzini | s->tray_open = !load; |
1986 | e48e84ea | Paolo Bonzini | scsi_device_set_ua(&s->qdev, SENSE_CODE(UNIT_ATTENTION_NO_MEDIUM)); |
1987 | 3c2f7c12 | Paolo Bonzini | s->media_event = true;
|
1988 | 4480de19 | Paolo Bonzini | s->eject_request = false;
|
1989 | 4480de19 | Paolo Bonzini | } |
1990 | 4480de19 | Paolo Bonzini | |
1991 | 4480de19 | Paolo Bonzini | static void scsi_cd_eject_request_cb(void *opaque, bool force) |
1992 | 4480de19 | Paolo Bonzini | { |
1993 | 4480de19 | Paolo Bonzini | SCSIDiskState *s = opaque; |
1994 | 4480de19 | Paolo Bonzini | |
1995 | 4480de19 | Paolo Bonzini | s->eject_request = true;
|
1996 | 4480de19 | Paolo Bonzini | if (force) {
|
1997 | 4480de19 | Paolo Bonzini | s->tray_locked = false;
|
1998 | 4480de19 | Paolo Bonzini | } |
1999 | 2c6942fa | Markus Armbruster | } |
2000 | 2c6942fa | Markus Armbruster | |
2001 | e4def80b | Markus Armbruster | static bool scsi_cd_is_tray_open(void *opaque) |
2002 | e4def80b | Markus Armbruster | { |
2003 | e4def80b | Markus Armbruster | return ((SCSIDiskState *)opaque)->tray_open;
|
2004 | e4def80b | Markus Armbruster | } |
2005 | e4def80b | Markus Armbruster | |
2006 | f107639a | Markus Armbruster | static bool scsi_cd_is_medium_locked(void *opaque) |
2007 | f107639a | Markus Armbruster | { |
2008 | f107639a | Markus Armbruster | return ((SCSIDiskState *)opaque)->tray_locked;
|
2009 | f107639a | Markus Armbruster | } |
2010 | f107639a | Markus Armbruster | |
2011 | aaebacef | Paolo Bonzini | static const BlockDevOps scsi_disk_removable_block_ops = { |
2012 | 2c6942fa | Markus Armbruster | .change_media_cb = scsi_cd_change_media_cb, |
2013 | 4480de19 | Paolo Bonzini | .eject_request_cb = scsi_cd_eject_request_cb, |
2014 | e4def80b | Markus Armbruster | .is_tray_open = scsi_cd_is_tray_open, |
2015 | f107639a | Markus Armbruster | .is_medium_locked = scsi_cd_is_medium_locked, |
2016 | aaebacef | Paolo Bonzini | |
2017 | aaebacef | Paolo Bonzini | .resize_cb = scsi_disk_resize_cb, |
2018 | aaebacef | Paolo Bonzini | }; |
2019 | aaebacef | Paolo Bonzini | |
2020 | aaebacef | Paolo Bonzini | static const BlockDevOps scsi_disk_block_ops = { |
2021 | aaebacef | Paolo Bonzini | .resize_cb = scsi_disk_resize_cb, |
2022 | f107639a | Markus Armbruster | }; |
2023 | f107639a | Markus Armbruster | |
2024 | 8a9c16f6 | Paolo Bonzini | static void scsi_disk_unit_attention_reported(SCSIDevice *dev) |
2025 | 8a9c16f6 | Paolo Bonzini | { |
2026 | 8a9c16f6 | Paolo Bonzini | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev); |
2027 | 8a9c16f6 | Paolo Bonzini | if (s->media_changed) {
|
2028 | 8a9c16f6 | Paolo Bonzini | s->media_changed = false;
|
2029 | e48e84ea | Paolo Bonzini | scsi_device_set_ua(&s->qdev, SENSE_CODE(MEDIUM_CHANGED)); |
2030 | 8a9c16f6 | Paolo Bonzini | } |
2031 | 8a9c16f6 | Paolo Bonzini | } |
2032 | 8a9c16f6 | Paolo Bonzini | |
2033 | e39be482 | Paolo Bonzini | static int scsi_initfn(SCSIDevice *dev) |
2034 | 2e5d83bb | pbrook | { |
2035 | d52affa7 | Gerd Hoffmann | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev); |
2036 | 2e5d83bb | pbrook | |
2037 | f8b6cc00 | Markus Armbruster | if (!s->qdev.conf.bs) {
|
2038 | 6a84cb1f | Markus Armbruster | error_report("drive property not set");
|
2039 | d52affa7 | Gerd Hoffmann | return -1; |
2040 | d52affa7 | Gerd Hoffmann | } |
2041 | d52affa7 | Gerd Hoffmann | |
2042 | bfe3d7ac | Paolo Bonzini | if (!(s->features & (1 << SCSI_DISK_F_REMOVABLE)) && |
2043 | bfe3d7ac | Paolo Bonzini | !bdrv_is_inserted(s->qdev.conf.bs)) { |
2044 | 98f28ad7 | Markus Armbruster | error_report("Device needs media, but drive is empty");
|
2045 | 98f28ad7 | Markus Armbruster | return -1; |
2046 | 98f28ad7 | Markus Armbruster | } |
2047 | 98f28ad7 | Markus Armbruster | |
2048 | 911525db | Markus Armbruster | blkconf_serial(&s->qdev.conf, &s->serial); |
2049 | b2df4314 | Markus Armbruster | if (dev->type == TYPE_DISK
|
2050 | b2df4314 | Markus Armbruster | && blkconf_geometry(&dev->conf, NULL, 65535, 255, 255) < 0) { |
2051 | b7eb0c9f | Markus Armbruster | return -1; |
2052 | b7eb0c9f | Markus Armbruster | } |
2053 | a0fef654 | Markus Armbruster | |
2054 | 552fee93 | Markus Armbruster | if (!s->version) {
|
2055 | 93bfef4c | Crístian Viana | s->version = g_strdup(qemu_get_version()); |
2056 | 552fee93 | Markus Armbruster | } |
2057 | 353815aa | Dmitry Fleytman | if (!s->vendor) {
|
2058 | 353815aa | Dmitry Fleytman | s->vendor = g_strdup("QEMU");
|
2059 | 353815aa | Dmitry Fleytman | } |
2060 | 552fee93 | Markus Armbruster | |
2061 | 44740c38 | Paolo Bonzini | if (bdrv_is_sg(s->qdev.conf.bs)) {
|
2062 | 6a84cb1f | Markus Armbruster | error_report("unwanted /dev/sg*");
|
2063 | 32bb404a | Markus Armbruster | return -1; |
2064 | 32bb404a | Markus Armbruster | } |
2065 | 32bb404a | Markus Armbruster | |
2066 | bfe3d7ac | Paolo Bonzini | if (s->features & (1 << SCSI_DISK_F_REMOVABLE)) { |
2067 | aaebacef | Paolo Bonzini | bdrv_set_dev_ops(s->qdev.conf.bs, &scsi_disk_removable_block_ops, s); |
2068 | aaebacef | Paolo Bonzini | } else {
|
2069 | aaebacef | Paolo Bonzini | bdrv_set_dev_ops(s->qdev.conf.bs, &scsi_disk_block_ops, s); |
2070 | 2e5d83bb | pbrook | } |
2071 | 44740c38 | Paolo Bonzini | bdrv_set_buffer_alignment(s->qdev.conf.bs, s->qdev.blocksize); |
2072 | 8cfacf07 | Christoph Hellwig | |
2073 | 44740c38 | Paolo Bonzini | bdrv_iostatus_enable(s->qdev.conf.bs); |
2074 | 7082826e | Paolo Bonzini | add_boot_device_path(s->qdev.conf.bootindex, &dev->qdev, NULL);
|
2075 | d52affa7 | Gerd Hoffmann | return 0; |
2076 | d52affa7 | Gerd Hoffmann | } |
2077 | d52affa7 | Gerd Hoffmann | |
2078 | b443ae67 | Markus Armbruster | static int scsi_hd_initfn(SCSIDevice *dev) |
2079 | b443ae67 | Markus Armbruster | { |
2080 | e39be482 | Paolo Bonzini | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev); |
2081 | e39be482 | Paolo Bonzini | s->qdev.blocksize = s->qdev.conf.logical_block_size; |
2082 | e39be482 | Paolo Bonzini | s->qdev.type = TYPE_DISK; |
2083 | 353815aa | Dmitry Fleytman | if (!s->product) {
|
2084 | 353815aa | Dmitry Fleytman | s->product = g_strdup("QEMU HARDDISK");
|
2085 | 353815aa | Dmitry Fleytman | } |
2086 | e39be482 | Paolo Bonzini | return scsi_initfn(&s->qdev);
|
2087 | b443ae67 | Markus Armbruster | } |
2088 | b443ae67 | Markus Armbruster | |
2089 | b443ae67 | Markus Armbruster | static int scsi_cd_initfn(SCSIDevice *dev) |
2090 | b443ae67 | Markus Armbruster | { |
2091 | e39be482 | Paolo Bonzini | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev); |
2092 | e39be482 | Paolo Bonzini | s->qdev.blocksize = 2048;
|
2093 | e39be482 | Paolo Bonzini | s->qdev.type = TYPE_ROM; |
2094 | bfe3d7ac | Paolo Bonzini | s->features |= 1 << SCSI_DISK_F_REMOVABLE;
|
2095 | 353815aa | Dmitry Fleytman | if (!s->product) {
|
2096 | 353815aa | Dmitry Fleytman | s->product = g_strdup("QEMU CD-ROM");
|
2097 | 353815aa | Dmitry Fleytman | } |
2098 | e39be482 | Paolo Bonzini | return scsi_initfn(&s->qdev);
|
2099 | b443ae67 | Markus Armbruster | } |
2100 | b443ae67 | Markus Armbruster | |
2101 | b443ae67 | Markus Armbruster | static int scsi_disk_initfn(SCSIDevice *dev) |
2102 | b443ae67 | Markus Armbruster | { |
2103 | 95b5edcd | Markus Armbruster | DriveInfo *dinfo; |
2104 | b443ae67 | Markus Armbruster | |
2105 | b443ae67 | Markus Armbruster | if (!dev->conf.bs) {
|
2106 | e39be482 | Paolo Bonzini | return scsi_initfn(dev); /* ... and die there */ |
2107 | b443ae67 | Markus Armbruster | } |
2108 | b443ae67 | Markus Armbruster | |
2109 | e39be482 | Paolo Bonzini | dinfo = drive_get_by_blockdev(dev->conf.bs); |
2110 | e39be482 | Paolo Bonzini | if (dinfo->media_cd) {
|
2111 | e39be482 | Paolo Bonzini | return scsi_cd_initfn(dev);
|
2112 | e39be482 | Paolo Bonzini | } else {
|
2113 | e39be482 | Paolo Bonzini | return scsi_hd_initfn(dev);
|
2114 | e39be482 | Paolo Bonzini | } |
2115 | b443ae67 | Markus Armbruster | } |
2116 | b443ae67 | Markus Armbruster | |
2117 | b08d0ea0 | Paolo Bonzini | static const SCSIReqOps scsi_disk_emulate_reqops = { |
2118 | 8dbd4574 | Paolo Bonzini | .size = sizeof(SCSIDiskReq),
|
2119 | 12010e7b | Paolo Bonzini | .free_req = scsi_free_request, |
2120 | b08d0ea0 | Paolo Bonzini | .send_command = scsi_disk_emulate_command, |
2121 | 314a3299 | Paolo Bonzini | .read_data = scsi_disk_emulate_read_data, |
2122 | 314a3299 | Paolo Bonzini | .write_data = scsi_disk_emulate_write_data, |
2123 | b08d0ea0 | Paolo Bonzini | .get_buf = scsi_get_buf, |
2124 | b08d0ea0 | Paolo Bonzini | }; |
2125 | b08d0ea0 | Paolo Bonzini | |
2126 | b08d0ea0 | Paolo Bonzini | static const SCSIReqOps scsi_disk_dma_reqops = { |
2127 | b08d0ea0 | Paolo Bonzini | .size = sizeof(SCSIDiskReq),
|
2128 | b08d0ea0 | Paolo Bonzini | .free_req = scsi_free_request, |
2129 | b08d0ea0 | Paolo Bonzini | .send_command = scsi_disk_dma_command, |
2130 | 12010e7b | Paolo Bonzini | .read_data = scsi_read_data, |
2131 | 12010e7b | Paolo Bonzini | .write_data = scsi_write_data, |
2132 | 12010e7b | Paolo Bonzini | .cancel_io = scsi_cancel_io, |
2133 | 12010e7b | Paolo Bonzini | .get_buf = scsi_get_buf, |
2134 | 43b978b9 | Paolo Bonzini | .load_request = scsi_disk_load_request, |
2135 | 43b978b9 | Paolo Bonzini | .save_request = scsi_disk_save_request, |
2136 | 8dbd4574 | Paolo Bonzini | }; |
2137 | 8dbd4574 | Paolo Bonzini | |
2138 | b08d0ea0 | Paolo Bonzini | static const SCSIReqOps *const scsi_disk_reqops_dispatch[256] = { |
2139 | b08d0ea0 | Paolo Bonzini | [TEST_UNIT_READY] = &scsi_disk_emulate_reqops, |
2140 | b08d0ea0 | Paolo Bonzini | [INQUIRY] = &scsi_disk_emulate_reqops, |
2141 | b08d0ea0 | Paolo Bonzini | [MODE_SENSE] = &scsi_disk_emulate_reqops, |
2142 | b08d0ea0 | Paolo Bonzini | [MODE_SENSE_10] = &scsi_disk_emulate_reqops, |
2143 | b08d0ea0 | Paolo Bonzini | [START_STOP] = &scsi_disk_emulate_reqops, |
2144 | b08d0ea0 | Paolo Bonzini | [ALLOW_MEDIUM_REMOVAL] = &scsi_disk_emulate_reqops, |
2145 | b08d0ea0 | Paolo Bonzini | [READ_CAPACITY_10] = &scsi_disk_emulate_reqops, |
2146 | b08d0ea0 | Paolo Bonzini | [READ_TOC] = &scsi_disk_emulate_reqops, |
2147 | b08d0ea0 | Paolo Bonzini | [READ_DVD_STRUCTURE] = &scsi_disk_emulate_reqops, |
2148 | b08d0ea0 | Paolo Bonzini | [READ_DISC_INFORMATION] = &scsi_disk_emulate_reqops, |
2149 | b08d0ea0 | Paolo Bonzini | [GET_CONFIGURATION] = &scsi_disk_emulate_reqops, |
2150 | b08d0ea0 | Paolo Bonzini | [GET_EVENT_STATUS_NOTIFICATION] = &scsi_disk_emulate_reqops, |
2151 | b08d0ea0 | Paolo Bonzini | [MECHANISM_STATUS] = &scsi_disk_emulate_reqops, |
2152 | b08d0ea0 | Paolo Bonzini | [SERVICE_ACTION_IN_16] = &scsi_disk_emulate_reqops, |
2153 | b08d0ea0 | Paolo Bonzini | [REQUEST_SENSE] = &scsi_disk_emulate_reqops, |
2154 | b08d0ea0 | Paolo Bonzini | [SYNCHRONIZE_CACHE] = &scsi_disk_emulate_reqops, |
2155 | b08d0ea0 | Paolo Bonzini | [SEEK_10] = &scsi_disk_emulate_reqops, |
2156 | b08d0ea0 | Paolo Bonzini | [MODE_SELECT] = &scsi_disk_emulate_reqops, |
2157 | b08d0ea0 | Paolo Bonzini | [MODE_SELECT_10] = &scsi_disk_emulate_reqops, |
2158 | 5222aaf2 | Paolo Bonzini | [UNMAP] = &scsi_disk_emulate_reqops, |
2159 | b08d0ea0 | Paolo Bonzini | [WRITE_SAME_10] = &scsi_disk_emulate_reqops, |
2160 | b08d0ea0 | Paolo Bonzini | [WRITE_SAME_16] = &scsi_disk_emulate_reqops, |
2161 | b08d0ea0 | Paolo Bonzini | |
2162 | b08d0ea0 | Paolo Bonzini | [READ_6] = &scsi_disk_dma_reqops, |
2163 | b08d0ea0 | Paolo Bonzini | [READ_10] = &scsi_disk_dma_reqops, |
2164 | b08d0ea0 | Paolo Bonzini | [READ_12] = &scsi_disk_dma_reqops, |
2165 | b08d0ea0 | Paolo Bonzini | [READ_16] = &scsi_disk_dma_reqops, |
2166 | b08d0ea0 | Paolo Bonzini | [VERIFY_10] = &scsi_disk_dma_reqops, |
2167 | b08d0ea0 | Paolo Bonzini | [VERIFY_12] = &scsi_disk_dma_reqops, |
2168 | b08d0ea0 | Paolo Bonzini | [VERIFY_16] = &scsi_disk_dma_reqops, |
2169 | b08d0ea0 | Paolo Bonzini | [WRITE_6] = &scsi_disk_dma_reqops, |
2170 | b08d0ea0 | Paolo Bonzini | [WRITE_10] = &scsi_disk_dma_reqops, |
2171 | b08d0ea0 | Paolo Bonzini | [WRITE_12] = &scsi_disk_dma_reqops, |
2172 | b08d0ea0 | Paolo Bonzini | [WRITE_16] = &scsi_disk_dma_reqops, |
2173 | b08d0ea0 | Paolo Bonzini | [WRITE_VERIFY_10] = &scsi_disk_dma_reqops, |
2174 | b08d0ea0 | Paolo Bonzini | [WRITE_VERIFY_12] = &scsi_disk_dma_reqops, |
2175 | b08d0ea0 | Paolo Bonzini | [WRITE_VERIFY_16] = &scsi_disk_dma_reqops, |
2176 | b08d0ea0 | Paolo Bonzini | }; |
2177 | b08d0ea0 | Paolo Bonzini | |
2178 | 63db0f0e | Paolo Bonzini | static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
|
2179 | 63db0f0e | Paolo Bonzini | uint8_t *buf, void *hba_private)
|
2180 | 8dbd4574 | Paolo Bonzini | { |
2181 | 8dbd4574 | Paolo Bonzini | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); |
2182 | 8dbd4574 | Paolo Bonzini | SCSIRequest *req; |
2183 | b08d0ea0 | Paolo Bonzini | const SCSIReqOps *ops;
|
2184 | b08d0ea0 | Paolo Bonzini | uint8_t command; |
2185 | 8dbd4574 | Paolo Bonzini | |
2186 | 79fb50bb | Paolo Bonzini | command = buf[0];
|
2187 | 79fb50bb | Paolo Bonzini | ops = scsi_disk_reqops_dispatch[command]; |
2188 | 79fb50bb | Paolo Bonzini | if (!ops) {
|
2189 | 79fb50bb | Paolo Bonzini | ops = &scsi_disk_emulate_reqops; |
2190 | 79fb50bb | Paolo Bonzini | } |
2191 | 79fb50bb | Paolo Bonzini | req = scsi_req_alloc(ops, &s->qdev, tag, lun, hba_private); |
2192 | 79fb50bb | Paolo Bonzini | |
2193 | b08d0ea0 | Paolo Bonzini | #ifdef DEBUG_SCSI
|
2194 | 79fb50bb | Paolo Bonzini | DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]); |
2195 | b08d0ea0 | Paolo Bonzini | { |
2196 | b08d0ea0 | Paolo Bonzini | int i;
|
2197 | 79fb50bb | Paolo Bonzini | for (i = 1; i < req->cmd.len; i++) { |
2198 | b08d0ea0 | Paolo Bonzini | printf(" 0x%02x", buf[i]);
|
2199 | b08d0ea0 | Paolo Bonzini | } |
2200 | b08d0ea0 | Paolo Bonzini | printf("\n");
|
2201 | b08d0ea0 | Paolo Bonzini | } |
2202 | b08d0ea0 | Paolo Bonzini | #endif
|
2203 | b08d0ea0 | Paolo Bonzini | |
2204 | 8dbd4574 | Paolo Bonzini | return req;
|
2205 | 8dbd4574 | Paolo Bonzini | } |
2206 | 8dbd4574 | Paolo Bonzini | |
2207 | 336a6915 | Paolo Bonzini | #ifdef __linux__
|
2208 | 336a6915 | Paolo Bonzini | static int get_device_type(SCSIDiskState *s) |
2209 | 336a6915 | Paolo Bonzini | { |
2210 | 336a6915 | Paolo Bonzini | BlockDriverState *bdrv = s->qdev.conf.bs; |
2211 | 336a6915 | Paolo Bonzini | uint8_t cmd[16];
|
2212 | 336a6915 | Paolo Bonzini | uint8_t buf[36];
|
2213 | 336a6915 | Paolo Bonzini | uint8_t sensebuf[8];
|
2214 | 336a6915 | Paolo Bonzini | sg_io_hdr_t io_header; |
2215 | 336a6915 | Paolo Bonzini | int ret;
|
2216 | 336a6915 | Paolo Bonzini | |
2217 | 336a6915 | Paolo Bonzini | memset(cmd, 0, sizeof(cmd)); |
2218 | 336a6915 | Paolo Bonzini | memset(buf, 0, sizeof(buf)); |
2219 | 336a6915 | Paolo Bonzini | cmd[0] = INQUIRY;
|
2220 | 336a6915 | Paolo Bonzini | cmd[4] = sizeof(buf); |
2221 | 336a6915 | Paolo Bonzini | |
2222 | 336a6915 | Paolo Bonzini | memset(&io_header, 0, sizeof(io_header)); |
2223 | 336a6915 | Paolo Bonzini | io_header.interface_id = 'S';
|
2224 | 336a6915 | Paolo Bonzini | io_header.dxfer_direction = SG_DXFER_FROM_DEV; |
2225 | 336a6915 | Paolo Bonzini | io_header.dxfer_len = sizeof(buf);
|
2226 | 336a6915 | Paolo Bonzini | io_header.dxferp = buf; |
2227 | 336a6915 | Paolo Bonzini | io_header.cmdp = cmd; |
2228 | 336a6915 | Paolo Bonzini | io_header.cmd_len = sizeof(cmd);
|
2229 | 336a6915 | Paolo Bonzini | io_header.mx_sb_len = sizeof(sensebuf);
|
2230 | 336a6915 | Paolo Bonzini | io_header.sbp = sensebuf; |
2231 | 336a6915 | Paolo Bonzini | io_header.timeout = 6000; /* XXX */ |
2232 | 336a6915 | Paolo Bonzini | |
2233 | 336a6915 | Paolo Bonzini | ret = bdrv_ioctl(bdrv, SG_IO, &io_header); |
2234 | 336a6915 | Paolo Bonzini | if (ret < 0 || io_header.driver_status || io_header.host_status) { |
2235 | 336a6915 | Paolo Bonzini | return -1; |
2236 | 336a6915 | Paolo Bonzini | } |
2237 | 336a6915 | Paolo Bonzini | s->qdev.type = buf[0];
|
2238 | bfe3d7ac | Paolo Bonzini | if (buf[1] & 0x80) { |
2239 | bfe3d7ac | Paolo Bonzini | s->features |= 1 << SCSI_DISK_F_REMOVABLE;
|
2240 | bfe3d7ac | Paolo Bonzini | } |
2241 | 336a6915 | Paolo Bonzini | return 0; |
2242 | 336a6915 | Paolo Bonzini | } |
2243 | 336a6915 | Paolo Bonzini | |
2244 | 336a6915 | Paolo Bonzini | static int scsi_block_initfn(SCSIDevice *dev) |
2245 | 336a6915 | Paolo Bonzini | { |
2246 | 336a6915 | Paolo Bonzini | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev); |
2247 | 336a6915 | Paolo Bonzini | int sg_version;
|
2248 | 336a6915 | Paolo Bonzini | int rc;
|
2249 | 336a6915 | Paolo Bonzini | |
2250 | 336a6915 | Paolo Bonzini | if (!s->qdev.conf.bs) {
|
2251 | 336a6915 | Paolo Bonzini | error_report("scsi-block: drive property not set");
|
2252 | 336a6915 | Paolo Bonzini | return -1; |
2253 | 336a6915 | Paolo Bonzini | } |
2254 | 336a6915 | Paolo Bonzini | |
2255 | 336a6915 | Paolo Bonzini | /* check we are using a driver managing SG_IO (version 3 and after) */
|
2256 | 336a6915 | Paolo Bonzini | if (bdrv_ioctl(s->qdev.conf.bs, SG_GET_VERSION_NUM, &sg_version) < 0 || |
2257 | 336a6915 | Paolo Bonzini | sg_version < 30000) {
|
2258 | 336a6915 | Paolo Bonzini | error_report("scsi-block: scsi generic interface too old");
|
2259 | 336a6915 | Paolo Bonzini | return -1; |
2260 | 336a6915 | Paolo Bonzini | } |
2261 | 336a6915 | Paolo Bonzini | |
2262 | 336a6915 | Paolo Bonzini | /* get device type from INQUIRY data */
|
2263 | 336a6915 | Paolo Bonzini | rc = get_device_type(s); |
2264 | 336a6915 | Paolo Bonzini | if (rc < 0) { |
2265 | 336a6915 | Paolo Bonzini | error_report("scsi-block: INQUIRY failed");
|
2266 | 336a6915 | Paolo Bonzini | return -1; |
2267 | 336a6915 | Paolo Bonzini | } |
2268 | 336a6915 | Paolo Bonzini | |
2269 | 336a6915 | Paolo Bonzini | /* Make a guess for the block size, we'll fix it when the guest sends.
|
2270 | 336a6915 | Paolo Bonzini | * READ CAPACITY. If they don't, they likely would assume these sizes
|
2271 | 336a6915 | Paolo Bonzini | * anyway. (TODO: check in /sys).
|
2272 | 336a6915 | Paolo Bonzini | */
|
2273 | 336a6915 | Paolo Bonzini | if (s->qdev.type == TYPE_ROM || s->qdev.type == TYPE_WORM) {
|
2274 | 336a6915 | Paolo Bonzini | s->qdev.blocksize = 2048;
|
2275 | 336a6915 | Paolo Bonzini | } else {
|
2276 | 336a6915 | Paolo Bonzini | s->qdev.blocksize = 512;
|
2277 | 336a6915 | Paolo Bonzini | } |
2278 | 336a6915 | Paolo Bonzini | return scsi_initfn(&s->qdev);
|
2279 | 336a6915 | Paolo Bonzini | } |
2280 | 336a6915 | Paolo Bonzini | |
2281 | 336a6915 | Paolo Bonzini | static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag,
|
2282 | 336a6915 | Paolo Bonzini | uint32_t lun, uint8_t *buf, |
2283 | 336a6915 | Paolo Bonzini | void *hba_private)
|
2284 | 336a6915 | Paolo Bonzini | { |
2285 | 336a6915 | Paolo Bonzini | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); |
2286 | 336a6915 | Paolo Bonzini | |
2287 | 336a6915 | Paolo Bonzini | switch (buf[0]) { |
2288 | 336a6915 | Paolo Bonzini | case READ_6:
|
2289 | 336a6915 | Paolo Bonzini | case READ_10:
|
2290 | 336a6915 | Paolo Bonzini | case READ_12:
|
2291 | 336a6915 | Paolo Bonzini | case READ_16:
|
2292 | 7f64f8e2 | Paolo Bonzini | case VERIFY_10:
|
2293 | 7f64f8e2 | Paolo Bonzini | case VERIFY_12:
|
2294 | 7f64f8e2 | Paolo Bonzini | case VERIFY_16:
|
2295 | 336a6915 | Paolo Bonzini | case WRITE_6:
|
2296 | 336a6915 | Paolo Bonzini | case WRITE_10:
|
2297 | 336a6915 | Paolo Bonzini | case WRITE_12:
|
2298 | 336a6915 | Paolo Bonzini | case WRITE_16:
|
2299 | 336a6915 | Paolo Bonzini | case WRITE_VERIFY_10:
|
2300 | 336a6915 | Paolo Bonzini | case WRITE_VERIFY_12:
|
2301 | 336a6915 | Paolo Bonzini | case WRITE_VERIFY_16:
|
2302 | eaccf49e | Paolo Bonzini | /* If we are not using O_DIRECT, we might read stale data from the
|
2303 | eaccf49e | Paolo Bonzini | * host cache if writes were made using other commands than these
|
2304 | eaccf49e | Paolo Bonzini | * ones (such as WRITE SAME or EXTENDED COPY, etc.). So, without
|
2305 | eaccf49e | Paolo Bonzini | * O_DIRECT everything must go through SG_IO.
|
2306 | eaccf49e | Paolo Bonzini | */
|
2307 | 137745c5 | Markus Armbruster | if (bdrv_get_flags(s->qdev.conf.bs) & BDRV_O_NOCACHE) {
|
2308 | eaccf49e | Paolo Bonzini | break;
|
2309 | eaccf49e | Paolo Bonzini | } |
2310 | eaccf49e | Paolo Bonzini | |
2311 | 33ebad12 | Paolo Bonzini | /* MMC writing cannot be done via pread/pwrite, because it sometimes
|
2312 | 33ebad12 | Paolo Bonzini | * involves writing beyond the maximum LBA or to negative LBA (lead-in).
|
2313 | 33ebad12 | Paolo Bonzini | * And once you do these writes, reading from the block device is
|
2314 | 33ebad12 | Paolo Bonzini | * unreliable, too. It is even possible that reads deliver random data
|
2315 | 33ebad12 | Paolo Bonzini | * from the host page cache (this is probably a Linux bug).
|
2316 | 33ebad12 | Paolo Bonzini | *
|
2317 | b08d0ea0 | Paolo Bonzini | * We might use scsi_disk_dma_reqops as long as no writing commands are
|
2318 | 33ebad12 | Paolo Bonzini | * seen, but performance usually isn't paramount on optical media. So,
|
2319 | 33ebad12 | Paolo Bonzini | * just make scsi-block operate the same as scsi-generic for them.
|
2320 | 33ebad12 | Paolo Bonzini | */
|
2321 | b08d0ea0 | Paolo Bonzini | if (s->qdev.type != TYPE_ROM) {
|
2322 | b08d0ea0 | Paolo Bonzini | return scsi_req_alloc(&scsi_disk_dma_reqops, &s->qdev, tag, lun,
|
2323 | b08d0ea0 | Paolo Bonzini | hba_private); |
2324 | b08d0ea0 | Paolo Bonzini | } |
2325 | 336a6915 | Paolo Bonzini | } |
2326 | 336a6915 | Paolo Bonzini | |
2327 | 336a6915 | Paolo Bonzini | return scsi_req_alloc(&scsi_generic_req_ops, &s->qdev, tag, lun,
|
2328 | 336a6915 | Paolo Bonzini | hba_private); |
2329 | 336a6915 | Paolo Bonzini | } |
2330 | 336a6915 | Paolo Bonzini | #endif
|
2331 | 336a6915 | Paolo Bonzini | |
2332 | 353815aa | Dmitry Fleytman | #define DEFINE_SCSI_DISK_PROPERTIES() \
|
2333 | 353815aa | Dmitry Fleytman | DEFINE_BLOCK_PROPERTIES(SCSIDiskState, qdev.conf), \ |
2334 | 353815aa | Dmitry Fleytman | DEFINE_PROP_STRING("ver", SCSIDiskState, version), \
|
2335 | 353815aa | Dmitry Fleytman | DEFINE_PROP_STRING("serial", SCSIDiskState, serial), \
|
2336 | 353815aa | Dmitry Fleytman | DEFINE_PROP_STRING("vendor", SCSIDiskState, vendor), \
|
2337 | 353815aa | Dmitry Fleytman | DEFINE_PROP_STRING("product", SCSIDiskState, product)
|
2338 | b443ae67 | Markus Armbruster | |
2339 | 39bffca2 | Anthony Liguori | static Property scsi_hd_properties[] = {
|
2340 | 39bffca2 | Anthony Liguori | DEFINE_SCSI_DISK_PROPERTIES(), |
2341 | bfe3d7ac | Paolo Bonzini | DEFINE_PROP_BIT("removable", SCSIDiskState, features,
|
2342 | bfe3d7ac | Paolo Bonzini | SCSI_DISK_F_REMOVABLE, false),
|
2343 | da8365db | Paolo Bonzini | DEFINE_PROP_BIT("dpofua", SCSIDiskState, features,
|
2344 | da8365db | Paolo Bonzini | SCSI_DISK_F_DPOFUA, false),
|
2345 | 27395add | Paolo Bonzini | DEFINE_PROP_HEX64("wwn", SCSIDiskState, wwn, 0), |
2346 | d252df48 | Markus Armbruster | DEFINE_BLOCK_CHS_PROPERTIES(SCSIDiskState, qdev.conf), |
2347 | 39bffca2 | Anthony Liguori | DEFINE_PROP_END_OF_LIST(), |
2348 | 39bffca2 | Anthony Liguori | }; |
2349 | 39bffca2 | Anthony Liguori | |
2350 | 43b978b9 | Paolo Bonzini | static const VMStateDescription vmstate_scsi_disk_state = { |
2351 | 43b978b9 | Paolo Bonzini | .name = "scsi-disk",
|
2352 | 43b978b9 | Paolo Bonzini | .version_id = 1,
|
2353 | 43b978b9 | Paolo Bonzini | .minimum_version_id = 1,
|
2354 | 43b978b9 | Paolo Bonzini | .minimum_version_id_old = 1,
|
2355 | 43b978b9 | Paolo Bonzini | .fields = (VMStateField[]) { |
2356 | 43b978b9 | Paolo Bonzini | VMSTATE_SCSI_DEVICE(qdev, SCSIDiskState), |
2357 | 43b978b9 | Paolo Bonzini | VMSTATE_BOOL(media_changed, SCSIDiskState), |
2358 | 43b978b9 | Paolo Bonzini | VMSTATE_BOOL(media_event, SCSIDiskState), |
2359 | 43b978b9 | Paolo Bonzini | VMSTATE_BOOL(eject_request, SCSIDiskState), |
2360 | 43b978b9 | Paolo Bonzini | VMSTATE_BOOL(tray_open, SCSIDiskState), |
2361 | 43b978b9 | Paolo Bonzini | VMSTATE_BOOL(tray_locked, SCSIDiskState), |
2362 | 43b978b9 | Paolo Bonzini | VMSTATE_END_OF_LIST() |
2363 | 43b978b9 | Paolo Bonzini | } |
2364 | 43b978b9 | Paolo Bonzini | }; |
2365 | 43b978b9 | Paolo Bonzini | |
2366 | b9eea3e6 | Anthony Liguori | static void scsi_hd_class_initfn(ObjectClass *klass, void *data) |
2367 | b9eea3e6 | Anthony Liguori | { |
2368 | 39bffca2 | Anthony Liguori | DeviceClass *dc = DEVICE_CLASS(klass); |
2369 | b9eea3e6 | Anthony Liguori | SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass); |
2370 | b9eea3e6 | Anthony Liguori | |
2371 | b9eea3e6 | Anthony Liguori | sc->init = scsi_hd_initfn; |
2372 | b9eea3e6 | Anthony Liguori | sc->destroy = scsi_destroy; |
2373 | b9eea3e6 | Anthony Liguori | sc->alloc_req = scsi_new_request; |
2374 | b9eea3e6 | Anthony Liguori | sc->unit_attention_reported = scsi_disk_unit_attention_reported; |
2375 | 39bffca2 | Anthony Liguori | dc->fw_name = "disk";
|
2376 | 39bffca2 | Anthony Liguori | dc->desc = "virtual SCSI disk";
|
2377 | 39bffca2 | Anthony Liguori | dc->reset = scsi_disk_reset; |
2378 | 39bffca2 | Anthony Liguori | dc->props = scsi_hd_properties; |
2379 | 43b978b9 | Paolo Bonzini | dc->vmsd = &vmstate_scsi_disk_state; |
2380 | b9eea3e6 | Anthony Liguori | } |
2381 | b9eea3e6 | Anthony Liguori | |
2382 | 39bffca2 | Anthony Liguori | static TypeInfo scsi_hd_info = {
|
2383 | 39bffca2 | Anthony Liguori | .name = "scsi-hd",
|
2384 | 39bffca2 | Anthony Liguori | .parent = TYPE_SCSI_DEVICE, |
2385 | 39bffca2 | Anthony Liguori | .instance_size = sizeof(SCSIDiskState),
|
2386 | 39bffca2 | Anthony Liguori | .class_init = scsi_hd_class_initfn, |
2387 | 39bffca2 | Anthony Liguori | }; |
2388 | 39bffca2 | Anthony Liguori | |
2389 | 39bffca2 | Anthony Liguori | static Property scsi_cd_properties[] = {
|
2390 | 39bffca2 | Anthony Liguori | DEFINE_SCSI_DISK_PROPERTIES(), |
2391 | 27395add | Paolo Bonzini | DEFINE_PROP_HEX64("wwn", SCSIDiskState, wwn, 0), |
2392 | 39bffca2 | Anthony Liguori | DEFINE_PROP_END_OF_LIST(), |
2393 | b9eea3e6 | Anthony Liguori | }; |
2394 | b9eea3e6 | Anthony Liguori | |
2395 | b9eea3e6 | Anthony Liguori | static void scsi_cd_class_initfn(ObjectClass *klass, void *data) |
2396 | b9eea3e6 | Anthony Liguori | { |
2397 | 39bffca2 | Anthony Liguori | DeviceClass *dc = DEVICE_CLASS(klass); |
2398 | b9eea3e6 | Anthony Liguori | SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass); |
2399 | b9eea3e6 | Anthony Liguori | |
2400 | b9eea3e6 | Anthony Liguori | sc->init = scsi_cd_initfn; |
2401 | b9eea3e6 | Anthony Liguori | sc->destroy = scsi_destroy; |
2402 | b9eea3e6 | Anthony Liguori | sc->alloc_req = scsi_new_request; |
2403 | b9eea3e6 | Anthony Liguori | sc->unit_attention_reported = scsi_disk_unit_attention_reported; |
2404 | 39bffca2 | Anthony Liguori | dc->fw_name = "disk";
|
2405 | 39bffca2 | Anthony Liguori | dc->desc = "virtual SCSI CD-ROM";
|
2406 | 39bffca2 | Anthony Liguori | dc->reset = scsi_disk_reset; |
2407 | 39bffca2 | Anthony Liguori | dc->props = scsi_cd_properties; |
2408 | 43b978b9 | Paolo Bonzini | dc->vmsd = &vmstate_scsi_disk_state; |
2409 | b9eea3e6 | Anthony Liguori | } |
2410 | b9eea3e6 | Anthony Liguori | |
2411 | 39bffca2 | Anthony Liguori | static TypeInfo scsi_cd_info = {
|
2412 | 39bffca2 | Anthony Liguori | .name = "scsi-cd",
|
2413 | 39bffca2 | Anthony Liguori | .parent = TYPE_SCSI_DEVICE, |
2414 | 39bffca2 | Anthony Liguori | .instance_size = sizeof(SCSIDiskState),
|
2415 | 39bffca2 | Anthony Liguori | .class_init = scsi_cd_class_initfn, |
2416 | b9eea3e6 | Anthony Liguori | }; |
2417 | b9eea3e6 | Anthony Liguori | |
2418 | 336a6915 | Paolo Bonzini | #ifdef __linux__
|
2419 | 39bffca2 | Anthony Liguori | static Property scsi_block_properties[] = {
|
2420 | 03847837 | Paolo Bonzini | DEFINE_PROP_DRIVE("drive", SCSIDiskState, qdev.conf.bs),
|
2421 | 0f1da449 | Paolo Bonzini | DEFINE_PROP_INT32("bootindex", SCSIDiskState, qdev.conf.bootindex, -1), |
2422 | 39bffca2 | Anthony Liguori | DEFINE_PROP_END_OF_LIST(), |
2423 | 39bffca2 | Anthony Liguori | }; |
2424 | 39bffca2 | Anthony Liguori | |
2425 | b9eea3e6 | Anthony Liguori | static void scsi_block_class_initfn(ObjectClass *klass, void *data) |
2426 | b9eea3e6 | Anthony Liguori | { |
2427 | 39bffca2 | Anthony Liguori | DeviceClass *dc = DEVICE_CLASS(klass); |
2428 | b9eea3e6 | Anthony Liguori | SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass); |
2429 | b9eea3e6 | Anthony Liguori | |
2430 | b9eea3e6 | Anthony Liguori | sc->init = scsi_block_initfn; |
2431 | b9eea3e6 | Anthony Liguori | sc->destroy = scsi_destroy; |
2432 | b9eea3e6 | Anthony Liguori | sc->alloc_req = scsi_block_new_request; |
2433 | 39bffca2 | Anthony Liguori | dc->fw_name = "disk";
|
2434 | 39bffca2 | Anthony Liguori | dc->desc = "SCSI block device passthrough";
|
2435 | 39bffca2 | Anthony Liguori | dc->reset = scsi_disk_reset; |
2436 | 39bffca2 | Anthony Liguori | dc->props = scsi_block_properties; |
2437 | 43b978b9 | Paolo Bonzini | dc->vmsd = &vmstate_scsi_disk_state; |
2438 | b9eea3e6 | Anthony Liguori | } |
2439 | b9eea3e6 | Anthony Liguori | |
2440 | 39bffca2 | Anthony Liguori | static TypeInfo scsi_block_info = {
|
2441 | 39bffca2 | Anthony Liguori | .name = "scsi-block",
|
2442 | 39bffca2 | Anthony Liguori | .parent = TYPE_SCSI_DEVICE, |
2443 | 39bffca2 | Anthony Liguori | .instance_size = sizeof(SCSIDiskState),
|
2444 | 39bffca2 | Anthony Liguori | .class_init = scsi_block_class_initfn, |
2445 | b9eea3e6 | Anthony Liguori | }; |
2446 | 336a6915 | Paolo Bonzini | #endif
|
2447 | b9eea3e6 | Anthony Liguori | |
2448 | 39bffca2 | Anthony Liguori | static Property scsi_disk_properties[] = {
|
2449 | 39bffca2 | Anthony Liguori | DEFINE_SCSI_DISK_PROPERTIES(), |
2450 | bfe3d7ac | Paolo Bonzini | DEFINE_PROP_BIT("removable", SCSIDiskState, features,
|
2451 | bfe3d7ac | Paolo Bonzini | SCSI_DISK_F_REMOVABLE, false),
|
2452 | da8365db | Paolo Bonzini | DEFINE_PROP_BIT("dpofua", SCSIDiskState, features,
|
2453 | da8365db | Paolo Bonzini | SCSI_DISK_F_DPOFUA, false),
|
2454 | 27395add | Paolo Bonzini | DEFINE_PROP_HEX64("wwn", SCSIDiskState, wwn, 0), |
2455 | 39bffca2 | Anthony Liguori | DEFINE_PROP_END_OF_LIST(), |
2456 | 39bffca2 | Anthony Liguori | }; |
2457 | 39bffca2 | Anthony Liguori | |
2458 | b9eea3e6 | Anthony Liguori | static void scsi_disk_class_initfn(ObjectClass *klass, void *data) |
2459 | b9eea3e6 | Anthony Liguori | { |
2460 | 39bffca2 | Anthony Liguori | DeviceClass *dc = DEVICE_CLASS(klass); |
2461 | b9eea3e6 | Anthony Liguori | SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass); |
2462 | b9eea3e6 | Anthony Liguori | |
2463 | b9eea3e6 | Anthony Liguori | sc->init = scsi_disk_initfn; |
2464 | b9eea3e6 | Anthony Liguori | sc->destroy = scsi_destroy; |
2465 | b9eea3e6 | Anthony Liguori | sc->alloc_req = scsi_new_request; |
2466 | b9eea3e6 | Anthony Liguori | sc->unit_attention_reported = scsi_disk_unit_attention_reported; |
2467 | 39bffca2 | Anthony Liguori | dc->fw_name = "disk";
|
2468 | 39bffca2 | Anthony Liguori | dc->desc = "virtual SCSI disk or CD-ROM (legacy)";
|
2469 | 39bffca2 | Anthony Liguori | dc->reset = scsi_disk_reset; |
2470 | 39bffca2 | Anthony Liguori | dc->props = scsi_disk_properties; |
2471 | 43b978b9 | Paolo Bonzini | dc->vmsd = &vmstate_scsi_disk_state; |
2472 | b9eea3e6 | Anthony Liguori | } |
2473 | b9eea3e6 | Anthony Liguori | |
2474 | 39bffca2 | Anthony Liguori | static TypeInfo scsi_disk_info = {
|
2475 | 39bffca2 | Anthony Liguori | .name = "scsi-disk",
|
2476 | 39bffca2 | Anthony Liguori | .parent = TYPE_SCSI_DEVICE, |
2477 | 39bffca2 | Anthony Liguori | .instance_size = sizeof(SCSIDiskState),
|
2478 | 39bffca2 | Anthony Liguori | .class_init = scsi_disk_class_initfn, |
2479 | d52affa7 | Gerd Hoffmann | }; |
2480 | d52affa7 | Gerd Hoffmann | |
2481 | 83f7d43a | Andreas Färber | static void scsi_disk_register_types(void) |
2482 | d52affa7 | Gerd Hoffmann | { |
2483 | 39bffca2 | Anthony Liguori | type_register_static(&scsi_hd_info); |
2484 | 39bffca2 | Anthony Liguori | type_register_static(&scsi_cd_info); |
2485 | b9eea3e6 | Anthony Liguori | #ifdef __linux__
|
2486 | 39bffca2 | Anthony Liguori | type_register_static(&scsi_block_info); |
2487 | b9eea3e6 | Anthony Liguori | #endif
|
2488 | 39bffca2 | Anthony Liguori | type_register_static(&scsi_disk_info); |
2489 | 8ccc2ace | ths | } |
2490 | 83f7d43a | Andreas Färber | |
2491 | 83f7d43a | Andreas Färber | type_init(scsi_disk_register_types) |