* [Qemu-devel] [PULL 2/5] scsi-disk: fix VERIFY emulation
2013-12-09 13:02 [Qemu-devel] [PULL 0/5] SCSI patches for 2013-12-09 Paolo Bonzini
2013-12-09 13:02 ` [Qemu-devel] [PULL 1/5] scsi-bus: fix transfer length and direction for VERIFY command Paolo Bonzini
@ 2013-12-09 13:02 ` Paolo Bonzini
2013-12-09 13:02 ` [Qemu-devel] [PULL 3/5] block/iscsi: introduce bdrv_co_{readv, writev, flush_to_disk} Paolo Bonzini
` (3 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Paolo Bonzini @ 2013-12-09 13:02 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-stable
VERIFY emulation was completely botched (and remained botched through
all the refactorings). The command must be emulated both in check-medium
mode (BYTCHK=00, which we implement by doing nothing) and in check-bytes
mode (which we do not implement yet). Unlike WRITE AND VERIFY (which we
treat simply as WRITE with FUA bit set), VERIFY cannot be handled like
READ. In fact the device is _receiving_ data for VERIFY, not _sending_
it like READ.
Cc: qemu-stable@nongnu.org
Tested-by: Hervé Poussineau <hpoussin@reactos.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
hw/scsi/scsi-disk.c | 27 ++++++++++++++++++++-------
1 file changed, 20 insertions(+), 7 deletions(-)
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index efadfc0..6904ac2 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -1720,10 +1720,19 @@ static void scsi_disk_emulate_write_data(SCSIRequest *req)
scsi_disk_emulate_unmap(r, r->iov.iov_base);
break;
+ case VERIFY_10:
+ case VERIFY_12:
+ case VERIFY_16:
+ if (r->req.status == -1) {
+ scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
+ }
+ break;
+
case WRITE_SAME_10:
case WRITE_SAME_16:
scsi_disk_emulate_write_same(r, r->iov.iov_base);
break;
+
default:
abort();
}
@@ -1964,6 +1973,14 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
case UNMAP:
DPRINTF("Unmap (len %lu)\n", (long)r->req.cmd.xfer);
break;
+ case VERIFY_10:
+ case VERIFY_12:
+ case VERIFY_16:
+ DPRINTF("Verify (bytchk %lu)\n", (r->req.buf[1] >> 1) & 3);
+ if (req->cmd.buf[1] & 6) {
+ goto illegal_request;
+ }
+ break;
case WRITE_SAME_10:
case WRITE_SAME_16:
DPRINTF("WRITE SAME %d (len %lu)\n",
@@ -2044,10 +2061,6 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf)
scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED));
return 0;
}
- /* fallthrough */
- case VERIFY_10:
- case VERIFY_12:
- case VERIFY_16:
DPRINTF("Write %s(sector %" PRId64 ", count %u)\n",
(command & 0xe) == 0xe ? "And Verify " : "",
r->req.cmd.lba, len);
@@ -2315,14 +2328,14 @@ static const SCSIReqOps *const scsi_disk_reqops_dispatch[256] = {
[UNMAP] = &scsi_disk_emulate_reqops,
[WRITE_SAME_10] = &scsi_disk_emulate_reqops,
[WRITE_SAME_16] = &scsi_disk_emulate_reqops,
+ [VERIFY_10] = &scsi_disk_emulate_reqops,
+ [VERIFY_12] = &scsi_disk_emulate_reqops,
+ [VERIFY_16] = &scsi_disk_emulate_reqops,
[READ_6] = &scsi_disk_dma_reqops,
[READ_10] = &scsi_disk_dma_reqops,
[READ_12] = &scsi_disk_dma_reqops,
[READ_16] = &scsi_disk_dma_reqops,
- [VERIFY_10] = &scsi_disk_dma_reqops,
- [VERIFY_12] = &scsi_disk_dma_reqops,
- [VERIFY_16] = &scsi_disk_dma_reqops,
[WRITE_6] = &scsi_disk_dma_reqops,
[WRITE_10] = &scsi_disk_dma_reqops,
[WRITE_12] = &scsi_disk_dma_reqops,
--
1.8.4.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [Qemu-devel] [PULL 3/5] block/iscsi: introduce bdrv_co_{readv, writev, flush_to_disk}
2013-12-09 13:02 [Qemu-devel] [PULL 0/5] SCSI patches for 2013-12-09 Paolo Bonzini
2013-12-09 13:02 ` [Qemu-devel] [PULL 1/5] scsi-bus: fix transfer length and direction for VERIFY command Paolo Bonzini
2013-12-09 13:02 ` [Qemu-devel] [PULL 2/5] scsi-disk: fix VERIFY emulation Paolo Bonzini
@ 2013-12-09 13:02 ` Paolo Bonzini
2013-12-09 13:02 ` [Qemu-devel] [PULL 4/5] scsi-disk: fix WRITE SAME with large non-zero payload Paolo Bonzini
` (2 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Paolo Bonzini @ 2013-12-09 13:02 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Lieven
From: Peter Lieven <pl@kamp.de>
this converts read, write and flush functions from aio to coroutines
eliminating almost 200 lines of code.
The requirement for libiscsi is bumped to version 1.4.0 which was
released in may 2012.
Signed-off-by: Peter Lieven <pl@kamp.de>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
block/iscsi.c | 401 +++++++++++++++-------------------------------------------
configure | 6 +-
2 files changed, 108 insertions(+), 299 deletions(-)
diff --git a/block/iscsi.c b/block/iscsi.c
index 829d444..fa69408 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -239,44 +239,6 @@ iscsi_process_write(void *arg)
iscsi_set_events(iscsilun);
}
-static int
-iscsi_aio_writev_acb(IscsiAIOCB *acb);
-
-static void
-iscsi_aio_write16_cb(struct iscsi_context *iscsi, int status,
- void *command_data, void *opaque)
-{
- IscsiAIOCB *acb = opaque;
-
- trace_iscsi_aio_write16_cb(iscsi, status, acb, acb->canceled);
-
- g_free(acb->buf);
- acb->buf = NULL;
-
- if (acb->canceled != 0) {
- return;
- }
-
- acb->status = 0;
- if (status != 0) {
- if (status == SCSI_STATUS_CHECK_CONDITION
- && acb->task->sense.key == SCSI_SENSE_UNIT_ATTENTION
- && acb->retries-- > 0) {
- scsi_free_scsi_task(acb->task);
- acb->task = NULL;
- if (iscsi_aio_writev_acb(acb) == 0) {
- iscsi_set_events(acb->iscsilun);
- return;
- }
- }
- error_report("Failed to write16 data to iSCSI lun. %s",
- iscsi_get_error(iscsi));
- acb->status = -EIO;
- }
-
- iscsi_schedule_bh(acb);
-}
-
static int64_t sector_lun2qemu(int64_t sector, IscsiLun *iscsilun)
{
return sector * iscsilun->block_size / BDRV_SECTOR_SIZE;
@@ -301,324 +263,172 @@ static bool is_request_lun_aligned(int64_t sector_num, int nb_sectors,
return 1;
}
-static int
-iscsi_aio_writev_acb(IscsiAIOCB *acb)
+static int coroutine_fn iscsi_co_writev(BlockDriverState *bs,
+ int64_t sector_num, int nb_sectors,
+ QEMUIOVector *iov)
{
- struct iscsi_context *iscsi = acb->iscsilun->iscsi;
- size_t size;
- uint32_t num_sectors;
+ IscsiLun *iscsilun = bs->opaque;
+ struct IscsiTask iTask;
uint64_t lba;
-#if !defined(LIBISCSI_FEATURE_IOVECTOR)
- struct iscsi_data data;
-#endif
- int ret;
-
- acb->canceled = 0;
- acb->bh = NULL;
- acb->status = -EINPROGRESS;
- acb->buf = NULL;
+ uint32_t num_sectors;
+ uint8_t *data = NULL;
+ uint8_t *buf = NULL;
- /* this will allow us to get rid of 'buf' completely */
- size = acb->nb_sectors * BDRV_SECTOR_SIZE;
+ if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) {
+ return -EINVAL;
+ }
+ lba = sector_qemu2lun(sector_num, iscsilun);
+ num_sectors = sector_qemu2lun(nb_sectors, iscsilun);
#if !defined(LIBISCSI_FEATURE_IOVECTOR)
- data.size = MIN(size, acb->qiov->size);
-
/* if the iovec only contains one buffer we can pass it directly */
- if (acb->qiov->niov == 1) {
- data.data = acb->qiov->iov[0].iov_base;
+ if (iov->niov == 1) {
+ data = iov->iov[0].iov_base;
} else {
- acb->buf = g_malloc(data.size);
- qemu_iovec_to_buf(acb->qiov, 0, acb->buf, data.size);
- data.data = acb->buf;
+ size_t size = MIN(nb_sectors * BDRV_SECTOR_SIZE, iov->size);
+ buf = g_malloc(size);
+ qemu_iovec_to_buf(iov, 0, buf, size);
+ data = buf;
}
#endif
-
- acb->task = malloc(sizeof(struct scsi_task));
- if (acb->task == NULL) {
- error_report("iSCSI: Failed to allocate task for scsi WRITE16 "
- "command. %s", iscsi_get_error(iscsi));
- return -1;
+ iscsi_co_init_iscsitask(iscsilun, &iTask);
+retry:
+ iTask.task = iscsi_write16_task(iscsilun->iscsi, iscsilun->lun, lba,
+ data, num_sectors * iscsilun->block_size,
+ iscsilun->block_size, 0, 0, 0, 0, 0,
+ iscsi_co_generic_cb, &iTask);
+ if (iTask.task == NULL) {
+ g_free(buf);
+ return -EIO;
}
- memset(acb->task, 0, sizeof(struct scsi_task));
-
- acb->task->xfer_dir = SCSI_XFER_WRITE;
- acb->task->cdb_size = 16;
- acb->task->cdb[0] = 0x8a;
- lba = sector_qemu2lun(acb->sector_num, acb->iscsilun);
- *(uint32_t *)&acb->task->cdb[2] = htonl(lba >> 32);
- *(uint32_t *)&acb->task->cdb[6] = htonl(lba & 0xffffffff);
- num_sectors = sector_qemu2lun(acb->nb_sectors, acb->iscsilun);
- *(uint32_t *)&acb->task->cdb[10] = htonl(num_sectors);
- acb->task->expxferlen = size;
-
#if defined(LIBISCSI_FEATURE_IOVECTOR)
- ret = iscsi_scsi_command_async(iscsi, acb->iscsilun->lun, acb->task,
- iscsi_aio_write16_cb,
- NULL,
- acb);
-#else
- ret = iscsi_scsi_command_async(iscsi, acb->iscsilun->lun, acb->task,
- iscsi_aio_write16_cb,
- &data,
- acb);
+ scsi_task_set_iov_out(iTask.task, (struct scsi_iovec *) iov->iov,
+ iov->niov);
#endif
- if (ret != 0) {
- scsi_free_scsi_task(acb->task);
- g_free(acb->buf);
- return -1;
+ while (!iTask.complete) {
+ iscsi_set_events(iscsilun);
+ qemu_coroutine_yield();
}
-#if defined(LIBISCSI_FEATURE_IOVECTOR)
- scsi_task_set_iov_out(acb->task, (struct scsi_iovec*) acb->qiov->iov, acb->qiov->niov);
-#endif
-
- return 0;
-}
-
-static BlockDriverAIOCB *
-iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num,
- QEMUIOVector *qiov, int nb_sectors,
- BlockDriverCompletionFunc *cb,
- void *opaque)
-{
- IscsiLun *iscsilun = bs->opaque;
- IscsiAIOCB *acb;
-
- if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) {
- return NULL;
+ if (iTask.task != NULL) {
+ scsi_free_scsi_task(iTask.task);
+ iTask.task = NULL;
}
- acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
- trace_iscsi_aio_writev(iscsilun->iscsi, sector_num, nb_sectors, opaque, acb);
-
- acb->iscsilun = iscsilun;
- acb->qiov = qiov;
- acb->nb_sectors = nb_sectors;
- acb->sector_num = sector_num;
- acb->retries = ISCSI_CMD_RETRIES;
-
- if (iscsi_aio_writev_acb(acb) != 0) {
- qemu_aio_release(acb);
- return NULL;
+ if (iTask.do_retry) {
+ goto retry;
}
- iscsi_set_events(iscsilun);
- return &acb->common;
-}
-
-static int
-iscsi_aio_readv_acb(IscsiAIOCB *acb);
-
-static void
-iscsi_aio_read16_cb(struct iscsi_context *iscsi, int status,
- void *command_data, void *opaque)
-{
- IscsiAIOCB *acb = opaque;
-
- trace_iscsi_aio_read16_cb(iscsi, status, acb, acb->canceled);
-
- if (acb->canceled != 0) {
- return;
- }
+ g_free(buf);
- acb->status = 0;
- if (status != 0) {
- if (status == SCSI_STATUS_CHECK_CONDITION
- && acb->task->sense.key == SCSI_SENSE_UNIT_ATTENTION
- && acb->retries-- > 0) {
- scsi_free_scsi_task(acb->task);
- acb->task = NULL;
- if (iscsi_aio_readv_acb(acb) == 0) {
- iscsi_set_events(acb->iscsilun);
- return;
- }
- }
- error_report("Failed to read16 data from iSCSI lun. %s",
- iscsi_get_error(iscsi));
- acb->status = -EIO;
+ if (iTask.status != SCSI_STATUS_GOOD) {
+ return -EIO;
}
- iscsi_schedule_bh(acb);
+ return 0;
}
-static int
-iscsi_aio_readv_acb(IscsiAIOCB *acb)
+static int coroutine_fn iscsi_co_readv(BlockDriverState *bs,
+ int64_t sector_num, int nb_sectors,
+ QEMUIOVector *iov)
{
- struct iscsi_context *iscsi = acb->iscsilun->iscsi;
- size_t size;
+ IscsiLun *iscsilun = bs->opaque;
+ struct IscsiTask iTask;
uint64_t lba;
uint32_t num_sectors;
- int ret;
#if !defined(LIBISCSI_FEATURE_IOVECTOR)
int i;
#endif
- acb->canceled = 0;
- acb->bh = NULL;
- acb->status = -EINPROGRESS;
- acb->buf = NULL;
-
- size = acb->nb_sectors * BDRV_SECTOR_SIZE;
-
- acb->task = malloc(sizeof(struct scsi_task));
- if (acb->task == NULL) {
- error_report("iSCSI: Failed to allocate task for scsi READ16 "
- "command. %s", iscsi_get_error(iscsi));
- return -1;
+ if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) {
+ return -EINVAL;
}
- memset(acb->task, 0, sizeof(struct scsi_task));
- acb->task->xfer_dir = SCSI_XFER_READ;
- acb->task->expxferlen = size;
- lba = sector_qemu2lun(acb->sector_num, acb->iscsilun);
- num_sectors = sector_qemu2lun(acb->nb_sectors, acb->iscsilun);
+ lba = sector_qemu2lun(sector_num, iscsilun);
+ num_sectors = sector_qemu2lun(nb_sectors, iscsilun);
- switch (acb->iscsilun->type) {
+ iscsi_co_init_iscsitask(iscsilun, &iTask);
+retry:
+ switch (iscsilun->type) {
case TYPE_DISK:
- acb->task->cdb_size = 16;
- acb->task->cdb[0] = 0x88;
- *(uint32_t *)&acb->task->cdb[2] = htonl(lba >> 32);
- *(uint32_t *)&acb->task->cdb[6] = htonl(lba & 0xffffffff);
- *(uint32_t *)&acb->task->cdb[10] = htonl(num_sectors);
+ iTask.task = iscsi_read16_task(iscsilun->iscsi, iscsilun->lun, lba,
+ num_sectors * iscsilun->block_size,
+ iscsilun->block_size, 0, 0, 0, 0, 0,
+ iscsi_co_generic_cb, &iTask);
break;
default:
- acb->task->cdb_size = 10;
- acb->task->cdb[0] = 0x28;
- *(uint32_t *)&acb->task->cdb[2] = htonl(lba);
- *(uint16_t *)&acb->task->cdb[7] = htons(num_sectors);
+ iTask.task = iscsi_read10_task(iscsilun->iscsi, iscsilun->lun, lba,
+ num_sectors * iscsilun->block_size,
+ iscsilun->block_size, 0, 0, 0, 0, 0,
+ iscsi_co_generic_cb, &iTask);
break;
}
-
- ret = iscsi_scsi_command_async(iscsi, acb->iscsilun->lun, acb->task,
- iscsi_aio_read16_cb,
- NULL,
- acb);
- if (ret != 0) {
- scsi_free_scsi_task(acb->task);
- return -1;
+ if (iTask.task == NULL) {
+ return -EIO;
}
-
#if defined(LIBISCSI_FEATURE_IOVECTOR)
- scsi_task_set_iov_in(acb->task, (struct scsi_iovec*) acb->qiov->iov, acb->qiov->niov);
+ scsi_task_set_iov_in(iTask.task, (struct scsi_iovec *) iov->iov, iov->niov);
#else
- for (i = 0; i < acb->qiov->niov; i++) {
- scsi_task_add_data_in_buffer(acb->task,
- acb->qiov->iov[i].iov_len,
- acb->qiov->iov[i].iov_base);
+ for (i = 0; i < iov->niov; i++) {
+ scsi_task_add_data_in_buffer(iTask.task,
+ iov->iov[i].iov_len,
+ iov->iov[i].iov_base);
}
#endif
- return 0;
-}
-
-static BlockDriverAIOCB *
-iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num,
- QEMUIOVector *qiov, int nb_sectors,
- BlockDriverCompletionFunc *cb,
- void *opaque)
-{
- IscsiLun *iscsilun = bs->opaque;
- IscsiAIOCB *acb;
-
- if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) {
- return NULL;
- }
- acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
- trace_iscsi_aio_readv(iscsilun->iscsi, sector_num, nb_sectors, opaque, acb);
-
- acb->nb_sectors = nb_sectors;
- acb->sector_num = sector_num;
- acb->iscsilun = iscsilun;
- acb->qiov = qiov;
- acb->retries = ISCSI_CMD_RETRIES;
-
- if (iscsi_aio_readv_acb(acb) != 0) {
- qemu_aio_release(acb);
- return NULL;
+ while (!iTask.complete) {
+ iscsi_set_events(iscsilun);
+ qemu_coroutine_yield();
}
- iscsi_set_events(iscsilun);
- return &acb->common;
-}
-
-static int
-iscsi_aio_flush_acb(IscsiAIOCB *acb);
-
-static void
-iscsi_synccache10_cb(struct iscsi_context *iscsi, int status,
- void *command_data, void *opaque)
-{
- IscsiAIOCB *acb = opaque;
-
- if (acb->canceled != 0) {
- return;
+ if (iTask.task != NULL) {
+ scsi_free_scsi_task(iTask.task);
+ iTask.task = NULL;
}
- acb->status = 0;
- if (status != 0) {
- if (status == SCSI_STATUS_CHECK_CONDITION
- && acb->task->sense.key == SCSI_SENSE_UNIT_ATTENTION
- && acb->retries-- > 0) {
- scsi_free_scsi_task(acb->task);
- acb->task = NULL;
- if (iscsi_aio_flush_acb(acb) == 0) {
- iscsi_set_events(acb->iscsilun);
- return;
- }
- }
- error_report("Failed to sync10 data on iSCSI lun. %s",
- iscsi_get_error(iscsi));
- acb->status = -EIO;
+ if (iTask.do_retry) {
+ goto retry;
}
- iscsi_schedule_bh(acb);
-}
-
-static int
-iscsi_aio_flush_acb(IscsiAIOCB *acb)
-{
- struct iscsi_context *iscsi = acb->iscsilun->iscsi;
-
- acb->canceled = 0;
- acb->bh = NULL;
- acb->status = -EINPROGRESS;
- acb->buf = NULL;
-
- acb->task = iscsi_synchronizecache10_task(iscsi, acb->iscsilun->lun,
- 0, 0, 0, 0,
- iscsi_synccache10_cb,
- acb);
- if (acb->task == NULL) {
- error_report("iSCSI: Failed to send synchronizecache10 command. %s",
- iscsi_get_error(iscsi));
- return -1;
+ if (iTask.status != SCSI_STATUS_GOOD) {
+ return -EIO;
}
return 0;
}
-static BlockDriverAIOCB *
-iscsi_aio_flush(BlockDriverState *bs,
- BlockDriverCompletionFunc *cb, void *opaque)
+static int coroutine_fn iscsi_co_flush(BlockDriverState *bs)
{
IscsiLun *iscsilun = bs->opaque;
+ struct IscsiTask iTask;
- IscsiAIOCB *acb;
+ iscsi_co_init_iscsitask(iscsilun, &iTask);
- acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
+retry:
+ if (iscsi_synchronizecache10_task(iscsilun->iscsi, iscsilun->lun, 0, 0, 0,
+ 0, iscsi_co_generic_cb, &iTask) == NULL) {
+ return -EIO;
+ }
- acb->iscsilun = iscsilun;
- acb->retries = ISCSI_CMD_RETRIES;
+ while (!iTask.complete) {
+ iscsi_set_events(iscsilun);
+ qemu_coroutine_yield();
+ }
- if (iscsi_aio_flush_acb(acb) != 0) {
- qemu_aio_release(acb);
- return NULL;
+ if (iTask.task != NULL) {
+ scsi_free_scsi_task(iTask.task);
+ iTask.task = NULL;
}
- iscsi_set_events(iscsilun);
+ if (iTask.do_retry) {
+ goto retry;
+ }
- return &acb->common;
+ if (iTask.status != SCSI_STATUS_GOOD) {
+ return -EIO;
+ }
+
+ return 0;
}
#ifdef __linux__
@@ -1624,10 +1434,9 @@ static BlockDriver bdrv_iscsi = {
#if defined(SCSI_SENSE_ASCQ_CAPACITY_DATA_HAS_CHANGED)
.bdrv_co_write_zeroes = iscsi_co_write_zeroes,
#endif
-
- .bdrv_aio_readv = iscsi_aio_readv,
- .bdrv_aio_writev = iscsi_aio_writev,
- .bdrv_aio_flush = iscsi_aio_flush,
+ .bdrv_co_readv = iscsi_co_readv,
+ .bdrv_co_writev = iscsi_co_writev,
+ .bdrv_co_flush_to_disk = iscsi_co_flush,
#ifdef __linux__
.bdrv_ioctl = iscsi_ioctl,
diff --git a/configure b/configure
index 0666228..8144d9f 100755
--- a/configure
+++ b/configure
@@ -3025,13 +3025,13 @@ fi
##########################################
# Do we have libiscsi
-# We check for iscsi_unmap_sync() to make sure we have a
-# recent enough version of libiscsi.
+# We check for iscsi_write16_sync() to make sure we have a
+# at least version 1.4.0 of libiscsi.
if test "$libiscsi" != "no" ; then
cat > $TMPC << EOF
#include <stdio.h>
#include <iscsi/iscsi.h>
-int main(void) { iscsi_unmap_sync(NULL,0,0,0,NULL,0); return 0; }
+int main(void) { iscsi_write16_sync(NULL,0,0,NULL,0,0,0,0,0,0,0); return 0; }
EOF
if $pkg_config --atleast-version=1.7.0 libiscsi; then
libiscsi="yes"
--
1.8.4.2
^ permalink raw reply related [flat|nested] 8+ messages in thread