debuggers.hg

view tools/ioemu/hw/scsi-disk.c @ 10995:08a11694b109

[qemu] Update ioemu to qemu 0.8.2.

Signed-off-by: Christian Limpach <Christian.Limpach@xensource.com>
author chris@kneesaa.uk.xensource.com
date Mon Aug 07 18:25:30 2006 +0100 (2006-08-07)
parents
children 00618037d37d
line source
1 /*
2 * SCSI Device emulation
3 *
4 * Copyright (c) 2006 CodeSourcery.
5 * Based on code by Fabrice Bellard
6 *
7 * Written by Paul Brook
8 *
9 * This code is licenced under the LGPL.
10 */
12 //#define DEBUG_SCSI
14 #ifdef DEBUG_SCSI
15 #define DPRINTF(fmt, args...) \
16 do { printf("scsi-disk: " fmt , ##args); } while (0)
17 #else
18 #define DPRINTF(fmt, args...) do {} while(0)
19 #endif
21 #define BADF(fmt, args...) \
22 do { fprintf(stderr, "scsi-disk: " fmt , ##args); } while (0)
24 #include "vl.h"
26 #define SENSE_NO_SENSE 0
27 #define SENSE_ILLEGAL_REQUEST 5
29 struct SCSIDevice
30 {
31 int command;
32 uint32_t tag;
33 BlockDriverState *bdrv;
34 /* The qemu block layer uses a fixed 512 byte sector size.
35 This is the number of 512 byte blocks in a single scsi sector. */
36 int cluster_size;
37 /* When transfering data buf_pos and buf_len contain a partially
38 transferred block of data (or response to a command), and
39 sector/sector_count identify any remaining sectors.
40 Both sector and sector_count are in terms of qemu 512 byte blocks. */
41 /* ??? We should probably keep track of whether the data trasfer is
42 a read or a write. Currently we rely on the host getting it right. */
43 int sector;
44 int sector_count;
45 int buf_pos;
46 int buf_len;
47 int sense;
48 char buf[512];
49 scsi_completionfn completion;
50 void *opaque;
51 };
53 static void scsi_command_complete(SCSIDevice *s, int sense)
54 {
55 s->sense = sense;
56 s->completion(s->opaque, s->tag, sense);
57 }
59 /* Read data from a scsi device. Returns nonzero on failure. */
60 int scsi_read_data(SCSIDevice *s, uint8_t *data, uint32_t len)
61 {
62 uint32_t n;
64 DPRINTF("Read %d (%d/%d)\n", len, s->buf_len, s->sector_count);
65 if (s->buf_len == 0 && s->sector_count == 0)
66 return 1;
68 if (s->buf_len) {
69 n = s->buf_len;
70 if (n > len)
71 n = len;
72 memcpy(data, s->buf + s->buf_pos, n);
73 s->buf_pos += n;
74 s->buf_len -= n;
75 data += n;
76 len -= n;
77 if (s->buf_len == 0)
78 s->buf_pos = 0;
79 }
81 n = len / 512;
82 if (n > s->sector_count)
83 n = s->sector_count;
85 if (n != 0) {
86 bdrv_read(s->bdrv, s->sector, data, n);
87 data += n * 512;
88 len -= n * 512;
89 s->sector += n;
90 s->sector_count -= n;
91 }
93 if (len && s->sector_count) {
94 bdrv_read(s->bdrv, s->sector, s->buf, 1);
95 s->sector++;
96 s->sector_count--;
97 s->buf_pos = 0;
98 s->buf_len = 512;
99 /* Recurse to complete the partial read. */
100 return scsi_read_data(s, data, len);
101 }
103 if (len != 0)
104 return 1;
106 if (s->buf_len == 0 && s->sector_count == 0)
107 scsi_command_complete(s, SENSE_NO_SENSE);
109 return 0;
110 }
112 /* Read data to a scsi device. Returns nonzero on failure. */
113 int scsi_write_data(SCSIDevice *s, uint8_t *data, uint32_t len)
114 {
115 uint32_t n;
117 DPRINTF("Write %d (%d/%d)\n", len, s->buf_len, s->sector_count);
118 if (s->buf_pos != 0) {
119 BADF("Bad state on write\n");
120 return 1;
121 }
123 if (s->sector_count == 0)
124 return 1;
126 if (s->buf_len != 0 || len < 512) {
127 n = 512 - s->buf_len;
128 if (n > len)
129 n = len;
131 memcpy(s->buf + s->buf_len, data, n);
132 data += n;
133 s->buf_len += n;
134 len -= n;
135 if (s->buf_len == 512) {
136 /* A full sector has been accumulated. Write it to disk. */
137 bdrv_write(s->bdrv, s->sector, s->buf, 1);
138 s->buf_len = 0;
139 s->sector++;
140 s->sector_count--;
141 }
142 }
144 n = len / 512;
145 if (n > s->sector_count)
146 n = s->sector_count;
148 if (n != 0) {
149 bdrv_write(s->bdrv, s->sector, data, n);
150 data += n * 512;
151 len -= n * 512;
152 s->sector += n;
153 s->sector_count -= n;
154 }
156 if (len >= 512)
157 return 1;
159 if (len && s->sector_count) {
160 /* Recurse to complete the partial write. */
161 return scsi_write_data(s, data, len);
162 }
164 if (len != 0)
165 return 1;
167 if (s->sector_count == 0)
168 scsi_command_complete(s, SENSE_NO_SENSE);
170 return 0;
171 }
173 /* Execute a scsi command. Returns the length of the data expected by the
174 command. This will be Positive for data transfers from the device
175 (eg. disk reads), negative for transfers to the device (eg. disk writes),
176 and zero if the command does not transfer any data. */
178 int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun)
179 {
180 int64_t nb_sectors;
181 uint32_t lba;
182 uint32_t len;
183 int cmdlen;
184 int is_write;
186 s->command = buf[0];
187 s->tag = tag;
188 s->sector_count = 0;
189 s->buf_pos = 0;
190 s->buf_len = 0;
191 is_write = 0;
192 DPRINTF("Command: 0x%02x", buf[0]);
193 switch (s->command >> 5) {
194 case 0:
195 lba = buf[3] | (buf[2] << 8) | ((buf[1] & 0x1f) << 16);
196 len = buf[4];
197 cmdlen = 6;
198 break;
199 case 1:
200 case 2:
201 lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24);
202 len = buf[8] | (buf[7] << 8);
203 cmdlen = 10;
204 break;
205 case 4:
206 lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24);
207 len = buf[13] | (buf[12] << 8) | (buf[11] << 16) | (buf[10] << 24);
208 cmdlen = 16;
209 break;
210 case 5:
211 lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24);
212 len = buf[9] | (buf[8] << 8) | (buf[7] << 16) | (buf[6] << 24);
213 cmdlen = 12;
214 break;
215 default:
216 BADF("Unsupported command length, command %x\n", s->command);
217 goto fail;
218 }
219 #ifdef DEBUG_SCSI
220 {
221 int i;
222 for (i = 1; i < cmdlen; i++) {
223 printf(" 0x%02x", buf[i]);
224 }
225 printf("\n");
226 }
227 #endif
228 if (lun || buf[1] >> 5) {
229 /* Only LUN 0 supported. */
230 DPRINTF("Unimplemented LUN %d\n", lun ? lun : buf[1] >> 5);
231 goto fail;
232 }
233 switch (s->command) {
234 case 0x0:
235 DPRINTF("Test Unit Ready\n");
236 break;
237 case 0x03:
238 DPRINTF("Request Sense (len %d)\n", len);
239 if (len < 4)
240 goto fail;
241 memset(buf, 0, 4);
242 s->buf[0] = 0xf0;
243 s->buf[1] = 0;
244 s->buf[2] = s->sense;
245 s->buf_len = 4;
246 break;
247 case 0x12:
248 DPRINTF("Inquiry (len %d)\n", len);
249 if (len < 36) {
250 BADF("Inquiry buffer too small (%d)\n", len);
251 }
252 memset(s->buf, 0, 36);
253 if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) {
254 s->buf[0] = 5;
255 s->buf[1] = 0x80;
256 memcpy(&s->buf[16], "QEMU CD-ROM ", 16);
257 } else {
258 s->buf[0] = 0;
259 memcpy(&s->buf[16], "QEMU HARDDISK ", 16);
260 }
261 memcpy(&s->buf[8], "QEMU ", 8);
262 memcpy(&s->buf[32], QEMU_VERSION, 4);
263 /* Identify device as SCSI-3 rev 1.
264 Some later commands are also implemented. */
265 s->buf[2] = 3;
266 s->buf[3] = 2; /* Format 2 */
267 s->buf[4] = 32;
268 s->buf_len = 36;
269 break;
270 case 0x16:
271 DPRINTF("Reserve(6)\n");
272 if (buf[1] & 1)
273 goto fail;
274 break;
275 case 0x17:
276 DPRINTF("Release(6)\n");
277 if (buf[1] & 1)
278 goto fail;
279 break;
280 case 0x1a:
281 case 0x5a:
282 {
283 char *p;
284 int page;
286 page = buf[2] & 0x3f;
287 DPRINTF("Mode Sense (page %d, len %d)\n", page, len);
288 p = s->buf;
289 memset(p, 0, 4);
290 s->buf[1] = 0; /* Default media type. */
291 s->buf[3] = 0; /* Block descriptor length. */
292 if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) {
293 s->buf[2] = 0x80; /* Readonly. */
294 }
295 p += 4;
296 if ((page == 8 || page == 0x3f)) {
297 /* Caching page. */
298 p[0] = 8;
299 p[1] = 0x12;
300 p[2] = 4; /* WCE */
301 p += 19;
302 }
303 if ((page == 0x3f || page == 0x2a)
304 && (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM)) {
305 /* CD Capabilities and Mechanical Status page. */
306 p[0] = 0x2a;
307 p[1] = 0x14;
308 p[2] = 3; // CD-R & CD-RW read
309 p[3] = 0; // Writing not supported
310 p[4] = 0x7f; /* Audio, composite, digital out,
311 mode 2 form 1&2, multi session */
312 p[5] = 0xff; /* CD DA, DA accurate, RW supported,
313 RW corrected, C2 errors, ISRC,
314 UPC, Bar code */
315 p[6] = 0x2d | (bdrv_is_locked(s->bdrv)? 2 : 0);
316 /* Locking supported, jumper present, eject, tray */
317 p[7] = 0; /* no volume & mute control, no
318 changer */
319 p[8] = (50 * 176) >> 8; // 50x read speed
320 p[9] = (50 * 176) & 0xff;
321 p[10] = 0 >> 8; // No volume
322 p[11] = 0 & 0xff;
323 p[12] = 2048 >> 8; // 2M buffer
324 p[13] = 2048 & 0xff;
325 p[14] = (16 * 176) >> 8; // 16x read speed current
326 p[15] = (16 * 176) & 0xff;
327 p[18] = (16 * 176) >> 8; // 16x write speed
328 p[19] = (16 * 176) & 0xff;
329 p[20] = (16 * 176) >> 8; // 16x write speed current
330 p[21] = (16 * 176) & 0xff;
331 p += 21;
332 }
333 s->buf_len = p - s->buf;
334 s->buf[0] = s->buf_len - 4;
335 if (s->buf_len > len)
336 s->buf_len = len;
337 }
338 break;
339 case 0x1b:
340 DPRINTF("Start Stop Unit\n");
341 break;
342 case 0x1e:
343 DPRINTF("Prevent Allow Medium Removal (prevent = %d)\n", buf[4] & 3);
344 bdrv_set_locked(s->bdrv, buf[4] & 1);
345 break;
346 case 0x25:
347 DPRINTF("Read Capacity\n");
348 /* The normal LEN field for this command is zero. */
349 memset(s->buf, 0, 8);
350 bdrv_get_geometry(s->bdrv, &nb_sectors);
351 s->buf[0] = (nb_sectors >> 24) & 0xff;
352 s->buf[1] = (nb_sectors >> 16) & 0xff;
353 s->buf[2] = (nb_sectors >> 8) & 0xff;
354 s->buf[3] = nb_sectors & 0xff;
355 s->buf[4] = 0;
356 s->buf[5] = 0;
357 s->buf[6] = s->cluster_size * 2;
358 s->buf[7] = 0;
359 s->buf_len = 8;
360 break;
361 case 0x08:
362 case 0x28:
363 DPRINTF("Read (sector %d, count %d)\n", lba, len);
364 s->sector = lba * s->cluster_size;
365 s->sector_count = len * s->cluster_size;
366 break;
367 case 0x0a:
368 case 0x2a:
369 DPRINTF("Write (sector %d, count %d)\n", lba, len);
370 s->sector = lba * s->cluster_size;
371 s->sector_count = len * s->cluster_size;
372 is_write = 1;
373 break;
374 case 0x35:
375 DPRINTF("Syncronise cache (sector %d, count %d)\n", lba, len);
376 bdrv_flush(s->bdrv);
377 break;
378 case 0x43:
379 {
380 int start_track, format, msf, toclen;
382 msf = buf[1] & 2;
383 format = buf[2] & 0xf;
384 start_track = buf[6];
385 bdrv_get_geometry(s->bdrv, &nb_sectors);
386 DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1);
387 switch(format) {
388 case 0:
389 toclen = cdrom_read_toc(nb_sectors, s->buf, msf, start_track);
390 break;
391 case 1:
392 /* multi session : only a single session defined */
393 toclen = 12;
394 memset(s->buf, 0, 12);
395 s->buf[1] = 0x0a;
396 s->buf[2] = 0x01;
397 s->buf[3] = 0x01;
398 break;
399 case 2:
400 toclen = cdrom_read_toc_raw(nb_sectors, s->buf, msf, start_track);
401 break;
402 default:
403 goto error_cmd;
404 }
405 if (toclen > 0) {
406 if (len > toclen)
407 len = toclen;
408 s->buf_len = len;
409 break;
410 }
411 error_cmd:
412 DPRINTF("Read TOC error\n");
413 goto fail;
414 }
415 case 0x46:
416 DPRINTF("Get Configuration (rt %d, maxlen %d)\n", buf[1] & 3, len);
417 memset(s->buf, 0, 8);
418 /* ??? This shoud probably return much more information. For now
419 just return the basic header indicating the CD-ROM profile. */
420 s->buf[7] = 8; // CD-ROM
421 s->buf_len = 8;
422 break;
423 case 0x56:
424 DPRINTF("Reserve(10)\n");
425 if (buf[1] & 3)
426 goto fail;
427 break;
428 case 0x57:
429 DPRINTF("Release(10)\n");
430 if (buf[1] & 3)
431 goto fail;
432 break;
433 case 0xa0:
434 DPRINTF("Report LUNs (len %d)\n", len);
435 if (len < 16)
436 goto fail;
437 memset(s->buf, 0, 16);
438 s->buf[3] = 8;
439 s->buf_len = 16;
440 break;
441 default:
442 DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
443 fail:
444 scsi_command_complete(s, SENSE_ILLEGAL_REQUEST);
445 return 0;
446 }
447 if (s->sector_count == 0 && s->buf_len == 0) {
448 scsi_command_complete(s, SENSE_NO_SENSE);
449 }
450 len = s->sector_count * 512 + s->buf_len;
451 return is_write ? -len : len;
452 }
454 void scsi_disk_destroy(SCSIDevice *s)
455 {
456 bdrv_close(s->bdrv);
457 qemu_free(s);
458 }
460 SCSIDevice *scsi_disk_init(BlockDriverState *bdrv,
461 scsi_completionfn completion,
462 void *opaque)
463 {
464 SCSIDevice *s;
466 s = (SCSIDevice *)qemu_mallocz(sizeof(SCSIDevice));
467 s->bdrv = bdrv;
468 s->completion = completion;
469 s->opaque = opaque;
470 if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) {
471 s->cluster_size = 4;
472 } else {
473 s->cluster_size = 1;
474 }
476 return s;
477 }