void test_writeverify10_residuals(void) { struct scsi_task *task_ret; unsigned char buf[10000]; struct iscsi_data data; int ok; unsigned int i; logging(LOG_VERBOSE, LOG_BLANK_LINE); logging(LOG_VERBOSE, "Test WRITEVERIFY10 commands with residuals"); logging(LOG_VERBOSE, "Block size is %zu", block_size); CHECK_FOR_DATALOSS; CHECK_FOR_SBC; if (sd->iscsi_ctx == NULL) { const char *err = "[SKIPPED] This WRITEVERIFY10 test is only " "supported for iSCSI backends"; logging(LOG_NORMAL, "%s", err); CU_PASS(err); return; } /* check if writeverify10 is supported */ WRITEVERIFY10(sd, 0, 0, block_size, 0, 0, 0, 0, NULL, EXPECT_STATUS_GOOD); /* Try a writeverify10 of 1 block but xferlength == 0 */ task = malloc(sizeof(struct scsi_task)); CU_ASSERT_PTR_NOT_NULL_FATAL(task); memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_WRITE_VERIFY10; task->cdb[1] = 2; /* BYTCHK = 1 */ task->cdb[8] = 1; task->cdb_size = 10; task->xfer_dir = SCSI_XFER_WRITE; task->expxferlen = 0; /* * we don't want autoreconnect since some targets will drop the session * on this condition. */ iscsi_set_noautoreconnect(sd->iscsi_ctx, 1); logging(LOG_VERBOSE, "Try writing one block but with iSCSI expected transfer length==0"); task_ret = iscsi_scsi_command_sync(sd->iscsi_ctx, sd->iscsi_lun, task, NULL); CU_ASSERT_PTR_NOT_NULL_FATAL(task_ret); CU_ASSERT_NOT_EQUAL(task->status, SCSI_STATUS_CANCELLED); /* XXX redundant? */ if (task->status == SCSI_STATUS_CHECK_CONDITION && task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST && task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE) { logging(LOG_NORMAL, "[SKIPPED] WRITEVERIFY10 is not implemented."); CU_PASS("WRITEVERIFY10 is not implemented."); return; } logging(LOG_VERBOSE, "Verify that the target returned SUCCESS"); if (task->status != SCSI_STATUS_GOOD) { logging(LOG_VERBOSE, "[FAILED] Target returned error %s", iscsi_get_error(sd->iscsi_ctx)); } CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); logging(LOG_VERBOSE, "Verify residual overflow flag is set"); if (task->residual_status != SCSI_RESIDUAL_OVERFLOW) { logging(LOG_VERBOSE, "[FAILED] Target did not set residual " "overflow flag"); } CU_ASSERT_EQUAL(task->residual_status, SCSI_RESIDUAL_OVERFLOW); logging(LOG_VERBOSE, "Verify we got %zu bytes of residual overflow", block_size); if (task->residual != block_size) { logging(LOG_VERBOSE, "[FAILED] Target did not set correct " "amount of residual. Expected %zu but got %zu.", block_size, task->residual); } CU_ASSERT_EQUAL(task->residual, block_size); scsi_free_scsi_task(task); task = NULL; /* in case the previous test failed the session */ iscsi_set_noautoreconnect(sd->iscsi_ctx, 0); logging(LOG_VERBOSE, "Try writing one block but with iSCSI expected transfer length==10000"); task = malloc(sizeof(struct scsi_task)); CU_ASSERT_PTR_NOT_NULL_FATAL(task); memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_WRITE_VERIFY10; task->cdb[1] = 2; /* BYTCHK = 1 */ task->cdb[8] = 1; task->cdb_size = 10; task->xfer_dir = SCSI_XFER_WRITE; task->expxferlen = 10000; memset(buf, 0xa6, sizeof(buf)); data.size = task->expxferlen; data.data = &buf[0]; task_ret = iscsi_scsi_command_sync(sd->iscsi_ctx, sd->iscsi_lun, task, &data); CU_ASSERT_PTR_NOT_NULL_FATAL(task_ret); logging(LOG_VERBOSE, "Verify that the target returned SUCCESS"); if (task->status != SCSI_STATUS_GOOD) { logging(LOG_VERBOSE, "[FAILED] Target returned error %s", iscsi_get_error(sd->iscsi_ctx)); } CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); logging(LOG_VERBOSE, "Verify residual underflow flag is set"); if (task->residual_status != SCSI_RESIDUAL_UNDERFLOW) { logging(LOG_VERBOSE, "[FAILED] Target did not set residual " "underflow flag"); } CU_ASSERT_EQUAL(task->residual_status, SCSI_RESIDUAL_UNDERFLOW); logging(LOG_VERBOSE, "Verify we got %zu bytes of residual underflow", 10000 - block_size); if (task->residual != 10000 - block_size) { logging(LOG_VERBOSE, "[FAILED] Target did not set correct " "amount of residual. Expected %zu but got %zu.", 10000 - block_size, task->residual); } CU_ASSERT_EQUAL(task->residual, 10000 - block_size); scsi_free_scsi_task(task); task = NULL; logging(LOG_VERBOSE, "Try writing one block but with iSCSI expected transfer length==200"); task = malloc(sizeof(struct scsi_task)); CU_ASSERT_PTR_NOT_NULL_FATAL(task); memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_WRITE_VERIFY10; task->cdb[1] = 2; /* BYTCHK = 1 */ task->cdb[8] = 1; task->cdb_size = 10; task->xfer_dir = SCSI_XFER_WRITE; task->expxferlen = 200; data.size = task->expxferlen; data.data = &buf[0]; task_ret = iscsi_scsi_command_sync(sd->iscsi_ctx, sd->iscsi_lun, task, &data); CU_ASSERT_PTR_NOT_NULL_FATAL(task_ret); logging(LOG_VERBOSE, "Verify that the target returned SUCCESS"); ok = task->status == SCSI_STATUS_GOOD || (task->status == SCSI_STATUS_CHECK_CONDITION && task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST && task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_FIELD_IN_INFORMATION_UNIT); if (!ok) { logging(LOG_VERBOSE, "[FAILED] Target returned error %s", iscsi_get_error(sd->iscsi_ctx)); } CU_ASSERT(ok); logging(LOG_VERBOSE, "Verify residual overflow flag is set"); if (task->residual_status != SCSI_RESIDUAL_OVERFLOW) { logging(LOG_VERBOSE, "[FAILED] Target did not set residual " "overflow flag"); } CU_ASSERT_EQUAL(task->residual_status, SCSI_RESIDUAL_OVERFLOW); logging(LOG_VERBOSE, "Verify we got %zu bytes of residual overflow", block_size - 200); if (task->residual != block_size - 200) { logging(LOG_VERBOSE, "[FAILED] Target did not set correct " "amount of residual. Expected %zu but got %zu.", block_size - 200, task->residual); } CU_ASSERT_EQUAL(task->residual, block_size - 200); scsi_free_scsi_task(task); task = NULL; logging(LOG_VERBOSE, "Try writing two blocks but iSCSI expected " "transfer length==%zu (==one block)", block_size); task = malloc(sizeof(struct scsi_task)); CU_ASSERT_PTR_NOT_NULL_FATAL(task); memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_WRITE_VERIFY10; task->cdb[1] = 2; /* BYTCHK = 1 */ task->cdb[8] = 2; task->cdb_size = 10; task->xfer_dir = SCSI_XFER_WRITE; task->expxferlen = block_size; data.size = task->expxferlen; data.data = &buf[0]; task_ret = iscsi_scsi_command_sync(sd->iscsi_ctx, sd->iscsi_lun, task, &data); CU_ASSERT_PTR_NOT_NULL_FATAL(task_ret); logging(LOG_VERBOSE, "Verify that the target returned SUCCESS"); if (task->status != SCSI_STATUS_GOOD) { logging(LOG_VERBOSE, "[FAILED] Target returned error %s", iscsi_get_error(sd->iscsi_ctx)); } CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); logging(LOG_VERBOSE, "Verify residual overflow flag is set"); if (task->residual_status != SCSI_RESIDUAL_OVERFLOW) { logging(LOG_VERBOSE, "[FAILED] Target did not set residual " "overflow flag"); } CU_ASSERT_EQUAL(task->residual_status, SCSI_RESIDUAL_OVERFLOW); logging(LOG_VERBOSE, "Verify we got one block of residual overflow"); if (task->residual != block_size) { logging(LOG_VERBOSE, "[FAILED] Target did not set correct " "amount of residual. Expected %zu but got %zu.", block_size, task->residual); } CU_ASSERT_EQUAL(task->residual, block_size); scsi_free_scsi_task(task); task = NULL; logging(LOG_VERBOSE, "Verify that if iSCSI EDTL > SCSI TL then we only write SCSI TL amount of data"); logging(LOG_VERBOSE, "Write two blocks of 'a'"); memset(buf, 'a', 10000); WRITE10(sd, 0, 2 * block_size, block_size, 0, 0, 0, 0, 0, buf, EXPECT_STATUS_GOOD); logging(LOG_VERBOSE, "Write one block of 'b' but set iSCSI EDTL to 2 blocks."); task = malloc(sizeof(struct scsi_task)); CU_ASSERT_PTR_NOT_NULL_FATAL(task); memset(buf, 'b', 10000); memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_WRITE_VERIFY10; task->cdb[1] = 2; /* BYTCHK = 1 */ task->cdb[8] = 1; task->cdb_size = 10; task->xfer_dir = SCSI_XFER_WRITE; task->expxferlen = 2 * block_size; data.size = task->expxferlen; data.data = &buf[0]; task_ret = iscsi_scsi_command_sync(sd->iscsi_ctx, sd->iscsi_lun, task, &data); CU_ASSERT_PTR_NOT_NULL_FATAL(task_ret); logging(LOG_VERBOSE, "Verify that the target returned SUCCESS"); if (task->status != SCSI_STATUS_GOOD) { logging(LOG_VERBOSE, "[FAILED] Target returned error %s", iscsi_get_error(sd->iscsi_ctx)); } CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); logging(LOG_VERBOSE, "Verify residual underflow flag is set"); if (task->residual_status != SCSI_RESIDUAL_UNDERFLOW) { logging(LOG_VERBOSE, "[FAILED] Target did not set residual " "underflow flag"); } CU_ASSERT_EQUAL(task->residual_status, SCSI_RESIDUAL_UNDERFLOW); logging(LOG_VERBOSE, "Verify we got one block of residual underflow"); if (task->residual != block_size) { logging(LOG_VERBOSE, "[FAILED] Target did not set correct " "amount of residual. Expected %zu but got %zu.", block_size, task->residual); } CU_ASSERT_EQUAL(task->residual, block_size); scsi_free_scsi_task(task); task = NULL; logging(LOG_VERBOSE, "Read the two blocks"); READ10(sd, NULL, 0, 2* block_size, block_size, 0, 0, 0, 0, 0, buf, EXPECT_STATUS_GOOD); logging(LOG_VERBOSE, "Verify that the first block was changed to 'b'"); for (i = 0; i < block_size; i++) { if (buf[i] != 'b') { logging(LOG_NORMAL, "First block did not contain expected 'b'"); CU_FAIL("Block was not written correctly"); break; } } logging(LOG_VERBOSE, "Verify that the second block was NOT overwritten and still contains 'a'"); for (i = block_size; i < 2 * block_size; i++) { if (buf[i] != 'a') { logging(LOG_NORMAL, "Second block was overwritten and no longer contain 'a'"); CU_FAIL("Second block was incorrectly overwritten"); break; } } logging(LOG_VERBOSE, "Verify that if iSCSI EDTL < SCSI TL then we only write iSCSI EDTL amount of data"); logging(LOG_VERBOSE, "Write two blocks of 'a'"); memset(buf, 'a', 10000); WRITE10(sd, 0, 2 * block_size, block_size, 0, 0, 0, 0, 0, buf, EXPECT_STATUS_GOOD); logging(LOG_VERBOSE, "Write two blocks of 'b' but set iSCSI EDTL to 1 blocks."); task = malloc(sizeof(struct scsi_task)); CU_ASSERT_PTR_NOT_NULL_FATAL(task); memset(buf, 'b', 10000); memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_WRITE_VERIFY10; task->cdb[1] = 2; /* BYTCHK = 1 */ task->cdb[8] = 2; task->cdb_size = 10; task->xfer_dir = SCSI_XFER_WRITE; task->expxferlen = block_size; data.size = task->expxferlen; data.data = &buf[0]; task_ret = iscsi_scsi_command_sync(sd->iscsi_ctx, sd->iscsi_lun, task, &data); CU_ASSERT_PTR_NOT_NULL_FATAL(task_ret); logging(LOG_VERBOSE, "Verify that the target returned SUCCESS"); if (task->status != SCSI_STATUS_GOOD) { logging(LOG_VERBOSE, "[FAILED] Target returned error %s", iscsi_get_error(sd->iscsi_ctx)); } CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); logging(LOG_VERBOSE, "Verify residual overflow flag is set"); if (task->residual_status != SCSI_RESIDUAL_OVERFLOW) { logging(LOG_VERBOSE, "[FAILED] Target did not set residual " "overflow flag"); } CU_ASSERT_EQUAL(task->residual_status, SCSI_RESIDUAL_OVERFLOW); logging(LOG_VERBOSE, "Verify we got one block of residual overflow"); if (task->residual != block_size) { logging(LOG_VERBOSE, "[FAILED] Target did not set correct " "amount of residual. Expected %zu but got %zu.", block_size, task->residual); } CU_ASSERT_EQUAL(task->residual, block_size); scsi_free_scsi_task(task); task = NULL; logging(LOG_VERBOSE, "Read the two blocks"); READ10(sd, NULL, 0, 2* block_size, block_size, 0, 0, 0, 0, 0, buf, EXPECT_STATUS_GOOD); logging(LOG_VERBOSE, "Verify that the first block was changed to 'b'"); for (i = 0; i < block_size; i++) { if (buf[i] != 'b') { logging(LOG_NORMAL, "First block did not contain expected 'b'"); CU_FAIL("Block was not written correctly"); break; } } logging(LOG_VERBOSE, "Verify that the second block was NOT overwritten and still contains 'a'"); for (i = block_size; i < 2 * block_size; i++) { if (buf[i] != 'a') { logging(LOG_NORMAL, "Second block was overwritten and no longer contain 'a'"); CU_FAIL("Second block was incorrectly overwritten"); break; } } }
int T0103_read10_rdprotect(const char *initiator, const char *url, int data_loss _U_, int show_info) { struct iscsi_context *iscsi; struct scsi_task *task; int full_size; struct scsi_inquiry_standard *inq; int ret, i, lun; printf("0103_read10_rdprotect:\n"); printf("======================\n"); if (show_info) { printf("Test how READ10 handles the rdprotect bits\n"); printf("1, Any non-zero valued for rdprotect should fail.\n"); printf("\n"); return 0; } iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* See how big this inquiry data is */ task = iscsi_inquiry_sync(iscsi, lun, 0, 0, 64); if (task == NULL || task->status != SCSI_STATUS_GOOD) { printf("Inquiry command failed : %s\n", iscsi_get_error(iscsi)); return -1; } full_size = scsi_datain_getfullsize(task); if (full_size > task->datain.size) { scsi_free_scsi_task(task); /* we need more data for the full list */ if ((task = iscsi_inquiry_sync(iscsi, lun, 0, 0, full_size)) == NULL) { printf("Inquiry command failed : %s\n", iscsi_get_error(iscsi)); return -1; } } inq = scsi_datain_unmarshall(task); if (inq == NULL) { printf("failed to unmarshall inquiry datain blob\n"); scsi_free_scsi_task(task); return -1; } if (inq->periperal_device_type != SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS) { printf("LUN is not SBC device. Skipping test\n"); scsi_free_scsi_task(task); return -1; } if (inq->protect) { printf("LUN is formatted with protection information. Skipping test\n"); scsi_free_scsi_task(task); return -1; } scsi_free_scsi_task(task); ret = 0; /* Try out Different non-zero values for RDPROTECT. They should all fail */ printf("Read10 with non-zero RDPROTECT ... "); for (i = 1; i < 8; i++) { task = malloc(sizeof(struct scsi_task)); if (task == NULL) { printf("Failed to allocate task structure\n"); ret = -1; goto finished; } memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_READ10; task->cdb[1] = (i<<5)&0xe0; task->cdb[8] = 1; task->cdb_size = 10; task->xfer_dir = SCSI_XFER_READ; task->expxferlen = 512; if (iscsi_scsi_command_sync(iscsi, lun, task, NULL) == NULL) { printf("[FAILED]\n"); printf("Failed to send read10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } if (task->status != SCSI_STATUS_CHECK_CONDITION || task->sense.key != SCSI_SENSE_ILLEGAL_REQUEST || task->sense.ascq != SCSI_SENSE_ASCQ_INVALID_FIELD_IN_CDB) { printf("[FAILED]\n"); printf("Read10 with rdprotect should fail with ILLEGAL REQUEST/INVALID OPCODE\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); } printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; }
int T0161_readcapacity16_alloclen(const char *initiator, const char *url, int data_loss _U_, int show_info) { struct iscsi_context *iscsi; struct scsi_task *task; struct iscsi_data data; int ret, lun; printf("0161_readcapacity16_alloclen:\n"); printf("=======================\n"); if (show_info) { printf("Test allocation-length for READCAPACITY16\n"); printf("1, Readcapacity with alloclen==0 is not an error\n"); printf("\n"); return 0; } iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } ret = 0; printf("READCAPACITY16 with AllocationLength==0 ... "); task = malloc(sizeof(struct scsi_task)); if (task == NULL) { printf("Failed to allocate task structure\n"); ret = -1; goto finished; } memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = 0x9e; task->cdb[1] = 0x10; task->cdb_size = 16; task->xfer_dir = SCSI_XFER_NONE; task->expxferlen = 0; if (iscsi_scsi_command_sync(iscsi, lun, task, NULL) == NULL) { printf("[FAILED]\n"); printf("Failed to send READCAPACITY16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto test2; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("READCAPACITY16 with AllocationLength==0 should not fail. Sense:%s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto test2; } scsi_free_scsi_task(task); printf("[OK]\n"); test2: finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; }