1/*
2 * Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2008, Axel D��rfler, axeld@pinc-software.de.
4 * Distributed under the terms of the MIT License.
5 */
6#ifndef IO_REQUEST_H
7#define IO_REQUEST_H
8
9
10#include <sys/uio.h>
11
12#include <new>
13
14#include <fs_interface.h>
15
16#include <condition_variable.h>
17#include <lock.h>
18#include <util/DoublyLinkedList.h>
19
20#include "dma_resources.h"
21
22
23#define B_PHYSICAL_IO_REQUEST	0x01	/* buffer points to physical memory */
24#define B_VIP_IO_REQUEST		0x02	/* used by the page writer -- make sure
25										   allocations won't fail */
26#define B_DELETE_IO_REQUEST		0x04	/* delete request when finished */
27
28class DMABuffer;
29struct IOOperation;
30
31typedef struct IOOperation io_operation;
32
33class IOBuffer : public DoublyLinkedListLinkImpl<IOBuffer> {
34public:
35	static	IOBuffer*			Create(uint32 count, bool vip);
36			void				Delete();
37
38			bool				IsVirtual() const { return !fPhysical; }
39			bool				IsPhysical() const { return fPhysical; }
40			bool				IsUser() const { return fUser; }
41
42			void				SetVecs(generic_size_t firstVecOffset,
43									generic_size_t lastVecSize,
44									const generic_io_vec* vecs, uint32 count,
45									generic_size_t length, uint32 flags);
46
47			void				SetPhysical(bool physical)
48									{ fPhysical = physical; }
49			void				SetUser(bool user) { fUser = user; }
50			void				SetLength(generic_size_t length)
51									{ fLength = length; }
52			void				SetVecCount(uint32 count) { fVecCount = count; }
53
54			generic_size_t		Length() const { return fLength; }
55
56			generic_io_vec*		Vecs() { return fVecs; }
57			generic_io_vec&		VecAt(size_t index) { return fVecs[index]; }
58			size_t				VecCount() const { return fVecCount; }
59			size_t				Capacity() const { return fCapacity; }
60
61			status_t			GetNextVirtualVec(void*& cookie, iovec& vector);
62			void				FreeVirtualVecCookie(void* cookie);
63
64			status_t			LockMemory(team_id team, bool isWrite);
65			void				UnlockMemory(team_id team, bool isWrite);
66			bool				IsMemoryLocked() const
67									{ return fMemoryLocked; }
68
69			void				Dump() const;
70
71private:
72								IOBuffer();
73								~IOBuffer();
74									// not implemented
75			void				_UnlockMemory(team_id team, size_t count,
76									bool isWrite);
77
78			bool				fUser;
79			bool				fPhysical;
80			bool				fVIP;
81			bool				fMemoryLocked;
82			generic_size_t		fLength;
83			size_t				fVecCount;
84			size_t				fCapacity;
85			generic_io_vec		fVecs[1];
86};
87
88
89struct IORequest;
90struct IORequestOwner;
91
92
93class IORequestChunk {
94public:
95								IORequestChunk();
96	virtual						~IORequestChunk();
97
98			IORequest*			Parent() const { return fParent; }
99			void				SetParent(IORequest* parent)
100									{ fParent = parent; }
101
102			status_t			Status() const { return fStatus; }
103
104			DoublyLinkedListLink<IORequestChunk>*
105									ListLink()	{ return &fListLink; }
106
107protected:
108			void				SetStatus(status_t status)
109									{ fStatus = status; }
110			void				ResetStatus()
111									{ fStatus = 1; }
112
113protected:
114			IORequest*			fParent;
115			status_t			fStatus;
116
117public:
118			DoublyLinkedListLink<IORequestChunk> fListLink;
119};
120
121typedef DoublyLinkedList<IORequestChunk,
122	DoublyLinkedListMemberGetLink<IORequestChunk, &IORequestChunk::fListLink> >
123		IORequestChunkList;
124
125
126struct IOOperation : IORequestChunk, DoublyLinkedListLinkImpl<IOOperation> {
127public:
128			bool				Finish();
129									// returns true, if it can be recycled
130									// otherwise, there is more to be done
131
132			void				SetStatus(status_t status, generic_size_t completedLength);
133
134			status_t			Prepare(IORequest* request);
135			void				SetOriginalRange(off_t offset,
136									generic_size_t length);
137									// also sets range
138			void				SetRange(off_t offset, generic_size_t length);
139
140			off_t				Offset() const;
141			generic_size_t		Length() const;
142
143			off_t				OriginalOffset() const
144									{ return fOriginalOffset; }
145			generic_size_t		OriginalLength() const
146									{ return fOriginalLength; }
147
148			generic_size_t		TransferredBytes() const
149									{ return fTransferredBytes; }
150
151			generic_io_vec*		Vecs() const;
152			uint32				VecCount() const;
153
154			void				SetPartial(bool partialBegin, bool partialEnd);
155			bool				HasPartialBegin() const
156									{ return fPartialBegin; }
157			bool				HasPartialEnd() const
158									{ return fPartialEnd; }
159			bool				IsWrite() const;
160			bool				IsRead() const;
161
162			void				SetBlockSize(generic_size_t blockSize)
163									{ fBlockSize  = blockSize; }
164
165			bool				UsesBounceBuffer() const
166									{ return fUsesBounceBuffer; }
167			void				SetUsesBounceBuffer(bool uses)
168									{ fUsesBounceBuffer = uses; }
169
170			DMABuffer*			Buffer() const { return fDMABuffer; }
171			void				SetBuffer(DMABuffer* buffer)
172									{ fDMABuffer = buffer; }
173
174			void				Dump() const;
175
176protected:
177			void				_PrepareVecs();
178			status_t			_CopyPartialBegin(bool isWrite,
179									bool& partialBlockOnly);
180			status_t			_CopyPartialEnd(bool isWrite);
181
182			DMABuffer*			fDMABuffer;
183			off_t				fOffset;
184			off_t				fOriginalOffset;
185			generic_size_t		fLength;
186			generic_size_t		fOriginalLength;
187			generic_size_t		fTransferredBytes;
188			generic_size_t		fBlockSize;
189			uint16				fSavedVecIndex;
190			uint16				fSavedVecLength;
191			uint8				fPhase;
192			bool				fPartialBegin;
193			bool				fPartialEnd;
194			bool				fUsesBounceBuffer;
195};
196
197
198typedef IOOperation io_operation;
199typedef DoublyLinkedList<IOOperation> IOOperationList;
200
201typedef struct IORequest io_request;
202typedef status_t (*io_request_finished_callback)(void* data,
203			io_request* request, status_t status, bool partialTransfer,
204			generic_size_t transferEndOffset);
205			// TODO: Return type: status_t -> void
206typedef status_t (*io_request_iterate_callback)(void* data,
207			io_request* request, bool* _partialTransfer);
208
209
210struct IORequest : IORequestChunk, DoublyLinkedListLinkImpl<IORequest> {
211								IORequest();
212	virtual						~IORequest();
213
214	static	IORequest*			Create(bool vip);
215
216			status_t			Init(off_t offset, generic_addr_t buffer,
217									generic_size_t length, bool write,
218									uint32 flags);
219			status_t			Init(off_t offset, const generic_io_vec* vecs,
220									size_t count, generic_size_t length,
221									bool write, uint32 flags)
222									{ return Init(offset, 0, 0, vecs, count,
223										length, write, flags); }
224			status_t			Init(off_t offset,
225									generic_size_t firstVecOffset,
226									generic_size_t lastVecSize,
227									const generic_io_vec* vecs, size_t count,
228									generic_size_t length, bool write,
229									uint32 flags);
230
231			void				SetOwner(IORequestOwner* owner)
232									{ fOwner = owner; }
233			IORequestOwner*		Owner() const	{ return fOwner; }
234
235			status_t			CreateSubRequest(off_t parentOffset,
236									off_t offset, generic_size_t length,
237									IORequest*& subRequest);
238			void				DeleteSubRequests();
239
240			void				SetFinishedCallback(
241									io_request_finished_callback callback,
242									void* cookie);
243			void				SetIterationCallback(
244									io_request_iterate_callback callback,
245									void* cookie);
246			io_request_finished_callback FinishedCallback(
247									void** _cookie = NULL) const;
248
249			status_t			Wait(uint32 flags = 0, bigtime_t timeout = 0);
250
251			bool				IsFinished() const
252									{ return fStatus != 1
253										&& fPendingChildren == 0; }
254			void				NotifyFinished();
255			bool				HasCallbacks() const;
256			void				SetStatusAndNotify(status_t status);
257
258			void				OperationFinished(IOOperation* operation);
259			void				SubRequestFinished(IORequest* request,
260									status_t status, bool partialTransfer,
261									generic_size_t transferEndOffset);
262			void				SetUnfinished();
263
264			generic_size_t		RemainingBytes() const
265									{ return fRemainingBytes; }
266			generic_size_t		TransferredBytes() const
267									{ return fTransferSize; }
268			bool				IsPartialTransfer() const
269									{ return fPartialTransfer; }
270			void				SetTransferredBytes(bool partialTransfer,
271									generic_size_t transferredBytes);
272
273			void				SetSuppressChildNotifications(bool suppress);
274			bool				SuppressChildNotifications() const
275									{ return fSuppressChildNotifications; }
276
277			bool				IsWrite() const	{ return fIsWrite; }
278			bool				IsRead() const	{ return !fIsWrite; }
279			team_id				TeamID() const		{ return fTeam; }
280			thread_id			ThreadID() const	{ return fThread; }
281			uint32				Flags() const	{ return fFlags; }
282
283			IOBuffer*			Buffer() const	{ return fBuffer; }
284			off_t				Offset() const	{ return fOffset; }
285			generic_size_t		Length() const	{ return fLength; }
286
287			void				SetOffset(off_t offset)	{ fOffset = offset; }
288
289			uint32				VecIndex() const	{ return fVecIndex; }
290			generic_size_t		VecOffset() const	{ return fVecOffset; }
291
292			void				Advance(generic_size_t bySize);
293
294			IORequest*			FirstSubRequest();
295			IORequest*			NextSubRequest(IORequest* previous);
296
297			void				AddOperation(IOOperation* operation);
298			void				RemoveOperation(IOOperation* operation);
299
300			status_t			CopyData(off_t offset, void* buffer,
301									size_t size);
302			status_t			CopyData(const void* buffer, off_t offset,
303									size_t size);
304			status_t			ClearData(off_t offset, generic_size_t size);
305
306			void				Dump() const;
307
308private:
309			status_t			_CopyData(void* buffer, off_t offset,
310									size_t size, bool copyIn);
311	static	status_t			_CopySimple(void* bounceBuffer,
312									generic_addr_t external, size_t size,
313									team_id team, bool copyIn);
314	static	status_t			_CopyPhysical(void* bounceBuffer,
315									generic_addr_t external, size_t size,
316									team_id team, bool copyIn);
317	static	status_t			_CopyUser(void* bounceBuffer,
318									generic_addr_t external, size_t size,
319									team_id team, bool copyIn);
320	static	status_t			_ClearDataSimple(generic_addr_t external,
321									generic_size_t size, team_id team);
322	static	status_t			_ClearDataPhysical(generic_addr_t external,
323									generic_size_t size, team_id team);
324	static	status_t			_ClearDataUser(generic_addr_t external,
325									generic_size_t size, team_id team);
326
327			mutex				fLock;
328			IORequestOwner*		fOwner;
329			IOBuffer*			fBuffer;
330			off_t				fOffset;
331			generic_size_t		fLength;
332			generic_size_t		fTransferSize;
333									// After all subrequests/operations have
334									// finished, number of contiguous bytes at
335									// the beginning of the request that have
336									// actually been transferred.
337			generic_size_t		fRelativeParentOffset;
338									// offset of this request relative to its
339									// parent
340			IORequestChunkList	fChildren;
341			int32				fPendingChildren;
342			uint32				fFlags;
343			team_id				fTeam;
344			thread_id			fThread;
345			bool				fIsWrite;
346			bool				fPartialTransfer;
347			bool				fSuppressChildNotifications;
348			bool				fIsNotified;
349
350			io_request_finished_callback	fFinishedCallback;
351			void*				fFinishedCookie;
352			io_request_iterate_callback	fIterationCallback;
353			void*				fIterationCookie;
354			ConditionVariable	fFinishedCondition;
355
356			// these are for iteration
357			uint32				fVecIndex;
358			generic_size_t		fVecOffset;
359			generic_size_t		fRemainingBytes;
360};
361
362
363typedef DoublyLinkedList<IORequest> IORequestList;
364
365
366#endif	// IO_REQUEST_H
367