Merge remote-tracking branch 'bonzini/scsi-next' into staging
* bonzini/scsi-next: scsi: Fix transfer length for READ POSITION commands. scsi: Add basic support for SCSI media changer commands. scsi: Ensure command and transfer lengths are set for all SCSI devices scsi: Fix LOAD_UNLOAD scsi: Fix data length == SCSI_SENSE_BUF_SIZE virtio-scsi: do not crash on adding buffers to the event queue megasas: LSI Megaraid SAS HBA emulation megasas: Add header file ISCSI: force use of sg for SMC and SSC devices ISCSI: Add SCSI passthrough via scsi-generic to libiscsi scsi-disk: implement READ DISC INFORMATION atapi: implement READ DISC INFORMATION scsi: add a qdev property for the disk's WWN scsi: simplify handling of the VPD page length field
This commit is contained in:
commit
ffd6e7a072
152
block/iscsi.c
152
block/iscsi.c
@ -35,6 +35,10 @@
|
|||||||
#include <iscsi/iscsi.h>
|
#include <iscsi/iscsi.h>
|
||||||
#include <iscsi/scsi-lowlevel.h>
|
#include <iscsi/scsi-lowlevel.h>
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
#include <scsi/sg.h>
|
||||||
|
#include <hw/scsi-defs.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct IscsiLun {
|
typedef struct IscsiLun {
|
||||||
struct iscsi_context *iscsi;
|
struct iscsi_context *iscsi;
|
||||||
@ -56,6 +60,9 @@ typedef struct IscsiAIOCB {
|
|||||||
int canceled;
|
int canceled;
|
||||||
size_t read_size;
|
size_t read_size;
|
||||||
size_t read_offset;
|
size_t read_offset;
|
||||||
|
#ifdef __linux__
|
||||||
|
sg_io_hdr_t *ioh;
|
||||||
|
#endif
|
||||||
} IscsiAIOCB;
|
} IscsiAIOCB;
|
||||||
|
|
||||||
struct IscsiTask {
|
struct IscsiTask {
|
||||||
@ -515,6 +522,136 @@ iscsi_aio_discard(BlockDriverState *bs,
|
|||||||
return &acb->common;
|
return &acb->common;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
static void
|
||||||
|
iscsi_aio_ioctl_cb(struct iscsi_context *iscsi, int status,
|
||||||
|
void *command_data, void *opaque)
|
||||||
|
{
|
||||||
|
IscsiAIOCB *acb = opaque;
|
||||||
|
|
||||||
|
if (acb->canceled != 0) {
|
||||||
|
qemu_aio_release(acb);
|
||||||
|
scsi_free_scsi_task(acb->task);
|
||||||
|
acb->task = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
acb->status = 0;
|
||||||
|
if (status < 0) {
|
||||||
|
error_report("Failed to ioctl(SG_IO) to iSCSI lun. %s",
|
||||||
|
iscsi_get_error(iscsi));
|
||||||
|
acb->status = -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
acb->ioh->driver_status = 0;
|
||||||
|
acb->ioh->host_status = 0;
|
||||||
|
acb->ioh->resid = 0;
|
||||||
|
|
||||||
|
#define SG_ERR_DRIVER_SENSE 0x08
|
||||||
|
|
||||||
|
if (status == SCSI_STATUS_CHECK_CONDITION && acb->task->datain.size >= 2) {
|
||||||
|
int ss;
|
||||||
|
|
||||||
|
acb->ioh->driver_status |= SG_ERR_DRIVER_SENSE;
|
||||||
|
|
||||||
|
acb->ioh->sb_len_wr = acb->task->datain.size - 2;
|
||||||
|
ss = (acb->ioh->mx_sb_len >= acb->ioh->sb_len_wr) ?
|
||||||
|
acb->ioh->mx_sb_len : acb->ioh->sb_len_wr;
|
||||||
|
memcpy(acb->ioh->sbp, &acb->task->datain.data[2], ss);
|
||||||
|
}
|
||||||
|
|
||||||
|
iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb);
|
||||||
|
scsi_free_scsi_task(acb->task);
|
||||||
|
acb->task = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BlockDriverAIOCB *iscsi_aio_ioctl(BlockDriverState *bs,
|
||||||
|
unsigned long int req, void *buf,
|
||||||
|
BlockDriverCompletionFunc *cb, void *opaque)
|
||||||
|
{
|
||||||
|
IscsiLun *iscsilun = bs->opaque;
|
||||||
|
struct iscsi_context *iscsi = iscsilun->iscsi;
|
||||||
|
struct iscsi_data data;
|
||||||
|
IscsiAIOCB *acb;
|
||||||
|
|
||||||
|
assert(req == SG_IO);
|
||||||
|
|
||||||
|
acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
|
||||||
|
|
||||||
|
acb->iscsilun = iscsilun;
|
||||||
|
acb->canceled = 0;
|
||||||
|
acb->buf = NULL;
|
||||||
|
acb->ioh = buf;
|
||||||
|
|
||||||
|
acb->task = malloc(sizeof(struct scsi_task));
|
||||||
|
if (acb->task == NULL) {
|
||||||
|
error_report("iSCSI: Failed to allocate task for scsi command. %s",
|
||||||
|
iscsi_get_error(iscsi));
|
||||||
|
qemu_aio_release(acb);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memset(acb->task, 0, sizeof(struct scsi_task));
|
||||||
|
|
||||||
|
switch (acb->ioh->dxfer_direction) {
|
||||||
|
case SG_DXFER_TO_DEV:
|
||||||
|
acb->task->xfer_dir = SCSI_XFER_WRITE;
|
||||||
|
break;
|
||||||
|
case SG_DXFER_FROM_DEV:
|
||||||
|
acb->task->xfer_dir = SCSI_XFER_READ;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
acb->task->xfer_dir = SCSI_XFER_NONE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
acb->task->cdb_size = acb->ioh->cmd_len;
|
||||||
|
memcpy(&acb->task->cdb[0], acb->ioh->cmdp, acb->ioh->cmd_len);
|
||||||
|
acb->task->expxferlen = acb->ioh->dxfer_len;
|
||||||
|
|
||||||
|
if (acb->task->xfer_dir == SCSI_XFER_WRITE) {
|
||||||
|
data.data = acb->ioh->dxferp;
|
||||||
|
data.size = acb->ioh->dxfer_len;
|
||||||
|
}
|
||||||
|
if (iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task,
|
||||||
|
iscsi_aio_ioctl_cb,
|
||||||
|
(acb->task->xfer_dir == SCSI_XFER_WRITE) ?
|
||||||
|
&data : NULL,
|
||||||
|
acb) != 0) {
|
||||||
|
scsi_free_scsi_task(acb->task);
|
||||||
|
qemu_aio_release(acb);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tell libiscsi to read straight into the buffer we got from ioctl */
|
||||||
|
if (acb->task->xfer_dir == SCSI_XFER_READ) {
|
||||||
|
scsi_task_add_data_in_buffer(acb->task,
|
||||||
|
acb->ioh->dxfer_len,
|
||||||
|
acb->ioh->dxferp);
|
||||||
|
}
|
||||||
|
|
||||||
|
iscsi_set_events(iscsilun);
|
||||||
|
|
||||||
|
return &acb->common;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int iscsi_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
|
||||||
|
{
|
||||||
|
IscsiLun *iscsilun = bs->opaque;
|
||||||
|
|
||||||
|
switch (req) {
|
||||||
|
case SG_GET_VERSION_NUM:
|
||||||
|
*(int *)buf = 30000;
|
||||||
|
break;
|
||||||
|
case SG_GET_SCSI_ID:
|
||||||
|
((struct sg_scsi_id *)buf)->scsi_type = iscsilun->type;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int64_t
|
static int64_t
|
||||||
iscsi_getlength(BlockDriverState *bs)
|
iscsi_getlength(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
@ -885,6 +1022,16 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
|
|||||||
if (iscsi_url != NULL) {
|
if (iscsi_url != NULL) {
|
||||||
iscsi_destroy_url(iscsi_url);
|
iscsi_destroy_url(iscsi_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Medium changer or tape. We dont have any emulation for this so this must
|
||||||
|
* be sg ioctl compatible. We force it to be sg, otherwise qemu will try
|
||||||
|
* to read from the device to guess the image format.
|
||||||
|
*/
|
||||||
|
if (iscsilun->type == TYPE_MEDIUM_CHANGER ||
|
||||||
|
iscsilun->type == TYPE_TAPE) {
|
||||||
|
bs->sg = 1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
failed:
|
failed:
|
||||||
@ -926,6 +1073,11 @@ static BlockDriver bdrv_iscsi = {
|
|||||||
.bdrv_aio_flush = iscsi_aio_flush,
|
.bdrv_aio_flush = iscsi_aio_flush,
|
||||||
|
|
||||||
.bdrv_aio_discard = iscsi_aio_discard,
|
.bdrv_aio_discard = iscsi_aio_discard,
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
.bdrv_ioctl = iscsi_ioctl,
|
||||||
|
.bdrv_aio_ioctl = iscsi_aio_ioctl,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static void iscsi_block_init(void)
|
static void iscsi_block_init(void)
|
||||||
|
@ -10,6 +10,7 @@ CONFIG_EEPRO100_PCI=y
|
|||||||
CONFIG_PCNET_PCI=y
|
CONFIG_PCNET_PCI=y
|
||||||
CONFIG_PCNET_COMMON=y
|
CONFIG_PCNET_COMMON=y
|
||||||
CONFIG_LSI_SCSI_PCI=y
|
CONFIG_LSI_SCSI_PCI=y
|
||||||
|
CONFIG_MEGASAS_SCSI_PCI=y
|
||||||
CONFIG_RTL8139_PCI=y
|
CONFIG_RTL8139_PCI=y
|
||||||
CONFIG_E1000_PCI=y
|
CONFIG_E1000_PCI=y
|
||||||
CONFIG_IDE_CORE=y
|
CONFIG_IDE_CORE=y
|
||||||
|
@ -86,6 +86,7 @@ hw-obj-$(CONFIG_OPENCORES_ETH) += opencores_eth.o
|
|||||||
|
|
||||||
# SCSI layer
|
# SCSI layer
|
||||||
hw-obj-$(CONFIG_LSI_SCSI_PCI) += lsi53c895a.o
|
hw-obj-$(CONFIG_LSI_SCSI_PCI) += lsi53c895a.o
|
||||||
|
hw-obj-$(CONFIG_MEGASAS_SCSI_PCI) += megasas.o
|
||||||
hw-obj-$(CONFIG_ESP) += esp.o
|
hw-obj-$(CONFIG_ESP) += esp.o
|
||||||
|
|
||||||
hw-obj-y += sysbus.o isa-bus.o
|
hw-obj-y += sysbus.o isa-bus.o
|
||||||
|
@ -956,6 +956,36 @@ static void cmd_read_cdvd_capacity(IDEState *s, uint8_t* buf)
|
|||||||
ide_atapi_cmd_reply(s, 8, 8);
|
ide_atapi_cmd_reply(s, 8, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void cmd_read_disc_information(IDEState *s, uint8_t* buf)
|
||||||
|
{
|
||||||
|
uint8_t type = buf[1] & 7;
|
||||||
|
uint32_t max_len = ube16_to_cpu(buf + 7);
|
||||||
|
|
||||||
|
/* Types 1/2 are only defined for Blu-Ray. */
|
||||||
|
if (type != 0) {
|
||||||
|
ide_atapi_cmd_error(s, ILLEGAL_REQUEST,
|
||||||
|
ASC_INV_FIELD_IN_CMD_PACKET);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(buf, 0, 34);
|
||||||
|
buf[1] = 32;
|
||||||
|
buf[2] = 0xe; /* last session complete, disc finalized */
|
||||||
|
buf[3] = 1; /* first track on disc */
|
||||||
|
buf[4] = 1; /* # of sessions */
|
||||||
|
buf[5] = 1; /* first track of last session */
|
||||||
|
buf[6] = 1; /* last track of last session */
|
||||||
|
buf[7] = 0x20; /* unrestricted use */
|
||||||
|
buf[8] = 0x00; /* CD-ROM or DVD-ROM */
|
||||||
|
/* 9-10-11: most significant byte corresponding bytes 4-5-6 */
|
||||||
|
/* 12-23: not meaningful for CD-ROM or DVD-ROM */
|
||||||
|
/* 24-31: disc bar code */
|
||||||
|
/* 32: disc application code */
|
||||||
|
/* 33: number of OPC tables */
|
||||||
|
|
||||||
|
ide_atapi_cmd_reply(s, 34, max_len);
|
||||||
|
}
|
||||||
|
|
||||||
static void cmd_read_dvd_structure(IDEState *s, uint8_t* buf)
|
static void cmd_read_dvd_structure(IDEState *s, uint8_t* buf)
|
||||||
{
|
{
|
||||||
int max_len;
|
int max_len;
|
||||||
@ -1045,6 +1075,7 @@ static const struct {
|
|||||||
[ 0x43 ] = { cmd_read_toc_pma_atip, CHECK_READY },
|
[ 0x43 ] = { cmd_read_toc_pma_atip, CHECK_READY },
|
||||||
[ 0x46 ] = { cmd_get_configuration, ALLOW_UA },
|
[ 0x46 ] = { cmd_get_configuration, ALLOW_UA },
|
||||||
[ 0x4a ] = { cmd_get_event_status_notification, ALLOW_UA },
|
[ 0x4a ] = { cmd_get_event_status_notification, ALLOW_UA },
|
||||||
|
[ 0x51 ] = { cmd_read_disc_information, CHECK_READY },
|
||||||
[ 0x5a ] = { cmd_mode_sense, /* (10) */ 0 },
|
[ 0x5a ] = { cmd_mode_sense, /* (10) */ 0 },
|
||||||
[ 0xa8 ] = { cmd_read, /* (12) */ CHECK_READY },
|
[ 0xa8 ] = { cmd_read, /* (12) */ CHECK_READY },
|
||||||
[ 0xad ] = { cmd_read_dvd_structure, CHECK_READY },
|
[ 0xad ] = { cmd_read_dvd_structure, CHECK_READY },
|
||||||
|
2198
hw/megasas.c
Normal file
2198
hw/megasas.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
#define PCI_CLASS_STORAGE_SCSI 0x0100
|
#define PCI_CLASS_STORAGE_SCSI 0x0100
|
||||||
#define PCI_CLASS_STORAGE_IDE 0x0101
|
#define PCI_CLASS_STORAGE_IDE 0x0101
|
||||||
|
#define PCI_CLASS_STORAGE_RAID 0x0104
|
||||||
#define PCI_CLASS_STORAGE_SATA 0x0106
|
#define PCI_CLASS_STORAGE_SATA 0x0106
|
||||||
#define PCI_CLASS_STORAGE_OTHER 0x0180
|
#define PCI_CLASS_STORAGE_OTHER 0x0180
|
||||||
|
|
||||||
@ -47,6 +48,7 @@
|
|||||||
|
|
||||||
#define PCI_VENDOR_ID_LSI_LOGIC 0x1000
|
#define PCI_VENDOR_ID_LSI_LOGIC 0x1000
|
||||||
#define PCI_DEVICE_ID_LSI_53C895A 0x0012
|
#define PCI_DEVICE_ID_LSI_53C895A 0x0012
|
||||||
|
#define PCI_DEVICE_ID_LSI_SAS1078 0x0060
|
||||||
|
|
||||||
#define PCI_VENDOR_ID_DEC 0x1011
|
#define PCI_VENDOR_ID_DEC 0x1011
|
||||||
#define PCI_DEVICE_ID_DEC_21154 0x0026
|
#define PCI_DEVICE_ID_DEC_21154 0x0026
|
||||||
|
@ -734,20 +734,16 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
|
|||||||
switch (buf[0] >> 5) {
|
switch (buf[0] >> 5) {
|
||||||
case 0:
|
case 0:
|
||||||
cmd->xfer = buf[4];
|
cmd->xfer = buf[4];
|
||||||
cmd->len = 6;
|
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
case 2:
|
case 2:
|
||||||
cmd->xfer = lduw_be_p(&buf[7]);
|
cmd->xfer = lduw_be_p(&buf[7]);
|
||||||
cmd->len = 10;
|
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
cmd->xfer = ldl_be_p(&buf[10]) & 0xffffffffULL;
|
cmd->xfer = ldl_be_p(&buf[10]) & 0xffffffffULL;
|
||||||
cmd->len = 16;
|
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
cmd->xfer = ldl_be_p(&buf[6]) & 0xffffffffULL;
|
cmd->xfer = ldl_be_p(&buf[6]) & 0xffffffffULL;
|
||||||
cmd->len = 12;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
@ -771,11 +767,9 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
|
|||||||
case SYNCHRONIZE_CACHE_16:
|
case SYNCHRONIZE_CACHE_16:
|
||||||
case LOCATE_16:
|
case LOCATE_16:
|
||||||
case LOCK_UNLOCK_CACHE:
|
case LOCK_UNLOCK_CACHE:
|
||||||
case LOAD_UNLOAD:
|
|
||||||
case SET_CD_SPEED:
|
case SET_CD_SPEED:
|
||||||
case SET_LIMITS:
|
case SET_LIMITS:
|
||||||
case WRITE_LONG_10:
|
case WRITE_LONG_10:
|
||||||
case MOVE_MEDIUM:
|
|
||||||
case UPDATE_BLOCK:
|
case UPDATE_BLOCK:
|
||||||
case RESERVE_TRACK:
|
case RESERVE_TRACK:
|
||||||
case SET_READ_AHEAD:
|
case SET_READ_AHEAD:
|
||||||
@ -885,7 +879,6 @@ static int scsi_req_stream_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *bu
|
|||||||
case READ_REVERSE:
|
case READ_REVERSE:
|
||||||
case RECOVER_BUFFERED_DATA:
|
case RECOVER_BUFFERED_DATA:
|
||||||
case WRITE_6:
|
case WRITE_6:
|
||||||
cmd->len = 6;
|
|
||||||
cmd->xfer = buf[4] | (buf[3] << 8) | (buf[2] << 16);
|
cmd->xfer = buf[4] | (buf[3] << 8) | (buf[2] << 16);
|
||||||
if (buf[1] & 0x01) { /* fixed */
|
if (buf[1] & 0x01) { /* fixed */
|
||||||
cmd->xfer *= dev->blocksize;
|
cmd->xfer *= dev->blocksize;
|
||||||
@ -895,22 +888,34 @@ static int scsi_req_stream_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *bu
|
|||||||
case READ_REVERSE_16:
|
case READ_REVERSE_16:
|
||||||
case VERIFY_16:
|
case VERIFY_16:
|
||||||
case WRITE_16:
|
case WRITE_16:
|
||||||
cmd->len = 16;
|
|
||||||
cmd->xfer = buf[14] | (buf[13] << 8) | (buf[12] << 16);
|
cmd->xfer = buf[14] | (buf[13] << 8) | (buf[12] << 16);
|
||||||
if (buf[1] & 0x01) { /* fixed */
|
if (buf[1] & 0x01) { /* fixed */
|
||||||
cmd->xfer *= dev->blocksize;
|
cmd->xfer *= dev->blocksize;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case REWIND:
|
case REWIND:
|
||||||
case START_STOP:
|
case LOAD_UNLOAD:
|
||||||
cmd->len = 6;
|
|
||||||
cmd->xfer = 0;
|
cmd->xfer = 0;
|
||||||
break;
|
break;
|
||||||
case SPACE_16:
|
case SPACE_16:
|
||||||
cmd->xfer = buf[13] | (buf[12] << 8);
|
cmd->xfer = buf[13] | (buf[12] << 8);
|
||||||
break;
|
break;
|
||||||
case READ_POSITION:
|
case READ_POSITION:
|
||||||
cmd->xfer = buf[8] | (buf[7] << 8);
|
switch (buf[1] & 0x1f) /* operation code */ {
|
||||||
|
case SHORT_FORM_BLOCK_ID:
|
||||||
|
case SHORT_FORM_VENDOR_SPECIFIC:
|
||||||
|
cmd->xfer = 20;
|
||||||
|
break;
|
||||||
|
case LONG_FORM:
|
||||||
|
cmd->xfer = 32;
|
||||||
|
break;
|
||||||
|
case EXTENDED_FORM:
|
||||||
|
cmd->xfer = buf[8] | (buf[7] << 8);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case FORMAT_UNIT:
|
case FORMAT_UNIT:
|
||||||
cmd->xfer = buf[4] | (buf[3] << 8);
|
cmd->xfer = buf[4] | (buf[3] << 8);
|
||||||
@ -922,6 +927,29 @@ static int scsi_req_stream_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *bu
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int scsi_req_medium_changer_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
|
||||||
|
{
|
||||||
|
switch (buf[0]) {
|
||||||
|
/* medium changer commands */
|
||||||
|
case EXCHANGE_MEDIUM:
|
||||||
|
case INITIALIZE_ELEMENT_STATUS:
|
||||||
|
case INITIALIZE_ELEMENT_STATUS_WITH_RANGE:
|
||||||
|
case MOVE_MEDIUM:
|
||||||
|
case POSITION_TO_ELEMENT:
|
||||||
|
cmd->xfer = 0;
|
||||||
|
break;
|
||||||
|
case READ_ELEMENT_STATUS:
|
||||||
|
cmd->xfer = buf[9] | (buf[8] << 8) | (buf[7] << 16);
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* generic commands */
|
||||||
|
default:
|
||||||
|
return scsi_req_length(cmd, dev, buf);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void scsi_cmd_xfer_mode(SCSICommand *cmd)
|
static void scsi_cmd_xfer_mode(SCSICommand *cmd)
|
||||||
{
|
{
|
||||||
if (!cmd->xfer) {
|
if (!cmd->xfer) {
|
||||||
@ -1001,11 +1029,36 @@ int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
|
|||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (dev->type == TYPE_TAPE) {
|
switch (buf[0] >> 5) {
|
||||||
rc = scsi_req_stream_length(cmd, dev, buf);
|
case 0:
|
||||||
} else {
|
cmd->len = 6;
|
||||||
rc = scsi_req_length(cmd, dev, buf);
|
break;
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
cmd->len = 10;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
cmd->len = 16;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
cmd->len = 12;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (dev->type) {
|
||||||
|
case TYPE_TAPE:
|
||||||
|
rc = scsi_req_stream_length(cmd, dev, buf);
|
||||||
|
break;
|
||||||
|
case TYPE_MEDIUM_CHANGER:
|
||||||
|
rc = scsi_req_medium_changer_length(cmd, dev, buf);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
rc = scsi_req_length(cmd, dev, buf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
@ -1183,7 +1236,8 @@ static const char *scsi_command_name(uint8_t cmd)
|
|||||||
[ REQUEST_SENSE ] = "REQUEST_SENSE",
|
[ REQUEST_SENSE ] = "REQUEST_SENSE",
|
||||||
[ FORMAT_UNIT ] = "FORMAT_UNIT",
|
[ FORMAT_UNIT ] = "FORMAT_UNIT",
|
||||||
[ READ_BLOCK_LIMITS ] = "READ_BLOCK_LIMITS",
|
[ READ_BLOCK_LIMITS ] = "READ_BLOCK_LIMITS",
|
||||||
[ REASSIGN_BLOCKS ] = "REASSIGN_BLOCKS",
|
[ REASSIGN_BLOCKS ] = "REASSIGN_BLOCKS/INITIALIZE ELEMENT STATUS",
|
||||||
|
/* LOAD_UNLOAD and INITIALIZE_ELEMENT_STATUS use the same operation code */
|
||||||
[ READ_6 ] = "READ_6",
|
[ READ_6 ] = "READ_6",
|
||||||
[ WRITE_6 ] = "WRITE_6",
|
[ WRITE_6 ] = "WRITE_6",
|
||||||
[ SET_CAPACITY ] = "SET_CAPACITY",
|
[ SET_CAPACITY ] = "SET_CAPACITY",
|
||||||
@ -1200,14 +1254,16 @@ static const char *scsi_command_name(uint8_t cmd)
|
|||||||
[ COPY ] = "COPY",
|
[ COPY ] = "COPY",
|
||||||
[ ERASE ] = "ERASE",
|
[ ERASE ] = "ERASE",
|
||||||
[ MODE_SENSE ] = "MODE_SENSE",
|
[ MODE_SENSE ] = "MODE_SENSE",
|
||||||
[ START_STOP ] = "START_STOP",
|
[ START_STOP ] = "START_STOP/LOAD_UNLOAD",
|
||||||
|
/* LOAD_UNLOAD and START_STOP use the same operation code */
|
||||||
[ RECEIVE_DIAGNOSTIC ] = "RECEIVE_DIAGNOSTIC",
|
[ RECEIVE_DIAGNOSTIC ] = "RECEIVE_DIAGNOSTIC",
|
||||||
[ SEND_DIAGNOSTIC ] = "SEND_DIAGNOSTIC",
|
[ SEND_DIAGNOSTIC ] = "SEND_DIAGNOSTIC",
|
||||||
[ ALLOW_MEDIUM_REMOVAL ] = "ALLOW_MEDIUM_REMOVAL",
|
[ ALLOW_MEDIUM_REMOVAL ] = "ALLOW_MEDIUM_REMOVAL",
|
||||||
[ READ_CAPACITY_10 ] = "READ_CAPACITY_10",
|
[ READ_CAPACITY_10 ] = "READ_CAPACITY_10",
|
||||||
[ READ_10 ] = "READ_10",
|
[ READ_10 ] = "READ_10",
|
||||||
[ WRITE_10 ] = "WRITE_10",
|
[ WRITE_10 ] = "WRITE_10",
|
||||||
[ SEEK_10 ] = "SEEK_10",
|
[ SEEK_10 ] = "SEEK_10/POSITION_TO_ELEMENT",
|
||||||
|
/* SEEK_10 and POSITION_TO_ELEMENT use the same operation code */
|
||||||
[ WRITE_VERIFY_10 ] = "WRITE_VERIFY_10",
|
[ WRITE_VERIFY_10 ] = "WRITE_VERIFY_10",
|
||||||
[ VERIFY_10 ] = "VERIFY_10",
|
[ VERIFY_10 ] = "VERIFY_10",
|
||||||
[ SEARCH_HIGH ] = "SEARCH_HIGH",
|
[ SEARCH_HIGH ] = "SEARCH_HIGH",
|
||||||
@ -1218,7 +1274,8 @@ static const char *scsi_command_name(uint8_t cmd)
|
|||||||
/* 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",
|
||||||
[ READ_DEFECT_DATA ] = "READ_DEFECT_DATA",
|
[ READ_DEFECT_DATA ] = "READ_DEFECT_DATA/INITIALIZE_ELEMENT_STATUS_WITH_RANGE",
|
||||||
|
/* READ_DEFECT_DATA and INITIALIZE_ELEMENT_STATUS_WITH_RANGE use the same operation code */
|
||||||
[ MEDIUM_SCAN ] = "MEDIUM_SCAN",
|
[ MEDIUM_SCAN ] = "MEDIUM_SCAN",
|
||||||
[ COMPARE ] = "COMPARE",
|
[ COMPARE ] = "COMPARE",
|
||||||
[ COPY_VERIFY ] = "COPY_VERIFY",
|
[ COPY_VERIFY ] = "COPY_VERIFY",
|
||||||
@ -1263,6 +1320,7 @@ static const char *scsi_command_name(uint8_t cmd)
|
|||||||
[ REPORT_LUNS ] = "REPORT_LUNS",
|
[ REPORT_LUNS ] = "REPORT_LUNS",
|
||||||
[ BLANK ] = "BLANK",
|
[ BLANK ] = "BLANK",
|
||||||
[ MOVE_MEDIUM ] = "MOVE_MEDIUM",
|
[ MOVE_MEDIUM ] = "MOVE_MEDIUM",
|
||||||
|
[ EXCHANGE_MEDIUM ] = "EXCHANGE MEDIUM",
|
||||||
[ LOAD_UNLOAD ] = "LOAD_UNLOAD",
|
[ LOAD_UNLOAD ] = "LOAD_UNLOAD",
|
||||||
[ READ_12 ] = "READ_12",
|
[ READ_12 ] = "READ_12",
|
||||||
[ WRITE_12 ] = "WRITE_12",
|
[ WRITE_12 ] = "WRITE_12",
|
||||||
@ -1389,7 +1447,7 @@ void scsi_req_complete(SCSIRequest *req, int status)
|
|||||||
assert(req->status == -1);
|
assert(req->status == -1);
|
||||||
req->status = status;
|
req->status = status;
|
||||||
|
|
||||||
assert(req->sense_len < sizeof(req->sense));
|
assert(req->sense_len <= sizeof(req->sense));
|
||||||
if (status == GOOD) {
|
if (status == GOOD) {
|
||||||
req->sense_len = 0;
|
req->sense_len = 0;
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#define REQUEST_SENSE 0x03
|
#define REQUEST_SENSE 0x03
|
||||||
#define FORMAT_UNIT 0x04
|
#define FORMAT_UNIT 0x04
|
||||||
#define READ_BLOCK_LIMITS 0x05
|
#define READ_BLOCK_LIMITS 0x05
|
||||||
|
#define INITIALIZE_ELEMENT_STATUS 0x07
|
||||||
#define REASSIGN_BLOCKS 0x07
|
#define REASSIGN_BLOCKS 0x07
|
||||||
#define READ_6 0x08
|
#define READ_6 0x08
|
||||||
#define WRITE_6 0x0a
|
#define WRITE_6 0x0a
|
||||||
@ -44,6 +45,7 @@
|
|||||||
#define COPY 0x18
|
#define COPY 0x18
|
||||||
#define ERASE 0x19
|
#define ERASE 0x19
|
||||||
#define MODE_SENSE 0x1a
|
#define MODE_SENSE 0x1a
|
||||||
|
#define LOAD_UNLOAD 0x1b
|
||||||
#define START_STOP 0x1b
|
#define START_STOP 0x1b
|
||||||
#define RECEIVE_DIAGNOSTIC 0x1c
|
#define RECEIVE_DIAGNOSTIC 0x1c
|
||||||
#define SEND_DIAGNOSTIC 0x1d
|
#define SEND_DIAGNOSTIC 0x1d
|
||||||
@ -53,6 +55,7 @@
|
|||||||
#define WRITE_10 0x2a
|
#define WRITE_10 0x2a
|
||||||
#define SEEK_10 0x2b
|
#define SEEK_10 0x2b
|
||||||
#define LOCATE_10 0x2b
|
#define LOCATE_10 0x2b
|
||||||
|
#define POSITION_TO_ELEMENT 0x2b
|
||||||
#define WRITE_VERIFY_10 0x2e
|
#define WRITE_VERIFY_10 0x2e
|
||||||
#define VERIFY_10 0x2f
|
#define VERIFY_10 0x2f
|
||||||
#define SEARCH_HIGH 0x30
|
#define SEARCH_HIGH 0x30
|
||||||
@ -63,6 +66,7 @@
|
|||||||
#define READ_POSITION 0x34
|
#define READ_POSITION 0x34
|
||||||
#define SYNCHRONIZE_CACHE 0x35
|
#define SYNCHRONIZE_CACHE 0x35
|
||||||
#define LOCK_UNLOCK_CACHE 0x36
|
#define LOCK_UNLOCK_CACHE 0x36
|
||||||
|
#define INITIALIZE_ELEMENT_STATUS_WITH_RANGE 0x37
|
||||||
#define READ_DEFECT_DATA 0x37
|
#define READ_DEFECT_DATA 0x37
|
||||||
#define MEDIUM_SCAN 0x38
|
#define MEDIUM_SCAN 0x38
|
||||||
#define COMPARE 0x39
|
#define COMPARE 0x39
|
||||||
@ -82,6 +86,7 @@
|
|||||||
#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 READ_DISC_INFORMATION 0x51
|
||||||
#define RESERVE_TRACK 0x53
|
#define RESERVE_TRACK 0x53
|
||||||
#define MODE_SELECT_10 0x55
|
#define MODE_SELECT_10 0x55
|
||||||
#define RESERVE_10 0x56
|
#define RESERVE_10 0x56
|
||||||
@ -116,7 +121,7 @@
|
|||||||
#define MAINTENANCE_IN 0xa3
|
#define MAINTENANCE_IN 0xa3
|
||||||
#define MAINTENANCE_OUT 0xa4
|
#define MAINTENANCE_OUT 0xa4
|
||||||
#define MOVE_MEDIUM 0xa5
|
#define MOVE_MEDIUM 0xa5
|
||||||
#define LOAD_UNLOAD 0xa6
|
#define EXCHANGE_MEDIUM 0xa6
|
||||||
#define SET_READ_AHEAD 0xa7
|
#define SET_READ_AHEAD 0xa7
|
||||||
#define READ_12 0xa8
|
#define READ_12 0xa8
|
||||||
#define WRITE_12 0xaa
|
#define WRITE_12 0xaa
|
||||||
@ -141,6 +146,14 @@
|
|||||||
*/
|
*/
|
||||||
#define SAI_READ_CAPACITY_16 0x10
|
#define SAI_READ_CAPACITY_16 0x10
|
||||||
|
|
||||||
|
/*
|
||||||
|
* READ POSITION service action codes
|
||||||
|
*/
|
||||||
|
#define SHORT_FORM_BLOCK_ID 0x00
|
||||||
|
#define SHORT_FORM_VENDOR_SPECIFIC 0x01
|
||||||
|
#define LONG_FORM 0x06
|
||||||
|
#define EXTENDED_FORM 0x08
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SAM Status codes
|
* SAM Status codes
|
||||||
*/
|
*/
|
||||||
|
@ -67,6 +67,7 @@ struct SCSIDiskState
|
|||||||
bool media_changed;
|
bool media_changed;
|
||||||
bool media_event;
|
bool media_event;
|
||||||
bool eject_request;
|
bool eject_request;
|
||||||
|
uint64_t wwn;
|
||||||
QEMUBH *bh;
|
QEMUBH *bh;
|
||||||
char *version;
|
char *version;
|
||||||
char *serial;
|
char *serial;
|
||||||
@ -522,6 +523,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
|
|||||||
{
|
{
|
||||||
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
|
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
|
||||||
int buflen = 0;
|
int buflen = 0;
|
||||||
|
int start;
|
||||||
|
|
||||||
if (req->cmd.buf[1] & 0x1) {
|
if (req->cmd.buf[1] & 0x1) {
|
||||||
/* Vital product data */
|
/* Vital product data */
|
||||||
@ -530,14 +532,14 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
|
|||||||
outbuf[buflen++] = s->qdev.type & 0x1f;
|
outbuf[buflen++] = s->qdev.type & 0x1f;
|
||||||
outbuf[buflen++] = page_code ; // this page
|
outbuf[buflen++] = page_code ; // this page
|
||||||
outbuf[buflen++] = 0x00;
|
outbuf[buflen++] = 0x00;
|
||||||
|
outbuf[buflen++] = 0x00;
|
||||||
|
start = buflen;
|
||||||
|
|
||||||
switch (page_code) {
|
switch (page_code) {
|
||||||
case 0x00: /* Supported page codes, mandatory */
|
case 0x00: /* Supported page codes, mandatory */
|
||||||
{
|
{
|
||||||
int pages;
|
|
||||||
DPRINTF("Inquiry EVPD[Supported pages] "
|
DPRINTF("Inquiry EVPD[Supported pages] "
|
||||||
"buffer size %zd\n", req->cmd.xfer);
|
"buffer size %zd\n", req->cmd.xfer);
|
||||||
pages = buflen++;
|
|
||||||
outbuf[buflen++] = 0x00; // list of supported pages (this page)
|
outbuf[buflen++] = 0x00; // list of supported pages (this page)
|
||||||
if (s->serial) {
|
if (s->serial) {
|
||||||
outbuf[buflen++] = 0x80; // unit serial number
|
outbuf[buflen++] = 0x80; // unit serial number
|
||||||
@ -547,7 +549,6 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
|
|||||||
outbuf[buflen++] = 0xb0; // block limits
|
outbuf[buflen++] = 0xb0; // block limits
|
||||||
outbuf[buflen++] = 0xb2; // thin provisioning
|
outbuf[buflen++] = 0xb2; // thin provisioning
|
||||||
}
|
}
|
||||||
outbuf[pages] = buflen - pages - 1; // number of pages
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0x80: /* Device serial number, optional */
|
case 0x80: /* Device serial number, optional */
|
||||||
@ -566,7 +567,6 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
|
|||||||
|
|
||||||
DPRINTF("Inquiry EVPD[Serial number] "
|
DPRINTF("Inquiry EVPD[Serial number] "
|
||||||
"buffer size %zd\n", req->cmd.xfer);
|
"buffer size %zd\n", req->cmd.xfer);
|
||||||
outbuf[buflen++] = l;
|
|
||||||
memcpy(outbuf+buflen, s->serial, l);
|
memcpy(outbuf+buflen, s->serial, l);
|
||||||
buflen += l;
|
buflen += l;
|
||||||
break;
|
break;
|
||||||
@ -584,14 +584,21 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
|
|||||||
DPRINTF("Inquiry EVPD[Device identification] "
|
DPRINTF("Inquiry EVPD[Device identification] "
|
||||||
"buffer size %zd\n", req->cmd.xfer);
|
"buffer size %zd\n", req->cmd.xfer);
|
||||||
|
|
||||||
outbuf[buflen++] = 4 + id_len;
|
|
||||||
outbuf[buflen++] = 0x2; // ASCII
|
outbuf[buflen++] = 0x2; // ASCII
|
||||||
outbuf[buflen++] = 0; // not officially assigned
|
outbuf[buflen++] = 0; // not officially assigned
|
||||||
outbuf[buflen++] = 0; // reserved
|
outbuf[buflen++] = 0; // reserved
|
||||||
outbuf[buflen++] = id_len; // length of data following
|
outbuf[buflen++] = id_len; // length of data following
|
||||||
|
|
||||||
memcpy(outbuf+buflen, str, id_len);
|
memcpy(outbuf+buflen, str, id_len);
|
||||||
buflen += id_len;
|
buflen += id_len;
|
||||||
|
|
||||||
|
if (s->wwn) {
|
||||||
|
outbuf[buflen++] = 0x1; // Binary
|
||||||
|
outbuf[buflen++] = 0x3; // NAA
|
||||||
|
outbuf[buflen++] = 0; // reserved
|
||||||
|
outbuf[buflen++] = 8;
|
||||||
|
stq_be_p(&outbuf[buflen], s->wwn);
|
||||||
|
buflen += 8;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0xb0: /* block limits */
|
case 0xb0: /* block limits */
|
||||||
@ -609,8 +616,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/* required VPD size with unmap support */
|
/* required VPD size with unmap support */
|
||||||
outbuf[3] = buflen = 0x3c;
|
buflen = 0x40;
|
||||||
|
|
||||||
memset(outbuf + 4, 0, buflen - 4);
|
memset(outbuf + 4, 0, buflen - 4);
|
||||||
|
|
||||||
/* optimal transfer length granularity */
|
/* optimal transfer length granularity */
|
||||||
@ -632,7 +638,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
|
|||||||
}
|
}
|
||||||
case 0xb2: /* thin provisioning */
|
case 0xb2: /* thin provisioning */
|
||||||
{
|
{
|
||||||
outbuf[3] = buflen = 8;
|
buflen = 8;
|
||||||
outbuf[4] = 0;
|
outbuf[4] = 0;
|
||||||
outbuf[5] = 0x60; /* write_same 10/16 supported */
|
outbuf[5] = 0x60; /* write_same 10/16 supported */
|
||||||
outbuf[6] = s->qdev.conf.discard_granularity ? 2 : 1;
|
outbuf[6] = s->qdev.conf.discard_granularity ? 2 : 1;
|
||||||
@ -643,6 +649,8 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/* done with EVPD */
|
/* done with EVPD */
|
||||||
|
assert(buflen - start <= 255);
|
||||||
|
outbuf[start - 1] = buflen - start;
|
||||||
return buflen;
|
return buflen;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -716,6 +724,39 @@ static inline bool media_is_cd(SCSIDiskState *s)
|
|||||||
return nb_sectors <= CD_MAX_SECTORS;
|
return nb_sectors <= CD_MAX_SECTORS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int scsi_read_disc_information(SCSIDiskState *s, SCSIDiskReq *r,
|
||||||
|
uint8_t *outbuf)
|
||||||
|
{
|
||||||
|
uint8_t type = r->req.cmd.buf[1] & 7;
|
||||||
|
|
||||||
|
if (s->qdev.type != TYPE_ROM) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Types 1/2 are only defined for Blu-Ray. */
|
||||||
|
if (type != 0) {
|
||||||
|
scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(outbuf, 0, 34);
|
||||||
|
outbuf[1] = 32;
|
||||||
|
outbuf[2] = 0xe; /* last session complete, disc finalized */
|
||||||
|
outbuf[3] = 1; /* first track on disc */
|
||||||
|
outbuf[4] = 1; /* # of sessions */
|
||||||
|
outbuf[5] = 1; /* first track of last session */
|
||||||
|
outbuf[6] = 1; /* last track of last session */
|
||||||
|
outbuf[7] = 0x20; /* unrestricted use */
|
||||||
|
outbuf[8] = 0x00; /* CD-ROM or DVD-ROM */
|
||||||
|
/* 9-10-11: most significant byte corresponding bytes 4-5-6 */
|
||||||
|
/* 12-23: not meaningful for CD-ROM or DVD-ROM */
|
||||||
|
/* 24-31: disc bar code */
|
||||||
|
/* 32: disc application code */
|
||||||
|
/* 33: number of OPC tables */
|
||||||
|
|
||||||
|
return 34;
|
||||||
|
}
|
||||||
|
|
||||||
static int scsi_read_dvd_structure(SCSIDiskState *s, SCSIDiskReq *r,
|
static int scsi_read_dvd_structure(SCSIDiskState *s, SCSIDiskReq *r,
|
||||||
uint8_t *outbuf)
|
uint8_t *outbuf)
|
||||||
{
|
{
|
||||||
@ -1355,6 +1396,12 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
|
|||||||
goto illegal_request;
|
goto illegal_request;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case READ_DISC_INFORMATION:
|
||||||
|
buflen = scsi_read_disc_information(s, r, outbuf);
|
||||||
|
if (buflen < 0) {
|
||||||
|
goto illegal_request;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case READ_DVD_STRUCTURE:
|
case READ_DVD_STRUCTURE:
|
||||||
buflen = scsi_read_dvd_structure(s, r, outbuf);
|
buflen = scsi_read_dvd_structure(s, r, outbuf);
|
||||||
if (buflen < 0) {
|
if (buflen < 0) {
|
||||||
@ -1482,6 +1529,7 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
|
|||||||
case ALLOW_MEDIUM_REMOVAL:
|
case ALLOW_MEDIUM_REMOVAL:
|
||||||
case READ_CAPACITY_10:
|
case READ_CAPACITY_10:
|
||||||
case READ_TOC:
|
case READ_TOC:
|
||||||
|
case READ_DISC_INFORMATION:
|
||||||
case READ_DVD_STRUCTURE:
|
case READ_DVD_STRUCTURE:
|
||||||
case GET_CONFIGURATION:
|
case GET_CONFIGURATION:
|
||||||
case GET_EVENT_STATUS_NOTIFICATION:
|
case GET_EVENT_STATUS_NOTIFICATION:
|
||||||
@ -1925,6 +1973,7 @@ static Property scsi_hd_properties[] = {
|
|||||||
SCSI_DISK_F_REMOVABLE, false),
|
SCSI_DISK_F_REMOVABLE, false),
|
||||||
DEFINE_PROP_BIT("dpofua", SCSIDiskState, features,
|
DEFINE_PROP_BIT("dpofua", SCSIDiskState, features,
|
||||||
SCSI_DISK_F_DPOFUA, false),
|
SCSI_DISK_F_DPOFUA, false),
|
||||||
|
DEFINE_PROP_HEX64("wwn", SCSIDiskState, wwn, 0),
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1969,6 +2018,7 @@ static TypeInfo scsi_hd_info = {
|
|||||||
|
|
||||||
static Property scsi_cd_properties[] = {
|
static Property scsi_cd_properties[] = {
|
||||||
DEFINE_SCSI_DISK_PROPERTIES(),
|
DEFINE_SCSI_DISK_PROPERTIES(),
|
||||||
|
DEFINE_PROP_HEX64("wwn", SCSIDiskState, wwn, 0),
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2030,6 +2080,7 @@ static Property scsi_disk_properties[] = {
|
|||||||
SCSI_DISK_F_REMOVABLE, false),
|
SCSI_DISK_F_REMOVABLE, false),
|
||||||
DEFINE_PROP_BIT("dpofua", SCSIDiskState, features,
|
DEFINE_PROP_BIT("dpofua", SCSIDiskState, features,
|
||||||
SCSI_DISK_F_DPOFUA, false),
|
SCSI_DISK_F_DPOFUA, false),
|
||||||
|
DEFINE_PROP_HEX64("wwn", SCSIDiskState, wwn, 0),
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -400,12 +400,6 @@ static int scsi_generic_initfn(SCSIDevice *s)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check we are really using a /dev/sg* file */
|
|
||||||
if (!bdrv_is_sg(s->conf.bs)) {
|
|
||||||
error_report("not /dev/sg*");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bdrv_get_on_error(s->conf.bs, 0) != BLOCK_ERR_STOP_ENOSPC) {
|
if (bdrv_get_on_error(s->conf.bs, 0) != BLOCK_ERR_STOP_ENOSPC) {
|
||||||
error_report("Device doesn't support drive option werror");
|
error_report("Device doesn't support drive option werror");
|
||||||
return -1;
|
return -1;
|
||||||
@ -416,8 +410,11 @@ static int scsi_generic_initfn(SCSIDevice *s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* check we are using a driver managing SG_IO (version 3 and after */
|
/* check we are using a driver managing SG_IO (version 3 and after */
|
||||||
if (bdrv_ioctl(s->conf.bs, SG_GET_VERSION_NUM, &sg_version) < 0 ||
|
if (bdrv_ioctl(s->conf.bs, SG_GET_VERSION_NUM, &sg_version) < 0) {
|
||||||
sg_version < 30000) {
|
error_report("scsi generic interface not supported");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (sg_version < 30000) {
|
||||||
error_report("scsi generic interface too old");
|
error_report("scsi generic interface too old");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -405,6 +405,10 @@ static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void virtio_scsi_handle_event(VirtIODevice *vdev, VirtQueue *vq)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status,
|
static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status,
|
||||||
size_t resid)
|
size_t resid)
|
||||||
{
|
{
|
||||||
@ -609,7 +613,7 @@ VirtIODevice *virtio_scsi_init(DeviceState *dev, VirtIOSCSIConf *proxyconf)
|
|||||||
s->ctrl_vq = virtio_add_queue(&s->vdev, VIRTIO_SCSI_VQ_SIZE,
|
s->ctrl_vq = virtio_add_queue(&s->vdev, VIRTIO_SCSI_VQ_SIZE,
|
||||||
virtio_scsi_handle_ctrl);
|
virtio_scsi_handle_ctrl);
|
||||||
s->event_vq = virtio_add_queue(&s->vdev, VIRTIO_SCSI_VQ_SIZE,
|
s->event_vq = virtio_add_queue(&s->vdev, VIRTIO_SCSI_VQ_SIZE,
|
||||||
NULL);
|
virtio_scsi_handle_event);
|
||||||
for (i = 0; i < s->conf->num_queues; i++) {
|
for (i = 0; i < s->conf->num_queues; i++) {
|
||||||
s->cmd_vqs[i] = virtio_add_queue(&s->vdev, VIRTIO_SCSI_VQ_SIZE,
|
s->cmd_vqs[i] = virtio_add_queue(&s->vdev, VIRTIO_SCSI_VQ_SIZE,
|
||||||
virtio_scsi_handle_cmd);
|
virtio_scsi_handle_cmd);
|
||||||
|
79
trace-events
79
trace-events
@ -512,6 +512,85 @@ lm32_uart_irq_state(int level) "irq state %d"
|
|||||||
# hw/lm32_sys.c
|
# hw/lm32_sys.c
|
||||||
lm32_sys_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
|
lm32_sys_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
|
||||||
|
|
||||||
|
# hw/megasas.c
|
||||||
|
megasas_init_firmware(uint64_t pa) "pa %" PRIx64 " "
|
||||||
|
megasas_init_queue(uint64_t queue_pa, int queue_len, uint64_t head, uint64_t tail, uint32_t flags) "queue at %" PRIx64 " len %d head %" PRIx64 " tail %" PRIx64 " flags %x"
|
||||||
|
megasas_initq_map_failed(int frame) "scmd %d: failed to map queue"
|
||||||
|
megasas_initq_mismatch(int queue_len, int fw_cmds) "queue size %d max fw cmds %d"
|
||||||
|
megasas_qf_found(unsigned int index, uint64_t pa) "found mapped frame %x pa %" PRIx64 ""
|
||||||
|
megasas_qf_new(unsigned int index, void *cmd) "return new frame %x cmd %p"
|
||||||
|
megasas_qf_failed(unsigned long pa) "all frames busy for frame %lx"
|
||||||
|
megasas_qf_enqueue(unsigned int index, unsigned int count, uint64_t context, unsigned int tail, int busy) "enqueue frame %x count %d context %" PRIx64 " tail %x busy %d"
|
||||||
|
megasas_qf_update(unsigned int head, unsigned int busy) "update reply queue head %x busy %d"
|
||||||
|
megasas_qf_dequeue(unsigned int index) "dequeue frame %x"
|
||||||
|
megasas_qf_map_failed(int cmd, unsigned long frame) "scmd %d: frame %lu"
|
||||||
|
megasas_qf_complete_noirq(uint64_t context) "context %" PRIx64 " "
|
||||||
|
megasas_qf_complete(uint64_t context, unsigned int tail, unsigned int offset, int busy, unsigned int doorbell) "context %" PRIx64 " tail %x offset %d busy %d doorbell %x"
|
||||||
|
megasas_handle_frame(const char *cmd, uint64_t addr, uint64_t context, uint32_t count) "MFI cmd %s addr %" PRIx64 " context %" PRIx64 " count %d"
|
||||||
|
megasas_frame_busy(uint64_t addr) "frame %" PRIx64 " busy"
|
||||||
|
megasas_unhandled_frame_cmd(int cmd, uint8_t frame_cmd) "scmd %d: Unhandled MFI cmd %x"
|
||||||
|
megasas_handle_scsi(const char *frame, int bus, int dev, int lun, void *sdev, unsigned long size) "%s dev %x/%x/%x sdev %p xfer %lu"
|
||||||
|
megasas_scsi_target_not_present(const char *frame, int bus, int dev, int lun) "%s dev %x/%x/%x target not present"
|
||||||
|
megasas_scsi_invalid_cdb_len(const char *frame, int bus, int dev, int lun, int len) "%s dev %x/%x/%x invalid cdb len %d"
|
||||||
|
megasas_iov_read_overflow(int cmd, int bytes, int len) "scmd %d: %d/%d bytes"
|
||||||
|
megasas_iov_write_overflow(int cmd, int bytes, int len) "scmd %d: %d/%d bytes"
|
||||||
|
megasas_iov_read_underflow(int cmd, int bytes, int len) "scmd %d: %d/%d bytes"
|
||||||
|
megasas_iov_write_underflow(int cmd, int bytes, int len) "scmd %d: %d/%d bytes"
|
||||||
|
megasas_scsi_req_alloc_failed(const char *frame, int dev, int lun) "%s dev %x/%x req allocation failed"
|
||||||
|
megasas_scsi_read_start(int cmd, int len) "scmd %d: transfer %d bytes of data"
|
||||||
|
megasas_scsi_write_start(int cmd, int len) "scmd %d: transfer %d bytes of data"
|
||||||
|
megasas_scsi_nodata(int cmd) "scmd %d: no data to be transferred"
|
||||||
|
megasas_scsi_complete(int cmd, uint32_t status, int len, int xfer) "scmd %d: finished with status %x, len %u/%u"
|
||||||
|
megasas_command_complete(int cmd, uint32_t status, uint32_t resid) "scmd %d: command completed, status %x, residual %d"
|
||||||
|
megasas_handle_io(int cmd, const char *frame, int dev, int lun, unsigned long lba, unsigned long count) "scmd %d: %s dev %x/%x lba %lx count %lu"
|
||||||
|
megasas_io_target_not_present(int cmd, const char *frame, int dev, int lun) "scmd %d: %s dev 1/%x/%x LUN not present"
|
||||||
|
megasas_io_read_start(int cmd, unsigned long lba, unsigned long count, unsigned long len) "scmd %d: start LBA %lx %lu blocks (%lu bytes)"
|
||||||
|
megasas_io_write_start(int cmd, unsigned long lba, unsigned long count, unsigned long len) "scmd %d: start LBA %lx %lu blocks (%lu bytes)"
|
||||||
|
megasas_io_complete(int cmd, uint32_t len) "scmd %d: %d bytes completed"
|
||||||
|
megasas_io_read(int cmd, int bytes, int len, unsigned long offset) "scmd %d: %d/%d bytes, iov offset %lu"
|
||||||
|
megasas_io_write(int cmd, int bytes, int len, unsigned long offset) "scmd %d: %d/%d bytes, iov offset %lu"
|
||||||
|
megasas_io_continue(int cmd, int bytes) "scmd %d: %d bytes left"
|
||||||
|
megasas_iovec_map_failed(int cmd, int index, unsigned long iov_size) "scmd %d: iovec %d size %lu"
|
||||||
|
megasas_iovec_sgl_overflow(int cmd, int index, int limit) "scmd %d: iovec count %d limit %d"
|
||||||
|
megasas_iovec_sgl_underflow(int cmd, int index) "scmd %d: iovec count %d"
|
||||||
|
megasas_iovec_sgl_invalid(int cmd, int index, uint64_t pa, uint32_t len) "scmd %d: element %d pa %" PRIx64 " len %u"
|
||||||
|
megasas_iovec_overflow(int cmd, int len, int limit) "scmd %d: len %d limit %d"
|
||||||
|
megasas_iovec_underflow(int cmd, int len, int limit) "scmd %d: len %d limit %d"
|
||||||
|
megasas_handle_dcmd(int cmd, int opcode) "scmd %d: MFI DCMD opcode %x"
|
||||||
|
megasas_finish_dcmd(int cmd, int size) "scmd %d: MFI DCMD wrote %d bytes"
|
||||||
|
megasas_dcmd_req_alloc_failed(int cmd, const char *desc) "scmd %d: %s alloc failed"
|
||||||
|
megasas_dcmd_internal_submit(int cmd, const char *desc, int dev) "scmd %d: %s to dev %d"
|
||||||
|
megasas_dcmd_internal_finish(int cmd, int opcode, int lun) "scmd %d: DCMD finish internal cmd %x lun %d"
|
||||||
|
megasas_dcmd_internal_invalid(int cmd, int opcode) "scmd %d: Invalid internal DCMD %x"
|
||||||
|
megasas_dcmd_unhandled(int cmd, int opcode, int len) "scmd %d: opcode %x, len %d"
|
||||||
|
megasas_dcmd_zero_sge(int cmd) "scmd %d: zero DCMD sge count"
|
||||||
|
megasas_dcmd_invalid_sge(int cmd, int count) "scmd %d: invalid DCMD sge count %d"
|
||||||
|
megasas_dcmd_map_failed(int cmd) "scmd %d: Failed to map DCMD buffer"
|
||||||
|
megasas_dcmd_invalid_xfer_len(int cmd, unsigned long size, unsigned long max) "scmd %d: invalid xfer len %ld, max %ld"
|
||||||
|
megasas_dcmd_enter(int cmd, const char *dcmd, int len) "scmd %d: DCMD %s len %d"
|
||||||
|
megasas_dcmd_dummy(int cmd, unsigned long size) "scmd %d: DCMD dummy xfer len %ld"
|
||||||
|
megasas_dcmd_set_fw_time(int cmd, unsigned long time) "scmd %d: Set FW time %lx"
|
||||||
|
megasas_dcmd_pd_get_list(int cmd, int num, int max, int offset) "scmd %d: DCMD PD get list: %d / %d PDs, size %d"
|
||||||
|
megasas_dcmd_ld_get_list(int cmd, int num, int max) "scmd %d: DCMD LD get list: found %d / %d LDs"
|
||||||
|
megasas_dcmd_ld_get_info(int cmd, int ld_id) "scmd %d: DCMD LD get info for dev %d"
|
||||||
|
megasas_dcmd_pd_get_info(int cmd, int pd_id) "scmd %d: DCMD PD get info for dev %d"
|
||||||
|
megasas_dcmd_pd_list_query(int cmd, int flags) "scmd %d: DCMD PD list query flags %x"
|
||||||
|
megasas_dcmd_dump_frame(int offset, char f0, char f1, char f2, char f3, char f4, char f5, char f6, char f7) "0x%x: %02x %02x %02x %02x %02x %02x %02x %02x"
|
||||||
|
megasas_abort_frame(int cmd, int abort_cmd) "scmd %d: aborting frame %x"
|
||||||
|
megasas_abort_no_cmd(int cmd, uint64_t context) "scmd %d: no active command for frame context %" PRIx64 ""
|
||||||
|
megasas_abort_invalid_context(int cmd, uint64_t context, int abort_cmd) "scmd %d: invalid frame context %" PRIx64 " for abort frame %x"
|
||||||
|
megasas_reset(void) "Reset"
|
||||||
|
megasas_init(int sges, int cmds, const char *intr, const char *mode) "Using %d sges, %d cmds, %s, %s mode"
|
||||||
|
megasas_msix_raise(int vector) "vector %d"
|
||||||
|
megasas_irq_lower(void) "INTx"
|
||||||
|
megasas_irq_raise(void) "INTx"
|
||||||
|
megasas_intr_enabled(void) "Interrupts enabled"
|
||||||
|
megasas_intr_disabled(void) "Interrupts disabled"
|
||||||
|
megasas_mmio_readl(unsigned long addr, uint32_t val) "addr 0x%lx: 0x%x"
|
||||||
|
megasas_mmio_invalid_readl(unsigned long addr) "addr 0x%lx"
|
||||||
|
megasas_mmio_writel(uint32_t addr, uint32_t val) "addr 0x%x: 0x%x"
|
||||||
|
megasas_mmio_invalid_writel(uint32_t addr, uint32_t val) "addr 0x%x: 0x%x"
|
||||||
|
|
||||||
# hw/milkymist-ac97.c
|
# hw/milkymist-ac97.c
|
||||||
milkymist_ac97_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
|
milkymist_ac97_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
|
||||||
milkymist_ac97_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
|
milkymist_ac97_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
|
||||||
|
Loading…
Reference in New Issue
Block a user