static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)

{

    SCSIRequest *req = &r->req;

    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);

    uint64_t nb_sectors;

    int buflen = 0;

    int ret;



    switch (req->cmd.buf[0]) {

    case TEST_UNIT_READY:

        if (!bdrv_is_inserted(s->bs))

            goto not_ready;

        break;

    case REQUEST_SENSE:

        if (req->cmd.xfer < 4)

            goto illegal_request;

        buflen = scsi_device_get_sense(&s->qdev, outbuf, req->cmd.xfer,

                                       (req->cmd.buf[1] & 1) == 0);

        break;

    case INQUIRY:

        buflen = scsi_disk_emulate_inquiry(req, outbuf);

        if (buflen < 0)

            goto illegal_request;

        break;

    case MODE_SENSE:

    case MODE_SENSE_10:

        buflen = scsi_disk_emulate_mode_sense(req, outbuf);

        if (buflen < 0)

            goto illegal_request;

        break;

    case READ_TOC:

        buflen = scsi_disk_emulate_read_toc(req, outbuf);

        if (buflen < 0)

            goto illegal_request;

        break;

    case RESERVE:

        if (req->cmd.buf[1] & 1)

            goto illegal_request;

        break;

    case RESERVE_10:

        if (req->cmd.buf[1] & 3)

            goto illegal_request;

        break;

    case RELEASE:

        if (req->cmd.buf[1] & 1)

            goto illegal_request;

        break;

    case RELEASE_10:

        if (req->cmd.buf[1] & 3)

            goto illegal_request;

        break;

    case START_STOP:

        if (s->qdev.type == TYPE_ROM && (req->cmd.buf[4] & 2)) {

            /* load/eject medium */

            bdrv_eject(s->bs, !(req->cmd.buf[4] & 1));

        }

        break;

    case ALLOW_MEDIUM_REMOVAL:

        bdrv_set_locked(s->bs, req->cmd.buf[4] & 1);

        break;

    case READ_CAPACITY_10:

        /* The normal LEN field for this command is zero.  */

        memset(outbuf, 0, 8);

        bdrv_get_geometry(s->bs, &nb_sectors);

        if (!nb_sectors)

            goto not_ready;

        nb_sectors /= s->cluster_size;

        /* Returned value is the address of the last sector.  */

        nb_sectors--;

        /* Remember the new size for read/write sanity checking. */

        s->max_lba = nb_sectors;

        /* Clip to 2TB, instead of returning capacity modulo 2TB. */

        if (nb_sectors > UINT32_MAX)

            nb_sectors = UINT32_MAX;

        outbuf[0] = (nb_sectors >> 24) & 0xff;

        outbuf[1] = (nb_sectors >> 16) & 0xff;

        outbuf[2] = (nb_sectors >> 8) & 0xff;

        outbuf[3] = nb_sectors & 0xff;

        outbuf[4] = 0;

        outbuf[5] = 0;

        outbuf[6] = s->cluster_size * 2;

        outbuf[7] = 0;

        buflen = 8;

        break;

    case SYNCHRONIZE_CACHE:

        ret = bdrv_flush(s->bs);

        if (ret < 0) {

            if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_FLUSH)) {

                return -1;

            }

        }

        break;

    case GET_CONFIGURATION:

        memset(outbuf, 0, 8);

        /* ??? This should probably return much more information.  For now

           just return the basic header indicating the CD-ROM profile.  */

        outbuf[7] = 8; // CD-ROM

        buflen = 8;

        break;

    case SERVICE_ACTION_IN:

        /* Service Action In subcommands. */

        if ((req->cmd.buf[1] & 31) == 0x10) {

            DPRINTF("SAI READ CAPACITY(16)\n");

            memset(outbuf, 0, req->cmd.xfer);

            bdrv_get_geometry(s->bs, &nb_sectors);

            if (!nb_sectors)

                goto not_ready;

            nb_sectors /= s->cluster_size;

            /* Returned value is the address of the last sector.  */

            nb_sectors--;

            /* Remember the new size for read/write sanity checking. */

            s->max_lba = nb_sectors;

            outbuf[0] = (nb_sectors >> 56) & 0xff;

            outbuf[1] = (nb_sectors >> 48) & 0xff;

            outbuf[2] = (nb_sectors >> 40) & 0xff;

            outbuf[3] = (nb_sectors >> 32) & 0xff;

            outbuf[4] = (nb_sectors >> 24) & 0xff;

            outbuf[5] = (nb_sectors >> 16) & 0xff;

            outbuf[6] = (nb_sectors >> 8) & 0xff;

            outbuf[7] = nb_sectors & 0xff;

            outbuf[8] = 0;

            outbuf[9] = 0;

            outbuf[10] = s->cluster_size * 2;

            outbuf[11] = 0;

            outbuf[12] = 0;

            outbuf[13] = get_physical_block_exp(&s->qdev.conf);



            /* set TPE bit if the format supports discard */

            if (s->qdev.conf.discard_granularity) {

                outbuf[14] = 0x80;

            }



            /* Protection, exponent and lowest lba field left blank. */

            buflen = req->cmd.xfer;

            break;

        }

        DPRINTF("Unsupported Service Action In\n");

        goto illegal_request;

    case REPORT_LUNS:

        if (req->cmd.xfer < 16)

            goto illegal_request;

        memset(outbuf, 0, 16);

        outbuf[3] = 8;

        buflen = 16;

        break;

    case VERIFY_10:

        break;

    default:

        scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));

        return -1;

    }

    return buflen;



