static int fbo_emulate_read_dvd_structure(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 format = cdb[7];
	uint32_t start_phys;
	uint32_t end_phys;
	char manuf_info[] = "VIRTUAL FB OPT";
	uint8_t buf[512];

	// TBD: If we simulate start/stop, then fail if stopped and format != 0xff
	/* Fail anything other than layer 0 */
	if (cdb[6])
		return tcmu_set_sense_data(sense, ILLEGAL_REQUEST,
					   ASC_INVALID_FIELD_IN_CDB, NULL);

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

	switch (format) {
	case DVD_STRUCT_PHYSICAL:
		if (state->flags & FBO_READ_ONLY)
			start_phys = 0x30000;
		else
			start_phys = 0x31000;
		buf[1] = 19;			//DVD Structure Data Length
		if (state->flags & FBO_READ_ONLY)
			buf[4] = 0x02;		// Book Type=0, Part Version=2
		else
			buf[4] = 0x12;		// Book Type=1, Part Version=2
		buf[5] = 0x0f;			// Maximum Rate=Not specified
		if (!(state->flags & FBO_READ_ONLY))
			buf[6] = 0x02;		// Layer Type=2
		buf[9] = start_phys >> 16;	// Starting physical sector
		*(uint16_t *)&buf[10] = htobe16(start_phys & 0xffff);
		end_phys = start_phys + state->num_lbas - 1;
		buf[13] = end_phys >> 16;
		*(uint16_t *)&buf[14] = htobe16(end_phys & 0xffff);

		tcmu_memcpy_into_iovec(iovec, iov_cnt, buf, 21);
		break;

	case DVD_STRUCT_COPYRIGHT:
		buf[1] = 6;	// DVD Structure Data Length

		tcmu_memcpy_into_iovec(iovec, iov_cnt, buf, 8);
		break;

	case DVD_STRUCT_MANUFACT:
		buf[2] = strlen(manuf_info) + 2;	// DVD Struct Data Len
		memcpy(&buf[4], manuf_info, strlen(manuf_info));

		tcmu_memcpy_into_iovec(iovec, iov_cnt, buf,
				       strlen(manuf_info) + 4);
		break;

	case 0x09:	// DVD-RAM Medium Status (Cartridge Info)
		if (state->flags & FBO_READ_ONLY)
			return tcmu_set_sense_data(sense, ILLEGAL_REQUEST,
						   ASC_INVALID_FIELD_IN_CDB,
						   NULL);
		buf[1] = 6;	// DVD Structure Data Length
		buf[5] = 0x10;	// Disc Type Identification

		tcmu_memcpy_into_iovec(iovec, iov_cnt, buf, 8);
		break;

	case 0xff:	// Read DVD Structure Capabilities List
		buf[1] = 18;	// DVD Structure Data Length

		buf[4] = 0x00;	// Format Field
		buf[5] = 0x40;	// SDS=0, RDS=1
		buf[7] = 21;	// Structure Length

		buf[8] = 0x01;	// Format Field
		buf[9] = 0x40;	// SDS=0, RDS=1
		buf[11] = 8;	// Structure Length

		buf[12] = 0x04;	// Format Field
		buf[13] = 0x40;	// SDS=0, RDS=1
		buf[15] = strlen(manuf_info) + 4;	// Structure Length

		buf[16] = 0x09;	// Format Field
		buf[17] = 0x40;	// SDS=0, RDS=1
		buf[19] = 8;	// Structure Length

		tcmu_memcpy_into_iovec(iovec, iov_cnt, buf, 20);
		break;

	default:
		return tcmu_set_sense_data(sense, ILLEGAL_REQUEST,
					   ASC_INVALID_FIELD_IN_CDB, NULL);
	}

	return SAM_STAT_GOOD;
}
static int fbo_emulate_read_dvd_structure(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 format = cdb[7];
	uint32_t start_phys;
	uint32_t end_phys;
	char manuf_info[] = "VIRTUAL FB OPT";
	uint8_t buf[512];

	 
	 
	if (cdb[6])
		return tcmu_set_sense_data(sense, ILLEGAL_REQUEST,
					   ASC_INVALID_FIELD_IN_CDB, NULL);

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

	switch (format) {
	case DVD_STRUCT_PHYSICAL:
		if (state->flags & FBO_READ_ONLY)
			start_phys = 0x30000;
		else
			start_phys = 0x31000;
		buf[1] = 19;			 
		if (state->flags & FBO_READ_ONLY)
			buf[4] = 0x02;		 
		else
			buf[4] = 0x12;		 
		buf[5] = 0x0f;			 
		if (!(state->flags & FBO_READ_ONLY))
			buf[6] = 0x02;		 
		buf[9] = start_phys >> 16;	 
		*(uint16_t *)&buf[10] = htobe16(start_phys & 0xffff);
		end_phys = start_phys + state->num_lbas - 1;
		buf[13] = end_phys >> 16;
		*(uint16_t *)&buf[14] = htobe16(end_phys & 0xffff);

		tcmu_memcpy_into_iovec(iovec, iov_cnt, buf, 21);
		break;

	case DVD_STRUCT_COPYRIGHT:
		buf[1] = 6;	 

		tcmu_memcpy_into_iovec(iovec, iov_cnt, buf, 8);
		break;

	case DVD_STRUCT_MANUFACT:
		buf[2] = strlen(manuf_info) + 2;	 
		memcpy(&buf[4], manuf_info, strlen(manuf_info));

		tcmu_memcpy_into_iovec(iovec, iov_cnt, buf,
				       strlen(manuf_info) + 4);
		break;

	case 0x09:	 
		if (state->flags & FBO_READ_ONLY)
			return tcmu_set_sense_data(sense, ILLEGAL_REQUEST,
						   ASC_INVALID_FIELD_IN_CDB,
						   NULL);
		buf[1] = 6;	 
		buf[5] = 0x10;	 

		tcmu_memcpy_into_iovec(iovec, iov_cnt, buf, 8);
		break;

	case 0xff:	 
		buf[1] = 18;	 

		buf[4] = 0x00;	 
		buf[5] = 0x40;	 
		buf[7] = 21;	 

		buf[8] = 0x01;	 
		buf[9] = 0x40;	 
		buf[11] = 8;	 

		buf[12] = 0x04;	 
		buf[13] = 0x40;	 
		buf[15] = strlen(manuf_info) + 4;	 

		buf[16] = 0x09;	 
		buf[17] = 0x40;	 
		buf[19] = 8;	 

		tcmu_memcpy_into_iovec(iovec, iov_cnt, buf, 20);
		break;

	default:
		return tcmu_set_sense_data(sense, ILLEGAL_REQUEST,
					   ASC_INVALID_FIELD_IN_CDB, NULL);
	}

	return SAM_STAT_GOOD;
}