|
@@ -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;
|
|
|
|
- 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;
|
|
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);
|