diff --git a/include/scsi-lowlevel.h b/include/scsi-lowlevel.h index 1b7d6ed..a1e9a22 100644 --- a/include/scsi-lowlevel.h +++ b/include/scsi-lowlevel.h @@ -145,6 +145,7 @@ enum scsi_sense_key { EXTERN const char *scsi_sense_key_str(int key); /* ascq */ +#define SCSI_SENSE_ASCQ_WRITE_AFTER_SANITIZE_REQUIRED 0x1115 #define SCSI_SENSE_ASCQ_MISCOMPARE_DURING_VERIFY 0x1d00 #define SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE 0x2000 #define SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE 0x2100 diff --git a/lib/scsi-lowlevel.c b/lib/scsi-lowlevel.c index 37f41d5..db689ee 100644 --- a/lib/scsi-lowlevel.c +++ b/lib/scsi-lowlevel.c @@ -145,6 +145,8 @@ const char * scsi_sense_ascq_str(int ascq) { struct value_string ascqs[] = { + {SCSI_SENSE_ASCQ_WRITE_AFTER_SANITIZE_REQUIRED, + "WRITE_AFTER_SANITIZE_REQUIRED"}, {SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE, "INVALID_OPERATION_CODE"}, {SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE, diff --git a/test-tool/test_sanitize_block_erase.c b/test-tool/test_sanitize_block_erase.c index ce1d389..30b42f1 100644 --- a/test-tool/test_sanitize_block_erase.c +++ b/test-tool/test_sanitize_block_erase.c @@ -26,6 +26,85 @@ #include "scsi-lowlevel.h" #include "iscsi-test-cu.h" +static void +check_wabereq(void) +{ + struct scsi_task *task_ret; + + logging(LOG_VERBOSE, "Read one block from LBA 0"); + task_ret = malloc(sizeof(struct scsi_task)); + CU_ASSERT_PTR_NOT_NULL(task_ret); + memset(task_ret, 0, sizeof(struct scsi_task)); + task_ret->cdb[0] = SCSI_OPCODE_READ10; + task_ret->cdb[8] = 1; + task_ret->cdb_size = 10; + task_ret->xfer_dir = SCSI_XFER_READ; + task_ret->expxferlen = 0; + task_ret = iscsi_scsi_command_sync(iscsic, tgt_lun, task_ret, NULL); + CU_ASSERT_PTR_NOT_NULL(task_ret); + CU_ASSERT_NOT_EQUAL(task_ret->status, SCSI_STATUS_CANCELLED); + + switch (inq_bdc->wabereq) { + case 0: + logging(LOG_NORMAL, "[FAILED] SANITIZE BLOCK ERASE " + "opcode is supported but WABEREQ is 0"); + CU_FAIL("[FAILED] SANITIZE BLOCK ERASE " + "opcode is supported but WABEREQ is 0"); + break; + case 1: + logging(LOG_VERBOSE, "WABEREQ==1. Reads from the " + "device should be successful."); + if (task_ret->status == SCSI_STATUS_GOOD) { + logging(LOG_VERBOSE, "[SUCCESS] Read was " + "successful after SANITIZE"); + break; + } + logging(LOG_NORMAL, "[FAILED] Read after " + "SANITIZE failed but WABEREQ is 1"); + CU_FAIL("[FAILED] Read after SANITIZE failed " + "but WABEREQ is 1"); + break; + case 2: + logging(LOG_VERBOSE, "WABEREQ==2. Reads from the " + "device should fail."); + if (task_ret->status == SCSI_STATUS_CHECK_CONDITION + && task_ret->sense.key == SCSI_SENSE_MEDIUM_ERROR + && task_ret->sense.ascq != SCSI_SENSE_ASCQ_WRITE_AFTER_SANITIZE_REQUIRED) { + logging(LOG_VERBOSE, "[SUCCESS] Read failed " + "with CHECK_CONDITION/MEDIUM_ERROR/" + "!WRITE_AFTER_SANITIZE_REQUIRED"); + break; + } + logging(LOG_VERBOSE, "[FAILED] Read should have failed " + "with CHECK_CONDITION/MEDIUM_ERROR/" + "!WRITE_AFTER_SANITIZE_REQUIRED"); + CU_FAIL("[FAILED] Read should have failed " + "with CHECK_CONDITION/MEDIUM_ERROR/" + "!WRITE_AFTER_SANITIZE_REQUIRED"); + break; + case 3: + logging(LOG_VERBOSE, "WABEREQ==3. Reads from the " + "device should fail."); + if (task_ret->status == SCSI_STATUS_CHECK_CONDITION + && task_ret->sense.key == SCSI_SENSE_MEDIUM_ERROR + && task_ret->sense.ascq == SCSI_SENSE_ASCQ_WRITE_AFTER_SANITIZE_REQUIRED) { + logging(LOG_VERBOSE, "[SUCCESS] Read failed " + "with CHECK_CONDITION/MEDIUM_ERROR/" + "WRITE_AFTER_SANITIZE_REQUIRED"); + break; + } + logging(LOG_VERBOSE, "[FAILED] Read should have failed " + "with CHECK_CONDITION/MEDIUM_ERROR/" + "WRITE_AFTER_SANITIZE_REQUIRED"); + CU_FAIL("[FAILED] Read should have failed " + "with CHECK_CONDITION/MEDIUM_ERROR/" + "WRITE_AFTER_SANITIZE_REQUIRED"); + break; + } + + scsi_free_scsi_task(task_ret); +} + void test_sanitize_block_erase(void) { @@ -81,14 +160,6 @@ test_sanitize_block_erase(void) logging(LOG_NORMAL, "This is a HDD device"); } - logging(LOG_VERBOSE, "Verify that WABEREQ is specified"); - if (inq_bdc && !inq_bdc->wabereq) { - logging(LOG_NORMAL, "[FAILED] SANITIZE BLOCK ERASE " - "opcode is supported but WABEREQ is 0"); - CU_FAIL("[FAILED] SANITIZE BLOCK ERASE " - "opcode is supported but WABEREQ is 0"); - } - logging(LOG_VERBOSE, "Test we can perform basic BLOCK ERASE SANITIZE"); ret = sanitize(iscsic, tgt_lun, @@ -105,4 +176,10 @@ test_sanitize_block_erase(void) ret = sanitize_invalidfieldincdb(iscsic, tgt_lun, 0, 0, SCSI_SANITIZE_BLOCK_ERASE, 8, &data); CU_ASSERT_EQUAL(ret, 0); + + if (inq_bdc) { + logging(LOG_VERBOSE, "Check WABEREQ setting and that READ " + "after SANITIZE works correctly."); + check_wabereq(); + } } diff --git a/test-tool/test_sanitize_crypto_erase.c b/test-tool/test_sanitize_crypto_erase.c index 33609b3..3592bf6 100644 --- a/test-tool/test_sanitize_crypto_erase.c +++ b/test-tool/test_sanitize_crypto_erase.c @@ -26,6 +26,85 @@ #include "scsi-lowlevel.h" #include "iscsi-test-cu.h" +static void +check_wacereq(void) +{ + struct scsi_task *task_ret; + + logging(LOG_VERBOSE, "Read one block from LBA 0"); + task_ret = malloc(sizeof(struct scsi_task)); + CU_ASSERT_PTR_NOT_NULL(task_ret); + memset(task_ret, 0, sizeof(struct scsi_task)); + task_ret->cdb[0] = SCSI_OPCODE_READ10; + task_ret->cdb[8] = 1; + task_ret->cdb_size = 10; + task_ret->xfer_dir = SCSI_XFER_READ; + task_ret->expxferlen = 0; + task_ret = iscsi_scsi_command_sync(iscsic, tgt_lun, task_ret, NULL); + CU_ASSERT_PTR_NOT_NULL(task_ret); + CU_ASSERT_NOT_EQUAL(task_ret->status, SCSI_STATUS_CANCELLED); + + switch (inq_bdc->wabereq) { + case 0: + logging(LOG_NORMAL, "[FAILED] SANITIZE BLOCK ERASE " + "opcode is supported but WACEREQ is 0"); + CU_FAIL("[FAILED] SANITIZE BLOCK ERASE " + "opcode is supported but WACEREQ is 0"); + break; + case 1: + logging(LOG_VERBOSE, "WACEREQ==1. Reads from the " + "device should be successful."); + if (task_ret->status == SCSI_STATUS_GOOD) { + logging(LOG_VERBOSE, "[SUCCESS] Read was " + "successful after SANITIZE"); + break; + } + logging(LOG_NORMAL, "[FAILED] Read after " + "SANITIZE failed but WACEREQ is 1"); + CU_FAIL("[FAILED] Read after SANITIZE failed " + "but WACEREQ is 1"); + break; + case 2: + logging(LOG_VERBOSE, "WACEREQ==2. Reads from the " + "device should fail."); + if (task_ret->status == SCSI_STATUS_CHECK_CONDITION + && task_ret->sense.key == SCSI_SENSE_MEDIUM_ERROR + && task_ret->sense.ascq != SCSI_SENSE_ASCQ_WRITE_AFTER_SANITIZE_REQUIRED) { + logging(LOG_VERBOSE, "[SUCCESS] Read failed " + "with CHECK_CONDITION/MEDIUM_ERROR/" + "!WRITE_AFTER_SANITIZE_REQUIRED"); + break; + } + logging(LOG_VERBOSE, "[FAILED] Read should have failed " + "with CHECK_CONDITION/MEDIUM_ERROR/" + "!WRITE_AFTER_SANITIZE_REQUIRED"); + CU_FAIL("[FAILED] Read should have failed " + "with CHECK_CONDITION/MEDIUM_ERROR/" + "!WRITE_AFTER_SANITIZE_REQUIRED"); + break; + case 3: + logging(LOG_VERBOSE, "WACEREQ==3. Reads from the " + "device should fail."); + if (task_ret->status == SCSI_STATUS_CHECK_CONDITION + && task_ret->sense.key == SCSI_SENSE_MEDIUM_ERROR + && task_ret->sense.ascq == SCSI_SENSE_ASCQ_WRITE_AFTER_SANITIZE_REQUIRED) { + logging(LOG_VERBOSE, "[SUCCESS] Read failed " + "with CHECK_CONDITION/MEDIUM_ERROR/" + "WRITE_AFTER_SANITIZE_REQUIRED"); + break; + } + logging(LOG_VERBOSE, "[FAILED] Read should have failed " + "with CHECK_CONDITION/MEDIUM_ERROR/" + "WRITE_AFTER_SANITIZE_REQUIRED"); + CU_FAIL("[FAILED] Read should have failed " + "with CHECK_CONDITION/MEDIUM_ERROR/" + "WRITE_AFTER_SANITIZE_REQUIRED"); + break; + } + + scsi_free_scsi_task(task_ret); +} + void test_sanitize_crypto_erase(void) { @@ -49,6 +128,23 @@ test_sanitize_crypto_erase(void) return; } + logging(LOG_VERBOSE, "Verify that we have BlockDeviceCharacteristics " + "VPD page."); + if (inq_bdc == NULL) { + logging(LOG_NORMAL, "[FAILED] SANITIZE CRYPTO ERASE opcode is " + "supported but BlockDeviceCharacteristics VPD page is " + "missing"); + CU_FAIL("[FAILED] BlockDeviceCharacteristics VPD " + "page is missing"); + } + + + logging(LOG_VERBOSE, "Test we can perform basic CRYPTO ERASE SANITIZE"); + ret = sanitize(iscsic, tgt_lun, + 0, 0, SCSI_SANITIZE_CRYPTO_ERASE, 0, NULL); + CU_ASSERT_EQUAL(ret, 0); + + data.size = 8; data.data = alloca(data.size); memset(data.data, 0, data.size); @@ -59,4 +155,10 @@ test_sanitize_crypto_erase(void) ret = sanitize_invalidfieldincdb(iscsic, tgt_lun, 0, 0, SCSI_SANITIZE_CRYPTO_ERASE, 8, &data); CU_ASSERT_EQUAL(ret, 0); + + if (inq_bdc) { + logging(LOG_VERBOSE, "Check WACEREQ setting and that READ " + "after SANITIZE works correctly."); + check_wacereq(); + } }