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