virtio: switch to the new virtqueue API
The virtio_req struct has been removed. The new lower-level API has been used instead. This puts more responsibility on the upper abstraction layers, but gives much more descriptor layout flexibility. It is required for e.g. upcoming Virtio-SCSI eventq implementation Change-Id: I9a310c0ba4451bf3a076bef4e90bb75c0046c70a Signed-off-by: Dariusz Stojaczyk <dariuszx.stojaczyk@intel.com> Reviewed-on: https://review.gerrithub.io/391028 Reviewed-by: Ben Walker <benjamin.walker@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com> Tested-by: SPDK Automated Test System <sys_sgsw@intel.com>
This commit is contained in:
parent
b37d1b60f1
commit
451de7e171
@ -82,7 +82,8 @@ struct virtio_scsi_dev {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct virtio_scsi_io_ctx {
|
struct virtio_scsi_io_ctx {
|
||||||
struct virtio_req vreq;
|
struct iovec iov_req;
|
||||||
|
struct iovec iov_resp;
|
||||||
union {
|
union {
|
||||||
struct virtio_scsi_cmd_req req;
|
struct virtio_scsi_cmd_req req;
|
||||||
struct virtio_scsi_ctrl_tmf_req tmf_req;
|
struct virtio_scsi_ctrl_tmf_req tmf_req;
|
||||||
@ -293,23 +294,19 @@ virtio_dev_to_scsi(struct virtio_dev *vdev)
|
|||||||
static struct virtio_scsi_io_ctx *
|
static struct virtio_scsi_io_ctx *
|
||||||
bdev_virtio_init_io_vreq(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
|
bdev_virtio_init_io_vreq(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
|
||||||
{
|
{
|
||||||
struct virtio_req *vreq;
|
|
||||||
struct virtio_scsi_cmd_req *req;
|
struct virtio_scsi_cmd_req *req;
|
||||||
struct virtio_scsi_cmd_resp *resp;
|
struct virtio_scsi_cmd_resp *resp;
|
||||||
struct virtio_scsi_disk *disk = (struct virtio_scsi_disk *)bdev_io->bdev;
|
struct virtio_scsi_disk *disk = (struct virtio_scsi_disk *)bdev_io->bdev;
|
||||||
struct virtio_scsi_io_ctx *io_ctx = (struct virtio_scsi_io_ctx *)bdev_io->driver_ctx;
|
struct virtio_scsi_io_ctx *io_ctx = (struct virtio_scsi_io_ctx *)bdev_io->driver_ctx;
|
||||||
|
|
||||||
vreq = &io_ctx->vreq;
|
|
||||||
req = &io_ctx->req;
|
req = &io_ctx->req;
|
||||||
resp = &io_ctx->resp;
|
resp = &io_ctx->resp;
|
||||||
|
|
||||||
vreq->iov_req.iov_base = req;
|
io_ctx->iov_req.iov_base = req;
|
||||||
vreq->iov_req.iov_len = sizeof(*req);
|
io_ctx->iov_req.iov_len = sizeof(*req);
|
||||||
|
|
||||||
vreq->iov_resp.iov_base = resp;
|
io_ctx->iov_resp.iov_base = resp;
|
||||||
vreq->iov_resp.iov_len = sizeof(*resp);
|
io_ctx->iov_resp.iov_len = sizeof(*resp);
|
||||||
|
|
||||||
vreq->is_write = bdev_io->type != SPDK_BDEV_IO_TYPE_READ;
|
|
||||||
|
|
||||||
memset(req, 0, sizeof(*req));
|
memset(req, 0, sizeof(*req));
|
||||||
req->lun[0] = 1;
|
req->lun[0] = 1;
|
||||||
@ -321,23 +318,18 @@ bdev_virtio_init_io_vreq(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_i
|
|||||||
static struct virtio_scsi_io_ctx *
|
static struct virtio_scsi_io_ctx *
|
||||||
bdev_virtio_init_tmf_vreq(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
|
bdev_virtio_init_tmf_vreq(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
|
||||||
{
|
{
|
||||||
struct virtio_req *vreq;
|
|
||||||
struct virtio_scsi_ctrl_tmf_req *tmf_req;
|
struct virtio_scsi_ctrl_tmf_req *tmf_req;
|
||||||
struct virtio_scsi_ctrl_tmf_resp *tmf_resp;
|
struct virtio_scsi_ctrl_tmf_resp *tmf_resp;
|
||||||
struct virtio_scsi_disk *disk = SPDK_CONTAINEROF(bdev_io->bdev, struct virtio_scsi_disk, bdev);
|
struct virtio_scsi_disk *disk = SPDK_CONTAINEROF(bdev_io->bdev, struct virtio_scsi_disk, bdev);
|
||||||
struct virtio_scsi_io_ctx *io_ctx = (struct virtio_scsi_io_ctx *)bdev_io->driver_ctx;
|
struct virtio_scsi_io_ctx *io_ctx = (struct virtio_scsi_io_ctx *)bdev_io->driver_ctx;
|
||||||
|
|
||||||
vreq = &io_ctx->vreq;
|
|
||||||
tmf_req = &io_ctx->tmf_req;
|
tmf_req = &io_ctx->tmf_req;
|
||||||
tmf_resp = &io_ctx->tmf_resp;
|
tmf_resp = &io_ctx->tmf_resp;
|
||||||
|
|
||||||
vreq->iov = NULL;
|
io_ctx->iov_req.iov_base = tmf_req;
|
||||||
vreq->iov_req.iov_base = tmf_req;
|
io_ctx->iov_req.iov_len = sizeof(*tmf_req);
|
||||||
vreq->iov_req.iov_len = sizeof(*tmf_req);
|
io_ctx->iov_resp.iov_base = tmf_resp;
|
||||||
vreq->iov_resp.iov_base = tmf_resp;
|
io_ctx->iov_resp.iov_len = sizeof(*tmf_resp);
|
||||||
vreq->iov_resp.iov_len = sizeof(*tmf_resp);
|
|
||||||
vreq->iovcnt = 0;
|
|
||||||
vreq->is_write = false;
|
|
||||||
|
|
||||||
memset(tmf_req, 0, sizeof(*tmf_req));
|
memset(tmf_req, 0, sizeof(*tmf_req));
|
||||||
tmf_req->lun[0] = 1;
|
tmf_req->lun[0] = 1;
|
||||||
@ -350,18 +342,31 @@ static void
|
|||||||
bdev_virtio_send_io(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
|
bdev_virtio_send_io(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
|
||||||
{
|
{
|
||||||
struct bdev_virtio_io_channel *virtio_channel = spdk_io_channel_get_ctx(ch);
|
struct bdev_virtio_io_channel *virtio_channel = spdk_io_channel_get_ctx(ch);
|
||||||
|
struct virtqueue *vq = virtio_channel->vq;
|
||||||
struct virtio_scsi_io_ctx *io_ctx = (struct virtio_scsi_io_ctx *)bdev_io->driver_ctx;
|
struct virtio_scsi_io_ctx *io_ctx = (struct virtio_scsi_io_ctx *)bdev_io->driver_ctx;
|
||||||
struct virtio_req *vreq = &io_ctx->vreq;
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
rc = virtio_xmit_pkt(virtio_channel->vq, vreq);
|
rc = virtqueue_req_start(vq, bdev_io, bdev_io->u.bdev.iovcnt + 2);
|
||||||
if (spdk_likely(rc == 0)) {
|
if (rc == -ENOMEM) {
|
||||||
return;
|
|
||||||
} else if (rc == -ENOMEM) {
|
|
||||||
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_NOMEM);
|
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_NOMEM);
|
||||||
} else {
|
return;
|
||||||
|
} else if (rc != 0) {
|
||||||
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
|
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtqueue_req_add_iovs(vq, &io_ctx->iov_req, 1, SPDK_VIRTIO_DESC_RO);
|
||||||
|
if (bdev_io->type == SPDK_BDEV_IO_TYPE_READ) {
|
||||||
|
virtqueue_req_add_iovs(vq, &io_ctx->iov_resp, 1, SPDK_VIRTIO_DESC_WR);
|
||||||
|
virtqueue_req_add_iovs(vq, bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt,
|
||||||
|
SPDK_VIRTIO_DESC_WR);
|
||||||
|
} else {
|
||||||
|
virtqueue_req_add_iovs(vq, bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt,
|
||||||
|
SPDK_VIRTIO_DESC_RO);
|
||||||
|
virtqueue_req_add_iovs(vq, &io_ctx->iov_resp, 1, SPDK_VIRTIO_DESC_WR);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtqueue_req_flush(vq);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -369,18 +374,15 @@ bdev_virtio_rw(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
|
|||||||
{
|
{
|
||||||
struct virtio_scsi_disk *disk = SPDK_CONTAINEROF(bdev_io->bdev, struct virtio_scsi_disk, bdev);
|
struct virtio_scsi_disk *disk = SPDK_CONTAINEROF(bdev_io->bdev, struct virtio_scsi_disk, bdev);
|
||||||
struct virtio_scsi_io_ctx *io_ctx = bdev_virtio_init_io_vreq(ch, bdev_io);
|
struct virtio_scsi_io_ctx *io_ctx = bdev_virtio_init_io_vreq(ch, bdev_io);
|
||||||
struct virtio_req *vreq = &io_ctx->vreq;
|
|
||||||
struct virtio_scsi_cmd_req *req = &io_ctx->req;
|
struct virtio_scsi_cmd_req *req = &io_ctx->req;
|
||||||
|
bool is_write = bdev_io->type == SPDK_BDEV_IO_TYPE_WRITE;
|
||||||
vreq->iov = bdev_io->u.bdev.iovs;
|
|
||||||
vreq->iovcnt = bdev_io->u.bdev.iovcnt;
|
|
||||||
|
|
||||||
if (disk->info.num_blocks > (1ULL << 32)) {
|
if (disk->info.num_blocks > (1ULL << 32)) {
|
||||||
req->cdb[0] = vreq->is_write ? SPDK_SBC_WRITE_16 : SPDK_SBC_READ_16;
|
req->cdb[0] = is_write ? SPDK_SBC_WRITE_16 : SPDK_SBC_READ_16;
|
||||||
to_be64(&req->cdb[2], bdev_io->u.bdev.offset_blocks);
|
to_be64(&req->cdb[2], bdev_io->u.bdev.offset_blocks);
|
||||||
to_be32(&req->cdb[10], bdev_io->u.bdev.num_blocks);
|
to_be32(&req->cdb[10], bdev_io->u.bdev.num_blocks);
|
||||||
} else {
|
} else {
|
||||||
req->cdb[0] = vreq->is_write ? SPDK_SBC_WRITE_10 : SPDK_SBC_READ_10;
|
req->cdb[0] = is_write ? SPDK_SBC_WRITE_10 : SPDK_SBC_READ_10;
|
||||||
to_be32(&req->cdb[2], bdev_io->u.bdev.offset_blocks);
|
to_be32(&req->cdb[2], bdev_io->u.bdev.offset_blocks);
|
||||||
to_be16(&req->cdb[7], bdev_io->u.bdev.num_blocks);
|
to_be16(&req->cdb[7], bdev_io->u.bdev.num_blocks);
|
||||||
}
|
}
|
||||||
@ -413,16 +415,13 @@ static void
|
|||||||
bdev_virtio_unmap(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
|
bdev_virtio_unmap(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
|
||||||
{
|
{
|
||||||
struct virtio_scsi_io_ctx *io_ctx = bdev_virtio_init_io_vreq(ch, bdev_io);
|
struct virtio_scsi_io_ctx *io_ctx = bdev_virtio_init_io_vreq(ch, bdev_io);
|
||||||
struct virtio_req *vreq = &io_ctx->vreq;
|
|
||||||
struct virtio_scsi_cmd_req *req = &io_ctx->req;
|
struct virtio_scsi_cmd_req *req = &io_ctx->req;
|
||||||
struct spdk_scsi_unmap_bdesc *desc, *first_desc;
|
struct spdk_scsi_unmap_bdesc *desc, *first_desc;
|
||||||
uint8_t *buf;
|
uint8_t *buf;
|
||||||
uint64_t offset_blocks, num_blocks;
|
uint64_t offset_blocks, num_blocks;
|
||||||
uint16_t cmd_len;
|
uint16_t cmd_len;
|
||||||
|
|
||||||
vreq->iov = bdev_io->u.bdev.iovs;
|
buf = bdev_io->u.bdev.iov.iov_base;
|
||||||
vreq->iovcnt = bdev_io->u.bdev.iovcnt;
|
|
||||||
buf = vreq->iov->iov_base;
|
|
||||||
|
|
||||||
offset_blocks = bdev_io->u.bdev.offset_blocks;
|
offset_blocks = bdev_io->u.bdev.offset_blocks;
|
||||||
num_blocks = bdev_io->u.bdev.num_blocks;
|
num_blocks = bdev_io->u.bdev.num_blocks;
|
||||||
@ -592,10 +591,9 @@ get_scsi_status(struct virtio_scsi_cmd_resp *resp, int *sk, int *asc, int *ascq)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
bdev_virtio_io_cpl(struct virtio_req *req)
|
bdev_virtio_io_cpl(struct spdk_bdev_io *bdev_io)
|
||||||
{
|
{
|
||||||
struct virtio_scsi_io_ctx *io_ctx = SPDK_CONTAINEROF(req, struct virtio_scsi_io_ctx, vreq);
|
struct virtio_scsi_io_ctx *io_ctx = (struct virtio_scsi_io_ctx *)bdev_io->driver_ctx;
|
||||||
struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(io_ctx);
|
|
||||||
int sk, asc, ascq;
|
int sk, asc, ascq;
|
||||||
|
|
||||||
get_scsi_status(&io_ctx->resp, &sk, &asc, &ascq);
|
get_scsi_status(&io_ctx->resp, &sk, &asc, &ascq);
|
||||||
@ -607,27 +605,27 @@ bdev_virtio_poll(void *arg)
|
|||||||
{
|
{
|
||||||
struct bdev_virtio_io_channel *ch = arg;
|
struct bdev_virtio_io_channel *ch = arg;
|
||||||
struct virtio_scsi_dev *svdev = ch->svdev;
|
struct virtio_scsi_dev *svdev = ch->svdev;
|
||||||
struct virtio_req *req[32];
|
void *io[32];
|
||||||
|
uint32_t io_len[32];
|
||||||
uint16_t i, cnt;
|
uint16_t i, cnt;
|
||||||
|
|
||||||
cnt = virtio_recv_pkts(ch->vq, req, SPDK_COUNTOF(req));
|
cnt = virtio_recv_pkts(ch->vq, (void **)io, io_len, SPDK_COUNTOF(io));
|
||||||
for (i = 0; i < cnt; ++i) {
|
for (i = 0; i < cnt; ++i) {
|
||||||
if (spdk_unlikely(svdev->scan_ctx &&
|
if (spdk_unlikely(svdev->scan_ctx &&
|
||||||
req[i] == &svdev->scan_ctx->io_ctx.vreq)) {
|
io[i] == &svdev->scan_ctx->io_ctx)) {
|
||||||
process_scan_resp(svdev->scan_ctx);
|
process_scan_resp(svdev->scan_ctx);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
bdev_virtio_io_cpl(req[i]);
|
bdev_virtio_io_cpl(io[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
bdev_virtio_tmf_cpl_cb(void *ctx)
|
bdev_virtio_tmf_cpl_cb(void *ctx)
|
||||||
{
|
{
|
||||||
struct virtio_req *req = ctx;
|
struct spdk_bdev_io *bdev_io = ctx;
|
||||||
struct virtio_scsi_io_ctx *io_ctx = SPDK_CONTAINEROF(req, struct virtio_scsi_io_ctx, vreq);
|
struct virtio_scsi_io_ctx *io_ctx = (struct virtio_scsi_io_ctx *)bdev_io->driver_ctx;
|
||||||
struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(io_ctx);
|
|
||||||
|
|
||||||
if (io_ctx->tmf_resp.response == VIRTIO_SCSI_S_OK) {
|
if (io_ctx->tmf_resp.response == VIRTIO_SCSI_S_OK) {
|
||||||
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS);
|
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS);
|
||||||
@ -637,12 +635,9 @@ bdev_virtio_tmf_cpl_cb(void *ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
bdev_virtio_tmf_cpl(struct virtio_req *req)
|
bdev_virtio_tmf_cpl(struct spdk_bdev_io *bdev_io)
|
||||||
{
|
{
|
||||||
struct virtio_scsi_io_ctx *io_ctx = SPDK_CONTAINEROF(req, struct virtio_scsi_io_ctx, vreq);
|
spdk_thread_send_msg(spdk_bdev_io_get_thread(bdev_io), bdev_virtio_tmf_cpl_cb, bdev_io);
|
||||||
struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(io_ctx);
|
|
||||||
|
|
||||||
spdk_thread_send_msg(spdk_bdev_io_get_thread(bdev_io), bdev_virtio_tmf_cpl_cb, req);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -679,9 +674,18 @@ static int
|
|||||||
bdev_virtio_send_tmf_io(struct virtqueue *ctrlq, struct spdk_bdev_io *bdev_io)
|
bdev_virtio_send_tmf_io(struct virtqueue *ctrlq, struct spdk_bdev_io *bdev_io)
|
||||||
{
|
{
|
||||||
struct virtio_scsi_io_ctx *io_ctx = (struct virtio_scsi_io_ctx *)bdev_io->driver_ctx;
|
struct virtio_scsi_io_ctx *io_ctx = (struct virtio_scsi_io_ctx *)bdev_io->driver_ctx;
|
||||||
struct virtio_req *vreq = &io_ctx->vreq;
|
int rc;
|
||||||
|
|
||||||
return virtio_xmit_pkt(ctrlq, vreq);
|
rc = virtqueue_req_start(ctrlq, bdev_io, 2);
|
||||||
|
if (rc != 0) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtqueue_req_add_iovs(ctrlq, &io_ctx->iov_req, 1, SPDK_VIRTIO_DESC_RO);
|
||||||
|
virtqueue_req_add_iovs(ctrlq, &io_ctx->iov_resp, 1, SPDK_VIRTIO_DESC_WR);
|
||||||
|
|
||||||
|
virtqueue_req_flush(ctrlq);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -690,21 +694,22 @@ bdev_virtio_ctrlq_poll(void *arg)
|
|||||||
struct virtio_dev *vdev = arg;
|
struct virtio_dev *vdev = arg;
|
||||||
struct virtqueue *ctrlq = vdev->vqs[VIRTIO_SCSI_CONTROLQ];
|
struct virtqueue *ctrlq = vdev->vqs[VIRTIO_SCSI_CONTROLQ];
|
||||||
struct spdk_ring *send_ring = ctrlq->poller_ctx;
|
struct spdk_ring *send_ring = ctrlq->poller_ctx;
|
||||||
void *req[16];
|
struct spdk_bdev_io *bdev_io[16];
|
||||||
|
uint32_t io_len[16];
|
||||||
uint16_t i, cnt;
|
uint16_t i, cnt;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
cnt = spdk_ring_dequeue(send_ring, req, SPDK_COUNTOF(req));
|
cnt = spdk_ring_dequeue(send_ring, (void **)bdev_io, SPDK_COUNTOF(bdev_io));
|
||||||
for (i = 0; i < cnt; ++i) {
|
for (i = 0; i < cnt; ++i) {
|
||||||
rc = bdev_virtio_send_tmf_io(ctrlq, req[i]);
|
rc = bdev_virtio_send_tmf_io(ctrlq, bdev_io[i]);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
bdev_virtio_tmf_abort(req[i], rc);
|
bdev_virtio_tmf_abort(bdev_io[i], rc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cnt = virtio_recv_pkts(ctrlq, (struct virtio_req **)req, SPDK_COUNTOF(req));
|
cnt = virtio_recv_pkts(ctrlq, (void **)bdev_io, io_len, SPDK_COUNTOF(bdev_io));
|
||||||
for (i = 0; i < cnt; ++i) {
|
for (i = 0; i < cnt; ++i) {
|
||||||
bdev_virtio_tmf_cpl(req[i]);
|
bdev_virtio_tmf_cpl(bdev_io[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -808,6 +813,26 @@ _virtio_scsi_dev_scan_finish(struct virtio_scsi_scan_base *base)
|
|||||||
spdk_dma_free(base);
|
spdk_dma_free(base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
send_scan_io(struct virtio_scsi_scan_base *base)
|
||||||
|
{
|
||||||
|
struct virtio_scsi_io_ctx *io_ctx = &base->io_ctx;
|
||||||
|
struct virtqueue *vq = base->channel->vq;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = virtqueue_req_start(vq, io_ctx, 3);
|
||||||
|
if (rc != 0) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtqueue_req_add_iovs(vq, &io_ctx->iov_req, 1, SPDK_VIRTIO_DESC_RO);
|
||||||
|
virtqueue_req_add_iovs(vq, &io_ctx->iov_resp, 1, SPDK_VIRTIO_DESC_WR);
|
||||||
|
virtqueue_req_add_iovs(vq, &base->iov, 1, SPDK_VIRTIO_DESC_WR);
|
||||||
|
|
||||||
|
virtqueue_req_flush(vq);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
send_inquiry_vpd(struct virtio_scsi_scan_base *base, uint8_t target_id, uint8_t page_code)
|
send_inquiry_vpd(struct virtio_scsi_scan_base *base, uint8_t target_id, uint8_t page_code)
|
||||||
{
|
{
|
||||||
@ -826,7 +851,7 @@ send_inquiry_vpd(struct virtio_scsi_scan_base *base, uint8_t target_id, uint8_t
|
|||||||
inquiry_cdb->page_code = page_code;
|
inquiry_cdb->page_code = page_code;
|
||||||
to_be16(inquiry_cdb->alloc_len, iov[0].iov_len);
|
to_be16(inquiry_cdb->alloc_len, iov[0].iov_len);
|
||||||
|
|
||||||
rc = virtio_xmit_pkt(base->channel->vq, &base->io_ctx.vreq);
|
rc = send_scan_io(base);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
@ -846,7 +871,7 @@ send_read_cap_10(struct virtio_scsi_scan_base *base, uint8_t target_id)
|
|||||||
iov[0].iov_len = 8;
|
iov[0].iov_len = 8;
|
||||||
req->cdb[0] = SPDK_SBC_READ_CAPACITY_10;
|
req->cdb[0] = SPDK_SBC_READ_CAPACITY_10;
|
||||||
|
|
||||||
rc = virtio_xmit_pkt(base->channel->vq, &base->io_ctx.vreq);
|
rc = send_scan_io(base);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
@ -868,7 +893,7 @@ send_read_cap_16(struct virtio_scsi_scan_base *base, uint8_t target_id)
|
|||||||
req->cdb[1] = SPDK_SBC_SAI_READ_CAPACITY_16;
|
req->cdb[1] = SPDK_SBC_SAI_READ_CAPACITY_16;
|
||||||
to_be32(&req->cdb[10], iov[0].iov_len);
|
to_be32(&req->cdb[10], iov[0].iov_len);
|
||||||
|
|
||||||
rc = virtio_xmit_pkt(base->channel->vq, &base->io_ctx.vreq);
|
rc = send_scan_io(base);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
@ -885,7 +910,7 @@ send_test_unit_ready(struct virtio_scsi_scan_base *base, uint8_t target_id)
|
|||||||
req->lun[1] = target_id;
|
req->lun[1] = target_id;
|
||||||
req->cdb[0] = SPDK_SPC_TEST_UNIT_READY;
|
req->cdb[0] = SPDK_SPC_TEST_UNIT_READY;
|
||||||
|
|
||||||
rc = virtio_xmit_pkt(base->channel->vq, &base->io_ctx.vreq);
|
rc = send_scan_io(base);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
@ -903,7 +928,7 @@ send_start_stop_unit(struct virtio_scsi_scan_base *base, uint8_t target_id)
|
|||||||
req->cdb[0] = SPDK_SBC_START_STOP_UNIT;
|
req->cdb[0] = SPDK_SBC_START_STOP_UNIT;
|
||||||
req->cdb[4] = SPDK_SBC_START_STOP_UNIT_START_BIT;
|
req->cdb[4] = SPDK_SBC_START_STOP_UNIT_START_BIT;
|
||||||
|
|
||||||
rc = virtio_xmit_pkt(base->channel->vq, &base->io_ctx.vreq);
|
rc = send_scan_io(base);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
@ -994,7 +1019,7 @@ process_scan_inquiry_vpd_supported_vpd_pages(struct virtio_scsi_scan_base *base)
|
|||||||
uint16_t i;
|
uint16_t i;
|
||||||
|
|
||||||
page_length = from_be16(vpd_data + 2);
|
page_length = from_be16(vpd_data + 2);
|
||||||
num_supported_pages = spdk_min(page_length, base->io_ctx.vreq.iov->iov_len - 4);
|
num_supported_pages = spdk_min(page_length, base->iov.iov_len - 4);
|
||||||
|
|
||||||
for (i = 0; i < num_supported_pages; i++) {
|
for (i = 0; i < num_supported_pages; i++) {
|
||||||
if (supported_vpd_pages[i] == SPDK_SPC_VPD_BLOCK_THIN_PROVISION) {
|
if (supported_vpd_pages[i] == SPDK_SPC_VPD_BLOCK_THIN_PROVISION) {
|
||||||
@ -1147,8 +1172,8 @@ process_scan_resp(struct virtio_scsi_scan_base *base)
|
|||||||
int rc, sk, asc, ascq;
|
int rc, sk, asc, ascq;
|
||||||
uint8_t target_id;
|
uint8_t target_id;
|
||||||
|
|
||||||
if (base->io_ctx.vreq.iov_req.iov_len < sizeof(struct virtio_scsi_cmd_req) ||
|
if (base->io_ctx.iov_req.iov_len < sizeof(struct virtio_scsi_cmd_req) ||
|
||||||
base->io_ctx.vreq.iov_resp.iov_len < sizeof(struct virtio_scsi_cmd_resp)) {
|
base->io_ctx.iov_resp.iov_len < sizeof(struct virtio_scsi_cmd_resp)) {
|
||||||
SPDK_ERRLOG("Received target scan message with invalid length.\n");
|
SPDK_ERRLOG("Received target scan message with invalid length.\n");
|
||||||
_virtio_scsi_dev_scan_finish(base);
|
_virtio_scsi_dev_scan_finish(base);
|
||||||
return;
|
return;
|
||||||
@ -1171,7 +1196,7 @@ process_scan_resp(struct virtio_scsi_scan_base *base)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* resend the same request */
|
/* resend the same request */
|
||||||
rc = virtio_xmit_pkt(base->channel->vq, &base->io_ctx.vreq);
|
rc = send_scan_io(base);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
@ -1210,29 +1235,25 @@ process_scan_resp(struct virtio_scsi_scan_base *base)
|
|||||||
static int
|
static int
|
||||||
_virtio_scsi_dev_scan_next(struct virtio_scsi_scan_base *base)
|
_virtio_scsi_dev_scan_next(struct virtio_scsi_scan_base *base)
|
||||||
{
|
{
|
||||||
struct iovec *iov;
|
struct virtio_scsi_io_ctx *io_ctx;
|
||||||
struct virtio_req *vreq;
|
|
||||||
struct virtio_scsi_cmd_req *req;
|
struct virtio_scsi_cmd_req *req;
|
||||||
struct virtio_scsi_cmd_resp *resp;
|
struct virtio_scsi_cmd_resp *resp;
|
||||||
struct spdk_scsi_cdb_inquiry *cdb;
|
struct spdk_scsi_cdb_inquiry *cdb;
|
||||||
|
struct iovec *iov;
|
||||||
|
|
||||||
memset(&base->info, 0, sizeof(base->info));
|
memset(&base->info, 0, sizeof(base->info));
|
||||||
base->info.target = base->target;
|
base->info.target = base->target;
|
||||||
|
|
||||||
vreq = &base->io_ctx.vreq;
|
io_ctx = &base->io_ctx;
|
||||||
req = &base->io_ctx.req;
|
req = &io_ctx->req;
|
||||||
resp = &base->io_ctx.resp;
|
resp = &io_ctx->resp;
|
||||||
iov = &base->iov;
|
iov = &base->iov;
|
||||||
|
|
||||||
vreq->iov = iov;
|
io_ctx->iov_req.iov_base = req;
|
||||||
vreq->iovcnt = 1;
|
io_ctx->iov_req.iov_len = sizeof(*req);
|
||||||
vreq->is_write = 0;
|
|
||||||
|
|
||||||
vreq->iov_req.iov_base = (void *)req;
|
io_ctx->iov_resp.iov_base = resp;
|
||||||
vreq->iov_req.iov_len = sizeof(*req);
|
io_ctx->iov_resp.iov_len = sizeof(*resp);
|
||||||
|
|
||||||
vreq->iov_resp.iov_base = (void *)resp;
|
|
||||||
vreq->iov_resp.iov_len = sizeof(*resp);
|
|
||||||
|
|
||||||
iov[0].iov_base = (void *)&base->payload;
|
iov[0].iov_base = (void *)&base->payload;
|
||||||
iov[0].iov_len = BDEV_VIRTIO_SCAN_PAYLOAD_SIZE;
|
iov[0].iov_len = BDEV_VIRTIO_SCAN_PAYLOAD_SIZE;
|
||||||
@ -1245,7 +1266,7 @@ _virtio_scsi_dev_scan_next(struct virtio_scsi_scan_base *base)
|
|||||||
to_be16(cdb->alloc_len, BDEV_VIRTIO_SCAN_PAYLOAD_SIZE);
|
to_be16(cdb->alloc_len, BDEV_VIRTIO_SCAN_PAYLOAD_SIZE);
|
||||||
|
|
||||||
base->retries = SCAN_REQUEST_RETRIES;
|
base->retries = SCAN_REQUEST_RETRIES;
|
||||||
return virtio_xmit_pkt(base->channel->vq, vreq);
|
return send_scan_io(base);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -399,7 +399,7 @@ vq_ring_free_chain(struct virtqueue *vq, uint16_t desc_idx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static uint16_t
|
static uint16_t
|
||||||
virtqueue_dequeue_burst_rx(struct virtqueue *vq, struct virtio_req **rx_pkts,
|
virtqueue_dequeue_burst_rx(struct virtqueue *vq, void **rx_pkts,
|
||||||
uint32_t *len, uint16_t num)
|
uint32_t *len, uint16_t num)
|
||||||
{
|
{
|
||||||
struct vring_used_elem *uep;
|
struct vring_used_elem *uep;
|
||||||
@ -542,89 +542,27 @@ virtqueue_req_add_iovs(struct virtqueue *vq, struct iovec *iovs, uint16_t iovcnt
|
|||||||
vq->vq_free_cnt = (uint16_t)(vq->vq_free_cnt - iovcnt);
|
vq->vq_free_cnt = (uint16_t)(vq->vq_free_cnt - iovcnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
virtqueue_enqueue_xmit(struct virtqueue *vq, struct virtio_req *req)
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
rc = virtqueue_req_start(vq, req, req->iovcnt + 2);
|
|
||||||
if (rc != 0) {
|
|
||||||
goto err_abort_nospc;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtqueue_req_add_iovs(vq, &req->iov_req, 1, SPDK_VIRTIO_DESC_RO);
|
|
||||||
if (req->is_write) {
|
|
||||||
virtqueue_req_add_iovs(vq, req->iov, req->iovcnt, SPDK_VIRTIO_DESC_RO);
|
|
||||||
virtqueue_req_add_iovs(vq, &req->iov_resp, 1, SPDK_VIRTIO_DESC_WR);
|
|
||||||
} else {
|
|
||||||
virtqueue_req_add_iovs(vq, &req->iov_resp, 1, SPDK_VIRTIO_DESC_WR);
|
|
||||||
virtqueue_req_add_iovs(vq, req->iov, req->iovcnt, SPDK_VIRTIO_DESC_WR);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
err_abort_nospc:
|
|
||||||
virtqueue_req_abort(vq);
|
|
||||||
SPDK_DEBUGLOG(SPDK_LOG_VIRTIO_DEV,
|
|
||||||
"not enough free descriptors. requested %"PRIu32", got %"PRIu16"\n",
|
|
||||||
req->iovcnt + 2, vq->vq_free_cnt);
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define VIRTIO_MBUF_BURST_SZ 64
|
|
||||||
#define DESC_PER_CACHELINE (RTE_CACHE_LINE_SIZE / sizeof(struct vring_desc))
|
#define DESC_PER_CACHELINE (RTE_CACHE_LINE_SIZE / sizeof(struct vring_desc))
|
||||||
uint16_t
|
uint16_t
|
||||||
virtio_recv_pkts(struct virtqueue *vq, struct virtio_req **reqs, uint16_t nb_pkts)
|
virtio_recv_pkts(struct virtqueue *vq, void **io, uint32_t *len, uint16_t nb_pkts)
|
||||||
{
|
{
|
||||||
struct virtio_req *rxm;
|
uint16_t nb_used, num;
|
||||||
uint16_t nb_used, num, nb_rx;
|
|
||||||
uint32_t len[VIRTIO_MBUF_BURST_SZ];
|
|
||||||
struct virtio_req *rcv_pkts[VIRTIO_MBUF_BURST_SZ];
|
|
||||||
uint32_t i;
|
|
||||||
|
|
||||||
assert(virtio_dev_get_status(vq->vdev) & VIRTIO_CONFIG_S_DRIVER_OK);
|
assert(virtio_dev_get_status(vq->vdev) & VIRTIO_CONFIG_S_DRIVER_OK);
|
||||||
|
|
||||||
nb_rx = 0;
|
|
||||||
nb_used = VIRTQUEUE_NUSED(vq);
|
nb_used = VIRTQUEUE_NUSED(vq);
|
||||||
|
|
||||||
virtio_rmb();
|
virtio_rmb();
|
||||||
|
|
||||||
num = (uint16_t)(spdk_likely(nb_used <= nb_pkts) ? nb_used : nb_pkts);
|
num = (uint16_t)(spdk_likely(nb_used <= nb_pkts) ? nb_used : nb_pkts);
|
||||||
num = (uint16_t)(spdk_likely(num <= VIRTIO_MBUF_BURST_SZ) ? num : VIRTIO_MBUF_BURST_SZ);
|
|
||||||
if (spdk_likely(num > DESC_PER_CACHELINE)) {
|
if (spdk_likely(num > DESC_PER_CACHELINE)) {
|
||||||
num = num - ((vq->vq_used_cons_idx + num) % DESC_PER_CACHELINE);
|
num = num - ((vq->vq_used_cons_idx + num) % DESC_PER_CACHELINE);
|
||||||
}
|
}
|
||||||
|
|
||||||
num = virtqueue_dequeue_burst_rx(vq, rcv_pkts, len, num);
|
num = virtqueue_dequeue_burst_rx(vq, io, len, num);
|
||||||
SPDK_DEBUGLOG(SPDK_LOG_VIRTIO_DEV, "used:%"PRIu16" dequeue:%"PRIu16"\n", nb_used, num);
|
SPDK_DEBUGLOG(SPDK_LOG_VIRTIO_DEV, "used:%"PRIu16" dequeue:%"PRIu16"\n", nb_used, num);
|
||||||
|
|
||||||
for (i = 0; i < num ; i++) {
|
return num;
|
||||||
rxm = rcv_pkts[i];
|
|
||||||
|
|
||||||
SPDK_DEBUGLOG(SPDK_LOG_VIRTIO_DEV, "packet len:%"PRIu32"\n", len[i]);
|
|
||||||
|
|
||||||
rxm->data_transferred = (uint16_t)(len[i]);
|
|
||||||
|
|
||||||
reqs[nb_rx++] = rxm;
|
|
||||||
}
|
|
||||||
|
|
||||||
return nb_rx;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
virtio_xmit_pkt(struct virtqueue *vq, struct virtio_req *req)
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
assert(virtio_dev_get_status(vq->vdev) & VIRTIO_CONFIG_S_DRIVER_OK);
|
|
||||||
virtio_rmb();
|
|
||||||
|
|
||||||
rc = virtqueue_enqueue_xmit(vq, req);
|
|
||||||
if (spdk_unlikely(rc != 0)) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtqueue_req_flush(vq);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -181,15 +181,6 @@ enum spdk_virtio_desc_type {
|
|||||||
/* TODO VIRTIO_DESC_INDIRECT */
|
/* TODO VIRTIO_DESC_INDIRECT */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct virtio_req {
|
|
||||||
struct iovec *iov;
|
|
||||||
struct iovec iov_req;
|
|
||||||
struct iovec iov_resp;
|
|
||||||
uint32_t iovcnt;
|
|
||||||
int is_write;
|
|
||||||
uint32_t data_transferred;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct virtio_driver {
|
struct virtio_driver {
|
||||||
TAILQ_HEAD(, virtio_dev) scsi_devs;
|
TAILQ_HEAD(, virtio_dev) scsi_devs;
|
||||||
};
|
};
|
||||||
@ -211,8 +202,7 @@ typedef int (*virtio_pci_create_cb)(struct virtio_pci_ctx *pci_ctx);
|
|||||||
(1ULL << VIRTIO_SCSI_F_INOUT | \
|
(1ULL << VIRTIO_SCSI_F_INOUT | \
|
||||||
1ULL << VIRTIO_F_VERSION_1)
|
1ULL << VIRTIO_F_VERSION_1)
|
||||||
|
|
||||||
uint16_t virtio_recv_pkts(struct virtqueue *vq, struct virtio_req **reqs,
|
uint16_t virtio_recv_pkts(struct virtqueue *vq, void **io, uint32_t *len, uint16_t io_cnt);
|
||||||
uint16_t nb_pkts);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start a new request on the current vring head position. The request will
|
* Start a new request on the current vring head position. The request will
|
||||||
@ -265,18 +255,6 @@ void virtqueue_req_abort(struct virtqueue *vq);
|
|||||||
void virtqueue_req_add_iovs(struct virtqueue *vq, struct iovec *iovs, uint16_t iovcnt,
|
void virtqueue_req_add_iovs(struct virtqueue *vq, struct iovec *iovs, uint16_t iovcnt,
|
||||||
enum spdk_virtio_desc_type desc_type);
|
enum spdk_virtio_desc_type desc_type);
|
||||||
|
|
||||||
/**
|
|
||||||
* Put given request into the virtqueue. The virtio device owning
|
|
||||||
* the virtqueue must be started. This will also send an interrupt unless
|
|
||||||
* the host explicitly set VRING_USED_F_NO_NOTIFY in virtqueue flags.
|
|
||||||
*
|
|
||||||
* \param vq virtio queue
|
|
||||||
* \param req virtio request
|
|
||||||
* \return 0 on success. In case the ring is full or no free descriptors
|
|
||||||
* are available -ENOMEM is returned.
|
|
||||||
*/
|
|
||||||
int virtio_xmit_pkt(struct virtqueue *vq, struct virtio_req *req);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a virtio device. The device will be in stopped state by default.
|
* Construct a virtio device. The device will be in stopped state by default.
|
||||||
* Before doing any I/O, it has to be manually started via \c virtio_dev_restart.
|
* Before doing any I/O, it has to be manually started via \c virtio_dev_restart.
|
||||||
|
Loading…
Reference in New Issue
Block a user