static int fbo_emulate_get_configuration(struct tcmu_device *dev, uint8_t *cdb,
					 struct iovec *iovec, size_t iov_cnt,
					 uint8_t *sense)
{
	struct fbo_state *state = tcmu_get_dev_private(dev);
	uint8_t rt = cdb[1] & 0x03;
	uint16_t start = be16toh(*(uint16_t *)&cdb[2]);
	int used_len;
	uint8_t *cur;
	uint8_t buf[512];

	/* Reserved value for RT */
	if (rt == 3)
		return tcmu_set_sense_data(sense, ILLEGAL_REQUEST,
					   ASC_INVALID_FIELD_IN_CDB, NULL);

	memset(buf, 0, sizeof(buf));

	/* Set current profile in the feature header */
	if (state->flags & FBO_READ_ONLY)
		*(uint16_t *)&buf[6] = htobe16(0x10);	// DVD-ROM
	else
		*(uint16_t *)&buf[6] = htobe16(0x12);	// DVD-RAM

	/* Feature header */
	used_len = 8;

	/* Profile List Feature */
	if ((rt == 2 && start == 0x0000) ||
	    (start <= 0x0000 && (rt == 0 || rt == 1))) {
		cur = &buf[used_len];
		*(uint16_t *)&cur[0] = htobe16(0x0000);
		cur[2] = 3;		// persistent=1, current=1
		cur[3] = 16;		// # of profile descriptors * 4

		*(uint16_t *)&cur[4] = htobe16(0x12);	// DVD-RAM Profile
		if (!(state->flags & FBO_READ_ONLY))
			cur[6] = 1;			// active profile

		*(uint16_t *)&cur[8] = htobe16(0x10);	// DVD-ROM Profile
		if (state->flags & FBO_READ_ONLY)
			cur[10] = 1;			// active profile

		*(uint16_t *)&cur[12] = htobe16(0x0a);	// CD-RW Profile

		*(uint16_t *)&cur[16] = htobe16(0x08);	// CD-ROM Profile

		used_len += 20;
	}

	/* Core Feature */
	if ((rt == 2 && start == 0x0001) ||
	    (start <= 0x0001 && (rt == 0 || rt == 1))) {
		cur = &buf[used_len];
		*(uint16_t *)&cur[0] = htobe16(0x0001);
		cur[2] = 7;	// version=1, persistent=1, current=1
		cur[3] = 8;	// additional length

		/* SCSI Physical Interface Standard */
		*(uint32_t *)&cur[4] = htobe32(1);
		cur[8] = 1;	// Device Busy Event

		used_len += 12;
	}

	/* Morphing Feature */
	if ((rt == 2 && start == 0x0002) ||
	    (start <= 0x0002 && (rt == 0 || rt == 1))) {
		cur = &buf[used_len];
		*(uint16_t *)&cur[0] = htobe16(0x0002);
		cur[2] = 7;	// version=1, persistent=1, current=1
		cur[3] = 4;	// additional length

		cur[4] = 2;	// OCEvent = 1, ASYNC = 0

		used_len += 8;
	}

	/* Removable Medium Feature */
	if ((rt == 2 && start == 0x0003) ||
	    (start <= 0x0003 && (rt == 0 || rt == 1))) {
		cur = &buf[used_len];
		*(uint16_t *)&cur[0] = htobe16(0x0003);
		cur[2] = 3;	// persistent=1, current=1
		cur[3] = 4;	// additional length

		cur[4] = 0x20;	// mechanism=1, eject=0, pvnt jmpr=0, lock=0

		used_len += 8;
	}

	/* Random Readable Feature */
	if ((rt == 2 && start == 0x0010) ||
	    (start <= 0x0010 && (rt == 0 || rt == 1))) {
		cur = &buf[used_len];
		*(uint16_t *)&cur[0] = htobe16(0x0010);
		cur[2] = 1;	// version=0, persistent=0, current=1
		cur[3] = 8;	// additional length

		*(uint32_t *)&cur[4] = htobe32(state->block_size);
		*(uint16_t *)&cur[8] = htobe16(0x10);	// Blocking
		cur[10] = 0x01;	// PP=1

		used_len += 12;
	}

	/* Multi Read Feature - never current */
	if ((rt == 2 && start == 0x001d) ||
	    (start <= 0x001d && rt == 0)) {
		cur = &buf[used_len];
		*(uint16_t *)&cur[0] = htobe16(0x001d);
		cur[2] = 0;	// version=0, persistent=0, current=0
		cur[3] = 0;	// additional length

		used_len += 4;
	}

	/* CD Read Feature - never current */
	if ((rt == 2 && start == 0x001e) ||
	    (start <= 0x001e && rt == 0)) {
		cur = &buf[used_len];
		*(uint16_t *)&cur[0] = htobe16(0x001e);
		cur[2] = 8;	// version=2, persistent=0, current=0
		cur[3] = 4;	// additional length

		used_len += 8;
	}

	/* DVD Read Feature */
	if ((rt == 2 && start == 0x001f) ||
	    (start <= 0x001f && (rt == 0 || rt == 1))) {
		cur = &buf[used_len];
		*(uint16_t *)&cur[0] = htobe16(0x001f);
		cur[2] = 1;	// version=0, persistent=0, current=1
		cur[3] = 0;	// additional length

		used_len += 4;
	}

	/* Random Writable Feature */
	if ((rt == 2 && start == CDF_RWRT) ||
	    (start <= CDF_RWRT &&
	     (rt == 0 || (rt == 1 && !(state->flags & FBO_READ_ONLY))))) {
		cur = &buf[used_len];
		*(uint16_t *)&cur[0] = htobe16(CDF_RWRT);
		if (state->flags & FBO_READ_ONLY)
			cur[2] = 4;	// version=1, persistent=0, current=0
		else
			cur[2] = 5;	// version=1, persistent=0, current=1
		cur[3] = 0xc;		// additional length

		*(uint32_t *)&cur[4] = htobe32(state->num_lbas - 1);
		*(uint32_t *)&cur[8] = htobe32(state->block_size);
		*(uint16_t *)&cur[12] = htobe16(0x10);	// Blocking
		cur[14] = 0x01;		// PP=1

		used_len += 16;
	}

	/* Incremental Streaming Writable Feature - never current */
	if ((rt == 2 && start == 0x0021) ||
	    (start <= 0x0021 && rt == 0)) {
		cur = &buf[used_len];
		*(uint16_t *)&cur[0] = htobe16(0x0021);
		cur[2] = 4;	// version=1, persistent=0, current=0
		cur[3] = 4;	// additional length

		used_len += 8;
	}

	/* Formattable Feature */
	if ((rt == 2 && start == 0x0023) ||
	    (start <= 0x0023 &&
	     (rt == 0 || (rt == 1 && !(state->flags & FBO_READ_ONLY))))) {
		cur = &buf[used_len];
		*(uint16_t *)&cur[0] = htobe16(0x0023);
		if (state->flags & FBO_READ_ONLY)
			cur[2] = 0;	// version=0, persistent=0, current=0
		else
			cur[2] = 1;	// version=0, persistent=0, current=1
		cur[3] = 0;	// additional length

		used_len += 4;
	}

	/* Hardware Defect Management Feature */
	if ((rt == 2 && start == CDF_HWDM) ||
	    (start <= CDF_HWDM &&
	     (rt == 0 || (rt == 1 && !(state->flags & FBO_READ_ONLY))))) {
		cur = &buf[used_len];
		*(uint16_t *)&cur[0] = htobe16(CDF_HWDM);
		if (state->flags & FBO_READ_ONLY)
			cur[2] = 4;	// version=1, persistent=0, current=0
		else
			cur[2] = 5;	// version=1, persistent=0, current=1
		cur[3] = 4;	// additional length

		used_len += 8;
	}

	/* Restricted Overwrite Feature - never current */
	if ((rt == 2 && start == 0x0026) ||
	    (start <= 0x0026 && rt == 0)) {
		cur = &buf[used_len];
		*(uint16_t *)&cur[0] = htobe16(0x0026);
		cur[2] = 0;	// version=0, persistent=0, current=0
		cur[3] = 0;	// additional length

		used_len += 4;
	}

	/* CD Track at Once Feature - never current */
	if ((rt == 2 && start == 0x002d) ||
	    (start <= 0x002d && rt == 0)) {
		cur = &buf[used_len];
		*(uint16_t *)&cur[0] = htobe16(0x002d);
		cur[2] = 8;	// version=2, persistent=0, current=0
		cur[3] = 4;	// additional length

		used_len += 8;
	}

	/* Timeout Feature */
	if ((rt == 2 && start == 0x0105) ||
	    (start <= 0x0105 && (rt == 0 || rt == 1))) {
		cur = &buf[used_len];
		*(uint16_t *)&cur[0] = htobe16(0x0105);
		cur[2] = 5;	// version=1, persistent=0, current=1
		cur[3] = 4;	// additional length

		used_len += 8;
	}

	*(uint32_t *)&buf[0] = htobe32(used_len - 4);

	tcmu_memcpy_into_iovec(iovec, iov_cnt, buf, used_len);

	return SAM_STAT_GOOD;
}