Esempio n. 1
0
status_t
VolumeCryptContext::Setup(int fd, const uint8* key, uint32 keyLength,
	const uint8* random, uint32 randomLength)
{
	off_t size;
	status_t status = get_size(fd, size);
	if (status != B_OK)
		return status;

	fOffset = max_c(4096, BLOCK_SIZE);
	fSize = size - fOffset;
	fHidden = false;

	const uint8* salt = random;
	random += PKCS5_SALT_SIZE;

	uint8 buffer[BLOCK_SIZE];
	memcpy(buffer, salt, PKCS5_SALT_SIZE);
	memset(buffer + PKCS5_SALT_SIZE, 0, BLOCK_SIZE - PKCS5_SALT_SIZE);

	true_crypt_header& header = *(true_crypt_header*)&buffer[PKCS5_SALT_SIZE];
	header.magic = B_HOST_TO_BENDIAN_INT32(kTrueCryptMagic);
	header.version = B_HOST_TO_BENDIAN_INT16(0x4);
	header.required_program_version = B_HOST_TO_BENDIAN_INT16(0x600);
	header.volume_size = B_HOST_TO_BENDIAN_INT64(fSize);
	header.encrypted_offset = B_HOST_TO_BENDIAN_INT64(fOffset);
	header.encrypted_size = B_HOST_TO_BENDIAN_INT64(fSize);
	header.flags = 0;
	memcpy(header.disk_key, random, sizeof(header.disk_key));
	header.crc_checksum = B_HOST_TO_BENDIAN_INT32(crc32(header.disk_key, 256));
	header.header_crc_checksum
		= B_HOST_TO_BENDIAN_INT32(crc32((uint8*)&header, 188));

	return _WriteHeader(fd, key, keyLength, 0, buffer);
}
Esempio n. 2
0
ssize_t
QuickCamDevice::ReadIIC16(uint8 address, uint16 *data)
{
	status_t err;
	uint8 buffer[0x23];
	memset(buffer, 0, sizeof(buffer));
	buffer[0x20] = Sensor() ? Sensor()->IICReadAddress() : 0;
	buffer[0x21] = 1 - 1;
	buffer[0x22] = 0x03;
	buffer[0] = address;
	err = SendCommand(USB_REQTYPE_DEVICE_OUT, 0x04, STV_I2C_WRITE, 0, 0x23, buffer);
	if (err < B_OK)
		return err;

	buffer[0] = 0xaa;
	buffer[1] = 0xaa;
	err = SendCommand(USB_REQTYPE_DEVICE_IN, 0x04, STV_I2C_READ, 0, 0x2, buffer);
	PRINT((CH ": SendCommand: %s" CT, strerror(err)));
	if (err < B_OK)
		return err;

	if (fChipIsBigEndian)
		*data = B_HOST_TO_BENDIAN_INT16(*(uint16 *)(&buffer[0]));
	else
		*data = B_HOST_TO_LENDIAN_INT16(*(uint16 *)(&buffer[0]));
	PRINT((CH ": 0x%04x" CT, *data));
	return 2;
}
Esempio n. 3
0
status_t
BRawNetBuffer::AppendUint16(uint16 value)
{
	uint16 netVal = B_HOST_TO_BENDIAN_INT16(value);
	ssize_t sizeW = fBuffer.WriteAt(fWritePosition, &netVal, sizeof(uint16));
	if (sizeW == B_NO_MEMORY)
		return B_NO_MEMORY;
	fWritePosition += sizeof(uint16);
	return B_OK;
}
Esempio n. 4
0
void CharView::Draw(BRect urect)
{
	BPoint		point;
	font_height	fheight;
	char		utf8Char[3];
	uint16		uniChar[1];

	urect = Bounds();

//	SetLowColor(def_viewcolor);
	SetDrawingMode(B_OP_COPY);
	SetHighColor(strokeColor);
	SetPenSize(1);
	StrokeRect(urect);

	urect.InsetBy(1, 1);
	SetHighColor(bgColor);
	FillRect(urect);
	SetLowColor(bgColor);
	SetHighColor(displayColor);

	if (drawmode) {
		font.SetSize(urect.Width() * 0.6);
		font.GetHeight(&fheight);

		//  Unicode to UTF8 Character encoding
		uniChar[0] = B_HOST_TO_BENDIAN_INT16(((mutf == 0) || (mutf == 65535)) ? 1 : mutf);
		int32 state = 0;
		int32 srcLen = 2;
		int32 destLen = sizeof(utf8Char);
		convert_to_utf8(B_UNICODE_CONVERSION, (const char*)uniChar, &srcLen,
						utf8Char, &destLen, &state);

		SetFont(&font);
	
		bool hasGlyph[1];
		font.GetHasGlyphs(utf8Char, 1, hasGlyph);

		if (hasGlyph[0]) {
			float choffset = (urect.right - urect.left - StringWidth(utf8Char, destLen)) / 2;
			float cvoffset = (urect.Height() - fheight.ascent - fheight.descent) / 2 + fheight.ascent;
			point.Set(choffset, cvoffset);
			DrawString(utf8Char, destLen, point);
		}
	}

/*	printf("\nCharView!\n");
	printf("utf8Char[0]: %x\n", utf8Char[0]);
	printf("utf8Char[1]: %x\n", utf8Char[1]);
	printf("utf8Char[2]: %x\n", utf8Char[2]);*/
}
Esempio n. 5
0
status_t
PackageWriter::_Finish()
{
	// write entries
	for (EntryList::ConstIterator it = fRootEntry->ChildIterator();
			Entry* entry = it.Next();) {
		_AddEntry(AT_FDCWD, entry, entry->Name());
	}

printf("header size:             %lu\n", sizeof(hpkg_header));
printf("heap size:               %lld\n", fHeapEnd - sizeof(hpkg_header));

	hpkg_header header;

	// write the TOC and package attributes
	_WriteTOC(header);
	_WritePackageAttributes(header);

	off_t totalSize = fHeapEnd;
printf("total size:              %lld\n", totalSize);

	// prepare the header

	// general
	header.magic = B_HOST_TO_BENDIAN_INT32(B_HPKG_MAGIC);
	header.header_size = B_HOST_TO_BENDIAN_INT16(
		(uint16)sizeof(hpkg_header));
	header.version = B_HOST_TO_BENDIAN_INT16(B_HPKG_VERSION);
	header.total_size = B_HOST_TO_BENDIAN_INT64(totalSize);

	// write the header
	_WriteBuffer(&header, sizeof(hpkg_header), 0);

	fFinished = true;
	return B_OK;
}
Esempio n. 6
0
static status_t
get_position(cd_driver_info *info, scsi_position *position)
{
	scsi_cmd_read_subchannel cmd;

	TRACE("get_position()\n");

	memset(&cmd, 0, sizeof(cmd));
	cmd.opcode = SCSI_OP_READ_SUB_CHANNEL;
	cmd.time = 1;
	cmd.subq = 1;
	cmd.parameter_list = scsi_sub_channel_parameter_list_cd_pos;
	cmd.track = 0;
	cmd.allocation_length = B_HOST_TO_BENDIAN_INT16(sizeof(scsi_position));

	return sSCSIPeripheral->simple_exec(info->scsi_periph_device,
		&cmd, sizeof(cmd), position, sizeof(*position), SCSI_DIR_IN);
}
Esempio n. 7
0
static status_t
read_table_of_contents(int fd, uint32 track, uint8 format, uint8 *buffer,
	size_t bufferSize)
{
	raw_device_command raw;
	uint8 *senseData = (uint8 *)malloc(kSenseSize);
	if (senseData == NULL)
		return B_NO_MEMORY;

	memset(&raw, 0, sizeof(raw_device_command));
	memset(senseData, 0, kSenseSize);
	memset(buffer, 0, bufferSize);

	scsi_cmd_read_toc &toc = *(scsi_cmd_read_toc*)&raw.command;
	toc.opcode = SCSI_OP_READ_TOC;
	toc.time = 1;
	toc.format = format;
	toc.track = track;
	toc.allocation_length = B_HOST_TO_BENDIAN_INT16(bufferSize);

	raw.command_length = 10;
	raw.flags = B_RAW_DEVICE_DATA_IN | B_RAW_DEVICE_REPORT_RESIDUAL
		| B_RAW_DEVICE_SHORT_READ_VALID;
	raw.scsi_status = 0;
	raw.cam_status = 0;
	raw.data = buffer;
	raw.data_length = bufferSize;
	raw.timeout = 10000000LL;	// 10 secs
	raw.sense_data = senseData;
	raw.sense_data_length = sizeof(kSenseSize);

	if (ioctl(fd, B_RAW_DEVICE_COMMAND, &raw) == 0
		&& raw.scsi_status == 0 && raw.cam_status == 1) {
		free(senseData);
		return B_OK;
	}

	free(senseData);
	return B_ERROR;
}
Esempio n. 8
0
static status_t
read_table_of_contents(int deviceFD, uint32 first_session, uchar* buffer,
	uint16 buffer_length, bool msf)
{
	scsi_table_of_contents_command scsi_command;
	raw_device_command raw_command;
	const uint32 sense_data_length = 1024;
	uchar sense_data[sense_data_length];
	status_t error = buffer ? B_OK : B_BAD_VALUE;

	DEBUG_INIT_ETC(NULL, ("fd: %d, buffer: %p, buffer_length: %d",
		deviceFD, buffer, buffer_length));

	if (error)
		return error;

	// Init the scsi command and copy it into the "raw scsi command"
	// ioctl struct
	memset(raw_command.command, 0, 16);
	scsi_command.command = 0x43;
	scsi_command.msf = 1;
	scsi_command.format = kFullTableOfContentsFormat;
	scsi_command.number = first_session;
	scsi_command.length = B_HOST_TO_BENDIAN_INT16(buffer_length);
	scsi_command.control = 0;
	scsi_command.reserved0 = scsi_command.reserved1 = scsi_command.reserved2
		= scsi_command.reserved3 = scsi_command.reserved4
		= scsi_command.reserved5 = scsi_command.reserved6 = 0;
	memcpy(raw_command.command, &scsi_command, sizeof(scsi_command));

	// Init the rest of the raw command
	raw_command.command_length = 10;
	raw_command.flags = kScsiFlags;
	raw_command.scsi_status = 0;
	raw_command.cam_status = 0;
	raw_command.data = buffer;
	raw_command.data_length = buffer_length;
	memset(raw_command.data, 0, raw_command.data_length);
	raw_command.sense_data = sense_data;
	raw_command.sense_data_length = sense_data_length;
	memset(raw_command.sense_data, 0, raw_command.sense_data_length);
	raw_command.timeout = kScsiTimeout;

	if (ioctl(deviceFD, B_RAW_DEVICE_COMMAND, &raw_command) == 0) {
		if (raw_command.scsi_status == 0 && raw_command.cam_status == 1) {
			// SUCCESS!!!
			DBG(dump_full_table_of_contents(buffer, buffer_length));
		} else {
			error = B_FILE_ERROR;
			TRACE(("%s: scsi ioctl succeeded, but scsi command failed\n",
				kModuleDebugName));
		}
	} else {
		error = errno;
		TRACE(("%s: scsi command failed with error 0x%lx\n", kModuleDebugName,
			error));
	}

	return error;

}
Esempio n. 9
0
static status_t
get_toc(cd_driver_info *info, scsi_toc *toc)
{
	scsi_ccb *ccb;
	status_t res;
	scsi_cmd_read_toc *cmd;
	size_t dataLength;
	scsi_toc_general *shortResponse = (scsi_toc_general *)toc->toc_data;

	TRACE("get_toc()\n");

	ccb = info->scsi->alloc_ccb(info->scsi_device);
	if (ccb == NULL)
		return B_NO_MEMORY;

	// first read number of tracks only
	ccb->flags = SCSI_DIR_IN;

	cmd = (scsi_cmd_read_toc *)ccb->cdb;

	memset(cmd, 0, sizeof(*cmd));
	cmd->opcode = SCSI_OP_READ_TOC;
	cmd->time = 1;
	cmd->format = SCSI_TOC_FORMAT_TOC;
	cmd->track = 1;
	cmd->allocation_length = B_HOST_TO_BENDIAN_INT16(sizeof(scsi_toc_general));

	ccb->cdb_length = sizeof(*cmd);

	ccb->sort = -1;
	ccb->timeout = SCSI_CD_STD_TIMEOUT;

	ccb->data = toc->toc_data;
	ccb->sg_list = NULL;
	ccb->data_length = sizeof(toc->toc_data);

	res = sSCSIPeripheral->safe_exec(info->scsi_periph_device, ccb);
	if (res != B_OK)
		goto err;

	// then read all track infos
	// (little hint: number of tracks is last - first + 1;
	//  but scsi_toc_toc has already one track, so we get
	//  last - first extra tracks; finally, we want the lead-out as
	//  well, so we add an extra track)
	dataLength = (shortResponse->last - shortResponse->first + 1)
		* sizeof(scsi_toc_track) + sizeof(scsi_toc_toc);
	dataLength = min_c(dataLength, sizeof(toc->toc_data));

	TRACE("  tracks: %d - %d, data length %d\n", shortResponse->first,
		shortResponse->last, (int)dataLength);

	cmd->allocation_length = B_HOST_TO_BENDIAN_INT16(dataLength);

	res = sSCSIPeripheral->safe_exec(info->scsi_periph_device, ccb);

err:
	info->scsi->free_ccb(ccb);

	return res;
}
Esempio n. 10
0
void
MemoryView::_GetNextHexBlock(char* buffer, int32 bufferSize,
	const char* address)
{
	switch(fHexMode) {
		case HexMode8BitInt:
		{
			snprintf(buffer, bufferSize, "%02" B_PRIx8,
				*((const uint8*)address));
			break;
		}
		case HexMode16BitInt:
		{
			uint16 data = *((const uint16*)address);
			switch(fCurrentEndianMode)
			{
				case EndianModeBigEndian:
				{
					data = B_HOST_TO_BENDIAN_INT16(data);
				}
				break;

				case EndianModeLittleEndian:
				{
					data = B_HOST_TO_LENDIAN_INT16(data);
				}
				break;
			}
			snprintf(buffer, bufferSize, "%04" B_PRIx16,
				data);
			break;
		}
		case HexMode32BitInt:
		{
			uint32 data = *((const uint32*)address);
			switch(fCurrentEndianMode)
			{
				case EndianModeBigEndian:
				{
					data = B_HOST_TO_BENDIAN_INT32(data);
				}
				break;

				case EndianModeLittleEndian:
				{
					data = B_HOST_TO_LENDIAN_INT32(data);
				}
				break;
			}
			snprintf(buffer, bufferSize, "%08" B_PRIx32,
				data);
			break;
		}
		case HexMode64BitInt:
		{
			uint64 data = *((const uint64*)address);
			switch(fCurrentEndianMode)
			{
				case EndianModeBigEndian:
				{
					data = B_HOST_TO_BENDIAN_INT64(data);
				}
				break;

				case EndianModeLittleEndian:
				{
					data = B_HOST_TO_LENDIAN_INT64(data);
				}
				break;
			}
			snprintf(buffer, bufferSize, "%0*" B_PRIx64,
				16, data);
			break;
		}
	}
}
Esempio n. 11
0
void
PackageWriter::_WriteAttributeValue(const AttributeValue& value, uint8 encoding)
{
	switch (value.type) {
		case B_HPKG_ATTRIBUTE_TYPE_INT:
		case B_HPKG_ATTRIBUTE_TYPE_UINT:
		{
			uint64 intValue = value.type == B_HPKG_ATTRIBUTE_TYPE_INT
				? (uint64)value.signedInt : value.unsignedInt;

			switch (encoding) {
				case B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT:
					_Write<uint8>((uint8)intValue);
					break;
				case B_HPKG_ATTRIBUTE_ENCODING_INT_16_BIT:
					_Write<uint16>(
						B_HOST_TO_BENDIAN_INT16((uint16)intValue));
					break;
				case B_HPKG_ATTRIBUTE_ENCODING_INT_32_BIT:
					_Write<uint32>(
						B_HOST_TO_BENDIAN_INT32((uint32)intValue));
					break;
				case B_HPKG_ATTRIBUTE_ENCODING_INT_64_BIT:
					_Write<uint64>(
						B_HOST_TO_BENDIAN_INT64((uint64)intValue));
					break;
				default:
				{
					fprintf(stderr, "_WriteAttributeValue(): invalid "
						"encoding %d for int value type %d\n", encoding,
						value.type);
					throw status_t(B_BAD_VALUE);
				}
			}

			break;
		}

		case B_HPKG_ATTRIBUTE_TYPE_STRING:
		{
			if (encoding == B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE)
				_WriteUnsignedLEB128(value.string->index);
			else
				_WriteString(value.string->string);
			break;
		}

		case B_HPKG_ATTRIBUTE_TYPE_RAW:
		{
			_WriteUnsignedLEB128(value.data.size);
			if (encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP)
				_WriteUnsignedLEB128(value.data.offset);
			else
				fDataWriter->WriteDataThrows(value.data.raw, value.data.size);
			break;
		}

		default:
			fprintf(stderr, "_WriteAttributeValue(): invalid value type: "
				"%d\n", value.type);
			throw status_t(B_BAD_VALUE);
	}
}
Esempio n. 12
0
static void
ata_mode_sense_10(ide_device_info *device, ide_qrequest *qrequest)
{
	scsi_ccb *request = qrequest->request;
	scsi_cmd_mode_sense_10 *cmd = (scsi_cmd_mode_sense_10 *)request->cdb;
	scsi_mode_param_header_10 param_header;
	scsi_modepage_control control;
	scsi_mode_param_block_desc block_desc;
	size_t totalLength = sizeof(scsi_mode_param_header_10)
		+ sizeof(scsi_mode_param_block_desc)
		+ sizeof(scsi_modepage_control);
	scsi_mode_param_dev_spec_da devspec = {
		_res0_0 : 0,
		dpo_fua : 0,
		_res0_6 : 0,
		write_protected : 0
	};
	uint32 allocationLength;

	SHOW_FLOW0(1, "Hi!");

	allocationLength = B_BENDIAN_TO_HOST_INT16(cmd->allocation_length);

	// we answer control page requests and "all pages" requests
	// (as the latter are the same as the first)
	if ((cmd->page_code != SCSI_MODEPAGE_CONTROL && cmd->page_code != SCSI_MODEPAGE_ALL)
		|| (cmd->page_control != SCSI_MODE_SENSE_PC_CURRENT
			&& cmd->page_control != SCSI_MODE_SENSE_PC_SAVED)) {
		set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_CDB_FIELD);
		return;
	}

	//param_header = (scsi_mode_param_header_10 *)request->data;
	param_header.mode_data_length = B_HOST_TO_BENDIAN_INT16(totalLength - 1);
	param_header.medium_type = 0; 		// XXX standard is a bit vague here
	param_header.dev_spec_parameter = *(uint8 *)&devspec;
	param_header.block_desc_length
		= B_HOST_TO_BENDIAN_INT16(sizeof(scsi_mode_param_block_desc));

	copy_sg_data(request, 0, allocationLength, &param_header,
		sizeof(param_header), false);

	/*block_desc = (scsi_mode_param_block_desc *)(request->data 
		+ sizeof(*param_header));*/
	memset(&block_desc, 0, sizeof(block_desc));
	// density is reserved (0), descriptor apply to entire medium (num_blocks=0)
	// remains the blocklen to be set
	block_desc.high_blocklen = 0;
	block_desc.med_blocklen = 512 >> 8;
	block_desc.low_blocklen = 512 & 0xff;

	copy_sg_data(request, sizeof(param_header), allocationLength,
		&block_desc, sizeof(block_desc), false);

	/*contr = (scsi_modepage_contr *)(request->data 
		+ sizeof(*param_header)
		+ ((uint16)param_header->high_block_desc_len << 8) 
		+ param_header->low_block_desc_len);*/

	memset(&control, 0, sizeof(control));
	control.RLEC = false;
	control.DQue = !device->CQ_enabled;
	control.QErr = false;
		// when a command fails we requeue all 
		// lost commands automagically
	control.QAM = SCSI_QAM_UNRESTRICTED;

	copy_sg_data(request, sizeof(param_header)
		+ B_BENDIAN_TO_HOST_INT16(param_header.block_desc_length),
		allocationLength, &control, sizeof(control), false);

	// the number of bytes that were transferred to buffer is
	// restricted by allocation length and by request data buffer size
	totalLength = min(totalLength, allocationLength);
	totalLength = min(totalLength, request->data_length);

	request->data_resid = request->data_length - totalLength;
}


