Merge remote-tracking branch 'bonzini/scsi-next' into staging
* bonzini/scsi-next: scsi: add support for ATA_PASSTHROUGH_xx scsi command esp: add missing const on TypeInfo structures esp: enable for all PCI machines Revert "megasas: disable due to build breakage" megasas: static SAS addresses scsi-disk: fix compilation with DEBUG_SCSI megasas: Update function megasys_scsi_uninit SCSI: STARTSTOPUNIT only eject/load media if powercondition is 0 SCSI: Update the sense code for PREVENT REMOVAL errors
This commit is contained in:
commit
b34bd5e5c8
@ -25,4 +25,3 @@ CONFIG_HPET=y
|
|||||||
CONFIG_APPLESMC=y
|
CONFIG_APPLESMC=y
|
||||||
CONFIG_I8259=y
|
CONFIG_I8259=y
|
||||||
CONFIG_PFLASH_CFI01=y
|
CONFIG_PFLASH_CFI01=y
|
||||||
CONFIG_ESP=y
|
|
||||||
|
@ -10,9 +10,11 @@ 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
|
||||||
CONFIG_IDE_QDEV=y
|
CONFIG_IDE_QDEV=y
|
||||||
CONFIG_IDE_PCI=y
|
CONFIG_IDE_PCI=y
|
||||||
CONFIG_AHCI=y
|
CONFIG_AHCI=y
|
||||||
|
CONFIG_ESP=y
|
||||||
|
4
hw/esp.c
4
hw/esp.c
@ -816,7 +816,7 @@ static void sysbus_esp_class_init(ObjectClass *klass, void *data)
|
|||||||
dc->vmsd = &vmstate_sysbus_esp_scsi;
|
dc->vmsd = &vmstate_sysbus_esp_scsi;
|
||||||
}
|
}
|
||||||
|
|
||||||
static TypeInfo sysbus_esp_info = {
|
static const TypeInfo sysbus_esp_info = {
|
||||||
.name = "esp",
|
.name = "esp",
|
||||||
.parent = TYPE_SYS_BUS_DEVICE,
|
.parent = TYPE_SYS_BUS_DEVICE,
|
||||||
.instance_size = sizeof(SysBusESPState),
|
.instance_size = sizeof(SysBusESPState),
|
||||||
@ -1176,7 +1176,7 @@ static void esp_pci_class_init(ObjectClass *klass, void *data)
|
|||||||
dc->vmsd = &vmstate_esp_pci_scsi;
|
dc->vmsd = &vmstate_esp_pci_scsi;
|
||||||
}
|
}
|
||||||
|
|
||||||
static TypeInfo esp_pci_info = {
|
static const TypeInfo esp_pci_info = {
|
||||||
.name = "am53c974",
|
.name = "am53c974",
|
||||||
.parent = TYPE_PCI_DEVICE,
|
.parent = TYPE_PCI_DEVICE,
|
||||||
.instance_size = sizeof(PCIESPState),
|
.instance_size = sizeof(PCIESPState),
|
||||||
|
68
hw/megasas.c
68
hw/megasas.c
@ -38,6 +38,9 @@
|
|||||||
#define MEGASAS_MAX_SECTORS 0xFFFF /* No real limit */
|
#define MEGASAS_MAX_SECTORS 0xFFFF /* No real limit */
|
||||||
#define MEGASAS_MAX_ARRAYS 128
|
#define MEGASAS_MAX_ARRAYS 128
|
||||||
|
|
||||||
|
#define NAA_LOCALLY_ASSIGNED_ID 0x3ULL
|
||||||
|
#define IEEE_COMPANY_LOCALLY_ASSIGNED 0x525400
|
||||||
|
|
||||||
#define MEGASAS_FLAG_USE_JBOD 0
|
#define MEGASAS_FLAG_USE_JBOD 0
|
||||||
#define MEGASAS_MASK_USE_JBOD (1 << MEGASAS_FLAG_USE_JBOD)
|
#define MEGASAS_MASK_USE_JBOD (1 << MEGASAS_FLAG_USE_JBOD)
|
||||||
#define MEGASAS_FLAG_USE_MSIX 1
|
#define MEGASAS_FLAG_USE_MSIX 1
|
||||||
@ -89,6 +92,8 @@ typedef struct MegasasState {
|
|||||||
int shutdown_event;
|
int shutdown_event;
|
||||||
int boot_event;
|
int boot_event;
|
||||||
|
|
||||||
|
uint64_t sas_addr;
|
||||||
|
|
||||||
uint64_t reply_queue_pa;
|
uint64_t reply_queue_pa;
|
||||||
void *reply_queue;
|
void *reply_queue;
|
||||||
int reply_queue_len;
|
int reply_queue_len;
|
||||||
@ -372,14 +377,16 @@ static uint64_t megasas_fw_time(void)
|
|||||||
return bcd_time;
|
return bcd_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t megasas_gen_sas_addr(uint64_t id)
|
/*
|
||||||
|
* Default disk sata address
|
||||||
|
* 0x1221 is the magic number as
|
||||||
|
* present in real hardware,
|
||||||
|
* so use it here, too.
|
||||||
|
*/
|
||||||
|
static uint64_t megasas_get_sata_addr(uint16_t id)
|
||||||
{
|
{
|
||||||
uint64_t addr;
|
uint64_t addr = (0x1221ULL << 48);
|
||||||
|
return addr & (id << 24);
|
||||||
addr = 0x5001a4aULL << 36;
|
|
||||||
addr |= id & 0xfffffffff;
|
|
||||||
|
|
||||||
return addr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -652,10 +659,7 @@ static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd)
|
|||||||
size_t dcmd_size = sizeof(info);
|
size_t dcmd_size = sizeof(info);
|
||||||
BusChild *kid;
|
BusChild *kid;
|
||||||
int num_ld_disks = 0;
|
int num_ld_disks = 0;
|
||||||
|
uint16_t sdev_id;
|
||||||
QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
|
|
||||||
num_ld_disks++;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&info, 0x0, cmd->iov_size);
|
memset(&info, 0x0, cmd->iov_size);
|
||||||
if (cmd->iov_size < dcmd_size) {
|
if (cmd->iov_size < dcmd_size) {
|
||||||
@ -669,10 +673,29 @@ static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd)
|
|||||||
info.pci.subvendor = cpu_to_le16(PCI_VENDOR_ID_LSI_LOGIC);
|
info.pci.subvendor = cpu_to_le16(PCI_VENDOR_ID_LSI_LOGIC);
|
||||||
info.pci.subdevice = cpu_to_le16(0x1013);
|
info.pci.subdevice = cpu_to_le16(0x1013);
|
||||||
|
|
||||||
info.host.type = MFI_INFO_HOST_PCIX;
|
/*
|
||||||
|
* For some reason the firmware supports
|
||||||
|
* only up to 8 device ports.
|
||||||
|
* Despite supporting a far larger number
|
||||||
|
* of devices for the physical devices.
|
||||||
|
* So just display the first 8 devices
|
||||||
|
* in the device port list, independent
|
||||||
|
* of how many logical devices are actually
|
||||||
|
* present.
|
||||||
|
*/
|
||||||
|
info.host.type = MFI_INFO_HOST_PCIE;
|
||||||
info.device.type = MFI_INFO_DEV_SAS3G;
|
info.device.type = MFI_INFO_DEV_SAS3G;
|
||||||
info.device.port_count = 2;
|
info.device.port_count = 8;
|
||||||
info.device.port_addr[0] = cpu_to_le64(megasas_gen_sas_addr((uint64_t)s));
|
QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
|
||||||
|
SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child);
|
||||||
|
|
||||||
|
if (num_ld_disks < 8) {
|
||||||
|
sdev_id = ((sdev->id & 0xFF) >> 8) | (sdev->lun & 0xFF);
|
||||||
|
info.device.port_addr[num_ld_disks] =
|
||||||
|
cpu_to_le64(megasas_get_sata_addr(sdev_id));
|
||||||
|
}
|
||||||
|
num_ld_disks++;
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(info.product_name, "MegaRAID SAS 8708EM2", 20);
|
memcpy(info.product_name, "MegaRAID SAS 8708EM2", 20);
|
||||||
snprintf(info.serial_number, 32, "QEMU%08lx",
|
snprintf(info.serial_number, 32, "QEMU%08lx",
|
||||||
@ -761,7 +784,7 @@ static int megasas_mfc_get_defaults(MegasasState *s, MegasasCmd *cmd)
|
|||||||
return MFI_STAT_INVALID_PARAMETER;
|
return MFI_STAT_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
info.sas_addr = cpu_to_le64(megasas_gen_sas_addr((uint64_t)s));
|
info.sas_addr = cpu_to_le64(s->sas_addr);
|
||||||
info.stripe_size = 3;
|
info.stripe_size = 3;
|
||||||
info.flush_time = 4;
|
info.flush_time = 4;
|
||||||
info.background_rate = 30;
|
info.background_rate = 30;
|
||||||
@ -891,7 +914,7 @@ static int megasas_dcmd_pd_get_list(MegasasState *s, MegasasCmd *cmd)
|
|||||||
info.addr[num_pd_disks].scsi_dev_type = sdev->type;
|
info.addr[num_pd_disks].scsi_dev_type = sdev->type;
|
||||||
info.addr[num_pd_disks].connect_port_bitmap = 0x1;
|
info.addr[num_pd_disks].connect_port_bitmap = 0x1;
|
||||||
info.addr[num_pd_disks].sas_addr[0] =
|
info.addr[num_pd_disks].sas_addr[0] =
|
||||||
cpu_to_le64(megasas_gen_sas_addr((uint64_t)sdev));
|
cpu_to_le64(megasas_get_sata_addr(sdev_id));
|
||||||
num_pd_disks++;
|
num_pd_disks++;
|
||||||
offset += sizeof(struct mfi_pd_address);
|
offset += sizeof(struct mfi_pd_address);
|
||||||
}
|
}
|
||||||
@ -994,7 +1017,7 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun,
|
|||||||
info->slot_number = (sdev->id & 0xFF);
|
info->slot_number = (sdev->id & 0xFF);
|
||||||
info->path_info.count = 1;
|
info->path_info.count = 1;
|
||||||
info->path_info.sas_addr[0] =
|
info->path_info.sas_addr[0] =
|
||||||
cpu_to_le64(megasas_gen_sas_addr((uint64_t)sdev));
|
cpu_to_le64(megasas_get_sata_addr(sdev_id));
|
||||||
info->connected_port_bitmap = 0x1;
|
info->connected_port_bitmap = 0x1;
|
||||||
info->device_speed = 1;
|
info->device_speed = 1;
|
||||||
info->link_speed = 1;
|
info->link_speed = 1;
|
||||||
@ -2040,7 +2063,7 @@ static const VMStateDescription vmstate_megasas = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static int megasas_scsi_uninit(PCIDevice *d)
|
static void megasas_scsi_uninit(PCIDevice *d)
|
||||||
{
|
{
|
||||||
MegasasState *s = DO_UPCAST(MegasasState, dev, d);
|
MegasasState *s = DO_UPCAST(MegasasState, dev, d);
|
||||||
|
|
||||||
@ -2050,7 +2073,6 @@ static int megasas_scsi_uninit(PCIDevice *d)
|
|||||||
memory_region_destroy(&s->mmio_io);
|
memory_region_destroy(&s->mmio_io);
|
||||||
memory_region_destroy(&s->port_io);
|
memory_region_destroy(&s->port_io);
|
||||||
memory_region_destroy(&s->queue_io);
|
memory_region_destroy(&s->queue_io);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct SCSIBusInfo megasas_scsi_info = {
|
static const struct SCSIBusInfo megasas_scsi_info = {
|
||||||
@ -2103,6 +2125,13 @@ static int megasas_scsi_init(PCIDevice *dev)
|
|||||||
msix_vector_use(&s->dev, 0);
|
msix_vector_use(&s->dev, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!s->sas_addr) {
|
||||||
|
s->sas_addr = ((NAA_LOCALLY_ASSIGNED_ID << 24) |
|
||||||
|
IEEE_COMPANY_LOCALLY_ASSIGNED) << 36;
|
||||||
|
s->sas_addr |= (pci_bus_num(dev->bus) << 16);
|
||||||
|
s->sas_addr |= (PCI_SLOT(dev->devfn) << 8);
|
||||||
|
s->sas_addr |= PCI_FUNC(dev->devfn);
|
||||||
|
}
|
||||||
if (s->fw_sge >= MEGASAS_MAX_SGE - MFI_PASS_FRAME_SIZE) {
|
if (s->fw_sge >= MEGASAS_MAX_SGE - MFI_PASS_FRAME_SIZE) {
|
||||||
s->fw_sge = MEGASAS_MAX_SGE - MFI_PASS_FRAME_SIZE;
|
s->fw_sge = MEGASAS_MAX_SGE - MFI_PASS_FRAME_SIZE;
|
||||||
} else if (s->fw_sge >= 128 - MFI_PASS_FRAME_SIZE) {
|
} else if (s->fw_sge >= 128 - MFI_PASS_FRAME_SIZE) {
|
||||||
@ -2137,6 +2166,7 @@ static Property megasas_properties[] = {
|
|||||||
MEGASAS_DEFAULT_SGE),
|
MEGASAS_DEFAULT_SGE),
|
||||||
DEFINE_PROP_UINT32("max_cmds", MegasasState, fw_cmds,
|
DEFINE_PROP_UINT32("max_cmds", MegasasState, fw_cmds,
|
||||||
MEGASAS_DEFAULT_FRAMES),
|
MEGASAS_DEFAULT_FRAMES),
|
||||||
|
DEFINE_PROP_HEX64("sas_address", MegasasState, sas_addr, 0),
|
||||||
#ifdef USE_MSIX
|
#ifdef USE_MSIX
|
||||||
DEFINE_PROP_BIT("use_msix", MegasasState, flags,
|
DEFINE_PROP_BIT("use_msix", MegasasState, flags,
|
||||||
MEGASAS_FLAG_USE_MSIX, false),
|
MEGASAS_FLAG_USE_MSIX, false),
|
||||||
|
1
hw/mfi.h
1
hw/mfi.h
@ -656,6 +656,7 @@ struct mfi_info_device {
|
|||||||
#define MFI_INFO_DEV_SAS3G 0x02
|
#define MFI_INFO_DEV_SAS3G 0x02
|
||||||
#define MFI_INFO_DEV_SATA1 0x04
|
#define MFI_INFO_DEV_SATA1 0x04
|
||||||
#define MFI_INFO_DEV_SATA3G 0x08
|
#define MFI_INFO_DEV_SATA3G 0x08
|
||||||
|
#define MFI_INFO_DEV_PCIE 0x10
|
||||||
uint8_t reserved[6];
|
uint8_t reserved[6];
|
||||||
uint8_t port_count;
|
uint8_t port_count;
|
||||||
uint64_t port_addr[8];
|
uint64_t port_addr[8];
|
||||||
|
@ -733,6 +733,72 @@ static int scsi_get_performance_length(int num_desc, int type, int data_type)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ata_passthrough_xfer_unit(SCSIDevice *dev, uint8_t *buf)
|
||||||
|
{
|
||||||
|
int byte_block = (buf[2] >> 2) & 0x1;
|
||||||
|
int type = (buf[2] >> 4) & 0x1;
|
||||||
|
int xfer_unit;
|
||||||
|
|
||||||
|
if (byte_block) {
|
||||||
|
if (type) {
|
||||||
|
xfer_unit = dev->blocksize;
|
||||||
|
} else {
|
||||||
|
xfer_unit = 512;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
xfer_unit = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return xfer_unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ata_passthrough_12_xfer_size(SCSIDevice *dev, uint8_t *buf)
|
||||||
|
{
|
||||||
|
int length = buf[2] & 0x3;
|
||||||
|
int xfer;
|
||||||
|
int unit = ata_passthrough_xfer_unit(dev, buf);
|
||||||
|
|
||||||
|
switch (length) {
|
||||||
|
case 0:
|
||||||
|
case 3: /* USB-specific. */
|
||||||
|
xfer = 0;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
xfer = buf[3];
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
xfer = buf[4];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return xfer * unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ata_passthrough_16_xfer_size(SCSIDevice *dev, uint8_t *buf)
|
||||||
|
{
|
||||||
|
int extend = buf[1] & 0x1;
|
||||||
|
int length = buf[2] & 0x3;
|
||||||
|
int xfer;
|
||||||
|
int unit = ata_passthrough_xfer_unit(dev, buf);
|
||||||
|
|
||||||
|
switch (length) {
|
||||||
|
case 0:
|
||||||
|
case 3: /* USB-specific. */
|
||||||
|
xfer = 0;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
xfer = buf[4];
|
||||||
|
xfer |= (extend ? buf[3] << 8 : 0);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
xfer = buf[6];
|
||||||
|
xfer |= (extend ? buf[5] << 8 : 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return xfer * unit;
|
||||||
|
}
|
||||||
|
|
||||||
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) {
|
||||||
@ -867,6 +933,17 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
|
|||||||
cmd->xfer = buf[9] | (buf[8] << 8);
|
cmd->xfer = buf[9] | (buf[8] << 8);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case ATA_PASSTHROUGH_12:
|
||||||
|
if (dev->type == TYPE_ROM) {
|
||||||
|
/* BLANK command of MMC */
|
||||||
|
cmd->xfer = 0;
|
||||||
|
} else {
|
||||||
|
cmd->xfer = ata_passthrough_12_xfer_size(dev, buf);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ATA_PASSTHROUGH_16:
|
||||||
|
cmd->xfer = ata_passthrough_16_xfer_size(dev, buf);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -996,9 +1073,14 @@ static void scsi_cmd_xfer_mode(SCSICommand *cmd)
|
|||||||
case SEND_DVD_STRUCTURE:
|
case SEND_DVD_STRUCTURE:
|
||||||
case PERSISTENT_RESERVE_OUT:
|
case PERSISTENT_RESERVE_OUT:
|
||||||
case MAINTENANCE_OUT:
|
case MAINTENANCE_OUT:
|
||||||
case ATA_PASSTHROUGH:
|
|
||||||
cmd->mode = SCSI_XFER_TO_DEV;
|
cmd->mode = SCSI_XFER_TO_DEV;
|
||||||
break;
|
break;
|
||||||
|
case ATA_PASSTHROUGH_12:
|
||||||
|
case ATA_PASSTHROUGH_16:
|
||||||
|
/* T_DIR */
|
||||||
|
cmd->mode = (cmd->buf[2] & 0x8) ?
|
||||||
|
SCSI_XFER_FROM_DEV : SCSI_XFER_TO_DEV;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
cmd->mode = SCSI_XFER_FROM_DEV;
|
cmd->mode = SCSI_XFER_FROM_DEV;
|
||||||
break;
|
break;
|
||||||
@ -1103,7 +1185,7 @@ const struct SCSISense sense_code_NO_MEDIUM = {
|
|||||||
|
|
||||||
/* LUN not ready, medium removal prevented */
|
/* LUN not ready, medium removal prevented */
|
||||||
const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED = {
|
const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED = {
|
||||||
.key = NOT_READY, .asc = 0x53, .ascq = 0x00
|
.key = NOT_READY, .asc = 0x53, .ascq = 0x02
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Hardware error, internal target failure */
|
/* Hardware error, internal target failure */
|
||||||
@ -1153,7 +1235,7 @@ const struct SCSISense sense_code_INCOMPATIBLE_FORMAT = {
|
|||||||
|
|
||||||
/* Illegal request, medium removal prevented */
|
/* Illegal request, medium removal prevented */
|
||||||
const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED = {
|
const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED = {
|
||||||
.key = ILLEGAL_REQUEST, .asc = 0x53, .ascq = 0x00
|
.key = ILLEGAL_REQUEST, .asc = 0x53, .ascq = 0x02
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Command aborted, I/O process terminated */
|
/* Command aborted, I/O process terminated */
|
||||||
@ -1335,7 +1417,7 @@ static const char *scsi_command_name(uint8_t cmd)
|
|||||||
[ PERSISTENT_RESERVE_OUT ] = "PERSISTENT_RESERVE_OUT",
|
[ PERSISTENT_RESERVE_OUT ] = "PERSISTENT_RESERVE_OUT",
|
||||||
[ WRITE_FILEMARKS_16 ] = "WRITE_FILEMARKS_16",
|
[ WRITE_FILEMARKS_16 ] = "WRITE_FILEMARKS_16",
|
||||||
[ EXTENDED_COPY ] = "EXTENDED_COPY",
|
[ EXTENDED_COPY ] = "EXTENDED_COPY",
|
||||||
[ ATA_PASSTHROUGH ] = "ATA_PASSTHROUGH",
|
[ ATA_PASSTHROUGH_16 ] = "ATA_PASSTHROUGH_16",
|
||||||
[ ACCESS_CONTROL_IN ] = "ACCESS_CONTROL_IN",
|
[ ACCESS_CONTROL_IN ] = "ACCESS_CONTROL_IN",
|
||||||
[ ACCESS_CONTROL_OUT ] = "ACCESS_CONTROL_OUT",
|
[ ACCESS_CONTROL_OUT ] = "ACCESS_CONTROL_OUT",
|
||||||
[ READ_16 ] = "READ_16",
|
[ READ_16 ] = "READ_16",
|
||||||
@ -1352,7 +1434,7 @@ static const char *scsi_command_name(uint8_t cmd)
|
|||||||
[ 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",
|
||||||
[ REPORT_LUNS ] = "REPORT_LUNS",
|
[ REPORT_LUNS ] = "REPORT_LUNS",
|
||||||
[ BLANK ] = "BLANK",
|
[ ATA_PASSTHROUGH_12 ] = "BLANK/ATA_PASSTHROUGH_12",
|
||||||
[ MOVE_MEDIUM ] = "MOVE_MEDIUM",
|
[ MOVE_MEDIUM ] = "MOVE_MEDIUM",
|
||||||
[ EXCHANGE_MEDIUM ] = "EXCHANGE MEDIUM",
|
[ EXCHANGE_MEDIUM ] = "EXCHANGE MEDIUM",
|
||||||
[ LOAD_UNLOAD ] = "LOAD_UNLOAD",
|
[ LOAD_UNLOAD ] = "LOAD_UNLOAD",
|
||||||
|
@ -100,7 +100,7 @@
|
|||||||
#define READ_REVERSE_16 0x81
|
#define READ_REVERSE_16 0x81
|
||||||
#define ALLOW_OVERWRITE 0x82
|
#define ALLOW_OVERWRITE 0x82
|
||||||
#define EXTENDED_COPY 0x83
|
#define EXTENDED_COPY 0x83
|
||||||
#define ATA_PASSTHROUGH 0x85
|
#define ATA_PASSTHROUGH_16 0x85
|
||||||
#define ACCESS_CONTROL_IN 0x86
|
#define ACCESS_CONTROL_IN 0x86
|
||||||
#define ACCESS_CONTROL_OUT 0x87
|
#define ACCESS_CONTROL_OUT 0x87
|
||||||
#define READ_16 0x88
|
#define READ_16 0x88
|
||||||
@ -117,7 +117,7 @@
|
|||||||
#define SERVICE_ACTION_IN_16 0x9e
|
#define SERVICE_ACTION_IN_16 0x9e
|
||||||
#define WRITE_LONG_16 0x9f
|
#define WRITE_LONG_16 0x9f
|
||||||
#define REPORT_LUNS 0xa0
|
#define REPORT_LUNS 0xa0
|
||||||
#define BLANK 0xa1
|
#define ATA_PASSTHROUGH_12 0xa1
|
||||||
#define MAINTENANCE_IN 0xa3
|
#define MAINTENANCE_IN 0xa3
|
||||||
#define MAINTENANCE_OUT 0xa4
|
#define MAINTENANCE_OUT 0xa4
|
||||||
#define MOVE_MEDIUM 0xa5
|
#define MOVE_MEDIUM 0xa5
|
||||||
|
@ -447,7 +447,7 @@ static void scsi_write_complete(void * opaque, int ret)
|
|||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
scsi_init_iovec(r, SCSI_DMA_BUF_SIZE);
|
scsi_init_iovec(r, SCSI_DMA_BUF_SIZE);
|
||||||
DPRINTF("Write complete tag=0x%x more=%d\n", r->req.tag, r->qiov.size);
|
DPRINTF("Write complete tag=0x%x more=%zd\n", r->req.tag, r->qiov.size);
|
||||||
scsi_req_data(&r->req, r->qiov.size);
|
scsi_req_data(&r->req, r->qiov.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1247,6 +1247,12 @@ static int scsi_disk_emulate_start_stop(SCSIDiskReq *r)
|
|||||||
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
|
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
|
||||||
bool start = req->cmd.buf[4] & 1;
|
bool start = req->cmd.buf[4] & 1;
|
||||||
bool loej = req->cmd.buf[4] & 2; /* load on start, eject on !start */
|
bool loej = req->cmd.buf[4] & 2; /* load on start, eject on !start */
|
||||||
|
int pwrcnd = req->cmd.buf[4] & 0xf0;
|
||||||
|
|
||||||
|
if (pwrcnd) {
|
||||||
|
/* eject/load only happens for power condition == 0 */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if ((s->features & (1 << SCSI_DISK_F_REMOVABLE)) && loej) {
|
if ((s->features & (1 << SCSI_DISK_F_REMOVABLE)) && loej) {
|
||||||
if (!start && !s->tray_open && s->tray_locked) {
|
if (!start && !s->tray_open && s->tray_locked) {
|
||||||
@ -1271,7 +1277,7 @@ static void scsi_disk_emulate_read_data(SCSIRequest *req)
|
|||||||
int buflen = r->iov.iov_len;
|
int buflen = r->iov.iov_len;
|
||||||
|
|
||||||
if (buflen) {
|
if (buflen) {
|
||||||
DPRINTF("Read buf_len=%zd\n", buflen);
|
DPRINTF("Read buf_len=%d\n", buflen);
|
||||||
r->iov.iov_len = 0;
|
r->iov.iov_len = 0;
|
||||||
r->started = true;
|
r->started = true;
|
||||||
scsi_req_data(&r->req, buflen);
|
scsi_req_data(&r->req, buflen);
|
||||||
@ -1449,7 +1455,7 @@ static void scsi_disk_emulate_write_data(SCSIRequest *req)
|
|||||||
|
|
||||||
if (r->iov.iov_len) {
|
if (r->iov.iov_len) {
|
||||||
int buflen = r->iov.iov_len;
|
int buflen = r->iov.iov_len;
|
||||||
DPRINTF("Write buf_len=%zd\n", buflen);
|
DPRINTF("Write buf_len=%d\n", buflen);
|
||||||
r->iov.iov_len = 0;
|
r->iov.iov_len = 0;
|
||||||
scsi_req_data(&r->req, buflen);
|
scsi_req_data(&r->req, buflen);
|
||||||
return;
|
return;
|
||||||
@ -2087,23 +2093,24 @@ static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
|
|||||||
const SCSIReqOps *ops;
|
const SCSIReqOps *ops;
|
||||||
uint8_t command;
|
uint8_t command;
|
||||||
|
|
||||||
#ifdef DEBUG_SCSI
|
|
||||||
DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, buf[0]);
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i = 1; i < r->req.cmd.len; i++) {
|
|
||||||
printf(" 0x%02x", buf[i]);
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
command = buf[0];
|
command = buf[0];
|
||||||
ops = scsi_disk_reqops_dispatch[command];
|
ops = scsi_disk_reqops_dispatch[command];
|
||||||
if (!ops) {
|
if (!ops) {
|
||||||
ops = &scsi_disk_emulate_reqops;
|
ops = &scsi_disk_emulate_reqops;
|
||||||
}
|
}
|
||||||
req = scsi_req_alloc(ops, &s->qdev, tag, lun, hba_private);
|
req = scsi_req_alloc(ops, &s->qdev, tag, lun, hba_private);
|
||||||
|
|
||||||
|
#ifdef DEBUG_SCSI
|
||||||
|
DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]);
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 1; i < req->cmd.len; i++) {
|
||||||
|
printf(" 0x%02x", buf[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return req;
|
return req;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user