Merge remote-tracking branch 'kwolf/block-stable' into staging
This commit is contained in:
commit
54dcd0b37e
@ -695,12 +695,7 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
|
|||||||
int action, code;
|
int action, code;
|
||||||
int max_len;
|
int max_len;
|
||||||
|
|
||||||
if (buf[0] == GPCMD_MODE_SENSE_10) {
|
max_len = ube16_to_cpu(buf + 7);
|
||||||
max_len = ube16_to_cpu(buf + 7);
|
|
||||||
} else {
|
|
||||||
max_len = buf[4];
|
|
||||||
}
|
|
||||||
|
|
||||||
action = buf[2] >> 6;
|
action = buf[2] >> 6;
|
||||||
code = buf[2] & 0x3f;
|
code = buf[2] & 0x3f;
|
||||||
|
|
||||||
@ -708,7 +703,7 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
|
|||||||
case 0: /* current values */
|
case 0: /* current values */
|
||||||
switch(code) {
|
switch(code) {
|
||||||
case MODE_PAGE_R_W_ERROR: /* error recovery */
|
case MODE_PAGE_R_W_ERROR: /* error recovery */
|
||||||
cpu_to_ube16(&buf[0], 16 + 6);
|
cpu_to_ube16(&buf[0], 16 - 2);
|
||||||
buf[2] = 0x70;
|
buf[2] = 0x70;
|
||||||
buf[3] = 0;
|
buf[3] = 0;
|
||||||
buf[4] = 0;
|
buf[4] = 0;
|
||||||
@ -727,7 +722,7 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
|
|||||||
ide_atapi_cmd_reply(s, 16, max_len);
|
ide_atapi_cmd_reply(s, 16, max_len);
|
||||||
break;
|
break;
|
||||||
case MODE_PAGE_AUDIO_CTL:
|
case MODE_PAGE_AUDIO_CTL:
|
||||||
cpu_to_ube16(&buf[0], 24 + 6);
|
cpu_to_ube16(&buf[0], 24 - 2);
|
||||||
buf[2] = 0x70;
|
buf[2] = 0x70;
|
||||||
buf[3] = 0;
|
buf[3] = 0;
|
||||||
buf[4] = 0;
|
buf[4] = 0;
|
||||||
@ -746,7 +741,7 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
|
|||||||
ide_atapi_cmd_reply(s, 24, max_len);
|
ide_atapi_cmd_reply(s, 24, max_len);
|
||||||
break;
|
break;
|
||||||
case MODE_PAGE_CAPABILITIES:
|
case MODE_PAGE_CAPABILITIES:
|
||||||
cpu_to_ube16(&buf[0], 28 + 6);
|
cpu_to_ube16(&buf[0], 30 - 2);
|
||||||
buf[2] = 0x70;
|
buf[2] = 0x70;
|
||||||
buf[3] = 0;
|
buf[3] = 0;
|
||||||
buf[4] = 0;
|
buf[4] = 0;
|
||||||
@ -755,7 +750,7 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
|
|||||||
buf[7] = 0;
|
buf[7] = 0;
|
||||||
|
|
||||||
buf[8] = MODE_PAGE_CAPABILITIES;
|
buf[8] = MODE_PAGE_CAPABILITIES;
|
||||||
buf[9] = 28 - 10;
|
buf[9] = 30 - 10;
|
||||||
buf[10] = 0x3b; /* read CDR/CDRW/DVDROM/DVDR/DVDRAM */
|
buf[10] = 0x3b; /* read CDR/CDRW/DVDROM/DVDR/DVDRAM */
|
||||||
buf[11] = 0x00;
|
buf[11] = 0x00;
|
||||||
|
|
||||||
@ -777,7 +772,9 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
|
|||||||
buf[25] = 0;
|
buf[25] = 0;
|
||||||
buf[26] = 0;
|
buf[26] = 0;
|
||||||
buf[27] = 0;
|
buf[27] = 0;
|
||||||
ide_atapi_cmd_reply(s, 28, max_len);
|
buf[28] = 0;
|
||||||
|
buf[29] = 0;
|
||||||
|
ide_atapi_cmd_reply(s, 30, max_len);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
goto error_cmd;
|
goto error_cmd;
|
||||||
@ -1043,7 +1040,6 @@ static const struct {
|
|||||||
[ 0x00 ] = { cmd_test_unit_ready, CHECK_READY },
|
[ 0x00 ] = { cmd_test_unit_ready, CHECK_READY },
|
||||||
[ 0x03 ] = { cmd_request_sense, ALLOW_UA },
|
[ 0x03 ] = { cmd_request_sense, ALLOW_UA },
|
||||||
[ 0x12 ] = { cmd_inquiry, ALLOW_UA },
|
[ 0x12 ] = { cmd_inquiry, ALLOW_UA },
|
||||||
[ 0x1a ] = { cmd_mode_sense, /* (6) */ 0 },
|
|
||||||
[ 0x1b ] = { cmd_start_stop_unit, 0 }, /* [1] */
|
[ 0x1b ] = { cmd_start_stop_unit, 0 }, /* [1] */
|
||||||
[ 0x1e ] = { cmd_prevent_allow_medium_removal, 0 },
|
[ 0x1e ] = { cmd_prevent_allow_medium_removal, 0 },
|
||||||
[ 0x25 ] = { cmd_read_cdvd_capacity, CHECK_READY },
|
[ 0x25 ] = { cmd_read_cdvd_capacity, CHECK_READY },
|
||||||
|
128
hw/scsi-bus.c
128
hw/scsi-bus.c
@ -9,8 +9,6 @@
|
|||||||
static char *scsibus_get_fw_dev_path(DeviceState *dev);
|
static char *scsibus_get_fw_dev_path(DeviceState *dev);
|
||||||
static int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf);
|
static int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf);
|
||||||
static void scsi_req_dequeue(SCSIRequest *req);
|
static void scsi_req_dequeue(SCSIRequest *req);
|
||||||
static int scsi_build_sense(uint8_t *in_buf, int in_len,
|
|
||||||
uint8_t *buf, int len, bool fixed);
|
|
||||||
|
|
||||||
static struct BusInfo scsi_bus_info = {
|
static struct BusInfo scsi_bus_info = {
|
||||||
.name = "SCSI",
|
.name = "SCSI",
|
||||||
@ -502,7 +500,7 @@ SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
|
|||||||
hba_private);
|
hba_private);
|
||||||
} else if (lun != d->lun ||
|
} else if (lun != d->lun ||
|
||||||
buf[0] == REPORT_LUNS ||
|
buf[0] == REPORT_LUNS ||
|
||||||
buf[0] == REQUEST_SENSE) {
|
(buf[0] == REQUEST_SENSE && (d->sense_len || cmd.xfer < 4))) {
|
||||||
req = scsi_req_alloc(&reqops_target_command, d, tag, lun,
|
req = scsi_req_alloc(&reqops_target_command, d, tag, lun,
|
||||||
hba_private);
|
hba_private);
|
||||||
} else {
|
} else {
|
||||||
@ -649,6 +647,31 @@ static void scsi_req_dequeue(SCSIRequest *req)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int scsi_get_performance_length(int num_desc, int type, int data_type)
|
||||||
|
{
|
||||||
|
/* MMC-6, paragraph 6.7. */
|
||||||
|
switch (type) {
|
||||||
|
case 0:
|
||||||
|
if ((data_type & 3) == 0) {
|
||||||
|
/* Each descriptor is as in Table 295 - Nominal performance. */
|
||||||
|
return 16 * num_desc + 8;
|
||||||
|
} else {
|
||||||
|
/* Each descriptor is as in Table 296 - Exceptions. */
|
||||||
|
return 6 * num_desc + 8;
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
case 4:
|
||||||
|
case 5:
|
||||||
|
return 8 * num_desc + 8;
|
||||||
|
case 2:
|
||||||
|
return 2048 * num_desc + 8;
|
||||||
|
case 3:
|
||||||
|
return 16 * num_desc + 8;
|
||||||
|
default:
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
|
static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
|
||||||
{
|
{
|
||||||
switch (buf[0] >> 5) {
|
switch (buf[0] >> 5) {
|
||||||
@ -666,11 +689,11 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
|
|||||||
cmd->len = 10;
|
cmd->len = 10;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
cmd->xfer = ldl_be_p(&buf[10]);
|
cmd->xfer = ldl_be_p(&buf[10]) & 0xffffffffULL;
|
||||||
cmd->len = 16;
|
cmd->len = 16;
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
cmd->xfer = ldl_be_p(&buf[6]);
|
cmd->xfer = ldl_be_p(&buf[6]) & 0xffffffffULL;
|
||||||
cmd->len = 12;
|
cmd->len = 12;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -681,8 +704,9 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
|
|||||||
case TEST_UNIT_READY:
|
case TEST_UNIT_READY:
|
||||||
case REWIND:
|
case REWIND:
|
||||||
case START_STOP:
|
case START_STOP:
|
||||||
case SEEK_6:
|
case SET_CAPACITY:
|
||||||
case WRITE_FILEMARKS:
|
case WRITE_FILEMARKS:
|
||||||
|
case WRITE_FILEMARKS_16:
|
||||||
case SPACE:
|
case SPACE:
|
||||||
case RESERVE:
|
case RESERVE:
|
||||||
case RELEASE:
|
case RELEASE:
|
||||||
@ -691,6 +715,8 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
|
|||||||
case VERIFY_10:
|
case VERIFY_10:
|
||||||
case SEEK_10:
|
case SEEK_10:
|
||||||
case SYNCHRONIZE_CACHE:
|
case SYNCHRONIZE_CACHE:
|
||||||
|
case SYNCHRONIZE_CACHE_16:
|
||||||
|
case LOCATE_16:
|
||||||
case LOCK_UNLOCK_CACHE:
|
case LOCK_UNLOCK_CACHE:
|
||||||
case LOAD_UNLOAD:
|
case LOAD_UNLOAD:
|
||||||
case SET_CD_SPEED:
|
case SET_CD_SPEED:
|
||||||
@ -698,6 +724,11 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
|
|||||||
case WRITE_LONG_10:
|
case WRITE_LONG_10:
|
||||||
case MOVE_MEDIUM:
|
case MOVE_MEDIUM:
|
||||||
case UPDATE_BLOCK:
|
case UPDATE_BLOCK:
|
||||||
|
case RESERVE_TRACK:
|
||||||
|
case SET_READ_AHEAD:
|
||||||
|
case PRE_FETCH:
|
||||||
|
case PRE_FETCH_16:
|
||||||
|
case ALLOW_OVERWRITE:
|
||||||
cmd->xfer = 0;
|
cmd->xfer = 0;
|
||||||
break;
|
break;
|
||||||
case MODE_SENSE:
|
case MODE_SENSE:
|
||||||
@ -711,14 +742,13 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
|
|||||||
case READ_BLOCK_LIMITS:
|
case READ_BLOCK_LIMITS:
|
||||||
cmd->xfer = 6;
|
cmd->xfer = 6;
|
||||||
break;
|
break;
|
||||||
case READ_POSITION:
|
|
||||||
cmd->xfer = 20;
|
|
||||||
break;
|
|
||||||
case SEND_VOLUME_TAG:
|
case SEND_VOLUME_TAG:
|
||||||
cmd->xfer *= 40;
|
/* GPCMD_SET_STREAMING from multimedia commands. */
|
||||||
break;
|
if (dev->type == TYPE_ROM) {
|
||||||
case MEDIUM_SCAN:
|
cmd->xfer = buf[10] | (buf[9] << 8);
|
||||||
cmd->xfer *= 8;
|
} else {
|
||||||
|
cmd->xfer = buf[9] | (buf[8] << 8);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case WRITE_10:
|
case WRITE_10:
|
||||||
case WRITE_VERIFY_10:
|
case WRITE_VERIFY_10:
|
||||||
@ -737,9 +767,39 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
|
|||||||
case READ_16:
|
case READ_16:
|
||||||
cmd->xfer *= dev->blocksize;
|
cmd->xfer *= dev->blocksize;
|
||||||
break;
|
break;
|
||||||
|
case FORMAT_UNIT:
|
||||||
|
/* MMC mandates the parameter list to be 12-bytes long. Parameters
|
||||||
|
* for block devices are restricted to the header right now. */
|
||||||
|
if (dev->type == TYPE_ROM && (buf[1] & 16)) {
|
||||||
|
cmd->xfer = 12;
|
||||||
|
} else {
|
||||||
|
cmd->xfer = (buf[1] & 16) == 0 ? 0 : (buf[1] & 32 ? 8 : 4);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case INQUIRY:
|
case INQUIRY:
|
||||||
|
case RECEIVE_DIAGNOSTIC:
|
||||||
|
case SEND_DIAGNOSTIC:
|
||||||
cmd->xfer = buf[4] | (buf[3] << 8);
|
cmd->xfer = buf[4] | (buf[3] << 8);
|
||||||
break;
|
break;
|
||||||
|
case READ_CD:
|
||||||
|
case READ_BUFFER:
|
||||||
|
case WRITE_BUFFER:
|
||||||
|
case SEND_CUE_SHEET:
|
||||||
|
cmd->xfer = buf[8] | (buf[7] << 8) | (buf[6] << 16);
|
||||||
|
break;
|
||||||
|
case PERSISTENT_RESERVE_OUT:
|
||||||
|
cmd->xfer = ldl_be_p(&buf[5]) & 0xffffffffULL;
|
||||||
|
break;
|
||||||
|
case ERASE_12:
|
||||||
|
if (dev->type == TYPE_ROM) {
|
||||||
|
/* MMC command GET PERFORMANCE. */
|
||||||
|
cmd->xfer = scsi_get_performance_length(buf[9] | (buf[8] << 8),
|
||||||
|
buf[10], buf[1] & 0x1f);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MECHANISM_STATUS:
|
||||||
|
case READ_DVD_STRUCTURE:
|
||||||
|
case SEND_DVD_STRUCTURE:
|
||||||
case MAINTENANCE_OUT:
|
case MAINTENANCE_OUT:
|
||||||
case MAINTENANCE_IN:
|
case MAINTENANCE_IN:
|
||||||
if (dev->type == TYPE_ROM) {
|
if (dev->type == TYPE_ROM) {
|
||||||
@ -755,6 +815,10 @@ static int scsi_req_stream_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *bu
|
|||||||
{
|
{
|
||||||
switch (buf[0]) {
|
switch (buf[0]) {
|
||||||
/* stream commands */
|
/* stream commands */
|
||||||
|
case ERASE_12:
|
||||||
|
case ERASE_16:
|
||||||
|
cmd->xfer = 0;
|
||||||
|
break;
|
||||||
case READ_6:
|
case READ_6:
|
||||||
case READ_REVERSE:
|
case READ_REVERSE:
|
||||||
case RECOVER_BUFFERED_DATA:
|
case RECOVER_BUFFERED_DATA:
|
||||||
@ -770,6 +834,15 @@ static int scsi_req_stream_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *bu
|
|||||||
cmd->len = 6;
|
cmd->len = 6;
|
||||||
cmd->xfer = 0;
|
cmd->xfer = 0;
|
||||||
break;
|
break;
|
||||||
|
case SPACE_16:
|
||||||
|
cmd->xfer = buf[13] | (buf[12] << 8);
|
||||||
|
break;
|
||||||
|
case READ_POSITION:
|
||||||
|
cmd->xfer = buf[8] | (buf[7] << 8);
|
||||||
|
break;
|
||||||
|
case FORMAT_UNIT:
|
||||||
|
cmd->xfer = buf[4] | (buf[3] << 8);
|
||||||
|
break;
|
||||||
/* generic commands */
|
/* generic commands */
|
||||||
default:
|
default:
|
||||||
return scsi_req_length(cmd, dev, buf);
|
return scsi_req_length(cmd, dev, buf);
|
||||||
@ -809,6 +882,8 @@ static void scsi_cmd_xfer_mode(SCSICommand *cmd)
|
|||||||
case SEARCH_LOW_12:
|
case SEARCH_LOW_12:
|
||||||
case MEDIUM_SCAN:
|
case MEDIUM_SCAN:
|
||||||
case SEND_VOLUME_TAG:
|
case SEND_VOLUME_TAG:
|
||||||
|
case SEND_CUE_SHEET:
|
||||||
|
case SEND_DVD_STRUCTURE:
|
||||||
case PERSISTENT_RESERVE_OUT:
|
case PERSISTENT_RESERVE_OUT:
|
||||||
case MAINTENANCE_OUT:
|
case MAINTENANCE_OUT:
|
||||||
cmd->mode = SCSI_XFER_TO_DEV;
|
cmd->mode = SCSI_XFER_TO_DEV;
|
||||||
@ -835,7 +910,7 @@ static uint64_t scsi_cmd_lba(SCSICommand *cmd)
|
|||||||
case 1:
|
case 1:
|
||||||
case 2:
|
case 2:
|
||||||
case 5:
|
case 5:
|
||||||
lba = ldl_be_p(&buf[2]);
|
lba = ldl_be_p(&buf[2]) & 0xffffffffULL;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
lba = ldq_be_p(&buf[2]);
|
lba = ldq_be_p(&buf[2]);
|
||||||
@ -1036,7 +1111,7 @@ static const char *scsi_command_name(uint8_t cmd)
|
|||||||
[ REASSIGN_BLOCKS ] = "REASSIGN_BLOCKS",
|
[ REASSIGN_BLOCKS ] = "REASSIGN_BLOCKS",
|
||||||
[ READ_6 ] = "READ_6",
|
[ READ_6 ] = "READ_6",
|
||||||
[ WRITE_6 ] = "WRITE_6",
|
[ WRITE_6 ] = "WRITE_6",
|
||||||
[ SEEK_6 ] = "SEEK_6",
|
[ SET_CAPACITY ] = "SET_CAPACITY",
|
||||||
[ READ_REVERSE ] = "READ_REVERSE",
|
[ READ_REVERSE ] = "READ_REVERSE",
|
||||||
[ WRITE_FILEMARKS ] = "WRITE_FILEMARKS",
|
[ WRITE_FILEMARKS ] = "WRITE_FILEMARKS",
|
||||||
[ SPACE ] = "SPACE",
|
[ SPACE ] = "SPACE",
|
||||||
@ -1064,7 +1139,7 @@ static const char *scsi_command_name(uint8_t cmd)
|
|||||||
[ SEARCH_EQUAL ] = "SEARCH_EQUAL",
|
[ SEARCH_EQUAL ] = "SEARCH_EQUAL",
|
||||||
[ SEARCH_LOW ] = "SEARCH_LOW",
|
[ SEARCH_LOW ] = "SEARCH_LOW",
|
||||||
[ SET_LIMITS ] = "SET_LIMITS",
|
[ SET_LIMITS ] = "SET_LIMITS",
|
||||||
[ PRE_FETCH ] = "PRE_FETCH",
|
[ PRE_FETCH ] = "PRE_FETCH/READ_POSITION",
|
||||||
/* READ_POSITION and PRE_FETCH use the same operation code */
|
/* READ_POSITION and PRE_FETCH use the same operation code */
|
||||||
[ SYNCHRONIZE_CACHE ] = "SYNCHRONIZE_CACHE",
|
[ SYNCHRONIZE_CACHE ] = "SYNCHRONIZE_CACHE",
|
||||||
[ LOCK_UNLOCK_CACHE ] = "LOCK_UNLOCK_CACHE",
|
[ LOCK_UNLOCK_CACHE ] = "LOCK_UNLOCK_CACHE",
|
||||||
@ -1101,9 +1176,11 @@ static const char *scsi_command_name(uint8_t cmd)
|
|||||||
[ WRITE_16 ] = "WRITE_16",
|
[ WRITE_16 ] = "WRITE_16",
|
||||||
[ WRITE_VERIFY_16 ] = "WRITE_VERIFY_16",
|
[ WRITE_VERIFY_16 ] = "WRITE_VERIFY_16",
|
||||||
[ VERIFY_16 ] = "VERIFY_16",
|
[ VERIFY_16 ] = "VERIFY_16",
|
||||||
[ SYNCHRONIZE_CACHE_16 ] = "SYNCHRONIZE_CACHE_16",
|
[ PRE_FETCH_16 ] = "PRE_FETCH_16",
|
||||||
|
[ SYNCHRONIZE_CACHE_16 ] = "SPACE_16/SYNCHRONIZE_CACHE_16",
|
||||||
|
/* SPACE_16 and SYNCHRONIZE_CACHE_16 use the same operation code */
|
||||||
[ LOCATE_16 ] = "LOCATE_16",
|
[ LOCATE_16 ] = "LOCATE_16",
|
||||||
[ WRITE_SAME_16 ] = "WRITE_SAME_16",
|
[ WRITE_SAME_16 ] = "ERASE_16/WRITE_SAME_16",
|
||||||
/* ERASE_16 and WRITE_SAME_16 use the same operation code */
|
/* ERASE_16 and WRITE_SAME_16 use the same operation code */
|
||||||
[ SERVICE_ACTION_IN_16 ] = "SERVICE_ACTION_IN_16",
|
[ SERVICE_ACTION_IN_16 ] = "SERVICE_ACTION_IN_16",
|
||||||
[ WRITE_LONG_16 ] = "WRITE_LONG_16",
|
[ WRITE_LONG_16 ] = "WRITE_LONG_16",
|
||||||
@ -1113,6 +1190,8 @@ static const char *scsi_command_name(uint8_t cmd)
|
|||||||
[ LOAD_UNLOAD ] = "LOAD_UNLOAD",
|
[ LOAD_UNLOAD ] = "LOAD_UNLOAD",
|
||||||
[ READ_12 ] = "READ_12",
|
[ READ_12 ] = "READ_12",
|
||||||
[ WRITE_12 ] = "WRITE_12",
|
[ WRITE_12 ] = "WRITE_12",
|
||||||
|
[ ERASE_12 ] = "ERASE_12/GET_PERFORMANCE",
|
||||||
|
/* ERASE_12 and GET_PERFORMANCE use the same operation code */
|
||||||
[ SERVICE_ACTION_IN_12 ] = "SERVICE_ACTION_IN_12",
|
[ SERVICE_ACTION_IN_12 ] = "SERVICE_ACTION_IN_12",
|
||||||
[ WRITE_VERIFY_12 ] = "WRITE_VERIFY_12",
|
[ WRITE_VERIFY_12 ] = "WRITE_VERIFY_12",
|
||||||
[ VERIFY_12 ] = "VERIFY_12",
|
[ VERIFY_12 ] = "VERIFY_12",
|
||||||
@ -1120,9 +1199,18 @@ static const char *scsi_command_name(uint8_t cmd)
|
|||||||
[ SEARCH_EQUAL_12 ] = "SEARCH_EQUAL_12",
|
[ SEARCH_EQUAL_12 ] = "SEARCH_EQUAL_12",
|
||||||
[ SEARCH_LOW_12 ] = "SEARCH_LOW_12",
|
[ SEARCH_LOW_12 ] = "SEARCH_LOW_12",
|
||||||
[ READ_ELEMENT_STATUS ] = "READ_ELEMENT_STATUS",
|
[ READ_ELEMENT_STATUS ] = "READ_ELEMENT_STATUS",
|
||||||
[ SEND_VOLUME_TAG ] = "SEND_VOLUME_TAG",
|
[ SEND_VOLUME_TAG ] = "SEND_VOLUME_TAG/SET_STREAMING",
|
||||||
|
/* SEND_VOLUME_TAG and SET_STREAMING use the same operation code */
|
||||||
|
[ READ_CD ] = "READ_CD",
|
||||||
[ READ_DEFECT_DATA_12 ] = "READ_DEFECT_DATA_12",
|
[ READ_DEFECT_DATA_12 ] = "READ_DEFECT_DATA_12",
|
||||||
|
[ READ_DVD_STRUCTURE ] = "READ_DVD_STRUCTURE",
|
||||||
|
[ RESERVE_TRACK ] = "RESERVE_TRACK",
|
||||||
|
[ SEND_CUE_SHEET ] = "SEND_CUE_SHEET",
|
||||||
|
[ SEND_DVD_STRUCTURE ] = "SEND_DVD_STRUCTURE",
|
||||||
[ SET_CD_SPEED ] = "SET_CD_SPEED",
|
[ SET_CD_SPEED ] = "SET_CD_SPEED",
|
||||||
|
[ SET_READ_AHEAD ] = "SET_READ_AHEAD",
|
||||||
|
[ ALLOW_OVERWRITE ] = "ALLOW_OVERWRITE",
|
||||||
|
[ MECHANISM_STATUS ] = "MECHANISM_STATUS",
|
||||||
};
|
};
|
||||||
|
|
||||||
if (cmd >= ARRAY_SIZE(names) || names[cmd] == NULL)
|
if (cmd >= ARRAY_SIZE(names) || names[cmd] == NULL)
|
||||||
@ -1279,7 +1367,7 @@ static char *scsibus_get_fw_dev_path(DeviceState *dev)
|
|||||||
SCSIDevice *d = DO_UPCAST(SCSIDevice, qdev, dev);
|
SCSIDevice *d = DO_UPCAST(SCSIDevice, qdev, dev);
|
||||||
char path[100];
|
char path[100];
|
||||||
|
|
||||||
snprintf(path, sizeof(path), "%s@%d:%d:%d", qdev_fw_name(dev),
|
snprintf(path, sizeof(path), "%s@%d,%d,%d", qdev_fw_name(dev),
|
||||||
d->channel, d->id, d->lun);
|
d->channel, d->id, d->lun);
|
||||||
|
|
||||||
return strdup(path);
|
return strdup(path);
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
#define REASSIGN_BLOCKS 0x07
|
#define REASSIGN_BLOCKS 0x07
|
||||||
#define READ_6 0x08
|
#define READ_6 0x08
|
||||||
#define WRITE_6 0x0a
|
#define WRITE_6 0x0a
|
||||||
#define SEEK_6 0x0b
|
#define SET_CAPACITY 0x0b
|
||||||
#define READ_REVERSE 0x0f
|
#define READ_REVERSE 0x0f
|
||||||
#define WRITE_FILEMARKS 0x10
|
#define WRITE_FILEMARKS 0x10
|
||||||
#define SPACE 0x11
|
#define SPACE 0x11
|
||||||
@ -81,14 +81,17 @@
|
|||||||
#define GET_EVENT_STATUS_NOTIFICATION 0x4a
|
#define GET_EVENT_STATUS_NOTIFICATION 0x4a
|
||||||
#define LOG_SELECT 0x4c
|
#define LOG_SELECT 0x4c
|
||||||
#define LOG_SENSE 0x4d
|
#define LOG_SENSE 0x4d
|
||||||
|
#define RESERVE_TRACK 0x53
|
||||||
#define MODE_SELECT_10 0x55
|
#define MODE_SELECT_10 0x55
|
||||||
#define RESERVE_10 0x56
|
#define RESERVE_10 0x56
|
||||||
#define RELEASE_10 0x57
|
#define RELEASE_10 0x57
|
||||||
#define MODE_SENSE_10 0x5a
|
#define MODE_SENSE_10 0x5a
|
||||||
|
#define SEND_CUE_SHEET 0x5d
|
||||||
#define PERSISTENT_RESERVE_IN 0x5e
|
#define PERSISTENT_RESERVE_IN 0x5e
|
||||||
#define PERSISTENT_RESERVE_OUT 0x5f
|
#define PERSISTENT_RESERVE_OUT 0x5f
|
||||||
#define VARLENGTH_CDB 0x7f
|
#define VARLENGTH_CDB 0x7f
|
||||||
#define WRITE_FILEMARKS_16 0x80
|
#define WRITE_FILEMARKS_16 0x80
|
||||||
|
#define ALLOW_OVERWRITE 0x82
|
||||||
#define EXTENDED_COPY 0x83
|
#define EXTENDED_COPY 0x83
|
||||||
#define ATA_PASSTHROUGH 0x85
|
#define ATA_PASSTHROUGH 0x85
|
||||||
#define ACCESS_CONTROL_IN 0x86
|
#define ACCESS_CONTROL_IN 0x86
|
||||||
@ -98,6 +101,8 @@
|
|||||||
#define WRITE_16 0x8a
|
#define WRITE_16 0x8a
|
||||||
#define WRITE_VERIFY_16 0x8e
|
#define WRITE_VERIFY_16 0x8e
|
||||||
#define VERIFY_16 0x8f
|
#define VERIFY_16 0x8f
|
||||||
|
#define PRE_FETCH_16 0x90
|
||||||
|
#define SPACE_16 0x91
|
||||||
#define SYNCHRONIZE_CACHE_16 0x91
|
#define SYNCHRONIZE_CACHE_16 0x91
|
||||||
#define LOCATE_16 0x92
|
#define LOCATE_16 0x92
|
||||||
#define WRITE_SAME_16 0x93
|
#define WRITE_SAME_16 0x93
|
||||||
@ -110,9 +115,11 @@
|
|||||||
#define MAINTENANCE_OUT 0xa4
|
#define MAINTENANCE_OUT 0xa4
|
||||||
#define MOVE_MEDIUM 0xa5
|
#define MOVE_MEDIUM 0xa5
|
||||||
#define LOAD_UNLOAD 0xa6
|
#define LOAD_UNLOAD 0xa6
|
||||||
|
#define SET_READ_AHEAD 0xa7
|
||||||
#define READ_12 0xa8
|
#define READ_12 0xa8
|
||||||
#define WRITE_12 0xaa
|
#define WRITE_12 0xaa
|
||||||
#define SERVICE_ACTION_IN_12 0xab
|
#define SERVICE_ACTION_IN_12 0xab
|
||||||
|
#define ERASE_12 0xac
|
||||||
#define READ_DVD_STRUCTURE 0xad
|
#define READ_DVD_STRUCTURE 0xad
|
||||||
#define WRITE_VERIFY_12 0xae
|
#define WRITE_VERIFY_12 0xae
|
||||||
#define VERIFY_12 0xaf
|
#define VERIFY_12 0xaf
|
||||||
@ -125,6 +132,7 @@
|
|||||||
#define SET_CD_SPEED 0xbb
|
#define SET_CD_SPEED 0xbb
|
||||||
#define MECHANISM_STATUS 0xbd
|
#define MECHANISM_STATUS 0xbd
|
||||||
#define READ_CD 0xbe
|
#define READ_CD 0xbe
|
||||||
|
#define SEND_DVD_STRUCTURE 0xbf
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SERVICE ACTION IN subcodes
|
* SERVICE ACTION IN subcodes
|
||||||
|
@ -797,7 +797,7 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* if a geometry hint is available, use it */
|
/* if a geometry hint is available, use it */
|
||||||
bdrv_get_geometry_hint(bdrv, &cylinders, &heads, &secs);
|
bdrv_guess_geometry(bdrv, &cylinders, &heads, &secs);
|
||||||
p[2] = (cylinders >> 16) & 0xff;
|
p[2] = (cylinders >> 16) & 0xff;
|
||||||
p[3] = (cylinders >> 8) & 0xff;
|
p[3] = (cylinders >> 8) & 0xff;
|
||||||
p[4] = cylinders & 0xff;
|
p[4] = cylinders & 0xff;
|
||||||
@ -831,7 +831,7 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
|
|||||||
p[2] = 5000 >> 8;
|
p[2] = 5000 >> 8;
|
||||||
p[3] = 5000 & 0xff;
|
p[3] = 5000 & 0xff;
|
||||||
/* if a geometry hint is available, use it */
|
/* if a geometry hint is available, use it */
|
||||||
bdrv_get_geometry_hint(bdrv, &cylinders, &heads, &secs);
|
bdrv_guess_geometry(bdrv, &cylinders, &heads, &secs);
|
||||||
p[4] = heads & 0xff;
|
p[4] = heads & 0xff;
|
||||||
p[5] = secs & 0xff;
|
p[5] = secs & 0xff;
|
||||||
p[6] = s->qdev.blocksize >> 8;
|
p[6] = s->qdev.blocksize >> 8;
|
||||||
@ -956,8 +956,9 @@ static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf)
|
|||||||
p += 8;
|
p += 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* MMC prescribes that CD/DVD drives have no block descriptors. */
|
||||||
bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
|
bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
|
||||||
if (!dbd && nb_sectors) {
|
if (!dbd && s->qdev.type == TYPE_DISK && nb_sectors) {
|
||||||
if (r->req.cmd.buf[0] == MODE_SENSE) {
|
if (r->req.cmd.buf[0] == MODE_SENSE) {
|
||||||
outbuf[3] = 8; /* Block descriptor length */
|
outbuf[3] = 8; /* Block descriptor length */
|
||||||
} else { /* MODE_SENSE_10 */
|
} else { /* MODE_SENSE_10 */
|
||||||
@ -1178,6 +1179,11 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
|
|||||||
outbuf[7] = 0;
|
outbuf[7] = 0;
|
||||||
buflen = 8;
|
buflen = 8;
|
||||||
break;
|
break;
|
||||||
|
case REQUEST_SENSE:
|
||||||
|
/* Just return "NO SENSE". */
|
||||||
|
buflen = scsi_build_sense(NULL, 0, outbuf, r->buflen,
|
||||||
|
(req->cmd.buf[1] & 1) == 0);
|
||||||
|
break;
|
||||||
case MECHANISM_STATUS:
|
case MECHANISM_STATUS:
|
||||||
buflen = scsi_emulate_mechanism_status(s, outbuf);
|
buflen = scsi_emulate_mechanism_status(s, outbuf);
|
||||||
if (buflen < 0) {
|
if (buflen < 0) {
|
||||||
@ -1312,6 +1318,7 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
|
|||||||
case GET_EVENT_STATUS_NOTIFICATION:
|
case GET_EVENT_STATUS_NOTIFICATION:
|
||||||
case MECHANISM_STATUS:
|
case MECHANISM_STATUS:
|
||||||
case SERVICE_ACTION_IN_16:
|
case SERVICE_ACTION_IN_16:
|
||||||
|
case REQUEST_SENSE:
|
||||||
case VERIFY_10:
|
case VERIFY_10:
|
||||||
rc = scsi_disk_emulate_command(r);
|
rc = scsi_disk_emulate_command(r);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
@ -1374,10 +1381,8 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SEEK_6:
|
|
||||||
case SEEK_10:
|
case SEEK_10:
|
||||||
DPRINTF("Seek(%d) (sector %" PRId64 ")\n", command == SEEK_6 ? 6 : 10,
|
DPRINTF("Seek(10) (sector %" PRId64 ")\n", r->req.cmd.lba);
|
||||||
r->req.cmd.lba);
|
|
||||||
if (r->req.cmd.lba > s->qdev.max_lba) {
|
if (r->req.cmd.lba > s->qdev.max_lba) {
|
||||||
goto illegal_lba;
|
goto illegal_lba;
|
||||||
}
|
}
|
||||||
@ -1408,8 +1413,6 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case REQUEST_SENSE:
|
|
||||||
abort();
|
|
||||||
default:
|
default:
|
||||||
DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
|
DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
|
||||||
scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
|
scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
|
||||||
@ -1553,7 +1556,7 @@ static int scsi_initfn(SCSIDevice *dev)
|
|||||||
bdrv_set_buffer_alignment(s->qdev.conf.bs, s->qdev.blocksize);
|
bdrv_set_buffer_alignment(s->qdev.conf.bs, s->qdev.blocksize);
|
||||||
|
|
||||||
bdrv_iostatus_enable(s->qdev.conf.bs);
|
bdrv_iostatus_enable(s->qdev.conf.bs);
|
||||||
add_boot_device_path(s->qdev.conf.bootindex, &dev->qdev, ",0");
|
add_boot_device_path(s->qdev.conf.bootindex, &dev->qdev, NULL);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1700,8 +1703,20 @@ static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag,
|
|||||||
case WRITE_VERIFY_10:
|
case WRITE_VERIFY_10:
|
||||||
case WRITE_VERIFY_12:
|
case WRITE_VERIFY_12:
|
||||||
case WRITE_VERIFY_16:
|
case WRITE_VERIFY_16:
|
||||||
return scsi_req_alloc(&scsi_disk_reqops, &s->qdev, tag, lun,
|
/* MMC writing cannot be done via pread/pwrite, because it sometimes
|
||||||
hba_private);
|
* involves writing beyond the maximum LBA or to negative LBA (lead-in).
|
||||||
|
* And once you do these writes, reading from the block device is
|
||||||
|
* unreliable, too. It is even possible that reads deliver random data
|
||||||
|
* from the host page cache (this is probably a Linux bug).
|
||||||
|
*
|
||||||
|
* We might use scsi_disk_reqops as long as no writing commands are
|
||||||
|
* seen, but performance usually isn't paramount on optical media. So,
|
||||||
|
* just make scsi-block operate the same as scsi-generic for them.
|
||||||
|
*/
|
||||||
|
if (s->qdev.type != TYPE_ROM) {
|
||||||
|
return scsi_req_alloc(&scsi_disk_reqops, &s->qdev, tag, lun,
|
||||||
|
hba_private);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return scsi_req_alloc(&scsi_generic_req_ops, &s->qdev, tag, lun,
|
return scsi_req_alloc(&scsi_generic_req_ops, &s->qdev, tag, lun,
|
||||||
|
@ -179,6 +179,8 @@ extern const struct SCSISense sense_code_DEVICE_INTERNAL_RESET;
|
|||||||
#define SENSE_CODE(x) sense_code_ ## x
|
#define SENSE_CODE(x) sense_code_ ## x
|
||||||
|
|
||||||
int scsi_sense_valid(SCSISense sense);
|
int scsi_sense_valid(SCSISense sense);
|
||||||
|
int scsi_build_sense(uint8_t *in_buf, int in_len,
|
||||||
|
uint8_t *buf, int len, bool fixed);
|
||||||
|
|
||||||
SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
|
SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
|
||||||
uint32_t tag, uint32_t lun, void *hba_private);
|
uint32_t tag, uint32_t lun, void *hba_private);
|
||||||
|
@ -421,6 +421,7 @@ snapshots.
|
|||||||
* disk_images_fat_images:: Virtual FAT disk images
|
* disk_images_fat_images:: Virtual FAT disk images
|
||||||
* disk_images_nbd:: NBD access
|
* disk_images_nbd:: NBD access
|
||||||
* disk_images_sheepdog:: Sheepdog disk images
|
* disk_images_sheepdog:: Sheepdog disk images
|
||||||
|
* disk_images_iscsi:: iSCSI LUNs
|
||||||
@end menu
|
@end menu
|
||||||
|
|
||||||
@node disk_images_quickstart
|
@node disk_images_quickstart
|
||||||
@ -695,6 +696,61 @@ qemu-img create sheepdog:@var{hostname}:@var{port}:@var{image} @var{size}
|
|||||||
qemu sheepdog:@var{hostname}:@var{port}:@var{image}
|
qemu sheepdog:@var{hostname}:@var{port}:@var{image}
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
|
@node disk_images_iscsi
|
||||||
|
@subsection iSCSI LUNs
|
||||||
|
|
||||||
|
iSCSI is a popular protocol used to access SCSI devices across a computer
|
||||||
|
network.
|
||||||
|
|
||||||
|
There are two different ways iSCSI devices can be used by QEMU.
|
||||||
|
|
||||||
|
The first method is to mount the iSCSI LUN on the host, and make it appear as
|
||||||
|
any other ordinary SCSI device on the host and then to access this device as a
|
||||||
|
/dev/sd device from QEMU. How to do this differs between host OSes.
|
||||||
|
|
||||||
|
The second method involves using the iSCSI initiator that is built into
|
||||||
|
QEMU. This provides a mechanism that works the same way regardless of which
|
||||||
|
host OS you are running QEMU on. This section will describe this second method
|
||||||
|
of using iSCSI together with QEMU.
|
||||||
|
|
||||||
|
In QEMU, iSCSI devices are described using special iSCSI URLs
|
||||||
|
|
||||||
|
@example
|
||||||
|
URL syntax:
|
||||||
|
iscsi://[<username>[%<password>]@@]<host>[:<port>]/<target-iqn-name>/<lun>
|
||||||
|
@end example
|
||||||
|
|
||||||
|
Username and password are optional and only used if your target is set up
|
||||||
|
using CHAP authentication for access control.
|
||||||
|
Alternatively the username and password can also be set via environment
|
||||||
|
variables to have these not show up in the process list
|
||||||
|
|
||||||
|
@example
|
||||||
|
export LIBISCSI_CHAP_USERNAME=<username>
|
||||||
|
export LIBISCSI_CHAP_PASSWORD=<password>
|
||||||
|
iscsi://<host>/<target-iqn-name>/<lun>
|
||||||
|
@end example
|
||||||
|
|
||||||
|
Howto set up a simple iSCSI target on loopback and accessing it via QEMU:
|
||||||
|
@example
|
||||||
|
This example shows how to set up an iSCSI target with one CDROM and one DISK
|
||||||
|
using the Linux STGT software target. This target is available on Red Hat based
|
||||||
|
systems as the package 'scsi-target-utils'.
|
||||||
|
|
||||||
|
tgtd --iscsi portal=127.0.0.1:3260
|
||||||
|
tgtadm --lld iscsi --op new --mode target --tid 1 -T iqn.qemu.test
|
||||||
|
tgtadm --lld iscsi --mode logicalunit --op new --tid 1 --lun 1 \
|
||||||
|
-b /IMAGES/disk.img --device-type=disk
|
||||||
|
tgtadm --lld iscsi --mode logicalunit --op new --tid 1 --lun 2 \
|
||||||
|
-b /IMAGES/cd.iso --device-type=cd
|
||||||
|
tgtadm --lld iscsi --op bind --mode target --tid 1 -I ALL
|
||||||
|
|
||||||
|
qemu-system-i386 -boot d -drive file=iscsi://127.0.0.1/iqn.qemu.test/1 \
|
||||||
|
-cdrom iscsi://127.0.0.1/iqn.qemu.test/2
|
||||||
|
@end example
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@node pcsys_network
|
@node pcsys_network
|
||||||
@section Network emulation
|
@section Network emulation
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user