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