Merge remote-tracking branch 'bonzini/scsi-next' into staging

* bonzini/scsi-next: (32 commits)
  virtio-scsi: enable MSI-X support
  virtio-scsi: add ioeventfd support
  virtio-scsi: report parameter change events
  virtio-scsi: do not report dropped events after reset
  virtio-scsi: Report missed events
  virtio-scsi: Implement hotplug support for virtio-scsi
  scsi: report parameter changes to HBA drivers
  scsi-disk: report resized disk via sense codes
  scsi: establish precedence levels for unit attention
  scsi: introduce hotplug() and hot_unplug() interfaces for SCSI bus
  scsi: add tracepoint for scsi_req_cancel
  scsi-disk: removable hard disks support load/eject
  scsi-disk: Fail medium writes with proper sense for readonly LUNs
  scsi-disk: improve the lba-out-of-range tests for read/write/verify
  scsi-disk: rd/wr/vr-protect !=0 is an error
  scsi-disk: support toggling the write cache
  scsi-disk: parse MODE SELECT commands and parameters
  scsi-disk: fix changeable values for MODE_PAGE_R_W_ERROR
  scsi-disk: adjust offsets in MODE SENSE by 2
  scsi-disk: support emulated TO_DEV requests
  ...
This commit is contained in:
Anthony Liguori 2012-07-30 09:59:23 -05:00
commit d4a06f466a
10 changed files with 821 additions and 342 deletions

View file

@ -28,6 +28,13 @@
#include "qemu_socket.h"
#include "iov.h"
void strpadcpy(char *buf, int buf_size, const char *str, char pad)
{
int len = qemu_strnlen(str, buf_size);
memcpy(buf, str, len);
memset(buf + len, pad, buf_size - len);
}
void pstrcpy(char *buf, int buf_size, const char *str)
{
int c;

View file

@ -282,8 +282,6 @@ static inline int lsi_irq_on_rsl(LSIState *s)
static void lsi_soft_reset(LSIState *s)
{
lsi_request *p;
DPRINTF("Reset\n");
s->carry = 0;
@ -350,15 +348,8 @@ static void lsi_soft_reset(LSIState *s)
s->sbc = 0;
s->csbc = 0;
s->sbr = 0;
while (!QTAILQ_EMPTY(&s->queue)) {
p = QTAILQ_FIRST(&s->queue);
QTAILQ_REMOVE(&s->queue, p, next);
g_free(p);
}
if (s->current) {
g_free(s->current);
s->current = NULL;
}
assert(QTAILQ_EMPTY(&s->queue));
assert(!s->current);
}
static int lsi_dma_40bit(LSIState *s)
@ -650,23 +641,24 @@ static lsi_request *lsi_find_by_tag(LSIState *s, uint32_t tag)
return NULL;
}
static void lsi_request_free(LSIState *s, lsi_request *p)
{
if (p == s->current) {
s->current = NULL;
} else {
QTAILQ_REMOVE(&s->queue, p, next);
}
g_free(p);
}
static void lsi_request_cancelled(SCSIRequest *req)
{
LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent);
lsi_request *p = req->hba_private;
if (s->current && req == s->current->req) {
scsi_req_unref(req);
g_free(s->current);
s->current = NULL;
return;
}
if (p) {
QTAILQ_REMOVE(&s->queue, p, next);
scsi_req_unref(req);
g_free(p);
}
req->hba_private = NULL;
lsi_request_free(s, p);
scsi_req_unref(req);
}
/* Record that data is available for a queued command. Returns zero if
@ -714,10 +706,10 @@ static void lsi_command_complete(SCSIRequest *req, uint32_t status, size_t resid
lsi_set_phase(s, PHASE_ST);
}
if (s->current && req == s->current->req) {
scsi_req_unref(s->current->req);
g_free(s->current);
s->current = NULL;
if (req->hba_private == s->current) {
req->hba_private = NULL;
lsi_request_free(s, s->current);
scsi_req_unref(req);
}
lsi_resume_script(s);
}
@ -728,7 +720,8 @@ static void lsi_transfer_data(SCSIRequest *req, uint32_t len)
LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent);
int out;
if (s->waiting == 1 || !s->current || req->hba_private != s->current ||
assert(req->hba_private);
if (s->waiting == 1 || req->hba_private != s->current ||
(lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON))) {
if (lsi_queue_req(s, req, len)) {
return;
@ -1738,7 +1731,7 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
lsi_execute_script(s);
}
if (val & LSI_ISTAT0_SRST) {
lsi_soft_reset(s);
qdev_reset_all(&s->dev.qdev);
}
break;
case 0x16: /* MBOX0 */

