void
test_inquiry_block_limits(void)
{
	int ret;
	struct scsi_inquiry_block_limits *bl;
	struct scsi_task *bl_task = NULL;
	struct scsi_inquiry_logical_block_provisioning *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);
	if (ret != 0) {
		logging(LOG_NORMAL, "[FAILURE] failed to send inquiry.");
		goto finished;
	}

	bl = scsi_datain_unmarshall(bl_task);
	if (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");
	} else {
		logging(LOG_VERBOSE, "Device is not SBC-3. Verify that "
			"PageLength == 0x0C (but allow 0x3C too. Some SBC-2 "
			"devices support some SBC-3 features.");
	}
	switch (bl_task->datain.data[3]) {
	case 0x3c:
		/* accept 0x3c (==SBC-3) for all levels */
		if (!sbc3_support) {
			logging(LOG_NORMAL, "[WARNING] SBC-3 pagelength (0x3C) "
				"returned but SBC-3 support was not claimed "
				"in the standard inquiry page.");
		}
		break;
	case 0x0c:
		/* only accept 0x0c for levels < SBC-3 */
		if (!sbc3_support) {
			break;
		}
		/* fallthrough */
	default:
		CU_FAIL("[FAILED] Invalid pagelength returned");
		logging(LOG_NORMAL, "[FAILURE] Invalid PageLength returned.");
	}


	if (bl_task->datain.data[3] != 0x3c) {
		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) {
		lbp = scsi_datain_unmarshall(lbp_task);
		if (lbp == NULL) {
			logging(LOG_NORMAL, "[FAILURE] failed to unmarshall "
			"inquiry datain blob.");
		}
	}

	if (lbp && 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(bl->max_unmap, 0);

		logging(LOG_VERBOSE, "Verify that MAXIMUM UNMAP LBA COUNT is "
			"at least 2^LBPPBE");
		CU_ASSERT_EQUAL(bl->max_unmap >= (1U << rc16->lbppbe), 1);

		if (bl->max_unmap != 0xffffffff) {
			logging(LOG_VERBOSE, "Verify that MAXIMUM UNMAP LBA "
				"COUNT is not insanely big");
			CU_ASSERT_TRUE(bl->max_unmap <= 1024*1024);
		}

		logging(LOG_VERBOSE, "Verify that MAXIMUM UNMAP BLOCK "
			"DESCRIPTOR COUNT is not 0");
		CU_ASSERT_NOT_EQUAL(bl->max_unmap_bdc, 0);
		if (bl->max_unmap_bdc != 0xffffffff) {
			logging(LOG_VERBOSE, "Verify that MAXIMUM UNMAP "
				"BLOCK DESCRIPTOR COUNT is not insanely big");
			CU_ASSERT_TRUE(bl->max_unmap_bdc <= 1024*1024);
		}
	} 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(bl->max_unmap, 0);

		logging(LOG_VERBOSE, "Verify that MAXIMUM UNMAP BLOCK "
			"DESCRIPTOR COUNT is 0");
		CU_ASSERT_EQUAL(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);
	}
}
Exemple #2
0
void test_canon_x(void)
{
	CALC_ELEMENT *t1;
	double a, b;
	/* addition x + a * x */
	t1 = create_bin_op('+', create_x(),
			   create_bin_op('*', create_number(2.5), create_x()));
	CU_ASSERT_EQUAL(canonical_form(&t1), 0);
	CU_ASSERT_EQUAL(t1->calc_t, CALC_X);
	CU_ASSERT_EQUAL(t1->status, STATUS_X_PRESENT);
	CU_ASSERT_EQUAL(t1->value, 3.5);
	free_calc_element(t1);

	/* addition a * x + b */
	t1 = create_bin_op('+',
			   create_bin_op('*', create_number(1.25), create_x()),
			   create_number(14));
	CU_ASSERT_EQUAL(canonical_form(&t1), 0);
	CU_ASSERT_EQUAL(t1->calc_t, CALC_BIN_OP);
	CU_ASSERT_EQUAL(t1->status, STATUS_X_PRESENT);
	CU_ASSERT_EQUAL(get_ax_b(t1, &a, &b), 0);
	CU_ASSERT_EQUAL(a, 1.25);
	CU_ASSERT_EQUAL(b, 14);
	free_calc_element(t1);

	/* addition a * x + b + c */
	t1 = create_bin_op('+',
			   create_bin_op('+',
					 create_bin_op('*', create_number(0.75),
						       create_x()),
					 create_number(6)),
			   create_number(-3.5));
	CU_ASSERT_EQUAL(canonical_form(&t1), 0);
	CU_ASSERT_EQUAL(t1->calc_t, CALC_BIN_OP);
	CU_ASSERT_EQUAL(t1->status, STATUS_X_PRESENT);
	CU_ASSERT_EQUAL(get_ax_b(t1, &a, &b), 0);
	CU_ASSERT_EQUAL(a, 0.75);
	CU_ASSERT_EQUAL(b, 2.5);
	free_calc_element(t1);

	/* addition (a1 * x + b1) + (a2 * x + b2) */
	t1 = create_bin_op('+', create_ax_b(9.0, -1.25), create_ax_b(2.0, 6.5));
	CU_ASSERT_EQUAL(canonical_form(&t1), 0);
	CU_ASSERT_EQUAL(t1->calc_t, CALC_BIN_OP);
	CU_ASSERT_EQUAL(t1->status, STATUS_X_PRESENT);
	CU_ASSERT_EQUAL(get_ax_b(t1, &a, &b), 0);
	CU_ASSERT_EQUAL(a, 11.0);
	CU_ASSERT_EQUAL(b, 5.25);
	free_calc_element(t1);

	/* multiplication a * x */
	t1 = create_bin_op('*', create_x(), create_number(-9.0));
	CU_ASSERT_EQUAL(canonical_form(&t1), 0);
	CU_ASSERT_EQUAL(t1->calc_t, CALC_X);
	CU_ASSERT_EQUAL(t1->status, STATUS_X_PRESENT);
	CU_ASSERT_EQUAL(get_ax_b(t1, &a, &b), 0);
	CU_ASSERT_EQUAL(a, -9.0);
	CU_ASSERT_EQUAL(b, 0);
	free_calc_element(t1);

	/* multiplication x * a */
	t1 = create_bin_op('*', create_number(7.5), create_x());
	CU_ASSERT_EQUAL(canonical_form(&t1), 0);
	CU_ASSERT_EQUAL(t1->calc_t, CALC_X);
	CU_ASSERT_EQUAL(t1->status, STATUS_X_PRESENT);
	CU_ASSERT_EQUAL(get_ax_b(t1, &a, &b), 0);
	CU_ASSERT_EQUAL(a, 7.5);
	CU_ASSERT_EQUAL(b, 0);
	free_calc_element(t1);

	/* multiplication c * (a * x + b) */
	t1 = create_bin_op('*', create_number(19), create_ax_b(4, -0.5));
	CU_ASSERT_EQUAL(canonical_form(&t1), 0);
	CU_ASSERT_EQUAL(t1->calc_t, CALC_BIN_OP);
	CU_ASSERT_EQUAL(t1->status, STATUS_X_PRESENT);
	CU_ASSERT_EQUAL(get_ax_b(t1, &a, &b), 0);
	CU_ASSERT_EQUAL(a, 76);
	CU_ASSERT_EQUAL(b, -9.5);
	free_calc_element(t1);

	/* multiplication (a * x + b) * c */
	t1 = create_bin_op('*', create_ax_b(-6, 4.5), create_number(0.5));
	CU_ASSERT_EQUAL(canonical_form(&t1), 0);
	CU_ASSERT_EQUAL(t1->calc_t, CALC_BIN_OP);
	CU_ASSERT_EQUAL(t1->status, STATUS_X_PRESENT);
	CU_ASSERT_EQUAL(get_ax_b(t1, &a, &b), 0);
	CU_ASSERT_EQUAL(a, -3.0);
	CU_ASSERT_EQUAL(b, 2.25);
	free_calc_element(t1);

	/* multiplication x * x */
	t1 = create_bin_op('*', create_x(), create_x());
	CU_ASSERT_NOT_EQUAL(canonical_form(&t1), 0);
	CU_ASSERT_EQUAL(t1->calc_t, CALC_BIN_OP);
	CU_ASSERT_EQUAL(t1->status, STATUS_X_NON_LINEAR | STATUS_X_PRESENT);
	free_calc_element(t1);

	/* multiplication x * (a * x + b) */
	t1 = create_bin_op('*', create_x(), create_x());
	CU_ASSERT_NOT_EQUAL(canonical_form(&t1), 0);
	CU_ASSERT_EQUAL(t1->calc_t, CALC_BIN_OP);
	CU_ASSERT_EQUAL(t1->status, STATUS_X_NON_LINEAR | STATUS_X_PRESENT);
	free_calc_element(t1);

	/* multiplication (2*x - (2*x - 3)) * (3x - 4) - false square, actually linear */
	t1 = create_bin_op('*', create_bin_op('-', create_ax_b(2.0, 0.0),
					      create_ax_b(2, -3)),
			   create_ax_b(3.0, -4.0));
	CU_ASSERT_EQUAL(canonical_form(&t1), 0);
	CU_ASSERT_EQUAL(t1->calc_t, CALC_BIN_OP);
	CU_ASSERT_EQUAL(get_ax_b(t1, &a, &b), 0);
	CU_ASSERT_EQUAL(a, 9.0);
	CU_ASSERT_EQUAL(b, -12.0);
	free_calc_element(t1);

	/* division x / a */
	t1 = create_bin_op('/', create_x(), create_number(2.0));
	CU_ASSERT_NOT_EQUAL(canonical_form(&t1), 0);
	CU_ASSERT_EQUAL(t1->calc_t, CALC_BIN_OP);
	CU_ASSERT_EQUAL(t1->status, STATUS_X_IN_DIV | STATUS_X_PRESENT);
	free_calc_element(t1);

	/* log (ax + b) */
	t1 = create_log(create_ax_b(9.0, -3.0));
	CU_ASSERT_NOT_EQUAL(canonical_form(&t1), 0);
	CU_ASSERT_EQUAL(t1->calc_t, CALC_LOG);
	CU_ASSERT_EQUAL(t1->status, STATUS_X_IN_LOG | STATUS_X_PRESENT);
	free_calc_element(t1);
}
Exemple #3
0
void test_parser(void)
{
	CALC_ELEMENT *e1 = NULL, *e2 = NULL;
	double a, b;
	strcpy(in_line, "(3+(4-1))*5");
	line_len = 11;
	CU_ASSERT_EQUAL(parse_line(&e1, &e2), 0);
	CU_ASSERT_PTR_NOT_NULL(e1);
	CU_ASSERT_PTR_NULL(e2);
	CU_ASSERT_EQUAL(canonical_form(&e1), 0);
	CU_ASSERT_EQUAL(e1->calc_t, CALC_NUM);
	CU_ASSERT_EQUAL(e1->value, 30);
	free_calc_element(e1);
	clear_line();
	e1 = NULL;
	e2 = NULL;

	strcpy(in_line, "2 * x + 0.5 = 1");
	line_len = 15;
	CU_ASSERT_EQUAL(parse_line(&e1, &e2), 0);
	CU_ASSERT_PTR_NOT_NULL(e1);
	CU_ASSERT_PTR_NOT_NULL(e2);
	CU_ASSERT_EQUAL(canonical_form(&e1), 0);
	CU_ASSERT_EQUAL(canonical_form(&e2), 0);
	CU_ASSERT_EQUAL(get_ax_b(e1, &a, &b), 0);
	CU_ASSERT_EQUAL(a, 2);
	CU_ASSERT_EQUAL(b, 0.5);
	CU_ASSERT_EQUAL(e2->calc_t, CALC_NUM);
	CU_ASSERT_EQUAL(e2->value, 1);
	free_calc_element(e1);
	free_calc_element(e2);
	clear_line();
	e1 = NULL;
	e2 = NULL;

	strcpy(in_line, "2x + 1 = 2(1-x)");
	line_len = 15;
	CU_ASSERT_EQUAL(parse_line(&e1, &e2), 0);
	CU_ASSERT_PTR_NOT_NULL(e1);
	CU_ASSERT_PTR_NOT_NULL(e2);
	CU_ASSERT_EQUAL(canonical_form(&e1), 0);
	CU_ASSERT_EQUAL(canonical_form(&e2), 0);
	CU_ASSERT_EQUAL(get_ax_b(e1, &a, &b), 0);
	CU_ASSERT_EQUAL(a, 2);
	CU_ASSERT_EQUAL(b, 1);
	CU_ASSERT_EQUAL(get_ax_b(e2, &a, &b), 0);
	CU_ASSERT_EQUAL(a, -2);
	CU_ASSERT_EQUAL(b, 2);
	free_calc_element(e1);
	free_calc_element(e2);
	clear_line();
	e1 = NULL;
	e2 = NULL;

	strcpy(in_line, "14.9 + 1 - 2 3.44");
	line_len = 17;
	CU_ASSERT_NOT_EQUAL(parse_line(&e1, &e2), 0);
	clear_line();
	e1 = NULL;
	e2 = NULL;

	strcpy(in_line, "((12)");
	line_len = 5;
	CU_ASSERT_NOT_EQUAL(parse_line(&e1, &e2), 0);
	clear_line();
	e1 = NULL;
	e2 = NULL;

	strcpy(in_line, "3x + -");
	line_len = 6;
	CU_ASSERT_NOT_EQUAL(parse_line(&e1, &e2), 0);
	clear_line();
	e1 = NULL;
	e2 = NULL;

	strcpy(in_line, "60/5/3*8/4");
	line_len = 10;
	CU_ASSERT_EQUAL(parse_line(&e1, &e2), 0);
	CU_ASSERT_EQUAL(canonical_form(&e1), 0);
	CU_ASSERT_EQUAL(e1->calc_t, CALC_NUM);
	CU_ASSERT_EQUAL(e1->value, 8);
	free_calc_element(e1);
	clear_line();
	e1 = NULL;
	e2 = NULL;

	/* log torturing */
	strcpy(in_line, "log 5)");
	line_len = 6;
	CU_ASSERT_NOT_EQUAL(parse_line(&e1, &e2), 0);
	clear_line();
	e1 = NULL;
	e2 = NULL;

	strcpy(in_line, "log(9 ");
	line_len = 6;
	CU_ASSERT_NOT_EQUAL(parse_line(&e1, &e2), 0);
	clear_line();
	e1 = NULL;
	e2 = NULL;

	strcpy(in_line, "leg(9)");
	line_len = 6;
	CU_ASSERT_NOT_EQUAL(parse_line(&e1, &e2), 0);
	clear_line();
	e1 = NULL;
	e2 = NULL;

	strcpy(in_line, "(2x - 2x + 6) * 4x = 12");
	line_len = 23;
	CU_ASSERT_EQUAL(parse_line(&e1, &e2), 0);
	CU_ASSERT_EQUAL(canonical_form(&e1), 0);
	CU_ASSERT_EQUAL(get_ax_b(e1, &a, &b), 0);
	CU_ASSERT_EQUAL(a, 24);
	CU_ASSERT_EQUAL(b, 0);
	clear_line();
	free_calc_element(e1);
	free_calc_element(e2);
	e1 = NULL;
	e2 = NULL;
}
Exemple #4
0
static void testAircraftHandling (void)
{
	const vec2_t destination = { 10, 10 };
	campaign_t *campaign;
	base_t *base;
	aircraft_t *aircraft;
	aircraft_t *newAircraft;
	aircraft_t *aircraftTemplate;
	int firstIdx;
	int initialCount;
	int count;
	int newFound;

	ResetCampaignData();

	campaign = GetCampaign();

	base = CreateBase("unittestaircraft", destination);
	CU_ASSERT_PTR_NOT_NULL_FATAL(base);

	/** @todo we should not assume that initial base has aircraft. It's a campaign parameter */
	aircraft = AIR_GetFirstFromBase(base);
	CU_ASSERT_PTR_NOT_NULL_FATAL(aircraft);

	/* aircraft should have a template */
	aircraftTemplate = aircraft->tpl;
	CU_ASSERT_PTR_NOT_NULL_FATAL(aircraftTemplate);

	firstIdx = aircraft->idx;
	initialCount = AIR_BaseCountAircraft(base);

	/* test deletion (part 1) */
	AIR_DeleteAircraft(aircraft);
	count = AIR_BaseCountAircraft(base);
	CU_ASSERT_EQUAL(count, initialCount - 1);

	/* test addition (part 1) */
	newAircraft = AIR_NewAircraft(base, aircraftTemplate);
	CU_ASSERT_PTR_NOT_NULL_FATAL(newAircraft);
	count = AIR_BaseCountAircraft(base);
	CU_ASSERT_EQUAL(count, initialCount);

	/* new aircraft assigned to the right base */
	CU_ASSERT_EQUAL(newAircraft->homebase, base);

	newFound = 0;
	AIR_Foreach(aircraft) {
		/* test deletion (part 2) */
		CU_ASSERT_NOT_EQUAL(firstIdx, aircraft->idx);
		/* for test addition (part 2) */
		if (aircraft->idx == newAircraft->idx)
			newFound++;
	}
	/* test addition (part 2) */
	CU_ASSERT_EQUAL(newFound, 1);

	/* check if AIR_Foreach iterates through all aircraft */
	AIR_Foreach(aircraft) {
		AIR_DeleteAircraft(aircraft);
	}
	aircraft = AIR_GetFirstFromBase(base);
	CU_ASSERT_PTR_NULL_FATAL(aircraft);
	count = AIR_BaseCountAircraft(base);
	CU_ASSERT_EQUAL(count, 0);

	/* cleanup for the following tests */
	E_DeleteAllEmployees(NULL);

	base->founded = qfalse;
}
static void
test_ofp_packet_input_forwarding_to_output(void)
{
    odp_packet_t pkt;
    odp_event_t ev;
    int res;

    /* Call ofp_packet_input using a pkt with destination ip
     * that does NOT match the local ip on ifnet and a route is found.
     * ARP is found for gateway IP.
     * Function returns OFP_PKT_PROCESSED and
     * packet is forwarded to ofp_ip_output.*/
    unsigned char ll_addr[13] = "123456789012";

    my_test_val = TEST_FORWARD_HOOK;

    CU_ASSERT_EQUAL(
        ofp_ipv4_lookup_mac(dst_ipaddr + 1, ll_addr, ifnet), -1);
    CU_ASSERT_EQUAL(
        ofp_arp_ipv4_insert(dst_ipaddr + 1, ll_addr, ifnet), 0);

    if (create_odp_packet_ip4(&pkt, test_frame, sizeof(test_frame),
                              dst_ipaddr, 0)) {
        CU_FAIL("Fail to create packet");
        return;
    }

    res = ofp_packet_input(pkt, interface_queue[port],
                           ofp_eth_vlan_processing);
    CU_ASSERT_EQUAL(res, OFP_PKT_PROCESSED);
    CU_ASSERT_NOT_EQUAL(ev = odp_queue_deq(ifnet->outq_def),
                        ODP_EVENT_INVALID);
    CU_ASSERT_EQUAL(odp_queue_deq(ifnet->outq_def), ODP_EVENT_INVALID);

#ifdef SP
    CU_ASSERT_EQUAL(odp_queue_deq(ifnet->spq_def), ODP_EVENT_INVALID);
#endif /* SP */

    CU_ASSERT_EQUAL(odp_packet_len(pkt), sizeof(test_frame));

    pkt = odp_packet_from_event(ev);
    struct ofp_ip *ip_in_pkt_data =
        (struct ofp_ip *)(in_pkt_data + OFP_ETHER_HDR_LEN);
    ip_in_pkt_data->ip_ttl--;

#ifdef OFP_PERFORMANCE
    /*checksum is not filled on ip_output*/
    ip_in_pkt_data->ip_sum =
        ((struct ofp_ip *)odp_packet_l3_ptr(pkt, NULL))->ip_sum;
#else
    ip_in_pkt_data->ip_sum = 0;
    ip_in_pkt_data->ip_sum = ofp_cksum_buffer((uint16_t *)ip_in_pkt_data,
                             ip_in_pkt_data->ip_hl<<2);

#endif

    if (memcmp((uint8_t *)odp_packet_data(pkt) + odp_packet_l3_offset(pkt),
               in_pkt_data + OFP_ETHER_HDR_LEN,
               sizeof(test_frame) - OFP_ETHER_HDR_LEN))
        CU_FAIL("corrupt l3 + data forwarded");
    struct ofp_ether_header *eth =
        (struct ofp_ether_header *)odp_packet_l2_ptr(pkt, NULL);

    if (memcmp(eth->ether_dhost, ll_addr, OFP_ETHER_ADDR_LEN))
        CU_FAIL("Bad destination mac address on the forwarded packet");
    CU_ASSERT_EQUAL(eth->ether_type, odp_cpu_to_be_16(OFP_ETHERTYPE_IP));

    CU_PASS("ofp_packet_input_forwarding_to_output");
}
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;
                }
        }
}
Exemple #7
0
/*
 * caller need create/release:
 * pm4_src, resources, ib_info, and ibs_request
 * submit command stream described in ibs_request and wait for this IB accomplished
 */