not_ready:

    if (!bdrv_is_inserted(s->bs)) {

        scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));

    } else {

        scsi_check_condition(r, SENSE_CODE(LUN_NOT_READY));

    }

    return -1;



illegal_request:

    scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));

    return -1;

}

static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)

{

    SCSIRequest *req = &r->req;

    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);

    uint64_t nb_sectors;

    int buflen = 0;

    int ret;



    switch (req->cmd.buf[0]) {

    case TEST_UNIT_READY:

        if (!bdrv_is_inserted(s->bs))

            goto not_ready;

        break;

    case REQUEST_SENSE:

        if (req->cmd.xfer < 4)

            goto illegal_request;

        buflen = scsi_device_get_sense(&s->qdev, outbuf, req->cmd.xfer,

                                       (req->cmd.buf[1] & 1) == 0);

        break;

    case INQUIRY:

        buflen = scsi_disk_emulate_inquiry(req, outbuf);

        if (buflen < 0)

            goto illegal_request;

        break;

    case MODE_SENSE:

    case MODE_SENSE_10:

        buflen = scsi_disk_emulate_mode_sense(req, outbuf);

        if (buflen < 0)

            goto illegal_request;

        break;

    case READ_TOC:

        buflen = scsi_disk_emulate_read_toc(req, outbuf);

        if (buflen < 0)

            goto illegal_request;

        break;

    case RESERVE:

        if (req->cmd.buf[1] & 1)

            goto illegal_request;

        break;

    case RESERVE_10:

        if (req->cmd.buf[1] & 3)

            goto illegal_request;

        break;

    case RELEASE:

        if (req->cmd.buf[1] & 1)

            goto illegal_request;

        break;

    case RELEASE_10:

        if (req->cmd.buf[1] & 3)

            goto illegal_request;

        break;

    case START_STOP:

        if (s->qdev.type == TYPE_ROM && (req->cmd.buf[4] & 2)) {

            

            bdrv_eject(s->bs, !(req->cmd.buf[4] & 1));

        }

        break;

    case ALLOW_MEDIUM_REMOVAL:

        bdrv_set_locked(s->bs, req->cmd.buf[4] & 1);

        break;

    case READ_CAPACITY_10:

        

        memset(outbuf, 0, 8);

        bdrv_get_geometry(s->bs, &nb_sectors);

        if (!nb_sectors)

            goto not_ready;

        nb_sectors /= s->cluster_size;

        

        nb_sectors--;

        

        s->max_lba = nb_sectors;

        

        if (nb_sectors > UINT32_MAX)

            nb_sectors = UINT32_MAX;

        outbuf[0] = (nb_sectors >> 24) & 0xff;

        outbuf[1] = (nb_sectors >> 16) & 0xff;

        outbuf[2] = (nb_sectors >> 8) & 0xff;

        outbuf[3] = nb_sectors & 0xff;

        outbuf[4] = 0;

        outbuf[5] = 0;

        outbuf[6] = s->cluster_size * 2;

        outbuf[7] = 0;

        buflen = 8;

        break;

    case SYNCHRONIZE_CACHE:

        ret = bdrv_flush(s->bs);

        if (ret < 0) {

            if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_FLUSH)) {

                return -1;

            }

        }

        break;

    case GET_CONFIGURATION:

        memset(outbuf, 0, 8);

        



        outbuf[7] = 8; 

        buflen = 8;

        break;

    case SERVICE_ACTION_IN:

        

        if ((req->cmd.buf[1] & 31) == 0x10) {

            DPRINTF("SAI READ CAPACITY(16)\n");

            memset(outbuf, 0, req->cmd.xfer);

            bdrv_get_geometry(s->bs, &nb_sectors);

            if (!nb_sectors)

                goto not_ready;

            nb_sectors /= s->cluster_size;

            

            nb_sectors--;

            

            s->max_lba = nb_sectors;

            outbuf[0] = (nb_sectors >> 56) & 0xff;

            outbuf[1] = (nb_sectors >> 48) & 0xff;

            outbuf[2] = (nb_sectors >> 40) & 0xff;

            outbuf[3] = (nb_sectors >> 32) & 0xff;

            outbuf[4] = (nb_sectors >> 24) & 0xff;

            outbuf[5] = (nb_sectors >> 16) & 0xff;

            outbuf[6] = (nb_sectors >> 8) & 0xff;

            outbuf[7] = nb_sectors & 0xff;

            outbuf[8] = 0;

            outbuf[9] = 0;

            outbuf[10] = s->cluster_size * 2;

            outbuf[11] = 0;

            outbuf[12] = 0;

            outbuf[13] = get_physical_block_exp(&s->qdev.conf);



            

            if (s->qdev.conf.discard_granularity) {

                outbuf[14] = 0x80;

            }



            

            buflen = req->cmd.xfer;

            break;

        }

        DPRINTF("Unsupported Service Action In\n");

        goto illegal_request;

    case REPORT_LUNS:

        if (req->cmd.xfer < 16)

            goto illegal_request;

        memset(outbuf, 0, 16);

        outbuf[3] = 8;

        buflen = 16;

        break;

    case VERIFY_10:

        break;

    default:

        scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));

        return -1;

    }

    return buflen;



