bdev/virtio: resend scan I/O on full-queue scenario
The upcoming rescan implementation will do scan I/O on existing I/O virtqueues. To handle scan cleanly, we need to queue scan I/O if virtqueues are full. The heuristics for resending I/O should be sufficient for all real case scenarios. A scan I/O consists of either 2 or 3 iovs. A raw I/O consists of at least 2 descriptors. Since most I/O requests contain some additional payload, in 99% of cases the scan I/O will be successfully resent after polling a single I/O response. To handle the remaining 1%, we try to resend a scan I/O up to SCAN_REQUEST_RETRIES (currently = 5) times. Change-Id: I8c84ed1d109d9f403c9d7b8efabb904eb26183db Signed-off-by: Dariusz Stojaczyk <dariuszx.stojaczyk@intel.com> Reviewed-on: https://review.gerrithub.io/392174 Tested-by: SPDK Automated Test System <sys_sgsw@intel.com> Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com>
This commit is contained in:
parent
a27d7bc188
commit
8b0f049e85
@ -129,6 +129,9 @@ struct virtio_scsi_scan_base {
|
|||||||
/** Remaining attempts for sending the current request. */
|
/** Remaining attempts for sending the current request. */
|
||||||
unsigned retries;
|
unsigned retries;
|
||||||
|
|
||||||
|
/** If set, the last scan I/O needs to be resent */
|
||||||
|
bool needs_resend;
|
||||||
|
|
||||||
struct virtio_scsi_io_ctx io_ctx;
|
struct virtio_scsi_io_ctx io_ctx;
|
||||||
struct iovec iov;
|
struct iovec iov;
|
||||||
uint8_t payload[BDEV_VIRTIO_SCAN_PAYLOAD_SIZE];
|
uint8_t payload[BDEV_VIRTIO_SCAN_PAYLOAD_SIZE];
|
||||||
@ -350,7 +353,9 @@ virtio_scsi_dev_get_disk_by_id(struct virtio_scsi_dev *svdev, uint8_t target_id)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int send_scan_io(struct virtio_scsi_scan_base *base);
|
||||||
static int _virtio_scsi_dev_scan_next(struct virtio_scsi_scan_base *base);
|
static int _virtio_scsi_dev_scan_next(struct virtio_scsi_scan_base *base);
|
||||||
|
static void _virtio_scsi_dev_scan_finish(struct virtio_scsi_scan_base *base, int errnum);
|
||||||
|
|
||||||
static int
|
static int
|
||||||
bdev_virtio_get_ctx_size(void)
|
bdev_virtio_get_ctx_size(void)
|
||||||
@ -686,6 +691,7 @@ bdev_virtio_poll(void *arg)
|
|||||||
void *io[32];
|
void *io[32];
|
||||||
uint32_t io_len[32];
|
uint32_t io_len[32];
|
||||||
uint16_t i, cnt;
|
uint16_t i, cnt;
|
||||||
|
int rc;
|
||||||
|
|
||||||
cnt = virtio_recv_pkts(ch->vq, (void **)io, io_len, SPDK_COUNTOF(io));
|
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) {
|
||||||
@ -697,6 +703,18 @@ bdev_virtio_poll(void *arg)
|
|||||||
|
|
||||||
bdev_virtio_io_cpl(io[i]);
|
bdev_virtio_io_cpl(io[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (spdk_unlikely(cnt > 0 && svdev->scan_ctx && svdev->scan_ctx->needs_resend)) {
|
||||||
|
rc = send_scan_io(svdev->scan_ctx);
|
||||||
|
if (rc != 0) {
|
||||||
|
assert(svdev->scan_ctx->retries > 0);
|
||||||
|
svdev->scan_ctx->retries--;
|
||||||
|
if (svdev->scan_ctx->retries == 0) {
|
||||||
|
SPDK_ERRLOG("Target scan failed unrecoverably with rc = %d.\n", rc);
|
||||||
|
_virtio_scsi_dev_scan_finish(svdev->scan_ctx, rc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -900,7 +918,8 @@ send_scan_io(struct virtio_scsi_scan_base *base)
|
|||||||
|
|
||||||
rc = virtqueue_req_start(vq, io_ctx, 2 + payload_iov_cnt);
|
rc = virtqueue_req_start(vq, io_ctx, 2 + payload_iov_cnt);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
return rc;
|
base->needs_resend = true;
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtqueue_req_add_iovs(vq, &io_ctx->iov_req, 1, SPDK_VIRTIO_DESC_RO);
|
virtqueue_req_add_iovs(vq, &io_ctx->iov_req, 1, SPDK_VIRTIO_DESC_RO);
|
||||||
@ -927,12 +946,11 @@ send_inquiry(struct virtio_scsi_scan_base *base)
|
|||||||
return send_scan_io(base);
|
return send_scan_io(base);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static int
|
||||||
send_inquiry_vpd(struct virtio_scsi_scan_base *base, uint8_t page_code)
|
send_inquiry_vpd(struct virtio_scsi_scan_base *base, uint8_t page_code)
|
||||||
{
|
{
|
||||||
struct virtio_scsi_cmd_req *req = &base->io_ctx.req;
|
struct virtio_scsi_cmd_req *req = &base->io_ctx.req;
|
||||||
struct spdk_scsi_cdb_inquiry *inquiry_cdb = (struct spdk_scsi_cdb_inquiry *)req->cdb;
|
struct spdk_scsi_cdb_inquiry *inquiry_cdb = (struct spdk_scsi_cdb_inquiry *)req->cdb;
|
||||||
int rc;
|
|
||||||
|
|
||||||
memset(req, 0, sizeof(*req));
|
memset(req, 0, sizeof(*req));
|
||||||
|
|
||||||
@ -942,34 +960,26 @@ send_inquiry_vpd(struct virtio_scsi_scan_base *base, uint8_t page_code)
|
|||||||
inquiry_cdb->page_code = page_code;
|
inquiry_cdb->page_code = page_code;
|
||||||
to_be16(inquiry_cdb->alloc_len, base->iov.iov_len);
|
to_be16(inquiry_cdb->alloc_len, base->iov.iov_len);
|
||||||
|
|
||||||
rc = send_scan_io(base);
|
return send_scan_io(base);
|
||||||
if (rc != 0) {
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static int
|
||||||
send_read_cap_10(struct virtio_scsi_scan_base *base)
|
send_read_cap_10(struct virtio_scsi_scan_base *base)
|
||||||
{
|
{
|
||||||
struct virtio_scsi_cmd_req *req = &base->io_ctx.req;
|
struct virtio_scsi_cmd_req *req = &base->io_ctx.req;
|
||||||
int rc;
|
|
||||||
|
|
||||||
memset(req, 0, sizeof(*req));
|
memset(req, 0, sizeof(*req));
|
||||||
|
|
||||||
base->iov.iov_len = 8;
|
base->iov.iov_len = 8;
|
||||||
req->cdb[0] = SPDK_SBC_READ_CAPACITY_10;
|
req->cdb[0] = SPDK_SBC_READ_CAPACITY_10;
|
||||||
|
|
||||||
rc = send_scan_io(base);
|
return send_scan_io(base);
|
||||||
if (rc != 0) {
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static int
|
||||||
send_read_cap_16(struct virtio_scsi_scan_base *base)
|
send_read_cap_16(struct virtio_scsi_scan_base *base)
|
||||||
{
|
{
|
||||||
struct virtio_scsi_cmd_req *req = &base->io_ctx.req;
|
struct virtio_scsi_cmd_req *req = &base->io_ctx.req;
|
||||||
int rc;
|
|
||||||
|
|
||||||
memset(req, 0, sizeof(*req));
|
memset(req, 0, sizeof(*req));
|
||||||
|
|
||||||
@ -978,58 +988,44 @@ send_read_cap_16(struct virtio_scsi_scan_base *base)
|
|||||||
req->cdb[1] = SPDK_SBC_SAI_READ_CAPACITY_16;
|
req->cdb[1] = SPDK_SBC_SAI_READ_CAPACITY_16;
|
||||||
to_be32(&req->cdb[10], base->iov.iov_len);
|
to_be32(&req->cdb[10], base->iov.iov_len);
|
||||||
|
|
||||||
rc = send_scan_io(base);
|
return send_scan_io(base);
|
||||||
if (rc != 0) {
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static int
|
||||||
send_test_unit_ready(struct virtio_scsi_scan_base *base)
|
send_test_unit_ready(struct virtio_scsi_scan_base *base)
|
||||||
{
|
{
|
||||||
struct virtio_scsi_cmd_req *req = &base->io_ctx.req;
|
struct virtio_scsi_cmd_req *req = &base->io_ctx.req;
|
||||||
int rc;
|
|
||||||
|
|
||||||
memset(req, 0, sizeof(*req));
|
memset(req, 0, sizeof(*req));
|
||||||
req->cdb[0] = SPDK_SPC_TEST_UNIT_READY;
|
req->cdb[0] = SPDK_SPC_TEST_UNIT_READY;
|
||||||
base->iov.iov_len = 0;
|
base->iov.iov_len = 0;
|
||||||
|
|
||||||
rc = send_scan_io(base);
|
return send_scan_io(base);
|
||||||
if (rc != 0) {
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static int
|
||||||
send_start_stop_unit(struct virtio_scsi_scan_base *base)
|
send_start_stop_unit(struct virtio_scsi_scan_base *base)
|
||||||
{
|
{
|
||||||
struct virtio_scsi_cmd_req *req = &base->io_ctx.req;
|
struct virtio_scsi_cmd_req *req = &base->io_ctx.req;
|
||||||
int rc;
|
|
||||||
|
|
||||||
memset(req, 0, sizeof(*req));
|
memset(req, 0, sizeof(*req));
|
||||||
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;
|
||||||
base->iov.iov_len = 0;
|
base->iov.iov_len = 0;
|
||||||
|
|
||||||
rc = send_scan_io(base);
|
return send_scan_io(base);
|
||||||
if (rc != 0) {
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
process_scan_start_stop_unit(struct virtio_scsi_scan_base *base)
|
process_scan_start_stop_unit(struct virtio_scsi_scan_base *base)
|
||||||
{
|
{
|
||||||
struct virtio_scsi_cmd_resp *resp = &base->io_ctx.resp;
|
struct virtio_scsi_cmd_resp *resp = &base->io_ctx.resp;
|
||||||
int rc = 0;
|
|
||||||
|
|
||||||
if (resp->response == VIRTIO_SCSI_S_OK && resp->status == SPDK_SCSI_STATUS_GOOD) {
|
if (resp->response == VIRTIO_SCSI_S_OK && resp->status == SPDK_SCSI_STATUS_GOOD) {
|
||||||
send_inquiry_vpd(base, SPDK_SPC_VPD_SUPPORTED_VPD_PAGES);
|
return send_inquiry_vpd(base, SPDK_SPC_VPD_SUPPORTED_VPD_PAGES);
|
||||||
} else {
|
|
||||||
rc = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -1037,23 +1033,20 @@ process_scan_test_unit_ready(struct virtio_scsi_scan_base *base)
|
|||||||
{
|
{
|
||||||
struct virtio_scsi_cmd_resp *resp = &base->io_ctx.resp;
|
struct virtio_scsi_cmd_resp *resp = &base->io_ctx.resp;
|
||||||
int sk, asc, ascq;
|
int sk, asc, ascq;
|
||||||
int rc = 0;
|
|
||||||
|
|
||||||
get_scsi_status(resp, &sk, &asc, &ascq);
|
get_scsi_status(resp, &sk, &asc, &ascq);
|
||||||
|
|
||||||
/* check response, get VPD if spun up otherwise send SSU */
|
/* check response, get VPD if spun up otherwise send SSU */
|
||||||
if (resp->response == VIRTIO_SCSI_S_OK && resp->status == SPDK_SCSI_STATUS_GOOD) {
|
if (resp->response == VIRTIO_SCSI_S_OK && resp->status == SPDK_SCSI_STATUS_GOOD) {
|
||||||
send_inquiry_vpd(base, SPDK_SPC_VPD_SUPPORTED_VPD_PAGES);
|
return send_inquiry_vpd(base, SPDK_SPC_VPD_SUPPORTED_VPD_PAGES);
|
||||||
} else if (resp->response == VIRTIO_SCSI_S_OK &&
|
} else if (resp->response == VIRTIO_SCSI_S_OK &&
|
||||||
resp->status == SPDK_SCSI_STATUS_CHECK_CONDITION &&
|
resp->status == SPDK_SCSI_STATUS_CHECK_CONDITION &&
|
||||||
sk == SPDK_SCSI_SENSE_UNIT_ATTENTION &&
|
sk == SPDK_SCSI_SENSE_UNIT_ATTENTION &&
|
||||||
asc == SPDK_SCSI_ASC_LOGICAL_UNIT_NOT_READY) {
|
asc == SPDK_SCSI_ASC_LOGICAL_UNIT_NOT_READY) {
|
||||||
send_start_stop_unit(base);
|
return send_start_stop_unit(base);
|
||||||
} else {
|
} else {
|
||||||
rc = -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -1076,8 +1069,7 @@ process_scan_inquiry_standard(struct virtio_scsi_scan_base *base)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
send_test_unit_ready(base);
|
return send_test_unit_ready(base);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -1105,11 +1097,10 @@ process_scan_inquiry_vpd_supported_vpd_pages(struct virtio_scsi_scan_base *base)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (block_provisioning_page_supported) {
|
if (block_provisioning_page_supported) {
|
||||||
send_inquiry_vpd(base, SPDK_SPC_VPD_BLOCK_THIN_PROVISION);
|
return send_inquiry_vpd(base, SPDK_SPC_VPD_BLOCK_THIN_PROVISION);
|
||||||
} else {
|
} else {
|
||||||
send_read_cap_10(base);
|
return send_read_cap_10(base);
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -1128,8 +1119,7 @@ process_scan_inquiry_vpd_block_thin_provision(struct virtio_scsi_scan_base *base
|
|||||||
SPDK_INFOLOG(SPDK_LOG_VIRTIO, "Target %u: unmap supported = %d\n",
|
SPDK_INFOLOG(SPDK_LOG_VIRTIO, "Target %u: unmap supported = %d\n",
|
||||||
base->info.target, (int)base->info.unmap_supported);
|
base->info.target, (int)base->info.unmap_supported);
|
||||||
|
|
||||||
send_read_cap_10(base);
|
return send_read_cap_10(base);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -1224,8 +1214,7 @@ process_read_cap_10(struct virtio_scsi_scan_base *base)
|
|||||||
max_block = from_be32(base->payload);
|
max_block = from_be32(base->payload);
|
||||||
|
|
||||||
if (max_block == 0xffffffff) {
|
if (max_block == 0xffffffff) {
|
||||||
send_read_cap_16(base);
|
return send_read_cap_16(base);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
base->info.num_blocks = (uint64_t)max_block + 1;
|
base->info.num_blocks = (uint64_t)max_block + 1;
|
||||||
@ -1236,8 +1225,7 @@ process_read_cap_10(struct virtio_scsi_scan_base *base)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
_virtio_scsi_dev_scan_next(base);
|
return _virtio_scsi_dev_scan_next(base);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -1260,8 +1248,7 @@ process_read_cap_16(struct virtio_scsi_scan_base *base)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
_virtio_scsi_dev_scan_next(base);
|
return _virtio_scsi_dev_scan_next(base);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1298,7 +1285,7 @@ process_scan_resp(struct virtio_scsi_scan_base *base)
|
|||||||
/* resend the same request */
|
/* resend the same request */
|
||||||
rc = send_scan_io(base);
|
rc = send_scan_io(base);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
assert(false);
|
/* Let response poller do the resend */
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1327,7 +1314,11 @@ process_scan_resp(struct virtio_scsi_scan_base *base)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rc < 0) {
|
if (rc != 0) {
|
||||||
|
if (base->needs_resend) {
|
||||||
|
return; /* Let response poller do the resend */
|
||||||
|
}
|
||||||
|
|
||||||
_virtio_scsi_dev_scan_next(base);
|
_virtio_scsi_dev_scan_next(base);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1461,14 +1452,10 @@ virtio_scsi_dev_scan(struct virtio_scsi_dev *svdev, bdev_virtio_create_cb cb_fn,
|
|||||||
|
|
||||||
rc = send_inquiry(base);
|
rc = send_inquiry(base);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
SPDK_ERRLOG("Failed to start target scan.\n");
|
/* Let response poller do the resend */
|
||||||
spdk_put_io_channel(io_ch);
|
|
||||||
spdk_dma_free(base);
|
|
||||||
svdev->scan_ctx = NULL;
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
Loading…
Reference in New Issue
Block a user