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 165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <qemu-common.h> 175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sysemu.h> 18cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner#include "blockdev.h" 198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project//#define DEBUG_SCSI 208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef DEBUG_SCSI 225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define DPRINTF(fmt, ...) \ 235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerdo { printf("scsi-disk: " fmt , ## __VA_ARGS__); } while (0) 248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#else 255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define DPRINTF(fmt, ...) do {} while(0) 268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif 278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define BADF(fmt, ...) \ 295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerdo { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0) 308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "qemu-common.h" 328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "block.h" 338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "scsi-disk.h" 348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define SENSE_NO_SENSE 0 368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define SENSE_NOT_READY 2 378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define SENSE_HARDWARE_ERROR 4 388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define SENSE_ILLEGAL_REQUEST 5 398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define STATUS_GOOD 0 415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define STATUS_CHECK_CONDITION 2 425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define SCSI_DMA_BUF_SIZE 131072 445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define SCSI_MAX_INQUIRY_LEN 256 455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define SCSI_REQ_STATUS_RETRY 0x01 478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef struct SCSIRequest { 498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIDeviceState *dev; 508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t tag; 515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* ??? We should probably keep track of whether the data transfer is 528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project a read or a write. Currently we rely on the host getting it right. */ 538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Both sector and sector_count are in terms of qemu 512 byte blocks. */ 545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint64_t sector; 555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint32_t sector_count; 565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct iovec iov; 575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUIOVector qiov; 588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project BlockDriverAIOCB *aiocb; 598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project struct SCSIRequest *next; 605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint32_t status; 618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} SCSIRequest; 628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstruct SCSIDeviceState 648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project BlockDriverState *bdrv; 668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIRequest *requests; 678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* The qemu block layer uses a fixed 512 byte sector size. 688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project This is the number of 512 byte blocks in a single scsi sector. */ 698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int cluster_size; 705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint64_t max_lba; 718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int sense; 728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int tcq; 738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Completion functions may be called from either scsi_{read,write}_data 748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project or from the AIO completion routines. */ 758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project scsi_completionfn completion; 768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project void *opaque; 775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner char drive_serial_str[21]; 788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}; 798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Global pool of SCSIRequest structures. */ 818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic SCSIRequest *free_requests = NULL; 828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic SCSIRequest *scsi_new_request(SCSIDeviceState *s, uint32_t tag) 848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIRequest *r; 868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (free_requests) { 888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r = free_requests; 898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project free_requests = r->next; 908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r = qemu_malloc(sizeof(SCSIRequest)); 925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner r->iov.iov_base = qemu_memalign(512, SCSI_DMA_BUF_SIZE); 938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->dev = s; 958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->tag = tag; 968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->sector_count = 0; 975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner r->iov.iov_len = 0; 988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->aiocb = NULL; 995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner r->status = 0; 1008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->next = s->requests; 1028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->requests = r; 1038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return r; 1048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 1058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void scsi_remove_request(SCSIRequest *r) 1078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 1088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIRequest *last; 1098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIDeviceState *s = r->dev; 1108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (s->requests == r) { 1128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->requests = r->next; 1138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 1148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project last = s->requests; 1158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project while (last && last->next != r) 1168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project last = last->next; 1178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (last) { 1188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project last->next = r->next; 1198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 1208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project BADF("Orphaned request\n"); 1218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->next = free_requests; 1248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project free_requests = r; 1258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 1268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic SCSIRequest *scsi_find_request(SCSIDeviceState *s, uint32_t tag) 1288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 1298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIRequest *r; 1308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r = s->requests; 1328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project while (r && r->tag != tag) 1338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r = r->next; 1348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return r; 1368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 1378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Helper function for command completion. */ 1395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void scsi_command_complete(SCSIRequest *r, int status, int sense) 1408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 1418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIDeviceState *s = r->dev; 1428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t tag; 1435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner DPRINTF("Command complete tag=0x%x status=%d sense=%d\n", r->tag, status, sense); 1448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->sense = sense; 1458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project tag = r->tag; 1468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project scsi_remove_request(r); 1475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->completion(s->opaque, SCSI_REASON_DONE, tag, status); 1488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 1498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Cancel a pending data transfer. */ 1518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void scsi_cancel_io(SCSIDevice *d, uint32_t tag) 1528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 1538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIDeviceState *s = d->state; 1548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIRequest *r; 1558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Cancel tag=0x%x\n", tag); 1568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r = scsi_find_request(s, tag); 1578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (r) { 1588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (r->aiocb) 1598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bdrv_aio_cancel(r->aiocb); 1608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->aiocb = NULL; 1618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project scsi_remove_request(r); 1628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 1648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void scsi_read_complete(void * opaque, int ret) 1668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 1678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIRequest *r = (SCSIRequest *)opaque; 1688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIDeviceState *s = r->dev; 1698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (ret) { 1718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("IO error\n"); 1725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->completion(s->opaque, SCSI_REASON_DATA, r->tag, 0); 1735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_NO_SENSE); 1748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return; 1758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner DPRINTF("Data ready tag=0x%x len=%d\n", r->tag, r->iov.iov_len); 1778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->completion(s->opaque, SCSI_REASON_DATA, r->tag, r->iov.iov_len); 1798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 1808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Read more data from scsi device into buffer. */ 1828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void scsi_read_data(SCSIDevice *d, uint32_t tag) 1838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 1848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIDeviceState *s = d->state; 1858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIRequest *r; 1868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t n; 1878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r = scsi_find_request(s, tag); 1898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (!r) { 1908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project BADF("Bad read tag 0x%x\n", tag); 1918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* ??? This is the wrong error. */ 1925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR); 1938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return; 1948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (r->sector_count == (uint32_t)-1) { 1965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner DPRINTF("Read buf_len=%d\n", r->iov.iov_len); 1978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->sector_count = 0; 1985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->completion(s->opaque, SCSI_REASON_DATA, r->tag, r->iov.iov_len); 1998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return; 2008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 2018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Read sector_count=%d\n", r->sector_count); 2028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (r->sector_count == 0) { 2035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner scsi_command_complete(r, STATUS_GOOD, SENSE_NO_SENSE); 2048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return; 2058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 2068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project n = r->sector_count; 2088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (n > SCSI_DMA_BUF_SIZE / 512) 2098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project n = SCSI_DMA_BUF_SIZE / 512; 2108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner r->iov.iov_len = n * 512; 2125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_iovec_init_external(&r->qiov, &r->iov, 1); 2135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner r->aiocb = bdrv_aio_readv(s->bdrv, r->sector, &r->qiov, n, 2145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner scsi_read_complete, r); 2158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (r->aiocb == NULL) 2165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR); 2178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->sector += n; 2188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->sector_count -= n; 2198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 2208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int scsi_handle_write_error(SCSIRequest *r, int error) 2225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 223cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner BlockErrorAction action = bdrv_get_on_error(r->dev->bdrv, 0); 2245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (action == BLOCK_ERR_IGNORE) 2265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 2275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC) 2295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner || action == BLOCK_ERR_STOP_ANY) { 2305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner r->status |= SCSI_REQ_STATUS_RETRY; 2315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner vm_stop(0); 2325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else { 2335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner scsi_command_complete(r, STATUS_CHECK_CONDITION, 2345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SENSE_HARDWARE_ERROR); 2355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 2365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 1; 2385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 2395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void scsi_write_complete(void * opaque, int ret) 2418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 2428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIRequest *r = (SCSIRequest *)opaque; 2438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIDeviceState *s = r->dev; 2448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t len; 2455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint32_t n; 2465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner r->aiocb = NULL; 2488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (ret) { 2505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (scsi_handle_write_error(r, -ret)) 2515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 2528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 2538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner n = r->iov.iov_len / 512; 2555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner r->sector += n; 2565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner r->sector_count -= n; 2578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (r->sector_count == 0) { 2585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner scsi_command_complete(r, STATUS_GOOD, SENSE_NO_SENSE); 2598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 2608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project len = r->sector_count * 512; 2618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (len > SCSI_DMA_BUF_SIZE) { 2628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project len = SCSI_DMA_BUF_SIZE; 2638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 2645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner r->iov.iov_len = len; 2658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Write complete tag=0x%x more=%d\n", r->tag, len); 2668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->completion(s->opaque, SCSI_REASON_DATA, r->tag, len); 2678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 2688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 2698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void scsi_write_request(SCSIRequest *r) 2715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 2725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SCSIDeviceState *s = r->dev; 2735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint32_t n; 2745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner n = r->iov.iov_len / 512; 2765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (n) { 2775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_iovec_init_external(&r->qiov, &r->iov, 1); 2785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner r->aiocb = bdrv_aio_writev(s->bdrv, r->sector, &r->qiov, n, 2795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner scsi_write_complete, r); 2805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (r->aiocb == NULL) 2815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner scsi_command_complete(r, STATUS_CHECK_CONDITION, 2825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SENSE_HARDWARE_ERROR); 2835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else { 2845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Invoke completion routine to fetch data from host. */ 2855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner scsi_write_complete(r, 0); 2865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 2875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 2885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Write data to a scsi device. Returns nonzero on failure. 2908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project The transfer may complete asynchronously. */ 2918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int scsi_write_data(SCSIDevice *d, uint32_t tag) 2928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 2938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIDeviceState *s = d->state; 2948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIRequest *r; 2958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Write data tag=0x%x\n", tag); 2978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r = scsi_find_request(s, tag); 2988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (!r) { 2998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project BADF("Bad write tag 0x%x\n", tag); 3005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR); 3018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return 1; 3028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 3035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (r->aiocb) 3058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project BADF("Data transfer already in progress\n"); 3065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner scsi_write_request(r); 3088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return 0; 3108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 3118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void scsi_dma_restart_cb(void *opaque, int running, int reason) 3135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 3145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SCSIDeviceState *s = opaque; 3155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SCSIRequest *r = s->requests; 3165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!running) 3175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 3185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner while (r) { 3205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (r->status & SCSI_REQ_STATUS_RETRY) { 3215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner r->status &= ~SCSI_REQ_STATUS_RETRY; 322cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner scsi_write_request(r); 3235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 3245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner r = r->next; 3255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 3265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 3275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Return a pointer to the data buffer. */ 3298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag) 3308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 3318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIDeviceState *s = d->state; 3328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIRequest *r; 3338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r = scsi_find_request(s, tag); 3358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (!r) { 3368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project BADF("Bad buffer tag 0x%x\n", tag); 3378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return NULL; 3388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 3395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return (uint8_t *)r->iov.iov_base; 3408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 3418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Execute a scsi command. Returns the length of the data expected by the 3438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project command. This will be Positive for data transfers from the device 3448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project (eg. disk reads), negative for transfers to the device (eg. disk writes), 3458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project and zero if the command does not transfer any data. */ 3468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, 3488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint8_t *buf, int lun) 3498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 3508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIDeviceState *s = d->state; 3518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint64_t nb_sectors; 3525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint64_t lba; 3538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t len; 3548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int cmdlen; 3558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int is_write; 3568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint8_t command; 3578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint8_t *outbuf; 3588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIRequest *r; 3598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project command = buf[0]; 3618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r = scsi_find_request(s, tag); 3628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (r) { 3638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project BADF("Tag 0x%x already in use\n", tag); 3648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project scsi_cancel_io(d, tag); 3658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 3668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* ??? Tags are not unique for different luns. We only implement a 3678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project single lun, so this should not matter. */ 3688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r = scsi_new_request(s, tag); 3695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf = (uint8_t *)r->iov.iov_base; 3708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project is_write = 0; 3718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]); 3728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project switch (command >> 5) { 3738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0: 3745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner lba = (uint64_t) buf[3] | ((uint64_t) buf[2] << 8) | 3755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner (((uint64_t) buf[1] & 0x1f) << 16); 3768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project len = buf[4]; 3778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project cmdlen = 6; 3788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 3798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 1: 3808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 2: 3815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner lba = (uint64_t) buf[5] | ((uint64_t) buf[4] << 8) | 3825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ((uint64_t) buf[3] << 16) | ((uint64_t) buf[2] << 24); 3838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project len = buf[8] | (buf[7] << 8); 3848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project cmdlen = 10; 3858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 3868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 4: 3875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner lba = (uint64_t) buf[9] | ((uint64_t) buf[8] << 8) | 3885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ((uint64_t) buf[7] << 16) | ((uint64_t) buf[6] << 24) | 3895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ((uint64_t) buf[5] << 32) | ((uint64_t) buf[4] << 40) | 3905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ((uint64_t) buf[3] << 48) | ((uint64_t) buf[2] << 56); 3918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project len = buf[13] | (buf[12] << 8) | (buf[11] << 16) | (buf[10] << 24); 3928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project cmdlen = 16; 3938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 3948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 5: 3955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner lba = (uint64_t) buf[5] | ((uint64_t) buf[4] << 8) | 3965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ((uint64_t) buf[3] << 16) | ((uint64_t) buf[2] << 24); 3978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project len = buf[9] | (buf[8] << 8) | (buf[7] << 16) | (buf[6] << 24); 3988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project cmdlen = 12; 3998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 4008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project default: 4018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project BADF("Unsupported command length, command %x\n", command); 4028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto fail; 4038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef DEBUG_SCSI 4058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 4068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int i; 4078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for (i = 1; i < cmdlen; i++) { 4088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project printf(" 0x%02x", buf[i]); 4098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project printf("\n"); 4118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif 4138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (lun || buf[1] >> 5) { 4148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Only LUN 0 supported. */ 4158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Unimplemented LUN %d\n", lun ? lun : buf[1] >> 5); 4165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (command != 0x03 && command != 0x12) /* REQUEST SENSE and INQUIRY */ 4175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto fail; 4188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project switch (command) { 4208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x0: 4218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Test Unit Ready\n"); 4225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!bdrv_is_inserted(s->bdrv)) 4235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto notready; 4248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 4258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x03: 4268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Request Sense (len %d)\n", len); 4278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (len < 4) 4288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto fail; 4298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memset(outbuf, 0, 4); 4305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner r->iov.iov_len = 4; 4315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (s->sense == SENSE_NOT_READY && len >= 18) { 4325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner memset(outbuf, 0, 18); 4335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner r->iov.iov_len = 18; 4345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[7] = 10; 4355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* asc 0x3a, ascq 0: Medium not present */ 4365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[12] = 0x3a; 4375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[13] = 0; 4385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 4398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[0] = 0xf0; 4408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[1] = 0; 4418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[2] = s->sense; 4428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 4438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x12: 4448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Inquiry (len %d)\n", len); 4458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (buf[1] & 0x2) { 4468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Command support data - optional, not implemented */ 4478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project BADF("optional INQUIRY command support request not implemented\n"); 4488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto fail; 4498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project else if (buf[1] & 0x1) { 4518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Vital product data */ 4528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint8_t page_code = buf[2]; 4538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (len < 4) { 4548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project BADF("Error: Inquiry (EVPD[%02X]) buffer size %d is " 4558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project "less than 4\n", page_code, len); 4568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto fail; 4578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 4598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project switch (page_code) { 4608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x00: 4618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 4628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Supported page codes, mandatory */ 4638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Inquiry EVPD[Supported pages] " 4648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project "buffer size %d\n", len); 4658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 4665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner r->iov.iov_len = 0; 4678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 4688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { 4695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[r->iov.iov_len++] = 5; 4708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 4715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[r->iov.iov_len++] = 0; 4728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 4745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[r->iov.iov_len++] = 0x00; // this page 4755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[r->iov.iov_len++] = 0x00; 4765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[r->iov.iov_len++] = 3; // number of pages 4775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[r->iov.iov_len++] = 0x00; // list of supported pages (this page) 4785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[r->iov.iov_len++] = 0x80; // unit serial number 4795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[r->iov.iov_len++] = 0x83; // device identification 4808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 4828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x80: 4838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 4845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int l; 4855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Device serial number, optional */ 4878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (len < 4) { 4888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project BADF("Error: EVPD[Serial number] Inquiry buffer " 4898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project "size %d too small, %d needed\n", len, 4); 4908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto fail; 4918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 4938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Inquiry EVPD[Serial number] buffer size %d\n", len); 4945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner l = MIN(len, strlen(s->drive_serial_str)); 4958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 4965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner r->iov.iov_len = 0; 4978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 4988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Supported page codes */ 4998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { 5005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[r->iov.iov_len++] = 5; 5018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 5025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[r->iov.iov_len++] = 0; 5038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 5048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 5055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[r->iov.iov_len++] = 0x80; // this page 5065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[r->iov.iov_len++] = 0x00; 5075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[r->iov.iov_len++] = l; 5085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner memcpy(&outbuf[r->iov.iov_len], s->drive_serial_str, l); 5095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner r->iov.iov_len += l; 5108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 5118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 5128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 5138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x83: 5148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 5158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Device identification page, mandatory */ 5168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int max_len = 255 - 8; 5178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int id_len = strlen(bdrv_get_device_name(s->bdrv)); 5188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (id_len > max_len) 5198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project id_len = max_len; 5208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 5218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Inquiry EVPD[Device identification] " 5228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project "buffer size %d\n", len); 5235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner r->iov.iov_len = 0; 5248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { 5255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[r->iov.iov_len++] = 5; 5268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 5275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[r->iov.iov_len++] = 0; 5288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 5298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 5305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[r->iov.iov_len++] = 0x83; // this page 5315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[r->iov.iov_len++] = 0x00; 5325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[r->iov.iov_len++] = 3 + id_len; 5338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 5345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[r->iov.iov_len++] = 0x2; // ASCII 5355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[r->iov.iov_len++] = 0; // not officially assigned 5365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[r->iov.iov_len++] = 0; // reserved 5375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[r->iov.iov_len++] = id_len; // length of data following 5388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 5395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner memcpy(&outbuf[r->iov.iov_len], 5408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bdrv_get_device_name(s->bdrv), id_len); 5415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner r->iov.iov_len += id_len; 5428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 5438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 5448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project default: 5458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project BADF("Error: unsupported Inquiry (EVPD[%02X]) " 5468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project "buffer size %d\n", page_code, len); 5478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto fail; 5488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 5498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* done with EVPD */ 5508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 5518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 5528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project else { 5538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Standard INQUIRY data */ 5548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (buf[2] != 0) { 5558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project BADF("Error: Inquiry (STANDARD) page or code " 5568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project "is non-zero [%02X]\n", buf[2]); 5578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto fail; 5588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 5598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 5608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* PAGE CODE == 0 */ 5618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (len < 5) { 5628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project BADF("Error: Inquiry (STANDARD) buffer size %d " 5638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project "is less than 5\n", len); 5648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto fail; 5658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 5668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 5678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (len < 36) { 5688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project BADF("Error: Inquiry (STANDARD) buffer size %d " 5698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project "is less than 36 (TODO: only 5 required)\n", len); 5708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 5718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 5725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if(len > SCSI_MAX_INQUIRY_LEN) 5745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner len = SCSI_MAX_INQUIRY_LEN; 5755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner memset(outbuf, 0, len); 5775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (lun || buf[1] >> 5) { 5795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[0] = 0x7f; /* LUN not supported */ 5805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { 5818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[0] = 5; 5828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[1] = 0x80; 5838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memcpy(&outbuf[16], "QEMU CD-ROM ", 16); 5848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 5858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[0] = 0; 5868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memcpy(&outbuf[16], "QEMU HARDDISK ", 16); 5878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 5888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memcpy(&outbuf[8], "QEMU ", 8); 5898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memcpy(&outbuf[32], QEMU_VERSION, 4); 5908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Identify device as SCSI-3 rev 1. 5918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project Some later commands are also implemented. */ 5928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[2] = 3; 5938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[3] = 2; /* Format 2 */ 5945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[4] = len - 5; /* Additional Length = (Len - 1) - 4 */ 5958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Sync data transfer and TCQ. */ 5968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[7] = 0x10 | (s->tcq ? 0x02 : 0); 5975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner r->iov.iov_len = len; 5988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 5998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x16: 6008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Reserve(6)\n"); 6018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (buf[1] & 1) 6028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto fail; 6038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 6048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x17: 6058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Release(6)\n"); 6068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (buf[1] & 1) 6078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto fail; 6088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 6098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x1a: 6108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x5a: 6118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 6128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint8_t *p; 6138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int page; 6148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 6158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project page = buf[2] & 0x3f; 6168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Mode Sense (page %d, len %d)\n", page, len); 6178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p = outbuf; 6188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memset(p, 0, 4); 6198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[1] = 0; /* Default media type. */ 6208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[3] = 0; /* Block descriptor length. */ 6218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { 6228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[2] = 0x80; /* Readonly. */ 6238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 6248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p += 4; 6258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (page == 4) { 6268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int cylinders, heads, secs; 6278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 6288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Rigid disk device geometry page. */ 6298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[0] = 4; 6308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[1] = 0x16; 6318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* if a geometry hint is available, use it */ 6328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bdrv_get_geometry_hint(s->bdrv, &cylinders, &heads, &secs); 6338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[2] = (cylinders >> 16) & 0xff; 6348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[3] = (cylinders >> 8) & 0xff; 6358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[4] = cylinders & 0xff; 6368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[5] = heads & 0xff; 6378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Write precomp start cylinder, disabled */ 6388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[6] = (cylinders >> 16) & 0xff; 6398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[7] = (cylinders >> 8) & 0xff; 6408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[8] = cylinders & 0xff; 6418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Reduced current start cylinder, disabled */ 6428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[9] = (cylinders >> 16) & 0xff; 6438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[10] = (cylinders >> 8) & 0xff; 6448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[11] = cylinders & 0xff; 6458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Device step rate [ns], 200ns */ 6468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[12] = 0; 6478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[13] = 200; 6488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Landing zone cylinder */ 6498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[14] = 0xff; 6508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[15] = 0xff; 6518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[16] = 0xff; 6528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Medium rotation rate [rpm], 5400 rpm */ 6538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[20] = (5400 >> 8) & 0xff; 6548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[21] = 5400 & 0xff; 6558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p += 0x16; 6568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else if (page == 5) { 6578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int cylinders, heads, secs; 6588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 6598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Flexible disk device geometry page. */ 6608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[0] = 5; 6618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[1] = 0x1e; 6628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Transfer rate [kbit/s], 5Mbit/s */ 6638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[2] = 5000 >> 8; 6648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[3] = 5000 & 0xff; 6658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* if a geometry hint is available, use it */ 6668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bdrv_get_geometry_hint(s->bdrv, &cylinders, &heads, &secs); 6678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[4] = heads & 0xff; 6688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[5] = secs & 0xff; 6698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[6] = s->cluster_size * 2; 6708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[8] = (cylinders >> 8) & 0xff; 6718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[9] = cylinders & 0xff; 6728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Write precomp start cylinder, disabled */ 6738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[10] = (cylinders >> 8) & 0xff; 6748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[11] = cylinders & 0xff; 6758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Reduced current start cylinder, disabled */ 6768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[12] = (cylinders >> 8) & 0xff; 6778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[13] = cylinders & 0xff; 6788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Device step rate [100us], 100us */ 6798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[14] = 0; 6808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[15] = 1; 6818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Device step pulse width [us], 1us */ 6828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[16] = 1; 6838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Device head settle delay [100us], 100us */ 6848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[17] = 0; 6858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[18] = 1; 6868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Motor on delay [0.1s], 0.1s */ 6878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[19] = 1; 6888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Motor off delay [0.1s], 0.1s */ 6898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[20] = 1; 6908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Medium rotation rate [rpm], 5400 rpm */ 6918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[28] = (5400 >> 8) & 0xff; 6928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[29] = 5400 & 0xff; 6938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p += 0x1e; 6948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else if ((page == 8 || page == 0x3f)) { 6958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Caching page. */ 6968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memset(p,0,20); 6978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[0] = 8; 6988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[1] = 0x12; 6998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[2] = 4; /* WCE */ 7008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p += 20; 7018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 7028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if ((page == 0x3f || page == 0x2a) 7038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project && (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM)) { 7048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* CD Capabilities and Mechanical Status page. */ 7058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[0] = 0x2a; 7068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[1] = 0x14; 7078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[2] = 3; // CD-R & CD-RW read 7088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[3] = 0; // Writing not supported 7098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[4] = 0x7f; /* Audio, composite, digital out, 7108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project mode 2 form 1&2, multi session */ 7118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[5] = 0xff; /* CD DA, DA accurate, RW supported, 7128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project RW corrected, C2 errors, ISRC, 7138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project UPC, Bar code */ 7148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[6] = 0x2d | (bdrv_is_locked(s->bdrv)? 2 : 0); 7158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Locking supported, jumper present, eject, tray */ 7168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[7] = 0; /* no volume & mute control, no 7178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project changer */ 7188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[8] = (50 * 176) >> 8; // 50x read speed 7198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[9] = (50 * 176) & 0xff; 7208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[10] = 0 >> 8; // No volume 7218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[11] = 0 & 0xff; 7228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[12] = 2048 >> 8; // 2M buffer 7238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[13] = 2048 & 0xff; 7248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[14] = (16 * 176) >> 8; // 16x read speed current 7258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[15] = (16 * 176) & 0xff; 7268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[18] = (16 * 176) >> 8; // 16x write speed 7278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[19] = (16 * 176) & 0xff; 7288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[20] = (16 * 176) >> 8; // 16x write speed current 7298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p[21] = (16 * 176) & 0xff; 7308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p += 22; 7318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 7325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner r->iov.iov_len = p - outbuf; 7335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[0] = r->iov.iov_len - 4; 7345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (r->iov.iov_len > len) 7355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner r->iov.iov_len = len; 7368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 7378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 7388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x1b: 7398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Start Stop Unit\n"); 7405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM && 7415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner (buf[4] & 2)) 7425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* load/eject medium */ 7435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bdrv_eject(s->bdrv, !(buf[4] & 1)); 7448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 7458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x1e: 7468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Prevent Allow Medium Removal (prevent = %d)\n", buf[4] & 3); 7478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bdrv_set_locked(s->bdrv, buf[4] & 1); 7488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 7498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x25: 7508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Read Capacity\n"); 7518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* The normal LEN field for this command is zero. */ 7528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memset(outbuf, 0, 8); 7538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bdrv_get_geometry(s->bdrv, &nb_sectors); 7545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner nb_sectors /= s->cluster_size; 7558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* Returned value is the address of the last sector. */ 7568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (nb_sectors) { 7578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project nb_sectors--; 7585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Remember the new size for read/write sanity checking. */ 7595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->max_lba = nb_sectors; 7605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Clip to 2TB, instead of returning capacity modulo 2TB. */ 7615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (nb_sectors > UINT32_MAX) 7625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner nb_sectors = UINT32_MAX; 7638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[0] = (nb_sectors >> 24) & 0xff; 7648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[1] = (nb_sectors >> 16) & 0xff; 7658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[2] = (nb_sectors >> 8) & 0xff; 7668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[3] = nb_sectors & 0xff; 7678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[4] = 0; 7688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[5] = 0; 7698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[6] = s->cluster_size * 2; 7708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[7] = 0; 7715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner r->iov.iov_len = 8; 7728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 7735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner notready: 7745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_NOT_READY); 7758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return 0; 7768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 7778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 7788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x08: 7798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x28: 7805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case 0x88: 7815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner DPRINTF("Read (sector %lld, count %d)\n", lba, len); 7825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (lba > s->max_lba) 7835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto illegal_lba; 7848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->sector = lba * s->cluster_size; 7858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->sector_count = len * s->cluster_size; 7868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 7878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x0a: 7888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x2a: 7895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case 0x8a: 7905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner DPRINTF("Write (sector %lld, count %d)\n", lba, len); 7915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (lba > s->max_lba) 7925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto illegal_lba; 7938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->sector = lba * s->cluster_size; 7948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->sector_count = len * s->cluster_size; 7958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project is_write = 1; 7968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 7978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x35: 7988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Synchronise cache (sector %d, count %d)\n", lba, len); 7998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bdrv_flush(s->bdrv); 8008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 8018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x43: 8028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 8038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int start_track, format, msf, toclen; 8048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 8058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project msf = buf[1] & 2; 8068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project format = buf[2] & 0xf; 8078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project start_track = buf[6]; 8088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bdrv_get_geometry(s->bdrv, &nb_sectors); 8098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1); 8105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner nb_sectors /= s->cluster_size; 8118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project switch(format) { 8128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0: 8138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project toclen = cdrom_read_toc(nb_sectors, outbuf, msf, start_track); 8148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 8158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 1: 8168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* multi session : only a single session defined */ 8178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project toclen = 12; 8188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memset(outbuf, 0, 12); 8198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[1] = 0x0a; 8208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[2] = 0x01; 8218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[3] = 0x01; 8228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 8238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 2: 8248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project toclen = cdrom_read_toc_raw(nb_sectors, outbuf, msf, start_track); 8258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 8268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project default: 8278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto error_cmd; 8288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 8298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (toclen > 0) { 8308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (len > toclen) 8318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project len = toclen; 8325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner r->iov.iov_len = len; 8338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 8348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 8358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project error_cmd: 8368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Read TOC error\n"); 8378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto fail; 8388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 8398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x46: 8408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Get Configuration (rt %d, maxlen %d)\n", buf[1] & 3, len); 8418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memset(outbuf, 0, 8); 8428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* ??? This should probably return much more information. For now 8438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project just return the basic header indicating the CD-ROM profile. */ 8448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[7] = 8; // CD-ROM 8455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner r->iov.iov_len = 8; 8468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 8478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x56: 8488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Reserve(10)\n"); 8498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (buf[1] & 3) 8508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto fail; 8518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 8528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0x57: 8538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Release(10)\n"); 8548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (buf[1] & 3) 8558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto fail; 8568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 8575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case 0x9e: 8585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Service Action In subcommands. */ 8595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if ((buf[1] & 31) == 0x10) { 8605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner DPRINTF("SAI READ CAPACITY(16)\n"); 8615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner memset(outbuf, 0, len); 8625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bdrv_get_geometry(s->bdrv, &nb_sectors); 8635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner nb_sectors /= s->cluster_size; 8645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Returned value is the address of the last sector. */ 8655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (nb_sectors) { 8665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner nb_sectors--; 8675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Remember the new size for read/write sanity checking. */ 8685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->max_lba = nb_sectors; 8695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[0] = (nb_sectors >> 56) & 0xff; 8705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[1] = (nb_sectors >> 48) & 0xff; 8715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[2] = (nb_sectors >> 40) & 0xff; 8725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[3] = (nb_sectors >> 32) & 0xff; 8735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[4] = (nb_sectors >> 24) & 0xff; 8745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[5] = (nb_sectors >> 16) & 0xff; 8755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[6] = (nb_sectors >> 8) & 0xff; 8765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[7] = nb_sectors & 0xff; 8775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[8] = 0; 8785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[9] = 0; 8795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[10] = s->cluster_size * 2; 8805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner outbuf[11] = 0; 8815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Protection, exponent and lowest lba field left blank. */ 8825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner r->iov.iov_len = len; 8835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else { 8845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_NOT_READY); 8855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 8865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 8875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 8885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 8895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner DPRINTF("Unsupported Service Action In\n"); 8905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto fail; 8918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case 0xa0: 8928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Report LUNs (len %d)\n", len); 8938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (len < 16) 8948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto fail; 8958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project memset(outbuf, 0, 16); 8968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project outbuf[3] = 8; 8975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner r->iov.iov_len = 16; 8985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 8995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case 0x2f: 9005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner DPRINTF("Verify (sector %d, count %d)\n", lba, len); 9018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 9028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project default: 9038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]); 9048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project fail: 9055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_ILLEGAL_REQUEST); 9068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return 0; 9075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner illegal_lba: 9085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR); 9095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 9108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 9115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (r->sector_count == 0 && r->iov.iov_len == 0) { 9125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner scsi_command_complete(r, STATUS_GOOD, SENSE_NO_SENSE); 9138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 9145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner len = r->sector_count * 512 + r->iov.iov_len; 9158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (is_write) { 9168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return -len; 9178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 9188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (!r->sector_count) 9198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project r->sector_count = -1; 9208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return len; 9218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 9228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 9238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 9248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void scsi_destroy(SCSIDevice *d) 9258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 9268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_free(d->state); 9278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_free(d); 9288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 9298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 9308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source ProjectSCSIDevice *scsi_disk_init(BlockDriverState *bdrv, int tcq, 9318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project scsi_completionfn completion, void *opaque) 9328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 9338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIDevice *d; 9348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SCSIDeviceState *s; 9355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint64_t nb_sectors; 9368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 9378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s = (SCSIDeviceState *)qemu_mallocz(sizeof(SCSIDeviceState)); 9388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->bdrv = bdrv; 9398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->tcq = tcq; 9408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->completion = completion; 9418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->opaque = opaque; 9428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { 9438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->cluster_size = 4; 9448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 9458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project s->cluster_size = 1; 9468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 9475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bdrv_get_geometry(s->bdrv, &nb_sectors); 9485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner nb_sectors /= s->cluster_size; 9495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (nb_sectors) 9505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner nb_sectors--; 9515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->max_lba = nb_sectors; 952cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner#if 0 9535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner strncpy(s->drive_serial_str, drive_get_serial(s->bdrv), 9545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner sizeof(s->drive_serial_str)); 9555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (strlen(s->drive_serial_str) == 0) 956cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner#endif 9575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pstrcpy(s->drive_serial_str, sizeof(s->drive_serial_str), "0"); 9585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s); 9598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project d = (SCSIDevice *)qemu_mallocz(sizeof(SCSIDevice)); 9608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project d->state = s; 9618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project d->destroy = scsi_destroy; 9628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project d->send_command = scsi_send_command; 9638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project d->read_data = scsi_read_data; 9648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project d->write_data = scsi_write_data; 9658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project d->cancel_io = scsi_cancel_io; 9668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project d->get_buf = scsi_get_buf; 9678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 9688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return d; 9698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 970