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.
8 //! General SCSI emulation routines
11 #include "ide_internal.h"
19 /*! Emulate REQUEST SENSE */
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
;
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
);
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
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
;
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
;
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
) {
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
);
98 vm_memcpy_from_physical(buffer
, sgList
->address
+ offset
, bytes
,
101 vm_memcpy_to_physical(sgList
->address
+ offset
, buffer
, bytes
,
105 buffer
= (char *)buffer
+ bytes
;