View file

@ -544,7 +544,7 @@ static void megasas_reset_frames(MegasasState *s)
static void megasas_abort_command(MegasasCmd *cmd)
{
if (cmd->req) {
scsi_req_abort(cmd->req, ABORTED_COMMAND);
scsi_req_cancel(cmd->req);
cmd->req = NULL;
}
}
@ -1290,35 +1290,16 @@ static int megasas_cluster_reset_ld(MegasasState *s, MegasasCmd *cmd)
static int megasas_dcmd_set_properties(MegasasState *s, MegasasCmd *cmd)
{
uint8_t *dummy = g_malloc(cmd->iov_size);
struct mfi_ctrl_props info;
size_t dcmd_size = sizeof(info);
dma_buf_write(dummy, cmd->iov_size, &cmd->qsg);
trace_megasas_dcmd_dump_frame(0,
dummy[0x00], dummy[0x01], dummy[0x02], dummy[0x03],
dummy[0x04], dummy[0x05], dummy[0x06], dummy[0x07]);
trace_megasas_dcmd_dump_frame(1,
dummy[0x08], dummy[0x09], dummy[0x0a], dummy[0x0b],
dummy[0x0c], dummy[0x0d], dummy[0x0e], dummy[0x0f]);
trace_megasas_dcmd_dump_frame(2,
dummy[0x10], dummy[0x11], dummy[0x12], dummy[0x13],
dummy[0x14], dummy[0x15], dummy[0x16], dummy[0x17]);
trace_megasas_dcmd_dump_frame(3,
dummy[0x18], dummy[0x19], dummy[0x1a], dummy[0x1b],
dummy[0x1c], dummy[0x1d], dummy[0x1e], dummy[0x1f]);
trace_megasas_dcmd_dump_frame(4,
dummy[0x20], dummy[0x21], dummy[0x22], dummy[0x23],
dummy[0x24], dummy[0x25], dummy[0x26], dummy[0x27]);
trace_megasas_dcmd_dump_frame(5,
dummy[0x28], dummy[0x29], dummy[0x2a], dummy[0x2b],
dummy[0x2c], dummy[0x2d], dummy[0x2e], dummy[0x2f]);
trace_megasas_dcmd_dump_frame(6,
dummy[0x30], dummy[0x31], dummy[0x32], dummy[0x33],
dummy[0x34], dummy[0x35], dummy[0x36], dummy[0x37]);
trace_megasas_dcmd_dump_frame(7,
dummy[0x38], dummy[0x39], dummy[0x3a], dummy[0x3b],
dummy[0x3c], dummy[0x3d], dummy[0x3e], dummy[0x3f]);
g_free(dummy);
if (cmd->iov_size < dcmd_size) {
trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size,
dcmd_size);
return MFI_STAT_INVALID_PARAMETER;
}
dma_buf_write((uint8_t *)&info, cmd->iov_size, &cmd->qsg);
trace_megasas_dcmd_unsupported(cmd->index, cmd->iov_size);
return MFI_STAT_OK;
}

View file

