From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from [140.186.70.92] (port=48643 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1PSFJd-0001Oa-Mn for qemu-devel@nongnu.org; Mon, 13 Dec 2010 15:48:18 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1PSFJZ-0006yO-4h for qemu-devel@nongnu.org; Mon, 13 Dec 2010 15:48:10 -0500 Received: from mail-pw0-f45.google.com ([209.85.160.45]:37727) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1PSFJY-0006yH-Om for qemu-devel@nongnu.org; Mon, 13 Dec 2010 15:48:09 -0500 Received: by pwj6 with SMTP id 6so1388328pwj.4 for ; Mon, 13 Dec 2010 12:48:07 -0800 (PST) MIME-Version: 1.0 In-Reply-To: <1292227550-6338-2-git-send-email-ronniesahlberg@gmail.com> References: <1292227550-6338-1-git-send-email-ronniesahlberg@gmail.com> <1292227550-6338-2-git-send-email-ronniesahlberg@gmail.com> From: Blue Swirl Date: Mon, 13 Dec 2010 20:47:47 +0000 Message-ID: Subject: Re: [Qemu-devel] [PATCH] libiscsi Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Ronnie Sahlberg Cc: qemu-devel@nongnu.org On Mon, Dec 13, 2010 at 8:05 AM, Ronnie Sahlberg wrote: > This patch adds a new block driver : block.iscsi.c > This driver interfaces with the multiplatform posix library > for iscsi initiator/client access to iscsi devices hosted at > git://github.com/sahlberg/libiscsi.git > > The patch adds the driver to interface with the iscsi library. > It also updated the configure script to > * by default, probe is libiscsi is available and if so, build > =C2=A0qemu against libiscsi. > * --enable-libiscsi > =C2=A0Force a build against libiscsi. If libiscsi is not available > =C2=A0the build will fail. > * --disable-libiscsi > =C2=A0Do not link against libiscsi, even if it is available. > > When linked with libiscsi, qemu gains support to access iscsi resources > such as disks and cdrom directly, without having to make the devices visi= ble > to the host. > > You can specify devices using a iscsi url of the form : > iscsi://[:/ > > Example: > -drive file=3Discsi://10.1.1.1:3260/iqn.ronnie.test/1 > > -cdrom iscsi://10.1.1.1:3260/iqn.ronnie.test/2 > > Signed-off-by: Ronnie Sahlberg > --- > =C2=A0Makefile.objs | =C2=A0 =C2=A02 +- > =C2=A0block/iscsi.c | =C2=A0528 +++++++++++++++++++++++++++++++++++++++++= ++++++++++++++++ > =C2=A0configure =C2=A0 =C2=A0 | =C2=A0 29 +++ > =C2=A03 files changed, 558 insertions(+), 1 deletions(-) > =C2=A0create mode 100644 block/iscsi.c > > diff --git a/Makefile.objs b/Makefile.objs > index cebb945..81731c5 100644 > --- a/Makefile.objs > +++ b/Makefile.objs > @@ -22,7 +22,7 @@ block-nested-y +=3D raw.o cow.o qcow.o vdi.o vmdk.o clo= op.o dmg.o bochs.o vpc.o vv > =C2=A0block-nested-y +=3D qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-= snapshot.o > =C2=A0block-nested-y +=3D parallels.o nbd.o blkdebug.o sheepdog.o blkveri= fy.o > =C2=A0block-nested-$(CONFIG_WIN32) +=3D raw-win32.o > -block-nested-$(CONFIG_POSIX) +=3D raw-posix.o > +block-nested-$(CONFIG_POSIX) +=3D raw-posix.o iscsi.o Please use CONFIG_ISCSI... > =C2=A0block-nested-$(CONFIG_CURL) +=3D curl.o > > =C2=A0block-obj-y +=3D =C2=A0$(addprefix block/, $(block-nested-y)) > diff --git a/block/iscsi.c b/block/iscsi.c > new file mode 100644 > index 0000000..fba5ee6 > --- /dev/null > +++ b/block/iscsi.c > @@ -0,0 +1,528 @@ > +/* > + * QEMU Block driver for iSCSI images > + * > + * Copyright (c) 2010 Ronnie Sahlberg > + * > + * Permission is hereby granted, free of charge, to any person obtaining= a copy > + * of this software and associated documentation files (the "Software"),= to deal > + * in the Software without restriction, including without limitation the= rights > + * to use, copy, modify, merge, publish, distribute, sublicense, and/or = sell > + * copies of the Software, and to permit persons to whom the Software is > + * furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice shall be includ= ed in > + * all copies or substantial portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRE= SS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILI= TY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHA= LL > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR = OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISI= NG FROM, > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALING= S IN > + * THE SOFTWARE. > + */ > + > +#include "config-host.h" > +#ifdef CONFIG_LIBISCSI ... then this is not needed. > + > +#include > +#include "sysemu.h" > +#include "qemu-common.h" > +#include "qemu-error.h" > +#include "block_int.h" > + > +#include > +#include > + > + > +typedef struct ISCSILUN { > + =C2=A0 =C2=A0struct iscsi_context *iscsi; > + =C2=A0 =C2=A0int lun; > + =C2=A0 =C2=A0int block_size; > + =C2=A0 =C2=A0unsigned long num_blocks; > +} ISCSILUN; > + > +typedef struct ISCSIAIOCB { > + =C2=A0 =C2=A0BlockDriverAIOCB common; > + =C2=A0 =C2=A0QEMUIOVector *qiov; > + =C2=A0 =C2=A0QEMUBH *bh; > + =C2=A0 =C2=A0ISCSILUN *iscsilun; > + =C2=A0 =C2=A0int canceled; > + =C2=A0 =C2=A0int status; > + =C2=A0 =C2=A0size_t read_size; > +} ISCSIAIOCB; > + > +struct iscsi_task { > + =C2=A0 =C2=A0ISCSILUN *iscsilun; > + =C2=A0 =C2=A0int status; > + =C2=A0 =C2=A0int complete; > +}; Please see CODING_STYLE for struct naming and use of typedefs. > + > +static int > +iscsi_is_inserted(BlockDriverState *bs) > +{ > + =C2=A0 =C2=A0ISCSILUN *iscsilun =3D bs->opaque; > + =C2=A0 =C2=A0struct iscsi_context *iscsi =3D iscsilun->iscsi; > + > + =C2=A0 =C2=A0return iscsi_is_logged_in(iscsi); > +} > + > + > +static void > +iscsi_aio_cancel(BlockDriverAIOCB *blockacb) > +{ > + =C2=A0 =C2=A0ISCSIAIOCB *acb =3D (ISCSIAIOCB *)blockacb; > + > + =C2=A0 =C2=A0acb->status =3D -EIO; > + =C2=A0 =C2=A0acb->common.cb(acb->common.opaque, acb->status); > + =C2=A0 =C2=A0acb->canceled =3D 1; > +} > + > +static AIOPool iscsi_aio_pool =3D { > + =C2=A0 =C2=A0.aiocb_size =C2=A0 =C2=A0 =C2=A0 =C2=A0 =3D sizeof(ISCSIAI= OCB), > + =C2=A0 =C2=A0.cancel =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =3D iscs= i_aio_cancel, > +}; > + > + > +static void iscsi_process_read(void *arg); > +static void iscsi_process_write(void *arg); > + > +static void > +iscsi_set_events(ISCSILUN *iscsilun) > +{ > + =C2=A0 =C2=A0struct iscsi_context *iscsi =3D iscsilun->iscsi; > + > + =C2=A0 =C2=A0qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), iscsi_process= _read, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 (iscsi_which_events(iscsi)&POLLOUT) Please insert space around operators. > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 ?iscsi_process_write:NULL, Also around ?:. > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 NULL, NULL, iscsilun); > +} > + > +static void > +iscsi_process_read(void *arg) > +{ > + =C2=A0 =C2=A0ISCSILUN *iscsilun =3D arg; > + =C2=A0 =C2=A0struct iscsi_context *iscsi =3D iscsilun->iscsi; > + > + =C2=A0 =C2=A0iscsi_service(iscsi, POLLIN); > + =C2=A0 =C2=A0iscsi_set_events(iscsilun); > +} > + > +static void > +iscsi_process_write(void *arg) > +{ > + =C2=A0 =C2=A0ISCSILUN *iscsilun =3D arg; > + =C2=A0 =C2=A0struct iscsi_context *iscsi =3D iscsilun->iscsi; > + > + =C2=A0 =C2=A0iscsi_service(iscsi, POLLOUT); > + =C2=A0 =C2=A0iscsi_set_events(iscsilun); > +} > + > + > +static int > +iscsi_schedule_bh(QEMUBHFunc *cb, ISCSIAIOCB *acb) > +{ > + =C2=A0 =C2=A0acb->bh =3D qemu_bh_new(cb, acb); > + =C2=A0 =C2=A0if (!acb->bh) { > + =C2=A0 =C2=A0 =C2=A0 error_report("oom: could not create iscsi bh"); > + =C2=A0 =C2=A0 =C2=A0 return -EIO; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0qemu_bh_schedule(acb->bh); > + =C2=A0 =C2=A0return 0; > +} > + > +static void > +iscsi_readv_writev_bh_cb(void *p) > +{ > + =C2=A0 =C2=A0ISCSIAIOCB *acb =3D p; > + > + =C2=A0 =C2=A0acb->common.cb(acb->common.opaque, acb->status); > + =C2=A0 =C2=A0qemu_aio_release(acb); > +} > + > +static void > +iscsi_aio_write10_cb(struct iscsi_context *iscsi, int status, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0vo= id *command_data, void *private_data) > +{ > + =C2=A0 =C2=A0ISCSIAIOCB *acb =3D private_data; > + > + =C2=A0 =C2=A0if (acb->canceled !=3D 0) { > + =C2=A0 =C2=A0 =C2=A0 qemu_aio_release(acb); > + =C2=A0 =C2=A0 =C2=A0 return; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0acb->status =3D 0; > + =C2=A0 =C2=A0if (status < 0) { > + =C2=A0 =C2=A0 =C2=A0 error_report("Failed to write10 data to iSCSI lun.= %s", > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0is= csi_get_error(iscsi)); > + =C2=A0 =C2=A0 =C2=A0 acb->status =3D -EIO; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb); > +} > + > +static BlockDriverAIOCB * > +iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0QEMUIOVector *qi= ov, int nb_sectors, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0BlockDriverCompl= etionFunc *cb, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0void *opaque) > +{ > + =C2=A0 =C2=A0ISCSILUN *iscsilun =3D bs->opaque; > + =C2=A0 =C2=A0struct iscsi_context *iscsi =3D iscsilun->iscsi; > + =C2=A0 =C2=A0ISCSIAIOCB *acb; > + =C2=A0 =C2=A0size_t size; > + =C2=A0 =C2=A0unsigned char *buf; Why unsigned? Maybe uint8_t or plain char instead? > + > + =C2=A0 =C2=A0acb =3D qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque); > + =C2=A0 =C2=A0if (!acb) { > + =C2=A0 =C2=A0 =C2=A0 return NULL; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0acb->iscsilun =3D iscsilun; > + =C2=A0 =C2=A0acb->qiov =C2=A0 =C2=A0 =3D qiov; > + > + =C2=A0 =C2=A0acb->canceled =C2=A0 =3D 0; > + > + =C2=A0 =C2=A0/* XXX we should pass the iovec to write10 to avoid the ex= tra copy */ > + =C2=A0 =C2=A0/* this will allow us to get rid of 'buf' completely */ > + =C2=A0 =C2=A0size =3D nb_sectors * BDRV_SECTOR_SIZE; > + =C2=A0 =C2=A0buf =3D qemu_malloc(size); > + =C2=A0 =C2=A0qemu_iovec_to_buffer(acb->qiov, buf); > + =C2=A0 =C2=A0if (iscsi_write10_async(iscsi, iscsilun->lun, buf, size, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 sector_num * BDRV_SECTOR_SIZE > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 / iscsilun->block_size, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 0, 0, iscsilun->block_size, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 iscsi_aio_write10_cb, acb) !=3D 0) { When the function call is this long, perhaps it would be more readable to assign a temporary variable with the result and use that in if expression. The expression sector_num * BDRV_SECTOR_SIZE / iscsilun->block_size is used often, refactoring this to a function could make the code a bit clearer. > + =C2=A0 =C2=A0 =C2=A0 error_report("iSCSI: Failed to send write10 comman= d. %s", > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0is= csi_get_error(iscsi)); > + =C2=A0 =C2=A0 =C2=A0 qemu_free(buf); > + =C2=A0 =C2=A0 =C2=A0 qemu_aio_release(acb); > + =C2=A0 =C2=A0 =C2=A0 return NULL; > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0qemu_free(buf); > + =C2=A0 =C2=A0iscsi_set_events(iscsilun); > + > + =C2=A0 =C2=A0return &acb->common; > +} > + > +static void > +iscsi_aio_read10_cb(struct iscsi_context *iscsi, int status, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 void *co= mmand_data, void *private_data) > +{ > + =C2=A0 =C2=A0ISCSIAIOCB *acb =3D private_data; > + =C2=A0 =C2=A0struct scsi_task *scsi =3D command_data; > + > + =C2=A0 =C2=A0if (acb->canceled !=3D 0) { > + =C2=A0 =C2=A0 =C2=A0 qemu_aio_release(acb); > + =C2=A0 =C2=A0 =C2=A0 return; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0acb->status =3D 0; > + =C2=A0 =C2=A0if (status < 0) { > + =C2=A0 =C2=A0 =C2=A0 error_report("Failed to read10 data from iSCSI lun= . %s", > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0is= csi_get_error(iscsi)); > + =C2=A0 =C2=A0 =C2=A0 acb->status =3D -EIO; > + =C2=A0 =C2=A0} else { > + =C2=A0 =C2=A0 =C2=A0 qemu_iovec_from_buffer(acb->qiov, scsi->datain.dat= a, acb->read_size); > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb); > +} > + > +static BlockDriverAIOCB * > +iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 QEMUIOVector *qiov, in= t nb_sectors, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 BlockDriverCompletionF= unc *cb, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 void *opaque) > +{ > + =C2=A0 =C2=A0ISCSILUN *iscsilun =3D bs->opaque; > + =C2=A0 =C2=A0struct iscsi_context *iscsi =3D iscsilun->iscsi; > + =C2=A0 =C2=A0ISCSIAIOCB *acb; > + =C2=A0 =C2=A0size_t qemu_read_size, lun_read_size; > + > + =C2=A0 =C2=A0qemu_read_size =3D BDRV_SECTOR_SIZE * (size_t)nb_sectors; > + =C2=A0 =C2=A0lun_read_size =C2=A0=3D (qemu_read_size + iscsilun->block_= size - 1) > + =C2=A0 =C2=A0 =C2=A0/ iscsilun->block_size * iscsilun->block_size; > + > + =C2=A0 =C2=A0acb =3D qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque); > + =C2=A0 =C2=A0if (!acb) { > + =C2=A0 =C2=A0 =C2=A0 return NULL; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0acb->iscsilun =3D iscsilun; > + =C2=A0 =C2=A0acb->qiov =C2=A0 =C2=A0 =3D qiov; > + > + =C2=A0 =C2=A0acb->canceled =C2=A0 =3D 0; > + =C2=A0 =C2=A0acb->read_size =C2=A0=3D qemu_read_size; > + > + =C2=A0 =C2=A0if (iscsi_read10_async(iscsi, iscsilun->lun, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0sector_num * BDRV_SECTOR_SIZE > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0/ iscsilun->block_size, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0lun_read_size, iscsilun->block_size, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0iscsi_aio_read10_cb, acb) !=3D 0) { > + =C2=A0 =C2=A0 =C2=A0 error_report("iSCSI: Failed to send read10 command= . %s", > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0is= csi_get_error(iscsi)); > + =C2=A0 =C2=A0 =C2=A0 qemu_aio_release(acb); > + =C2=A0 =C2=A0 =C2=A0 return NULL; > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0iscsi_set_events(iscsilun); > + > + =C2=A0 =C2=A0return &acb->common; > +} > + > + > +static void synccache10_cb(struct iscsi_context *iscsi, int status, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0void *command_data, void *private_data) Usually 'opaque' is used instead of 'private_data'. > +{ > + =C2=A0 =C2=A0struct iscsi_task *task =3D private_data; > + > + =C2=A0 =C2=A0task->status =C2=A0 =3D status; > + =C2=A0 =C2=A0task->complete =3D 1; > +} > + > +static int > +iscsi_flush(BlockDriverState *bs) > +{ > + =C2=A0 =C2=A0ISCSILUN *iscsilun =3D bs->opaque; > + =C2=A0 =C2=A0struct iscsi_context *iscsi =3D iscsilun->iscsi; > + =C2=A0 =C2=A0struct iscsi_task task; > + > + =C2=A0 =C2=A0task.iscsilun =3D iscsilun; > + =C2=A0 =C2=A0task.status =3D 0; > + =C2=A0 =C2=A0task.complete =3D 0; > + > + =C2=A0 =C2=A0if (iscsi_synchronizecache10_async(iscsi, iscsilun->lun, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A00, 0, 0, 0, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0synccache10_c= b, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0&task) !=3D 0= ) { > + =C2=A0 =C2=A0 =C2=A0 error_report("iSCSI: Failed to send SYNCHRONIZECAC= HE10. %s", > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0is= csi_get_error(iscsi)); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return -1; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0async_context_push(); > + =C2=A0 =C2=A0while (!task.complete) { > + =C2=A0 =C2=A0 =C2=A0 iscsi_set_events(iscsilun); > + =C2=A0 =C2=A0 =C2=A0 qemu_aio_wait(); > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0async_context_pop(); > + =C2=A0 =C2=A0if (task.status !=3D 0) { > + =C2=A0 =C2=A0 =C2=A0 error_report("iSCSI: Failed to send SYNCHRONIZECAC= HE10: %s", > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0is= csi_get_error(iscsi)); > + =C2=A0 =C2=A0 =C2=A0 return -EIO; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0return 0; > +} > + > +static int64_t > +iscsi_getlength(BlockDriverState *bs) > +{ > + =C2=A0 =C2=A0ISCSILUN *iscsilun =3D bs->opaque; > + =C2=A0 =C2=A0int64_t len; > + > + =C2=A0 =C2=A0len =C2=A0=3D iscsilun->num_blocks; > + =C2=A0 =C2=A0len *=3D iscsilun->block_size; > + > + =C2=A0 =C2=A0return len; > +} > + > +static void > +iscsi_readcapacity10_cb(struct iscsi_context *iscsi, int status, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 void *command_data, void *private_data) > +{ > + =C2=A0 =C2=A0struct iscsi_task *task =3D private_data; > + =C2=A0 =C2=A0struct scsi_readcapacity10 *rc10; > + =C2=A0 =C2=A0struct scsi_task *scsi =3D command_data; > + > + =C2=A0 =C2=A0if (status !=3D 0) { > + =C2=A0 =C2=A0 =C2=A0 error_report("iSCSI: Failed to read capacity of iS= CSI lun. %s", > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0is= csi_get_error(iscsi)); > + =C2=A0 =C2=A0 =C2=A0 task->status =C2=A0 =3D 1; > + =C2=A0 =C2=A0 =C2=A0 task->complete =3D 1; > + =C2=A0 =C2=A0 =C2=A0 return; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0rc10 =3D scsi_datain_unmarshall(scsi); > + =C2=A0 =C2=A0if (rc10 =3D=3D NULL) { > + =C2=A0 =C2=A0 =C2=A0 error_report("iSCSI: Failed to unmarshall readcapa= city10 data."); > + =C2=A0 =C2=A0 =C2=A0 task->status =C2=A0 =3D 1; > + =C2=A0 =C2=A0 =C2=A0 task->complete =3D 1; > + =C2=A0 =C2=A0 =C2=A0 return; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0task->iscsilun->block_size =3D rc10->block_size; > + =C2=A0 =C2=A0task->iscsilun->num_blocks =3D rc10->lba; > + > + =C2=A0 =C2=A0task->status =C2=A0 =3D 0; > + =C2=A0 =C2=A0task->complete =3D 1; > +} > + > + > +static void > +iscsi_connect_cb(struct iscsi_context *iscsi, int status, void *command_= data, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0void *private_da= ta) > +{ > + =C2=A0 =C2=A0struct iscsi_task *task =3D private_data; > + > + =C2=A0 =C2=A0if (status !=3D 0) { > + =C2=A0 =C2=A0 =C2=A0 task->status =C2=A0 =3D 1; > + =C2=A0 =C2=A0 =C2=A0 task->complete =3D 1; > + =C2=A0 =C2=A0 =C2=A0 return; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0if (iscsi_readcapacity10_async(iscsi, task->iscsilun->lun,= 0, 0, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0iscsi_readcapacity10_cb, pr= ivate_data) > + =C2=A0 =C2=A0 =C2=A0 !=3D 0) { > + =C2=A0 =C2=A0 =C2=A0 error_report("iSCSI: failed to send readcapacity c= ommand."); > + =C2=A0 =C2=A0 =C2=A0 task->status =C2=A0 =3D 1; > + =C2=A0 =C2=A0 =C2=A0 task->complete =3D 1; > + =C2=A0 =C2=A0} > +} > + > +/* > + * We support iscsi url's on the form > + * iscsi://[:]// > + */ > +static int iscsi_open(BlockDriverState *bs, const char *filename, int fl= ags) > +{ > + =C2=A0 =C2=A0ISCSILUN *iscsilun =3D bs->opaque; > + =C2=A0 =C2=A0struct iscsi_context *iscsi =3D NULL; > + =C2=A0 =C2=A0struct iscsi_task task; > + =C2=A0 =C2=A0char *ptr, *host, *target, *url; > + =C2=A0 =C2=A0char *tmp; > + =C2=A0 =C2=A0int ret, lun; > + > + =C2=A0 =C2=A0bzero(iscsilun, sizeof(ISCSILUN)); memset() > + > + =C2=A0 =C2=A0url =3D qemu_strdup(filename); > + > + =C2=A0 =C2=A0if (strncmp(url, "iscsi://", 8)) { > + =C2=A0 =C2=A0 =C2=A0 error_report("iSCSI: url does not start with 'iscs= i://'"); > + =C2=A0 =C2=A0 =C2=A0 ret =3D -EINVAL; > + =C2=A0 =C2=A0 =C2=A0 goto failed; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0host =3D url + 8; > + > + =C2=A0 =C2=A0ptr =3D index(host, '/'); strchr()