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//! General SCSI emulation routines 9 10 11#include "ide_internal.h" 12#include "ide_sim.h" 13 14#include <vm/vm.h> 15 16#include <string.h> 17 18 19/*! Emulate REQUEST SENSE */ 20void 21ide_request_sense(ide_device_info *device, ide_qrequest *qrequest) 22{ 23 scsi_ccb *request = qrequest->request; 24 scsi_cmd_request_sense *cmd = (scsi_cmd_request_sense *)request->cdb; 25 scsi_sense sense; 26 uint32 transferSize; 27 28 // cannot use finish_checksense here, as data is not copied into autosense buffer 29 // but into normal data buffer, SCSI result is GOOD and CAM status is REQ_CMP 30 31 if (device->combined_sense) 32 create_sense(device, &sense); 33 else 34 memset(&sense, 0, sizeof(sense)); 35 36 copy_sg_data(request, 0, cmd->allocation_length, &sense, sizeof(sense), false); 37 38 // reset sense information on read 39 device->combined_sense = 0; 40 41 transferSize = min_c(sizeof(sense), cmd->allocation_length); 42 transferSize = min_c(transferSize, request->data_length); 43 44 request->data_resid = request->data_length - transferSize; 45 46 // normally, all flags are set to "success", but for Request Sense 47 // this would have overwritten the sense we want to read 48 device->subsys_status = SCSI_REQ_CMP; 49 request->device_status = SCSI_STATUS_GOOD; 50} 51 52 53/*! Copy data between request data and buffer 54 request - request to copy data from/to 55 offset - offset of data in request 56 allocation_length- limit of request's data buffer according to CDB 57 buffer - data to copy data from/to 58 size - number of bytes to copy 59 to_buffer - true: copy from request to buffer 60 false: copy from buffer to request 61 return: true, if data of request was large enough 62*/ 63bool 64copy_sg_data(scsi_ccb *request, uint offset, uint allocationLength, 65 void *buffer, int size, bool toBuffer) 66{ 67 const physical_entry *sgList = request->sg_list; 68 int sgCount = request->sg_count; 69 int requestSize; 70 71 SHOW_FLOW(3, "offset=%u, req_size_limit=%d, size=%d, sg_list=%p, sg_cnt=%d, %s buffer", 72 offset, allocationLength, size, sgList, sgCount, toBuffer ? "to" : "from"); 73 74 // skip unused S/G entries 75 while (sgCount > 0 && offset >= sgList->size) { 76 offset -= sgList->size; 77 ++sgList; 78 --sgCount; 79 } 80 81 if (sgCount == 0) 82 return 0; 83 84 // remaining bytes we are allowed to copy from/to request 85 requestSize = min_c(allocationLength, request->data_length) - offset; 86 87 // copy one S/G entry at a time 88 for (; size > 0 && requestSize > 0 && sgCount > 0; ++sgList, --sgCount) { 89 size_t bytes; 90 91 bytes = min_c(size, requestSize); 92 bytes = min_c(bytes, sgList->size); 93 94 SHOW_FLOW(4, "buffer=%p, virt_addr=%p, bytes=%d, to_buffer=%d", 95 buffer, (void *)(sgList->address + offset), (int)bytes, toBuffer); 96 97 if (toBuffer) { 98 vm_memcpy_from_physical(buffer, sgList->address + offset, bytes, 99 false); 100 } else { 101 vm_memcpy_to_physical(sgList->address + offset, buffer, bytes, 102 false); 103 } 104 105 buffer = (char *)buffer + bytes; 106 size -= bytes; 107 offset = 0; 108 } 109 110 return size == 0; 111} 112