0a122b
From a976099b24c5db9cb4ab1a059b01610d2fc48537 Mon Sep 17 00:00:00 2001
0a122b
Message-Id: <a976099b24c5db9cb4ab1a059b01610d2fc48537.1389014116.git.minovotn@redhat.com>
0a122b
In-Reply-To: <c8cc35838d42aa286242772d97e3a9be7bb786ba.1389014116.git.minovotn@redhat.com>
0a122b
References: <c8cc35838d42aa286242772d97e3a9be7bb786ba.1389014116.git.minovotn@redhat.com>
0a122b
From: Paolo Bonzini <pbonzini@redhat.com>
0a122b
Date: Mon, 9 Dec 2013 14:08:52 +0100
0a122b
Subject: [PATCH 04/50] iscsi: add .bdrv_get_block_status
0a122b
0a122b
RH-Author: Paolo Bonzini <pbonzini@redhat.com>
0a122b
Message-id: <1386598178-11845-7-git-send-email-pbonzini@redhat.com>
0a122b
Patchwork-id: 56043
0a122b
O-Subject: [RHEL 7.0 qemu-kvm PATCH 06/52] iscsi: add .bdrv_get_block_status
0a122b
Bugzilla: 1007815
0a122b
RH-Acked-by: Jeffrey Cody <jcody@redhat.com>
0a122b
RH-Acked-by: Fam Zheng <famz@redhat.com>
0a122b
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
0a122b
0a122b
From: Peter Lieven <pl@kamp.de>
0a122b
0a122b
this patch adds a coroutine for .bdrv_co_block_status as well as
0a122b
a generic framework that can be used to build coroutines in block/iscsi.
0a122b
0a122b
Signed-off-by: Peter Lieven <pl@kamp.de>
0a122b
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
0a122b
(cherry picked from commit 54a5c1d5db47b4146490937ed73e3f56022aaba6)
0a122b
---
0a122b
 block/iscsi.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
0a122b
 1 file changed, 136 insertions(+)
0a122b
0a122b
Signed-off-by: Michal Novotny <minovotn@redhat.com>
0a122b
---
0a122b
 block/iscsi.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
0a122b
 1 file changed, 136 insertions(+)
0a122b
0a122b
diff --git a/block/iscsi.c b/block/iscsi.c
0a122b
index 6804b6d..f8d021a 100644
0a122b
--- a/block/iscsi.c
0a122b
+++ b/block/iscsi.c
0a122b
@@ -58,6 +58,15 @@ typedef struct IscsiLun {
0a122b
     struct scsi_inquiry_block_limits bl;
0a122b
 } IscsiLun;
0a122b
 
0a122b
+typedef struct IscsiTask {
0a122b
+    int status;
0a122b
+    int complete;
0a122b
+    int retries;
0a122b
+    int do_retry;
0a122b
+    struct scsi_task *task;
0a122b
+    Coroutine *co;
0a122b
+} IscsiTask;
0a122b
+
0a122b
 typedef struct IscsiAIOCB {
0a122b
     BlockDriverAIOCB common;
0a122b
     QEMUIOVector *qiov;
0a122b
@@ -111,6 +120,41 @@ iscsi_schedule_bh(IscsiAIOCB *acb)
0a122b
     qemu_bh_schedule(acb->bh);
0a122b
 }
0a122b
 
0a122b
+static void
0a122b
+iscsi_co_generic_cb(struct iscsi_context *iscsi, int status,
0a122b
+                        void *command_data, void *opaque)
0a122b
+{
0a122b
+    struct IscsiTask *iTask = opaque;
0a122b
+    struct scsi_task *task = command_data;
0a122b
+
0a122b
+    iTask->complete = 1;
0a122b
+    iTask->status = status;
0a122b
+    iTask->do_retry = 0;
0a122b
+    iTask->task = task;
0a122b
+
0a122b
+    if (iTask->retries-- > 0 && status == SCSI_STATUS_CHECK_CONDITION
0a122b
+        && task->sense.key == SCSI_SENSE_UNIT_ATTENTION) {
0a122b
+        iTask->do_retry = 1;
0a122b
+        goto out;
0a122b
+    }
0a122b
+
0a122b
+    if (status != SCSI_STATUS_GOOD) {
0a122b
+        error_report("iSCSI: Failure. %s", iscsi_get_error(iscsi));
0a122b
+    }
0a122b
+
0a122b
+out:
0a122b
+    if (iTask->co) {
0a122b
+        qemu_coroutine_enter(iTask->co, NULL);
0a122b
+    }
0a122b
+}
0a122b
+
0a122b
+static void iscsi_co_init_iscsitask(IscsiLun *iscsilun, struct IscsiTask *iTask)
0a122b
+{
0a122b
+    *iTask = (struct IscsiTask) {
0a122b
+        .co         = qemu_coroutine_self(),
0a122b
+        .retries    = ISCSI_CMD_RETRIES,
0a122b
+    };
0a122b
+}
0a122b
 
0a122b
 static void
0a122b
 iscsi_abort_task_cb(struct iscsi_context *iscsi, int status, void *command_data,
0a122b
@@ -854,6 +898,96 @@ iscsi_getlength(BlockDriverState *bs)
0a122b
     return len;
0a122b
 }