/*! Emulate modifying control page */
static bool
ata_mode_select_control_page(ide_device_info *device, ide_qrequest *qrequest,
	scsi_modepage_control *page)
{
	if (page->header.page_length != sizeof(*page) - sizeof(page->header)) {
		set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_PARAM_LIST_LENGTH_ERR);
		return false;
	}

	// we only support enabling/disabling command queuing
	enable_CQ(device, !page->DQue);
	return true;
}


/*! Emulate MODE SELECT 10 command */
static void
ata_mode_select_10(ide_device_info *device, ide_qrequest *qrequest)
{
	scsi_ccb *request = qrequest->request;
	scsi_cmd_mode_select_10 *cmd = (scsi_cmd_mode_select_10 *)request->cdb;
	scsi_mode_param_header_10 param_header;
	scsi_modepage_header page_header;
	uint32 totalLength;
	uint32 modepageOffset;
	char modepage_buffer[64];	// !!! enlarge this to support longer mode pages

	if (cmd->save_pages || cmd->pf != 1) {
		set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_CDB_FIELD);
		return;
	}

	totalLength = min(request->data_length,
		B_BENDIAN_TO_HOST_INT16(cmd->param_list_length));

	// first, retrieve page header to get size of different chunks
	//param_header = (scsi_mode_param_header_10 *)request->data;
	if (!copy_sg_data(request, 0, totalLength, &param_header, sizeof(param_header), true))
		goto err;

	totalLength = min(totalLength,
		B_BENDIAN_TO_HOST_INT16(param_header.mode_data_length) + 1UL);

	// this is the start of the first mode page;
	// we ignore the block descriptor silently
	modepageOffset = sizeof(param_header)
		+ B_BENDIAN_TO_HOST_INT16(param_header.block_desc_length);

	// go through list of pages		
	while (modepageOffset < totalLength) {
		uint32 pageLength;

		// get header to know how long page is
		if (!copy_sg_data(request, modepageOffset, totalLength,
				&page_header, sizeof(page_header), true))
			goto err;

		// get size of one page and copy it to buffer
		pageLength = page_header.page_length + sizeof(scsi_modepage_header);

		// the buffer has a maximum size - this is really standard compliant but
		// sufficient for our needs
		if (pageLength > sizeof(modepage_buffer))
			goto err;

		if (!copy_sg_data(request, modepageOffset, totalLength,
				&modepage_buffer, min(pageLength, sizeof(modepage_buffer)), true))
			goto err;

		// modify page;
		// currently, we only support the control mode page
		switch (page_header.page_code) {
			case SCSI_MODEPAGE_CONTROL:
				if (!ata_mode_select_control_page(device, qrequest,
						(scsi_modepage_control *)modepage_buffer))
					return;
				break;

			default:
				set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST,
					SCSIS_ASC_INV_PARAM_LIST_FIELD);
				return;
		}

		modepageOffset += pageLength;
	}

	if (modepageOffset != totalLength)
		goto err;

	request->data_resid = request->data_length - totalLength;
	return;

	// if we arrive here, data length was incorrect
