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