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 max_len;
|
||||
|
||||
if (buf[0] == GPCMD_MODE_SENSE_10) {
|
||||
max_len = ube16_to_cpu(buf + 7);
|
||||
} else {
|
||||
max_len = buf[4];
|
||||
}
|
||||
|
||||
max_len = ube16_to_cpu(buf + 7);
|
||||
action = buf[2] >> 6;
|
||||
code = buf[2] & 0x3f;
|
||||
|
||||
@ -708,7 +703,7 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
|
||||
case 0: /* current values */
|
||||
switch(code) {
|
||||
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[3] = 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);
|
||||
break;
|
||||
case MODE_PAGE_AUDIO_CTL:
|
||||
cpu_to_ube16(&buf[0], 24 + 6);
|
||||
cpu_to_ube16(&buf[0], 24 - 2);
|
||||
buf[2] = 0x70;
|
||||
buf[3] = 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);
|
||||
break;
|
||||
case MODE_PAGE_CAPABILITIES:
|
||||
cpu_to_ube16(&buf[0], 28 + 6);
|
||||
cpu_to_ube16(&buf[0], 30 - 2);
|
||||
buf[2] = 0x70;
|
||||
buf[3] = 0;
|
||||
buf[4] = 0;
|
||||
@ -755,7 +750,7 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
|
||||
buf[7] = 0;
|
||||
|
||||
buf[8] = MODE_PAGE_CAPABILITIES;
|
||||
buf[9] = 28 - 10;
|
||||
buf[9] = 30 - 10;
|
||||
buf[10] = 0x3b; /* read CDR/CDRW/DVDROM/DVDR/DVDRAM */
|
||||
buf[11] = 0x00;
|
||||
|
||||
@ -777,7 +772,9 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
|
||||
buf[25] = 0;
|
||||
buf[26] = 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;
|
||||
default:
|
||||
goto error_cmd;
|
||||
@ -1043,7 +1040,6 @@ static const struct {
|
||||
[ 0x00 ] = { cmd_test_unit_ready, CHECK_READY },
|
||||
[ 0x03 ] = { cmd_request_sense, ALLOW_UA },
|
||||
[ 0x12 ] = { cmd_inquiry, ALLOW_UA },
|
||||
[ 0x1a ] = { cmd_mode_sense, /* (6) */ 0 },
|
||||
[ 0x1b ] = { cmd_start_stop_unit, 0 }, /* [1] */
|
||||
[ 0x1e ] = { cmd_prevent_allow_medium_removal, 0 },
|
||||
[ 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 int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf);
|
||||
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 = {
|
||||
.name = "SCSI",
|
||||
@ -502,7 +500,7 @@ SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
|
||||
hba_private);
|
||||
} else if (lun != d->lun ||
|
||||
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,
|
||||
hba_private);
|
||||
} 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)
|
||||
{
|
||||
switch (buf[0] >> 5) {
|
||||
@ -666,11 +689,11 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
|
||||
cmd->len = 10;
|
||||
break;
|
||||
case 4:
|
||||
cmd->xfer = ldl_be_p(&buf[10]);
|
||||
cmd->xfer = ldl_be_p(&buf[10]) & 0xffffffffULL;
|
||||
cmd->len = 16;
|
||||
break;
|
||||
case 5:
|
||||
cmd->xfer = ldl_be_p(&buf[6]);
|
||||
cmd->xfer = ldl_be_p(&buf[6]) & 0xffffffffULL;
|
||||
cmd->len = 12;
|
||||
break;
|
||||
default:
|
||||
@ -681,8 +704,9 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
|
||||
case TEST_UNIT_READY:
|
||||
case REWIND:
|
||||
case START_STOP:
|
||||
case SEEK_6:
|
||||
case SET_CAPACITY:
|
||||
case WRITE_FILEMARKS:
|
||||
case WRITE_FILEMARKS_16:
|
||||
case SPACE:
|
||||
case RESERVE:
|
||||
case RELEASE:
|
||||
@ -691,6 +715,8 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
|
||||
case VERIFY_10:
|
||||
case SEEK_10:
|
||||
case SYNCHRONIZE_CACHE:
|
||||
case SYNCHRONIZE_CACHE_16:
|
||||
case LOCATE_16:
|
||||
case LOCK_UNLOCK_CACHE:
|
||||
case LOAD_UNLOAD:
|
||||
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 MOVE_MEDIUM:
|
||||
case UPDATE_BLOCK:
|
||||
case RESERVE_TRACK:
|
||||
case SET_READ_AHEAD:
|
||||
case PRE_FETCH:
|
||||
case PRE_FETCH_16:
|
||||
case ALLOW_OVERWRITE:
|
||||
cmd->xfer = 0;
|
||||
break;
|
||||
case MODE_SENSE:
|
||||
@ -711,14 +742,13 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
|
||||
case READ_BLOCK_LIMITS:
|
||||
cmd->xfer = 6;
|
||||
break;
|
||||
case READ_POSITION:
|
||||
cmd->xfer = 20;
|
||||
break;
|
||||
case SEND_VOLUME_TAG:
|
||||
cmd->xfer *= 40;
|
||||
break;
|
||||
case MEDIUM_SCAN:
|
||||
cmd->xfer *= 8;
|
||||
/* GPCMD_SET_STREAMING from multimedia commands. */
|
||||
if (dev->type == TYPE_ROM) {
|
||||
cmd->xfer = buf[10] | (buf[9] << 8);
|
||||
} else {
|
||||
cmd->xfer = buf[9] | (buf[8] << 8);
|
||||
}
|
||||
break;
|
||||
case WRITE_10:
|
||||
case WRITE_VERIFY_10:
|
||||
@ -737,9 +767,39 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
|
||||
case READ_16:
|
||||
cmd->xfer *= dev->blocksize;
|
||||
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 RECEIVE_DIAGNOSTIC:
|
||||
case SEND_DIAGNOSTIC:
|
||||
cmd->xfer = buf[4] | (buf[3] << 8);
|
||||
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_IN:
|
||||
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]) {
|
||||
/* stream commands */
|
||||
case ERASE_12:
|
||||
case ERASE_16:
|
||||
cmd->xfer = 0;
|
||||
break;
|
||||
case READ_6:
|
||||
case READ_REVERSE:
|
||||
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->xfer = 0;
|
||||
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 */
|
||||
default:
|
||||
return scsi_req_length(cmd, dev, buf);
|
||||
@ -809,6 +882,8 @@ static void scsi_cmd_xfer_mode(SCSICommand *cmd)
|
||||
case SEARCH_LOW_12:
|
||||
case MEDIUM_SCAN:
|
||||
case SEND_VOLUME_TAG:
|
||||
case SEND_CUE_SHEET:
|
||||
case SEND_DVD_STRUCTURE:
|
||||
case PERSISTENT_RESERVE_OUT:
|
||||
case MAINTENANCE_OUT:
|
||||
cmd->mode = SCSI_XFER_TO_DEV;
|
||||
@ -835,7 +910,7 @@ static uint64_t scsi_cmd_lba(SCSICommand *cmd)
|
||||
case 1:
|
||||
case 2:
|
||||
case 5:
|
||||
lba = ldl_be_p(&buf[2]);
|
||||
lba = ldl_be_p(&buf[2]) & 0xffffffffULL;
|
||||
break;
|
||||
case 4:
|
||||
lba = ldq_be_p(&buf[2]);
|
||||
@ -1036,7 +1111,7 @@ static const char *scsi_command_name(uint8_t cmd)
|
||||
[ REASSIGN_BLOCKS ] = "REASSIGN_BLOCKS",
|
||||
[ READ_6 ] = "READ_6",
|
||||
[ WRITE_6 ] = "WRITE_6",
|
||||
[ SEEK_6 ] = "SEEK_6",
|
||||
[ SET_CAPACITY ] = "SET_CAPACITY",
|
||||
[ READ_REVERSE ] = "READ_REVERSE",
|
||||
[ WRITE_FILEMARKS ] = "WRITE_FILEMARKS",
|
||||
[ SPACE ] = "SPACE",
|
||||
@ -1064,7 +1139,7 @@ static const char *scsi_command_name(uint8_t cmd)
|
||||
[ SEARCH_EQUAL ] = "SEARCH_EQUAL",
|
||||
[ SEARCH_LOW ] = "SEARCH_LOW",
|
||||
[ SET_LIMITS ] = "SET_LIMITS",
|
||||
[ PRE_FETCH ] = "PRE_FETCH",
|
||||
[ PRE_FETCH ] = "PRE_FETCH/READ_POSITION",
|
||||
/* READ_POSITION and PRE_FETCH use the same operation code */
|
||||
[ SYNCHRONIZE_CACHE ] = "SYNCHRONIZE_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_VERIFY_16 ] = "WRITE_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",
|
||||
[ 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 */
|
||||
[ SERVICE_ACTION_IN_16 ] = "SERVICE_ACTION_IN_16",
|
||||
[ WRITE_LONG_16 ] = "WRITE_LONG_16",
|
||||
@ -1113,6 +1190,8 @@ static const char *scsi_command_name(uint8_t cmd)
|
||||
[ LOAD_UNLOAD ] = "LOAD_UNLOAD",
|
||||
[ READ_12 ] = "READ_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",
|
||||
[ WRITE_VERIFY_12 ] = "WRITE_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_LOW_12 ] = "SEARCH_LOW_12",
|
||||
[ 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_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_READ_AHEAD ] = "SET_READ_AHEAD",
|
||||
[ ALLOW_OVERWRITE ] = "ALLOW_OVERWRITE",
|
||||
[ MECHANISM_STATUS ] = "MECHANISM_STATUS",
|
||||
};
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
return strdup(path);
|
||||
|
@ -32,7 +32,7 @@
|
||||
#define REASSIGN_BLOCKS 0x07
|
||||
#define READ_6 0x08
|
||||
#define WRITE_6 0x0a
|
||||
#define SEEK_6 0x0b
|
||||
#define SET_CAPACITY 0x0b
|
||||
#define READ_REVERSE 0x0f
|
||||
#define WRITE_FILEMARKS 0x10
|
||||
#define SPACE 0x11
|
||||
@ -81,14 +81,17 @@
|
||||
#define GET_EVENT_STATUS_NOTIFICATION 0x4a
|
||||
#define LOG_SELECT 0x4c
|
||||
#define LOG_SENSE 0x4d
|
||||
#define RESERVE_TRACK 0x53
|
||||
#define MODE_SELECT_10 0x55
|
||||
#define RESERVE_10 0x56
|
||||
#define RELEASE_10 0x57
|
||||
#define MODE_SENSE_10 0x5a
|
||||
#define SEND_CUE_SHEET 0x5d
|
||||
#define PERSISTENT_RESERVE_IN 0x5e
|
||||
#define PERSISTENT_RESERVE_OUT 0x5f
|
||||
#define VARLENGTH_CDB 0x7f
|
||||
#define WRITE_FILEMARKS_16 0x80
|
||||
#define ALLOW_OVERWRITE 0x82
|
||||
#define EXTENDED_COPY 0x83
|
||||
#define ATA_PASSTHROUGH 0x85
|
||||
#define ACCESS_CONTROL_IN 0x86
|
||||
@ -98,6 +101,8 @@
|
||||
#define WRITE_16 0x8a
|
||||
#define WRITE_VERIFY_16 0x8e
|
||||
#define VERIFY_16 0x8f
|
||||
#define PRE_FETCH_16 0x90
|
||||
#define SPACE_16 0x91
|
||||
#define SYNCHRONIZE_CACHE_16 0x91
|
||||
#define LOCATE_16 0x92
|
||||
#define WRITE_SAME_16 0x93
|
||||
@ -110,9 +115,11 @@
|
||||
#define MAINTENANCE_OUT 0xa4
|
||||
#define MOVE_MEDIUM 0xa5
|
||||
#define LOAD_UNLOAD 0xa6
|
||||
#define SET_READ_AHEAD 0xa7
|
||||
#define READ_12 0xa8
|
||||
#define WRITE_12 0xaa
|
||||
#define SERVICE_ACTION_IN_12 0xab
|
||||
#define ERASE_12 0xac
|
||||
#define READ_DVD_STRUCTURE 0xad
|
||||
#define WRITE_VERIFY_12 0xae
|
||||
#define VERIFY_12 0xaf
|
||||
@ -125,6 +132,7 @@
|
||||
#define SET_CD_SPEED 0xbb
|
||||
#define MECHANISM_STATUS 0xbd
|
||||
#define READ_CD 0xbe
|
||||
#define SEND_DVD_STRUCTURE 0xbf
|
||||
|
||||
/*
|
||||
* SERVICE ACTION IN subcodes
|
||||
|
@ -797,7 +797,7 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
|
||||
break;
|
||||
}
|
||||
/* 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[3] = (cylinders >> 8) & 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[3] = 5000 & 0xff;
|
||||
/* 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[5] = secs & 0xff;
|
||||
p[6] = s->qdev.blocksize >> 8;
|
||||
@ -956,8 +956,9 @@ static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf)
|
||||
p += 8;
|
||||
}
|
||||
|
||||
/* MMC prescribes that CD/DVD drives have no block descriptors. */
|
||||
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) {
|
||||
outbuf[3] = 8; /* Block descriptor length */
|
||||
} else { /* MODE_SENSE_10 */
|
||||
@ -1178,6 +1179,11 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
|
||||
outbuf[7] = 0;
|
||||
buflen = 8;
|
||||
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:
|
||||
buflen = scsi_emulate_mechanism_status(s, outbuf);
|
||||
if (buflen < 0) {
|
||||
@ -1312,6 +1318,7 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
|
||||
case GET_EVENT_STATUS_NOTIFICATION:
|
||||
case MECHANISM_STATUS:
|
||||
case SERVICE_ACTION_IN_16:
|
||||
case REQUEST_SENSE:
|
||||
case VERIFY_10:
|
||||
rc = scsi_disk_emulate_command(r);
|
||||
if (rc < 0) {
|
||||
@ -1374,10 +1381,8 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case SEEK_6:
|
||||
case SEEK_10:
|
||||
DPRINTF("Seek(%d) (sector %" PRId64 ")\n", command == SEEK_6 ? 6 : 10,
|
||||
r->req.cmd.lba);
|
||||
DPRINTF("Seek(10) (sector %" PRId64 ")\n", r->req.cmd.lba);
|
||||
if (r->req.cmd.lba > s->qdev.max_lba) {
|
||||
goto illegal_lba;
|
||||
}
|
||||
@ -1408,8 +1413,6 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
|
||||
}
|
||||
|
||||
break;
|
||||
case REQUEST_SENSE:
|
||||
abort();
|
||||
default:
|
||||
DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
|
||||
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_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;
|
||||
}
|
||||
|
||||
@ -1700,8 +1703,20 @@ static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag,
|
||||
case WRITE_VERIFY_10:
|
||||
case WRITE_VERIFY_12:
|
||||
case WRITE_VERIFY_16:
|
||||
return scsi_req_alloc(&scsi_disk_reqops, &s->qdev, tag, lun,
|
||||
hba_private);
|
||||
/* MMC writing cannot be done via pread/pwrite, because it sometimes
|
||||
* 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,
|
||||
|
@ -179,6 +179,8 @@ extern const struct SCSISense sense_code_DEVICE_INTERNAL_RESET;
|
||||
#define SENSE_CODE(x) sense_code_ ## x
|
||||
|
||||
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,
|
||||
uint32_t tag, uint32_t lun, void *hba_private);
|
||||
|
@ -421,6 +421,7 @@ snapshots.
|
||||
* disk_images_fat_images:: Virtual FAT disk images
|
||||
* disk_images_nbd:: NBD access
|
||||
* disk_images_sheepdog:: Sheepdog disk images
|
||||
* disk_images_iscsi:: iSCSI LUNs
|
||||
@end menu
|
||||
|
||||
@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}
|
||||
@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
|
||||
@section Network emulation
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user