err:
	set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_PARAM_LIST_LENGTH_ERR);
}
Esempio n. 13
0
status_t
BNetBuffer::AppendUint16(uint16 data)
{
	uint16 be_data = B_HOST_TO_BENDIAN_INT16(data);
	return AppendData((const void*)&be_data, sizeof(uint16));
}
Esempio n. 14
0
File: io.cpp Progetto: DonCN/haiku
/*! Universal read/write function */
static status_t
read_write(scsi_periph_device_info *device, scsi_ccb *request,
	io_operation *operation, uint64 offset, size_t originalNumBlocks,
	physical_entry* vecs, size_t vecCount, bool isWrite,
	size_t* _bytesTransferred)
{
	uint32 blockSize = device->block_size;
	size_t numBlocks = originalNumBlocks;
	uint32 pos = offset;
	err_res res;
	int retries = 0;

	do {
		size_t numBytes;
		bool isReadWrite10 = false;

		request->flags = isWrite ? SCSI_DIR_OUT : SCSI_DIR_IN;

		// io_operations are generated by a DMAResource and thus contain DMA
		// safe physical vectors
		if (operation != NULL)
			request->flags |= SCSI_DMA_SAFE;

		// make sure we avoid 10 byte commands if they aren't supported
		if (!device->rw10_enabled || device->preferred_ccb_size == 6) {
			// restricting transfer is OK - the block manager will
			// take care of transferring the rest
			if (numBlocks > 0x100)
				numBlocks = 0x100;

			// no way to break the 21 bit address limit
			if (offset > 0x200000)
				return B_BAD_VALUE;

			// don't allow transfer cross the 24 bit address limit
			// (I'm not sure whether this is allowed, but this way we
			// are sure to not ask for trouble)
			if (offset < 0x100000)
				numBlocks = min_c(numBlocks, 0x100000 - pos);
		}

		numBytes = numBlocks * blockSize;
		if (numBlocks != originalNumBlocks)
			panic("I/O operation would need to be cut.");

		request->data = NULL;
		request->sg_list = vecs;
		request->data_length = numBytes;
		request->sg_count = vecCount;
		request->io_operation = operation;
		request->sort = pos;
		request->timeout = device->std_timeout;
		// see whether daemon instructed us to post an ordered command;
		// reset flag after read
		SHOW_FLOW(3, "flag=%x, next_tag=%x, ordered: %s",
			(int)request->flags, (int)device->next_tag_action,
			(request->flags & SCSI_ORDERED_QTAG) != 0 ? "yes" : "no");

		// use shortest commands whenever possible
		if (offset + numBlocks < 0x200000LL && numBlocks <= 0x100) {
			scsi_cmd_rw_6 *cmd = (scsi_cmd_rw_6 *)request->cdb;

			isReadWrite10 = false;

			memset(cmd, 0, sizeof(*cmd));
			cmd->opcode = isWrite ? SCSI_OP_WRITE_6 : SCSI_OP_READ_6;
			cmd->high_lba = (pos >> 16) & 0x1f;
			cmd->mid_lba = (pos >> 8) & 0xff;
			cmd->low_lba = pos & 0xff;
			cmd->length = numBlocks;

			request->cdb_length = sizeof(*cmd);
		} else if (offset + numBlocks < 0x100000000LL && numBlocks <= 0x10000) {
			scsi_cmd_rw_10 *cmd = (scsi_cmd_rw_10 *)request->cdb;

			isReadWrite10 = true;

			memset(cmd, 0, sizeof(*cmd));
			cmd->opcode = isWrite ? SCSI_OP_WRITE_10 : SCSI_OP_READ_10;
			cmd->relative_address = 0;
			cmd->force_unit_access = 0;
			cmd->disable_page_out = 0;
			cmd->lba = B_HOST_TO_BENDIAN_INT32(pos);
			cmd->length = B_HOST_TO_BENDIAN_INT16(numBlocks);

			request->cdb_length = sizeof(*cmd);
		} else if (offset + numBlocks < 0x100000000LL && numBlocks <= 0x10000000) {
			scsi_cmd_rw_12 *cmd = (scsi_cmd_rw_12 *)request->cdb;

			memset(cmd, 0, sizeof(*cmd));
			cmd->opcode = isWrite ? SCSI_OP_WRITE_12 : SCSI_OP_READ_12;
			cmd->relative_address = 0;
			cmd->force_unit_access = 0;
			cmd->disable_page_out = 0;
			cmd->lba = B_HOST_TO_BENDIAN_INT32(pos);
			cmd->length = B_HOST_TO_BENDIAN_INT32(numBlocks);

			request->cdb_length = sizeof(*cmd);
		} else {
			scsi_cmd_rw_16 *cmd = (scsi_cmd_rw_16 *)request->cdb;

			memset(cmd, 0, sizeof(*cmd));
			cmd->opcode = isWrite ? SCSI_OP_WRITE_16 : SCSI_OP_READ_16;
			cmd->force_unit_access_non_volatile = 0;
			cmd->force_unit_access = 0;
			cmd->disable_page_out = 0;
			cmd->lba = B_HOST_TO_BENDIAN_INT64(offset);
			cmd->length = B_HOST_TO_BENDIAN_INT32(numBlocks);

			request->cdb_length = sizeof(*cmd);
		}

		// TODO: last chance to detect errors that occured during concurrent accesses
		//status_t status = handle->pending_error;
		//if (status != B_OK)
		//	return status;

		device->scsi->async_io(request);

		acquire_sem(request->completion_sem);

		// ask generic peripheral layer what to do now
		res = periph_check_error(device, request);

		// TODO: bytes might have been transferred even in the error case!
		switch (res.action) {
			case err_act_ok:
				*_bytesTransferred = numBytes - request->data_resid;
				break;

			case err_act_start:
				res = periph_send_start_stop(device, request, 1,
					device->removable);
				if (res.action == err_act_ok)
					res.action = err_act_retry;
				break;

			case err_act_invalid_req:
				// if this was a 10 byte command, the device probably doesn't
				// support them, so disable them and retry
				if (isReadWrite10) {
					atomic_and(&device->rw10_enabled, 0);
					res.action = err_act_retry;
				} else
					res.action = err_act_fail;
				break;
		}
	} while ((res.action == err_act_retry && retries++ < 3)
Esempio n. 15
0
status_t Flap::AddInt16(int16 value) {
	int16 v = B_HOST_TO_BENDIAN_INT16(value);
	return AddRawData((uchar *)&v, sizeof(value));
};