block/iscsi: use 16 byte CDBs only when necessary

this patch changes the driver to uses 16 Byte CDBs for
READ/WRITE only if the target requires 64bit lba addressing.

On one hand this saves 6 bytes in each PDU on the other
hand it seems that 10 Byte CDBs seems to be much better
supported and tested as a recent issue I had with a
major storage supplier lined out.

For WRITESAME the logic is a bit more tricky as WRITESAME10
with UNMAP was added really late. Thus a fallback to WRITESAME16
is possible if it supports UNMAP and WRITESAME10 not.

Signed-off-by: Peter Lieven <pl@kamp.de>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Peter Lieven 2014-06-04 15:47:39 +02:00 committed by Paolo Bonzini
parent fcd470d857
commit 9281fe9eea

View File

@ -65,6 +65,7 @@ typedef struct IscsiLun {
unsigned char *zeroblock; unsigned char *zeroblock;
unsigned long *allocationmap; unsigned long *allocationmap;
int cluster_sectors; int cluster_sectors;
bool use_16_for_rw;
} IscsiLun; } IscsiLun;
typedef struct IscsiTask { typedef struct IscsiTask {
@ -381,10 +382,17 @@ static int coroutine_fn iscsi_co_writev(BlockDriverState *bs,
#endif #endif
iscsi_co_init_iscsitask(iscsilun, &iTask); iscsi_co_init_iscsitask(iscsilun, &iTask);
retry: retry:
iTask.task = iscsi_write16_task(iscsilun->iscsi, iscsilun->lun, lba, if (iscsilun->use_16_for_rw) {
data, num_sectors * iscsilun->block_size, iTask.task = iscsi_write16_task(iscsilun->iscsi, iscsilun->lun, lba,
iscsilun->block_size, 0, 0, 0, 0, 0, data, num_sectors * iscsilun->block_size,
iscsi_co_generic_cb, &iTask); iscsilun->block_size, 0, 0, 0, 0, 0,
iscsi_co_generic_cb, &iTask);
} else {
iTask.task = iscsi_write10_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) { if (iTask.task == NULL) {
g_free(buf); g_free(buf);
return -ENOMEM; return -ENOMEM;
@ -570,14 +578,12 @@ static int coroutine_fn iscsi_co_readv(BlockDriverState *bs,
iscsi_co_init_iscsitask(iscsilun, &iTask); iscsi_co_init_iscsitask(iscsilun, &iTask);
retry: retry:
switch (iscsilun->type) { if (iscsilun->use_16_for_rw) {
case TYPE_DISK:
iTask.task = iscsi_read16_task(iscsilun->iscsi, iscsilun->lun, lba, iTask.task = iscsi_read16_task(iscsilun->iscsi, iscsilun->lun, lba,
num_sectors * iscsilun->block_size, num_sectors * iscsilun->block_size,
iscsilun->block_size, 0, 0, 0, 0, 0, iscsilun->block_size, 0, 0, 0, 0, 0,
iscsi_co_generic_cb, &iTask); iscsi_co_generic_cb, &iTask);
break; } else {
default:
iTask.task = iscsi_read10_task(iscsilun->iscsi, iscsilun->lun, lba, iTask.task = iscsi_read10_task(iscsilun->iscsi, iscsilun->lun, lba,
num_sectors * iscsilun->block_size, num_sectors * iscsilun->block_size,
iscsilun->block_size, iscsilun->block_size,
@ -585,7 +591,6 @@ retry:
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
#endif #endif
iscsi_co_generic_cb, &iTask); iscsi_co_generic_cb, &iTask);
break;
} }
if (iTask.task == NULL) { if (iTask.task == NULL) {
return -ENOMEM; return -ENOMEM;
@ -921,19 +926,27 @@ coroutine_fn iscsi_co_write_zeroes(BlockDriverState *bs, int64_t sector_num,
struct IscsiTask iTask; struct IscsiTask iTask;
uint64_t lba; uint64_t lba;
uint32_t nb_blocks; uint32_t nb_blocks;
bool use_16_for_ws = iscsilun->use_16_for_rw;
if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) { if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) {
return -EINVAL; return -EINVAL;
} }
if ((flags & BDRV_REQ_MAY_UNMAP) && !iscsilun->lbp.lbpws) { if (flags & BDRV_REQ_MAY_UNMAP) {
/* WRITE SAME with UNMAP is not supported by the target, if (!use_16_for_ws && !iscsilun->lbp.lbpws10) {
* fall back and try WRITE SAME without UNMAP */ /* WRITESAME10 with UNMAP is unsupported try WRITESAME16 */
flags &= ~BDRV_REQ_MAY_UNMAP; use_16_for_ws = true;
}
if (use_16_for_ws && !iscsilun->lbp.lbpws) {
/* WRITESAME16 with UNMAP is not supported by the target,
* fall back and try WRITESAME10/16 without UNMAP */
flags &= ~BDRV_REQ_MAY_UNMAP;
use_16_for_ws = iscsilun->use_16_for_rw;
}
} }
if (!(flags & BDRV_REQ_MAY_UNMAP) && !iscsilun->has_write_same) { if (!(flags & BDRV_REQ_MAY_UNMAP) && !iscsilun->has_write_same) {
/* WRITE SAME without UNMAP is not supported by the target */ /* WRITESAME without UNMAP is not supported by the target */
return -ENOTSUP; return -ENOTSUP;
} }
@ -946,10 +959,18 @@ coroutine_fn iscsi_co_write_zeroes(BlockDriverState *bs, int64_t sector_num,
iscsi_co_init_iscsitask(iscsilun, &iTask); iscsi_co_init_iscsitask(iscsilun, &iTask);
retry: retry:
if (iscsi_writesame16_task(iscsilun->iscsi, iscsilun->lun, lba, if (use_16_for_ws) {
iscsilun->zeroblock, iscsilun->block_size, iTask.task = iscsi_writesame16_task(iscsilun->iscsi, iscsilun->lun, lba,
nb_blocks, 0, !!(flags & BDRV_REQ_MAY_UNMAP), iscsilun->zeroblock, iscsilun->block_size,
0, 0, iscsi_co_generic_cb, &iTask) == NULL) { nb_blocks, 0, !!(flags & BDRV_REQ_MAY_UNMAP),
0, 0, iscsi_co_generic_cb, &iTask);
} else {
iTask.task = iscsi_writesame10_task(iscsilun->iscsi, iscsilun->lun, lba,
iscsilun->zeroblock, iscsilun->block_size,
nb_blocks, 0, !!(flags & BDRV_REQ_MAY_UNMAP),
0, 0, iscsi_co_generic_cb, &iTask);
}
if (iTask.task == NULL) {
return -ENOMEM; return -ENOMEM;
} }
@ -1147,6 +1168,7 @@ static void iscsi_readcapacity_sync(IscsiLun *iscsilun, Error **errp)
iscsilun->num_blocks = rc16->returned_lba + 1; iscsilun->num_blocks = rc16->returned_lba + 1;
iscsilun->lbpme = rc16->lbpme; iscsilun->lbpme = rc16->lbpme;
iscsilun->lbprz = rc16->lbprz; iscsilun->lbprz = rc16->lbprz;
iscsilun->use_16_for_rw = (rc16->returned_lba > 0xffffffff);
} }
} }
break; break;