static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)

{

    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);

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

    int32_t len;

    uint8_t command;

    uint8_t *outbuf;

    int rc;



    command = buf[0];

    outbuf = (uint8_t *)r->iov.iov_base;

    DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", req->lun, req->tag, buf[0]);



    if (scsi_req_parse(&r->req, buf) != 0) {

        BADF("Unsupported command length, command %x\n", command);

        scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_OPCODE));

        return 0;

    }

#ifdef DEBUG_SCSI

    {

        int i;

        for (i = 1; i < r->req.cmd.len; i++) {

            printf(" 0x%02x", buf[i]);

        }

        printf("\n");

    }

#endif



    if (req->lun) {

        /* Only LUN 0 supported.  */

        DPRINTF("Unimplemented LUN %d\n", req->lun);

        if (command != REQUEST_SENSE && command != INQUIRY) {

            scsi_command_complete(r, CHECK_CONDITION,

                                  SENSE_CODE(LUN_NOT_SUPPORTED));

            return 0;

        }

    }

    switch (command) {

    case TEST_UNIT_READY:

    case REQUEST_SENSE:

    case INQUIRY:

    case MODE_SENSE:

    case MODE_SENSE_10:

    case RESERVE:

    case RESERVE_10:

    case RELEASE:

    case RELEASE_10:

    case START_STOP:

    case ALLOW_MEDIUM_REMOVAL:

    case READ_CAPACITY:

    case SYNCHRONIZE_CACHE:

    case READ_TOC:

    case GET_CONFIGURATION:

    case SERVICE_ACTION_IN:

    case REPORT_LUNS:

    case VERIFY:

        rc = scsi_disk_emulate_command(r, outbuf);

        if (rc < 0) {

            return 0;

        }



        r->iov.iov_len = rc;

        break;

    case READ_6:

    case READ_10:

    case READ_12:

    case READ_16:

        len = r->req.cmd.xfer / s->qdev.blocksize;

        DPRINTF("Read (sector %" PRId64 ", count %d)\n", r->req.cmd.lba, len);

        if (r->req.cmd.lba > s->max_lba)

            goto illegal_lba;

        r->sector = r->req.cmd.lba * s->cluster_size;

        r->sector_count = len * s->cluster_size;

        break;

    case WRITE_6:

    case WRITE_10:

    case WRITE_12:

    case WRITE_16:

    case WRITE_VERIFY:

    case WRITE_VERIFY_12:

    case WRITE_VERIFY_16:

        len = r->req.cmd.xfer / s->qdev.blocksize;

        DPRINTF("Write %s(sector %" PRId64 ", count %d)\n",

                (command & 0xe) == 0xe ? "And Verify " : "",

                r->req.cmd.lba, len);

        if (r->req.cmd.lba > s->max_lba)

            goto illegal_lba;

        r->sector = r->req.cmd.lba * s->cluster_size;

        r->sector_count = len * s->cluster_size;

        break;

    case MODE_SELECT:

        DPRINTF("Mode Select(6) (len %lu)\n", (long)r->req.cmd.xfer);

        /* We don't support mode parameter changes.

           Allow the mode parameter header + block descriptors only. */

        if (r->req.cmd.xfer > 12) {

            goto fail;

        }

        break;

    case MODE_SELECT_10:

        DPRINTF("Mode Select(10) (len %lu)\n", (long)r->req.cmd.xfer);

        /* We don't support mode parameter changes.

           Allow the mode parameter header + block descriptors only. */

        if (r->req.cmd.xfer > 16) {

            goto fail;

        }

        break;

    case SEEK_6:

    case SEEK_10:

        DPRINTF("Seek(%d) (sector %" PRId64 ")\n", command == SEEK_6 ? 6 : 10,

                r->req.cmd.lba);

        if (r->req.cmd.lba > s->max_lba) {

            goto illegal_lba;

        }

        break;

    case WRITE_SAME_16:

        len = r->req.cmd.xfer / s->qdev.blocksize;



        DPRINTF("WRITE SAME(16) (sector %" PRId64 ", count %d)\n",

                r->req.cmd.lba, len);



        if (r->req.cmd.lba > s->max_lba) {

            goto illegal_lba;

        }



        /*

         * We only support WRITE SAME with the unmap bit set for now.

         */

        if (!(buf[1] & 0x8)) {

            goto fail;

        }



        rc = bdrv_discard(s->bs, r->req.cmd.lba * s->cluster_size,

                          len * s->cluster_size);

        if (rc < 0) {

            /* XXX: better error code ?*/

            goto fail;

        }



        break;

    default:

        DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);

        scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_OPCODE));

        return 0;

    fail:

        scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_FIELD));

        return 0;

    illegal_lba:

        scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(LBA_OUT_OF_RANGE));

        return 0;

    }

    if (r->sector_count == 0 && r->iov.iov_len == 0) {

        scsi_command_complete(r, GOOD, SENSE_CODE(NO_SENSE));

    }

    len = r->sector_count * 512 + r->iov.iov_len;

    if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {

        return -len;

    } else {

        if (!r->sector_count)

            r->sector_count = -1;

        return len;

    }

}

