• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "scsi_linux_adapter.h"
17 
18 #include <cerrno>
19 #include <cstdint>
20 #include <fcntl.h>
21 #include <hdf_base.h>
22 #include <hdf_log.h>
23 #include <cstdlib>
24 #include <cstring>
25 #include <scsi/sg.h>
26 #include <securec.h>
27 #include <sys/ioctl.h>
28 #include <termios.h>
29 #include <unistd.h>
30 #include <sstream>
31 #include <iomanip>
32 
33 #include "usbd_wrapper.h"
34 
35 #define HDF_LOG_TAG scsi_linux_adapter
36 
37 namespace OHOS {
38 namespace HDI {
39 namespace Usb {
40 namespace ScsiDdk {
41 namespace V1_0 {
42 
43 constexpr uint8_t SCSIPERIPHERAL_MAX_SENSE_DATA_LEN = 252;
44 constexpr uint8_t TWO_BYTE = 2;
45 constexpr uint8_t OPERATION_CODE_REQUEST_SENSE = 0x03;
46 
BytesToHex(const uint8_t * data,size_t length)47 static std::string BytesToHex(const uint8_t* data, size_t length)
48 {
49     std::ostringstream oss;
50     oss << std::hex << std::setfill('0');
51     for (size_t i = 0; i < length; ++i) {
52         oss << std::setw(TWO_BYTE) << static_cast<int>(data[i]) << ' ';
53     }
54     return oss.str();
55 }
56 
DxferDirectionToString(int direction)57 static std::string DxferDirectionToString(int direction)
58 {
59     switch (direction) {
60         case SG_DXFER_NONE: return "SG_DXFER_NONE";
61         case SG_DXFER_TO_DEV: return "SG_DXFER_TO_DEV";
62         case SG_DXFER_FROM_DEV: return "SG_DXFER_FROM_DEV";
63         case SG_DXFER_TO_FROM_DEV: return "SG_DXFER_TO_FROM_DEV";
64         default: return "UNKNOWN (" + std::to_string(direction) + ")";
65     }
66 }
ToString(const struct sg_io_hdr & ioHdr)67 static std::string ToString(const struct sg_io_hdr& ioHdr)
68 {
69     std::ostringstream buffer;
70     buffer << "sg_io_hdr{\n" << "  interface_id='" << ioHdr.interface_id << "' (" <<
71         static_cast<int>(ioHdr.interface_id) << ")\n" << "  cmdp=" <<  static_cast<void*>(ioHdr.cmdp) << " (";
72     if (ioHdr.cmdp && ioHdr.cmd_len > 0) {
73         buffer << "CMD: " << BytesToHex(reinterpret_cast<const uint8_t*>(ioHdr.cmdp), ioHdr.cmd_len);
74     } else {
75         buffer << "NULL or empty CMD";
76     }
77     buffer << ")\n" << "  cmd_len=" << static_cast<int>(ioHdr.cmd_len) << '\n' << "  dxfer_direction=" <<
78         DxferDirectionToString(ioHdr.dxfer_direction) << " (" << std::dec << ioHdr.dxfer_direction << ")\n" <<
79         "  dxferp=" << static_cast<void*>(ioHdr.dxferp) << '\n' << "  dxfer_len=" << ioHdr.dxfer_len << '\n' <<
80         "  sbp=" << static_cast<void*>(ioHdr.sbp) << '\n' << "  mx_sb_len=" << static_cast<int>(ioHdr.mx_sb_len) <<
81         '\n' << "  timeout=" << ioHdr.timeout << "\n" << "}";
82 
83     return buffer.str();
84 }
85 
UpdateResponse(const struct sg_io_hdr & ioHdr,Response & response)86 static void UpdateResponse(const struct sg_io_hdr& ioHdr, Response& response)
87 {
88     response.status = ioHdr.status;
89     response.maskedStatus = ioHdr.masked_status;
90     response.msgStatus = ioHdr.msg_status;
91     response.sbLenWr = ioHdr.sb_len_wr;
92     response.hostStatus = ioHdr.host_status;
93     response.driverStatus = ioHdr.driver_status;
94     response.resId = ioHdr.resid;
95     response.duration = ioHdr.duration;
96     response.transferredLength = ioHdr.dxfer_len - ioHdr.resid;
97 }
98 
SendRequest(const Request & request,uint8_t * buffer,uint32_t bufferSize,Response & response)99 int32_t LinuxScsiOsAdapter::SendRequest(const Request& request, uint8_t *buffer, uint32_t bufferSize,
100     Response& response)
101 {
102     uint8_t cmdLen = request.commandDescriptorBlock.size();
103     if (cmdLen == 0) {
104         HDF_LOGE("SendRequest: Command Descriptor Block is empty");
105         return SCSIPERIPHERAL_DDK_INVALID_PARAMETER;
106     }
107 
108     std::vector<uint8_t> cmd(request.commandDescriptorBlock.data(), request.commandDescriptorBlock.data() + cmdLen);
109 
110     struct sg_io_hdr ioHdr;
111     int32_t result = memset_s(&ioHdr, sizeof(ioHdr), 0, sizeof(ioHdr));
112     if (result != 0) {
113         HDF_LOGE("%{public}s memset_s(ioHdr) failed, result=%{public}d", __func__, result);
114         return SCSIPERIPHERAL_DDK_MEMORY_ERROR;
115     }
116     ioHdr.interface_id = 'S';
117     ioHdr.cmdp = cmd.data();
118     ioHdr.cmd_len = cmdLen;
119     ioHdr.dxfer_direction = request.dataTransferDirection;
120 
121     if ((buffer != nullptr) && (bufferSize != 0)) {
122         ioHdr.dxferp = buffer;
123         ioHdr.dxfer_len = bufferSize;
124     }
125 
126     if (cmd[0] == OPERATION_CODE_REQUEST_SENSE) {
127         ioHdr.sbp = nullptr;
128         ioHdr.mx_sb_len = 0;
129     } else {
130         response.senseData.resize(SCSIPERIPHERAL_MAX_SENSE_DATA_LEN);
131         ioHdr.sbp = response.senseData.data();
132         ioHdr.mx_sb_len = response.senseData.size();
133     }
134     ioHdr.timeout = request.timeout;
135     HDF_LOGD("SendRequest, request.devFd=%{public}d, \n%{public}s", request.devFd, ToString(ioHdr).c_str());
136 
137     if (ioctl(request.devFd, SG_IO, &ioHdr) < 0) {
138         if (errno == ETIME) {
139             HDF_LOGE("%{public}s: ioctl timeout", __func__);
140             return SCSIPERIPHERAL_DDK_TIMEOUT;
141         } else {
142             HDF_LOGE("%{public}s: ioctl failed, errno=%{public}d (%{public}s)", __func__, errno, strerror(errno));
143             return SCSIPERIPHERAL_DDK_IO_ERROR;
144         }
145     }
146 
147     UpdateResponse(ioHdr, response);
148     HDF_LOGD("response.status=%{public}x, transferredLength=%{public}d", response.status, response.transferredLength);
149     HDF_LOGD("SendRequest, response.senseData=[ %{public}s ]",
150         BytesToHex(reinterpret_cast<const uint8_t*>(response.senseData.data()), response.senseData.size()).c_str());
151 
152     return HDF_SUCCESS;
153 }
154 } // namespace V1_0
155 } // namespace ScsiDdk
156 } // namespace Usb
157 } // namespace HDI
158 } // namespace OHOS
159