bdev_virtio: retry sending scan requests

Scan requests will be re-sent
if non-critical failure has
happened.

This is actually required, as
some Virtio SCSI devices require
a dummy request to clear it's
POWER ON OCCURED unit attention
status after Virtio device init.
The very first request might fail
with asc = 0x29 (POWER ON, RESET,
OR BUS RESET OCCURED), but
subsequent requests will be
processed correctly.

Change-Id: I809bfe7952062995078f33dccb92192d722e6574
Signed-off-by: Dariusz Stojaczyk <dariuszx.stojaczyk@intel.com>
Reviewed-on: https://review.gerrithub.io/383689
Tested-by: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com>
This commit is contained in:
Dariusz Stojaczyk 2017-10-25 10:08:37 +02:00 committed by Daniel Verkamp
parent fde584034d
commit cfa668375b

View File

@ -57,6 +57,7 @@
#define BDEV_VIRTIO_SCAN_PAYLOAD_SIZE 256 #define BDEV_VIRTIO_SCAN_PAYLOAD_SIZE 256
#define CTRLQ_POLL_PERIOD_US (1000 * 5) #define CTRLQ_POLL_PERIOD_US (1000 * 5)
#define CTRLQ_RING_SIZE 16 #define CTRLQ_RING_SIZE 16
#define SCAN_REQUEST_RETRIES 5
#define VIRTIO_SCSI_CONTROLQ 0 #define VIRTIO_SCSI_CONTROLQ 0
#define VIRTIO_SCSI_EVENTQ 1 #define VIRTIO_SCSI_EVENTQ 1
@ -92,6 +93,9 @@ struct virtio_scsi_scan_base {
/* Disks to be registered after the scan finishes */ /* Disks to be registered after the scan finishes */
TAILQ_HEAD(, virtio_scsi_disk) found_disks; TAILQ_HEAD(, virtio_scsi_disk) found_disks;
/** Remaining attempts for sending the current request. */
unsigned retries;
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];
@ -782,7 +786,9 @@ static void
process_scan_resp(struct virtio_scsi_scan_base *base, struct virtio_req *vreq) process_scan_resp(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_req *req = vreq->iov_req.iov_base;
int rc; struct virtio_scsi_cmd_resp *resp = vreq->iov_resp.iov_base;
int rc, sk, asc, ascq;
uint8_t target_id;
if (vreq->iov_req.iov_len < sizeof(struct virtio_scsi_cmd_req) || if (vreq->iov_req.iov_len < sizeof(struct virtio_scsi_cmd_req) ||
vreq->iov_resp.iov_len < sizeof(struct virtio_scsi_cmd_resp)) { vreq->iov_resp.iov_len < sizeof(struct virtio_scsi_cmd_resp)) {
@ -791,6 +797,32 @@ process_scan_resp(struct virtio_scsi_scan_base *base, struct virtio_req *vreq)
return; return;
} }
get_scsi_status(resp, &sk, &asc, &ascq);
target_id = req->lun[1];
if (resp->response == VIRTIO_SCSI_S_OK &&
resp->status == SPDK_SCSI_STATUS_CHECK_CONDITION &&
sk != SPDK_SCSI_SENSE_ILLEGAL_REQUEST) {
assert(base->retries > 0);
base->retries--;
if (base->retries == 0) {
SPDK_NOTICELOG("Target %"PRIu8" is present, but unavailable.\n", target_id);
SPDK_TRACEDUMP(SPDK_TRACE_VIRTIO, "CDB", req->cdb, sizeof(req->cdb));
SPDK_TRACEDUMP(SPDK_TRACE_VIRTIO, "SENSE DATA", resp->sense, sizeof(resp->sense));
scan_target_finish(base);
return;
}
/* resend the same request */
rc = virtio_xmit_pkt(base->vq, vreq);
if (rc != 0) {
assert(false);
}
return;
}
base->retries = SCAN_REQUEST_RETRIES;
switch (req->cdb[0]) { switch (req->cdb[0]) {
case SPDK_SPC_INQUIRY: case SPDK_SPC_INQUIRY:
rc = process_scan_inquiry(base, vreq); rc = process_scan_inquiry(base, vreq);
@ -859,6 +891,7 @@ scan_target(struct virtio_scsi_scan_base *base)
cdb->opcode = SPDK_SPC_INQUIRY; cdb->opcode = SPDK_SPC_INQUIRY;
cdb->alloc_len[1] = 255; cdb->alloc_len[1] = 255;
base->retries = SCAN_REQUEST_RETRIES;
return virtio_xmit_pkt(base->vq, vreq); return virtio_xmit_pkt(base->vq, vreq);
} }