@ -186,6 +186,10 @@ static int scsi_qdev_init(DeviceState *qdev)
dev);
}
if (bus->info->hotplug) {
bus->info->hotplug(bus, dev);
}
err:
return rc;
}
@ -1068,6 +1072,16 @@ int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
return 0;
}
void scsi_device_report_change(SCSIDevice *dev, SCSISense sense)
{
SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus);
scsi_device_set_ua(dev, sense);
if (bus->info->change) {
bus->info->change(bus, dev, sense);
}
}
/*
* Predefined sense codes
*/
@ -1112,6 +1126,16 @@ const struct SCSISense sense_code_INVALID_FIELD = {
.key = ILLEGAL_REQUEST, .asc = 0x24, .ascq = 0x00
};
/* Illegal request, Invalid field in parameter list */
const struct SCSISense sense_code_INVALID_PARAM = {
.key = ILLEGAL_REQUEST, .asc = 0x26, .ascq = 0x00
};
/* Illegal request, Parameter list length error */
const struct SCSISense sense_code_INVALID_PARAM_LEN = {
.key = ILLEGAL_REQUEST, .asc = 0x1a, .ascq = 0x00
};
/* Illegal request, LUN not supported */
const struct SCSISense sense_code_LUN_NOT_SUPPORTED = {
.key = ILLEGAL_REQUEST, .asc = 0x25, .ascq = 0x00
@ -1147,6 +1171,11 @@ const struct SCSISense sense_code_LUN_FAILURE = {
.key = ABORTED_COMMAND, .asc = 0x3e, .ascq = 0x01
};
/* Unit attention, Capacity data has changed */
const struct SCSISense sense_code_CAPACITY_CHANGED = {
.key = UNIT_ATTENTION, .asc = 0x2a, .ascq = 0x09
};
/* Unit attention, Power on, reset or bus device reset occurred */
const struct SCSISense sense_code_RESET = {
.key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x00
@ -1172,6 +1201,11 @@ const struct SCSISense sense_code_DEVICE_INTERNAL_RESET = {
.key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x04
};
/* Data Protection, Write Protected */
const struct SCSISense sense_code_WRITE_PROTECTED = {
.key = DATA_PROTECT, .asc = 0x27, .ascq = 0x00
};
/*
* scsi_build_sense
*
@ -1481,6 +1515,7 @@ void scsi_req_complete(SCSIRequest *req, int status)
void scsi_req_cancel(SCSIRequest *req)
{
trace_scsi_req_cancel(req->dev->id, req->lun, req->tag);
if (!req->enqueued) {
return;
}
@ -1511,6 +1546,55 @@ void scsi_req_abort(SCSIRequest *req, int status)
scsi_req_unref(req);
}
static int scsi_ua_precedence(SCSISense sense)
{
if (sense.key != UNIT_ATTENTION) {
return INT_MAX;
}
if (sense.asc == 0x29 && sense.ascq == 0x04) {
/* DEVICE INTERNAL RESET goes with POWER ON OCCURRED */
return 1;
} else if (sense.asc == 0x3F && sense.ascq == 0x01) {
/* MICROCODE HAS BEEN CHANGED goes with SCSI BUS RESET OCCURRED */
return 2;
} else if (sense.asc == 0x29 && (sense.ascq == 0x05 || sense.ascq == 0x06)) {
/* These two go with "all others". */
;
} else if (sense.asc == 0x29 && sense.ascq <= 0x07) {
/* POWER ON, RESET OR BUS DEVICE RESET OCCURRED = 0
* POWER ON OCCURRED = 1
* SCSI BUS RESET OCCURRED = 2
* BUS DEVICE RESET FUNCTION OCCURRED = 3
* I_T NEXUS LOSS OCCURRED = 7
*/
return sense.ascq;
} else if (sense.asc == 0x2F && sense.ascq == 0x01) {
/* COMMANDS CLEARED BY POWER LOSS NOTIFICATION */
return 8;
}
return (sense.asc << 8) | sense.ascq;
}
void scsi_device_set_ua(SCSIDevice *sdev, SCSISense sense)
{
int prec1, prec2;
if (sense.key != UNIT_ATTENTION) {
return;
}
trace_scsi_device_set_ua(sdev->id, sdev->lun, sense.key,
sense.asc, sense.ascq);
/*
* Override a pre-existing unit attention condition, except for a more
* important reset condition.
*/
prec1 = scsi_ua_precedence(sdev->unit_attention);
prec2 = scsi_ua_precedence(sense);
if (prec2 < prec1) {
sdev->unit_attention = sense;
}
}
void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense)
{
SCSIRequest *req;
@ -1519,7 +1603,8 @@ void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense)
req = QTAILQ_FIRST(&sdev->requests);
scsi_req_cancel(req);
}
sdev->unit_attention = sense;
scsi_device_set_ua(sdev, sense);
}
static char *scsibus_get_dev_path(DeviceState *dev)
@ -1634,6 +1719,17 @@ static int get_scsi_requests(QEMUFile *f, void *pv, size_t size)
return 0;
}
static int scsi_qdev_unplug(DeviceState *qdev)
{
SCSIDevice *dev = SCSI_DEVICE(qdev);
SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus);
if (bus->info->hot_unplug) {
bus->info->hot_unplug(bus, dev);
}
return qdev_simple_unplug_cb(qdev);
}
static const VMStateInfo vmstate_info_scsi_requests = {
.name = "scsi-requests",
.get = get_scsi_requests,
@ -1670,7 +1766,7 @@ static void scsi_device_class_init(ObjectClass *klass, void *data)
DeviceClass *k = DEVICE_CLASS(klass);
k->bus_type = TYPE_SCSI_BUS;
k->init = scsi_qdev_init;
k->unplug = qdev_simple_unplug_cb;
k->unplug = scsi_qdev_unplug;
k->exit = scsi_qdev_exit;
k->props = scsi_props;
}

