blob: 4249aa6051cf246bf6d2dffcac3752e3bf2152c1 [file] [log] [blame]
merothh54856102021-11-04 12:07:41 +05301/*
2 * Copyright (c) 2020 The Linux Foundation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
13 * * Neither the name of The Linux Foundation nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30
31#define LOG_TAG "recovery_ufs"
32
33#include "recovery-ufs-bsg.h"
34
35#ifndef _BSG_FRAMEWORK_KERNEL_HEADERS
36#ifndef _GENERIC_KERNEL_HEADERS
37#include <scsi/ufs/ioctl.h>
38#include <scsi/ufs/ufs.h>
39#endif
40#endif
41
42//Size of the buffer that needs to be passed to the UFS ioctl
43#define UFS_ATTR_DATA_SIZE 32
44
45#ifdef _BSG_FRAMEWORK_KERNEL_HEADERS
46static int get_ufs_bsg_dev(void)
47{
48 DIR *dir;
49 struct dirent *ent;
50 int ret = -ENODEV;
51
52 if ((dir = opendir ("/dev")) != NULL) {
53 /* read all the files and directories within directory */
54 while ((ent = readdir(dir)) != NULL) {
55 if (!strcmp(ent->d_name, "ufs-bsg") ||
56 !strcmp(ent->d_name, "ufs-bsg0")) {
57 snprintf(ufs_bsg_dev, FNAME_SZ, "/dev/%s", ent->d_name);
58 ret = 0;
59 break;
60 }
61 }
62 if (ret)
63 ALOGE("could not find the ufs-bsg dev\n");
64 closedir (dir);
65 } else {
66 /* could not open directory */
67 ALOGE("could not open /dev (error no: %d)\n", errno);
68 ret = -EINVAL;
69 }
70
71 return ret;
72}
73
74int ufs_bsg_dev_open(void)
75{
76 int ret;
77 if (!fd_ufs_bsg) {
78 fd_ufs_bsg = open(ufs_bsg_dev, O_RDWR);
79 ret = errno;
80 if (fd_ufs_bsg < 0) {
81 ALOGE("Unable to open %s (error no: %d)",
82 ufs_bsg_dev, errno);
83 fd_ufs_bsg = 0;
84 return ret;
85 }
86 }
87 return 0;
88}
89
90void ufs_bsg_dev_close(void)
91{
92 if (fd_ufs_bsg) {
93 close(fd_ufs_bsg);
94 fd_ufs_bsg = 0;
95 }
96}
97
98static int ufs_bsg_ioctl(int fd, struct ufs_bsg_request *req,
99 struct ufs_bsg_reply *rsp, __u8 *buf, __u32 buf_len,
100 enum bsg_ioctl_dir dir)
101{
102 int ret;
LuK1337dc711ce2021-05-27 20:44:42 +0200103 struct sg_io_v4 sg_io{};
merothh54856102021-11-04 12:07:41 +0530104
105 sg_io.guard = 'Q';
106 sg_io.protocol = BSG_PROTOCOL_SCSI;
107 sg_io.subprotocol = BSG_SUB_PROTOCOL_SCSI_TRANSPORT;
108 sg_io.request_len = sizeof(*req);
109 sg_io.request = (__u64)req;
110 sg_io.response = (__u64)rsp;
111 sg_io.max_response_len = sizeof(*rsp);
112 if (dir == BSG_IOCTL_DIR_FROM_DEV) {
113 sg_io.din_xfer_len = buf_len;
114 sg_io.din_xferp = (__u64)(buf);
115 } else {
116 sg_io.dout_xfer_len = buf_len;
117 sg_io.dout_xferp = (__u64)(buf);
118 }
119
120 ret = ioctl(fd, SG_IO, &sg_io);
121 if (ret)
122 ALOGE("%s: Error from sg_io ioctl (return value: %d, error no: %d, reply result from LLD: %d\n)",
123 __func__, ret, errno, rsp->result);
124
125 if (sg_io.info || rsp->result) {
126 ALOGE("%s: Error from sg_io info (check sg info: device_status: 0x%x, transport_status: 0x%x, driver_status: 0x%x, reply result from LLD: %d\n)",
127 __func__, sg_io.device_status, sg_io.transport_status,
128 sg_io.driver_status, rsp->result);
129 ret = -EAGAIN;
130 }
131
132 return ret;
133}
134
135static void compose_ufs_bsg_query_req(struct ufs_bsg_request *req, __u8 func,
136 __u8 opcode, __u8 idn, __u8 index, __u8 sel,
137 __u16 length)
138{
139 struct utp_upiu_header *hdr = &req->upiu_req.header;
140 struct utp_upiu_query *qr = &req->upiu_req.qr;
141
142 req->msgcode = UTP_UPIU_QUERY_REQ;
143 hdr->dword_0 = DWORD(UTP_UPIU_QUERY_REQ, 0, 0, 0);
144 hdr->dword_1 = DWORD(0, func, 0, 0);
145 hdr->dword_2 = DWORD(0, 0, length >> 8, (__u8)length);
146 qr->opcode = opcode;
147 qr->idn = idn;
148 qr->index = index;
149 qr->selector = sel;
150 qr->length = htobe16(length);
151}
152
153
154static int ufs_query_attr(int fd, __u32 value,
155 __u8 func, __u8 opcode, __u8 idn,
156 __u8 index, __u8 sel)
157{
LuK1337dc711ce2021-05-27 20:44:42 +0200158 struct ufs_bsg_request req{};
159 struct ufs_bsg_reply rsp{};
merothh54856102021-11-04 12:07:41 +0530160 enum bsg_ioctl_dir dir = BSG_IOCTL_DIR_FROM_DEV;
161 int ret = 0;
162
163 if (opcode == QUERY_REQ_OP_WRITE_DESC || opcode == QUERY_REQ_OP_WRITE_ATTR)
164 dir = BSG_IOCTL_DIR_TO_DEV;
165
166 req.upiu_req.qr.value = htobe32(value);
167
168 compose_ufs_bsg_query_req(&req, func, opcode, idn, index, sel, 0);
169
170 ret = ufs_bsg_ioctl(fd, &req, &rsp, 0, 0, dir);
171 if (ret)
172 ALOGE("%s: Error from ufs_bsg_ioctl (return value: %d, error no: %d\n)",
173 __func__, ret, errno);
174
175 return ret;
176}
177
LuK1337dc711ce2021-05-27 20:44:42 +0200178int32_t set_boot_lun(char *sg_dev __unused,uint8_t lun_id)
merothh54856102021-11-04 12:07:41 +0530179{
180 int32_t ret;
181 __u32 boot_lun_id = lun_id;
182
183 ret = get_ufs_bsg_dev();
184 if (ret)
185 return ret;
186 ALOGV("Found the ufs bsg dev: %s\n", ufs_bsg_dev);
187
188 ret = ufs_bsg_dev_open();
189 if (ret)
190 return ret;
191 ALOGV("Opened ufs bsg dev: %s\n", ufs_bsg_dev);
192
193 ret = ufs_query_attr(fd_ufs_bsg, boot_lun_id, QUERY_REQ_FUNC_STD_WRITE,
194 QUERY_REQ_OP_WRITE_ATTR, QUERY_ATTR_IDN_BOOT_LU_EN, 0, 0);
195 if (ret) {
196 ALOGE("Error requesting ufs attr idn %d via query ioctl (return value: %d, error no: %d)",
197 QUERY_ATTR_IDN_BOOT_LU_EN, ret, errno);
198 goto out;
199 }
200out:
201 ufs_bsg_dev_close();
202 return ret;
203}
204#endif
205
206#ifndef _BSG_FRAMEWORK_KERNEL_HEADERS
207int32_t set_boot_lun(char *sg_dev, uint8_t boot_lun_id)
208{
209#ifndef _GENERIC_KERNEL_HEADERS
210 int fd = -1;
211 int rc;
212 struct ufs_ioctl_query_data *data = NULL;
213 size_t ioctl_data_size = sizeof(struct ufs_ioctl_query_data) + UFS_ATTR_DATA_SIZE;
214
215 data = (struct ufs_ioctl_query_data*)malloc(ioctl_data_size);
216 if (!data) {
217 fprintf(stderr, "%s: Failed to alloc query data struct\n",
218 __func__);
219 goto error;
220 }
221 memset(data, 0, ioctl_data_size);
222 data->opcode = UPIU_QUERY_OPCODE_WRITE_ATTR;
223 data->idn = QUERY_ATTR_IDN_BOOT_LU_EN;
224 data->buf_size = UFS_ATTR_DATA_SIZE;
225 data->buffer[0] = boot_lun_id;
226 fd = open(sg_dev, O_RDWR);
227 if (fd < 0) {
228 fprintf(stderr, "%s: Failed to open %s(%s)\n",
229 __func__,
230 sg_dev,
231 strerror(errno));
232 goto error;
233 }
234 rc = ioctl(fd, UFS_IOCTL_QUERY, data);
235 if (rc) {
236 fprintf(stderr, "%s: UFS query ioctl failed(%s)\n",
237 __func__,
238 strerror(errno));
239 goto error;
240 }
241 close(fd);
242 free(data);
243 return 0;
244error:
245 if (fd >= 0)
246 close(fd);
247 if (data)
248 free(data);
249 return -1;
250#else
251 return 0;
252#endif
253}
254#endif
255