/* Helper function for command completion. */ static void scsi_command_complete_noio(SCSIGenericReq *r, int ret) { int status; SCSISense sense; assert(r->req.aiocb == NULL); if (r->req.io_canceled) { scsi_req_cancel_complete(&r->req); goto done; } status = sg_io_sense_from_errno(-ret, &r->io_header, &sense); if (status == CHECK_CONDITION) { if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) { r->req.sense_len = r->io_header.sb_len_wr; } else { scsi_req_build_sense(&r->req, sense); } } DPRINTF("Command complete 0x%p tag=0x%x status=%d\n", r, r->req.tag, status); scsi_req_complete(&r->req, status); done: scsi_req_unref(&r->req); }
static int32_t scsi_unit_attention(SCSIRequest *req, uint8_t *buf) { if (req->dev && req->dev->unit_attention.key == UNIT_ATTENTION) { scsi_req_build_sense(req, req->dev->unit_attention); } else if (req->bus->unit_attention.key == UNIT_ATTENTION) { scsi_req_build_sense(req, req->bus->unit_attention); } scsi_req_complete(req, CHECK_CONDITION); return 0; }
/* Helper function for command completion. */ static void scsi_command_complete(void *opaque, int ret) { int status; SCSIGenericReq *r = (SCSIGenericReq *)opaque; r->req.aiocb = NULL; if (r->req.io_canceled) { scsi_req_cancel_complete(&r->req); goto done; } if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) { r->req.sense_len = r->io_header.sb_len_wr; } if (ret != 0) { switch (ret) { case -EDOM: status = TASK_SET_FULL; break; case -ENOMEM: status = CHECK_CONDITION; scsi_req_build_sense(&r->req, SENSE_CODE(TARGET_FAILURE)); break; default: status = CHECK_CONDITION; scsi_req_build_sense(&r->req, SENSE_CODE(IO_ERROR)); break; } } else { if (r->io_header.host_status == SG_ERR_DID_NO_CONNECT || r->io_header.host_status == SG_ERR_DID_BUS_BUSY || r->io_header.host_status == SG_ERR_DID_TIME_OUT || (r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT)) { status = BUSY; BADF("Driver Timeout\n"); } else if (r->io_header.host_status) { status = CHECK_CONDITION; scsi_req_build_sense(&r->req, SENSE_CODE(I_T_NEXUS_LOSS)); } else if (r->io_header.status) { status = r->io_header.status; } else if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) { status = CHECK_CONDITION; } else { status = GOOD; } } DPRINTF("Command complete 0x%p tag=0x%x status=%d\n", r, r->req.tag, status); scsi_req_complete(&r->req, status); done: scsi_req_unref(&r->req); }
/* Helper function for command completion. */ static void scsi_command_complete(void *opaque, int ret) { SCSIGenericReq *r = (SCSIGenericReq *)opaque; SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev); r->req.aiocb = NULL; s->driver_status = r->io_header.driver_status; if (s->driver_status & SG_ERR_DRIVER_SENSE) s->senselen = r->io_header.sb_len_wr; if (ret != 0) { switch (ret) { case -EDOM: r->req.status = TASK_SET_FULL; break; case -EINVAL: r->req.status = CHECK_CONDITION; scsi_set_sense(s, SENSE_CODE(INVALID_FIELD)); break; case -ENOMEM: r->req.status = CHECK_CONDITION; scsi_set_sense(s, SENSE_CODE(TARGET_FAILURE)); break; default: r->req.status = CHECK_CONDITION; scsi_set_sense(s, SENSE_CODE(IO_ERROR)); break; } } else { if (s->driver_status & SG_ERR_DRIVER_TIMEOUT) { r->req.status = BUSY; BADF("Driver Timeout\n"); } else if (r->io_header.status) r->req.status = r->io_header.status; else if (s->driver_status & SG_ERR_DRIVER_SENSE) r->req.status = CHECK_CONDITION; else r->req.status = GOOD; } DPRINTF("Command complete 0x%p tag=0x%x status=%d\n", r, r->req.tag, r->req.status); scsi_req_complete(&r->req); }
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; } }
static int32_t scsi_invalid_command(SCSIRequest *req, uint8_t *buf) { scsi_req_build_sense(req, SENSE_CODE(INVALID_OPCODE)); scsi_req_complete(req, CHECK_CONDITION); return 0; }