not_ready:

    if (!bdrv_is_inserted(s->bs)) {

        scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));

    } else {

        scsi_check_condition(r, SENSE_CODE(LUN_NOT_READY));

    }

    return -1;



illegal_request:

    scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));

    return -1;

}

static int FUNC_0(SCSIDiskReq *VAR_0, uint8_t *VAR_1)

{

    SCSIRequest *req = &VAR_0->req;

    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);

    uint64_t nb_sectors;

    int VAR_2 = 0;

    int VAR_3;



    switch (req->cmd.buf[0]) {

    case TEST_UNIT_READY:

        if (!bdrv_is_inserted(s->bs))

            goto not_ready;

        break;

    case REQUEST_SENSE:

        if (req->cmd.xfer < 4)

            goto illegal_request;

        VAR_2 = scsi_device_get_sense(&s->qdev, VAR_1, req->cmd.xfer,

                                       (req->cmd.buf[1] & 1) == 0);

        break;

    case INQUIRY:

        VAR_2 = scsi_disk_emulate_inquiry(req, VAR_1);

        if (VAR_2 < 0)

            goto illegal_request;

        break;

    case MODE_SENSE:

    case MODE_SENSE_10:

        VAR_2 = scsi_disk_emulate_mode_sense(req, VAR_1);

        if (VAR_2 < 0)

            goto illegal_request;

        break;

    case READ_TOC:

        VAR_2 = scsi_disk_emulate_read_toc(req, VAR_1);

        if (VAR_2 < 0)

            goto illegal_request;

        break;

    case RESERVE:

        if (req->cmd.buf[1] & 1)

            goto illegal_request;

        break;

    case RESERVE_10:

        if (req->cmd.buf[1] & 3)

            goto illegal_request;

        break;

    case RELEASE:

        if (req->cmd.buf[1] & 1)

            goto illegal_request;

        break;

    case RELEASE_10:

        if (req->cmd.buf[1] & 3)

            goto illegal_request;

        break;

    case START_STOP:

        if (s->qdev.type == TYPE_ROM && (req->cmd.buf[4] & 2)) {

            

            bdrv_eject(s->bs, !(req->cmd.buf[4] & 1));

        }

        break;

    case ALLOW_MEDIUM_REMOVAL:

        bdrv_set_locked(s->bs, req->cmd.buf[4] & 1);

        break;

    case READ_CAPACITY_10:

        

        memset(VAR_1, 0, 8);

        bdrv_get_geometry(s->bs, &nb_sectors);

        if (!nb_sectors)

            goto not_ready;

        nb_sectors /= s->cluster_size;

        

        nb_sectors--;

        

        s->max_lba = nb_sectors;

        

        if (nb_sectors > UINT32_MAX)

            nb_sectors = UINT32_MAX;

        VAR_1[0] = (nb_sectors >> 24) & 0xff;

        VAR_1[1] = (nb_sectors >> 16) & 0xff;

        VAR_1[2] = (nb_sectors >> 8) & 0xff;

        VAR_1[3] = nb_sectors & 0xff;

        VAR_1[4] = 0;

        VAR_1[5] = 0;

        VAR_1[6] = s->cluster_size * 2;

        VAR_1[7] = 0;

        VAR_2 = 8;

        break;

    case SYNCHRONIZE_CACHE:

        VAR_3 = bdrv_flush(s->bs);

        if (VAR_3 < 0) {

            if (scsi_handle_rw_error(VAR_0, -VAR_3, SCSI_REQ_STATUS_RETRY_FLUSH)) {

                return -1;

            }

        }

        break;

    case GET_CONFIGURATION:

        memset(VAR_1, 0, 8);

        



        VAR_1[7] = 8; 

        VAR_2 = 8;

        break;

    case SERVICE_ACTION_IN:

        

        if ((req->cmd.buf[1] & 31) == 0x10) {

            DPRINTF("SAI READ CAPACITY(16)\n");

            memset(VAR_1, 0, req->cmd.xfer);

            bdrv_get_geometry(s->bs, &nb_sectors);

            if (!nb_sectors)

                goto not_ready;

            nb_sectors /= s->cluster_size;

            

            nb_sectors--;

            

            s->max_lba = nb_sectors;

            VAR_1[0] = (nb_sectors >> 56) & 0xff;

            VAR_1[1] = (nb_sectors >> 48) & 0xff;

            VAR_1[2] = (nb_sectors >> 40) & 0xff;

            VAR_1[3] = (nb_sectors >> 32) & 0xff;

            VAR_1[4] = (nb_sectors >> 24) & 0xff;

            VAR_1[5] = (nb_sectors >> 16) & 0xff;

            VAR_1[6] = (nb_sectors >> 8) & 0xff;

            VAR_1[7] = nb_sectors & 0xff;

            VAR_1[8] = 0;

            VAR_1[9] = 0;

            VAR_1[10] = s->cluster_size * 2;

            VAR_1[11] = 0;

            VAR_1[12] = 0;

            VAR_1[13] = get_physical_block_exp(&s->qdev.conf);



            

            if (s->qdev.conf.discard_granularity) {

                VAR_1[14] = 0x80;

            }



            

            VAR_2 = req->cmd.xfer;

            break;

        }

        DPRINTF("Unsupported Service Action In\n");

        goto illegal_request;

    case REPORT_LUNS:

        if (req->cmd.xfer < 16)

            goto illegal_request;

        memset(VAR_1, 0, 16);

        VAR_1[3] = 8;

        VAR_2 = 16;

        break;

    case VERIFY_10:

        break;

    default:

        scsi_check_condition(VAR_0, SENSE_CODE(INVALID_OPCODE));

        return -1;

    }

    return VAR_2;



