Commit 0907db57 authored by Li Feng's avatar Li Feng Committed by Tomasz Zawadzki
Browse files

vhost-scsi: support parameter changed notification



If the capacity of scsi bdev has changed, vhost-scsi should
notify the guest to handle this change.

Change-Id: I1087b28cdb719f6b727ff0ae486cee6a0719bb0c
Signed-off-by: default avatarLi Feng <fengli@smartx.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/4124


Reviewed-by: default avatarChangpeng Liu <changpeng.liu@intel.com>
Reviewed-by: default avatarShuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
parent 5029fe14
Loading
Loading
Loading
Loading
+102 −7
Original line number Diff line number Diff line
@@ -148,6 +148,8 @@ static void vhost_scsi_dump_info_json(struct spdk_vhost_dev *vdev,
static void vhost_scsi_write_config_json(struct spdk_vhost_dev *vdev,
		struct spdk_json_write_ctx *w);
static int vhost_scsi_dev_remove(struct spdk_vhost_dev *vdev);
static int vhost_scsi_dev_param_changed(struct spdk_vhost_dev *vdev,
					unsigned scsi_tgt_num);

static const struct spdk_vhost_dev_backend spdk_vhost_scsi_device_backend = {
	.session_ctx_size = sizeof(struct spdk_vhost_scsi_session) - sizeof(struct spdk_vhost_session),
@@ -933,10 +935,10 @@ spdk_vhost_scsi_dev_get_tgt(struct spdk_vhost_dev *vdev, uint8_t num)
	return svdev->scsi_dev_state[num].dev;
}

static void
vhost_scsi_lun_hotremove(const struct spdk_scsi_lun *lun, void *arg)
static unsigned
get_scsi_dev_num(const struct spdk_vhost_scsi_dev *svdev,
		 const struct spdk_scsi_lun *lun)
{
	struct spdk_vhost_scsi_dev *svdev = arg;
	const struct spdk_scsi_dev *scsi_dev;
	unsigned scsi_dev_num;

@@ -949,6 +951,31 @@ vhost_scsi_lun_hotremove(const struct spdk_scsi_lun *lun, void *arg)
		}
	}

	return scsi_dev_num;
}

static void
vhost_scsi_lun_resize(const struct spdk_scsi_lun *lun, void *arg)
{
	struct spdk_vhost_scsi_dev *svdev = arg;
	unsigned scsi_dev_num;

	scsi_dev_num = get_scsi_dev_num(svdev, lun);
	if (scsi_dev_num == SPDK_VHOST_SCSI_CTRLR_MAX_DEVS) {
		/* The entire device has been already removed. */
		return;
	}

	vhost_scsi_dev_param_changed(&svdev->vdev, scsi_dev_num);
}

