2 * SCSI Device emulation
4 * Copyright (c) 2006 CodeSourcery.
5 * Based on code by Fabrice Bellard
7 * Written by Paul Brook
9 * This code is licenced under the LGPL.
15 #define DPRINTF(fmt, args...) \
16 do { printf("scsi-disk: " fmt , ##args); } while (0)
18 #define DPRINTF(fmt, args...) do {} while(0)
21 #define BADF(fmt, args...) \
22 do { fprintf(stderr, "scsi-disk: " fmt , ##args); } while (0)
26 #define SENSE_NO_SENSE 0
27 #define SENSE_ILLEGAL_REQUEST 5
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. */
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. */
49 scsi_completionfn completion
;
53 static void scsi_command_complete(SCSIDevice
*s
, int sense
)
56 s
->completion(s
->opaque
, s
->tag
, sense
);
59 /* Read data from a scsi device. Returns nonzero on failure. */
60 int scsi_read_data(SCSIDevice
*s
, uint8_t *data
, uint32_t len
)
64 DPRINTF("Read %d (%d/%d)\n", len
, s
->buf_len
, s
->sector_count
);
65 if (s
->buf_len
== 0 && s
->sector_count
== 0)
72 memcpy(data
, s
->buf
+ s
->buf_pos
, n
);
82 if (n
> s
->sector_count
)
86 bdrv_read(s
->bdrv
, s
->sector
, data
, n
);
93 if (len
&& s
->sector_count
) {
94 bdrv_read(s
->bdrv
, s
->sector
, s
->buf
, 1);
99 /* Recurse to complete the partial read. */
100 return scsi_read_data(s
, data
, len
);
106 if (s
->buf_len
== 0 && s
->sector_count
== 0)
107 scsi_command_complete(s
, SENSE_NO_SENSE
);
112 /* Read data to a scsi device. Returns nonzero on failure. */
113 int scsi_write_data(SCSIDevice
*s
, uint8_t *data
, uint32_t len
)
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");
123 if (s
->sector_count
== 0)
126 if (s
->buf_len
!= 0 || len
< 512) {
127 n
= 512 - s
->buf_len
;
131 memcpy(s
->buf
+ s
->buf_len
, data
, 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);
145 if (n
> s
->sector_count
)
149 bdrv_write(s
->bdrv
, s
->sector
, data
, n
);
153 s
->sector_count
-= n
;
159 if (len
&& s
->sector_count
) {
160 /* Recurse to complete the partial write. */
161 return scsi_write_data(s
, data
, len
);
167 if (s
->sector_count
== 0)
168 scsi_command_complete(s
, SENSE_NO_SENSE
);
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
)
192 DPRINTF("Command: 0x%02x", buf
[0]);
193 switch (s
->command
>> 5) {
195 lba
= buf
[3] | (buf
[2] << 8) | ((buf
[1] & 0x1f) << 16);
201 lba
= buf
[5] | (buf
[4] << 8) | (buf
[3] << 16) | (buf
[2] << 24);
202 len
= buf
[8] | (buf
[7] << 8);
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);
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);
216 BADF("Unsupported command length, command %x\n", s
->command
);
222 for (i
= 1; i
< cmdlen
; i
++) {
223 printf(" 0x%02x", buf
[i
]);
228 if (lun
|| buf
[1] >> 5) {
229 /* Only LUN 0 supported. */
230 DPRINTF("Unimplemented LUN %d\n", lun
? lun
: buf
[1] >> 5);
233 switch (s
->command
) {
235 DPRINTF("Test Unit Ready\n");
238 DPRINTF("Request Sense (len %d)\n", len
);
244 s
->buf
[2] = s
->sense
;
248 DPRINTF("Inquiry (len %d)\n", len
);
250 BADF("Inquiry buffer too small (%d)\n", len
);
252 memset(s
->buf
, 0, 36);
253 if (bdrv_get_type_hint(s
->bdrv
) == BDRV_TYPE_CDROM
) {
256 memcpy(&s
->buf
[16], "QEMU CD-ROM ", 16);
259 memcpy(&s
->buf
[16], "QEMU HARDDISK ", 16);
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. */
266 s
->buf
[3] = 2; /* Format 2 */
271 DPRINTF("Reserve(6)\n");
276 DPRINTF("Release(6)\n");
286 page
= buf
[2] & 0x3f;
287 DPRINTF("Mode Sense (page %d, len %d)\n", page
, len
);
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. */
296 if ((page
== 8 || page
== 0x3f)) {
303 if ((page
== 0x3f || page
== 0x2a)
304 && (bdrv_get_type_hint(s
->bdrv
) == BDRV_TYPE_CDROM
)) {
305 /* CD Capabilities and Mechanical Status page. */
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,
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
319 p
[8] = (50 * 176) >> 8; // 50x read speed
320 p
[9] = (50 * 176) & 0xff;
321 p
[10] = 0 >> 8; // No volume
323 p
[12] = 2048 >> 8; // 2M buffer
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;
333 s
->buf_len
= p
- s
->buf
;
334 s
->buf
[0] = s
->buf_len
- 4;
335 if (s
->buf_len
> len
)
340 DPRINTF("Start Stop Unit\n");
343 DPRINTF("Prevent Allow Medium Removal (prevent = %d)\n", buf
[4] & 3);
344 bdrv_set_locked(s
->bdrv
, buf
[4] & 1);
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;
357 s
->buf
[6] = s
->cluster_size
* 2;
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
;
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
;
375 DPRINTF("Syncronise cache (sector %d, count %d)\n", lba
, len
);
380 int start_track
, format
, msf
, toclen
;
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);
389 toclen
= cdrom_read_toc(nb_sectors
, s
->buf
, msf
, start_track
);
392 /* multi session : only a single session defined */
394 memset(s
->buf
, 0, 12);
400 toclen
= cdrom_read_toc_raw(nb_sectors
, s
->buf
, msf
, start_track
);
412 DPRINTF("Read TOC error\n");
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
424 DPRINTF("Reserve(10)\n");
429 DPRINTF("Release(10)\n");
434 DPRINTF("Report LUNs (len %d)\n", len
);
437 memset(s
->buf
, 0, 16);
442 DPRINTF("Unknown SCSI command (%2.2x)\n", buf
[0]);
444 scsi_command_complete(s
, SENSE_ILLEGAL_REQUEST
);
447 if (s
->sector_count
== 0 && s
->buf_len
== 0) {
448 scsi_command_complete(s
, SENSE_NO_SENSE
);
450 len
= s
->sector_count
* 512 + s
->buf_len
;
451 return is_write
? -len
: len
;
454 void scsi_disk_destroy(SCSIDevice
*s
)
460 SCSIDevice
*scsi_disk_init(BlockDriverState
*bdrv
,
461 scsi_completionfn completion
,
466 s
= (SCSIDevice
*)qemu_mallocz(sizeof(SCSIDevice
));
468 s
->completion
= completion
;
470 if (bdrv_get_type_hint(s
->bdrv
) == BDRV_TYPE_CDROM
) {