File diff suppressed because it is too large Load diff

View file

@ -131,6 +131,9 @@ struct SCSIBusInfo {
void (*transfer_data)(SCSIRequest *req, uint32_t arg);
void (*complete)(SCSIRequest *req, uint32_t arg, size_t resid);
void (*cancel)(SCSIRequest *req);
void (*hotplug)(SCSIBus *bus, SCSIDevice *dev);
void (*hot_unplug)(SCSIBus *bus, SCSIDevice *dev);
void (*change)(SCSIBus *bus, SCSIDevice *dev, SCSISense sense);
QEMUSGList *(*get_sg_list)(SCSIRequest *req);
void (*save_request)(QEMUFile *f, SCSIRequest *req);
@ -180,6 +183,10 @@ extern const struct SCSISense sense_code_INVALID_OPCODE;
extern const struct SCSISense sense_code_LBA_OUT_OF_RANGE;
/* Illegal request, Invalid field in CDB */
extern const struct SCSISense sense_code_INVALID_FIELD;
/* Illegal request, Invalid field in parameter list */
extern const struct SCSISense sense_code_INVALID_PARAM;
/* Illegal request, Parameter list length error */
extern const struct SCSISense sense_code_INVALID_PARAM_LEN;
/* Illegal request, LUN not supported */
extern const struct SCSISense sense_code_LUN_NOT_SUPPORTED;
/* Illegal request, Saving parameters not supported */
@ -194,6 +201,8 @@ extern const struct SCSISense sense_code_IO_ERROR;
extern const struct SCSISense sense_code_I_T_NEXUS_LOSS;
/* Command aborted, Logical Unit failure */
extern const struct SCSISense sense_code_LUN_FAILURE;
/* LUN not ready, Capacity data has changed */
extern const struct SCSISense sense_code_CAPACITY_CHANGED;
/* LUN not ready, Medium not present */
extern const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM;
/* Unit attention, Power on, reset or bus device reset occurred */
@ -204,6 +213,8 @@ extern const struct SCSISense sense_code_MEDIUM_CHANGED;
extern const struct SCSISense sense_code_REPORTED_LUNS_CHANGED;
/* Unit attention, Device internal reset */
extern const struct SCSISense sense_code_DEVICE_INTERNAL_RESET;
/* Data Protection, Write Protected */
extern const struct SCSISense sense_code_WRITE_PROTECTED;
#define SENSE_CODE(x) sense_code_ ## x
@ -231,6 +242,8 @@ void scsi_req_abort(SCSIRequest *req, int status);
void scsi_req_cancel(SCSIRequest *req);
void scsi_req_retry(SCSIRequest *req);
void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense);
void scsi_device_set_ua(SCSIDevice *sdev, SCSISense sense);
void scsi_device_report_change(SCSIDevice *dev, SCSISense sense);
int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed);
SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int target, int lun);

View file

@ -1023,7 +1023,9 @@ static int virtio_scsi_init_pci(PCIDevice *pci_dev)
return -EINVAL;
}
vdev->nvectors = proxy->nvectors;
vdev->nvectors = proxy->nvectors == DEV_NVECTORS_UNSPECIFIED
? proxy->scsi.num_queues + 3
: proxy->nvectors;
virtio_init_pci(proxy, vdev);
/* make the actual value visible */
@ -1040,7 +1042,8 @@ static int virtio_scsi_exit_pci(PCIDevice *pci_dev)
}
static Property virtio_scsi_properties[] = {
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, DEV_NVECTORS_UNSPECIFIED),
DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOPCIProxy, host_features, scsi),
DEFINE_PROP_END_OF_LIST(),
};

View file

