void
test_compareandwrite_miscompare(void)
{
	int i, ret;
	unsigned j;
	unsigned char *buf = alloca(2 * 256 * block_size);
	int maxbl;

	CHECK_FOR_DATALOSS;
	CHECK_FOR_SBC;

	if (inq_bl && inq_bl->max_cmp) {
		maxbl = inq_bl->max_cmp;
	} else {
		/* Assume we are not limited */
		maxbl = 256;
	}
	logging(LOG_VERBOSE, LOG_BLANK_LINE);
	logging(LOG_VERBOSE, "Test COMPARE_AND_WRITE of 1-256 blocks at the "
		"start of the LUN. One Byte miscompare in the final block.");
	for (i = 1; i < 256; i++) {
		logging(LOG_VERBOSE, "Write %d blocks of 'A' at LBA:0", i);
		memset(buf, 'A', 2 * i * block_size);
		if (maximum_transfer_length && maximum_transfer_length < i) {
			break;
		}
		ret = write16(iscsic, tgt_lun, 0, i * block_size,
		    block_size, 0, 0, 0, 0, 0, buf);
		if (ret == -2) {
			logging(LOG_NORMAL, "[SKIPPED] WRITE16 is not implemented.");
			CU_PASS("WRITE16 is not implemented.");
			return;
		}	
		CU_ASSERT_EQUAL(ret, 0);

		
		logging(LOG_VERBOSE, "Change byte 27 from the end to 'C' so that it does not match.");
		buf[i * block_size - 27] = 'C';

		if (i > maxbl) {
			logging(LOG_VERBOSE, "Number of blocks %d is greater than "
				"BlockLimits.MaximumCompareAndWriteLength(%d). "
				"Command should fail with INVALID_FIELD_IN_CDB",
				i, maxbl);
			ret = compareandwrite_invalidfieldincdb(iscsic, tgt_lun, 0,
				buf, 2 * i * block_size, block_size,
				0, 0, 0, 0);
			if (ret == -2) {
				CU_PASS("[SKIPPED] Target does not support "
					"COMPARE_AND_WRITE. Skipping test");
				return;
			}
			CU_ASSERT_EQUAL(ret, 0);

			continue;
		}

		memset(buf + i * block_size, 'B', i * block_size);

		logging(LOG_VERBOSE, "Overwrite %d blocks with 'B' "
			"at LBA:0 (if they all contain 'A')", i);
		ret = compareandwrite_miscompare(iscsic, tgt_lun, 0,
			buf, 2 * i * block_size, block_size, 0, 0, 0, 0);
		if (ret == -2) {
			CU_PASS("[SKIPPED] Target does not support "
				"COMPARE_AND_WRITE. Skipping test");
			return;
		}
		CU_ASSERT_EQUAL(ret, 0);

		logging(LOG_VERBOSE, "Read %d blocks at LBA:0 and verify "
			"they are still unchanged as 'A'", i);
		ret = read16(iscsic, tgt_lun, 0, i * block_size,
		    block_size, 0, 0, 0, 0, 0, buf);
		CU_ASSERT_EQUAL(ret, 0);

		for (j = 0; j < i * block_size; j++) {
			if (buf[j] != 'A') {
				logging(LOG_VERBOSE, "[FAILED] Data changed "
					"eventhough there was a miscompare");
				CU_FAIL("Block was written to");
				return;
			}
		}
	}


	logging(LOG_VERBOSE, "Test COMPARE_AND_WRITE of 1-256 blocks at the "
		"end of the LUN");
	for (i = 1; i < 256; i++) {
		logging(LOG_VERBOSE, "Write %d blocks of 'A' at LBA:%" PRIu64,
			i, num_blocks - i);
		memset(buf, 'A', 2 * i * block_size);
		if (maximum_transfer_length && maximum_transfer_length < i) {
			break;
		}
		ret = write16(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, "Change byte 27 from the end to 'C' so that it does not match.");
		buf[i * block_size - 27] = 'C';


		if (i > maxbl) {
			logging(LOG_VERBOSE, "Number of blocks %d is greater than "
				"BlockLimits.MaximumCompareAndWriteLength(%d). "
				"Command should fail with INVALID_FIELD_IN_CDB",
				i, maxbl);
			ret = compareandwrite_invalidfieldincdb(iscsic, tgt_lun, 0,
				buf, 2 * i * block_size, block_size,
				0, 0, 0, 0);
			CU_ASSERT_EQUAL(ret, 0);

			continue;
		}
		memset(buf + i * block_size, 'B', i * block_size);

		logging(LOG_VERBOSE, "Overwrite %d blocks with 'B' "
			"at LBA:%" PRIu64 " (if they all contain 'A')",
			i, num_blocks - i);
		ret = compareandwrite_miscompare(iscsic, tgt_lun,
			num_blocks - i,
			buf, 2 * i * block_size, block_size, 0, 0, 0, 0);
		CU_ASSERT_EQUAL(ret, 0);

		logging(LOG_VERBOSE, "Read %d blocks at LBA:%" PRIu64 
			"they are still unchanged as 'A'",
			i, num_blocks - i);
		ret = read16(iscsic, tgt_lun, num_blocks - i, i * block_size,
		    block_size, 0, 0, 0, 0, 0, buf);
		CU_ASSERT_EQUAL(ret, 0);

		for (j = 0; j < i * block_size; j++) {
			if (buf[j] != 'A') {
				logging(LOG_VERBOSE, "[FAILED] Data changed "
					"eventhough there was a miscompare");
				CU_FAIL("Block was written to");
				return;
			}
		}
	}
}
void
test_compareandwrite_miscompare(void)
{
	int i, ret;
	unsigned j;
	unsigned char *buf = alloca(2 * 256 * block_size);

	CHECK_FOR_DATALOSS;
	CHECK_FOR_SBC;

	logging(LOG_VERBOSE, LOG_BLANK_LINE);
	logging(LOG_VERBOSE, "Test COMPARE_AND_WRITE of 1-256 blocks at the "
		"start of the LUN. One Byte miscompare in the final block.");
	for (i = 1; i < 256; i++) {
		logging(LOG_VERBOSE, "Write %d blocks of 'A' at LBA:0", i);
		memset(buf, 'A', 2 * i * block_size);
		if (maximum_transfer_length && maximum_transfer_length < i) {
			break;
		}
		ret = write16(iscsic, tgt_lun, 0, i * block_size,
		    block_size, 0, 0, 0, 0, 0, buf);
		if (ret == -2) {
			logging(LOG_NORMAL, "[SKIPPED] WRITE16 is not implemented.");
			CU_PASS("WRITE16 is not implemented.");
			return;
		}	
		CU_ASSERT_EQUAL(ret, 0);

		
		logging(LOG_VERBOSE, "Change byte 27 from the end to 'C' so that it does not match.");
		buf[i * block_size - 27] = 'C';


		memset(buf + i * block_size, 'B', i * block_size);

		logging(LOG_VERBOSE, "Overwrite %d blocks with 'B' "
			"at LBA:0 (if they all contain 'A')", i);
		ret = compareandwrite_miscompare(iscsic, tgt_lun, 0,
			buf, 2 * i * block_size, block_size, 0, 0, 0, 0);
		if (ret == -2) {
			CU_PASS("[SKIPPED] Target does not support "
				"COMPARE_AND_WRITE. Skipping test");
			return;
		}
		CU_ASSERT_EQUAL(ret, 0);

		logging(LOG_VERBOSE, "Read %d blocks at LBA:0 and verify "
			"they are still unchanged as 'A'", i);
		ret = read16(iscsic, tgt_lun, 0, i * block_size,
		    block_size, 0, 0, 0, 0, 0, buf);
		CU_ASSERT_EQUAL(ret, 0);

		for (j = 0; j < i * block_size; j++) {
			if (buf[j] != 'A') {
				logging(LOG_VERBOSE, "[FAILED] Data changed "
					"eventhough there was a miscompare");
				CU_FAIL("Block was written to");
				return;
			}
		}
	}


	logging(LOG_VERBOSE, "Test COMPARE_AND_WRITE of 1-256 blocks at the "
		"end of the LUN");
	for (i = 1; i < 256; i++) {
		logging(LOG_VERBOSE, "Write %d blocks of 'A' at LBA:%" PRIu64,
			i, num_blocks - i);
		memset(buf, 'A', 2 * i * block_size);
		if (maximum_transfer_length && maximum_transfer_length < i) {
			break;
		}
		ret = write16(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, "Change byte 27 from the end to 'C' so that it does not match.");
		buf[i * block_size - 27] = 'C';


		memset(buf + i * block_size, 'B', i * block_size);

		logging(LOG_VERBOSE, "Overwrite %d blocks with 'B' "
			"at LBA:%" PRIu64 " (if they all contain 'A')",
			i, num_blocks - i);
		ret = compareandwrite_miscompare(iscsic, tgt_lun,
			num_blocks - i,
			buf, 2 * i * block_size, block_size, 0, 0, 0, 0);
		CU_ASSERT_EQUAL(ret, 0);

		logging(LOG_VERBOSE, "Read %d blocks at LBA:%" PRIu64 
			"they are still unchanged as 'A'",
			i, num_blocks - i);
		ret = read16(iscsic, tgt_lun, num_blocks - i, i * block_size,
		    block_size, 0, 0, 0, 0, 0, buf);
		CU_ASSERT_EQUAL(ret, 0);

		for (j = 0; j < i * block_size; j++) {
			if (buf[j] != 'A') {
				logging(LOG_VERBOSE, "[FAILED] Data changed "
					"eventhough there was a miscompare");
				CU_FAIL("Block was written to");
				return;
			}
		}
	}
}