static void amdgpu_test_exec_cs_helper(amdgpu_context_handle context_handle,
				       unsigned ip_type,
				       int instance, int pm4_dw, uint32_t *pm4_src,
				       int res_cnt, amdgpu_bo_handle *resources,
				       struct amdgpu_cs_ib_info *ib_info,
				       struct amdgpu_cs_request *ibs_request)
{
	int r;
	uint32_t expired;
	uint32_t *ring_ptr;
	amdgpu_bo_handle ib_result_handle;
	void *ib_result_cpu;
	uint64_t ib_result_mc_address;
	struct amdgpu_cs_fence fence_status = {0};
	amdgpu_bo_handle *all_res = alloca(sizeof(resources[0]) * (res_cnt + 1));
	amdgpu_va_handle va_handle;

	/* prepare CS */
	CU_ASSERT_NOT_EQUAL(pm4_src, NULL);
	CU_ASSERT_NOT_EQUAL(resources, NULL);
	CU_ASSERT_NOT_EQUAL(ib_info, NULL);
	CU_ASSERT_NOT_EQUAL(ibs_request, NULL);
	CU_ASSERT_TRUE(pm4_dw <= 1024);

	/* allocate IB */
	r = amdgpu_bo_alloc_and_map(device_handle, 4096, 4096,
				    AMDGPU_GEM_DOMAIN_GTT, 0,
				    &ib_result_handle, &ib_result_cpu,
				    &ib_result_mc_address, &va_handle);
	CU_ASSERT_EQUAL(r, 0);

