All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Michael S. Tsirkin" <mst@redhat.com>
To: "Nicholas A. Bellinger" <nab@daterainc.com>
Cc: target-devel <target-devel@vger.kernel.org>,
	linux-scsi <linux-scsi@vger.kernel.org>,
	Paolo Bonzini <pbonzini@redhat.com>,
	"Martin K. Petersen" <martin.petersen@oracle.com>,
	Sagi Grimberg <sagig@mellanox.com>,
	Christoph Hellwig <hch@lst.de>, Hannes Reinecke <hare@suse.de>,
	"H. Peter Anvin" <hpa@zytor.com>,
	Nicholas Bellinger <nab@linux-iscsi.org>,
	Sagi Grimberg <sagig@dev.mellanox.co.il>
Subject: Re: [PATCH 5/6] vhost/scsi: Enable T10 PI IOV -> SGL memory mapping
Date: Mon, 7 Apr 2014 12:16:54 +0300	[thread overview]
Message-ID: <20140407091654.GC14183@redhat.com> (raw)
In-Reply-To: <1396819929-29687-6-git-send-email-nab@daterainc.com>

On Sun, Apr 06, 2014 at 09:32:08PM +0000, Nicholas A. Bellinger wrote:
> From: Nicholas Bellinger <nab@linux-iscsi.org>
> 
> This patch updates vhost_scsi_handle_vq() to check for the existance
> of virtio_scsi_cmd_req_pi comparing vq->iov[0].iov_len in order to
> calculate seperate data + protection SGLs from data_num.
> 
> Also update tcm_vhost_submission_work() to pass the pre-allocated
> cmd->tvc_prot_sgl[] memory into target_submit_cmd_map_sgls(), and
> update vhost_scsi_get_tag() parameters to accept scsi_tag, lun, and
> task_attr.
> 
> v3 changes:
>   - Use feature_bit for determining virtio-scsi header type (Paolo)
> 
> v2 changes:
>   - Use virtio_scsi_cmd_req_pi instead of existing ->prio (Paolo)
>   - Make protection buffer come before data buffer (Paolo)
>   - Update vhost_scsi_get_tag() parameter usage
> 
> Cc: Michael S. Tsirkin <mst@redhat.com>
> Cc: Paolo Bonzini <pbonzini@redhat.com>
> Cc: Martin K. Petersen <martin.petersen@oracle.com>
> Cc: Christoph Hellwig <hch@lst.de>
> Cc: Hannes Reinecke <hare@suse.de>
> Cc: Sagi Grimberg <sagig@dev.mellanox.co.il>
> Cc: H. Peter Anvin <hpa@zytor.com>
> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
> ---
>  drivers/vhost/scsi.c |  179 ++++++++++++++++++++++++++++++++++----------------
>  1 file changed, 121 insertions(+), 58 deletions(-)
> 
> diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c
> index eabcf18..19cd21a 100644
> --- a/drivers/vhost/scsi.c
> +++ b/drivers/vhost/scsi.c
> @@ -169,7 +169,8 @@ enum {
>  };
>  
>  enum {
> -	VHOST_SCSI_FEATURES = VHOST_FEATURES | (1ULL << VIRTIO_SCSI_F_HOTPLUG)
> +	VHOST_SCSI_FEATURES = VHOST_FEATURES | (1ULL << VIRTIO_SCSI_F_HOTPLUG) |
> +					       (1ULL << VIRTIO_SCSI_F_T10_PI)
>  };
>  
>  #define VHOST_SCSI_MAX_TARGET	256
> @@ -720,11 +721,9 @@ static void vhost_scsi_complete_cmd_work(struct vhost_work *work)
>  }
>  
>  static struct tcm_vhost_cmd *
> -vhost_scsi_get_tag(struct vhost_virtqueue *vq,
> -			struct tcm_vhost_tpg *tpg,
> -			struct virtio_scsi_cmd_req *v_req,
> -			u32 exp_data_len,
> -			int data_direction)
> +vhost_scsi_get_tag(struct vhost_virtqueue *vq, struct tcm_vhost_tpg *tpg,
> +		   unsigned char *cdb, u64 scsi_tag, u16 lun, u8 task_attr,
> +		   u32 exp_data_len, int data_direction)
>  {
>  	struct tcm_vhost_cmd *cmd;
>  	struct tcm_vhost_nexus *tv_nexus;
> @@ -756,13 +755,16 @@ vhost_scsi_get_tag(struct vhost_virtqueue *vq,
>  	cmd->tvc_prot_sgl = prot_sg;
>  	cmd->tvc_upages = pages;
>  	cmd->tvc_se_cmd.map_tag = tag;
> -	cmd->tvc_tag = v_req->tag;
> -	cmd->tvc_task_attr = v_req->task_attr;
> +	cmd->tvc_tag = scsi_tag;
> +	cmd->tvc_lun = lun;
> +	cmd->tvc_task_attr = task_attr;
>  	cmd->tvc_exp_data_len = exp_data_len;
>  	cmd->tvc_data_direction = data_direction;
>  	cmd->tvc_nexus = tv_nexus;
>  	cmd->inflight = tcm_vhost_get_inflight(vq);
>  
> +	memcpy(cmd->tvc_cdb, cdb, TCM_VHOST_MAX_CDB_SIZE);
> +
>  	return cmd;
>  }
>  
> @@ -913,18 +915,15 @@ static void tcm_vhost_submission_work(struct work_struct *work)
>  		container_of(work, struct tcm_vhost_cmd, work);
>  	struct tcm_vhost_nexus *tv_nexus;
>  	struct se_cmd *se_cmd = &cmd->tvc_se_cmd;
> -	struct scatterlist *sg_ptr, *sg_bidi_ptr = NULL;
> -	int rc, sg_no_bidi = 0;
> +	struct scatterlist *sg_ptr, *sg_prot_ptr = NULL;
> +	int rc;
>  
> +	/* FIXME: BIDI operation */
>  	if (cmd->tvc_sgl_count) {
>  		sg_ptr = cmd->tvc_sgl;
> -/* FIXME: Fix BIDI operation in tcm_vhost_submission_work() */
> -#if 0
> -		if (se_cmd->se_cmd_flags & SCF_BIDI) {
> -			sg_bidi_ptr = NULL;
> -			sg_no_bidi = 0;
> -		}
> -#endif
> +
> +		if (cmd->tvc_prot_sgl_count)
> +			sg_prot_ptr = cmd->tvc_prot_sgl;
>  	} else {
>  		sg_ptr = NULL;
>  	}
> @@ -935,7 +934,7 @@ static void tcm_vhost_submission_work(struct work_struct *work)
>  			cmd->tvc_lun, cmd->tvc_exp_data_len,
>  			cmd->tvc_task_attr, cmd->tvc_data_direction,
>  			TARGET_SCF_ACK_KREF, sg_ptr, cmd->tvc_sgl_count,
> -			sg_bidi_ptr, sg_no_bidi, NULL, 0);
> +			NULL, 0, sg_prot_ptr, cmd->tvc_prot_sgl_count);
>  	if (rc < 0) {
>  		transport_send_check_condition_and_sense(se_cmd,
>  				TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
> @@ -967,12 +966,18 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
>  {
>  	struct tcm_vhost_tpg **vs_tpg;
>  	struct virtio_scsi_cmd_req v_req;
> +	struct virtio_scsi_cmd_req_pi v_req_pi;
>  	struct tcm_vhost_tpg *tpg;
>  	struct tcm_vhost_cmd *cmd;
> -	u32 exp_data_len, data_first, data_num, data_direction;
> +	u64 tag;
> +	u32 exp_data_len, data_first, data_num, data_direction, prot_first;
>  	unsigned out, in, i;
> -	int head, ret;
> -	u8 target;
> +	int head, ret, data_niov, prot_niov;
> +	size_t req_size;
> +	u16 lun;
> +	u8 *target, *lunp, task_attr;
> +	bool hdr_pi;
> +	unsigned char *req, *cdb;

Make req void *, then we won't need the casts?

>  
>  	mutex_lock(&vq->mutex);
>  	/*
> @@ -1003,7 +1008,7 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
>  			break;
>  		}
>  
> -/* FIXME: BIDI operation */
> +		/* FIXME: BIDI operation */
>  		if (out == 1 && in == 1) {
>  			data_direction = DMA_NONE;
>  			data_first = 0;
> @@ -1033,29 +1038,47 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
>  			break;
>  		}
>  
> -		if (unlikely(vq->iov[0].iov_len != sizeof(v_req))) {
> -			vq_err(vq, "Expecting virtio_scsi_cmd_req, got %zu"
> -				" bytes\n", vq->iov[0].iov_len);
> -			break;
> +		if (vs->dev.acked_features & VIRTIO_SCSI_F_T10_PI) {
> +			if (unlikely(vq->iov[0].iov_len != sizeof(v_req_pi))) {
> +				pr_err("Expecting virtio_scsi_cmd_req_pi: %zu,"
> +				       " got %zu\n", sizeof(v_req_pi),
> +				       vq->iov[0].iov_len);
> +				break;
> +			}

Hmm still relying on a specific IOV layout I see :(
It's really a violation of the spec even though it works
fine with Linux guests.
I know this isn't the only place this is broken but
can't we finally fix it?
Since you are touching this code anyway - how about
not adding more code we need to fix later?

It's not too hard - just verify total length is big enough
(instead of an exact match), then call
memcpy_fromiovecend/memcpy_toiovecend.
(or memcpy_fromiovec if you don't mind that iovec is modified).

This will help make sure
we are not making interface mistakes like we did for block
with VIRTIO_BLK_T_SCSI_CMD.


Once vhost scsi code will be clean in this respect, we can set
VIRTIO_F_ANY_LAYOUT to signal this to userspace.


> +			req = (unsigned char *)&v_req_pi;
> +			lunp = &v_req_pi.lun[0];
> +			target = &v_req_pi.lun[1];
> +			req_size = sizeof(v_req_pi);
> +			hdr_pi = true;
> +		} else {
> +			if (unlikely(vq->iov[0].iov_len != sizeof(v_req))) {
> +				pr_err("Expecting virtio_scsi_cmd_req: %zu,"
> +				       " got %zu\n", sizeof(v_req),
> +				       vq->iov[0].iov_len);
> +				break;
> +			}
> +			req = (unsigned char *)&v_req;
> +			lunp = &v_req.lun[0];
> +			target = &v_req.lun[1];
> +			req_size = sizeof(v_req);
> +			hdr_pi = false;
>  		}
> +
>  		pr_debug("Calling __copy_from_user: vq->iov[0].iov_base: %p,"
> -			" len: %zu\n", vq->iov[0].iov_base, sizeof(v_req));
> -		ret = __copy_from_user(&v_req, vq->iov[0].iov_base,
> -				sizeof(v_req));
> +			 " len: %zu\n", vq->iov[0].iov_base, req_size);
> +		ret = __copy_from_user(req, vq->iov[0].iov_base, req_size);
>  		if (unlikely(ret)) {
>  			vq_err(vq, "Faulted on virtio_scsi_cmd_req\n");
>  			break;
>  		}
>  
>  		/* virtio-scsi spec requires byte 0 of the lun to be 1 */
> -		if (unlikely(v_req.lun[0] != 1)) {
> +		if (unlikely(*lunp != 1)) {
>  			vhost_scsi_send_bad_target(vs, vq, head, out);
>  			continue;
>  		}
>  
> -		/* Extract the tpgt */
> -		target = v_req.lun[1];
> -		tpg = ACCESS_ONCE(vs_tpg[target]);
> +		tpg = ACCESS_ONCE(vs_tpg[*target]);
>  
>  		/* Target does not exist, fail the request */
>  		if (unlikely(!tpg)) {
> @@ -1063,17 +1086,69 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
>  			continue;
>  		}
>  
> +		data_niov = data_num;
> +		prot_niov = prot_first = 0;
> +		/*
> +		 * Determine if any proteciton information iovecs are preceeding
> +		 * the actual data payload, and adjust data_niov + data_first
> +		 *
> +		 * Also extract virtio_scsi header bits for vhost_scsi_get_tag()
> +		 */
> +		if (data_num && hdr_pi) {
> +			if (v_req_pi.do_pi_niov) {
> +				if (data_direction != DMA_TO_DEVICE) {
> +					vq_err(vq, "Received non zero do_pi_niov"
> +						", but wrong data_direction\n");
> +					goto err_cmd;
> +				}
> +				prot_niov = v_req_pi.do_pi_niov;
> +			} else if (v_req_pi.di_pi_niov) {
> +				if (data_direction != DMA_FROM_DEVICE) {
> +					vq_err(vq, "Received non zero di_pi_niov"
> +						", but wrong data_direction\n");
> +					goto err_cmd;
> +				}
> +				prot_niov = v_req_pi.di_pi_niov;
> +			}
> +
> +			data_niov = data_num - prot_niov;
> +			prot_first = data_first;
> +			data_first += prot_niov;
> +
> +			tag = v_req_pi.tag;
> +			task_attr = v_req_pi.task_attr;
> +			cdb = &v_req_pi.cdb[0];
> +			lun = ((v_req_pi.lun[2] << 8) | v_req_pi.lun[3]) & 0x3FFF;
> +		} else {
> +			tag = v_req.tag;
> +			task_attr = v_req.task_attr;
> +			cdb = &v_req.cdb[0];
> +			lun = ((v_req.lun[2] << 8) | v_req.lun[3]) & 0x3FFF;
> +		}
>  		exp_data_len = 0;
> -		for (i = 0; i < data_num; i++)
> +		for (i = 0; i < data_niov; i++)
>  			exp_data_len += vq->iov[data_first + i].iov_len;
> +		/*
> +		 * Check that the recieved CDB size does not exceeded our
> +		 * hardcoded max for vhost-scsi
> +		 *
> +		 * TODO what if cdb was too small for varlen cdb header?
> +		 */
> +		if (unlikely(scsi_command_size(cdb) > TCM_VHOST_MAX_CDB_SIZE)) {
> +			vq_err(vq, "Received SCSI CDB with command_size: %d that"
> +				" exceeds SCSI_MAX_VARLEN_CDB_SIZE: %d\n",
> +				scsi_command_size(cdb), TCM_VHOST_MAX_CDB_SIZE);
> +			goto err_cmd;
> +		}
>  
> -		cmd = vhost_scsi_get_tag(vq, tpg, &v_req,
> +		cmd = vhost_scsi_get_tag(vq, tpg, cdb, tag, lun, task_attr,
>  					 exp_data_len, data_direction);
>  		if (IS_ERR(cmd)) {
>  			vq_err(vq, "vhost_scsi_get_tag failed %ld\n",
>  					PTR_ERR(cmd));
>  			goto err_cmd;
>  		}
> +
>  		pr_debug("Allocated tv_cmd: %p exp_data_len: %d, data_direction"
>  			": %d\n", cmd, exp_data_len, data_direction);
>  
> @@ -1081,40 +1156,28 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
>  		cmd->tvc_vq = vq;
>  		cmd->tvc_resp = vq->iov[out].iov_base;
>  
> -		/*
> -		 * Copy in the recieved CDB descriptor into cmd->tvc_cdb
> -		 * that will be used by tcm_vhost_new_cmd_map() and down into
> -		 * target_setup_cmd_from_cdb()
> -		 */
> -		memcpy(cmd->tvc_cdb, v_req.cdb, TCM_VHOST_MAX_CDB_SIZE);
> -		/*
> -		 * Check that the recieved CDB size does not exceeded our
> -		 * hardcoded max for tcm_vhost
> -		 */
> -		/* TODO what if cdb was too small for varlen cdb header? */
> -		if (unlikely(scsi_command_size(cmd->tvc_cdb) >
> -					TCM_VHOST_MAX_CDB_SIZE)) {
> -			vq_err(vq, "Received SCSI CDB with command_size: %d that"
> -				" exceeds SCSI_MAX_VARLEN_CDB_SIZE: %d\n",
> -				scsi_command_size(cmd->tvc_cdb),
> -				TCM_VHOST_MAX_CDB_SIZE);
> -			goto err_free;
> -		}
> -		cmd->tvc_lun = ((v_req.lun[2] << 8) | v_req.lun[3]) & 0x3FFF;
> -
>  		pr_debug("vhost_scsi got command opcode: %#02x, lun: %d\n",
>  			cmd->tvc_cdb[0], cmd->tvc_lun);
>  
> +		if (prot_niov) {
> +			ret = vhost_scsi_map_iov_to_prot(cmd,
> +					&vq->iov[prot_first], prot_niov,
> +					data_direction == DMA_FROM_DEVICE);
> +			if (unlikely(ret)) {
> +				vq_err(vq, "Failed to map iov to"
> +					" prot_sgl\n");
> +				goto err_free;
> +			}
> +		}
>  		if (data_direction != DMA_NONE) {
>  			ret = vhost_scsi_map_iov_to_sgl(cmd,
> -					&vq->iov[data_first], data_num,
> +					&vq->iov[data_first], data_niov,
>  					data_direction == DMA_FROM_DEVICE);
>  			if (unlikely(ret)) {
>  				vq_err(vq, "Failed to map iov to sgl\n");
>  				goto err_free;
>  			}
>  		}
> -
>  		/*
>  		 * Save the descriptor from vhost_get_vq_desc() to be used to
>  		 * complete the virtio-scsi request in TCM callback context via
> -- 
> 1.7.10.4

  reply	other threads:[~2014-04-07  9:16 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-04-06 21:32 [PATCH 0/6] vhost/scsi: Add T10 PI SGL passthrough support Nicholas A. Bellinger
2014-04-06 21:32 ` [PATCH 1/6] virtio-scsi.h: Add virtio_scsi_cmd_req_pi + VIRTIO_SCSI_F_T10_PI bits Nicholas A. Bellinger
2014-04-07  9:55   ` Michael S. Tsirkin
2014-04-08 20:31     ` Paolo Bonzini
2014-04-09 13:22       ` Michael S. Tsirkin
2014-04-13  1:18         ` Paolo Bonzini
2014-04-06 21:32 ` [PATCH 2/6] vhost/scsi: Move sanity check into vhost_scsi_map_iov_to_sgl Nicholas A. Bellinger
2014-04-06 21:32 ` [PATCH 3/6] vhost/scsi: Add preallocation of protection SGLs Nicholas A. Bellinger
2014-04-06 21:32 ` [PATCH 4/6] vhost/scsi: Add T10 PI IOV -> SGL memory mapping logic Nicholas A. Bellinger
2014-04-06 21:32 ` [PATCH 5/6] vhost/scsi: Enable T10 PI IOV -> SGL memory mapping Nicholas A. Bellinger
2014-04-07  9:16   ` Michael S. Tsirkin [this message]
2014-04-08 20:36     ` Paolo Bonzini
2014-04-06 21:32 ` [PATCH 6/6] virtio-scsi: Enable DIF/DIX modes in SCSI host LLD Nicholas A. Bellinger
2014-04-07  8:03   ` Sagi Grimberg
2014-04-07  8:40     ` Nicholas A. Bellinger
2014-04-07  8:45   ` Michael S. Tsirkin
2014-04-07  8:56     ` Nicholas A. Bellinger
2014-04-07  8:56     ` Nicholas A. Bellinger
2014-04-07  9:02       ` Michael S. Tsirkin
2014-04-07  9:13         ` Nicholas A. Bellinger
2014-04-07  9:13         ` Nicholas A. Bellinger
2014-04-08 20:35           ` Paolo Bonzini
2014-04-08 20:35           ` Paolo Bonzini
2014-05-07  9:13       ` Michael S. Tsirkin
2014-05-19 19:07         ` Nicholas A. Bellinger
2014-05-19 19:07         ` Nicholas A. Bellinger
2014-05-19 19:15           ` Michael S. Tsirkin
2014-05-19 20:54             ` Nicholas A. Bellinger
2014-05-19 22:43               ` Michael S. Tsirkin
2014-05-19 20:54             ` Nicholas A. Bellinger
2014-05-20  8:35           ` Paolo Bonzini
2014-05-20  8:35           ` Paolo Bonzini
2014-05-20 18:24             ` Nicholas A. Bellinger
2014-05-20 18:24             ` Nicholas A. Bellinger

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20140407091654.GC14183@redhat.com \
    --to=mst@redhat.com \
    --cc=hare@suse.de \
    --cc=hch@lst.de \
    --cc=hpa@zytor.com \
    --cc=linux-scsi@vger.kernel.org \
    --cc=martin.petersen@oracle.com \
    --cc=nab@daterainc.com \
    --cc=nab@linux-iscsi.org \
    --cc=pbonzini@redhat.com \
    --cc=sagig@dev.mellanox.co.il \
    --cc=sagig@mellanox.com \
    --cc=target-devel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.