Remove the test for accessing 0blocks (transfer length==0) at the end of the device since they were invalid. SBC says that : If the LBA plus the transfer length exceeds the capacity of the medium, then the device server shall terminate the command with CHECK CONDITION status with the sense key set to ILLEGAL REQUEST and the additional sense code set to LOGICAL BLOCK ADDRESS OUT OF RANGE. This means that if TL==0 then a LBA that is the first LBA beyond the end of device is actually valid. Improve output for error conditions and harminize all tests
209 lines
6.3 KiB
C
209 lines
6.3 KiB
C
/*
|
|
Copyright (C) 2012 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include "iscsi.h"
|
|
#include "scsi-lowlevel.h"
|
|
#include "iscsi-test.h"
|
|
|
|
int T0233_write12_0blocks(const char *initiator, const char *url, int data_loss, int show_info)
|
|
{
|
|
struct iscsi_context *iscsi;
|
|
struct scsi_task *task;
|
|
struct scsi_readcapacity16 *rc16;
|
|
int ret = 0, lun;
|
|
uint32_t block_size;
|
|
uint64_t num_blocks;
|
|
|
|
printf("0233_write12_0blocks:\n");
|
|
printf("====================\n");
|
|
if (show_info) {
|
|
printf("Test that WRITE12 works correctly when transfer length is 0 blocks.\n");
|
|
printf("1, Write at LBA:0 should work.\n");
|
|
printf("2, Write at one block beyond end-of-lun should fail. (only on LUNs with less than 2^31 blocks)\n");
|
|
printf("3, Write at LBA:2^31 should fail (only on LUNs with less than 2^31 blocks).\n");
|
|
printf("4, Write at LBA:-1 should fail (only on LUNs with less than 2^31 blocks).\n");
|
|
printf("\n");
|
|
return 0;
|
|
}
|
|
|
|
iscsi = iscsi_context_login(initiator, url, &lun);
|
|
if (iscsi == NULL) {
|
|
printf("Failed to login to target\n");
|
|
return -1;
|
|
}
|
|
|
|
/* find the size of the LUN */
|
|
task = iscsi_readcapacity16_sync(iscsi, lun);
|
|
if (task == NULL) {
|
|
printf("Failed to send READCAPACITY16 command: %s\n", iscsi_get_error(iscsi));
|
|
ret = -1;
|
|
goto finished;
|
|
}
|
|
if (task->status != SCSI_STATUS_GOOD) {
|
|
printf("READCAPACITY16 command: failed with sense. %s\n", iscsi_get_error(iscsi));
|
|
ret = -1;
|
|
scsi_free_scsi_task(task);
|
|
goto finished;
|
|
}
|
|
rc16 = scsi_datain_unmarshall(task);
|
|
if (rc16 == NULL) {
|
|
printf("failed to unmarshall READCAPACITY16 data. %s\n", iscsi_get_error(iscsi));
|
|
ret = -1;
|
|
scsi_free_scsi_task(task);
|
|
goto finished;
|
|
}
|
|
|
|
block_size = rc16->block_length;
|
|
num_blocks = rc16->returned_lba;
|
|
scsi_free_scsi_task(task);
|
|
|
|
if (!data_loss) {
|
|
printf("--dataloss flag is not set. Skipping test\n");
|
|
ret = -2;
|
|
goto finished;
|
|
}
|
|
|
|
|
|
printf("WRITE12 0blocks at LBA:0 ... ");
|
|
task = iscsi_write12_sync(iscsi, lun, 0, NULL, 0, block_size, 0, 0, 0, 0, 0);
|
|
if (task == NULL) {
|
|
printf("[FAILED]\n");
|
|
printf("Failed to send WRITE12 command: %s\n", iscsi_get_error(iscsi));
|
|
ret = -1;
|
|
goto test2;
|
|
}
|
|
if (task->status != SCSI_STATUS_GOOD) {
|
|
printf("[FAILED]\n");
|
|
printf("WRITE12 command: failed with 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:
|
|
printf("WRITE12 0blocks at one block beyond <end-of-LUN> ... ");
|
|
if (num_blocks > 0x80000000) {
|
|
printf("[SKIPPED]\n");
|
|
printf("LUN is too big, skipping test\n");
|
|
goto test3;
|
|
}
|
|
task = iscsi_write12_sync(iscsi, lun, num_blocks + 1, NULL, 0, block_size, 0, 0, 0, 0, 0);
|
|
if (task == NULL) {
|
|
printf("[FAILED]\n");
|
|
printf("Failed to send WRITE12 command: %s\n", iscsi_get_error(iscsi));
|
|
ret = -1;
|
|
goto test3;
|
|
}
|
|
if (task->status == SCSI_STATUS_GOOD) {
|
|
printf("[FAILED]\n");
|
|
printf("WRITE12 command: Should fail when writing 0blocks beyond end\n");
|
|
ret = -1;
|
|
scsi_free_scsi_task(task);
|
|
goto test3;
|
|
}
|
|
if (task->status != SCSI_STATUS_CHECK_CONDITION
|
|
|| task->sense.key != SCSI_SENSE_ILLEGAL_REQUEST
|
|
|| task->sense.ascq != SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE) {
|
|
printf("[FAILED]\n");
|
|
printf("WRITE12 failed but ascq was wrong. Should have failed with ILLEGAL_REQUEST/LBA_OUT_OF_RANGE. Sense:%s\n", iscsi_get_error(iscsi));
|
|
ret = -1;
|
|
scsi_free_scsi_task(task);
|
|
goto test3;
|
|
}
|
|
scsi_free_scsi_task(task);
|
|
printf("[OK]\n");
|
|
|
|
test3:
|
|
printf("WRITE12 0blocks at LBA 2^31 ... ");
|
|
if (num_blocks > 0x80000000) {
|
|
printf("[SKIPPED]\n");
|
|
printf("LUN is too big, skipping test\n");
|
|
goto test4;
|
|
}
|
|
task = iscsi_write12_sync(iscsi, lun, 0x80000000, NULL, 0, block_size, 0, 0, 0, 0, 0);
|
|
if (task == NULL) {
|
|
printf("[FAILED]\n");
|
|
printf("Failed to send WRITE12 command: %s\n", iscsi_get_error(iscsi));
|
|
ret = -1;
|
|
goto test4;
|
|
}
|
|
if (task->status == SCSI_STATUS_GOOD) {
|
|
printf("[FAILED]\n");
|
|
printf("WRITE12 command: Should fail when writing 0blocks at 2^31\n");
|
|
ret = -1;
|
|
scsi_free_scsi_task(task);
|
|
goto test4;
|
|
}
|
|
if (task->status != SCSI_STATUS_CHECK_CONDITION
|
|
|| task->sense.key != SCSI_SENSE_ILLEGAL_REQUEST
|
|
|| task->sense.ascq != SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE) {
|
|
printf("[FAILED]\n");
|
|
printf("WRITE12 failed but ascq was wrong. Should have failed with ILLEGAL_REQUEST/LBA_OUT_OF_RANGE. Sense:%s\n", iscsi_get_error(iscsi));
|
|
ret = -1;
|
|
scsi_free_scsi_task(task);
|
|
goto test4;
|
|
}
|
|
scsi_free_scsi_task(task);
|
|
printf("[OK]\n");
|
|
|
|
|
|
test4:
|
|
printf("WRITE12 0blocks at LBA -1 ... ");
|
|
if (num_blocks > 0x80000000) {
|
|
printf("[SKIPPED]\n");
|
|
printf("LUN is too big, skipping test\n");
|
|
goto test5;
|
|
}
|
|
task = iscsi_write12_sync(iscsi, lun, -1, NULL, 0, block_size, 0, 0, 0, 0, 0);
|
|
if (task == NULL) {
|
|
printf("[FAILED]\n");
|
|
printf("Failed to send WRITE12 command: %s\n", iscsi_get_error(iscsi));
|
|
ret = -1;
|
|
goto test5;
|
|
}
|
|
if (task->status == SCSI_STATUS_GOOD) {
|
|
printf("[FAILED]\n");
|
|
printf("WRITE12 command: Should fail when writing 0blocks at -1\n");
|
|
ret = -1;
|
|
scsi_free_scsi_task(task);
|
|
goto test5;
|
|
}
|
|
if (task->status != SCSI_STATUS_CHECK_CONDITION
|
|
|| task->sense.key != SCSI_SENSE_ILLEGAL_REQUEST
|
|
|| task->sense.ascq != SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE) {
|
|
printf("[FAILED]\n");
|
|
printf("WRITE12 failed but ascq was wrong. Should have failed with ILLEGAL_REQUEST/LBA_OUT_OF_RANGE. Sense:%s\n", iscsi_get_error(iscsi));
|
|
ret = -1;
|
|
scsi_free_scsi_task(task);
|
|
goto test5;
|
|
}
|
|
scsi_free_scsi_task(task);
|
|
printf("[OK]\n");
|
|
|
|
|
|
test5:
|
|
|
|
finished:
|
|
iscsi_logout_sync(iscsi);
|
|
iscsi_destroy_context(iscsi);
|
|
return ret;
|
|
}
|