BPicture: Fix archive constructor.
[haiku.git] / src / add-ons / kernel / bus_managers / ide / emulation.cpp
blob21759abf8589be1b2d9dbc93d22b0172f5e0a052
1 /*
2 * Copyright 2004-2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3 * Copyright 2002/03, Thomas Kurschel. All rights reserved.
5 * Distributed under the terms of the MIT License.
6 */
8 //! General SCSI emulation routines
11 #include "ide_internal.h"
12 #include "ide_sim.h"
14 #include <vm/vm.h>
16 #include <string.h>
19 /*! Emulate REQUEST SENSE */
20 void
21 ide_request_sense(ide_device_info *device, ide_qrequest *qrequest)
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;
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
31 if (device->combined_sense)
32 create_sense(device, &sense);
33 else
34 memset(&sense, 0, sizeof(sense));
36 copy_sg_data(request, 0, cmd->allocation_length, &sense, sizeof(sense), false);
38 // reset sense information on read
39 device->combined_sense = 0;
41 transferSize = min_c(sizeof(sense), cmd->allocation_length);
42 transferSize = min_c(transferSize, request->data_length);
44 request->data_resid = request->data_length - transferSize;
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;
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
63 bool
64 copy_sg_data(scsi_ccb *request, uint offset, uint allocationLength,
65 void *buffer, int size, bool toBuffer)
67 const physical_entry *sgList = request->sg_list;
68 int sgCount = request->sg_count;
69 int requestSize;
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");
74 // skip unused S/G entries
75 while (sgCount > 0 && offset >= sgList->size) {
76 offset -= sgList->size;
77 ++sgList;
78 --sgCount;
81 if (sgCount == 0)
82 return 0;
84 // remaining bytes we are allowed to copy from/to request
85 requestSize = min_c(allocationLength, request->data_length) - offset;
87 // copy one S/G entry at a time
88 for (; size > 0 && requestSize > 0 && sgCount > 0; ++sgList, --sgCount) {
89 size_t bytes;
91 bytes = min_c(size, requestSize);
92 bytes = min_c(bytes, sgList->size);
94 SHOW_FLOW(4, "buffer=%p, virt_addr=%p, bytes=%d, to_buffer=%d",
95 buffer, (void *)(sgList->address + offset), (int)bytes, toBuffer);
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);
105 buffer = (char *)buffer + bytes;
106 size -= bytes;
107 offset = 0;
110 return size == 0;