0a122b
 
0a122b
+static int64_t coroutine_fn iscsi_co_get_block_status(BlockDriverState *bs,
0a122b
+                                                  int64_t sector_num,
0a122b
+                                                  int nb_sectors, int *pnum)
0a122b
+{
0a122b
+    IscsiLun *iscsilun = bs->opaque;
0a122b
+    struct scsi_get_lba_status *lbas = NULL;
0a122b
+    struct scsi_lba_status_descriptor *lbasd = NULL;
0a122b
+    struct IscsiTask iTask;
0a122b
+    int64_t ret;
0a122b
+
0a122b
+    iscsi_co_init_iscsitask(iscsilun, &iTask);
0a122b
+
0a122b
+    if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) {
0a122b
+        ret = -EINVAL;
0a122b
+        goto out;
0a122b
+    }
0a122b
+
0a122b
+    /* default to all sectors allocated */
0a122b
+    ret = BDRV_BLOCK_DATA;
0a122b
+    ret |= (sector_num << BDRV_SECTOR_BITS) | BDRV_BLOCK_OFFSET_VALID;
0a122b
+    *pnum = nb_sectors;
0a122b
+
0a122b
+    /* LUN does not support logical block provisioning */
0a122b
+    if (iscsilun->lbpme == 0) {
0a122b
+        goto out;
0a122b
+    }
0a122b
+
0a122b
+retry:
0a122b
+    if (iscsi_get_lba_status_task(iscsilun->iscsi, iscsilun->lun,
0a122b
+                                  sector_qemu2lun(sector_num, iscsilun),
0a122b
+                                  8 + 16, iscsi_co_generic_cb,
0a122b
+                                  &iTask) == NULL) {
0a122b
+        ret = -EIO;
0a122b
+        goto out;
0a122b
+    }
0a122b
+
0a122b
+    while (!iTask.complete) {
0a122b
+        iscsi_set_events(iscsilun);
0a122b
+        qemu_coroutine_yield();
0a122b
+    }
0a122b
+
0a122b
+    if (iTask.do_retry) {
0a122b
+        if (iTask.task != NULL) {
0a122b
+            scsi_free_scsi_task(iTask.task);
0a122b
+            iTask.task = NULL;
0a122b
+        }
0a122b
+        goto retry;
0a122b
+    }
0a122b
+
0a122b
+    if (iTask.status != SCSI_STATUS_GOOD) {
0a122b
+        /* in case the get_lba_status_callout fails (i.e.
0a122b
+         * because the device is busy or the cmd is not
0a122b
+         * supported) we pretend all blocks are allocated
0a122b
+         * for backwards compatiblity */
0a122b
+        goto out;
0a122b
+    }
0a122b
+
0a122b
+    lbas = scsi_datain_unmarshall(iTask.task);
0a122b
+    if (lbas == NULL) {
0a122b
+        ret = -EIO;
0a122b
+        goto out;
0a122b
+    }
0a122b
+
0a122b
+    lbasd = &lbas->descriptors[0];
0a122b
+
0a122b
+    if (sector_qemu2lun(sector_num, iscsilun) != lbasd->lba) {
0a122b
+        ret = -EIO;
0a122b
+        goto out;
0a122b
+    }
0a122b
+
0a122b
+    *pnum = sector_lun2qemu(lbasd->num_blocks, iscsilun);
0a122b
+    if (*pnum > nb_sectors) {
0a122b
+        *pnum = nb_sectors;
0a122b
+    }
0a122b
+
0a122b
+    if (lbasd->provisioning == SCSI_PROVISIONING_TYPE_DEALLOCATED ||
0a122b
+        lbasd->provisioning == SCSI_PROVISIONING_TYPE_ANCHORED) {
0a122b
+        ret &= ~BDRV_BLOCK_DATA;
0a122b
+        if (iscsilun->lbprz) {
0a122b
+            ret |= BDRV_BLOCK_ZERO;
0a122b
+        }
0a122b
+    }
0a122b
+
0a122b
+out:
0a122b
+    if (iTask.task != NULL) {
0a122b
+        scsi_free_scsi_task(iTask.task);
0a122b
+    }
0a122b
+    return ret;
0a122b
+}
0a122b
+
0a122b
 static int parse_chap(struct iscsi_context *iscsi, const char *target)
0a122b
 {
0a122b
     QemuOptsList *list;
0a122b
@@ -1406,6 +1540,8 @@ static BlockDriver bdrv_iscsi = {
0a122b
     .bdrv_getlength  = iscsi_getlength,
0a122b
     .bdrv_truncate   = iscsi_truncate,
0a122b
 
0a122b
+    .bdrv_co_get_block_status = iscsi_co_get_block_status,
0a122b
+
0a122b
     .bdrv_aio_readv  = iscsi_aio_readv,
0a122b
     .bdrv_aio_writev = iscsi_aio_writev,
0a122b
     .bdrv_aio_flush  = iscsi_aio_flush,
0a122b
-- 
0a122b
1.7.11.7
0a122b