	/* copy PM4 packet to ring from caller */
	ring_ptr = ib_result_cpu;
	memcpy(ring_ptr, pm4_src, pm4_dw * sizeof(*pm4_src));

	ib_info->ib_mc_address = ib_result_mc_address;
	ib_info->size = pm4_dw;

	ibs_request->ip_type = ip_type;
	ibs_request->ring = instance;
	ibs_request->number_of_ibs = 1;
	ibs_request->ibs = ib_info;
	ibs_request->fence_info.handle = NULL;

	memcpy(all_res, resources, sizeof(resources[0]) * res_cnt);
	all_res[res_cnt] = ib_result_handle;

	r = amdgpu_bo_list_create(device_handle, res_cnt+1, all_res,
				  NULL, &ibs_request->resources);
	CU_ASSERT_EQUAL(r, 0);

	CU_ASSERT_NOT_EQUAL(ibs_request, NULL);

	/* submit CS */
	r = amdgpu_cs_submit(context_handle, 0, ibs_request, 1);
	CU_ASSERT_EQUAL(r, 0);

	r = amdgpu_bo_list_destroy(ibs_request->resources);
	CU_ASSERT_EQUAL(r, 0);

	fence_status.ip_type = ip_type;
	fence_status.ring = ibs_request->ring;
	fence_status.context = context_handle;
	fence_status.fence = ibs_request->seq_no;

