scsi-disk.c revision 8b23a6c7e1aee255004dd19098d4c2462b61b849
18b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* 28b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * SCSI Device emulation 38b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * 48b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Copyright (c) 2006 CodeSourcery. 58b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Based on code by Fabrice Bellard 68b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * 78b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Written by Paul Brook 88b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * 98b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * This code is licenced under the LGPL. 108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * 118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Note that this file only handles the SCSI architecture model and device 128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * commands. Emulation of interface/link layer protocols is handled by 138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * the host adapter emulator. 148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */ 158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project//#define DEBUG_SCSI 178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef DEBUG_SCSI 198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define DPRINTF(fmt, args...) \ 208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectdo { printf("scsi-disk: " fmt , ##args); } while (0) 218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#else 228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define DPRINTF(fmt, args...) do {} while(0) 238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif 248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define BADF(fmt, args...) \ 268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectdo { fprintf(stderr, "scsi-disk: " fmt , ##args); } while (0) 278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "qemu-common.h" 298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "block.h" 308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "scsi-disk.h" 318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define SENSE_NO_SENSE 0 338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define SENSE_NOT_READY 2 348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define SENSE_HARDWARE_ERROR 4 358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define SENSE_ILLEGAL_REQUEST 5 368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define SCSI_DMA_BUF_SIZE 65536 388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef struct SCSIRequest { 408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIDeviceState *dev; 418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t tag; 428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* ??? We should probably keep track of whether the data trasfer is 438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project a read or a write. Currently we rely on the host getting it right. */ 448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Both sector and sector_count are in terms of qemu 512 byte blocks. */ 458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int sector; 468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int sector_count; 478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* The amounnt of data in the buffer. */ 488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int buf_len; 498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint8_t *dma_buf; 508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project BlockDriverAIOCB *aiocb; 518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project struct SCSIRequest *next; 528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} SCSIRequest; 538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstruct SCSIDeviceState 558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project BlockDriverState *bdrv; 578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIRequest *requests; 588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* The qemu block layer uses a fixed 512 byte sector size. 598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project This is the number of 512 byte blocks in a single scsi sector. */ 608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int cluster_size; 618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int sense; 628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int tcq; 638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Completion functions may be called from either scsi_{read,write}_data 648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project or from the AIO completion routines. */ 658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project scsi_completionfn completion; 668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project void *opaque; 678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}; 688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Global pool of SCSIRequest structures. */ 708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic SCSIRequest *free_requests = NULL; 718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic SCSIRequest *scsi_new_request(SCSIDeviceState *s, uint32_t tag) 738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIRequest *r; 758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (free_requests) { 778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r = free_requests; 788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project free_requests = r->next; 798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r = qemu_malloc(sizeof(SCSIRequest)); 818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->dma_buf = qemu_memalign(512, SCSI_DMA_BUF_SIZE); 828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->dev = s; 848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->tag = tag; 858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->sector_count = 0; 868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->buf_len = 0; 878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->aiocb = NULL; 888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->next = s->requests; 908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->requests = r; 918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return r; 928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void scsi_remove_request(SCSIRequest *r) 958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIRequest *last; 978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIDeviceState *s = r->dev; 988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (s->requests == r) { 1008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->requests = r->next; 1018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 1028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project last = s->requests; 1038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project while (last && last->next != r) 1048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project last = last->next; 1058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (last) { 1068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project last->next = r->next; 1078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 1088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project BADF("Orphaned request\n"); 1098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->next = free_requests; 1128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project free_requests = r; 1138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 1148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic SCSIRequest *scsi_find_request(SCSIDeviceState *s, uint32_t tag) 1168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 1178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIRequest *r; 1188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r = s->requests; 1208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project while (r && r->tag != tag) 1218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r = r->next; 1228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return r; 1248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 1258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Helper function for command completion. */ 1278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void scsi_command_complete(SCSIRequest *r, int sense) 1288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 1298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIDeviceState *s = r->dev; 1308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t tag; 1318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Command complete tag=0x%x sense=%d\n", r->tag, sense); 1328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->sense = sense; 1338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project tag = r->tag; 1348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project scsi_remove_request(r); 1358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->completion(s->opaque, SCSI_REASON_DONE, tag, sense); 1368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 1378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Cancel a pending data transfer. */ 1398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void scsi_cancel_io(SCSIDevice *d, uint32_t tag) 1408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 1418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIDeviceState *s = d->state; 1428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIRequest *r; 1438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Cancel tag=0x%x\n", tag); 1448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r = scsi_find_request(s, tag); 1458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (r) { 1468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (r->aiocb) 1478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bdrv_aio_cancel(r->aiocb); 1488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->aiocb = NULL; 1498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project scsi_remove_request(r); 1508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 1528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void scsi_read_complete(void * opaque, int ret) 1548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 1558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIRequest *r = (SCSIRequest *)opaque; 1568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIDeviceState *s = r->dev; 1578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (ret) { 1598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("IO error\n"); 1608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project scsi_command_complete(r, SENSE_HARDWARE_ERROR); 1618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return; 1628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Data ready tag=0x%x len=%d\n", r->tag, r->buf_len); 1648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->completion(s->opaque, SCSI_REASON_DATA, r->tag, r->buf_len); 1668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 1678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Read more data from scsi device into buffer. */ 1698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void scsi_read_data(SCSIDevice *d, uint32_t tag) 1708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 1718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIDeviceState *s = d->state; 1728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIRequest *r; 1738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t n; 1748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r = scsi_find_request(s, tag); 1768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (!r) { 1778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project BADF("Bad read tag 0x%x\n", tag); 1788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* ??? This is the wrong error. */ 1798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project scsi_command_complete(r, SENSE_HARDWARE_ERROR); 1808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return; 1818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (r->sector_count == (uint32_t)-1) { 1838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Read buf_len=%d\n", r->buf_len); 1848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->sector_count = 0; 1858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->completion(s->opaque, SCSI_REASON_DATA, r->tag, r->buf_len); 1868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return; 1878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Read sector_count=%d\n", r->sector_count); 1898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (r->sector_count == 0) { 1908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project scsi_command_complete(r, SENSE_NO_SENSE); 1918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return; 1928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project n = r->sector_count; 1958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (n > SCSI_DMA_BUF_SIZE / 512) 1968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project n = SCSI_DMA_BUF_SIZE / 512; 1978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->buf_len = n * 512; 1998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->aiocb = bdrv_aio_read(s->bdrv, r->sector, r->dma_buf, n, 2008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project scsi_read_complete, r); 2018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (r->aiocb == NULL) 2028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project scsi_command_complete(r, SENSE_HARDWARE_ERROR); 2038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->sector += n; 2048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->sector_count -= n; 2058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 2068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void scsi_write_complete(void * opaque, int ret) 2088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 2098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIRequest *r = (SCSIRequest *)opaque; 2108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIDeviceState *s = r->dev; 2118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t len; 2128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (ret) { 2148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project fprintf(stderr, "scsi-disc: IO write error\n"); 2158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project exit(1); 2168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 2178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->aiocb = NULL; 2198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (r->sector_count == 0) { 2208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project scsi_command_complete(r, SENSE_NO_SENSE); 2218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 2228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project len = r->sector_count * 512; 2238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (len > SCSI_DMA_BUF_SIZE) { 2248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project len = SCSI_DMA_BUF_SIZE; 2258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 2268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->buf_len = len; 2278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Write complete tag=0x%x more=%d\n", r->tag, len); 2288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->completion(s->opaque, SCSI_REASON_DATA, r->tag, len); 2298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 2308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 2318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Write data to a scsi device. Returns nonzero on failure. 2338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project The transfer may complete asynchronously. */ 2348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int scsi_write_data(SCSIDevice *d, uint32_t tag) 2358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 2368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIDeviceState *s = d->state; 2378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIRequest *r; 2388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t n; 2398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Write data tag=0x%x\n", tag); 2418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r = scsi_find_request(s, tag); 2428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (!r) { 2438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project BADF("Bad write tag 0x%x\n", tag); 2448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project scsi_command_complete(r, SENSE_HARDWARE_ERROR); 2458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return 1; 2468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 2478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (r->aiocb) 2488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project BADF("Data transfer already in progress\n"); 2498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project n = r->buf_len / 512; 2508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (n) { 2518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->aiocb = bdrv_aio_write(s->bdrv, r->sector, r->dma_buf, n, 2528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project scsi_write_complete, r); 2538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (r->aiocb == NULL) 2548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project scsi_command_complete(r, SENSE_HARDWARE_ERROR); 2558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->sector += n; 2568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->sector_count -= n; 2578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 2588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Invoke completion routine to fetch data from host. */ 2598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project scsi_write_complete(r, 0); 2608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 2618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return 0; 2638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 2648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Return a pointer to the data buffer. */ 2668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag) 2678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 2688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIDeviceState *s = d->state; 2698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIRequest *r; 2708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r = scsi_find_request(s, tag); 2728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (!r) { 2738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project BADF("Bad buffer tag 0x%x\n", tag); 2748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return NULL; 2758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 2768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return r->dma_buf; 2778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 2788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Execute a scsi command. Returns the length of the data expected by the 2808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project command. This will be Positive for data transfers from the device 2818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project (eg. disk reads), negative for transfers to the device (eg. disk writes), 2828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project and zero if the command does not transfer any data. */ 2838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, 2858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint8_t *buf, int lun) 2868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 2878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIDeviceState *s = d->state; 2888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint64_t nb_sectors; 2898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t lba; 2908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t len; 2918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int cmdlen; 2928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int is_write; 2938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint8_t command; 2948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint8_t *outbuf; 2958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIRequest *r; 2968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project command = buf[0]; 2988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r = scsi_find_request(s, tag); 2998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (r) { 3008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project BADF("Tag 0x%x already in use\n", tag); 3018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project scsi_cancel_io(d, tag); 3028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 3038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* ??? Tags are not unique for different luns. We only implement a 3048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project single lun, so this should not matter. */ 3058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r = scsi_new_request(s, tag); 3068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf = r->dma_buf; 3078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project is_write = 0; 3088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]); 3098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project switch (command >> 5) { 3108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0: 3118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project lba = buf[3] | (buf[2] << 8) | ((buf[1] & 0x1f) << 16); 3128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project len = buf[4]; 3138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project cmdlen = 6; 3148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 3158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 1: 3168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 2: 3178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24); 3188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project len = buf[8] | (buf[7] << 8); 3198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project cmdlen = 10; 3208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 3218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 4: 3228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24); 3238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project len = buf[13] | (buf[12] << 8) | (buf[11] << 16) | (buf[10] << 24); 3248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project cmdlen = 16; 3258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 3268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 5: 3278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24); 3288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project len = buf[9] | (buf[8] << 8) | (buf[7] << 16) | (buf[6] << 24); 3298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project cmdlen = 12; 3308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 3318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project default: 3328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project BADF("Unsupported command length, command %x\n", command); 3338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto fail; 3348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 3358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef DEBUG_SCSI 3368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 3378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int i; 3388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for (i = 1; i < cmdlen; i++) { 3398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project printf(" 0x%02x", buf[i]); 3408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 3418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project printf("\n"); 3428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 3438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif 3448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (lun || buf[1] >> 5) { 3458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Only LUN 0 supported. */ 3468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Unimplemented LUN %d\n", lun ? lun : buf[1] >> 5); 3478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto fail; 3488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 3498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project switch (command) { 3508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x0: 3518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Test Unit Ready\n"); 3528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 3538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x03: 3548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Request Sense (len %d)\n", len); 3558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (len < 4) 3568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto fail; 3578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memset(outbuf, 0, 4); 3588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[0] = 0xf0; 3598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[1] = 0; 3608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[2] = s->sense; 3618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->buf_len = 4; 3628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 3638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x12: 3648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Inquiry (len %d)\n", len); 3658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (buf[1] & 0x2) { 3668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Command support data - optional, not implemented */ 3678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project BADF("optional INQUIRY command support request not implemented\n"); 3688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto fail; 3698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 3708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project else if (buf[1] & 0x1) { 3718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Vital product data */ 3728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint8_t page_code = buf[2]; 3738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (len < 4) { 3748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project BADF("Error: Inquiry (EVPD[%02X]) buffer size %d is " 3758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project "less than 4\n", page_code, len); 3768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto fail; 3778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 3788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project switch (page_code) { 3808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x00: 3818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 3828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Supported page codes, mandatory */ 3838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Inquiry EVPD[Supported pages] " 3848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project "buffer size %d\n", len); 3858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->buf_len = 0; 3878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { 3898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[r->buf_len++] = 5; 3908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 3918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[r->buf_len++] = 0; 3928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 3938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[r->buf_len++] = 0x00; // this page 3958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[r->buf_len++] = 0x00; 3968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[r->buf_len++] = 3; // number of pages 3978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[r->buf_len++] = 0x00; // list of supported pages (this page) 3988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[r->buf_len++] = 0x80; // unit serial number 3998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[r->buf_len++] = 0x83; // device identification 4008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 4028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x80: 4038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 4048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Device serial number, optional */ 4058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (len < 4) { 4068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project BADF("Error: EVPD[Serial number] Inquiry buffer " 4078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project "size %d too small, %d needed\n", len, 4); 4088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto fail; 4098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 4118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Inquiry EVPD[Serial number] buffer size %d\n", len); 4128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 4138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->buf_len = 0; 4148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 4158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Supported page codes */ 4168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { 4178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[r->buf_len++] = 5; 4188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 4198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[r->buf_len++] = 0; 4208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 4228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[r->buf_len++] = 0x80; // this page 4238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[r->buf_len++] = 0x00; 4248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[r->buf_len++] = 0x01; // 1 byte data follow 4258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 4268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[r->buf_len++] = '0'; // 1 byte data follow 4278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 4298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 4308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x83: 4318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 4328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Device identification page, mandatory */ 4338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int max_len = 255 - 8; 4348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int id_len = strlen(bdrv_get_device_name(s->bdrv)); 4358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (id_len > max_len) 4368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project id_len = max_len; 4378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 4388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Inquiry EVPD[Device identification] " 4398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project "buffer size %d\n", len); 4408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->buf_len = 0; 4418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { 4428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[r->buf_len++] = 5; 4438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 4448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[r->buf_len++] = 0; 4458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 4478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[r->buf_len++] = 0x83; // this page 4488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[r->buf_len++] = 0x00; 4498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[r->buf_len++] = 3 + id_len; 4508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 4518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[r->buf_len++] = 0x2; // ASCII 4528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[r->buf_len++] = 0; // not officially assigned 4538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[r->buf_len++] = 0; // reserved 4548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[r->buf_len++] = id_len; // length of data following 4558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 4568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memcpy(&outbuf[r->buf_len], 4578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bdrv_get_device_name(s->bdrv), id_len); 4588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->buf_len += id_len; 4598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 4618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project default: 4628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project BADF("Error: unsupported Inquiry (EVPD[%02X]) " 4638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project "buffer size %d\n", page_code, len); 4648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto fail; 4658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* done with EVPD */ 4678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 4688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project else { 4708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Standard INQUIRY data */ 4718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (buf[2] != 0) { 4728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project BADF("Error: Inquiry (STANDARD) page or code " 4738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project "is non-zero [%02X]\n", buf[2]); 4748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto fail; 4758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 4778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* PAGE CODE == 0 */ 4788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (len < 5) { 4798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project BADF("Error: Inquiry (STANDARD) buffer size %d " 4808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project "is less than 5\n", len); 4818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto fail; 4828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 4848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (len < 36) { 4858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project BADF("Error: Inquiry (STANDARD) buffer size %d " 4868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project "is less than 36 (TODO: only 5 required)\n", len); 4878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memset(outbuf, 0, 36); 4908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { 4918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[0] = 5; 4928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[1] = 0x80; 4938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memcpy(&outbuf[16], "QEMU CD-ROM ", 16); 4948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 4958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[0] = 0; 4968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memcpy(&outbuf[16], "QEMU HARDDISK ", 16); 4978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memcpy(&outbuf[8], "QEMU ", 8); 4998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memcpy(&outbuf[32], QEMU_VERSION, 4); 5008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Identify device as SCSI-3 rev 1. 5018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project Some later commands are also implemented. */ 5028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[2] = 3; 5038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[3] = 2; /* Format 2 */ 5048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[4] = 31; 5058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Sync data transfer and TCQ. */ 5068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[7] = 0x10 | (s->tcq ? 0x02 : 0); 5078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->buf_len = 36; 5088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 5098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x16: 5108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Reserve(6)\n"); 5118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (buf[1] & 1) 5128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto fail; 5138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 5148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x17: 5158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Release(6)\n"); 5168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (buf[1] & 1) 5178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto fail; 5188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 5198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x1a: 5208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x5a: 5218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 5228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint8_t *p; 5238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int page; 5248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 5258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project page = buf[2] & 0x3f; 5268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Mode Sense (page %d, len %d)\n", page, len); 5278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p = outbuf; 5288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memset(p, 0, 4); 5298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[1] = 0; /* Default media type. */ 5308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[3] = 0; /* Block descriptor length. */ 5318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { 5328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[2] = 0x80; /* Readonly. */ 5338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 5348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p += 4; 5358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (page == 4) { 5368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int cylinders, heads, secs; 5378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 5388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Rigid disk device geometry page. */ 5398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[0] = 4; 5408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[1] = 0x16; 5418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* if a geometry hint is available, use it */ 5428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bdrv_get_geometry_hint(s->bdrv, &cylinders, &heads, &secs); 5438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[2] = (cylinders >> 16) & 0xff; 5448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[3] = (cylinders >> 8) & 0xff; 5458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[4] = cylinders & 0xff; 5468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[5] = heads & 0xff; 5478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Write precomp start cylinder, disabled */ 5488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[6] = (cylinders >> 16) & 0xff; 5498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[7] = (cylinders >> 8) & 0xff; 5508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[8] = cylinders & 0xff; 5518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Reduced current start cylinder, disabled */ 5528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[9] = (cylinders >> 16) & 0xff; 5538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[10] = (cylinders >> 8) & 0xff; 5548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[11] = cylinders & 0xff; 5558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Device step rate [ns], 200ns */ 5568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[12] = 0; 5578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[13] = 200; 5588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Landing zone cylinder */ 5598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[14] = 0xff; 5608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[15] = 0xff; 5618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[16] = 0xff; 5628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Medium rotation rate [rpm], 5400 rpm */ 5638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[20] = (5400 >> 8) & 0xff; 5648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[21] = 5400 & 0xff; 5658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p += 0x16; 5668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else if (page == 5) { 5678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int cylinders, heads, secs; 5688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 5698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Flexible disk device geometry page. */ 5708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[0] = 5; 5718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[1] = 0x1e; 5728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Transfer rate [kbit/s], 5Mbit/s */ 5738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[2] = 5000 >> 8; 5748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[3] = 5000 & 0xff; 5758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* if a geometry hint is available, use it */ 5768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bdrv_get_geometry_hint(s->bdrv, &cylinders, &heads, &secs); 5778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[4] = heads & 0xff; 5788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[5] = secs & 0xff; 5798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[6] = s->cluster_size * 2; 5808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[8] = (cylinders >> 8) & 0xff; 5818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[9] = cylinders & 0xff; 5828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Write precomp start cylinder, disabled */ 5838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[10] = (cylinders >> 8) & 0xff; 5848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[11] = cylinders & 0xff; 5858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Reduced current start cylinder, disabled */ 5868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[12] = (cylinders >> 8) & 0xff; 5878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[13] = cylinders & 0xff; 5888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Device step rate [100us], 100us */ 5898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[14] = 0; 5908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[15] = 1; 5918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Device step pulse width [us], 1us */ 5928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[16] = 1; 5938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Device head settle delay [100us], 100us */ 5948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[17] = 0; 5958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[18] = 1; 5968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Motor on delay [0.1s], 0.1s */ 5978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[19] = 1; 5988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Motor off delay [0.1s], 0.1s */ 5998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[20] = 1; 6008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Medium rotation rate [rpm], 5400 rpm */ 6018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[28] = (5400 >> 8) & 0xff; 6028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[29] = 5400 & 0xff; 6038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p += 0x1e; 6048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else if ((page == 8 || page == 0x3f)) { 6058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Caching page. */ 6068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memset(p,0,20); 6078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[0] = 8; 6088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[1] = 0x12; 6098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[2] = 4; /* WCE */ 6108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p += 20; 6118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 6128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if ((page == 0x3f || page == 0x2a) 6138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project && (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM)) { 6148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* CD Capabilities and Mechanical Status page. */ 6158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[0] = 0x2a; 6168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[1] = 0x14; 6178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[2] = 3; // CD-R & CD-RW read 6188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[3] = 0; // Writing not supported 6198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[4] = 0x7f; /* Audio, composite, digital out, 6208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project mode 2 form 1&2, multi session */ 6218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[5] = 0xff; /* CD DA, DA accurate, RW supported, 6228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project RW corrected, C2 errors, ISRC, 6238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project UPC, Bar code */ 6248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[6] = 0x2d | (bdrv_is_locked(s->bdrv)? 2 : 0); 6258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Locking supported, jumper present, eject, tray */ 6268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[7] = 0; /* no volume & mute control, no 6278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project changer */ 6288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[8] = (50 * 176) >> 8; // 50x read speed 6298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[9] = (50 * 176) & 0xff; 6308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[10] = 0 >> 8; // No volume 6318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[11] = 0 & 0xff; 6328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[12] = 2048 >> 8; // 2M buffer 6338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[13] = 2048 & 0xff; 6348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[14] = (16 * 176) >> 8; // 16x read speed current 6358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[15] = (16 * 176) & 0xff; 6368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[18] = (16 * 176) >> 8; // 16x write speed 6378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[19] = (16 * 176) & 0xff; 6388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[20] = (16 * 176) >> 8; // 16x write speed current 6398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[21] = (16 * 176) & 0xff; 6408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p += 22; 6418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 6428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->buf_len = p - outbuf; 6438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[0] = r->buf_len - 4; 6448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (r->buf_len > len) 6458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->buf_len = len; 6468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 6478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 6488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x1b: 6498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Start Stop Unit\n"); 6508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 6518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x1e: 6528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Prevent Allow Medium Removal (prevent = %d)\n", buf[4] & 3); 6538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bdrv_set_locked(s->bdrv, buf[4] & 1); 6548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 6558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x25: 6568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Read Capacity\n"); 6578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* The normal LEN field for this command is zero. */ 6588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memset(outbuf, 0, 8); 6598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bdrv_get_geometry(s->bdrv, &nb_sectors); 6608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Returned value is the address of the last sector. */ 6618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (nb_sectors) { 6628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project nb_sectors--; 6638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[0] = (nb_sectors >> 24) & 0xff; 6648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[1] = (nb_sectors >> 16) & 0xff; 6658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[2] = (nb_sectors >> 8) & 0xff; 6668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[3] = nb_sectors & 0xff; 6678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[4] = 0; 6688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[5] = 0; 6698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[6] = s->cluster_size * 2; 6708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[7] = 0; 6718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->buf_len = 8; 6728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 6738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project scsi_command_complete(r, SENSE_NOT_READY); 6748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return 0; 6758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 6768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 6778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x08: 6788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x28: 6798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Read (sector %d, count %d)\n", lba, len); 6808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->sector = lba * s->cluster_size; 6818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->sector_count = len * s->cluster_size; 6828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 6838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x0a: 6848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x2a: 6858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Write (sector %d, count %d)\n", lba, len); 6868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->sector = lba * s->cluster_size; 6878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->sector_count = len * s->cluster_size; 6888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project is_write = 1; 6898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 6908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x35: 6918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Synchronise cache (sector %d, count %d)\n", lba, len); 6928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bdrv_flush(s->bdrv); 6938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 6948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x43: 6958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 6968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int start_track, format, msf, toclen; 6978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 6988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project msf = buf[1] & 2; 6998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project format = buf[2] & 0xf; 7008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project start_track = buf[6]; 7018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bdrv_get_geometry(s->bdrv, &nb_sectors); 7028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1); 7038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project switch(format) { 7048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0: 7058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project toclen = cdrom_read_toc(nb_sectors, outbuf, msf, start_track); 7068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 7078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 1: 7088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* multi session : only a single session defined */ 7098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project toclen = 12; 7108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memset(outbuf, 0, 12); 7118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[1] = 0x0a; 7128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[2] = 0x01; 7138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[3] = 0x01; 7148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 7158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 2: 7168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project toclen = cdrom_read_toc_raw(nb_sectors, outbuf, msf, start_track); 7178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 7188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project default: 7198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto error_cmd; 7208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 7218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (toclen > 0) { 7228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (len > toclen) 7238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project len = toclen; 7248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->buf_len = len; 7258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 7268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 7278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project error_cmd: 7288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Read TOC error\n"); 7298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto fail; 7308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 7318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x46: 7328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Get Configuration (rt %d, maxlen %d)\n", buf[1] & 3, len); 7338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memset(outbuf, 0, 8); 7348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* ??? This should probably return much more information. For now 7358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project just return the basic header indicating the CD-ROM profile. */ 7368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[7] = 8; // CD-ROM 7378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->buf_len = 8; 7388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 7398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x56: 7408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Reserve(10)\n"); 7418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (buf[1] & 3) 7428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto fail; 7438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 7448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x57: 7458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Release(10)\n"); 7468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (buf[1] & 3) 7478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto fail; 7488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 7498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0xa0: 7508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Report LUNs (len %d)\n", len); 7518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (len < 16) 7528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto fail; 7538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memset(outbuf, 0, 16); 7548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[3] = 8; 7558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->buf_len = 16; 7568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 7578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project default: 7588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]); 7598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project fail: 7608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project scsi_command_complete(r, SENSE_ILLEGAL_REQUEST); 7618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return 0; 7628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 7638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (r->sector_count == 0 && r->buf_len == 0) { 7648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project scsi_command_complete(r, SENSE_NO_SENSE); 7658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 7668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project len = r->sector_count * 512 + r->buf_len; 7678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (is_write) { 7688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return -len; 7698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 7708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (!r->sector_count) 7718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->sector_count = -1; 7728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return len; 7738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 7748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 7758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 7768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void scsi_destroy(SCSIDevice *d) 7778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 7788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_free(d->state); 7798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_free(d); 7808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 7818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 7828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source ProjectSCSIDevice *scsi_disk_init(BlockDriverState *bdrv, int tcq, 7838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project scsi_completionfn completion, void *opaque) 7848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 7858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIDevice *d; 7868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIDeviceState *s; 7878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 7888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s = (SCSIDeviceState *)qemu_mallocz(sizeof(SCSIDeviceState)); 7898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->bdrv = bdrv; 7908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->tcq = tcq; 7918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->completion = completion; 7928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->opaque = opaque; 7938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { 7948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->cluster_size = 4; 7958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 7968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->cluster_size = 1; 7978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 7988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 7998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project d = (SCSIDevice *)qemu_mallocz(sizeof(SCSIDevice)); 8008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project d->state = s; 8018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project d->destroy = scsi_destroy; 8028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project d->send_command = scsi_send_command; 8038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project d->read_data = scsi_read_data; 8048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project d->write_data = scsi_write_data; 8058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project d->cancel_io = scsi_cancel_io; 8068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project d->get_buf = scsi_get_buf; 8078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 8088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return d; 8098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 810