static void
vhost_scsi_lun_hotremove(const struct spdk_scsi_lun *lun, void *arg)
{
	struct spdk_vhost_scsi_dev *svdev = arg;
	unsigned scsi_dev_num;

	scsi_dev_num = get_scsi_dev_num(svdev, lun);
	if (scsi_dev_num == SPDK_VHOST_SCSI_CTRLR_MAX_DEVS) {
		/* The entire device has been already removed. */
		return;
@@ -1079,8 +1106,9 @@ spdk_vhost_scsi_dev_add_tgt(struct spdk_vhost_dev *vdev, int scsi_tgt_num,
	bdev_names_list[0] = (char *)bdev_name;

	state->status = VHOST_SCSI_DEV_ADDING;
	state->dev = spdk_scsi_dev_construct(target_name, bdev_names_list, lun_id_list, 1,
	state->dev = spdk_scsi_dev_construct_ext(target_name, bdev_names_list, lun_id_list, 1,
			SPDK_SPC_PROTOCOL_IDENTIFIER_SAS,
			vhost_scsi_lun_resize, svdev,
			vhost_scsi_lun_hotremove, svdev);

	if (state->dev == NULL) {
@@ -1138,7 +1166,7 @@ vhost_scsi_session_remove_tgt(struct spdk_vhost_dev *vdev,
	assert(state->status == VHOST_SCSI_DEV_PRESENT);
	state->status = VHOST_SCSI_DEV_REMOVING;

	/* Send a hotremove Virtio event */
	/* Send a hotremove virtio event */
	if (vhost_dev_has_feature(vsession, VIRTIO_SCSI_F_HOTPLUG)) {
		eventq_enqueue(svsession, scsi_tgt_num,
			       VIRTIO_SCSI_T_TRANSPORT_RESET, VIRTIO_SCSI_EVT_RESET_REMOVED);
@@ -1200,6 +1228,73 @@ spdk_vhost_scsi_dev_remove_tgt(struct spdk_vhost_dev *vdev, unsigned scsi_tgt_nu
	return 0;
}

static int
vhost_scsi_session_param_changed(struct spdk_vhost_dev *vdev,
				 struct spdk_vhost_session *vsession, void *ctx)
{
	unsigned scsi_tgt_num = (unsigned)(uintptr_t)ctx;
	struct spdk_vhost_scsi_session *svsession = (struct spdk_vhost_scsi_session *)vsession;
	struct spdk_scsi_dev_session_state *state = &svsession->scsi_dev_state[scsi_tgt_num];

	if (!vsession->started || state->dev == NULL) {
		/* Nothing to do */
		return 0;
	}

	/* Send a parameter change virtio event */
	if (vhost_dev_has_feature(vsession, VIRTIO_SCSI_F_CHANGE)) {
		/*
		 * virtio 1.0 spec says:
		 * By sending this event, the device signals a change in the configuration
		 * parameters of a logical unit, for example the capacity or cache mode.
		 * event is set to VIRTIO_SCSI_T_PARAM_CHANGE. lun addresses a logical unit
		 * in the SCSI host. The same event SHOULD also be reported as a unit
		 * attention condition. reason contains the additional sense code and
		 * additional sense code qualifier, respectively in bits 0…7 and 8…15.
		 * Note: For example, a change in * capacity will be reported as asc
		 * 0x2a, ascq 0x09 (CAPACITY DATA HAS CHANGED).
		 */
		eventq_enqueue(svsession, scsi_tgt_num, VIRTIO_SCSI_T_PARAM_CHANGE, 0x2a | (0x09 << 8));
	}

	return 0;
}

static int
vhost_scsi_dev_param_changed(struct spdk_vhost_dev *vdev, unsigned scsi_tgt_num)
{
	struct spdk_vhost_scsi_dev *svdev;
	struct spdk_scsi_dev_vhost_state *scsi_dev_state;

	if (scsi_tgt_num >= SPDK_VHOST_SCSI_CTRLR_MAX_DEVS) {
		SPDK_ERRLOG("%s: invalid SCSI target number %d\n", vdev->name, scsi_tgt_num);
		return -EINVAL;
	}

	svdev = to_scsi_dev(vdev);
	if (!svdev) {
		SPDK_ERRLOG("An invalid SCSI device that removing from a SCSI target.");
		return -EINVAL;
	}

	scsi_dev_state = &svdev->scsi_dev_state[scsi_tgt_num];

	if (scsi_dev_state->status != VHOST_SCSI_DEV_PRESENT) {
		return -EBUSY;
	}

	if (scsi_dev_state->dev == NULL || scsi_dev_state->status == VHOST_SCSI_DEV_ADDING) {
		SPDK_ERRLOG("%s: SCSI target %u is not occupied\n", vdev->name, scsi_tgt_num);
		return -ENODEV;
	}

	assert(scsi_dev_state->status != VHOST_SCSI_DEV_EMPTY);

	vhost_dev_foreach_session(vdev, vhost_scsi_session_param_changed,
				  NULL, (void *)(uintptr_t)scsi_tgt_num);
	return 0;
}

int
vhost_scsi_controller_construct(void)
{