scsi: introduce SCSICommand
This struct is currently unnamed. Give it a name and use it explicitly to decouple (some parts of) CDB parsing from SCSIRequest. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
parent
c39ce112b6
commit
2599aece1b
@ -217,35 +217,35 @@ static void scsi_req_dequeue(SCSIRequest *req)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int scsi_req_length(SCSIRequest *req, uint8_t *cmd)
|
static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
|
||||||
{
|
{
|
||||||
switch (cmd[0] >> 5) {
|
switch (buf[0] >> 5) {
|
||||||
case 0:
|
case 0:
|
||||||
req->cmd.xfer = cmd[4];
|
cmd->xfer = buf[4];
|
||||||
req->cmd.len = 6;
|
cmd->len = 6;
|
||||||
/* length 0 means 256 blocks */
|
/* length 0 means 256 blocks */
|
||||||
if (req->cmd.xfer == 0)
|
if (cmd->xfer == 0) {
|
||||||
req->cmd.xfer = 256;
|
cmd->xfer = 256;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
case 2:
|
case 2:
|
||||||
req->cmd.xfer = cmd[8] | (cmd[7] << 8);
|
cmd->xfer = buf[8] | (buf[7] << 8);
|
||||||
req->cmd.len = 10;
|
cmd->len = 10;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
req->cmd.xfer = cmd[13] | (cmd[12] << 8) | (cmd[11] << 16) | (cmd[10] << 24);
|
cmd->xfer = buf[13] | (buf[12] << 8) | (buf[11] << 16) | (buf[10] << 24);
|
||||||
req->cmd.len = 16;
|
cmd->len = 16;
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
req->cmd.xfer = cmd[9] | (cmd[8] << 8) | (cmd[7] << 16) | (cmd[6] << 24);
|
cmd->xfer = buf[9] | (buf[8] << 8) | (buf[7] << 16) | (buf[6] << 24);
|
||||||
req->cmd.len = 12;
|
cmd->len = 12;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
trace_scsi_req_parse_bad(req->dev->id, req->lun, req->tag, cmd[0]);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(cmd[0]) {
|
switch (buf[0]) {
|
||||||
case TEST_UNIT_READY:
|
case TEST_UNIT_READY:
|
||||||
case REWIND:
|
case REWIND:
|
||||||
case START_STOP:
|
case START_STOP:
|
||||||
@ -266,27 +266,27 @@ static int scsi_req_length(SCSIRequest *req, uint8_t *cmd)
|
|||||||
case WRITE_LONG_10:
|
case WRITE_LONG_10:
|
||||||
case MOVE_MEDIUM:
|
case MOVE_MEDIUM:
|
||||||
case UPDATE_BLOCK:
|
case UPDATE_BLOCK:
|
||||||
req->cmd.xfer = 0;
|
cmd->xfer = 0;
|
||||||
break;
|
break;
|
||||||
case MODE_SENSE:
|
case MODE_SENSE:
|
||||||
break;
|
break;
|
||||||
case WRITE_SAME_10:
|
case WRITE_SAME_10:
|
||||||
req->cmd.xfer = 1;
|
cmd->xfer = 1;
|
||||||
break;
|
break;
|
||||||
case READ_CAPACITY_10:
|
case READ_CAPACITY_10:
|
||||||
req->cmd.xfer = 8;
|
cmd->xfer = 8;
|
||||||
break;
|
break;
|
||||||
case READ_BLOCK_LIMITS:
|
case READ_BLOCK_LIMITS:
|
||||||
req->cmd.xfer = 6;
|
cmd->xfer = 6;
|
||||||
break;
|
break;
|
||||||
case READ_POSITION:
|
case READ_POSITION:
|
||||||
req->cmd.xfer = 20;
|
cmd->xfer = 20;
|
||||||
break;
|
break;
|
||||||
case SEND_VOLUME_TAG:
|
case SEND_VOLUME_TAG:
|
||||||
req->cmd.xfer *= 40;
|
cmd->xfer *= 40;
|
||||||
break;
|
break;
|
||||||
case MEDIUM_SCAN:
|
case MEDIUM_SCAN:
|
||||||
req->cmd.xfer *= 8;
|
cmd->xfer *= 8;
|
||||||
break;
|
break;
|
||||||
case WRITE_10:
|
case WRITE_10:
|
||||||
case WRITE_VERIFY_10:
|
case WRITE_VERIFY_10:
|
||||||
@ -295,7 +295,7 @@ static int scsi_req_length(SCSIRequest *req, uint8_t *cmd)
|
|||||||
case WRITE_VERIFY_12:
|
case WRITE_VERIFY_12:
|
||||||
case WRITE_16:
|
case WRITE_16:
|
||||||
case WRITE_VERIFY_16:
|
case WRITE_VERIFY_16:
|
||||||
req->cmd.xfer *= req->dev->blocksize;
|
cmd->xfer *= dev->blocksize;
|
||||||
break;
|
break;
|
||||||
case READ_10:
|
case READ_10:
|
||||||
case READ_6:
|
case READ_6:
|
||||||
@ -303,50 +303,51 @@ static int scsi_req_length(SCSIRequest *req, uint8_t *cmd)
|
|||||||
case RECOVER_BUFFERED_DATA:
|
case RECOVER_BUFFERED_DATA:
|
||||||
case READ_12:
|
case READ_12:
|
||||||
case READ_16:
|
case READ_16:
|
||||||
req->cmd.xfer *= req->dev->blocksize;
|
cmd->xfer *= dev->blocksize;
|
||||||
break;
|
break;
|
||||||
case INQUIRY:
|
case INQUIRY:
|
||||||
req->cmd.xfer = cmd[4] | (cmd[3] << 8);
|
cmd->xfer = buf[4] | (buf[3] << 8);
|
||||||
break;
|
break;
|
||||||
case MAINTENANCE_OUT:
|
case MAINTENANCE_OUT:
|
||||||
case MAINTENANCE_IN:
|
case MAINTENANCE_IN:
|
||||||
if (req->dev->type == TYPE_ROM) {
|
if (dev->type == TYPE_ROM) {
|
||||||
/* GPCMD_REPORT_KEY and GPCMD_SEND_KEY from multi media commands */
|
/* GPCMD_REPORT_KEY and GPCMD_SEND_KEY from multi media commands */
|
||||||
req->cmd.xfer = cmd[9] | (cmd[8] << 8);
|
cmd->xfer = buf[9] | (buf[8] << 8);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int scsi_req_stream_length(SCSIRequest *req, uint8_t *cmd)
|
static int scsi_req_stream_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
|
||||||
{
|
{
|
||||||
switch(cmd[0]) {
|
switch (buf[0]) {
|
||||||
/* stream commands */
|
/* stream commands */
|
||||||
case READ_6:
|
case READ_6:
|
||||||
case READ_REVERSE:
|
case READ_REVERSE:
|
||||||
case RECOVER_BUFFERED_DATA:
|
case RECOVER_BUFFERED_DATA:
|
||||||
case WRITE_6:
|
case WRITE_6:
|
||||||
req->cmd.len = 6;
|
cmd->len = 6;
|
||||||
req->cmd.xfer = cmd[4] | (cmd[3] << 8) | (cmd[2] << 16);
|
cmd->xfer = buf[4] | (buf[3] << 8) | (buf[2] << 16);
|
||||||
if (cmd[1] & 0x01) /* fixed */
|
if (buf[1] & 0x01) { /* fixed */
|
||||||
req->cmd.xfer *= req->dev->blocksize;
|
cmd->xfer *= dev->blocksize;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case REWIND:
|
case REWIND:
|
||||||
case START_STOP:
|
case START_STOP:
|
||||||
req->cmd.len = 6;
|
cmd->len = 6;
|
||||||
req->cmd.xfer = 0;
|
cmd->xfer = 0;
|
||||||
break;
|
break;
|
||||||
/* generic commands */
|
/* generic commands */
|
||||||
default:
|
default:
|
||||||
return scsi_req_length(req, cmd);
|
return scsi_req_length(cmd, dev, buf);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void scsi_req_xfer_mode(SCSIRequest *req)
|
static void scsi_cmd_xfer_mode(SCSICommand *cmd)
|
||||||
{
|
{
|
||||||
switch (req->cmd.buf[0]) {
|
switch (cmd->buf[0]) {
|
||||||
case WRITE_6:
|
case WRITE_6:
|
||||||
case WRITE_10:
|
case WRITE_10:
|
||||||
case WRITE_VERIFY_10:
|
case WRITE_VERIFY_10:
|
||||||
@ -378,21 +379,21 @@ static void scsi_req_xfer_mode(SCSIRequest *req)
|
|||||||
case SEND_VOLUME_TAG:
|
case SEND_VOLUME_TAG:
|
||||||
case PERSISTENT_RESERVE_OUT:
|
case PERSISTENT_RESERVE_OUT:
|
||||||
case MAINTENANCE_OUT:
|
case MAINTENANCE_OUT:
|
||||||
req->cmd.mode = SCSI_XFER_TO_DEV;
|
cmd->mode = SCSI_XFER_TO_DEV;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (req->cmd.xfer)
|
if (cmd->xfer)
|
||||||
req->cmd.mode = SCSI_XFER_FROM_DEV;
|
cmd->mode = SCSI_XFER_FROM_DEV;
|
||||||
else {
|
else {
|
||||||
req->cmd.mode = SCSI_XFER_NONE;
|
cmd->mode = SCSI_XFER_NONE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t scsi_req_lba(SCSIRequest *req)
|
static uint64_t scsi_cmd_lba(SCSICommand *cmd)
|
||||||
{
|
{
|
||||||
uint8_t *buf = req->cmd.buf;
|
uint8_t *buf = cmd->buf;
|
||||||
uint64_t lba;
|
uint64_t lba;
|
||||||
|
|
||||||
switch (buf[0] >> 5) {
|
switch (buf[0] >> 5) {
|
||||||
@ -427,16 +428,16 @@ int scsi_req_parse(SCSIRequest *req, uint8_t *buf)
|
|||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (req->dev->type == TYPE_TAPE) {
|
if (req->dev->type == TYPE_TAPE) {
|
||||||
rc = scsi_req_stream_length(req, buf);
|
rc = scsi_req_stream_length(&req->cmd, req->dev, buf);
|
||||||
} else {
|
} else {
|
||||||
rc = scsi_req_length(req, buf);
|
rc = scsi_req_length(&req->cmd, req->dev, buf);
|
||||||
}
|
}
|
||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
assert(buf == req->cmd.buf);
|
assert(buf == req->cmd.buf);
|
||||||
scsi_req_xfer_mode(req);
|
scsi_cmd_xfer_mode(&req->cmd);
|
||||||
req->cmd.lba = scsi_req_lba(req);
|
req->cmd.lba = scsi_cmd_lba(&req->cmd);
|
||||||
trace_scsi_req_parsed(req->dev->id, req->lun, req->tag, buf[0],
|
trace_scsi_req_parsed(req->dev->id, req->lun, req->tag, buf[0],
|
||||||
req->cmd.mode, req->cmd.xfer);
|
req->cmd.mode, req->cmd.xfer);
|
||||||
if (req->cmd.lba != -1) {
|
if (req->cmd.lba != -1) {
|
||||||
|
17
hw/scsi.h
17
hw/scsi.h
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
typedef struct SCSIBus SCSIBus;
|
typedef struct SCSIBus SCSIBus;
|
||||||
typedef struct SCSIBusOps SCSIBusOps;
|
typedef struct SCSIBusOps SCSIBusOps;
|
||||||
|
typedef struct SCSICommand SCSICommand;
|
||||||
typedef struct SCSIDevice SCSIDevice;
|
typedef struct SCSIDevice SCSIDevice;
|
||||||
typedef struct SCSIDeviceInfo SCSIDeviceInfo;
|
typedef struct SCSIDeviceInfo SCSIDeviceInfo;
|
||||||
typedef struct SCSIRequest SCSIRequest;
|
typedef struct SCSIRequest SCSIRequest;
|
||||||
@ -30,6 +31,14 @@ typedef struct SCSISense {
|
|||||||
|
|
||||||
#define SCSI_SENSE_BUF_SIZE 96
|
#define SCSI_SENSE_BUF_SIZE 96
|
||||||
|
|
||||||
|
struct SCSICommand {
|
||||||
|
uint8_t buf[SCSI_CMD_BUF_SIZE];
|
||||||
|
int len;
|
||||||
|
size_t xfer;
|
||||||
|
uint64_t lba;
|
||||||
|
enum SCSIXferMode mode;
|
||||||
|
};
|
||||||
|
|
||||||
struct SCSIRequest {
|
struct SCSIRequest {
|
||||||
SCSIBus *bus;
|
SCSIBus *bus;
|
||||||
SCSIDevice *dev;
|
SCSIDevice *dev;
|
||||||
@ -38,13 +47,7 @@ struct SCSIRequest {
|
|||||||
uint32_t tag;
|
uint32_t tag;
|
||||||
uint32_t lun;
|
uint32_t lun;
|
||||||
uint32_t status;
|
uint32_t status;
|
||||||
struct {
|
SCSICommand cmd;
|
||||||
uint8_t buf[SCSI_CMD_BUF_SIZE];
|
|
||||||
int len;
|
|
||||||
size_t xfer;
|
|
||||||
uint64_t lba;
|
|
||||||
enum SCSIXferMode mode;
|
|
||||||
} cmd;
|
|
||||||
BlockDriverAIOCB *aiocb;
|
BlockDriverAIOCB *aiocb;
|
||||||
uint8_t sense[SCSI_SENSE_BUF_SIZE];
|
uint8_t sense[SCSI_SENSE_BUF_SIZE];
|
||||||
uint32_t sense_len;
|
uint32_t sense_len;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user