static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)

{

    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);

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

    int32_t len;

    uint8_t command;

    uint8_t *outbuf;

    int rc;



    command = buf[0];

    outbuf = (uint8_t *)r->iov.iov_base;

    DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", req->lun, req->tag, buf[0]);



    if (scsi_req_parse(&r->req, buf) != 0) {

        BADF("Unsupported command length, command %x\n", command);

        scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_OPCODE));

        return 0;

    }

#ifdef DEBUG_SCSI

    {

        int i;

        for (i = 1; i < r->req.cmd.len; i++) {

            printf(" 0x%02x", buf[i]);

        }

        printf("\n");

    }

#endif



    if (req->lun) {

        

        DPRINTF("Unimplemented LUN %d\n", req->lun);

        if (command != REQUEST_SENSE && command != INQUIRY) {

            scsi_command_complete(r, CHECK_CONDITION,

                                  SENSE_CODE(LUN_NOT_SUPPORTED));

            return 0;

        }

    }

    switch (command) {

    case TEST_UNIT_READY:

    case REQUEST_SENSE:

    case INQUIRY:

    case MODE_SENSE:

    case MODE_SENSE_10:

    case RESERVE:

    case RESERVE_10:

    case RELEASE:

    case RELEASE_10:

    case START_STOP:

    case ALLOW_MEDIUM_REMOVAL:

    case READ_CAPACITY:

    case SYNCHRONIZE_CACHE:

    case READ_TOC:

    case GET_CONFIGURATION:

    case SERVICE_ACTION_IN:

    case REPORT_LUNS:

    case VERIFY:

        rc = scsi_disk_emulate_command(r, outbuf);

        if (rc < 0) {

            return 0;

        }



        r->iov.iov_len = rc;

        break;

    case READ_6:

    case READ_10:

    case READ_12:

    case READ_16:

        len = r->req.cmd.xfer / s->qdev.blocksize;

        DPRINTF("Read (sector %" PRId64 ", count %d)\n", r->req.cmd.lba, len);

        if (r->req.cmd.lba > s->max_lba)

            goto illegal_lba;

        r->sector = r->req.cmd.lba * s->cluster_size;

        r->sector_count = len * s->cluster_size;

        break;

    case WRITE_6:

    case WRITE_10:

    case WRITE_12:

    case WRITE_16:

    case WRITE_VERIFY:

    case WRITE_VERIFY_12:

    case WRITE_VERIFY_16:

        len = r->req.cmd.xfer / s->qdev.blocksize;

        DPRINTF("Write %s(sector %" PRId64 ", count %d)\n",

                (command & 0xe) == 0xe ? "And Verify " : "",

                r->req.cmd.lba, len);

        if (r->req.cmd.lba > s->max_lba)

            goto illegal_lba;

        r->sector = r->req.cmd.lba * s->cluster_size;

        r->sector_count = len * s->cluster_size;

        break;

    case MODE_SELECT:

        DPRINTF("Mode Select(6) (len %lu)\n", (long)r->req.cmd.xfer);

        



        if (r->req.cmd.xfer > 12) {

            goto fail;

        }

        break;

    case MODE_SELECT_10:

        DPRINTF("Mode Select(10) (len %lu)\n", (long)r->req.cmd.xfer);

        



        if (r->req.cmd.xfer > 16) {

            goto fail;

        }

        break;

    case SEEK_6:

    case SEEK_10:

        DPRINTF("Seek(%d) (sector %" PRId64 ")\n", command == SEEK_6 ? 6 : 10,

                r->req.cmd.lba);

        if (r->req.cmd.lba > s->max_lba) {

            goto illegal_lba;

        }

        break;

    case WRITE_SAME_16:

        len = r->req.cmd.xfer / s->qdev.blocksize;



        DPRINTF("WRITE SAME(16) (sector %" PRId64 ", count %d)\n",

                r->req.cmd.lba, len);



        if (r->req.cmd.lba > s->max_lba) {

            goto illegal_lba;

        }



        





        if (!(buf[1] & 0x8)) {

            goto fail;

        }



        rc = bdrv_discard(s->bs, r->req.cmd.lba * s->cluster_size,

                          len * s->cluster_size);

        if (rc < 0) {

            

            goto fail;

        }



        break;

    default:

        DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);

        scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_OPCODE));

        return 0;

    fail:

        scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_FIELD));

        return 0;

    illegal_lba:

        scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(LBA_OUT_OF_RANGE));

        return 0;

    }

    if (r->sector_count == 0 && r->iov.iov_len == 0) {

        scsi_command_complete(r, GOOD, SENSE_CODE(NO_SENSE));

    }

    len = r->sector_count * 512 + r->iov.iov_len;

    if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {

        return -len;

    } else {

        if (!r->sector_count)

            r->sector_count = -1;

        return len;

    }

}

    case VERIFY:     case READ_CAPACITY:     case WRITE_VERIFY:     case WRITE_VERIFY:     case READ_CAPACITY:     case VERIFY:     case READ_CAPACITY:     case VERIFY:     case WRITE_VERIFY:
static int32_t FUNC_0(SCSIRequest *req, uint8_t *buf)

{

    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);

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

    int32_t len;

    uint8_t command;

    uint8_t *outbuf;

    int VAR_0;



    command = buf[0];

    outbuf = (uint8_t *)r->iov.iov_base;

    DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", req->lun, req->tag, buf[0]);



    if (scsi_req_parse(&r->req, buf) != 0) {

        BADF("Unsupported command length, command %x\n", command);

        scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_OPCODE));

        return 0;

    }

#ifdef DEBUG_SCSI

    {

        int i;

        for (i = 1; i < r->req.cmd.len; i++) {

            printf(" 0x%02x", buf[i]);

        }

        printf("\n");

    }

#endif



    if (req->lun) {

        

        DPRINTF("Unimplemented LUN %d\n", req->lun);

        if (command != REQUEST_SENSE && command != INQUIRY) {

            scsi_command_complete(r, CHECK_CONDITION,

                                  SENSE_CODE(LUN_NOT_SUPPORTED));

            return 0;

        }

    }

    switch (command) {

    case TEST_UNIT_READY:

    case REQUEST_SENSE:

    case INQUIRY:

    case MODE_SENSE:

    case MODE_SENSE_10:

    case RESERVE:

    case RESERVE_10:

    case RELEASE:

    case RELEASE_10:

    case START_STOP:

    case ALLOW_MEDIUM_REMOVAL:

    case READ_CAPACITY:

    case SYNCHRONIZE_CACHE:

    case READ_TOC:

    case GET_CONFIGURATION:

    case SERVICE_ACTION_IN:

    case REPORT_LUNS:

    case VERIFY:

        VAR_0 = scsi_disk_emulate_command(r, outbuf);

        if (VAR_0 < 0) {

            return 0;

        }



        r->iov.iov_len = VAR_0;

        break;

    case READ_6:

    case READ_10:

    case READ_12:

    case READ_16:

        len = r->req.cmd.xfer / s->qdev.blocksize;

        DPRINTF("Read (sector %" PRId64 ", count %d)\n", r->req.cmd.lba, len);

        if (r->req.cmd.lba > s->max_lba)

            goto illegal_lba;

        r->sector = r->req.cmd.lba * s->cluster_size;

        r->sector_count = len * s->cluster_size;

        break;

    case WRITE_6:

    case WRITE_10:

    case WRITE_12:

    case WRITE_16:

    case WRITE_VERIFY:

    case WRITE_VERIFY_12:

    case WRITE_VERIFY_16:

        len = r->req.cmd.xfer / s->qdev.blocksize;

        DPRINTF("Write %s(sector %" PRId64 ", count %d)\n",

                (command & 0xe) == 0xe ? "And Verify " : "",

                r->req.cmd.lba, len);

        if (r->req.cmd.lba > s->max_lba)

            goto illegal_lba;

        r->sector = r->req.cmd.lba * s->cluster_size;

        r->sector_count = len * s->cluster_size;

        break;

    case MODE_SELECT:

        DPRINTF("Mode Select(6) (len %lu)\n", (long)r->req.cmd.xfer);

        



        if (r->req.cmd.xfer > 12) {

            goto fail;

        }

        break;

    case MODE_SELECT_10:

        DPRINTF("Mode Select(10) (len %lu)\n", (long)r->req.cmd.xfer);

        



        if (r->req.cmd.xfer > 16) {

            goto fail;

        }

        break;

    case SEEK_6:

    case SEEK_10:

        DPRINTF("Seek(%d) (sector %" PRId64 ")\n", command == SEEK_6 ? 6 : 10,

                r->req.cmd.lba);

        if (r->req.cmd.lba > s->max_lba) {

            goto illegal_lba;

        }

        break;

    case WRITE_SAME_16:

        len = r->req.cmd.xfer / s->qdev.blocksize;



        DPRINTF("WRITE SAME(16) (sector %" PRId64 ", count %d)\n",

                r->req.cmd.lba, len);



        if (r->req.cmd.lba > s->max_lba) {

            goto illegal_lba;

        }



        





        if (!(buf[1] & 0x8)) {

            goto fail;

        }



        VAR_0 = bdrv_discard(s->bs, r->req.cmd.lba * s->cluster_size,

                          len * s->cluster_size);

        if (VAR_0 < 0) {

            

            goto fail;

        }



        break;

    default:

        DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);

        scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_OPCODE));

        return 0;

    fail:

        scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_FIELD));

        return 0;

    illegal_lba:

        scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(LBA_OUT_OF_RANGE));

        return 0;

    }

    if (r->sector_count == 0 && r->iov.iov_len == 0) {

        scsi_command_complete(r, GOOD, SENSE_CODE(NO_SENSE));

    }

    len = r->sector_count * 512 + r->iov.iov_len;

    if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {

        return -len;

    } else {

        if (!r->sector_count)

            r->sector_count = -1;

        return len;

    }

}

