xref: /haiku/src/add-ons/kernel/bus_managers/ata/ATAHelper.cpp (revision 91054f1d38dd7827c0f0ba9490c213775ec7b471)
1 /*
2  * Copyright 2009, Michael Lotz, mmlr@mlotz.ch.
3  * Copyright 2004-2007, Axel Dörfler, axeld@pinc-software.de.
4  * Copyright 2002/03, Thomas Kurschel. All rights reserved.
5  *
6  * Distributed under the terms of the MIT License.
7  */
8 
9 #include "ATAPrivate.h"
10 
11 #include <vm.h>
12 #include <string.h>
13 
14 
15 /*!	Copy data between ccb data and buffer
16 	ccb			- ccb to copy data from/to
17 	offset			- offset of data in ccb
18 	allocation_length- limit of ccb's data buffer according to CDB
19 	buffer			- data to copy data from/to
20 	size			- number of bytes to copy
21 	to_buffer		- true: copy from ccb to buffer
22 					  false: copy from buffer to ccb
23 	return: true, if data of ccb was large enough
24 */
25 bool
26 copy_sg_data(scsi_ccb *ccb, uint offset, uint allocationLength,
27 	void *buffer, int size, bool toBuffer)
28 {
29 	const physical_entry *sgList = ccb->sg_list;
30 	int sgCount = ccb->sg_count;
31 
32 	// skip unused S/G entries
33 	while (sgCount > 0 && offset >= sgList->size) {
34 		offset -= sgList->size;
35 		++sgList;
36 		--sgCount;
37 	}
38 
39 	if (sgCount == 0)
40 		return false;
41 
42 	// remaining bytes we are allowed to copy from/to ccb
43 	int requestSize = MIN(allocationLength, ccb->data_length) - offset;
44 
45 	// copy one S/G entry at a time
46 	for (; size > 0 && requestSize > 0 && sgCount > 0; ++sgList, --sgCount) {
47 		size_t bytes;
48 
49 		bytes = MIN(size, requestSize);
50 		bytes = MIN(bytes, sgList->size);
51 
52 		if (toBuffer) {
53 			vm_memcpy_from_physical(buffer, (addr_t)sgList->address + offset,
54 				bytes, false);
55 		} else {
56 			vm_memcpy_to_physical((addr_t)sgList->address + offset, buffer,
57 				bytes, false);
58 		}
59 
60 		buffer = (char *)buffer + bytes;
61 		size -= bytes;
62 		offset = 0;
63 	}
64 
65 	return size == 0;
66 }
67