From 43be836ae5a1d0810c8d2654d407cebdfef8d4c4 Mon Sep 17 00:00:00 2001 From: Dariusz Stojaczyk Date: Mon, 4 Sep 2017 19:23:46 +0200 Subject: [PATCH] bdev_virtio: use READ CAPACITY (10) for initial target scan Added READ CAPACITY (10) support. This is a work towards supporting both (10) and (16)-bit SCSI commands. If READ CAPACITY (10) returns 0xFFFFFFFF as max lba, a READ CAPACITY (16) is sent. As specified in SBC-3 5.10.2 READ CAPACITY (10): ``` If the number of logical blocks exceeds the maximum value that is able to be specified in the RETURNED LOGICAL BLOCK ADDRESS field, the device server shall set the RETURNED LOGICAL BLOCK ADDRESS field to FFFFFFFFh. The application client should then issue a READ CAPACITY (16) command (see 3.27) to retrieve the READ CAPACITY (16) parameter data. ``` Change-Id: If82bc45e904e91d95b124724e895350098337ae9 Signed-off-by: Dariusz Stojaczyk Reviewed-on: https://review.gerrithub.io/377091 Tested-by: SPDK Automated Test System Reviewed-by: Jim Harris Reviewed-by: Changpeng Liu Reviewed-by: Daniel Verkamp --- lib/bdev/virtio/bdev_virtio.c | 90 +++++++++++++++++++++++++++-------- 1 file changed, 71 insertions(+), 19 deletions(-) diff --git a/lib/bdev/virtio/bdev_virtio.c b/lib/bdev/virtio/bdev_virtio.c index 1f25db10e..b9af17655 100644 --- a/lib/bdev/virtio/bdev_virtio.c +++ b/lib/bdev/virtio/bdev_virtio.c @@ -310,31 +310,53 @@ scan_target_finish(struct virtio_scsi_scan_base *base) spdk_bdev_module_init_done(SPDK_GET_BDEV_MODULE(virtio_scsi)); } -static int -process_scan_inquiry(struct virtio_scsi_scan_base *base, struct virtio_req *vreq) +static void +send_read_cap_10(struct virtio_scsi_scan_base *base, uint8_t target_id, struct virtio_req *vreq) { struct iovec *iov = vreq->iov; struct virtio_scsi_cmd_req *req = vreq->iov_req.iov_base; + + memset(req, 0, sizeof(*req)); + req->lun[0] = 1; + req->lun[1] = target_id; + + iov[0].iov_len = 8; + req->cdb[0] = SPDK_SBC_READ_CAPACITY_10; + + virtio_xmit_pkts(base->vdev->vqs[2], vreq); +} + +static void +send_read_cap_16(struct virtio_scsi_scan_base *base, uint8_t target_id, struct virtio_req *vreq) +{ + struct iovec *iov = vreq->iov; + struct virtio_scsi_cmd_req *req = vreq->iov_req.iov_base; + + memset(req, 0, sizeof(*req)); + req->lun[0] = 1; + req->lun[1] = target_id; + + iov[0].iov_len = 32; + req->cdb[0] = SPDK_SPC_SERVICE_ACTION_IN_16; + req->cdb[1] = SPDK_SBC_SAI_READ_CAPACITY_16; + to_be32(&req->cdb[10], iov[0].iov_len); + + virtio_xmit_pkts(base->vdev->vqs[2], vreq); +} + +static int +process_scan_inquiry(struct virtio_scsi_scan_base *base, struct virtio_req *vreq) +{ + struct virtio_scsi_cmd_req *req = vreq->iov_req.iov_base; struct virtio_scsi_cmd_resp *resp = vreq->iov_resp.iov_base; - uint8_t lun_id; + uint8_t target_id; if (resp->response != VIRTIO_SCSI_S_OK || resp->status != SPDK_SCSI_STATUS_GOOD) { return -1; } - lun_id = req->lun[1]; - /* reuse vreq for next request */ - memset(req, 0, sizeof(*req)); - req->lun[0] = 1; - req->lun[1] = lun_id; - - req->cdb[0] = SPDK_SPC_SERVICE_ACTION_IN_16; - req->cdb[1] = SPDK_SBC_SAI_READ_CAPACITY_16; - - iov[0].iov_len = 32; - to_be32(&req->cdb[10], iov[0].iov_len); - - virtio_xmit_pkts(base->vdev->vqs[2], vreq); + target_id = req->lun[1]; + send_read_cap_10(base, target_id, vreq); return 0; } @@ -371,7 +393,34 @@ alloc_virtio_disk(struct virtio_scsi_scan_base *base, uint64_t num_blocks, uint3 } static int -process_read_cap(struct virtio_scsi_scan_base *base, struct virtio_req *vreq) +process_read_cap_10(struct virtio_scsi_scan_base *base, struct virtio_req *vreq) +{ + struct virtio_scsi_cmd_req *req = vreq->iov_req.iov_base; + struct virtio_scsi_cmd_resp *resp = vreq->iov_resp.iov_base; + uint64_t max_block; + uint32_t block_size; + uint8_t target_id; + + if (resp->response != VIRTIO_SCSI_S_OK || resp->status != SPDK_SCSI_STATUS_GOOD) { + SPDK_ERRLOG("READ CAPACITY (10) failed for target %"PRIu8".\n", req->lun[1]); + return -1; + } + + block_size = from_be32((uint8_t *)vreq->iov[0].iov_base + 4); + max_block = from_be32(vreq->iov[0].iov_base); + + if (max_block == 0xffffffff) { + target_id = req->lun[1]; + + send_read_cap_16(base, target_id, vreq); + return 0; + } + + return alloc_virtio_disk(base, max_block + 1, block_size); +} + +static int +process_read_cap_16(struct virtio_scsi_scan_base *base, struct virtio_req *vreq) { struct virtio_scsi_cmd_req *req = vreq->iov_req.iov_base; struct virtio_scsi_cmd_resp *resp = vreq->iov_resp.iov_base; @@ -379,7 +428,7 @@ process_read_cap(struct virtio_scsi_scan_base *base, struct virtio_req *vreq) uint32_t block_size; if (resp->response != VIRTIO_SCSI_S_OK || resp->status != SPDK_SCSI_STATUS_GOOD) { - SPDK_ERRLOG("read capacity failed for target %"PRIu8".\n", req->lun[1]); + SPDK_ERRLOG("READ CAPACITY (16) failed for target %"PRIu8".\n", req->lun[1]); return -1; } @@ -405,8 +454,11 @@ process_scan_resp(struct virtio_scsi_scan_base *base, struct virtio_req *vreq) case SPDK_SPC_INQUIRY: rc = process_scan_inquiry(base, vreq); break; + case SPDK_SBC_READ_CAPACITY_10: + rc = process_read_cap_10(base, vreq); + break; case SPDK_SPC_SERVICE_ACTION_IN_16: - rc = process_read_cap(base, vreq); + rc = process_read_cap_16(base, vreq); break; default: SPDK_ERRLOG("Received invalid target scan message: cdb[0] = %"PRIu8".\n", req->cdb[0]);