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