145a206a7SAxel Dörfler/*
245a206a7SAxel Dörfler * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
345a206a7SAxel Dörfler * Copyright 2008, Axel D��rfler, axeld@pinc-software.de.
445a206a7SAxel Dörfler * Distributed under the terms of the MIT License.
545a206a7SAxel Dörfler */
645a206a7SAxel Dörfler
745a206a7SAxel Dörfler#include <stdio.h>
845a206a7SAxel Dörfler#include <string.h>
945a206a7SAxel Dörfler
1045a206a7SAxel Dörfler#include <device_manager.h>
1145a206a7SAxel Dörfler
12621f42cbSIngo Weinhold#include <vm/vm.h>
138faff60cSAxel Dörfler
1445a206a7SAxel Dörfler#include "dma_resources.h"
1545a206a7SAxel Dörfler#include "io_requests.h"
16621f42cbSIngo Weinhold#include "IOSchedulerSimple.h"
1745a206a7SAxel Dörfler
1845a206a7SAxel Dörfler
19025f7c32SIngo Weinhold#define DMA_TEST_BLOCK_SIZE				512
20025f7c32SIngo Weinhold#define DMA_TEST_BUFFER_COUNT			10
21025f7c32SIngo Weinhold#define DMA_TEST_BOUNCE_BUFFER_COUNT	128
2245a206a7SAxel Dörfler
2345a206a7SAxel Dörfler
248faff60cSAxel Dörflerclass TestSuite;
2545a206a7SAxel Dörfler
268faff60cSAxel Dörflerclass TestSuiteContext {
278faff60cSAxel Dörflerpublic:
288faff60cSAxel Dörfler							TestSuiteContext();
298faff60cSAxel Dörfler							~TestSuiteContext();
308faff60cSAxel Dörfler
31c3a9fa21SAxel Dörfler			status_t		Init(size_t size, bool contiguous = true);
3245a206a7SAxel Dörfler
338faff60cSAxel Dörfler			addr_t			DataBase() const { return fDataBase; }
348faff60cSAxel Dörfler			addr_t			PhysicalDataBase() const
358faff60cSAxel Dörfler								{ return fPhysicalDataBase; }
36c3a9fa21SAxel Dörfler			addr_t			SecondPhysicalDataBase() const
37c3a9fa21SAxel Dörfler								{ return fSecondPhysicalDataBase; }
38c3a9fa21SAxel Dörfler
39c3a9fa21SAxel Dörfler			bool			IsContiguous() const
40c3a9fa21SAxel Dörfler								{ return fSecondPhysicalDataBase == 0; }
418faff60cSAxel Dörfler
428faff60cSAxel Dörfler			addr_t			CompareBase() const { return fCompareBase; }
438faff60cSAxel Dörfler
448faff60cSAxel Dörfler			size_t			Size() const { return fSize; }
458faff60cSAxel Dörfler
468faff60cSAxel Dörflerprivate:
47c3a9fa21SAxel Dörfler			void			_Uninit();
48c3a9fa21SAxel Dörfler
498faff60cSAxel Dörfler			area_id			fDataArea;
508faff60cSAxel Dörfler			addr_t			fDataBase;
518faff60cSAxel Dörfler			addr_t			fPhysicalDataBase;
52c3a9fa21SAxel Dörfler			addr_t			fSecondPhysicalDataBase;
538faff60cSAxel Dörfler			area_id			fCompareArea;
548faff60cSAxel Dörfler			addr_t			fCompareBase;
558faff60cSAxel Dörfler			size_t			fSize;
568faff60cSAxel Dörfler};
5745a206a7SAxel Dörfler
5845a206a7SAxel Dörflerclass Test : public DoublyLinkedListLinkImpl<Test> {
5945a206a7SAxel Dörflerpublic:
608faff60cSAxel Dörfler							Test(TestSuite& suite, off_t offset, size_t length,
618faff60cSAxel Dörfler								bool isWrite, uint32 flags);
6245a206a7SAxel Dörfler
6345a206a7SAxel Dörfler			Test&			AddSource(addr_t base, size_t length);
6445a206a7SAxel Dörfler			Test&			NextResult(off_t offset, bool partialBegin,
6545a206a7SAxel Dörfler								bool partialEnd);
6645a206a7SAxel Dörfler			Test&			AddTarget(addr_t base, size_t length,
6745a206a7SAxel Dörfler								bool usesBounceBuffer);
6845a206a7SAxel Dörfler
6945a206a7SAxel Dörfler			void			Run(DMAResource& resource);
7045a206a7SAxel Dörfler
7145a206a7SAxel Dörflerprivate:
728faff60cSAxel Dörfler			addr_t			_SourceToVirtual(addr_t source);
738faff60cSAxel Dörfler			addr_t			_SourceToCompare(addr_t source);
748faff60cSAxel Dörfler			void			_Prepare();
758faff60cSAxel Dörfler			void			_CheckCompare();
768faff60cSAxel Dörfler			void			_CheckWrite();
778faff60cSAxel Dörfler			void			_CheckResults();
788faff60cSAxel Dörfler			status_t		_DoIO(IOOperation& operation);
7945a206a7SAxel Dörfler			void			_Panic(const char* message,...);
8045a206a7SAxel Dörfler
818faff60cSAxel Dörfler			TestSuite&		fSuite;
8245a206a7SAxel Dörfler			off_t			fOffset;
8345a206a7SAxel Dörfler			size_t			fLength;
8445a206a7SAxel Dörfler			bool			fIsWrite;
8545a206a7SAxel Dörfler			uint32			fFlags;
86621f42cbSIngo Weinhold			generic_io_vec	fSourceVecs[32];
8745a206a7SAxel Dörfler			uint32			fSourceCount;
8845a206a7SAxel Dörfler
8945a206a7SAxel Dörfler			struct target_t {
9045a206a7SAxel Dörfler				addr_t		address;
9145a206a7SAxel Dörfler				size_t		length;
9245a206a7SAxel Dörfler				bool		uses_bounce_buffer;
9345a206a7SAxel Dörfler			};
9445a206a7SAxel Dörfler			struct result_t {
9545a206a7SAxel Dörfler				off_t		offset;
9645a206a7SAxel Dörfler				target_t	targets[32];
9745a206a7SAxel Dörfler				uint32		count;
9845a206a7SAxel Dörfler				bool		partial_begin;
9945a206a7SAxel Dörfler				bool		partial_end;
10045a206a7SAxel Dörfler			};
10145a206a7SAxel Dörfler			result_t		fResults[32];
10245a206a7SAxel Dörfler			uint32			fResultCount;
10345a206a7SAxel Dörfler};
10445a206a7SAxel Dörfler
10545a206a7SAxel Dörflertypedef DoublyLinkedList<Test> TestList;
10645a206a7SAxel Dörfler
10745a206a7SAxel Dörfler
10845a206a7SAxel Dörflerclass TestSuite {
10945a206a7SAxel Dörflerpublic:
1108faff60cSAxel Dörfler	TestSuite(TestSuiteContext& context, const char* name,
1118faff60cSAxel Dörfler			const dma_restrictions& restrictions, size_t blockSize)
11245a206a7SAxel Dörfler		:
1138faff60cSAxel Dörfler		fContext(context)
11445a206a7SAxel Dörfler	{
11545a206a7SAxel Dörfler		dprintf("----- Run \"%s\" tests ---------------------------\n", name);
116621f42cbSIngo Weinhold		dprintf("  DMA restrictions: address %#" B_PRIxGENADDR " - %#"
117621f42cbSIngo Weinhold			B_PRIxGENADDR ", align %" B_PRIuGENADDR ", boundary %" B_PRIuGENADDR
118621f42cbSIngo Weinhold			",\n    max transfer %" B_PRIuGENADDR ", max segs %" B_PRIx32
119621f42cbSIngo Weinhold			", max seg size %" B_PRIxGENADDR ", flags %" B_PRIx32 "\n\n",
120621f42cbSIngo Weinhold			restrictions.low_address, restrictions.high_address,
121621f42cbSIngo Weinhold			restrictions.alignment, restrictions.boundary,
122621f42cbSIngo Weinhold			restrictions.max_transfer_size, restrictions.max_segment_count,
123621f42cbSIngo Weinhold			restrictions.max_segment_size, restrictions.flags);
12445a206a7SAxel Dörfler
125025f7c32SIngo Weinhold		status_t status = fDMAResource.Init(restrictions, blockSize, 10, 10);
12645a206a7SAxel Dörfler		if (status != B_OK)
12745a206a7SAxel Dörfler			panic("initializing DMA resource failed: %s\n", strerror(status));
12845a206a7SAxel Dörfler	}
12945a206a7SAxel Dörfler
13045a206a7SAxel Dörfler	~TestSuite()
13145a206a7SAxel Dörfler	{
13245a206a7SAxel Dörfler		while (Test* test = fTests.RemoveHead()) {
13345a206a7SAxel Dörfler			delete test;
13445a206a7SAxel Dörfler		}
13545a206a7SAxel Dörfler	}
13645a206a7SAxel Dörfler
13745a206a7SAxel Dörfler	Test& AddTest(off_t offset, size_t length, bool isWrite, uint32 flags)
13845a206a7SAxel Dörfler	{
1398faff60cSAxel Dörfler		Test* test = new(std::nothrow) Test(*this, offset, length, isWrite,
1408faff60cSAxel Dörfler			flags);
14145a206a7SAxel Dörfler		fTests.Add(test);
14245a206a7SAxel Dörfler
14345a206a7SAxel Dörfler		return *test;
14445a206a7SAxel Dörfler	}
14545a206a7SAxel Dörfler
14645a206a7SAxel Dörfler	void Run()
14745a206a7SAxel Dörfler	{
14845a206a7SAxel Dörfler		TestList::Iterator iterator = fTests.GetIterator();
14945a206a7SAxel Dörfler		uint32 count = 1;
15045a206a7SAxel Dörfler		while (Test* test = iterator.Next()) {
15145a206a7SAxel Dörfler			dprintf("test %lu...\n", count++);
15245a206a7SAxel Dörfler			test->Run(fDMAResource);
15345a206a7SAxel Dörfler		}
15445a206a7SAxel Dörfler	}
15545a206a7SAxel Dörfler
1568faff60cSAxel Dörfler	addr_t DataBase() const { return fContext.DataBase(); }
1578faff60cSAxel Dörfler	addr_t PhysicalDataBase() const { return fContext.PhysicalDataBase(); }
158c3a9fa21SAxel Dörfler	addr_t SecondPhysicalDataBase() const
159c3a9fa21SAxel Dörfler		{ return fContext.SecondPhysicalDataBase(); }
160c3a9fa21SAxel Dörfler	bool IsContiguous() const { return fContext.IsContiguous(); }
1618faff60cSAxel Dörfler	addr_t CompareBase() const { return fContext.CompareBase(); }
1628faff60cSAxel Dörfler	size_t Size() const { return fContext.Size(); }
1638faff60cSAxel Dörfler
16445a206a7SAxel Dörflerprivate:
1658faff60cSAxel Dörfler	TestSuiteContext& fContext;
16645a206a7SAxel Dörfler	DMAResource		fDMAResource;
16745a206a7SAxel Dörfler	uint8*			fBase;
16845a206a7SAxel Dörfler	uint8*			fPhysicalBase;
1698faff60cSAxel Dörfler	size_t			fSize;
17045a206a7SAxel Dörfler	TestList		fTests;
17145a206a7SAxel Dörfler};
17245a206a7SAxel Dörfler
17345a206a7SAxel Dörfler
1748faff60cSAxel Dörflerstruct device_manager_info* sDeviceManager;
1758faff60cSAxel Dörfler
1768faff60cSAxel Dörflerstatic area_id sArea;
1778faff60cSAxel Dörflerstatic size_t sAreaSize;
1788faff60cSAxel Dörflerstatic void* sAreaAddress;
1798faff60cSAxel Dörflerstatic DMAResource* sDMAResource;
18033f9067bSAxel Dörflerstatic IOScheduler* sIOScheduler;
18133f9067bSAxel Dörfler
18233f9067bSAxel Dörfler
18333f9067bSAxel Dörflerstatus_t
18433f9067bSAxel Dörflerdo_io(void* data, IOOperation* operation)
18533f9067bSAxel Dörfler{
18633f9067bSAxel Dörfler	uint8* disk = (uint8*)sAreaAddress;
18733f9067bSAxel Dörfler	off_t offset = operation->Offset();
18833f9067bSAxel Dörfler
18933f9067bSAxel Dörfler	for (uint32 i = 0; i < operation->VecCount(); i++) {
190621f42cbSIngo Weinhold		const generic_io_vec& vec = operation->Vecs()[i];
191621f42cbSIngo Weinhold		generic_addr_t base = vec.base;
192621f42cbSIngo Weinhold		generic_size_t length = vec.length;
19333f9067bSAxel Dörfler
19453cce89bSIngo Weinhold		if (operation->IsWrite())
19553cce89bSIngo Weinhold			vm_memcpy_from_physical(disk + offset, base, length, false);
19653cce89bSIngo Weinhold		else
19753cce89bSIngo Weinhold			vm_memcpy_to_physical(base, disk + offset, length, false);
19833f9067bSAxel Dörfler	}
19933f9067bSAxel Dörfler
20033f9067bSAxel Dörfler	if (sIOScheduler != NULL)
2017f12cc54SIngo Weinhold		sIOScheduler->OperationCompleted(operation, B_OK, operation->Length());
20233f9067bSAxel Dörfler	return B_OK;
20333f9067bSAxel Dörfler}
20433f9067bSAxel Dörfler
20533f9067bSAxel Dörfler
20633f9067bSAxel Dörfler//	#pragma mark -
2078faff60cSAxel Dörfler
2088faff60cSAxel Dörfler
2098faff60cSAxel DörflerTestSuiteContext::TestSuiteContext()
21045a206a7SAxel Dörfler	:
2118faff60cSAxel Dörfler	fDataArea(-1),
2128faff60cSAxel Dörfler	fCompareArea(-1),
2138faff60cSAxel Dörfler	fSize(0)
2148faff60cSAxel Dörfler{
2158faff60cSAxel Dörfler}
2168faff60cSAxel Dörfler
2178faff60cSAxel Dörfler
2188faff60cSAxel DörflerTestSuiteContext::~TestSuiteContext()
219c3a9fa21SAxel Dörfler{
220c3a9fa21SAxel Dörfler	_Uninit();
221c3a9fa21SAxel Dörfler}
222c3a9fa21SAxel Dörfler
223c3a9fa21SAxel Dörfler
224c3a9fa21SAxel Dörflervoid
225c3a9fa21SAxel DörflerTestSuiteContext::_Uninit()
2268faff60cSAxel Dörfler{
2278faff60cSAxel Dörfler	delete_area(fDataArea);
2288faff60cSAxel Dörfler	delete_area(fCompareArea);
2298faff60cSAxel Dörfler}
2308faff60cSAxel Dörfler
2318faff60cSAxel Dörfler
2328faff60cSAxel Dörflerstatus_t
233c3a9fa21SAxel DörflerTestSuiteContext::Init(size_t size, bool contiguous)
2348faff60cSAxel Dörfler{
235c3a9fa21SAxel Dörfler	if (!contiguous) {
236c3a9fa21SAxel Dörfler		// we can't force this, so we have to try and see
237c3a9fa21SAxel Dörfler
238c3a9fa21SAxel Dörfler		if (size != B_PAGE_SIZE * 2)
239c3a9fa21SAxel Dörfler			return B_NOT_SUPPORTED;
240c3a9fa21SAxel Dörfler
241c3a9fa21SAxel Dörfler		while (true) {
242c3a9fa21SAxel Dörfler			fDataArea = create_area("data buffer", (void**)&fDataBase,
243c3a9fa21SAxel Dörfler				B_ANY_KERNEL_ADDRESS, size, B_FULL_LOCK,
244c3a9fa21SAxel Dörfler				B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
245c3a9fa21SAxel Dörfler			if (fDataArea < B_OK)
246c3a9fa21SAxel Dörfler				return fDataArea;
247c3a9fa21SAxel Dörfler
248c3a9fa21SAxel Dörfler			// get memory map to see if we succeeded
2498faff60cSAxel Dörfler
250c3a9fa21SAxel Dörfler			physical_entry entry[2];
251c3a9fa21SAxel Dörfler			get_memory_map((void*)fDataBase, 2 * B_PAGE_SIZE, entry, 2);
2528faff60cSAxel Dörfler
253c3a9fa21SAxel Dörfler			if (entry[0].size == B_PAGE_SIZE) {
254c3a9fa21SAxel Dörfler				fPhysicalDataBase = (addr_t)entry[0].address;
255c3a9fa21SAxel Dörfler				fSecondPhysicalDataBase = (addr_t)entry[1].address;
256c3a9fa21SAxel Dörfler
257621f42cbSIngo Weinhold				dprintf("DMA Test area %p, physical %#" B_PRIxPHYSADDR
258621f42cbSIngo Weinhold					", second physical %#" B_PRIxPHYSADDR "\n",
259c3a9fa21SAxel Dörfler					(void*)fDataBase, entry[0].address, entry[1].address);
260c3a9fa21SAxel Dörfler				break;
261c3a9fa21SAxel Dörfler			}
262c3a9fa21SAxel Dörfler
263c3a9fa21SAxel Dörfler			// try again
264c3a9fa21SAxel Dörfler			delete_area(fDataArea);
265c3a9fa21SAxel Dörfler		}
266c3a9fa21SAxel Dörfler	} else {
267c3a9fa21SAxel Dörfler		fDataArea = create_area("data buffer", (void**)&fDataBase,
268c3a9fa21SAxel Dörfler			B_ANY_KERNEL_ADDRESS, size, B_CONTIGUOUS,
269c3a9fa21SAxel Dörfler			B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
270c3a9fa21SAxel Dörfler		if (fDataArea < B_OK)
271c3a9fa21SAxel Dörfler			return fDataArea;
272c3a9fa21SAxel Dörfler
273c3a9fa21SAxel Dörfler		physical_entry entry;
274c3a9fa21SAxel Dörfler		get_memory_map((void*)fDataBase, B_PAGE_SIZE, &entry, 1);
275c3a9fa21SAxel Dörfler
276c3a9fa21SAxel Dörfler		fPhysicalDataBase = (addr_t)entry.address;
277c3a9fa21SAxel Dörfler		fSecondPhysicalDataBase = 0;
278c3a9fa21SAxel Dörfler
279621f42cbSIngo Weinhold		dprintf("DMA Test area %p, physical %#" B_PRIxPHYSADDR "\n",
280621f42cbSIngo Weinhold			(void*)fDataBase, entry.address);
281c3a9fa21SAxel Dörfler	}
2828faff60cSAxel Dörfler
2838faff60cSAxel Dörfler	fCompareArea = create_area("compare buffer", (void**)&fCompareBase,
2848faff60cSAxel Dörfler		B_ANY_KERNEL_ADDRESS, size, B_FULL_LOCK,
2858faff60cSAxel Dörfler		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
2868faff60cSAxel Dörfler	if (fCompareArea < B_OK)
2878faff60cSAxel Dörfler		return fCompareArea;
2888faff60cSAxel Dörfler
2898faff60cSAxel Dörfler	fSize = size;
2908faff60cSAxel Dörfler	return B_OK;
2918faff60cSAxel Dörfler}
2928faff60cSAxel Dörfler
2938faff60cSAxel Dörfler
2948faff60cSAxel Dörfler//	#pragma mark -
2958faff60cSAxel Dörfler
2968faff60cSAxel Dörfler
2978faff60cSAxel DörflerTest::Test(TestSuite& suite, off_t offset, size_t length, bool isWrite,
2988faff60cSAxel Dörfler		uint32 flags)
2998faff60cSAxel Dörfler	:
3008faff60cSAxel Dörfler	fSuite(suite),
30145a206a7SAxel Dörfler	fOffset(offset),
30245a206a7SAxel Dörfler	fLength(length),
30345a206a7SAxel Dörfler	fIsWrite(isWrite),
30445a206a7SAxel Dörfler	fFlags(flags),
30545a206a7SAxel Dörfler	fSourceCount(0),
30645a206a7SAxel Dörfler	fResultCount(0)
30745a206a7SAxel Dörfler{
30845a206a7SAxel Dörfler}
30945a206a7SAxel Dörfler
31045a206a7SAxel Dörfler
31145a206a7SAxel DörflerTest&
31245a206a7SAxel DörflerTest::AddSource(addr_t address, size_t length)
31345a206a7SAxel Dörfler{
314c3a9fa21SAxel Dörfler	if (fSuite.IsContiguous() || (fFlags & B_PHYSICAL_IO_REQUEST) != 0
315c3a9fa21SAxel Dörfler		|| address < B_PAGE_SIZE) {
316621f42cbSIngo Weinhold		fSourceVecs[fSourceCount].base
317621f42cbSIngo Weinhold			= ((fFlags & B_PHYSICAL_IO_REQUEST) == 0
318621f42cbSIngo Weinhold				? fSuite.DataBase() : fSuite.PhysicalDataBase()) + address;
319c3a9fa21SAxel Dörfler	} else {
320621f42cbSIngo Weinhold		fSourceVecs[fSourceCount].base
321621f42cbSIngo Weinhold			= fSuite.SecondPhysicalDataBase() + address;
322c3a9fa21SAxel Dörfler	}
323621f42cbSIngo Weinhold	fSourceVecs[fSourceCount].length = length;
32445a206a7SAxel Dörfler	fSourceCount++;
32545a206a7SAxel Dörfler
32645a206a7SAxel Dörfler	return *this;
32745a206a7SAxel Dörfler}
32845a206a7SAxel Dörfler
32945a206a7SAxel Dörfler
33045a206a7SAxel DörflerTest&
33145a206a7SAxel DörflerTest::NextResult(off_t offset, bool partialBegin, bool partialEnd)
33245a206a7SAxel Dörfler{
33345a206a7SAxel Dörfler	fResults[fResultCount].offset = offset;
33445a206a7SAxel Dörfler	fResults[fResultCount].count = 0;
33545a206a7SAxel Dörfler	fResults[fResultCount].partial_begin = partialBegin;
33645a206a7SAxel Dörfler	fResults[fResultCount].partial_end = partialEnd;
33745a206a7SAxel Dörfler	fResultCount++;
33845a206a7SAxel Dörfler
33945a206a7SAxel Dörfler	return *this;
34045a206a7SAxel Dörfler}
34145a206a7SAxel Dörfler
34245a206a7SAxel Dörfler
34345a206a7SAxel DörflerTest&
34445a206a7SAxel DörflerTest::AddTarget(addr_t base, size_t length, bool usesBounceBuffer)
34545a206a7SAxel Dörfler{
34645a206a7SAxel Dörfler	struct result_t& result = fResults[fResultCount - 1];
34745a206a7SAxel Dörfler	struct target_t& target = result.targets[result.count++];
34845a206a7SAxel Dörfler
34945a206a7SAxel Dörfler	target.address = base;
35045a206a7SAxel Dörfler	target.length = length;
35145a206a7SAxel Dörfler	target.uses_bounce_buffer = usesBounceBuffer;
35245a206a7SAxel Dörfler
35345a206a7SAxel Dörfler	return *this;
35445a206a7SAxel Dörfler}
35545a206a7SAxel Dörfler
35645a206a7SAxel Dörfler
3578faff60cSAxel Dörfleraddr_t
3588faff60cSAxel DörflerTest::_SourceToVirtual(addr_t source)
3598faff60cSAxel Dörfler{
360c3a9fa21SAxel Dörfler	if ((fFlags & B_PHYSICAL_IO_REQUEST) != 0) {
361c3a9fa21SAxel Dörfler		if (!fSuite.IsContiguous() && source >= B_PAGE_SIZE)
362c3a9fa21SAxel Dörfler			return source - fSuite.SecondPhysicalDataBase() + fSuite.DataBase();
363c3a9fa21SAxel Dörfler
3648faff60cSAxel Dörfler		return source - fSuite.PhysicalDataBase() + fSuite.DataBase();
365c3a9fa21SAxel Dörfler	}
3668faff60cSAxel Dörfler
3678faff60cSAxel Dörfler	return source;
3688faff60cSAxel Dörfler}
3698faff60cSAxel Dörfler
3708faff60cSAxel Dörfler
3718faff60cSAxel Dörfleraddr_t
3728faff60cSAxel DörflerTest::_SourceToCompare(addr_t source)
3738faff60cSAxel Dörfler{
374c3a9fa21SAxel Dörfler	if ((fFlags & B_PHYSICAL_IO_REQUEST) != 0) {
375c3a9fa21SAxel Dörfler		if (!fSuite.IsContiguous() && source >= B_PAGE_SIZE) {
376c3a9fa21SAxel Dörfler			return source - fSuite.SecondPhysicalDataBase()
377c3a9fa21SAxel Dörfler				+ fSuite.CompareBase();
378c3a9fa21SAxel Dörfler		}
379c3a9fa21SAxel Dörfler
3808faff60cSAxel Dörfler		return source - fSuite.PhysicalDataBase() + fSuite.CompareBase();
381c3a9fa21SAxel Dörfler	}
3828faff60cSAxel Dörfler
3838faff60cSAxel Dörfler	return source - fSuite.DataBase() + fSuite.CompareBase();
3848faff60cSAxel Dörfler}
3858faff60cSAxel Dörfler
3868faff60cSAxel Dörfler
3878faff60cSAxel Dörflervoid
3888faff60cSAxel DörflerTest::_Prepare()
3898faff60cSAxel Dörfler{
3908faff60cSAxel Dörfler	// prepare disk
3918faff60cSAxel Dörfler
3928faff60cSAxel Dörfler	uint8* disk = (uint8*)sAreaAddress;
3938faff60cSAxel Dörfler	for (size_t i = 0; i < sAreaSize; i++) {
3948faff60cSAxel Dörfler		disk[i] = i % 26 + 'a';
3958faff60cSAxel Dörfler	}
3968faff60cSAxel Dörfler
3978faff60cSAxel Dörfler	// prepare data
3988faff60cSAxel Dörfler
3998faff60cSAxel Dörfler	memset((void*)fSuite.DataBase(), 0xcc, fSuite.Size());
4008faff60cSAxel Dörfler
4018faff60cSAxel Dörfler	if (fIsWrite) {
4028faff60cSAxel Dörfler		off_t offset = fOffset;
4038faff60cSAxel Dörfler		size_t length = fLength;
4048faff60cSAxel Dörfler
4058faff60cSAxel Dörfler		for (uint32 i = 0; i < fSourceCount; i++) {
406621f42cbSIngo Weinhold			uint8* data = (uint8*)_SourceToVirtual(fSourceVecs[i].base);
407621f42cbSIngo Weinhold			size_t vecLength = min_c(fSourceVecs[i].length, length);
4088faff60cSAxel Dörfler
4098faff60cSAxel Dörfler			for (uint32 j = 0; j < vecLength; j++) {
4108faff60cSAxel Dörfler				data[j] = (offset + j) % 10 + '0';
4118faff60cSAxel Dörfler			}
4128faff60cSAxel Dörfler			offset += vecLength;
4138faff60cSAxel Dörfler			length -= vecLength;
4148faff60cSAxel Dörfler		}
4158faff60cSAxel Dörfler	}
4168faff60cSAxel Dörfler
4178faff60cSAxel Dörfler	// prepare compare data
4188faff60cSAxel Dörfler
4198faff60cSAxel Dörfler	memset((void*)fSuite.CompareBase(), 0xcc, fSuite.Size());
4208faff60cSAxel Dörfler
4218faff60cSAxel Dörfler	if (fIsWrite) {
4228faff60cSAxel Dörfler		// copy data from source
4238faff60cSAxel Dörfler		off_t offset = fOffset;
4248faff60cSAxel Dörfler		size_t length = fLength;
4258faff60cSAxel Dörfler
4268faff60cSAxel Dörfler		for (uint32 i = 0; i < fSourceCount; i++) {
427621f42cbSIngo Weinhold			uint8* compare = (uint8*)_SourceToCompare(fSourceVecs[i].base);
428621f42cbSIngo Weinhold			size_t vecLength = min_c(fSourceVecs[i].length, length);
4298faff60cSAxel Dörfler
430621f42cbSIngo Weinhold			memcpy(compare, (void*)_SourceToVirtual(fSourceVecs[i].base),
4318faff60cSAxel Dörfler				vecLength);
4328faff60cSAxel Dörfler			offset += vecLength;
4338faff60cSAxel Dörfler			length -= vecLength;
4348faff60cSAxel Dörfler		}
4358faff60cSAxel Dörfler	} else {
4368faff60cSAxel Dörfler		// copy data from drive
4378faff60cSAxel Dörfler		off_t offset = fOffset;
4388faff60cSAxel Dörfler		size_t length = fLength;
4398faff60cSAxel Dörfler
4408faff60cSAxel Dörfler		for (uint32 i = 0; i < fSourceCount; i++) {
441621f42cbSIngo Weinhold			uint8* compare = (uint8*)_SourceToCompare(fSourceVecs[i].base);
442621f42cbSIngo Weinhold			size_t vecLength = min_c(fSourceVecs[i].length, length);
4438faff60cSAxel Dörfler
4448faff60cSAxel Dörfler			memcpy(compare, disk + offset, vecLength);
4458faff60cSAxel Dörfler			offset += vecLength;
4468faff60cSAxel Dörfler			length -= vecLength;
4478faff60cSAxel Dörfler		}
4488faff60cSAxel Dörfler	}
4498faff60cSAxel Dörfler
4508faff60cSAxel Dörfler	if (fIsWrite)
4518faff60cSAxel Dörfler		_CheckCompare();
4528faff60cSAxel Dörfler}
4538faff60cSAxel Dörfler
4548faff60cSAxel Dörfler
4558faff60cSAxel Dörflervoid
4568faff60cSAxel DörflerTest::_CheckCompare()
4578faff60cSAxel Dörfler{
4588faff60cSAxel Dörfler	uint8* data = (uint8*)fSuite.DataBase();
4598faff60cSAxel Dörfler	uint8* compare = (uint8*)fSuite.CompareBase();
4608faff60cSAxel Dörfler
4618faff60cSAxel Dörfler	for (size_t i = 0; i < fSuite.Size(); i++) {
4628faff60cSAxel Dörfler		if (data[i] != compare[i]) {
4638faff60cSAxel Dörfler			dprintf("offset %lu differs, %s:\n", i,
4648faff60cSAxel Dörfler				fIsWrite ? "write" : "read");
4658faff60cSAxel Dörfler			i &= ~63;
4668faff60cSAxel Dörfler			dump_block((char*)&data[i], min_c(64, fSuite.Size() - i), "  ");
4678faff60cSAxel Dörfler			dprintf("should be:\n");
4688faff60cSAxel Dörfler			dump_block((char*)&compare[i], min_c(64, fSuite.Size() - i), "  ");
4698faff60cSAxel Dörfler
4708faff60cSAxel Dörfler			_Panic("Data %s differs", fIsWrite ? "write" : "read");
4718faff60cSAxel Dörfler		}
4728faff60cSAxel Dörfler	}
4738faff60cSAxel Dörfler}
4748faff60cSAxel Dörfler
4758faff60cSAxel Dörfler
4768faff60cSAxel Dörflervoid
4778faff60cSAxel DörflerTest::_CheckWrite()
4788faff60cSAxel Dörfler{
4798faff60cSAxel Dörfler	_CheckCompare();
4808faff60cSAxel Dörfler
4818faff60cSAxel Dörfler	// check if we overwrote parts we shouldn't have
4828faff60cSAxel Dörfler
483