static BlockDriverAIOCB * iscsi_aio_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors, BlockDriverCompletionFunc *cb, void *opaque) { IscsiLun *iscsilun = bs->opaque; struct iscsi_context *iscsi = iscsilun->iscsi; IscsiAIOCB *acb; struct unmap_list list[1]; acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque); acb->iscsilun = iscsilun; acb->canceled = 0; acb->bh = NULL; acb->status = -EINPROGRESS; list[0].lba = sector_qemu2lun(sector_num, iscsilun); list[0].num = nb_sectors * BDRV_SECTOR_SIZE / iscsilun->block_size; acb->task = iscsi_unmap_task(iscsi, iscsilun->lun, 0, 0, &list[0], 1, iscsi_unmap_cb, acb); if (acb->task == NULL) { error_report("iSCSI: Failed to send unmap command. %s", iscsi_get_error(iscsi)); qemu_aio_release(acb); return NULL; } iscsi_set_events(iscsilun); return &acb->common; }
static BlockDriverAIOCB * iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, BlockDriverCompletionFunc *cb, void *opaque) { IscsiLun *iscsilun = bs->opaque; struct iscsi_context *iscsi = iscsilun->iscsi; IscsiAIOCB *acb; size_t qemu_read_size, lun_read_size; int i; qemu_read_size = BDRV_SECTOR_SIZE * (size_t)nb_sectors; acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque); trace_iscsi_aio_readv(iscsi, sector_num, nb_sectors, opaque, acb); acb->iscsilun = iscsilun; acb->qiov = qiov; acb->canceled = 0; acb->read_size = qemu_read_size; acb->buf = NULL; /* If LUN blocksize is bigger than BDRV_BLOCK_SIZE a read from QEMU * may be misaligned to the LUN, so we may need to read some extra * data. */ acb->read_offset = 0; if (iscsilun->block_size > BDRV_SECTOR_SIZE) { uint64_t bdrv_offset = BDRV_SECTOR_SIZE * sector_num; acb->read_offset = bdrv_offset % iscsilun->block_size; } lun_read_size = (qemu_read_size + iscsilun->block_size + acb->read_offset - 1) / iscsilun->block_size * iscsilun->block_size; acb->task = iscsi_read10_task(iscsi, iscsilun->lun, sector_qemu2lun(sector_num, iscsilun), lun_read_size, iscsilun->block_size, 0, 0, 0, 0, 0, iscsi_aio_read10_cb, acb); if (acb->task == NULL) { error_report("iSCSI: Failed to send read10 command. %s", iscsi_get_error(iscsi)); qemu_aio_release(acb); return NULL; } 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); } iscsi_set_events(iscsilun); return &acb->common; }
static BlockDriverAIOCB * iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, BlockDriverCompletionFunc *cb, void *opaque) { IscsiLun *iscsilun = bs->opaque; struct iscsi_context *iscsi = iscsilun->iscsi; IscsiAIOCB *acb; size_t size; int fua = 0; /* set FUA on writes when cache mode is write through */ if (!(bs->open_flags & BDRV_O_CACHE_WB)) { fua = 1; } acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque); trace_iscsi_aio_writev(iscsi, sector_num, nb_sectors, opaque, acb); acb->iscsilun = iscsilun; acb->qiov = qiov; acb->canceled = 0; /* XXX we should pass the iovec to write10 to avoid the extra copy */ /* this will allow us to get rid of 'buf' completely */ size = nb_sectors * BDRV_SECTOR_SIZE; acb->buf = g_malloc(size); qemu_iovec_to_buffer(acb->qiov, acb->buf); acb->task = iscsi_write10_task(iscsi, iscsilun->lun, sector_qemu2lun(sector_num, iscsilun), acb->buf, size, iscsilun->block_size, 0, 0, fua, 0, 0, iscsi_aio_write10_cb, acb); if (acb->task == NULL) { error_report("iSCSI: Failed to send write10 command. %s", iscsi_get_error(iscsi)); g_free(acb->buf); qemu_aio_release(acb); return NULL; } iscsi_set_events(iscsilun); return &acb->common; }
static int iscsi_aio_discard_acb(IscsiAIOCB *acb) { struct iscsi_context *iscsi = acb->iscsilun->iscsi; struct unmap_list list[1]; acb->canceled = 0; acb->bh = NULL; acb->status = -EINPROGRESS; acb->buf = NULL; list[0].lba = sector_qemu2lun(acb->sector_num, acb->iscsilun); list[0].num = acb->nb_sectors * BDRV_SECTOR_SIZE / acb->iscsilun->block_size; acb->task = iscsi_unmap_task(iscsi, acb->iscsilun->lun, 0, 0, &list[0], 1, iscsi_unmap_cb, acb); if (acb->task == NULL) { error_report("iSCSI: Failed to send unmap command. %s", iscsi_get_error(iscsi)); return -1; } return 0; }
static int iscsi_aio_readv_acb(IscsiAIOCB *acb) { struct iscsi_context *iscsi = acb->iscsilun->iscsi; size_t size; 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; } 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); switch (acb->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); 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); 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 defined(LIBISCSI_FEATURE_IOVECTOR) scsi_task_set_iov_in(acb->task, (struct scsi_iovec*) acb->qiov->iov, acb->qiov->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); } #endif return 0; }
static int iscsi_aio_writev_acb(IscsiAIOCB *acb) { struct iscsi_context *iscsi = acb->iscsilun->iscsi; size_t size; uint32_t num_sectors; 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; /* this will allow us to get rid of 'buf' completely */ size = acb->nb_sectors * BDRV_SECTOR_SIZE; #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; } else { acb->buf = g_malloc(data.size); qemu_iovec_to_buf(acb->qiov, 0, acb->buf, data.size); data.data = acb->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; } 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); #endif if (ret != 0) { scsi_free_scsi_task(acb->task); g_free(acb->buf); return -1; } #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_readv(BlockDriverState *bs, int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, BlockDriverCompletionFunc *cb, void *opaque) { IscsiLun *iscsilun = bs->opaque; struct iscsi_context *iscsi = iscsilun->iscsi; IscsiAIOCB *acb; size_t qemu_read_size; int i; uint64_t lba; uint32_t num_sectors; qemu_read_size = BDRV_SECTOR_SIZE * (size_t)nb_sectors; acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque); trace_iscsi_aio_readv(iscsi, sector_num, nb_sectors, opaque, acb); acb->iscsilun = iscsilun; acb->qiov = qiov; acb->canceled = 0; acb->bh = NULL; acb->status = -EINPROGRESS; acb->read_size = qemu_read_size; acb->buf = NULL; /* If LUN blocksize is bigger than BDRV_BLOCK_SIZE a read from QEMU * may be misaligned to the LUN, so we may need to read some extra * data. */ acb->read_offset = 0; if (iscsilun->block_size > BDRV_SECTOR_SIZE) { uint64_t bdrv_offset = BDRV_SECTOR_SIZE * sector_num; acb->read_offset = bdrv_offset % iscsilun->block_size; } num_sectors = (qemu_read_size + iscsilun->block_size + acb->read_offset - 1) / iscsilun->block_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)); qemu_aio_release(acb); return NULL; } memset(acb->task, 0, sizeof(struct scsi_task)); acb->task->xfer_dir = SCSI_XFER_READ; lba = sector_qemu2lun(sector_num, iscsilun); acb->task->expxferlen = qemu_read_size; 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); 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); break; } if (iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task, iscsi_aio_read16_cb, NULL, acb) != 0) { scsi_free_scsi_task(acb->task); qemu_aio_release(acb); return NULL; } 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); } iscsi_set_events(iscsilun); return &acb->common; }
static BlockDriverAIOCB * iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, BlockDriverCompletionFunc *cb, void *opaque) { IscsiLun *iscsilun = bs->opaque; struct iscsi_context *iscsi = iscsilun->iscsi; IscsiAIOCB *acb; size_t size; uint32_t num_sectors; uint64_t lba; struct iscsi_data data; acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque); trace_iscsi_aio_writev(iscsi, sector_num, nb_sectors, opaque, acb); acb->iscsilun = iscsilun; acb->qiov = qiov; acb->canceled = 0; acb->bh = NULL; acb->status = -EINPROGRESS; /* XXX we should pass the iovec to write16 to avoid the extra copy */ /* this will allow us to get rid of 'buf' completely */ size = nb_sectors * BDRV_SECTOR_SIZE; data.size = MIN(size, acb->qiov->size); /* if the iovec only contains one buffer we can pass it directly */ if (acb->qiov->niov == 1) { acb->buf = NULL; data.data = acb->qiov->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; } 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)); qemu_aio_release(acb); return NULL; } 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(sector_num, iscsilun); *(uint32_t *)&acb->task->cdb[2] = htonl(lba >> 32); *(uint32_t *)&acb->task->cdb[6] = htonl(lba & 0xffffffff); num_sectors = size / iscsilun->block_size; *(uint32_t *)&acb->task->cdb[10] = htonl(num_sectors); acb->task->expxferlen = size; if (iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task, iscsi_aio_write16_cb, &data, acb) != 0) { scsi_free_scsi_task(acb->task); g_free(acb->buf); qemu_aio_release(acb); return NULL; } iscsi_set_events(iscsilun); return &acb->common; }
static int iscsi_aio_readv_acb(IscsiAIOCB *acb) { struct iscsi_context *iscsi = acb->iscsilun->iscsi; 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; /* If LUN blocksize is bigger than BDRV_BLOCK_SIZE a read from QEMU * may be misaligned to the LUN, so we may need to read some extra * data. */ acb->read_offset = 0; if (acb->iscsilun->block_size > BDRV_SECTOR_SIZE) { uint64_t bdrv_offset = BDRV_SECTOR_SIZE * acb->sector_num; acb->read_offset = bdrv_offset % acb->iscsilun->block_size; } num_sectors = (acb->read_size + acb->iscsilun->block_size + acb->read_offset - 1) / acb->iscsilun->block_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; } memset(acb->task, 0, sizeof(struct scsi_task)); acb->task->xfer_dir = SCSI_XFER_READ; lba = sector_qemu2lun(acb->sector_num, acb->iscsilun); acb->task->expxferlen = acb->read_size; switch (acb->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); 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); break; } ret = iscsi_scsi_command_async(iscsi, acb->iscsilun->lun, acb->task, iscsi_aio_read16_cb, NULL, acb); if (ret != 0) { return -1; } #if defined(LIBISCSI_FEATURE_IOVECTOR) scsi_task_set_iov_in(acb->task, (struct scsi_iovec*) acb->qiov->iov, acb->qiov->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); } #endif return 0; }