static void scsi_read_complete(void * opaque, int ret) { SCSIGenericReq *r = (SCSIGenericReq *)opaque; SCSIDevice *s = r->req.dev; int len; r->req.aiocb = NULL; if (ret || r->req.io_canceled) { scsi_command_complete(r, ret); return; } len = r->io_header.dxfer_len - r->io_header.resid; DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, len); r->len = -1; if (len == 0) { scsi_command_complete(r, 0); } else { /* Snoop READ CAPACITY output to set the blocksize. */ if (r->req.cmd.buf[0] == READ_CAPACITY_10 && (ldl_be_p(&r->buf[0]) != 0xffffffffU || s->max_lba == 0)) { s->blocksize = ldl_be_p(&r->buf[4]); s->max_lba = ldl_be_p(&r->buf[0]) & 0xffffffffULL; } else if (r->req.cmd.buf[0] == SERVICE_ACTION_IN_16 && (r->req.cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) { s->blocksize = ldl_be_p(&r->buf[8]); s->max_lba = ldq_be_p(&r->buf[0]); } blk_set_guest_block_size(s->conf.blk, s->blocksize); scsi_req_data(&r->req, len); scsi_req_unref(&r->req); } }
static void scsi_write_complete(void * opaque, int ret) { SCSIGenericReq *r = (SCSIGenericReq *)opaque; SCSIDevice *s = r->req.dev; DPRINTF("scsi_write_complete() ret = %d\n", ret); r->req.aiocb = NULL; if (ret || r->req.io_canceled) { scsi_command_complete(r, ret); return; } if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 && s->type == TYPE_TAPE) { s->blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11]; DPRINTF("block size %d\n", s->blocksize); } scsi_command_complete(r, ret); }
/* Read more data from scsi device into buffer. */ static void scsi_read_data(SCSIRequest *req) { SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); SCSIDevice *s = r->req.dev; int ret; DPRINTF("scsi_read_data 0x%x\n", req->tag); /* The request is used as the AIO opaque value, so add a ref. */ scsi_req_ref(&r->req); if (r->len == -1) { scsi_command_complete(r, 0); return; } ret = execute_command(s->conf.bs, r, SG_DXFER_FROM_DEV, scsi_read_complete); if (ret < 0) { scsi_command_complete(r, ret); } }
static void scsi_write_complete(void * opaque, int ret) { SCSIGenericReq *r = (SCSIGenericReq *)opaque; SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev); DPRINTF("scsi_write_complete() ret = %d\n", ret); r->req.aiocb = NULL; if (ret) { DPRINTF("IO error\n"); scsi_command_complete(r, ret); return; } if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 && s->qdev.type == TYPE_TAPE) { s->qdev.blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11]; DPRINTF("block size %d\n", s->qdev.blocksize); } scsi_command_complete(r, ret); }
static void scsi_read_complete(void * opaque, int ret) { SCSIGenericReq *r = (SCSIGenericReq *)opaque; int len; r->req.aiocb = NULL; if (ret) { DPRINTF("IO error ret %d\n", ret); scsi_command_complete(r, ret); return; } len = r->io_header.dxfer_len - r->io_header.resid; DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, len); r->len = -1; if (len == 0) { scsi_command_complete(r, 0); } else { scsi_req_data(&r->req, len); } }
static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd) { SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); SCSIDevice *s = r->req.dev; int ret; DPRINTF("Command: lun=%d tag=0x%x len %zd data=0x%02x", lun, tag, r->req.cmd.xfer, cmd[0]); #ifdef DEBUG_SCSI { int i; for (i = 1; i < r->req.cmd.len; i++) { printf(" 0x%02x", cmd[i]); } printf("\n"); } #endif if (r->req.cmd.xfer == 0) { if (r->buf != NULL) g_free(r->buf); r->buflen = 0; r->buf = NULL; /* The request is used as the AIO opaque value, so add a ref. */ scsi_req_ref(&r->req); ret = execute_command(s->conf.bs, r, SG_DXFER_NONE, scsi_command_complete); if (ret < 0) { scsi_command_complete(r, ret); return 0; } return 0; } if (r->buflen != r->req.cmd.xfer) { if (r->buf != NULL) g_free(r->buf); r->buf = g_malloc(r->req.cmd.xfer); r->buflen = r->req.cmd.xfer; } memset(r->buf, 0, r->buflen); r->len = r->req.cmd.xfer; if (r->req.cmd.mode == SCSI_XFER_TO_DEV) { r->len = 0; return -r->req.cmd.xfer; } else { return r->req.cmd.xfer; } }
/* Read more data from scsi device into buffer. */ static void scsi_read_data(SCSIRequest *req) { SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev); int ret; DPRINTF("scsi_read_data 0x%x\n", req->tag); if (r->len == -1) { scsi_command_complete(r, 0); return; } if (r->req.cmd.buf[0] == REQUEST_SENSE && s->driver_status & SG_ERR_DRIVER_SENSE) { s->senselen = MIN(r->len, s->senselen); memcpy(r->buf, s->sensebuf, s->senselen); r->io_header.driver_status = 0; r->io_header.status = 0; r->io_header.dxfer_len = s->senselen; r->len = -1; DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, s->senselen); DPRINTF("Sense: %d %d %d %d %d %d %d %d\n", r->buf[0], r->buf[1], r->buf[2], r->buf[3], r->buf[4], r->buf[5], r->buf[6], r->buf[7]); scsi_req_data(&r->req, s->senselen); /* Clear sensebuf after REQUEST_SENSE */ scsi_clear_sense(s); return; } ret = execute_command(s->bs, r, SG_DXFER_FROM_DEV, scsi_read_complete); if (ret < 0) { scsi_command_complete(r, ret); return; } }
/* Write data to a scsi device. Returns nonzero on failure. The transfer may complete asynchronously. */ static void scsi_write_data(SCSIRequest *req) { SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, req->dev); SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); int ret; DPRINTF("scsi_write_data 0x%x\n", req->tag); if (r->len == 0) { r->len = r->buflen; scsi_req_data(&r->req, r->len); return; } ret = execute_command(s->bs, r, SG_DXFER_TO_DEV, scsi_write_complete); if (ret < 0) { scsi_command_complete(r, ret); } }
static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd) { SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, req->dev); SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); int ret; if (cmd[0] != REQUEST_SENSE && req->lun != s->lun) { DPRINTF("Unimplemented LUN %d\n", req->lun); scsi_set_sense(s, SENSE_CODE(LUN_NOT_SUPPORTED)); r->req.status = CHECK_CONDITION; scsi_req_complete(&r->req); return 0; } if (-1 == scsi_req_parse(&r->req, cmd)) { BADF("Unsupported command length, command %x\n", cmd[0]); scsi_command_complete(r, -EINVAL); return 0; } scsi_req_fixup(&r->req); DPRINTF("Command: lun=%d tag=0x%x len %zd data=0x%02x", lun, tag, r->req.cmd.xfer, cmd[0]); #ifdef DEBUG_SCSI { int i; for (i = 1; i < r->req.cmd.len; i++) { printf(" 0x%02x", cmd[i]); } printf("\n"); } #endif if (r->req.cmd.xfer == 0) { if (r->buf != NULL) qemu_free(r->buf); r->buflen = 0; r->buf = NULL; ret = execute_command(s->bs, r, SG_DXFER_NONE, scsi_command_complete); if (ret < 0) { scsi_command_complete(r, ret); return 0; } return 0; } if (r->buflen != r->req.cmd.xfer) { if (r->buf != NULL) qemu_free(r->buf); r->buf = qemu_malloc(r->req.cmd.xfer); r->buflen = r->req.cmd.xfer; } memset(r->buf, 0, r->buflen); r->len = r->req.cmd.xfer; if (r->req.cmd.mode == SCSI_XFER_TO_DEV) { r->len = 0; return -r->req.cmd.xfer; } else { return r->req.cmd.xfer; } }