	/* wait for IB accomplished */
	r = amdgpu_cs_query_fence_status(&fence_status,
					 AMDGPU_TIMEOUT_INFINITE,
					 0, &expired);
	CU_ASSERT_EQUAL(r, 0);
	CU_ASSERT_EQUAL(expired, true);

	r = amdgpu_bo_unmap_and_free(ib_result_handle, va_handle,
				     ib_result_mc_address, 4096);
	CU_ASSERT_EQUAL(r, 0);
}
void
test_prout_clear_simple(void)
{
        int ret = 0;
        uint32_t old_gen;
        const unsigned long long key = rand_key();
        struct scsi_task *tsk;
        struct scsi_persistent_reserve_in_read_keys *rk = NULL;

        CHECK_FOR_DATALOSS;

        logging(LOG_VERBOSE, LOG_BLANK_LINE);
        logging(LOG_VERBOSE, "Test Persistent Reserve OUT CLEAR works.");

        /* register our reservation key with the target */
        ret = prout_register_and_ignore(sd, key);
        if (ret == -2) {
                CU_PASS("PERSISTENT RESERVE OUT is not implemented.");
                return;
        }
        CU_ASSERT_EQUAL(ret, 0);

        ret = prin_read_keys(sd, &tsk, &rk, 16384);
        CU_ASSERT_EQUAL(ret, 0);
        CU_ASSERT_NOT_EQUAL(rk, NULL);
        if (!rk)
                goto out;

        CU_ASSERT_NOT_EQUAL(rk->num_keys, 0);
        /* retain PR generation number to check for increments */
        old_gen = rk->prgeneration;

        scsi_free_scsi_task(tsk);
        rk = NULL;        /* freed with tsk */

        /* reserve the target */
        ret = prout_reserve(sd, key,
                            SCSI_PERSISTENT_RESERVE_TYPE_EXCLUSIVE_ACCESS);
        CU_ASSERT_EQUAL(ret, 0);

        /* verify target reservation */
        ret = prin_verify_reserved_as(sd, key,
                                SCSI_PERSISTENT_RESERVE_TYPE_EXCLUSIVE_ACCESS);
        CU_ASSERT_EQUAL(ret, 0);

        /* clear reservation and registration */
        ret = prout_clear(sd, key);
        CU_ASSERT_EQUAL(ret, 0);

        ret = prin_verify_not_reserved(sd);
        CU_ASSERT_EQUAL(ret, 0);

        ret = prin_read_keys(sd, &tsk, &rk, 16384);
        CU_ASSERT_EQUAL(ret, 0);
        CU_ASSERT_NOT_EQUAL(rk, NULL);
        if (!rk)
                goto out;

        CU_ASSERT_EQUAL(rk->num_keys, 0);
        /* generation incremented once for CLEAR (not for RESERVE) */
        CU_ASSERT_EQUAL(rk->prgeneration, old_gen + 1);

out:
        scsi_free_scsi_task(tsk);
        rk = NULL;        /* freed with tsk */
}
static void testSRC_MSG_UAD_INIT(void)
{
	fd_set rfds;
	int ret;
	struct my_uad_src src;
	bool loop = true;
	struct timeval timeout;

	ret = io_src_msg_uad_init(&(src.uad_src), uad_cb, &(src.msg),
			sizeof(src.msg), "my_cool_socket_name_%d", 42);
	CU_ASSERT_EQUAL(ret, 0);

	ret = io_mon_init(&mon);
	CU_ASSERT_EQUAL(ret, 0);
	ret = io_mon_add_source(&mon, &(src.uad_src.src_msg.src));
	CU_ASSERT_EQUAL(ret, 0);

	ret = io_mon_activate_out_source(&mon, &(src.uad_src.src_msg.src), 1);
	CU_ASSERT_EQUAL(ret, 0);

	/* normal use cases */
	while (loop) {
		/* restore the timer */
		timeout.tv_sec = 1;
		timeout.tv_usec = 0;

		/* restore the read file descriptor set */
		FD_ZERO(&rfds);
		FD_SET(mon.epollfd, &rfds);
		ret = select(mon.epollfd + 1, &rfds, NULL, NULL, &timeout);

		/* error, not normal */
		CU_ASSERT_NOT_EQUAL(ret, -1);
		if (-1 == ret)
			goto out;

		/* timeout, not normal */
		CU_ASSERT_NOT_EQUAL(ret, 0);
		if (0 == ret)
			goto out;

		ret = io_mon_process_events(&mon);
		CU_ASSERT(ret >= 0);
		if (ret < 0)
			goto out;

		loop = STATE_ALL_DONE != state;
	}

out:
	/* cleanup */
	io_mon_clean(&mon);
	io_src_msg_uad_clean(&(src.uad_src));

	/* debriefeing */
	CU_ASSERT(state & STATE_MSG1_SENT);
	CU_ASSERT(state & STATE_MSG1_RECEIVED);
	CU_ASSERT(state & STATE_MSG2_SENT);
	CU_ASSERT(state & STATE_MSG2_RECEIVED);

	/* error use cases */
}
Exemple #10
0
void
test_verify16_dpo(void)
{ 
	int ret, dpofua, usage_data_dpo;
	struct scsi_task *ms_task = NULL;
	struct scsi_mode_sense *ms;
	struct scsi_task *rso_task = NULL;
	struct scsi_report_supported_op_codes_one_command *rsoc;
	unsigned char *buf = alloca(block_size);

	logging(LOG_VERBOSE, LOG_BLANK_LINE);
	logging(LOG_VERBOSE, "Test VERIFY16 DPO flag");

	CHECK_FOR_SBC;

	ret = read10(sd, NULL, 0, block_size,
		     block_size, 0, 0, 0, 0, 0, buf,
		     EXPECT_STATUS_GOOD);
	CU_ASSERT_EQUAL(ret, 0);

	logging(LOG_VERBOSE, "Read the DPOFUA flag from mode sense data");
	ret = modesense6(sd, &ms_task, 0, SCSI_MODESENSE_PC_CURRENT,
			 SCSI_MODEPAGE_RETURN_ALL_PAGES, 0, 255,
			 EXPECT_STATUS_GOOD);
	CU_ASSERT_EQUAL(ret, 0);
	logging(LOG_VERBOSE, "[SUCCESS] Mode sense returned status GOOD");
	ms = scsi_datain_unmarshall(ms_task);
	dpofua = ms && (ms->device_specific_parameter & 0x10);
	scsi_free_scsi_task(ms_task);

	if (dpofua) {
		logging(LOG_VERBOSE, "DPOFUA flag is set. Device should allow "
			"DPO/FUA flags in CDBs");
	} else {
		logging(LOG_VERBOSE, "DPOFUA flag is clear. Device should fail "
			"CDBs with DPO/FUA set");
	}

	logging(LOG_VERBOSE, "Test VERIFY16 with DPO==1");
	if (dpofua) {
		ret = verify16(sd, 0, block_size,
			       block_size, 0, 1, 0, buf,
			       EXPECT_STATUS_GOOD);
		if (ret == -2) {
			logging(LOG_NORMAL, "[SKIPPED] VERIFY16 is not implemented.");
			CU_PASS("VERIFY16 is not implemented.");
			return;
		}
		CU_ASSERT_EQUAL(ret, 0);
	} else {
		ret = verify16(sd, 0, block_size,
			       block_size, 0, 1, 0, buf,
			       EXPECT_INVALID_FIELD_IN_CDB);
		if (ret == -2) {
			logging(LOG_NORMAL, "[SKIPPED] VERIFY16 is not implemented.");
			CU_PASS("VERIFY16 is not implemented.");
			return;
		}
		CU_ASSERT_EQUAL(ret, 0);
	}

	logging(LOG_VERBOSE, "Try fetching REPORT_SUPPORTED_OPCODES "
		"for VERIFY16");
	ret = report_supported_opcodes(sd, &rso_task,
				       0, SCSI_REPORT_SUPPORTING_OPCODE,
				       SCSI_OPCODE_VERIFY16,
				       0,
				       65535,
				       EXPECT_STATUS_GOOD);
	if (ret == -2) {
		logging(LOG_NORMAL, "REPORT_SUPPORTED_OPCODES not implemented. "
			"Skipping this part of the test");
		return;
	}
	logging(LOG_VERBOSE, "Unmarshall the DATA-IN buffer");
	rsoc = scsi_datain_unmarshall(rso_task);
	CU_ASSERT_NOT_EQUAL(rsoc, NULL);
	usage_data_dpo = rsoc ? rsoc->cdb_usage_data[1] & 0x10 : -1;
	if (dpofua) {
		logging(LOG_VERBOSE, "DPOFUA is set. Verify the DPO flag "
			"is set in the CDB_USAGE_DATA");
		CU_ASSERT_EQUAL(usage_data_dpo, 0x10);
	} else {
		logging(LOG_VERBOSE, "DPOFUA is clear. Verify the DPO "
			"flag is clear in the CDB_USAGE_DATA");
		CU_ASSERT_EQUAL(usage_data_dpo, 0x00);
	}
	scsi_free_scsi_task(rso_task);
}