|
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 * |
|
11 * Note that this file only handles the SCSI architecture model and device |
|
12 * commands. Emulation of interface/link layer protocols is handled by |
|
13 * the host adapter emulator. |
|
14 */ |
|
15 |
|
16 //#define DEBUG_SCSI |
|
17 |
|
18 #ifdef DEBUG_SCSI |
|
19 #define DPRINTF(fmt, args...) \ |
|
20 do { printf("scsi-disk: " fmt , ##args); } while (0) |
|
21 #else |
|
22 #define DPRINTF(fmt, args...) do {} while(0) |
|
23 #endif |
|
24 |
|
25 #define BADF(fmt, args...) \ |
|
26 do { fprintf(stderr, "scsi-disk: " fmt , ##args); } while (0) |
|
27 |
|
28 #include "qemu-common.h" |
|
29 #include "block.h" |
|
30 #include "scsi-disk.h" |
|
31 |
|
32 #define SENSE_NO_SENSE 0 |
|
33 #define SENSE_NOT_READY 2 |
|
34 #define SENSE_HARDWARE_ERROR 4 |
|
35 #define SENSE_ILLEGAL_REQUEST 5 |
|
36 |
|
37 #define STATUS_GOOD 0 |
|
38 #define STATUS_CHECK_CONDITION 2 |
|
39 |
|
40 #define SCSI_DMA_BUF_SIZE 131072 |
|
41 #define SCSI_MAX_INQUIRY_LEN 256 |
|
42 |
|
43 typedef struct SCSIRequest { |
|
44 SCSIDeviceState *dev; |
|
45 uint32_t tag; |
|
46 /* ??? We should probably keep track of whether the data trasfer is |
|
47 a read or a write. Currently we rely on the host getting it right. */ |
|
48 /* Both sector and sector_count are in terms of qemu 512 byte blocks. */ |
|
49 int sector; |
|
50 int sector_count; |
|
51 /* The amounnt of data in the buffer. */ |
|
52 int buf_len; |
|
53 uint8_t *dma_buf; |
|
54 BlockDriverAIOCB *aiocb; |
|
55 struct SCSIRequest *next; |
|
56 } SCSIRequest; |
|
57 |
|
58 struct SCSIDeviceState |
|
59 { |
|
60 BlockDriverState *bdrv; |
|
61 SCSIRequest *requests; |
|
62 /* The qemu block layer uses a fixed 512 byte sector size. |
|
63 This is the number of 512 byte blocks in a single scsi sector. */ |
|
64 int cluster_size; |
|
65 int sense; |
|
66 int tcq; |
|
67 /* Completion functions may be called from either scsi_{read,write}_data |
|
68 or from the AIO completion routines. */ |
|
69 scsi_completionfn completion; |
|
70 void *opaque; |
|
71 }; |
|
72 |
|
73 /* Global pool of SCSIRequest structures. */ |
|
74 static SCSIRequest *free_requests = NULL; |
|
75 |
|
76 static SCSIRequest *scsi_new_request(SCSIDeviceState *s, uint32_t tag) |
|
77 { |
|
78 SCSIRequest *r; |
|
79 |
|
80 if (free_requests) { |
|
81 r = free_requests; |
|
82 free_requests = r->next; |
|
83 } else { |
|
84 r = qemu_malloc(sizeof(SCSIRequest)); |
|
85 r->dma_buf = qemu_memalign(512, SCSI_DMA_BUF_SIZE); |
|
86 } |
|
87 r->dev = s; |
|
88 r->tag = tag; |
|
89 r->sector_count = 0; |
|
90 r->buf_len = 0; |
|
91 r->aiocb = NULL; |
|
92 |
|
93 r->next = s->requests; |
|
94 s->requests = r; |
|
95 return r; |
|
96 } |
|
97 |
|
98 static void scsi_remove_request(SCSIRequest *r) |
|
99 { |
|
100 SCSIRequest *last; |
|
101 SCSIDeviceState *s = r->dev; |
|
102 |
|
103 if (s->requests == r) { |
|
104 s->requests = r->next; |
|
105 } else { |
|
106 last = s->requests; |
|
107 while (last && last->next != r) |
|
108 last = last->next; |
|
109 if (last) { |
|
110 last->next = r->next; |
|
111 } else { |
|
112 BADF("Orphaned request\n"); |
|
113 } |
|
114 } |
|
115 r->next = free_requests; |
|
116 free_requests = r; |
|
117 } |
|
118 |
|
119 static SCSIRequest *scsi_find_request(SCSIDeviceState *s, uint32_t tag) |
|
120 { |
|
121 SCSIRequest *r; |
|
122 |
|
123 r = s->requests; |
|
124 while (r && r->tag != tag) |
|
125 r = r->next; |
|
126 |
|
127 return r; |
|
128 } |
|
129 |
|
130 /* Helper function for command completion. */ |
|
131 static void scsi_command_complete(SCSIRequest *r, int status, int sense) |
|
132 { |
|
133 SCSIDeviceState *s = r->dev; |
|
134 uint32_t tag; |
|
135 DPRINTF("Command complete tag=0x%x status=%d sense=%d\n", r->tag, status, sense); |
|
136 s->sense = sense; |
|
137 tag = r->tag; |
|
138 scsi_remove_request(r); |
|
139 s->completion(s->opaque, SCSI_REASON_DONE, tag, status); |
|
140 } |
|
141 |
|
142 /* Cancel a pending data transfer. */ |
|
143 static void scsi_cancel_io(SCSIDevice *d, uint32_t tag) |
|
144 { |
|
145 SCSIDeviceState *s = d->state; |
|
146 SCSIRequest *r; |
|
147 DPRINTF("Cancel tag=0x%x\n", tag); |
|
148 r = scsi_find_request(s, tag); |
|
149 if (r) { |
|
150 if (r->aiocb) |
|
151 bdrv_aio_cancel(r->aiocb); |
|
152 r->aiocb = NULL; |
|
153 scsi_remove_request(r); |
|
154 } |
|
155 } |
|
156 |
|
157 static void scsi_read_complete(void * opaque, int ret) |
|
158 { |
|
159 SCSIRequest *r = (SCSIRequest *)opaque; |
|
160 SCSIDeviceState *s = r->dev; |
|
161 |
|
162 if (ret) { |
|
163 DPRINTF("IO error\n"); |
|
164 s->completion(s->opaque, SCSI_REASON_DATA, r->tag, 0); |
|
165 scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_NO_SENSE); |
|
166 return; |
|
167 } |
|
168 DPRINTF("Data ready tag=0x%x len=%d\n", r->tag, r->buf_len); |
|
169 |
|
170 s->completion(s->opaque, SCSI_REASON_DATA, r->tag, r->buf_len); |
|
171 } |
|
172 |
|
173 /* Read more data from scsi device into buffer. */ |
|
174 static void scsi_read_data(SCSIDevice *d, uint32_t tag) |
|
175 { |
|
176 SCSIDeviceState *s = d->state; |
|
177 SCSIRequest *r; |
|
178 uint32_t n; |
|
179 |
|
180 r = scsi_find_request(s, tag); |
|
181 if (!r) { |
|
182 BADF("Bad read tag 0x%x\n", tag); |
|
183 /* ??? This is the wrong error. */ |
|
184 scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR); |
|
185 return; |
|
186 } |
|
187 if (r->sector_count == (uint32_t)-1) { |
|
188 DPRINTF("Read buf_len=%d\n", r->buf_len); |
|
189 r->sector_count = 0; |
|
190 s->completion(s->opaque, SCSI_REASON_DATA, r->tag, r->buf_len); |
|
191 return; |
|
192 } |
|
193 DPRINTF("Read sector_count=%d\n", r->sector_count); |
|
194 if (r->sector_count == 0) { |
|
195 scsi_command_complete(r, STATUS_GOOD, SENSE_NO_SENSE); |
|
196 return; |
|
197 } |
|
198 |
|
199 n = r->sector_count; |
|
200 if (n > SCSI_DMA_BUF_SIZE / 512) |
|
201 n = SCSI_DMA_BUF_SIZE / 512; |
|
202 |
|
203 r->buf_len = n * 512; |
|
204 r->aiocb = bdrv_aio_read(s->bdrv, r->sector, r->dma_buf, n, |
|
205 scsi_read_complete, r); |
|
206 if (r->aiocb == NULL) |
|
207 scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR); |
|
208 r->sector += n; |
|
209 r->sector_count -= n; |
|
210 } |
|
211 |
|
212 static void scsi_write_complete(void * opaque, int ret) |
|
213 { |
|
214 SCSIRequest *r = (SCSIRequest *)opaque; |
|
215 SCSIDeviceState *s = r->dev; |
|
216 uint32_t len; |
|
217 |
|
218 if (ret) { |
|
219 fprintf(stderr, "scsi-disc: IO write error\n"); |
|
220 exit(1); |
|
221 } |
|
222 |
|
223 r->aiocb = NULL; |
|
224 if (r->sector_count == 0) { |
|
225 scsi_command_complete(r, STATUS_GOOD, SENSE_NO_SENSE); |
|
226 } else { |
|
227 len = r->sector_count * 512; |
|
228 if (len > SCSI_DMA_BUF_SIZE) { |
|
229 len = SCSI_DMA_BUF_SIZE; |
|
230 } |
|
231 r->buf_len = len; |
|
232 DPRINTF("Write complete tag=0x%x more=%d\n", r->tag, len); |
|
233 s->completion(s->opaque, SCSI_REASON_DATA, r->tag, len); |
|
234 } |
|
235 } |
|
236 |
|
237 /* Write data to a scsi device. Returns nonzero on failure. |
|
238 The transfer may complete asynchronously. */ |
|
239 static int scsi_write_data(SCSIDevice *d, uint32_t tag) |
|
240 { |
|
241 SCSIDeviceState *s = d->state; |
|
242 SCSIRequest *r; |
|
243 uint32_t n; |
|
244 |
|
245 DPRINTF("Write data tag=0x%x\n", tag); |
|
246 r = scsi_find_request(s, tag); |
|
247 if (!r) { |
|
248 BADF("Bad write tag 0x%x\n", tag); |
|
249 scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR); |
|
250 return 1; |
|
251 } |
|
252 if (r->aiocb) |
|
253 BADF("Data transfer already in progress\n"); |
|
254 n = r->buf_len / 512; |
|
255 if (n) { |
|
256 r->aiocb = bdrv_aio_write(s->bdrv, r->sector, r->dma_buf, n, |
|
257 scsi_write_complete, r); |
|
258 if (r->aiocb == NULL) |
|
259 scsi_command_complete(r, STATUS_CHECK_CONDITION, |
|
260 SENSE_HARDWARE_ERROR); |
|
261 r->sector += n; |
|
262 r->sector_count -= n; |
|
263 } else { |
|
264 /* Invoke completion routine to fetch data from host. */ |
|
265 scsi_write_complete(r, 0); |
|
266 } |
|
267 |
|
268 return 0; |
|
269 } |
|
270 |
|
271 /* Return a pointer to the data buffer. */ |
|
272 static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag) |
|
273 { |
|
274 SCSIDeviceState *s = d->state; |
|
275 SCSIRequest *r; |
|
276 |
|
277 r = scsi_find_request(s, tag); |
|
278 if (!r) { |
|
279 BADF("Bad buffer tag 0x%x\n", tag); |
|
280 return NULL; |
|
281 } |
|
282 return r->dma_buf; |
|
283 } |
|
284 |
|
285 /* Execute a scsi command. Returns the length of the data expected by the |
|
286 command. This will be Positive for data transfers from the device |
|
287 (eg. disk reads), negative for transfers to the device (eg. disk writes), |
|
288 and zero if the command does not transfer any data. */ |
|
289 |
|
290 static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, |
|
291 uint8_t *buf, int lun) |
|
292 { |
|
293 SCSIDeviceState *s = d->state; |
|
294 uint64_t nb_sectors; |
|
295 uint32_t lba; |
|
296 uint32_t len; |
|
297 int cmdlen; |
|
298 int is_write; |
|
299 uint8_t command; |
|
300 uint8_t *outbuf; |
|
301 SCSIRequest *r; |
|
302 |
|
303 command = buf[0]; |
|
304 r = scsi_find_request(s, tag); |
|
305 if (r) { |
|
306 BADF("Tag 0x%x already in use\n", tag); |
|
307 scsi_cancel_io(d, tag); |
|
308 } |
|
309 /* ??? Tags are not unique for different luns. We only implement a |
|
310 single lun, so this should not matter. */ |
|
311 r = scsi_new_request(s, tag); |
|
312 outbuf = r->dma_buf; |
|
313 is_write = 0; |
|
314 DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]); |
|
315 switch (command >> 5) { |
|
316 case 0: |
|
317 lba = buf[3] | (buf[2] << 8) | ((buf[1] & 0x1f) << 16); |
|
318 len = buf[4]; |
|
319 cmdlen = 6; |
|
320 break; |
|
321 case 1: |
|
322 case 2: |
|
323 lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24); |
|
324 len = buf[8] | (buf[7] << 8); |
|
325 cmdlen = 10; |
|
326 break; |
|
327 case 4: |
|
328 lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24); |
|
329 len = buf[13] | (buf[12] << 8) | (buf[11] << 16) | (buf[10] << 24); |
|
330 cmdlen = 16; |
|
331 break; |
|
332 case 5: |
|
333 lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24); |
|
334 len = buf[9] | (buf[8] << 8) | (buf[7] << 16) | (buf[6] << 24); |
|
335 cmdlen = 12; |
|
336 break; |
|
337 default: |
|
338 BADF("Unsupported command length, command %x\n", command); |
|
339 goto fail; |
|
340 } |
|
341 #ifdef DEBUG_SCSI |
|
342 { |
|
343 int i; |
|
344 for (i = 1; i < cmdlen; i++) { |
|
345 printf(" 0x%02x", buf[i]); |
|
346 } |
|
347 printf("\n"); |
|
348 } |
|
349 #endif |
|
350 if (lun || buf[1] >> 5) { |
|
351 /* Only LUN 0 supported. */ |
|
352 DPRINTF("Unimplemented LUN %d\n", lun ? lun : buf[1] >> 5); |
|
353 if (command != 0x03 && command != 0x12) /* REQUEST SENSE and INQUIRY */ |
|
354 goto fail; |
|
355 } |
|
356 switch (command) { |
|
357 case 0x0: |
|
358 DPRINTF("Test Unit Ready\n"); |
|
359 break; |
|
360 case 0x03: |
|
361 DPRINTF("Request Sense (len %d)\n", len); |
|
362 if (len < 4) |
|
363 goto fail; |
|
364 memset(outbuf, 0, 4); |
|
365 outbuf[0] = 0xf0; |
|
366 outbuf[1] = 0; |
|
367 outbuf[2] = s->sense; |
|
368 r->buf_len = 4; |
|
369 break; |
|
370 case 0x12: |
|
371 DPRINTF("Inquiry (len %d)\n", len); |
|
372 if (buf[1] & 0x2) { |
|
373 /* Command support data - optional, not implemented */ |
|
374 BADF("optional INQUIRY command support request not implemented\n"); |
|
375 goto fail; |
|
376 } |
|
377 else if (buf[1] & 0x1) { |
|
378 /* Vital product data */ |
|
379 uint8_t page_code = buf[2]; |
|
380 if (len < 4) { |
|
381 BADF("Error: Inquiry (EVPD[%02X]) buffer size %d is " |
|
382 "less than 4\n", page_code, len); |
|
383 goto fail; |
|
384 } |
|
385 |
|
386 switch (page_code) { |
|
387 case 0x00: |
|
388 { |
|
389 /* Supported page codes, mandatory */ |
|
390 DPRINTF("Inquiry EVPD[Supported pages] " |
|
391 "buffer size %d\n", len); |
|
392 |
|
393 r->buf_len = 0; |
|
394 |
|
395 if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { |
|
396 outbuf[r->buf_len++] = 5; |
|
397 } else { |
|
398 outbuf[r->buf_len++] = 0; |
|
399 } |
|
400 |
|
401 outbuf[r->buf_len++] = 0x00; // this page |
|
402 outbuf[r->buf_len++] = 0x00; |
|
403 outbuf[r->buf_len++] = 3; // number of pages |
|
404 outbuf[r->buf_len++] = 0x00; // list of supported pages (this page) |
|
405 outbuf[r->buf_len++] = 0x80; // unit serial number |
|
406 outbuf[r->buf_len++] = 0x83; // device identification |
|
407 } |
|
408 break; |
|
409 case 0x80: |
|
410 { |
|
411 /* Device serial number, optional */ |
|
412 if (len < 4) { |
|
413 BADF("Error: EVPD[Serial number] Inquiry buffer " |
|
414 "size %d too small, %d needed\n", len, 4); |
|
415 goto fail; |
|
416 } |
|
417 |
|
418 DPRINTF("Inquiry EVPD[Serial number] buffer size %d\n", len); |
|
419 |
|
420 r->buf_len = 0; |
|
421 |
|
422 /* Supported page codes */ |
|
423 if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { |
|
424 outbuf[r->buf_len++] = 5; |
|
425 } else { |
|
426 outbuf[r->buf_len++] = 0; |
|
427 } |
|
428 |
|
429 outbuf[r->buf_len++] = 0x80; // this page |
|
430 outbuf[r->buf_len++] = 0x00; |
|
431 outbuf[r->buf_len++] = 0x01; // 1 byte data follow |
|
432 |
|
433 outbuf[r->buf_len++] = '0'; // 1 byte data follow |
|
434 } |
|
435 |
|
436 break; |
|
437 case 0x83: |
|
438 { |
|
439 /* Device identification page, mandatory */ |
|
440 int max_len = 255 - 8; |
|
441 int id_len = strlen(bdrv_get_device_name(s->bdrv)); |
|
442 if (id_len > max_len) |
|
443 id_len = max_len; |
|
444 |
|
445 DPRINTF("Inquiry EVPD[Device identification] " |
|
446 "buffer size %d\n", len); |
|
447 r->buf_len = 0; |
|
448 if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { |
|
449 outbuf[r->buf_len++] = 5; |
|
450 } else { |
|
451 outbuf[r->buf_len++] = 0; |
|
452 } |
|
453 |
|
454 outbuf[r->buf_len++] = 0x83; // this page |
|
455 outbuf[r->buf_len++] = 0x00; |
|
456 outbuf[r->buf_len++] = 3 + id_len; |
|
457 |
|
458 outbuf[r->buf_len++] = 0x2; // ASCII |
|
459 outbuf[r->buf_len++] = 0; // not officially assigned |
|
460 outbuf[r->buf_len++] = 0; // reserved |
|
461 outbuf[r->buf_len++] = id_len; // length of data following |
|
462 |
|
463 memcpy(&outbuf[r->buf_len], |
|
464 bdrv_get_device_name(s->bdrv), id_len); |
|
465 r->buf_len += id_len; |
|
466 } |
|
467 break; |
|
468 default: |
|
469 BADF("Error: unsupported Inquiry (EVPD[%02X]) " |
|
470 "buffer size %d\n", page_code, len); |
|
471 goto fail; |
|
472 } |
|
473 /* done with EVPD */ |
|
474 break; |
|
475 } |
|
476 else { |
|
477 /* Standard INQUIRY data */ |
|
478 if (buf[2] != 0) { |
|
479 BADF("Error: Inquiry (STANDARD) page or code " |
|
480 "is non-zero [%02X]\n", buf[2]); |
|
481 goto fail; |
|
482 } |
|
483 |
|
484 /* PAGE CODE == 0 */ |
|
485 if (len < 5) { |
|
486 BADF("Error: Inquiry (STANDARD) buffer size %d " |
|
487 "is less than 5\n", len); |
|
488 goto fail; |
|
489 } |
|
490 |
|
491 if (len < 36) { |
|
492 BADF("Error: Inquiry (STANDARD) buffer size %d " |
|
493 "is less than 36 (TODO: only 5 required)\n", len); |
|
494 } |
|
495 } |
|
496 |
|
497 if(len > SCSI_MAX_INQUIRY_LEN) |
|
498 len = SCSI_MAX_INQUIRY_LEN; |
|
499 |
|
500 memset(outbuf, 0, len); |
|
501 |
|
502 if (lun || buf[1] >> 5) { |
|
503 outbuf[0] = 0x7f; /* LUN not supported */ |
|
504 } else if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { |
|
505 outbuf[0] = 5; |
|
506 outbuf[1] = 0x80; |
|
507 memcpy(&outbuf[16], "QEMU CD-ROM ", 16); |
|
508 } else { |
|
509 outbuf[0] = 0; |
|
510 memcpy(&outbuf[16], "QEMU HARDDISK ", 16); |
|
511 } |
|
512 memcpy(&outbuf[8], "QEMU ", 8); |
|
513 memcpy(&outbuf[32], QEMU_VERSION, 4); |
|
514 /* Identify device as SCSI-3 rev 1. |
|
515 Some later commands are also implemented. */ |
|
516 outbuf[2] = 3; |
|
517 outbuf[3] = 2; /* Format 2 */ |
|
518 outbuf[4] = len - 5; /* Additional Length = (Len - 1) - 4 */ |
|
519 /* Sync data transfer and TCQ. */ |
|
520 outbuf[7] = 0x10 | (s->tcq ? 0x02 : 0); |
|
521 r->buf_len = len; |
|
522 break; |
|
523 case 0x16: |
|
524 DPRINTF("Reserve(6)\n"); |
|
525 if (buf[1] & 1) |
|
526 goto fail; |
|
527 break; |
|
528 case 0x17: |
|
529 DPRINTF("Release(6)\n"); |
|
530 if (buf[1] & 1) |
|
531 goto fail; |
|
532 break; |
|
533 case 0x1a: |
|
534 case 0x5a: |
|
535 { |
|
536 uint8_t *p; |
|
537 int page; |
|
538 |
|
539 page = buf[2] & 0x3f; |
|
540 DPRINTF("Mode Sense (page %d, len %d)\n", page, len); |
|
541 p = outbuf; |
|
542 memset(p, 0, 4); |
|
543 outbuf[1] = 0; /* Default media type. */ |
|
544 outbuf[3] = 0; /* Block descriptor length. */ |
|
545 if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { |
|
546 outbuf[2] = 0x80; /* Readonly. */ |
|
547 } |
|
548 p += 4; |
|
549 if (page == 4) { |
|
550 int cylinders, heads, secs; |
|
551 |
|
552 /* Rigid disk device geometry page. */ |
|
553 p[0] = 4; |
|
554 p[1] = 0x16; |
|
555 /* if a geometry hint is available, use it */ |
|
556 bdrv_get_geometry_hint(s->bdrv, &cylinders, &heads, &secs); |
|
557 p[2] = (cylinders >> 16) & 0xff; |
|
558 p[3] = (cylinders >> 8) & 0xff; |
|
559 p[4] = cylinders & 0xff; |
|
560 p[5] = heads & 0xff; |
|
561 /* Write precomp start cylinder, disabled */ |
|
562 p[6] = (cylinders >> 16) & 0xff; |
|
563 p[7] = (cylinders >> 8) & 0xff; |
|
564 p[8] = cylinders & 0xff; |
|
565 /* Reduced current start cylinder, disabled */ |
|
566 p[9] = (cylinders >> 16) & 0xff; |
|
567 p[10] = (cylinders >> 8) & 0xff; |
|
568 p[11] = cylinders & 0xff; |
|
569 /* Device step rate [ns], 200ns */ |
|
570 p[12] = 0; |
|
571 p[13] = 200; |
|
572 /* Landing zone cylinder */ |
|
573 p[14] = 0xff; |
|
574 p[15] = 0xff; |
|
575 p[16] = 0xff; |
|
576 /* Medium rotation rate [rpm], 5400 rpm */ |
|
577 p[20] = (5400 >> 8) & 0xff; |
|
578 p[21] = 5400 & 0xff; |
|
579 p += 0x16; |
|
580 } else if (page == 5) { |
|
581 int cylinders, heads, secs; |
|
582 |
|
583 /* Flexible disk device geometry page. */ |
|
584 p[0] = 5; |
|
585 p[1] = 0x1e; |
|
586 /* Transfer rate [kbit/s], 5Mbit/s */ |
|
587 p[2] = 5000 >> 8; |
|
588 p[3] = 5000 & 0xff; |
|
589 /* if a geometry hint is available, use it */ |
|
590 bdrv_get_geometry_hint(s->bdrv, &cylinders, &heads, &secs); |
|
591 p[4] = heads & 0xff; |
|
592 p[5] = secs & 0xff; |
|
593 p[6] = s->cluster_size * 2; |
|
594 p[8] = (cylinders >> 8) & 0xff; |
|
595 p[9] = cylinders & 0xff; |
|
596 /* Write precomp start cylinder, disabled */ |
|
597 p[10] = (cylinders >> 8) & 0xff; |
|
598 p[11] = cylinders & 0xff; |
|
599 /* Reduced current start cylinder, disabled */ |
|
600 p[12] = (cylinders >> 8) & 0xff; |
|
601 p[13] = cylinders & 0xff; |
|
602 /* Device step rate [100us], 100us */ |
|
603 p[14] = 0; |
|
604 p[15] = 1; |
|
605 /* Device step pulse width [us], 1us */ |
|
606 p[16] = 1; |
|
607 /* Device head settle delay [100us], 100us */ |
|
608 p[17] = 0; |
|
609 p[18] = 1; |
|
610 /* Motor on delay [0.1s], 0.1s */ |
|
611 p[19] = 1; |
|
612 /* Motor off delay [0.1s], 0.1s */ |
|
613 p[20] = 1; |
|
614 /* Medium rotation rate [rpm], 5400 rpm */ |
|
615 p[28] = (5400 >> 8) & 0xff; |
|
616 p[29] = 5400 & 0xff; |
|
617 p += 0x1e; |
|
618 } else if ((page == 8 || page == 0x3f)) { |
|
619 /* Caching page. */ |
|
620 memset(p,0,20); |
|
621 p[0] = 8; |
|
622 p[1] = 0x12; |
|
623 p[2] = 4; /* WCE */ |
|
624 p += 20; |
|
625 } |
|
626 if ((page == 0x3f || page == 0x2a) |
|
627 && (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM)) { |
|
628 /* CD Capabilities and Mechanical Status page. */ |
|
629 p[0] = 0x2a; |
|
630 p[1] = 0x14; |
|
631 p[2] = 3; // CD-R & CD-RW read |
|
632 p[3] = 0; // Writing not supported |
|
633 p[4] = 0x7f; /* Audio, composite, digital out, |
|
634 mode 2 form 1&2, multi session */ |
|
635 p[5] = 0xff; /* CD DA, DA accurate, RW supported, |
|
636 RW corrected, C2 errors, ISRC, |
|
637 UPC, Bar code */ |
|
638 p[6] = 0x2d | (bdrv_is_locked(s->bdrv)? 2 : 0); |
|
639 /* Locking supported, jumper present, eject, tray */ |
|
640 p[7] = 0; /* no volume & mute control, no |
|
641 changer */ |
|
642 p[8] = (50 * 176) >> 8; // 50x read speed |
|
643 p[9] = (50 * 176) & 0xff; |
|
644 p[10] = 0 >> 8; // No volume |
|
645 p[11] = 0 & 0xff; |
|
646 p[12] = 2048 >> 8; // 2M buffer |
|
647 p[13] = 2048 & 0xff; |
|
648 p[14] = (16 * 176) >> 8; // 16x read speed current |
|
649 p[15] = (16 * 176) & 0xff; |
|
650 p[18] = (16 * 176) >> 8; // 16x write speed |
|
651 p[19] = (16 * 176) & 0xff; |
|
652 p[20] = (16 * 176) >> 8; // 16x write speed current |
|
653 p[21] = (16 * 176) & 0xff; |
|
654 p += 22; |
|
655 } |
|
656 r->buf_len = p - outbuf; |
|
657 outbuf[0] = r->buf_len - 4; |
|
658 if (r->buf_len > len) |
|
659 r->buf_len = len; |
|
660 } |
|
661 break; |
|
662 case 0x1b: |
|
663 DPRINTF("Start Stop Unit\n"); |
|
664 break; |
|
665 case 0x1e: |
|
666 DPRINTF("Prevent Allow Medium Removal (prevent = %d)\n", buf[4] & 3); |
|
667 bdrv_set_locked(s->bdrv, buf[4] & 1); |
|
668 break; |
|
669 case 0x25: |
|
670 DPRINTF("Read Capacity\n"); |
|
671 /* The normal LEN field for this command is zero. */ |
|
672 memset(outbuf, 0, 8); |
|
673 bdrv_get_geometry(s->bdrv, &nb_sectors); |
|
674 /* Returned value is the address of the last sector. */ |
|
675 if (nb_sectors) { |
|
676 nb_sectors--; |
|
677 outbuf[0] = (nb_sectors >> 24) & 0xff; |
|
678 outbuf[1] = (nb_sectors >> 16) & 0xff; |
|
679 outbuf[2] = (nb_sectors >> 8) & 0xff; |
|
680 outbuf[3] = nb_sectors & 0xff; |
|
681 outbuf[4] = 0; |
|
682 outbuf[5] = 0; |
|
683 outbuf[6] = s->cluster_size * 2; |
|
684 outbuf[7] = 0; |
|
685 r->buf_len = 8; |
|
686 } else { |
|
687 scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_NOT_READY); |
|
688 return 0; |
|
689 } |
|
690 break; |
|
691 case 0x08: |
|
692 case 0x28: |
|
693 DPRINTF("Read (sector %d, count %d)\n", lba, len); |
|
694 r->sector = lba * s->cluster_size; |
|
695 r->sector_count = len * s->cluster_size; |
|
696 break; |
|
697 case 0x0a: |
|
698 case 0x2a: |
|
699 DPRINTF("Write (sector %d, count %d)\n", lba, len); |
|
700 r->sector = lba * s->cluster_size; |
|
701 r->sector_count = len * s->cluster_size; |
|
702 is_write = 1; |
|
703 break; |
|
704 case 0x35: |
|
705 DPRINTF("Synchronise cache (sector %d, count %d)\n", lba, len); |
|
706 bdrv_flush(s->bdrv); |
|
707 break; |
|
708 case 0x43: |
|
709 { |
|
710 int start_track, format, msf, toclen; |
|
711 |
|
712 msf = buf[1] & 2; |
|
713 format = buf[2] & 0xf; |
|
714 start_track = buf[6]; |
|
715 bdrv_get_geometry(s->bdrv, &nb_sectors); |
|
716 DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1); |
|
717 switch(format) { |
|
718 case 0: |
|
719 toclen = cdrom_read_toc(nb_sectors, outbuf, msf, start_track); |
|
720 break; |
|
721 case 1: |
|
722 /* multi session : only a single session defined */ |
|
723 toclen = 12; |
|
724 memset(outbuf, 0, 12); |
|
725 outbuf[1] = 0x0a; |
|
726 outbuf[2] = 0x01; |
|
727 outbuf[3] = 0x01; |
|
728 break; |
|
729 case 2: |
|
730 toclen = cdrom_read_toc_raw(nb_sectors, outbuf, msf, start_track); |
|
731 break; |
|
732 default: |
|
733 goto error_cmd; |
|
734 } |
|
735 if (toclen > 0) { |
|
736 if (len > toclen) |
|
737 len = toclen; |
|
738 r->buf_len = len; |
|
739 break; |
|
740 } |
|
741 error_cmd: |
|
742 DPRINTF("Read TOC error\n"); |
|
743 goto fail; |
|
744 } |
|
745 case 0x46: |
|
746 DPRINTF("Get Configuration (rt %d, maxlen %d)\n", buf[1] & 3, len); |
|
747 memset(outbuf, 0, 8); |
|
748 /* ??? This should probably return much more information. For now |
|
749 just return the basic header indicating the CD-ROM profile. */ |
|
750 outbuf[7] = 8; // CD-ROM |
|
751 r->buf_len = 8; |
|
752 break; |
|
753 case 0x56: |
|
754 DPRINTF("Reserve(10)\n"); |
|
755 if (buf[1] & 3) |
|
756 goto fail; |
|
757 break; |
|
758 case 0x57: |
|
759 DPRINTF("Release(10)\n"); |
|
760 if (buf[1] & 3) |
|
761 goto fail; |
|
762 break; |
|
763 case 0xa0: |
|
764 DPRINTF("Report LUNs (len %d)\n", len); |
|
765 if (len < 16) |
|
766 goto fail; |
|
767 memset(outbuf, 0, 16); |
|
768 outbuf[3] = 8; |
|
769 r->buf_len = 16; |
|
770 break; |
|
771 case 0x2f: |
|
772 DPRINTF("Verify (sector %d, count %d)\n", lba, len); |
|
773 break; |
|
774 default: |
|
775 DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]); |
|
776 fail: |
|
777 scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_ILLEGAL_REQUEST); |
|
778 return 0; |
|
779 } |
|
780 if (r->sector_count == 0 && r->buf_len == 0) { |
|
781 scsi_command_complete(r, STATUS_GOOD, SENSE_NO_SENSE); |
|
782 } |
|
783 len = r->sector_count * 512 + r->buf_len; |
|
784 if (is_write) { |
|
785 return -len; |
|
786 } else { |
|
787 if (!r->sector_count) |
|
788 r->sector_count = -1; |
|
789 return len; |
|
790 } |
|
791 } |
|
792 |
|
793 static void scsi_destroy(SCSIDevice *d) |
|
794 { |
|
795 qemu_free(d->state); |
|
796 qemu_free(d); |
|
797 } |
|
798 |
|
799 SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, int tcq, |
|
800 scsi_completionfn completion, void *opaque) |
|
801 { |
|
802 SCSIDevice *d; |
|
803 SCSIDeviceState *s; |
|
804 |
|
805 s = (SCSIDeviceState *)qemu_mallocz(sizeof(SCSIDeviceState)); |
|
806 s->bdrv = bdrv; |
|
807 s->tcq = tcq; |
|
808 s->completion = completion; |
|
809 s->opaque = opaque; |
|
810 if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { |
|
811 s->cluster_size = 4; |
|
812 } else { |
|
813 s->cluster_size = 1; |
|
814 } |
|
815 |
|
816 d = (SCSIDevice *)qemu_mallocz(sizeof(SCSIDevice)); |
|
817 d->state = s; |
|
818 d->destroy = scsi_destroy; |
|
819 d->send_command = scsi_send_command; |
|
820 d->read_data = scsi_read_data; |
|
821 d->write_data = scsi_write_data; |
|
822 d->cancel_io = scsi_cancel_io; |
|
823 d->get_buf = scsi_get_buf; |
|
824 |
|
825 return d; |
|
826 } |