diff --git a/Makefile.am b/Makefile.am index 37f6e1e..7aeb549 100644 --- a/Makefile.am +++ b/Makefile.am @@ -189,11 +189,12 @@ bin_iscsi_test_cu_SOURCES = test-tool/iscsi-test-cu.c \ test-tool/iscsi-support.c \ test-tool/test_get_lba_status_simple.c \ test-tool/test_get_lba_status_beyond_eol.c \ - test-tool/test_inquiry_standard.c \ test-tool/test_inquiry_alloc_length.c \ + test-tool/test_inquiry_block_limits.c \ test-tool/test_inquiry_evpd.c \ - test-tool/test_inquiry_supported_vpd.c \ test-tool/test_inquiry_mandatory_vpd_sbc.c \ + test-tool/test_inquiry_standard.c \ + test-tool/test_inquiry_supported_vpd.c \ test-tool/test_inquiry_version_descriptors.c \ test-tool/test_iscsi_cmdsn_toohigh.c \ test-tool/test_iscsi_cmdsn_toolow.c \ diff --git a/test-tool/iscsi-test-cu.c b/test-tool/iscsi-test-cu.c index 8e527c5..69dd257 100644 --- a/test-tool/iscsi-test-cu.c +++ b/test-tool/iscsi-test-cu.c @@ -70,8 +70,9 @@ static CU_TestInfo tests_inquiry[] = { { (char *)"InquiryStandard", test_inquiry_standard }, { (char *)"InquiryAllocLength", test_inquiry_alloc_length}, { (char *)"InquiryEVPD", test_inquiry_evpd}, - { (char *)"InquirySupportedVPD", test_inquiry_supported_vpd}, + { (char *)"InquiryBlockLimits", test_inquiry_block_limits}, { (char *)"InquiryMandatoryVPDSBC", test_inquiry_mandatory_vpd_sbc}, + { (char *)"InquirySupportedVPD", test_inquiry_supported_vpd}, { (char *)"InquiryVersionDescriptors", test_inquiry_version_descriptors}, CU_TEST_INFO_NULL }; diff --git a/test-tool/iscsi-test-cu.h b/test-tool/iscsi-test-cu.h index d3d8d05..3c64d8d 100644 --- a/test-tool/iscsi-test-cu.h +++ b/test-tool/iscsi-test-cu.h @@ -43,11 +43,12 @@ int test_teardown_pgr(void); void test_get_lba_status_simple(void); void test_get_lba_status_beyond_eol(void); -void test_inquiry_standard(void); void test_inquiry_alloc_length(void); +void test_inquiry_block_limits(void); void test_inquiry_evpd(void); -void test_inquiry_supported_vpd(void); void test_inquiry_mandatory_vpd_sbc(void); +void test_inquiry_standard(void); +void test_inquiry_supported_vpd(void); void test_inquiry_version_descriptors(void); void test_iscsi_cmdsn_toohigh(void); diff --git a/test-tool/test_inquiry_block_limits.c b/test-tool/test_inquiry_block_limits.c new file mode 100644 index 0000000..7e26460 --- /dev/null +++ b/test-tool/test_inquiry_block_limits.c @@ -0,0 +1,159 @@ +/* + Copyright (C) 2013 by Ronnie Sahlberg + + 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 . +*/ + +#include + +#include + +#include "iscsi.h" +#include "scsi-lowlevel.h" +#include "iscsi-support.h" +#include "iscsi-test-cu.h" + +void +test_inquiry_block_limits(void) +{ + int ret, expected_pl; + struct scsi_inquiry_block_limits *inq_bl; + struct scsi_task *bl_task = NULL; + struct scsi_inquiry_logical_block_provisioning *inq_lbp = NULL; + struct scsi_task *lbp_task = NULL; + + logging(LOG_VERBOSE, LOG_BLANK_LINE); + logging(LOG_VERBOSE, "Test of the INQUIRY Block Limits"); + + CHECK_FOR_SBC; + + logging(LOG_VERBOSE, "Block device. Verify that we can read Block Limits VPD"); + ret = inquiry(iscsic, tgt_lun, + 1, SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS, + 64, &bl_task); + CU_ASSERT_EQUAL(ret, 0); + + inq_bl = scsi_datain_unmarshall(bl_task); + if (inq_bl == NULL) { + logging(LOG_NORMAL, "[FAILURE] failed to unmarshall inquiry " + "datain blob."); + CU_FAIL("[FAILURE] failed to unmarshall inquiry " + "datain blob."); + goto finished; + } + + logging(LOG_VERBOSE, "Verify that the PageLength matches up with the size of the DATA-IN buffer."); + CU_ASSERT_EQUAL(bl_task->datain.size, bl_task->datain.data[3] + 4); + if (bl_task->datain.size != bl_task->datain.data[3] + 4) { + logging(LOG_NORMAL, "[FAILURE] Invalid PageLength returned. " + "Was %d but expected %d", + bl_task->datain.data[3], bl_task->datain.size - 4); + } else { + logging(LOG_VERBOSE, "[SUCCESS] PageLength matches DataIn buffer size"); + } + + logging(LOG_VERBOSE, "Verify that the PageLength matches SCSI-level."); + /* if it is not SBC3 then we assume it must be SBC2 */ + if (sbc3_support) { + logging(LOG_VERBOSE, "Device claims SBC-3. Verify that " "PageLength == 0x3C"); + expected_pl = 0x3c; + } else { + logging(LOG_VERBOSE, "Device is not SBC-3. Verify that " + "PageLength == 0x0C"); + expected_pl = 0x0c; + } + CU_ASSERT_EQUAL(bl_task->datain.data[3], expected_pl); + if (bl_task->datain.data[3] != expected_pl) { + logging(LOG_NORMAL, "[FAILURE] Invalid PageLength returned. " + "Was %d but expected %d", + bl_task->datain.data[3], expected_pl); + } else { + logging(LOG_VERBOSE, "[SUCCESS] PageLength matches SCSI SBC " + "level"); + } + + if (!sbc3_support) { + goto finished; + } + + + /* + * MAXIMUM UNMAP LBA COUNT + * MAXIMUM UNMAP BLOCK DESCRIPTOR COUNT + */ + logging(LOG_VERBOSE, "Try reading the logical block provisioning VPD"); + ret = inquiry(iscsic, tgt_lun, + 1, SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING, + 64, &lbp_task); + if (ret == 0) { + inq_lbp = scsi_datain_unmarshall(lbp_task); + if (inq_lbp == NULL) { + logging(LOG_NORMAL, "[FAILURE] failed to unmarshall " + "inquiry datain blob."); + } + } + + if (inq_lbp && inq_lbp->lbpu) { + /* We support UNMAP so MAXIMUM UNMAP LBA COUNT and + * MAXIMUM UNMAP BLOCK DESCRIPTOR COUNT. + * They must be > 0. + * It can be 0xffffffff which means no limit, but if there is + * an explicit limit set, then we check that it looks sane. + * Sane here means < 1M. + */ + 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); + + 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); + + if (inq_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); + } + + 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) { + 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); + } + } 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); + + logging(LOG_VERBOSE, "Verify that MAXIMUM UNMAP BLOCK " + "DESCRIPTOR COUNT is 0"); + CU_ASSERT_EQUAL(inq_bl->max_unmap_bdc, 0); + } + + + +finished: + if (bl_task != NULL) { + scsi_free_scsi_task(bl_task); + } + if (lbp_task != NULL) { + scsi_free_scsi_task(lbp_task); + } +}