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