diff --git a/test-tool/iscsi-support.c b/test-tool/iscsi-support.c index 80766e2..6e645ce 100644 --- a/test-tool/iscsi-support.c +++ b/test-tool/iscsi-support.c @@ -48,6 +48,7 @@ const char *tgt_url; struct scsi_inquiry_standard *inq; struct scsi_inquiry_logical_block_provisioning *inq_lbp; +struct scsi_inquiry_block_limits *inq_bl; struct scsi_readcapacity16 *rc16; size_t block_size; diff --git a/test-tool/iscsi-support.h b/test-tool/iscsi-support.h index c48414c..f83e9c3 100644 --- a/test-tool/iscsi-support.h +++ b/test-tool/iscsi-support.h @@ -130,6 +130,7 @@ do { \ extern struct scsi_inquiry_standard *inq; extern struct scsi_inquiry_logical_block_provisioning *inq_lbp; +extern struct scsi_inquiry_block_limits *inq_bl; extern struct scsi_readcapacity16 *rc16; extern size_t block_size; diff --git a/test-tool/iscsi-test-cu.c b/test-tool/iscsi-test-cu.c index 7422d7f..02c3aa0 100644 --- a/test-tool/iscsi-test-cu.c +++ b/test-tool/iscsi-test-cu.c @@ -865,6 +865,7 @@ main(int argc, char *argv[]) struct scsi_readcapacity10 *rc10; struct scsi_task *inq_task = NULL; struct scsi_task *inq_lbp_task = NULL; + struct scsi_task *inq_bl_task = NULL; struct scsi_task *rc16_task = NULL; int full_size; int is_usb; @@ -1051,6 +1052,31 @@ main(int argc, char *argv[]) } } + /* try reading block limits vpd */ + inq_bl_task = iscsi_inquiry_sync(iscsic, lun, 1, SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS, 64); + if (inq_bl_task && inq_bl_task->status != SCSI_STATUS_GOOD) { + scsi_free_scsi_task(inq_bl_task); + inq_bl_task = NULL; + } + if (inq_bl_task) { + full_size = scsi_datain_getfullsize(inq_bl_task); + if (full_size > inq_bl_task->datain.size) { + scsi_free_scsi_task(inq_lbp_task); + + if ((inq_bl_task = iscsi_inquiry_sync(iscsic, lun, 1, SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS, full_size)) == NULL) { + printf("Inquiry command failed : %s\n", iscsi_get_error(iscsic)); + return -1; + } + } + + inq_bl = scsi_datain_unmarshall(inq_bl_task); + if (inq_bl == NULL) { + printf("failed to unmarshall inquiry datain blob\n"); + return -1; + } + } + + /* if thin provisioned we also need to read the VPD page for it */ if (rc16 && rc16->lbpme != 0){ inq_lbp_task = iscsi_inquiry_sync(iscsic, lun, 1, SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING, 64); @@ -1141,6 +1167,9 @@ main(int argc, char *argv[]) if (inq_task != NULL) { scsi_free_scsi_task(inq_task); } + if (inq_bl_task != NULL) { + scsi_free_scsi_task(inq_bl_task); + } if (inq_lbp_task != NULL) { scsi_free_scsi_task(inq_lbp_task); } diff --git a/test-tool/test_inquiry_block_limits.c b/test-tool/test_inquiry_block_limits.c index 098a407..95345cb 100644 --- a/test-tool/test_inquiry_block_limits.c +++ b/test-tool/test_inquiry_block_limits.c @@ -28,7 +28,7 @@ void test_inquiry_block_limits(void) { int ret; - struct scsi_inquiry_block_limits *inq_bl; + struct scsi_inquiry_block_limits *bl; struct scsi_task *bl_task = NULL; struct scsi_inquiry_logical_block_provisioning *lbp = NULL; struct scsi_task *lbp_task = NULL; @@ -44,8 +44,8 @@ test_inquiry_block_limits(void) 64, &bl_task); CU_ASSERT_EQUAL(ret, 0); - inq_bl = scsi_datain_unmarshall(bl_task); - if (inq_bl == NULL) { + bl = scsi_datain_unmarshall(bl_task); + if (bl == NULL) { logging(LOG_NORMAL, "[FAILURE] failed to unmarshall inquiry " "datain blob."); CU_FAIL("[FAILURE] failed to unmarshall inquiry " @@ -125,36 +125,36 @@ test_inquiry_block_limits(void) logging(LOG_VERBOSE, "Device claims UNMAP support via LBPU"); logging(LOG_VERBOSE, "Verify that MAXIMUM UNMAP LBA COUNT is " "not 0"); - CU_ASSERT_NOT_EQUAL(inq_bl->max_unmap, 0); + CU_ASSERT_NOT_EQUAL(bl->max_unmap, 0); logging(LOG_VERBOSE, "Verify that MAXIMUM UNMAP LBA COUNT is " "at least 2^LBPPBE"); - CU_ASSERT_EQUAL(inq_bl->max_unmap >= (1U << rc16->lbppbe), 1); + CU_ASSERT_EQUAL(bl->max_unmap >= (1U << rc16->lbppbe), 1); - if (inq_bl->max_unmap != 0xffffffff) { + if (bl->max_unmap != 0xffffffff) { logging(LOG_VERBOSE, "Verify that MAXIMUM UNMAP LBA " "COUNT is not insanely big"); - CU_ASSERT_EQUAL(inq_bl->max_unmap <= 1024*1024, 0); + CU_ASSERT_EQUAL(bl->max_unmap <= 1024*1024, 0); } logging(LOG_VERBOSE, "Verify that MAXIMUM UNMAP BLOCK " "DESCRIPTOR COUNT is not 0"); - CU_ASSERT_NOT_EQUAL(inq_bl->max_unmap_bdc, 0); - if (inq_bl->max_unmap_bdc != 0xffffffff) { + CU_ASSERT_NOT_EQUAL(bl->max_unmap_bdc, 0); + if (bl->max_unmap_bdc != 0xffffffff) { logging(LOG_VERBOSE, "Verify that MAXIMUM UNMAP " "BLOCK DESCRIPTOR COUNT is not insanely big"); - CU_ASSERT_EQUAL(inq_bl->max_unmap_bdc <= 1024*1024, 0); + CU_ASSERT_EQUAL(bl->max_unmap_bdc <= 1024*1024, 0); } } else { logging(LOG_VERBOSE, "Device does not claim UNMAP support via " "LBPU"); logging(LOG_VERBOSE, "Verify that MAXIMUM UNMAP LBA COUNT is " "0"); - CU_ASSERT_EQUAL(inq_bl->max_unmap, 0); + CU_ASSERT_EQUAL(bl->max_unmap, 0); logging(LOG_VERBOSE, "Verify that MAXIMUM UNMAP BLOCK " "DESCRIPTOR COUNT is 0"); - CU_ASSERT_EQUAL(inq_bl->max_unmap_bdc, 0); + CU_ASSERT_EQUAL(bl->max_unmap_bdc, 0); } diff --git a/test-tool/test_writesame10_unmap.c b/test-tool/test_writesame10_unmap.c index c173222..398642b 100644 --- a/test-tool/test_writesame10_unmap.c +++ b/test-tool/test_writesame10_unmap.c @@ -16,6 +16,7 @@ */ #include +#include #include @@ -30,6 +31,7 @@ test_writesame10_unmap(void) { int i, ret; unsigned int j; + unsigned char *buf = malloc(block_size * 256); CHECK_FOR_DATALOSS; CHECK_FOR_THIN_PROVISIONING; @@ -37,9 +39,118 @@ test_writesame10_unmap(void) CHECK_FOR_SBC; logging(LOG_VERBOSE, LOG_BLANK_LINE); - logging(LOG_VERBOSE, "Test WRITESAME10 of 1-256 blocks at the start of the LUN"); + logging(LOG_VERBOSE, "Test WRITESAME10 of 1-256 blocks at the start of " + "the LUN"); for (i = 1; i <= 256; i++) { - unsigned char *buf = malloc(block_size * i); + logging(LOG_VERBOSE, "Write %d blocks of 0xFF", i); + memset(buf, 0xff, block_size * i); + ret = write10(iscsic, tgt_lun, 0, + i * block_size, block_size, + 0, 0, 0, 0, 0, buf); + CU_ASSERT_EQUAL(ret, 0); + + logging(LOG_VERBOSE, "Unmap %d blocks using WRITESAME10", i); + ret = writesame10(iscsic, tgt_lun, 0, + block_size, i, + 0, 1, 0, 0, NULL); + CU_ASSERT_EQUAL(ret, 0); + + if (rc16->lbprz) { + logging(LOG_VERBOSE, "LBPRZ is set. Read the unmapped " + "blocks back and verify they are all zero"); + + logging(LOG_VERBOSE, "Read %d blocks and verify they " + "are now zero", i); + ret = read10(iscsic, tgt_lun, 0, + i * block_size, block_size, + 0, 0, 0, 0, 0, buf); + for (j = 0; j < block_size * i; j++) { + if (buf[j] != 0) { + CU_ASSERT_EQUAL(buf[j], 0); + } + } + } else { + logging(LOG_VERBOSE, "LBPRZ is clear. Skip the read " + "and verify zero test"); + } + } + + + logging(LOG_VERBOSE, "Test WRITESAME10 of 1-256 blocks at the end of " + "the LUN"); + for (i = 1; i <= 256; i++) { + logging(LOG_VERBOSE, "Write %d blocks of 0xFF", i); + memset(buf, 0xff, block_size * i); + ret = write10(iscsic, tgt_lun, num_blocks - i, + i * block_size, block_size, + 0, 0, 0, 0, 0, buf); + CU_ASSERT_EQUAL(ret, 0); + + logging(LOG_VERBOSE, "Unmap %d blocks using WRITESAME10", i); + ret = writesame10(iscsic, tgt_lun, num_blocks - i, + block_size, i, + 0, 1, 0, 0, buf); + CU_ASSERT_EQUAL(ret, 0); + + if (rc16->lbprz) { + logging(LOG_VERBOSE, "LBPRZ is set. Read the unmapped " + "blocks back and verify they are all zero"); + + logging(LOG_VERBOSE, "Read %d blocks and verify they " + "are now zero", i); + ret = read10(iscsic, tgt_lun, num_blocks - i, + i * block_size, block_size, + 0, 0, 0, 0, 0, buf); + for (j = 0; j < block_size * i; j++) { + if (buf[j] != 0) { + CU_ASSERT_EQUAL(buf[j], 0); + } + } + } else { + logging(LOG_VERBOSE, "LBPRZ is clear. Skip the read " + "and verify zero test"); + } + } + + logging(LOG_VERBOSE, "Verify that WRITESAME10 ANCHOR==1 + UNMAP==0 is " + "invalid"); + ret = writesame10_invalidfieldincdb(iscsic, tgt_lun, 0, + block_size, 1, + 1, 0, 0, 0, NULL); + CU_ASSERT_EQUAL(ret, 0); + + + + if (inq_lbp->anc_sup) { + logging(LOG_VERBOSE, "Test WRITESAME10 ANCHOR==1 + UNMAP==0"); + ret = writesame10(iscsic, tgt_lun, 0, + block_size, 1, + 1, 1, 0, 0, NULL); + } else { + logging(LOG_VERBOSE, "Test WRITESAME10 ANCHOR==1 + UNMAP==0 no " + "ANC_SUP so expecting to fail"); + ret = writesame10_invalidfieldincdb(iscsic, tgt_lun, 0, + block_size, 1, + 1, 1, 0, 0, NULL); + } + CU_ASSERT_EQUAL(ret, 0); + + + if (inq_bl == NULL) { + logging(LOG_VERBOSE, "[FAILED] WRITESAME10 works but " + "BlockLimits VPD is missing."); + CU_FAIL("[FAILED] WRITESAME10 works but " + "BlockLimits VPD is missing."); + free(buf); + return; + } + + i = 256; + if (inq_bl->max_ws_len == 0 || inq_bl->max_ws_len >= 256) { + logging(LOG_VERBOSE, "Block Limits VPD page reports MAX_WS_LEN " + "as either 0 (==no limit) or >= 256. Test Unmapping " + "256 blocks to verify that it can handle 2-byte " + "lengths"); logging(LOG_VERBOSE, "Write %d blocks of 0xFF", i); memset(buf, 0xff, block_size * i); @@ -72,68 +183,16 @@ test_writesame10_unmap(void) logging(LOG_VERBOSE, "LBPRZ is clear. Skip the read " "and verify zero test"); } - free(buf); - } - - - logging(LOG_VERBOSE, "Test WRITESAME10 of 1-256 blocks at the end of the LUN"); - for (i = 1; i <= 256; i++) { - unsigned char *buf = malloc(block_size * i); - - logging(LOG_VERBOSE, "Write %d blocks of 0xFF", i); - memset(buf, 0xff, block_size * i); - ret = write10(iscsic, tgt_lun, num_blocks - i, - i * block_size, block_size, - 0, 0, 0, 0, 0, buf); - CU_ASSERT_EQUAL(ret, 0); + } else { + logging(LOG_VERBOSE, "Block Limits VPD page reports MAX_WS_LEN " + "as <256. Verify that a 256 block unmap fails with " + "INVALID_FIELD_IN_CDB."); logging(LOG_VERBOSE, "Unmap %d blocks using WRITESAME10", i); - ret = writesame10(iscsic, tgt_lun, num_blocks - i, - block_size, i, - 0, 1, 0, 0, buf); - CU_ASSERT_EQUAL(ret, 0); - - if (rc16->lbprz) { - logging(LOG_VERBOSE, "LBPRZ is set. Read the unmapped " - "blocks back and verify they are all zero"); - - logging(LOG_VERBOSE, "Read %d blocks and verify they " - "are now zero", i); - ret = read10(iscsic, tgt_lun, num_blocks - i, - i * block_size, block_size, - 0, 0, 0, 0, 0, buf); - for (j = 0; j < block_size * i; j++) { - if (buf[j] != 0) { - CU_ASSERT_EQUAL(buf[j], 0); - } - } - } else { - logging(LOG_VERBOSE, "LBPRZ is clear. Skip the read " - "and verify zero test"); - } - free(buf); - } - - logging(LOG_VERBOSE, "Verify that WRITESAME10 ANCHOR==1 + UNMAP==0 is invalid"); - ret = writesame10_invalidfieldincdb(iscsic, tgt_lun, 0, - block_size, 1, - 1, 0, 0, 0, NULL); - CU_ASSERT_EQUAL(ret, 0); - - - - if (inq_lbp->anc_sup) { - logging(LOG_VERBOSE, "Test WRITESAME10 ANCHOR==1 + UNMAP==0"); - ret = writesame10(iscsic, tgt_lun, 0, - block_size, 1, - 1, 1, 0, 0, NULL); - } else { - logging(LOG_VERBOSE, "Test WRITESAME10 ANCHOR==1 + UNMAP==0 no ANC_SUP so expecting to fail"); ret = writesame10_invalidfieldincdb(iscsic, tgt_lun, 0, - block_size, 1, - 1, 1, 0, 0, NULL); + block_size, i, + 0, 1, 0, 0, NULL); + CU_ASSERT_EQUAL(ret, 0); } - - CU_ASSERT_EQUAL(ret, 0); - + free(buf); } diff --git a/test-tool/test_writesame16_unmap.c b/test-tool/test_writesame16_unmap.c index f232ac7..b96c0dd 100644 --- a/test-tool/test_writesame16_unmap.c +++ b/test-tool/test_writesame16_unmap.c @@ -16,7 +16,6 @@ */ #include -#include #include @@ -31,7 +30,7 @@ test_writesame16_unmap(void) { int i, ret; unsigned int j; - unsigned char *buf = alloca(256 * block_size); + unsigned char *buf = malloc(block_size * 65536); CHECK_FOR_DATALOSS; @@ -55,6 +54,7 @@ test_writesame16_unmap(void) if (ret == -2) { logging(LOG_NORMAL, "[SKIPPED] WRITESAME16 is not implemented."); CU_PASS("[SKIPPED] Target does not support WRITESAME16. Skipping test"); + free(buf); return; } CU_ASSERT_EQUAL(ret, 0); @@ -135,4 +135,117 @@ test_writesame16_unmap(void) CU_ASSERT_EQUAL(ret, 0); + + if (inq_bl == NULL) { + logging(LOG_VERBOSE, "[FAILED] WRITESAME16 works but " + "BlockLimits VPD is missing."); + CU_FAIL("[FAILED] WRITESAME10 works but " + "BlockLimits VPD is missing."); + free(buf); + return; + } + + i = 256; + if (inq_bl->max_ws_len == 0 || inq_bl->max_ws_len >= 256) { + logging(LOG_VERBOSE, "Block Limits VPD page reports MAX_WS_LEN " + "as either 0 (==no limit) or >= 256. Test Unmapping " + "256 blocks to verify that it can handle 2-byte " + "lengths"); + + logging(LOG_VERBOSE, "Write %d blocks of 0xFF", i); + memset(buf, 0xff, block_size * i); + ret = write10(iscsic, tgt_lun, 0, + i * block_size, block_size, + 0, 0, 0, 0, 0, buf); + CU_ASSERT_EQUAL(ret, 0); + + logging(LOG_VERBOSE, "Unmap %d blocks using WRITESAME10", i); + ret = writesame10(iscsic, tgt_lun, 0, + block_size, i, + 0, 1, 0, 0, NULL); + CU_ASSERT_EQUAL(ret, 0); + + if (rc16->lbprz) { + logging(LOG_VERBOSE, "LBPRZ is set. Read the unmapped " + "blocks back and verify they are all zero"); + + logging(LOG_VERBOSE, "Read %d blocks and verify they " + "are now zero", i); + ret = read10(iscsic, tgt_lun, 0, + i * block_size, block_size, + 0, 0, 0, 0, 0, buf); + for (j = 0; j < block_size * i; j++) { + if (buf[j] != 0) { + CU_ASSERT_EQUAL(buf[j], 0); + } + } + } else { + logging(LOG_VERBOSE, "LBPRZ is clear. Skip the read " + "and verify zero test"); + } + } else { + logging(LOG_VERBOSE, "Block Limits VPD page reports MAX_WS_LEN " + "as <256. Verify that a 256 block unmap fails with " + "INVALID_FIELD_IN_CDB."); + + logging(LOG_VERBOSE, "Unmap %d blocks using WRITESAME10", i); + ret = writesame10_invalidfieldincdb(iscsic, tgt_lun, 0, + block_size, i, + 0, 1, 0, 0, NULL); + CU_ASSERT_EQUAL(ret, 0); + } + + + + i = 65536; + if (inq_bl->max_ws_len == 0 || inq_bl->max_ws_len >= 256) { + logging(LOG_VERBOSE, "Block Limits VPD page reports MAX_WS_LEN " + "as either 0 (==no limit) or >= 256. Test Unmapping " + "256 blocks to verify that it can handle 2-byte " + "lengths"); + + logging(LOG_VERBOSE, "Write %d blocks of 0xFF", i); + memset(buf, 0xff, block_size * i); + ret = write10(iscsic, tgt_lun, 0, + i * block_size, block_size, + 0, 0, 0, 0, 0, buf); + CU_ASSERT_EQUAL(ret, 0); + + logging(LOG_VERBOSE, "Unmap %d blocks using WRITESAME10", i); + ret = writesame10(iscsic, tgt_lun, 0, + block_size, i, + 0, 1, 0, 0, NULL); + CU_ASSERT_EQUAL(ret, 0); + + if (rc16->lbprz) { + logging(LOG_VERBOSE, "LBPRZ is set. Read the unmapped " + "blocks back and verify they are all zero"); + + logging(LOG_VERBOSE, "Read %d blocks and verify they " + "are now zero", i); + ret = read10(iscsic, tgt_lun, 0, + i * block_size, block_size, + 0, 0, 0, 0, 0, buf); + for (j = 0; j < block_size * i; j++) { + if (buf[j] != 0) { + CU_ASSERT_EQUAL(buf[j], 0); + } + } + } else { + logging(LOG_VERBOSE, "LBPRZ is clear. Skip the read " + "and verify zero test"); + } + } else { + logging(LOG_VERBOSE, "Block Limits VPD page reports MAX_WS_LEN " + "as <256. Verify that a 256 block unmap fails with " + "INVALID_FIELD_IN_CDB."); + + logging(LOG_VERBOSE, "Unmap %d blocks using WRITESAME10", i); + ret = writesame10_invalidfieldincdb(iscsic, tgt_lun, 0, + block_size, i, + 0, 1, 0, 0, NULL); + CU_ASSERT_EQUAL(ret, 0); + } + + free(buf); }