1aa4ba93eSIngo Weinhold/*
24535495dSIngo Weinhold * Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
399ccb18dSAxel Dörfler * Copyright 2008-2017, Axel D��rfler, axeld@pinc-software.de.
4aa4ba93eSIngo Weinhold * Distributed under the terms of the MIT License.
5aa4ba93eSIngo Weinhold */
6aa4ba93eSIngo Weinhold
7435c43f5SIngo Weinhold
8aa4ba93eSIngo Weinhold#include "IORequest.h"
9aa4ba93eSIngo Weinhold
10aa4ba93eSIngo Weinhold#include <string.h>
11aa4ba93eSIngo Weinhold
12aa4ba93eSIngo Weinhold#include <arch/debug.h>
13aa4ba93eSIngo Weinhold#include <debug.h>
14aa4ba93eSIngo Weinhold#include <heap.h>
15aa4ba93eSIngo Weinhold#include <kernel.h>
16c63b3de6SIngo Weinhold#include <team.h>
17aa4ba93eSIngo Weinhold#include <thread.h>
18aa4ba93eSIngo Weinhold#include <util/AutoLock.h>
19e50cf876SIngo Weinhold#include <vm/vm.h>
20e50cf876SIngo Weinhold#include <vm/VMAddressSpace.h>
21aa4ba93eSIngo Weinhold
22aa4ba93eSIngo Weinhold#include "dma_resources.h"
23aa4ba93eSIngo Weinhold
24aa4ba93eSIngo Weinhold
25aa4ba93eSIngo Weinhold//#define TRACE_IO_REQUEST
26aa4ba93eSIngo Weinhold#ifdef TRACE_IO_REQUEST
27aa4ba93eSIngo Weinhold#	define TRACE(x...) dprintf(x)
28aa4ba93eSIngo Weinhold#else
29aa4ba93eSIngo Weinhold#	define TRACE(x...) ;
30aa4ba93eSIngo Weinhold#endif
31aa4ba93eSIngo Weinhold
32aa4ba93eSIngo Weinhold
33aa4ba93eSIngo Weinhold// partial I/O operation phases
34aa4ba93eSIngo Weinholdenum {
35aa4ba93eSIngo Weinhold	PHASE_READ_BEGIN	= 0,
36aa4ba93eSIngo Weinhold	PHASE_READ_END		= 1,
37aa4ba93eSIngo Weinhold	PHASE_DO_ALL		= 2
38aa4ba93eSIngo Weinhold};
39aa4ba93eSIngo Weinhold
40aa4ba93eSIngo Weinhold
4199ccb18dSAxel Dörflerstruct virtual_vec_cookie {
4299ccb18dSAxel Dörfler	uint32			vec_index;
4399ccb18dSAxel Dörfler	generic_size_t	vec_offset;
4499ccb18dSAxel Dörfler	area_id			mapped_area;
4599ccb18dSAxel Dörfler	void*			physical_page_handle;
4699ccb18dSAxel Dörfler	addr_t			virtual_address;
4799ccb18dSAxel Dörfler
4899ccb18dSAxel Dörfler	virtual_vec_cookie()
4999ccb18dSAxel Dörfler		:
5099ccb18dSAxel Dörfler		vec_index(0),
5199ccb18dSAxel Dörfler		vec_offset(0),
5299ccb18dSAxel Dörfler		mapped_area(-1),
5399ccb18dSAxel Dörfler		physical_page_handle(NULL),
5499ccb18dSAxel Dörfler		virtual_address((addr_t)-1)
5599ccb18dSAxel Dörfler	{
5699ccb18dSAxel Dörfler	}
5799ccb18dSAxel Dörfler
5899ccb18dSAxel Dörfler	void PutPhysicalPageIfNeeded()
5999ccb18dSAxel Dörfler	{
6099ccb18dSAxel Dörfler		if (virtual_address != (addr_t)-1) {
6199ccb18dSAxel Dörfler			vm_put_physical_page(virtual_address, physical_page_handle);
6299ccb18dSAxel Dörfler			virtual_address = (addr_t)-1;
6399ccb18dSAxel Dörfler		}
6499ccb18dSAxel Dörfler	}
6599ccb18dSAxel Dörfler};
6699ccb18dSAxel Dörfler
6799ccb18dSAxel Dörfler
68aa4ba93eSIngo Weinhold// #pragma mark -
69aa4ba93eSIngo Weinhold
70aa4ba93eSIngo Weinhold
71aa4ba93eSIngo WeinholdIORequestChunk::IORequestChunk()
72aa4ba93eSIngo Weinhold	:
73aa4ba93eSIngo Weinhold	fParent(NULL),
74aa4ba93eSIngo Weinhold	fStatus(1)
75aa4ba93eSIngo Weinhold{
76aa4ba93eSIngo Weinhold}
77aa4ba93eSIngo Weinhold
78aa4ba93eSIngo Weinhold
79aa4ba93eSIngo WeinholdIORequestChunk::~IORequestChunk()
80aa4ba93eSIngo Weinhold{
81aa4ba93eSIngo Weinhold}
82aa4ba93eSIngo Weinhold
83aa4ba93eSIngo Weinhold
84aa4ba93eSIngo Weinhold//	#pragma mark -
85aa4ba93eSIngo Weinhold
86aa4ba93eSIngo Weinhold
87aa4ba93eSIngo WeinholdIOBuffer*
88aa4ba93eSIngo WeinholdIOBuffer::Create(uint32 count, bool vip)
89aa4ba93eSIngo Weinhold{
90435c43f5SIngo Weinhold	size_t size = sizeof(IOBuffer) + sizeof(generic_io_vec) * (count - 1);
91aa4ba93eSIngo Weinhold	IOBuffer* buffer
92deee8524SIngo Weinhold		= (IOBuffer*)(malloc_etc(size, vip ? HEAP_PRIORITY_VIP : 0));
93aa4ba93eSIngo Weinhold	if (buffer == NULL)
94aa4ba93eSIngo Weinhold		return NULL;
95aa4ba93eSIngo Weinhold
96aa4ba93eSIngo Weinhold	buffer->fCapacity = count;
97aa4ba93eSIngo Weinhold	buffer->fVecCount = 0;
98aa4ba93eSIngo Weinhold	buffer->fUser = false;
99aa4ba93eSIngo Weinhold	buffer->fPhysical = false;
100aa4ba93eSIngo Weinhold	buffer->fVIP = vip;
101aa4ba93eSIngo Weinhold	buffer->fMemoryLocked = false;
102aa4ba93eSIngo Weinhold
103aa4ba93eSIngo Weinhold	return buffer;
104aa4ba93eSIngo Weinhold}
105aa4ba93eSIngo Weinhold
106aa4ba93eSIngo Weinhold
107aa4ba93eSIngo Weinholdvoid
108aa4ba93eSIngo WeinholdIOBuffer::Delete()
109aa4ba93eSIngo Weinhold{
110deee8524SIngo Weinhold	free_etc(this, fVIP ? HEAP_PRIORITY_VIP : 0);
111aa4ba93eSIngo Weinhold}
112aa4ba93eSIngo Weinhold
113aa4ba93eSIngo Weinhold
114aa4ba93eSIngo Weinholdvoid
115435c43f5SIngo WeinholdIOBuffer::SetVecs(generic_size_t firstVecOffset, const generic_io_vec* vecs,
116435c43f5SIngo Weinhold	uint32 count, generic_size_t length, uint32 flags)
117aa4ba93eSIngo Weinhold{
118435c43f5SIngo Weinhold	memcpy(fVecs, vecs, sizeof(generic_io_vec) * count);
119435c43f5SIngo Weinhold
120aa4ba93eSIngo Weinhold	if (count > 0 && firstVecOffset > 0) {
121435c43f5SIngo Weinhold		fVecs[0].base += firstVecOffset;
122435c43f5SIngo Weinhold		fVecs[0].length -= firstVecOffset;
123aa4ba93eSIngo Weinhold	}
124aa4ba93eSIngo Weinhold
125aa4ba93eSIngo Weinhold	fVecCount = count;
126aa4ba93eSIngo Weinhold	fLength = length;
127aa4ba93eSIngo Weinhold	fPhysical = (flags & B_PHYSICAL_IO_REQUEST) != 0;
128435c43f5SIngo Weinhold	fUser = !fPhysical && IS_USER_ADDRESS(vecs[0].base);
129aa4ba93eSIngo Weinhold}
130aa4ba93eSIngo Weinhold
131aa4ba93eSIngo Weinhold
13232e2b6a1SMichael Lotzstatus_t
13332e2b6a1SMichael LotzIOBuffer::GetNextVirtualVec(void*& _cookie, iovec& vector)
13432e2b6a1SMichael Lotz{
13532e2b6a1SMichael Lotz	virtual_vec_cookie* cookie = (virtual_vec_cookie*)_cookie;
13632e2b6a1SMichael Lotz	if (cookie == NULL) {
137deee8524SIngo Weinhold		cookie = new(malloc_flags(fVIP ? HEAP_PRIORITY_VIP : 0))
138deee8524SIngo Weinhold			virtual_vec_cookie;
13932e2b6a1SMichael Lotz		if (cookie == NULL)
14032e2b6a1SMichael Lotz			return B_NO_MEMORY;
14132e2b6a1SMichael Lotz
14232e2b6a1SMichael Lotz		_cookie = cookie;
14332e2b6a1SMichael Lotz	}
14432e2b6a1SMichael Lotz
14532e2b6a1SMichael Lotz	// recycle a potential previously mapped page
14699ccb18dSAxel Dörfler	cookie->PutPhysicalPageIfNeeded();
14732e2b6a1SMichael Lotz
14832e2b6a1SMichael Lotz	if (cookie->vec_index >= fVecCount)
14932e2b6a1SMichael Lotz		return B_BAD_INDEX;
15032e2b6a1SMichael Lotz
15132e2b6a1SMichael Lotz	if (!fPhysical) {
152435c43f5SIngo Weinhold		vector.iov_base = (void*)(addr_t)fVecs[cookie->vec_index].base;
153435c43f5SIngo Weinhold		vector.iov_len = fVecs[cookie->vec_index++].length;
15432e2b6a1SMichael Lotz		return B_OK;
15532e2b6a1SMichael Lotz	}
15632e2b6a1SMichael Lotz
15732e2b6a1SMichael Lotz	if (cookie->vec_index == 0
158435c43f5SIngo Weinhold		&& (fVecCount > 1 || fVecs[0].length > B_PAGE_SIZE)) {
15932e2b6a1SMichael Lotz		void* mappedAddress;
16032e2b6a1SMichael Lotz		addr_t mappedSize;
16132e2b6a1SMichael Lotz
162d4af8f3eSIngo Weinhold// TODO: This is a potential violation of the VIP requirement, since
163d4af8f3eSIngo Weinhold// vm_map_physical_memory_vecs() allocates memory without special flags!
16432e2b6a1SMichael Lotz		cookie->mapped_area = vm_map_physical_memory_vecs(
16590d870c1SIngo Weinhold			VMAddressSpace::KernelID(), "io buffer mapped physical vecs",
16632e2b6a1SMichael Lotz			&mappedAddress, B_ANY_KERNEL_ADDRESS, &mappedSize,
16732e2b6a1SMichael Lotz			B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, fVecs, fVecCount);
16832e2b6a1SMichael Lotz
16932e2b6a1SMichael Lotz		if (cookie->mapped_area >= 0) {
170435c43f5SIngo Weinhold			vector.iov_base = mappedAddress;
17132e2b6a1SMichael Lotz			vector.iov_len = mappedSize;
17232e2b6a1SMichael Lotz			return B_OK;
17332e2b6a1SMichael Lotz		} else
17432e2b6a1SMichael Lotz			ktrace_printf("failed to map area: %s\n", strerror(cookie->mapped_area));
17532e2b6a1SMichael Lotz	}
17632e2b6a1SMichael Lotz
17732e2b6a1SMichael Lotz	// fallback to page wise mapping
178435c43f5SIngo Weinhold	generic_io_vec& currentVec = fVecs[cookie->vec_index];
179435c43f5SIngo Weinhold	generic_addr_t address = currentVec.base + cookie->vec_offset;
180435c43f5SIngo Weinhold	size_t pageOffset = address % B_PAGE_SIZE;
18132e2b6a1SMichael Lotz
182d4af8f3eSIngo Weinhold// TODO: This is a potential violation of the VIP requirement, since
183d4af8f3eSIngo Weinhold// vm_get_physical_page() may allocate memory without special flags!
18432e2b6a1SMichael Lotz	status_t result = vm_get_physical_page(address - pageOffset,
18532e2b6a1SMichael Lotz		&cookie->virtual_address, &cookie->physical_page_handle);
18632e2b6a1SMichael Lotz	if (result != B_OK)
18732e2b6a1SMichael Lotz		return result;
18832e2b6a1SMichael Lotz
189435c43f5SIngo Weinhold	generic_size_t length = min_c(currentVec.length - cookie->vec_offset,
19032e2b6a1SMichael Lotz		B_PAGE_SIZE - pageOffset);
19132e2b6a1SMichael Lotz
19232e2b6a1SMichael Lotz	vector.iov_base = (void*)(cookie->virtual_address + pageOffset);
19332e2b6a1SMichael Lotz	vector.iov_len = length;
19432e2b6a1SMichael Lotz
19532e2b6a1SMichael Lotz	cookie->vec_offset += length;
196435c43f5SIngo Weinhold	if (cookie->vec_offset >= currentVec.length) {
19732e2b6a1SMichael Lotz		cookie->vec_index++;
19832e2b6a1SMichael Lotz		cookie->vec_offset = 0;
19932e2b6a1SMichael Lotz	}
20032e2b6a1SMichael Lotz
20132e2b6a1SMichael Lotz	return B_OK;
20232e2b6a1SMichael Lotz}
20332e2b6a1SMichael Lotz
20432e2b6a1SMichael Lotz
20532e2b6a1SMichael Lotzvoid
20632e2b6a1SMichael LotzIOBuffer::FreeVirtualVecCookie(void* _cookie)
20732e2b6a1SMichael Lotz{
20832e2b6a1SMichael Lotz	virtual_vec_cookie* cookie = (virtual_vec_cookie*)_cookie;
20932e2b6a1SMichael Lotz	if (cookie->mapped_area >= 0)
21032e2b6a1SMichael Lotz		delete_area(cookie->mapped_area);
21199ccb18dSAxel Dörfler
21299ccb18dSAxel Dörfler	cookie->PutPhysicalPageIfNeeded();
21332e2b6a1SMichael Lotz
214deee8524SIngo Weinhold	free_etc(cookie, fVIP ? HEAP_PRIORITY_VIP : 0);
21532e2b6a1SMichael Lotz}
21632e2b6a1SMichael Lotz
21732e2b6a1SMichael Lotz
218aa4ba93eSIngo Weinholdstatus_t
219aa4ba93eSIngo WeinholdIOBuffer::LockMemory(team_id team, bool isWrite)
220aa4ba93eSIngo Weinhold{
221aa4ba93eSIngo Weinhold	if (fMemoryLocked) {
222aa4ba93eSIngo Weinhold		panic("memory already locked!");
223aa4ba93eSIngo Weinhold		return B_BAD_VALUE;
224aa4ba93eSIngo Weinhold	}
225aa4ba93eSIngo Weinhold
226aa4ba93eSIngo Weinhold	for (uint32 i = 0; i < fVecCount; i++) {
227435c43f5SIngo Weinhold		status_t status = lock_memory_etc(team, (void*)(addr_t)fVecs[i].base,
228435c43f5SIngo Weinhold			fVecs[i].length, isWrite ? 0 : B_READ_DEVICE);
229aa4ba93eSIngo Weinhold		if (status != B_OK) {
230aa4ba93eSIngo Weinhold			_UnlockMemory(team, i, isWrite);
231aa4ba93eSIngo Weinhold			return status;
232aa4ba93eSIngo Weinhold		}
233aa4ba93eSIngo Weinhold	}
234aa4ba93eSIngo Weinhold
235aa4ba93eSIngo Weinhold	fMemoryLocked = true;
236aa4ba93eSIngo Weinhold	return B_OK;
237aa4ba93eSIngo Weinhold}
238aa4ba93eSIngo Weinhold
239aa4ba93eSIngo Weinhold
240aa4ba93eSIngo Weinholdvoid
241aa4ba93eSIngo WeinholdIOBuffer::_UnlockMemory(team_id team, size_t count, bool isWrite)
242aa4ba93eSIngo Weinhold{
243aa4ba93eSIngo Weinhold	for (uint32 i = 0; i < count; i++) {
244435c43f5SIngo Weinhold		unlock_memory_etc(team, (void*)(addr_t)fVecs[i].base, fVecs[i].length,
245aa4ba93eSIngo Weinhold			isWrite ? 0 : B_READ_DEVICE);
246aa4ba93eSIngo Weinhold	}
247aa4ba93eSIngo Weinhold}
248aa4ba93eSIngo Weinhold
249aa4ba93eSIngo Weinhold
250aa4ba93eSIngo Weinholdvoid
251aa4ba93eSIngo WeinholdIOBuffer::UnlockMemory(team_id team, bool isWrite)
252aa4ba93eSIngo Weinhold{
253aa4ba93eSIngo Weinhold	if (!fMemoryLocked) {
254aa4ba93eSIngo Weinhold		panic("memory not locked");
255aa4ba93eSIngo Weinhold		return;
256aa4ba93eSIngo Weinhold	}
257aa4ba93eSIngo Weinhold
258aa4ba93eSIngo Weinhold	_UnlockMemory(team, fVecCount, isWrite);
259aa4ba93eSIngo Weinhold	fMemoryLocked = false;
260aa4ba93eSIngo Weinhold}
261aa4ba93eSIngo Weinhold
262aa4ba93eSIngo Weinhold
263aa4ba93eSIngo Weinholdvoid
264aa4ba93eSIngo WeinholdIOBuffer::Dump() const
265aa4ba93eSIngo Weinhold{
266aa4ba93eSIngo Weinhold	kprintf("IOBuffer at %p\n", this);
267aa4ba93eSIngo Weinhold
268aa4ba93eSIngo Weinhold	kprintf("  origin:     %s\n", fUser ? "user" : "kernel");
269aa4ba93eSIngo Weinhold	kprintf("  kind:       %s\n", fPhysical ? "physical" : "virtual");
2701d578e15SIngo Weinhold	kprintf("  length:     %" B_PRIuGENADDR "\n", fLength);
2711d578e15SIngo Weinhold	kprintf("  capacity:   %" B_PRIuSIZE "\n", fCapacity);
2721d578e15SIngo Weinhold	kprintf("  vecs:       %" B_PRIuSIZE "\n", fVecCount);
273aa4ba93eSIngo Weinhold
274aa4ba93eSIngo Weinhold	for (uint32 i = 0; i < fVecCount; i++) {
275435c43f5SIngo Weinhold		kprintf("    [%" B_PRIu32 "] %#" B_PRIxGENADDR ", %" B_PRIuGENADDR "\n",
276435c43f5SIngo Weinhold			i, fVecs[i].base, fVecs[i].length);
277aa4ba93eSIngo Weinhold	}
278aa4ba93eSIngo Weinhold}
279aa4ba93eSIngo Weinhold
280aa4ba93eSIngo Weinhold
281aa4ba93eSIngo Weinhold// #pragma mark -
282aa4ba93eSIngo Weinhold
283aa4ba93eSIngo Weinhold
284aa4ba93eSIngo Weinholdbool
285aa4ba93eSIngo WeinholdIOOperation::Finish()
286aa4ba93eSIngo Weinhold{
287aa4ba93eSIngo Weinhold	TRACE("IOOperation::Finish()\n");
288aa4ba93eSIngo Weinhold	if (fStatus == B_OK) {
289aa4ba93eSIngo Weinhold		if (fParent->IsWrite()) {
290aa4ba93eSIngo Weinhold			TRACE("  is write\n");
291aa4ba93eSIngo Weinhold			if (fPhase == PHASE_READ_BEGIN) {
292aa4ba93eSIngo Weinhold				TRACE("  phase read begin\n");
293aa4ba93eSIngo Weinhold				// repair phase adjusted vec
294435c43f5SIngo Weinhold				fDMABuffer->VecAt(fSavedVecIndex).length = fSavedVecLength;
295aa4ba93eSIngo Weinhold
296aa4ba93eSIngo Weinhold				// partial write: copy partial begin to bounce buffer
297aa4ba93eSIngo Weinhold				bool skipReadEndPhase;
298aa4ba93eSIngo Weinhold				status_t error = _CopyPartialBegin(true, skipReadEndPhase);
299aa4ba93eSIngo Weinhold				if (error == B_OK) {
300aa4ba93eSIngo Weinhold					// We're done with the first phase only (read in begin).
301aa4ba93eSIngo Weinhold					// Get ready for next phase...
302aa4ba93eSIngo Weinhold					fPhase = HasPartialEnd() && !skipReadEndPhase
303aa4ba93eSIngo Weinhold						? PHASE_READ_END : PHASE_DO_ALL;
304aa4ba93eSIngo Weinhold					_PrepareVecs();
305aa4ba93eSIngo Weinhold					ResetStatus();
306aa4ba93eSIngo Weinhold						// TODO: Is there a race condition, if the request is
307aa4ba93eSIngo Weinhold						// aborted at the same time?
308aa4ba93eSIngo Weinhold					return false;
309aa4ba93eSIngo Weinhold				}
310aa4ba93eSIngo Weinhold
311aa4ba93eSIngo Weinhold				SetStatus(error);
312aa4ba93eSIngo Weinhold			} else if (fPhase == PHASE_READ_END) {
313aa4ba93eSIngo Weinhold				TRACE("  phase read end\n");
314aa4ba93eSIngo Weinhold				// repair phase adjusted vec
315435c43f5SIngo Weinhold				generic_io_vec& vec = fDMABuffer->VecAt(fSavedVecIndex);
316435c43f5SIngo Weinhold				vec.base += vec.length - fSavedVecLength;
317435c43f5SIngo Weinhold				vec.length = fSavedVecLength;
318aa4ba93eSIngo Weinhold
319aa4ba93eSIngo Weinhold				// partial write: copy partial end to bounce buffer
320aa4ba93eSIngo Weinhold				status_t error = _CopyPartialEnd(true);
321aa4ba93eSIngo Weinhold				if (error == B_OK) {
322aa4ba93eSIngo Weinhold					// We're done with the second phase only (read in end).
323aa4ba93eSIngo Weinhold					// Get ready for next phase...
324aa4ba93eSIngo Weinhold					fPhase = PHASE_DO_ALL;
325aa4ba93eSIngo Weinhold					ResetStatus();
326aa4ba93eSIngo Weinhold						// TODO: Is there a race condition, if the request is
327aa4ba93eSIngo Weinhold						// aborted at the same time?
328aa4ba93eSIngo Weinhold					return false;
329aa4ba93eSIngo Weinhold				}
330aa4ba93eSIngo Weinhold
331aa4ba93eSIngo Weinhold				SetStatus(error);
332aa4ba93eSIngo Weinhold			}
333aa4ba93eSIngo Weinhold		}
334aa4ba93eSIngo Weinhold	}
335aa4ba93eSIngo Weinhold
336aa4ba93eSIngo Weinhold	if (fParent->IsRead() && UsesBounceBuffer()) {
337aa4ba93eSIngo Weinhold		TRACE("  read with bounce buffer\n");
338aa4ba93eSIngo Weinhold		// copy the bounce buffer segments to the final location
339aa4ba93eSIngo Weinhold		uint8* bounceBuffer = (uint8*)fDMABuffer->BounceBufferAddress();
340435c43f5SIngo Weinhold		phys_addr_t bounceBufferStart
341435c43f5SIngo Weinhold			= fDMABuffer->PhysicalBounceBufferAddress();
342435c43f5SIngo Weinhold		phys_addr_t bounceBufferEnd = bounceBufferStart
343aa4ba93eSIngo Weinhold			+ fDMABuffer->BounceBufferSize();
344aa4ba93eSIngo Weinhold
345435c43f5SIngo Weinhold		const generic_io_vec* vecs = fDMABuffer->Vecs();
346aa4ba93eSIngo Weinhold		uint32 vecCount = fDMABuffer->VecCount();
347aa4ba93eSIngo Weinhold
348aa4ba93eSIngo Weinhold		status_t error = B_OK;
349aa4ba93eSIngo Weinhold
3500228ef36SIngo Weinhold		// We iterate through the vecs we have read, moving offset (the device
351435c43f5SIngo Weinhold		// offset) as we go. If [offset, offset + vec.length) intersects with
3520228ef36SIngo Weinhold		// [startOffset, endOffset) we copy to the final location.
353aa4ba93eSIngo Weinhold		off_t offset = fOffset;
3540228ef36SIngo Weinhold		const off_t startOffset = fOriginalOffset;
3550228ef36SIngo Weinhold		const off_t endOffset = fOriginalOffset + fOriginalLength;
356aa4ba93eSIngo Weinhold
357aa4ba93eSIngo Weinhold		for (uint32 i = 0; error == B_OK && i < vecCount; i++) {
358435c43f5SIngo Weinhold			const generic_io_vec& vec = vecs[i];
359435c43f5SIngo Weinhold			generic_addr_t base = vec.base;
360435c43f5SIngo Weinhold			generic_size_t length = vec.length;
361aa4ba93eSIngo Weinhold
362aa4ba93eSIngo Weinhold			if (offset < startOffset) {
3630228ef36SIngo Weinhold				// If the complete vector is before the start offset, skip it.
3641d578e15SIngo Weinhold				if (offset + (off_t)length <= startOffset) {
365aa4ba93eSIngo Weinhold					offset += length;
366aa4ba93eSIngo Weinhold					continue;
367aa4ba93eSIngo Weinhold				}
368aa4ba93eSIngo Weinhold
3690228ef36SIngo Weinhold				// The vector starts before the start offset, but intersects
3700228ef36SIngo Weinhold				// with it. Skip the part we aren't interested in.
371435c43f5SIngo Weinhold				generic_size_t diff = startOffset - offset;
3720228ef36SIngo Weinhold				offset += diff;
373aa4ba93eSIngo Weinhold				base += diff;
374aa4ba93eSIngo Weinhold				length -= diff;
375aa4ba93eSIngo Weinhold			}
376aa4ba93eSIngo Weinhold
3771d578e15SIngo Weinhold			if (offset + (off_t)length > endOffset) {
3780228ef36SIngo Weinhold				// If we're already beyond the end offset, we're done.
379aa4ba93eSIngo Weinhold				if (offset >= endOffset)
380aa4ba93eSIngo Weinhold					break;
381aa4ba93eSIngo Weinhold
3820228ef36SIngo Weinhold				// The vector extends beyond the end offset -- cut it.
383aa4ba93eSIngo Weinhold				length = endOffset - offset;
384aa4ba93eSIngo Weinhold			}
385aa4ba93eSIngo Weinhold
386aa4ba93eSIngo Weinhold			if (base >= bounceBufferStart && base < bounceBufferEnd) {
387aa4ba93eSIngo Weinhold				error = fParent->CopyData(
388aa4ba93eSIngo Weinhold					bounceBuffer + (base - bounceBufferStart), offset, length);
389aa4ba93eSIngo Weinhold			}
390aa4ba93eSIngo Weinhold
391aa4ba93eSIngo Weinhold			offset += length;
392aa4ba93eSIngo Weinhold		}
393aa4ba93eSIngo Weinhold
394aa4ba93eSIngo Weinhold		if (error != B_OK)
395aa4ba93eSIngo Weinhold			SetStatus(error);
396aa4ba93eSIngo Weinhold	}
397aa4ba93eSIngo Weinhold
398aa4ba93eSIngo Weinhold	return true;
399aa4ba93eSIngo Weinhold}
400aa4ba93eSIngo Weinhold
401aa4ba93eSIngo Weinhold
402aa4ba93eSIngo Weinhold/*!	Note: SetPartial() must be called first!
403aa4ba93eSIngo Weinhold*/
404aa4ba93eSIngo Weinholdstatus_t
405aa4ba93eSIngo WeinholdIOOperation::Prepare(IORequest* request)
406aa4ba93eSIngo Weinhold{
407aa4ba93eSIngo Weinhold	if (fParent != NULL)
408aa4ba93eSIngo Weinhold		fParent->RemoveOperation(this);
409aa4ba93eSIngo Weinhold
410aa4ba93eSIngo Weinhold	fParent = request;
411aa4ba93eSIngo Weinhold
412aa4ba93eSIngo Weinhold	fTransferredBytes = 0;
413aa4ba93eSIngo Weinhold
414aa4ba93eSIngo Weinhold	// set initial phase
415aa4ba93eSIngo Weinhold	fPhase = PHASE_DO_ALL;
416aa4ba93eSIngo Weinhold	if (fParent->IsWrite()) {
417aa4ba93eSIngo Weinhold		// Copy data to bounce buffer segments, save the partial begin/end vec,
418aa4ba93eSIngo Weinhold		// which will be copied after their respective read phase.
419aa4ba93eSIngo Weinhold		if (UsesBounceBuffer()) {
420aa4ba93eSIngo Weinhold			TRACE("  write with bounce buffer\n");
421aa4ba93eSIngo Weinhold			uint8* bounceBuffer = (uint8*)fDMABuffer->BounceBufferAddress();
422435c43f5SIngo Weinhold			phys_addr_t bounceBufferStart
423aa4ba93eSIngo Weinhold				= fDMABuffer->PhysicalBounceBufferAddress();
424435c43f5SIngo Weinhold			phys_addr_t bounceBufferEnd = bounceBufferStart
425aa4ba93eSIngo Weinhold				+ fDMABuffer->BounceBufferSize();
426aa4ba93eSIngo Weinhold
427435c43f5SIngo Weinhold			const generic_io_vec* vecs = fDMABuffer->Vecs();
428aa4ba93eSIngo Weinhold			uint32 vecCount = fDMABuffer->VecCount();
429435c43f5SIngo Weinhold			generic_size_t vecOffset = 0;
430aa4ba93eSIngo Weinhold			uint32 i = 0;
431aa4ba93eSIngo Weinhold
432aa4ba93eSIngo Weinhold			off_t offset = fOffset;
433aa4ba93eSIngo Weinhold			off_t endOffset = fOffset + fLength;
434aa4ba93eSIngo Weinhold
435aa4ba93eSIngo Weinhold			if (HasPartialBegin()) {
436aa4ba93eSIngo Weinhold				// skip first block
437435c43f5SIngo Weinhold				generic_size_t toSkip = fBlockSize;
438aa4ba93eSIngo Weinhold				while (toSkip > 0) {
439435c43f5SIngo Weinhold					if (vecs[i].length <= toSkip) {
440435c43f5SIngo Weinhold						toSkip -= vecs[i].length;
441aa4ba93eSIngo Weinhold						i++;
442aa4ba93eSIngo Weinhold					} else {
443aa4ba93eSIngo Weinhold						vecOffset = toSkip;
444aa4ba93eSIngo Weinhold						break;
445aa4ba93eSIngo Weinhold					}
446aa4ba93eSIngo Weinhold				}
447aa4ba93eSIngo Weinhold
448aa4ba93eSIngo Weinhold				offset += fBlockSize;
449aa4ba93eSIngo Weinhold			}
450aa4ba93eSIngo Weinhold
451aa4ba93eSIngo Weinhold			if (HasPartialEnd()) {
452aa4ba93eSIngo Weinhold				// skip last block
453435c43f5SIngo Weinhold				generic_size_t toSkip = fBlockSize;
454aa4ba93eSIngo Weinhold				while (toSkip > 0) {
455435c43f5SIngo Weinhold					if (vecs[vecCount - 1].length <= toSkip) {
456435c43f5SIngo Weinhold						toSkip -= vecs[vecCount - 1].length;
457aa4ba93eSIngo Weinhold						vecCount--;
458aa4ba93eSIngo Weinhold					} else
459aa4ba93eSIngo Weinhold						break;
460aa4ba93eSIngo Weinhold				}
461aa4ba93eSIngo Weinhold
462aa4ba93eSIngo Weinhold				endOffset -= fBlockSize;
463aa4ba93eSIngo Weinhold			}
464aa4ba93eSIngo Weinhold
465aa4ba93eSIngo Weinhold			for (; i < vecCount; i++) {
466435c43f5SIngo Weinhold				const generic_io_vec& vec = vecs[i];
467435c43f5SIngo Weinhold				generic_addr_t base = vec.base + vecOffset;
468435c43f5SIngo Weinhold				generic_size_t length = vec.length - vecOffset;
469aa4ba93eSIngo Weinhold				vecOffset = 0;
470aa4ba93eSIngo Weinhold
471aa4ba93eSIngo Weinhold				if (base >= bounceBufferStart && base < bounceBufferEnd) {
4721d578e15SIngo Weinhold					if (offset + (off_t)length > endOffset)
473aa4ba93eSIngo Weinhold						length = endOffset - offset;
474aa4ba93eSIngo Weinhold					status_t error = fParent->CopyData(offset,
475aa4ba93eSIngo Weinhold						bounceBuffer + (base - bounceBufferStart), length);
476aa4ba93eSIngo Weinhold					if (error != B_OK)
477aa4ba93eSIngo Weinhold						return error;
478aa4ba93eSIngo Weinhold				}
479aa4ba93eSIngo Weinhold
480aa4ba93eSIngo Weinhold				offset += length;
481aa4ba93eSIngo Weinhold			}
482aa4ba93eSIngo Weinhold		}
483aa4ba93eSIngo Weinhold
484aa4ba93eSIngo Weinhold		if (HasPartialBegin())
485aa4ba93eSIngo Weinhold			fPhase = PHASE_READ_BEGIN;
486aa4ba93eSIngo Weinhold		else if (HasPartialEnd())
487aa4ba93eSIngo Weinhold			fPhase = PHASE_READ_END;
488aa4ba93eSIngo Weinhold
489aa4ba93eSIngo Weinhold		_PrepareVecs();
490aa4ba93eSIngo Weinhold	}
491aa4ba93eSIngo Weinhold
492aa4ba93eSIngo Weinhold	ResetStatus();
493aa4ba93eSIngo Weinhold
494aa4ba93eSIngo Weinhold	if (fParent != NULL)
495aa4ba93eSIngo Weinhold		fParent->AddOperation(this);
496aa4ba93eSIngo Weinhold
497aa4ba93eSIngo Weinhold	return B_OK;
498aa4ba93eSIngo Weinhold}
499aa4ba93eSIngo Weinhold
500aa4ba93eSIngo Weinhold
501aa4ba93eSIngo Weinholdvoid
502435c43f5SIngo WeinholdIOOperation::SetOriginalRange(off_t offset, generic_size_t length)
503aa4ba93eSIngo Weinhold{
504aa4ba93eSIngo Weinhold	fOriginalOffset = fOffset = offset;
505aa4ba93eSIngo Weinhold	fOriginalLength = fLength = length;
506aa4ba93eSIngo Weinhold}
507aa4ba93eSIngo Weinhold
508aa4ba93eSIngo Weinhold
509aa4ba93eSIngo Weinholdvoid
510435c43f5SIngo WeinholdIOOperation::SetRange(off_t offset, generic_size_t length)
511aa4ba93eSIngo Weinhold{
512aa4ba93eSIngo Weinhold	fOffset = offset;
513aa4ba93eSIngo Weinhold	fLength = length;
514aa4ba93eSIngo Weinhold}
515aa4ba93eSIngo Weinhold
516aa4ba93eSIngo Weinhold
517aa4ba93eSIngo Weinholdoff_t
518aa4ba93eSIngo WeinholdIOOperation::Offset() const
519aa4ba93eSIngo Weinhold{
520aa4ba93eSIngo Weinhold	return fPhase == PHASE_READ_END ? fOffset + fLength - fBlockSize : fOffset;
521aa4ba93eSIngo Weinhold}
522aa4ba93eSIngo Weinhold
523aa4ba93eSIngo Weinhold
524435c43f5SIngo Weinholdgeneric_size_t
525aa4ba93eSIngo WeinholdIOOperation::Length() const
526aa4ba93eSIngo Weinhold{
527aa4ba93eSIngo Weinhold	return fPhase == PHASE_DO_ALL ? fLength : fBlockSize;
528aa4ba93eSIngo Weinhold}
529aa4ba93eSIngo Weinhold
530aa4ba93eSIngo Weinhold
531435c43f5SIngo Weinholdgeneric_io_vec*
532aa4ba93eSIngo WeinholdIOOperation::Vecs() const
533aa4ba93eSIngo Weinhold{
534aa4ba93eSIngo Weinhold	switch (fPhase) {
535aa4ba93eSIngo Weinhold		case PHASE_READ_END:
536aa4ba93eSIngo Weinhold			return fDMABuffer->Vecs() + fSavedVecIndex;
537aa4ba93eSIngo Weinhold		case PHASE_READ_BEGIN:
538aa4ba93eSIngo Weinhold		case PHASE_DO_ALL:
539aa4ba93eSIngo Weinhold		default:
540aa4ba93eSIngo Weinhold			return fDMABuffer->Vecs();
541aa4ba93eSIngo Weinhold	}
542aa4ba93eSIngo Weinhold}
543aa4ba93eSIngo Weinhold
544aa4ba93eSIngo Weinhold
545aa4ba93eSIngo Weinholduint32
546aa4ba93eSIngo WeinholdIOOperation::VecCount() const
547aa4ba93eSIngo Weinhold{
548aa4ba93eSIngo Weinhold	switch (fPhase) {
549aa4ba93eSIngo Weinhold		case PHASE_READ_BEGIN:
550aa4ba93eSIngo Weinhold			return fSavedVecIndex + 1;
551aa4ba93eSIngo Weinhold		case PHASE_READ_END:
552aa4ba93eSIngo Weinhold			return fDMABuffer->VecCount() - fSavedVecIndex;
553aa4ba93eSIngo Weinhold		case PHASE_DO_ALL:
554aa4ba93eSIngo Weinhold		default:
555aa4ba93eSIngo Weinhold			return fDMABuffer->VecCount();
556aa4ba93eSIngo Weinhold	}
557aa4ba93eSIngo Weinhold}
558aa4ba93eSIngo Weinhold
559aa4ba93eSIngo Weinhold
560aa4ba93eSIngo Weinholdvoid
561aa4ba93eSIngo WeinholdIOOperation::SetPartial(bool partialBegin, bool partialEnd)
562aa4ba93eSIngo Weinhold{
563aa4ba93eSIngo Weinhold	TRACE("partial begin %d, end %d\n", partialBegin, partialEnd);
564aa4ba93eSIngo Weinhold	fPartialBegin = partialBegin;
565aa4ba93eSIngo Weinhold	fPartialEnd = partialEnd;
566aa4ba93eSIngo Weinhold}
567aa4ba93eSIngo Weinhold
568aa4ba93eSIngo Weinhold
569aa4ba93eSIngo Weinholdbool
570aa4ba93eSIngo WeinholdIOOperation::IsWrite() const
571aa4ba93eSIngo Weinhold{
572aa4ba93eSIngo Weinhold	return fParent->IsWrite() && fPhase == PHASE_DO_ALL;
573aa4ba93eSIngo Weinhold}
574aa4ba93eSIngo Weinhold
575aa4ba93eSIngo Weinhold
576aa4ba93eSIngo Weinholdbool
577aa4ba93eSIngo WeinholdIOOperation::IsRead() const
578aa4ba93eSIngo Weinhold{
579aa4ba93eSIngo Weinhold	return fParent->IsRead();
580aa4ba93eSIngo Weinhold}
581aa4ba93eSIngo Weinhold
582aa4ba93eSIngo Weinhold
583aa4ba93eSIngo Weinholdvoid
584aa4ba93eSIngo WeinholdIOOperation::_PrepareVecs()
585aa4ba93eSIngo Weinhold{
586aa4ba93eSIngo Weinhold	// we need to prepare the vecs for consumption by the drivers
587aa4ba93eSIngo Weinhold	if (fPhase == PHASE_READ_BEGIN) {
588435c43f5SIngo Weinhold		generic_io_vec* vecs = fDMABuffer->Vecs();
589aa4ba93eSIngo Weinhold		uint32 vecCount = fDMABuffer->VecCount();
590435c43f5SIngo Weinhold		generic_size_t vecLength = fBlockSize;
591aa4ba93eSIngo Weinhold		for (uint32 i = 0; i < vecCount; i++) {
592435c43f5SIngo Weinhold			generic_io_vec& vec = vecs[i];
593435c43f5SIngo Weinhold			if (vec.length >= vecLength) {
594aa4ba93eSIngo Weinhold				fSavedVecIndex = i;
595435c43f5SIngo Weinhold				fSavedVecLength = vec.length;
596435c43f5SIngo Weinhold				vec.length = vecLength;
597aa4ba93eSIngo Weinhold				break;
598aa4ba93eSIngo Weinhold			}
599435c43f5SIngo Weinhold			vecLength -= vec.length;
600aa4ba93eSIngo Weinhold		}
601aa4ba93eSIngo Weinhold	} else if (fPhase == PHASE_READ_END) {
602435c43f5SIngo Weinhold		generic_io_vec* vecs = fDMABuffer->Vecs();
603aa4ba93eSIngo Weinhold		uint32 vecCount = fDMABuffer->VecCount();
604435c43f5SIngo Weinhold		generic_size_t vecLength = fBlockSize;
605aa4ba93eSIngo Weinhold		for (int32 i = vecCount - 1; i >= 0; i--) {
606435c43f5SIngo Weinhold			generic_io_vec& vec = vecs[i];
607435c43f5SIngo Weinhold			if (vec.length >= vecLength) {
608aa4ba93eSIngo Weinhold				fSavedVecIndex = i;
609435c43f5SIngo Weinhold				fSavedVecLength = vec.length;
610435c43f5SIngo Weinhold				vec.base += vec.length - vecLength;
611435c43f5SIngo Weinhold				vec.length = vecLength;
612aa4ba93eSIngo Weinhold				break;
613aa4ba93eSIngo Weinhold			}
614435c43f5SIngo Weinhold			vecLength -= vec.length;
615aa4ba93eSIngo Weinhold		}
616aa4ba93eSIngo Weinhold	}
617aa4ba93eSIngo Weinhold}
618aa4ba93eSIngo Weinhold
619aa4ba93eSIngo Weinhold
620aa4ba93eSIngo Weinholdstatus_t
621aa4ba93eSIngo WeinholdIOOperation::_CopyPartialBegin(bool isWrite, bool& singleBlockOnly)
622aa4ba93eSIngo Weinhold{
623435c43f5SIngo Weinhold	generic_size_t relativeOffset = OriginalOffset() - fOffset;
624435c43f5SIngo Weinhold	generic_size_t length = fBlockSize - relativeOffset;
625aa4ba93eSIngo Weinhold
626aa4ba93eSIngo Weinhold	singleBlockOnly = length >= OriginalLength();
627aa4ba93eSIngo Weinhold	if (singleBlockOnly)
628aa4ba93eSIngo Weinhold		length = OriginalLength();
629aa4ba93eSIngo Weinhold
630aa4ba93eSIngo Weinhold	TRACE("_CopyPartialBegin(%s, single only %d)\n",
631aa4ba93eSIngo Weinhold		isWrite ? "write" : "read", singleBlockOnly);
632aa4ba93eSIngo Weinhold
633aa4ba93eSIngo Weinhold	if (isWrite) {
634aa4ba93eSIngo Weinhold		return fParent->CopyData(OriginalOffset(),
635aa4ba93eSIngo Weinhold			(uint8*)fDMABuffer->BounceBufferAddress() + relativeOffset, length);
636aa4ba93eSIngo Weinhold	} else {
637aa4ba93eSIngo Weinhold		return fParent->CopyData(
638aa4ba93eSIngo Weinhold			(uint8*)fDMABuffer->BounceBufferAddress() + relativeOffset,
639aa4ba93eSIngo Weinhold			OriginalOffset(), length);
640aa4ba93eSIngo Weinhold	}
641aa4ba93eSIngo Weinhold}
642aa4ba93eSIngo Weinhold
643aa4ba93eSIngo Weinhold
644aa4ba93eSIngo Weinholdstatus_t
645aa4ba93eSIngo WeinholdIOOperation::_CopyPartialEnd(bool isWrite)
646aa4ba93eSIngo Weinhold{
647aa4ba93eSIngo Weinhold	TRACE("_CopyPartialEnd(%s)\n", isWrite ? "write" : "read");
648aa4ba93eSIngo Weinhold
649435c43f5SIngo Weinhold	const generic_io_vec& lastVec
650435c43f5SIngo Weinhold		= fDMABuffer->VecAt(fDMABuffer->VecCount() - 1);
651aa4ba93eSIngo Weinhold	off_t lastVecPos = fOffset + fLength - fBlockSize;
652aa4ba93eSIngo Weinhold	uint8* base = (uint8*)fDMABuffer->BounceBufferAddress()
653435c43f5SIngo Weinhold		+ (lastVec.base + lastVec.length - fBlockSize
654aa4ba93eSIngo Weinhold		- fDMABuffer->PhysicalBounceBufferAddress());
655aa4ba93eSIngo Weinhold		// NOTE: this won't work if we don't use the bounce buffer contiguously
656aa4ba93eSIngo Weinhold		// (because of boundary alignments).
657435c43f5SIngo Weinhold	generic_size_t length = OriginalOffset() + OriginalLength() - lastVecPos;
658aa4ba93eSIngo Weinhold
659aa4ba93eSIngo Weinhold	if (isWrite)
660aa4ba93eSIngo Weinhold		return fParent->CopyData(lastVecPos, base, length);
661aa4ba93eSIngo Weinhold
662aa4ba93eSIngo Weinhold	return fParent->CopyData(base, lastVecPos, length);
663aa4ba93eSIngo Weinhold}
664aa4ba93eSIngo Weinhold
665aa4ba93eSIngo Weinhold
666aa4ba93eSIngo Weinholdvoid
667aa4ba93eSIngo WeinholdIOOperation::Dump() const
668aa4ba93eSIngo Weinhold{
669aa4ba93eSIngo Weinhold	kprintf("io_operation at %p\n", this);
670aa4ba93eSIngo Weinhold
671aa4ba93eSIngo Weinhold	kprintf("  parent:           %p\n", fParent);
672aa4ba93eSIngo Weinhold	kprintf("  status:           %s\n", strerror(fStatus));
673aa4ba93eSIngo Weinhold	kprintf("  dma buffer:       %p\n", fDMABuffer);
674294711f9SAlex Smith	kprintf("  offset:           %-8" B_PRIdOFF " (original: %" B_PRIdOFF ")\n",
675294711f9SAlex Smith		fOffset, fOriginalOffset);
6761d578e15SIngo Weinhold	kprintf("  length:           %-8" B_PRIuGENADDR " (original: %"
6771d578e15SIngo Weinhold		B_PRIuGENADDR ")\n", fLength, fOriginalLength);
6781d578e15SIngo Weinhold	kprintf("  transferred:      %" B_PRIuGENADDR "\n", fTransferredBytes);
6791d578e15SIngo Weinhold	kprintf("  block size:       %" B_PRIuGENADDR "\n", fBlockSize);
680aa4ba93eSIngo Weinhold	kprintf("  saved vec index:  %u\n", fSavedVecIndex);
681aa4ba93eSIngo Weinhold	kprintf("  saved vec length: %u\n", fSavedVecLength);
682aa4ba93eSIngo Weinhold	kprintf("  r/w:              %s\n", IsWrite() ? "write" : "read");
683aa4ba93eSIngo Weinhold	kprintf("  phase:            %s\n", fPhase == PHASE_READ_BEGIN
684aa4ba93eSIngo Weinhold		? "read begin" : fPhase == PHASE_READ_END ? "read end"
685aa4ba93eSIngo Weinhold		: fPhase == PHASE_DO_ALL ? "do all" : "unknown");
686aa4ba93eSIngo Weinhold	kprintf("  partial begin:    %s\n", fPartialBegin ? "yes" : "no");
687aa4ba93eSIngo Weinhold	kprintf("  partial end:      %s\n", fPartialEnd ? "yes" : "no");
688aa4ba93eSIngo Weinhold	kprintf("  bounce buffer:    %s\n", fUsesBounceBuffer ? "yes" : "no");
689aa4ba93eSIngo Weinhold
690aa4ba93eSIngo Weinhold	set_debug_variable("_parent", (addr_t)fParent);
691aa4ba93eSIngo Weinhold	set_debug_variable("_buffer", (addr_t)fDMABuffer);
692aa4ba93eSIngo Weinhold}
693aa4ba93eSIngo Weinhold
694aa4ba93eSIngo Weinhold
695aa4ba93eSIngo Weinhold// #pragma mark -
696aa4ba93eSIngo Weinhold
697aa4ba93eSIngo Weinhold
698aa4ba93eSIngo WeinholdIORequest::IORequest()
699aa4ba93eSIngo Weinhold	:
7002f7eb9b5SIngo Weinhold	fIsNotified(false),
701aa4ba93eSIngo Weinhold	fFinishedCallback(NULL),
702aa4ba93eSIngo Weinhold	fFinishedCookie(NULL),
703aa4ba93eSIngo Weinhold	fIterationCallback(NULL),
704aa4ba93eSIngo Weinhold	fIterationCookie(NULL)
705aa4ba93eSIngo Weinhold{
706aa4ba93eSIngo Weinhold	mutex_init(&fLock, "I/O request lock");
707aa4ba93eSIngo Weinhold	fFinishedCondition.Init(this, "I/O request finished");
708aa4ba93eSIngo Weinhold}
709aa4ba93eSIngo Weinhold
710aa4ba93eSIngo Weinhold
711aa4ba93eSIngo WeinholdIORequest::~IORequest()
712aa4ba93eSIngo Weinhold{
713aa4ba93eSIngo Weinhold	mutex_lock(&fLock);
714aa4ba93eSIngo Weinhold	DeleteSubRequests();
7158b222e62SAugustin Cavalier	if (fBuffer != NULL)
7168b222e62SAugustin Cavalier		fBuffer->Delete();
717aa4ba93eSIngo Weinhold	mutex_destroy(&fLock);
718aa4ba93eSIngo Weinhold}
719aa4ba93eSIngo Weinhold
720aa4ba93eSIngo Weinhold
721aa4ba93eSIngo Weinhold/* static */ IORequest*
722aa4ba93eSIngo WeinholdIORequest::Create(bool vip)
723aa4ba93eSIngo Weinhold{
724deee8524SIngo Weinhold	return vip
725deee8524SIngo Weinhold		? new(malloc_flags(HEAP_PRIORITY_VIP)) IORequest
726deee8524SIngo Weinhold		: new(std::nothrow) IORequest;
727aa4ba93eSIngo Weinhold}
728aa4ba93eSIngo Weinhold
729aa4ba93eSIngo Weinhold
730aa4ba93eSIngo Weinholdstatus_t
731435c43f5SIngo WeinholdIORequest::Init(off_t offset, generic_addr_t buffer, generic_size_t length,
732435c43f5SIngo Weinhold	bool write, uint32 flags)
733aa4ba93eSIngo Weinhold{
7349f7e78eeSIngo Weinhold	ASSERT(offset >= 0);
7359f7e78eeSIngo Weinhold
736435c43f5SIngo Weinhold	generic_io_vec vec;
737435c43f5SIngo Weinhold	vec.base = buffer;
738435c43f5SIngo Weinhold	vec.length = length;
739aa4ba93eSIngo Weinhold	return Init(offset, &vec, 1, length, write, flags);
740aa4ba93eSIngo Weinhold}
741aa4ba93eSIngo Weinhold
742aa4ba93eSIngo Weinhold
743aa4ba93eSIngo Weinholdstatus_t