static int32_t FUNC_0(SCSIRequest *req, uint8_t *buf)
{ SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); int32_t len; uint8_t command; uint8_t *outbuf; int VAR_0; command = buf[0]; outbuf = (uint8_t *)r->iov.iov_base; DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", req->lun, req->tag, buf[0]); if (scsi_req_parse(&r->req, buf) != 0) { BADF("Unsupported command length, command %x\n", command); scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_OPCODE)); return 0; } #ifdef DEBUG_SCSI
{ int i; for (i = 1; i < r->req.cmd.len; i++) { printf(" 0x%02x", buf[i]); } printf("\n"); } #endif
if (req->lun) { DPRINTF("Unimplemented LUN %d\n", req->lun); if (command != REQUEST_SENSE && command != INQUIRY) { scsi_command_complete(r, CHECK_CONDITION,
SENSE_CODE(LUN_NOT_SUPPORTED)); return 0; } } switch (command) { case TEST_UNIT_READY:
case REQUEST_SENSE:
case INQUIRY:
case MODE_SENSE:
case MODE_SENSE_10:
case RESERVE:
case RESERVE_10:
case RELEASE:
case RELEASE_10:
case START_STOP:
case ALLOW_MEDIUM_REMOVAL:
case READ_CAPACITY:
case SYNCHRONIZE_CACHE:
case READ_TOC:
case GET_CONFIGURATION:
case SERVICE_ACTION_IN:
case REPORT_LUNS:
case VERIFY:
VAR_0 = scsi_disk_emulate_command(r, outbuf); if (VAR_0 < 0) { return 0; } r->iov.iov_len = VAR_0; break; case READ_6:
case READ_10:
case READ_12:
case READ_16:
len = r->req.cmd.xfer / s->qdev.blocksize; DPRINTF("Read (sector %" PRId64 ", count %d)\n", r->req.cmd.lba, len); if (r->req.cmd.lba > s->max_lba)
goto illegal_lba; r->sector = r->req.cmd.lba * s->cluster_size; r->sector_count = len * s->cluster_size; break; case WRITE_6:
case WRITE_10:
case WRITE_12:
case WRITE_16:
case WRITE_VERIFY:
case WRITE_VERIFY_12:
case WRITE_VERIFY_16:
len = r->req.cmd.xfer / s->qdev.blocksize; DPRINTF("Write %s(sector %" PRId64 ", count %d)\n",
(command & 0xe) == 0xe ? "And Verify " : "",
r->req.cmd.lba, len); if (r->req.cmd.lba > s->max_lba)
goto illegal_lba; r->sector = r->req.cmd.lba * s->cluster_size; r->sector_count = len * s->cluster_size; break; case MODE_SELECT:
DPRINTF("Mode Select(6) (len %lu)\n", (long)r->req.cmd.xfer); if (r->req.cmd.xfer > 12) { goto fail; } break; case MODE_SELECT_10:
DPRINTF("Mode Select(10) (len %lu)\n", (long)r->req.cmd.xfer); if (r->req.cmd.xfer > 16) { goto fail; } break; case SEEK_6:
case SEEK_10:
DPRINTF("Seek(%d) (sector %" PRId64 ")\n", command == SEEK_6 ? 6 : 10,
r->req.cmd.lba); if (r->req.cmd.lba > s->max_lba) { goto illegal_lba; } break; case WRITE_SAME_16:
len = r->req.cmd.xfer / s->qdev.blocksize; DPRINTF("WRITE SAME(16) (sector %" PRId64 ", count %d)\n",
r->req.cmd.lba, len); if (r->req.cmd.lba > s->max_lba) { goto illegal_lba; } if (!(buf[1] & 0x8)) { goto fail; } VAR_0 = bdrv_discard(s->bs, r->req.cmd.lba * s->cluster_size,
len * s->cluster_size); if (VAR_0 < 0) { goto fail; } break; default:
DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]); scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_OPCODE)); return 0; fail:
scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_FIELD)); return 0; illegal_lba:
scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(LBA_OUT_OF_RANGE)); return 0; } if (r->sector_count == 0 && r->iov.iov_len == 0) { scsi_command_complete(r, GOOD, SENSE_CODE(NO_SENSE)); } len = r->sector_count * 512 + r->iov.iov_len; if (r->req.cmd.mode == SCSI_XFER_TO_DEV) { return -len; } else { if (!r->sector_count)
r->sector_count = -1; return len; } }