blob: 84b0b2a54b484de7447531ba8c4f4c656f88f5a9 [file] [log] [blame]
micky387ec5db572021-06-10 19:46:35 +02001/*
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
35static int get_ufs_bsg_dev(void)
36{
37 DIR *dir;
38 struct dirent *ent;
39 int ret = -ENODEV;
40
41 if ((dir = opendir ("/dev")) != NULL) {
42 /* read all the files and directories within directory */
43 while ((ent = readdir(dir)) != NULL) {
44 if (!strcmp(ent->d_name, "ufs-bsg") ||
45 !strcmp(ent->d_name, "ufs-bsg0")) {
46 snprintf(ufs_bsg_dev, FNAME_SZ, "/dev/%s", ent->d_name);
47 ret = 0;
48 break;
49 }
50 }
51 if (ret)
52 ALOGE("could not find the ufs-bsg dev\n");
53 closedir (dir);
54 } else {
55 /* could not open directory */
56 ALOGE("could not open /dev (error no: %d)\n", errno);
57 ret = -EINVAL;
58 }
59
60 return ret;
61}
62
63int ufs_bsg_dev_open(void)
64{
65 int ret;
66 if (!fd_ufs_bsg) {
67 fd_ufs_bsg = open(ufs_bsg_dev, O_RDWR);
68 ret = errno;
69 if (fd_ufs_bsg < 0) {
70 ALOGE("Unable to open %s (error no: %d)",
71 ufs_bsg_dev, errno);
72 fd_ufs_bsg = 0;
73 return ret;
74 }
75 }
76 return 0;
77}
78
79void ufs_bsg_dev_close(void)
80{
81 if (fd_ufs_bsg) {
82 close(fd_ufs_bsg);
83 fd_ufs_bsg = 0;
84 }
85}
86
87static int ufs_bsg_ioctl(int fd, struct ufs_bsg_request *req,
88 struct ufs_bsg_reply *rsp, __u8 *buf, __u32 buf_len,
89 enum bsg_ioctl_dir dir)
90{
91 int ret;
92 struct sg_io_v4 sg_io = {0};
93
94 sg_io.guard = 'Q';
95 sg_io.protocol = BSG_PROTOCOL_SCSI;
96 sg_io.subprotocol = BSG_SUB_PROTOCOL_SCSI_TRANSPORT;
97 sg_io.request_len = sizeof(*req);
98 sg_io.request = (__u64)req;
99 sg_io.response = (__u64)rsp;
100 sg_io.max_response_len = sizeof(*rsp);
101 if (dir == BSG_IOCTL_DIR_FROM_DEV) {
102 sg_io.din_xfer_len = buf_len;
103 sg_io.din_xferp = (__u64)(buf);
104 } else {
105 sg_io.dout_xfer_len = buf_len;
106 sg_io.dout_xferp = (__u64)(buf);
107 }
108
109 ret = ioctl(fd, SG_IO, &sg_io);
110 if (ret)
111 ALOGE("%s: Error from sg_io ioctl (return value: %d, error no: %d, reply result from LLD: %d\n)",
112 __func__, ret, errno, rsp->result);
113
114 if (sg_io.info || rsp->result) {
115 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)",
116 __func__, sg_io.device_status, sg_io.transport_status,
117 sg_io.driver_status, rsp->result);
118 ret = -EAGAIN;
119 }
120
121 return ret;
122}
123
124static void compose_ufs_bsg_query_req(struct ufs_bsg_request *req, __u8 func,
125 __u8 opcode, __u8 idn, __u8 index, __u8 sel,
126 __u16 length)
127{
128 struct utp_upiu_header *hdr = &req->upiu_req.header;
129 struct utp_upiu_query *qr = &req->upiu_req.qr;
130
131 req->msgcode = UTP_UPIU_QUERY_REQ;
132 hdr->dword_0 = DWORD(UTP_UPIU_QUERY_REQ, 0, 0, 0);
133 hdr->dword_1 = DWORD(0, func, 0, 0);
134 hdr->dword_2 = DWORD(0, 0, length >> 8, (__u8)length);
135 qr->opcode = opcode;
136 qr->idn = idn;
137 qr->index = index;
138 qr->selector = sel;
139 qr->length = htobe16(length);
140}
141
142
143static int ufs_query_attr(int fd, __u32 value,
144 __u8 func, __u8 opcode, __u8 idn,
145 __u8 index, __u8 sel)
146{
147 struct ufs_bsg_request req = {0};
148 struct ufs_bsg_reply rsp = {0};
149 enum bsg_ioctl_dir dir = BSG_IOCTL_DIR_FROM_DEV;
150 int ret = 0;
151
152 if (opcode == QUERY_REQ_OP_WRITE_DESC || opcode == QUERY_REQ_OP_WRITE_ATTR)
153 dir = BSG_IOCTL_DIR_TO_DEV;
154
155 req.upiu_req.qr.value = htobe32(value);
156
157 compose_ufs_bsg_query_req(&req, func, opcode, idn, index, sel, 0);
158
159 ret = ufs_bsg_ioctl(fd, &req, &rsp, 0, 0, dir);
160 if (ret)
161 ALOGE("%s: Error from ufs_bsg_ioctl (return value: %d, error no: %d\n)",
162 __func__, ret, errno);
163
164 return ret;
165}
166
167int32_t set_boot_lun(char *sg_dev,uint8_t lun_id)
168{
169 int32_t ret;
170 __u32 boot_lun_id = lun_id;
171
172 ret = get_ufs_bsg_dev();
173 if (ret)
174 return ret;
175 ALOGV("Found the ufs bsg dev: %s\n", ufs_bsg_dev);
176
177 ret = ufs_bsg_dev_open();
178 if (ret)
179 return ret;
180 ALOGV("Opened ufs bsg dev: %s\n", ufs_bsg_dev);
181
182 ret = ufs_query_attr(fd_ufs_bsg, boot_lun_id, QUERY_REQ_FUNC_STD_WRITE,
183 QUERY_REQ_OP_WRITE_ATTR, QUERY_ATTR_IDN_BOOT_LU_EN, 0, 0);
184 if (ret) {
185 ALOGE("Error requesting ufs attr idn %d via query ioctl (return value: %d, error no: %d)",
186 QUERY_ATTR_IDN_BOOT_LU_EN, ret, errno);
187 goto out;
188 }
189out:
190 ufs_bsg_dev_close();
191 return ret;
192}