@ -24,6 +24,11 @@
#define VIRTIO_SCSI_MAX_TARGET 255
#define VIRTIO_SCSI_MAX_LUN 16383
/* Feature Bits */
#define VIRTIO_SCSI_F_INOUT 0
#define VIRTIO_SCSI_F_HOTPLUG 1
#define VIRTIO_SCSI_F_CHANGE 2
/* Response codes */
#define VIRTIO_SCSI_S_OK 0
#define VIRTIO_SCSI_S_OVERRUN 1
@ -59,6 +64,12 @@
#define VIRTIO_SCSI_T_NO_EVENT 0
#define VIRTIO_SCSI_T_TRANSPORT_RESET 1
#define VIRTIO_SCSI_T_ASYNC_NOTIFY 2
#define VIRTIO_SCSI_T_PARAM_CHANGE 3
/* Reasons for transport reset event */
#define VIRTIO_SCSI_EVT_RESET_HARD 0
#define VIRTIO_SCSI_EVT_RESET_RESCAN 1
#define VIRTIO_SCSI_EVT_RESET_REMOVED 2
/* SCSI command request, followed by data-out */
typedef struct {
@ -132,6 +143,7 @@ typedef struct {
uint32_t sense_size;
uint32_t cdb_size;
int resetting;
bool events_dropped;
VirtQueue *ctrl_vq;
VirtQueue *event_vq;
VirtQueue *cmd_vqs[0];
@ -206,11 +218,13 @@ static void qemu_sgl_init_external(QEMUSGList *qsgl, struct iovec *sg,
static void virtio_scsi_parse_req(VirtIOSCSI *s, VirtQueue *vq,
VirtIOSCSIReq *req)
{
assert(req->elem.out_num && req->elem.in_num);
assert(req->elem.in_num);
req->vq = vq;
req->dev = s;
req->sreq = NULL;
req->req.buf = req->elem.out_sg[0].iov_base;
if (req->elem.out_num) {
req->req.buf = req->elem.out_sg[0].iov_base;
}
req->resp.buf = req->elem.in_sg[0].iov_base;
if (req->elem.out_num > 1) {
@ -405,10 +419,6 @@ 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,
size_t resid)
{
@ -545,6 +555,8 @@ static void virtio_scsi_set_config(VirtIODevice *vdev,
static uint32_t virtio_scsi_get_features(VirtIODevice *vdev,
uint32_t requested_features)
{
requested_features |= (1UL << VIRTIO_SCSI_F_HOTPLUG);
requested_features |= (1UL << VIRTIO_SCSI_F_CHANGE);
return requested_features;
}
@ -554,6 +566,7 @@ static void virtio_scsi_reset(VirtIODevice *vdev)
s->sense_size = VIRTIO_SCSI_SENSE_SIZE;
s->cdb_size = VIRTIO_SCSI_CDB_SIZE;
s->events_dropped = false;
}
/* The device does not have anything to save beyond the virtio data.
@ -577,6 +590,93 @@ static int virtio_scsi_load(QEMUFile *f, void *opaque, int version_id)
return 0;
}
static void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev,
uint32_t event, uint32_t reason)
{
VirtIOSCSIReq *req = virtio_scsi_pop_req(s, s->event_vq);
VirtIOSCSIEvent *evt;
int in_size;
if (!req) {
s->events_dropped = true;
return;
}
if (req->elem.out_num || req->elem.in_num != 1) {
virtio_scsi_bad_req();
}
if (s->events_dropped) {
event |= VIRTIO_SCSI_T_EVENTS_MISSED;
s->events_dropped = false;
}
in_size = req->elem.in_sg[0].iov_len;
if (in_size < sizeof(VirtIOSCSIEvent)) {
virtio_scsi_bad_req();
}
evt = req->resp.event;
memset(evt, 0, sizeof(VirtIOSCSIEvent));
evt->event = event;
evt->reason = reason;
if (!dev) {
assert(event == VIRTIO_SCSI_T_NO_EVENT);
} else {
evt->lun[0] = 1;
evt->lun[1] = dev->id;
/* Linux wants us to keep the same encoding we use for REPORT LUNS. */
if (dev->lun >= 256) {
evt->lun[2] = (dev->lun >> 8) | 0x40;
}
evt->lun[3] = dev->lun & 0xFF;
}
virtio_scsi_complete_req(req);
}
static void virtio_scsi_handle_event(VirtIODevice *vdev, VirtQueue *vq)
{
VirtIOSCSI *s = (VirtIOSCSI *)vdev;
if (s->events_dropped) {
virtio_scsi_push_event(s, NULL, VIRTIO_SCSI_T_NO_EVENT, 0);
}
}
static void virtio_scsi_change(SCSIBus *bus, SCSIDevice *dev, SCSISense sense)
{
VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus);
if (((s->vdev.guest_features >> VIRTIO_SCSI_F_CHANGE) & 1) &&
(s->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK) &&
dev->type != TYPE_ROM) {
virtio_scsi_push_event(s, dev, VIRTIO_SCSI_T_PARAM_CHANGE,
sense.asc | (sense.ascq << 8));
}
}
static void virtio_scsi_hotplug(SCSIBus *bus, SCSIDevice *dev)
{
VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus);
if (((s->vdev.guest_features >> VIRTIO_SCSI_F_HOTPLUG) & 1) &&
(s->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK)) {
virtio_scsi_push_event(s, dev, VIRTIO_SCSI_T_TRANSPORT_RESET,
VIRTIO_SCSI_EVT_RESET_RESCAN);
}
}
static void virtio_scsi_hot_unplug(SCSIBus *bus, SCSIDevice *dev)
{
VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus);
if ((s->vdev.guest_features >> VIRTIO_SCSI_F_HOTPLUG) & 1) {
virtio_scsi_push_event(s, dev, VIRTIO_SCSI_T_TRANSPORT_RESET,
VIRTIO_SCSI_EVT_RESET_REMOVED);
}
}
static struct SCSIBusInfo virtio_scsi_scsi_info = {
.tcq = true,
.max_channel = VIRTIO_SCSI_MAX_CHANNEL,
@ -585,6 +685,9 @@ static struct SCSIBusInfo virtio_scsi_scsi_info = {
.complete = virtio_scsi_command_complete,
.cancel = virtio_scsi_request_cancelled,
.change = virtio_scsi_change,
.hotplug = virtio_scsi_hotplug,
.hot_unplug = virtio_scsi_hot_unplug,
.get_sg_list = virtio_scsi_get_sg_list,
.save_request = virtio_scsi_save_request,
.load_request = virtio_scsi_load_request,

View file

@ -138,6 +138,7 @@ int qemu_timedate_diff(struct tm *tm);
/* cutils.c */
void pstrcpy(char *buf, int buf_size, const char *str);
void strpadcpy(char *buf, int buf_size, const char *str, char pad);
char *pstrcat(char *buf, int buf_size, const char *s);
int strstart(const char *str, const char *val, const char **ptr);
int stristart(const char *str, const char *val, const char **ptr);

View file

@ -403,6 +403,7 @@ usb_host_parse_error(int bus, int addr, const char *errmsg) "dev %d:%d, msg %s"
# hw/scsi-bus.c
scsi_req_alloc(int target, int lun, int tag) "target %d lun %d tag %d"
scsi_req_cancel(int target, int lun, int tag) "target %d lun %d tag %d"
scsi_req_data(int target, int lun, int tag, int len) "target %d lun %d tag %d len %d"
scsi_req_data_canceled(int target, int lun, int tag, int len) "target %d lun %d tag %d len %d"
scsi_req_dequeue(int target, int lun, int tag) "target %d lun %d tag %d"
@ -411,6 +412,7 @@ scsi_req_parsed(int target, int lun, int tag, int cmd, int mode, int xfer) "targ
scsi_req_parsed_lba(int target, int lun, int tag, int cmd, uint64_t lba) "target %d lun %d tag %d command %d lba %"PRIu64
scsi_req_parse_bad(int target, int lun, int tag, int cmd) "target %d lun %d tag %d command %d"
scsi_req_build_sense(int target, int lun, int tag, int key, int asc, int ascq) "target %d lun %d tag %d key %#02x asc %#02x ascq %#02x"
scsi_device_set_ua(int target, int lun, int key, int asc, int ascq) "target %d lun %d key %#02x asc %#02x ascq %#02x"
scsi_report_luns(int target, int lun, int tag) "target %d lun %d tag %d"
scsi_inquiry(int target, int lun, int tag, int cdb1, int cdb2) "target %d lun %d tag %d page %#02x/%#02x"
scsi_test_unit_ready(int target, int lun, int tag) "target %d lun %d tag %d"
@ -595,7 +597,7 @@ megasas_dcmd_ld_get_list(int cmd, int num, int max) "scmd %d: DCMD LD get list:
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_dcmd_unsupported(int cmd, unsigned long size) "scmd %d: set properties len %ld"
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"