not_ready:

    if (!bdrv_is_inserted(s->bs)) {

        scsi_check_condition(VAR_0, SENSE_CODE(NO_MEDIUM));

    } else {

        scsi_check_condition(VAR_0, SENSE_CODE(LUN_NOT_READY));

    }

    return -1;



illegal_request:

    scsi_check_condition(VAR_0, SENSE_CODE(INVALID_FIELD));

    return -1;

}

static int FUNC_0(SCSIDiskReq *VAR_0, uint8_t *VAR_1)
{ SCSIRequest *req = &VAR_0->req; SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); uint64_t nb_sectors; int VAR_2 = 0; int VAR_3; switch (req->cmd.buf[0]) { case TEST_UNIT_READY:
if (!bdrv_is_inserted(s->bs))
goto not_ready; break; case REQUEST_SENSE:
if (req->cmd.xfer < 4)
goto illegal_request; VAR_2 = scsi_device_get_sense(&s->qdev, VAR_1, req->cmd.xfer,
(req->cmd.buf[1] & 1) == 0); break; case INQUIRY:
VAR_2 = scsi_disk_emulate_inquiry(req, VAR_1); if (VAR_2 < 0)
goto illegal_request; break; case MODE_SENSE:
case MODE_SENSE_10:
VAR_2 = scsi_disk_emulate_mode_sense(req, VAR_1); if (VAR_2 < 0)
goto illegal_request; break; case READ_TOC:
VAR_2 = scsi_disk_emulate_read_toc(req, VAR_1); if (VAR_2 < 0)
goto illegal_request; break; case RESERVE:
if (req->cmd.buf[1] & 1)
goto illegal_request; break; case RESERVE_10:
if (req->cmd.buf[1] & 3)
goto illegal_request; break; case RELEASE:
if (req->cmd.buf[1] & 1)
goto illegal_request; break; case RELEASE_10:
if (req->cmd.buf[1] & 3)
goto illegal_request; break; case START_STOP:
if (s->qdev.type == TYPE_ROM && (req->cmd.buf[4] & 2)) { bdrv_eject(s->bs, !(req->cmd.buf[4] & 1)); } break; case ALLOW_MEDIUM_REMOVAL:
bdrv_set_locked(s->bs, req->cmd.buf[4] & 1); break; case READ_CAPACITY_10:
memset(VAR_1, 0, 8); bdrv_get_geometry(s->bs, &nb_sectors); if (!nb_sectors)
goto not_ready; nb_sectors /= s->cluster_size; nb_sectors--; s->max_lba = nb_sectors; if (nb_sectors > UINT32_MAX)
nb_sectors = UINT32_MAX; VAR_1[0] = (nb_sectors >> 24) & 0xff; VAR_1[1] = (nb_sectors >> 16) & 0xff; VAR_1[2] = (nb_sectors >> 8) & 0xff; VAR_1[3] = nb_sectors & 0xff; VAR_1[4] = 0; VAR_1[5] = 0; VAR_1[6] = s->cluster_size * 2; VAR_1[7] = 0; VAR_2 = 8; break; case SYNCHRONIZE_CACHE:
VAR_3 = bdrv_flush(s->bs); if (VAR_3 < 0) { if (scsi_handle_rw_error(VAR_0, -VAR_3, SCSI_REQ_STATUS_RETRY_FLUSH)) { return -1; } } break; case GET_CONFIGURATION:
memset(VAR_1, 0, 8); VAR_1[7] = 8; VAR_2 = 8; break; case SERVICE_ACTION_IN:
if ((req->cmd.buf[1] & 31) == 0x10) { DPRINTF("SAI READ CAPACITY(16)\n"); memset(VAR_1, 0, req->cmd.xfer); bdrv_get_geometry(s->bs, &nb_sectors); if (!nb_sectors)
goto not_ready; nb_sectors /= s->cluster_size; nb_sectors--; s->max_lba = nb_sectors; VAR_1[0] = (nb_sectors >> 56) & 0xff; VAR_1[1] = (nb_sectors >> 48) & 0xff; VAR_1[2] = (nb_sectors >> 40) & 0xff; VAR_1[3] = (nb_sectors >> 32) & 0xff; VAR_1[4] = (nb_sectors >> 24) & 0xff; VAR_1[5] = (nb_sectors >> 16) & 0xff; VAR_1[6] = (nb_sectors >> 8) & 0xff; VAR_1[7] = nb_sectors & 0xff; VAR_1[8] = 0; VAR_1[9] = 0; VAR_1[10] = s->cluster_size * 2; VAR_1[11] = 0; VAR_1[12] = 0; VAR_1[13] = get_physical_block_exp(&s->qdev.conf); if (s->qdev.conf.discard_granularity) { VAR_1[14] = 0x80; } VAR_2 = req->cmd.xfer; break; } DPRINTF("Unsupported Service Action In\n"); goto illegal_request; case REPORT_LUNS:
if (req->cmd.xfer < 16)
goto illegal_request; memset(VAR_1, 0, 16); VAR_1[3] = 8; VAR_2 = 16; break; case VERIFY_10:
break; default:
scsi_check_condition(VAR_0, SENSE_CODE(INVALID_OPCODE)); return -1; } return VAR_2; not_ready:
if (!bdrv_is_inserted(s->bs)) { scsi_check_condition(VAR_0, SENSE_CODE(NO_MEDIUM)); } else { scsi_check_condition(VAR_0, SENSE_CODE(LUN_NOT_READY)); } return -1; illegal_request:
scsi_check_condition(VAR_0, SENSE_CODE(INVALID_FIELD)); return -1; }