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 "VirtioSCSIPrivate.h"
10
11#include <string.h>
12
13#include <vm/vm.h>
14
15
16/*!	Copy data between ccb data and buffer
17	ccb			- ccb to copy data from/to
18	offset			- offset of data in ccb
19	allocation_length- limit of ccb's data buffer according to CDB
20	buffer			- data to copy data from/to
21	size			- number of bytes to copy
22	to_buffer		- true: copy from ccb to buffer
23					  false: copy from buffer to ccb
24	return: true, if data of ccb was large enough
25*/
26bool
27copy_sg_data(scsi_ccb *ccb, uint offset, uint allocationLength,
28	void *buffer, int size, bool toBuffer)
29{
30	const physical_entry *sgList = ccb->sg_list;
31	int sgCount = ccb->sg_count;
32
33	// skip unused S/G entries
34	while (sgCount > 0 && offset >= sgList->size) {
35		offset -= sgList->size;
36		++sgList;
37		--sgCount;
38	}
39
40	if (sgCount == 0)
41		return false;
42
43	// remaining bytes we are allowed to copy from/to ccb
44	int requestSize = MIN(allocationLength, ccb->data_length) - offset;
45
46	// copy one S/G entry at a time
47	for (; size > 0 && requestSize > 0 && sgCount > 0; ++sgList, --sgCount) {
48		size_t bytes;
49
50		bytes = MIN(size, requestSize);
51		bytes = MIN(bytes, sgList->size);
52
53		if (toBuffer) {
54			vm_memcpy_from_physical(buffer, sgList->address + offset, bytes,
55				false);
56		} else {
57			vm_memcpy_to_physical(sgList->address + offset, buffer, bytes,
58				false);
59		}
60
61		buffer = (char *)buffer + bytes;
62		size -= bytes;
63		offset = 0;
64	}
65
66	return size == 0;
67}
68
69
70void
71swap_words(void *data, size_t size)
72{
73	uint16 *word = (uint16 *)data;
74	size_t count = size / 2;
75	while (count--) {
76		*word = B_BENDIAN_TO_HOST_INT16(*word);
77		word++;
78	}
79}
80