1// SPDX-License-Identifier: GPL-2.0
2/*
3 * bsg endpoint that supports UPIUs
4 *
5 * Copyright (C) 2018 Western Digital Corporation
6 */
7#include "ufs_bsg.h"
8
9static int ufs_bsg_get_query_desc_size(struct ufs_hba *hba, int *desc_len,
10				       struct utp_upiu_query *qr)
11{
12	int desc_size = be16_to_cpu(qr->length);
13	int desc_id = qr->idn;
14
15	if (desc_size <= 0)
16		return -EINVAL;
17
18	ufshcd_map_desc_id_to_length(hba, desc_id, desc_len);
19	if (!*desc_len)
20		return -EINVAL;
21
22	*desc_len = min_t(int, *desc_len, desc_size);
23
24	return 0;
25}
26
27static int ufs_bsg_verify_query_size(struct ufs_hba *hba,
28				     unsigned int request_len,
29				     unsigned int reply_len)
30{
31	int min_req_len = sizeof(struct ufs_bsg_request);
32	int min_rsp_len = sizeof(struct ufs_bsg_reply);
33
34	if (min_req_len > request_len || min_rsp_len > reply_len) {
35		dev_err(hba->dev, "not enough space assigned\n");
36		return -EINVAL;
37	}
38
39	return 0;
40}
41
42static int ufs_bsg_alloc_desc_buffer(struct ufs_hba *hba, struct bsg_job *job,
43				     uint8_t **desc_buff, int *desc_len,
44				     enum query_opcode desc_op)
45{
46	struct ufs_bsg_request *bsg_request = job->request;
47	struct utp_upiu_query *qr;
48	u8 *descp;
49
50	if (desc_op != UPIU_QUERY_OPCODE_WRITE_DESC &&
51	    desc_op != UPIU_QUERY_OPCODE_READ_DESC)
52		goto out;
53
54	qr = &bsg_request->upiu_req.qr;
55	if (ufs_bsg_get_query_desc_size(hba, desc_len, qr)) {
56		dev_err(hba->dev, "Illegal desc size\n");
57		return -EINVAL;
58	}
59
60	if (*desc_len > job->request_payload.payload_len) {
61		dev_err(hba->dev, "Illegal desc size\n");
62		return -EINVAL;
63	}
64
65	descp = kzalloc(*desc_len, GFP_KERNEL);
66	if (!descp)
67		return -ENOMEM;
68
69	if (desc_op == UPIU_QUERY_OPCODE_WRITE_DESC)
70		sg_copy_to_buffer(job->request_payload.sg_list,
71				  job->request_payload.sg_cnt, descp,
72				  *desc_len);
73
74	*desc_buff = descp;
75
76out:
77	return 0;
78}
79
80static int ufs_bsg_request(struct bsg_job *job)
81{
82	struct ufs_bsg_request *bsg_request = job->request;
83	struct ufs_bsg_reply *bsg_reply = job->reply;
84	struct ufs_hba *hba = shost_priv(dev_to_shost(job->dev->parent));
85	unsigned int req_len = job->request_len;
86	unsigned int reply_len = job->reply_len;
87	struct uic_command uc = {};
88	int msgcode;
89	uint8_t *desc_buff = NULL;
90	int desc_len = 0;
91	enum query_opcode desc_op = UPIU_QUERY_OPCODE_NOP;
92	int ret;
93
94	ret = ufs_bsg_verify_query_size(hba, req_len, reply_len);
95	if (ret)
96		goto out;
97
98	bsg_reply->reply_payload_rcv_len = 0;
99
100	pm_runtime_get_sync(hba->dev);
101
102	msgcode = bsg_request->msgcode;
103	switch (msgcode) {
104	case UPIU_TRANSACTION_QUERY_REQ:
105		desc_op = bsg_request->upiu_req.qr.opcode;
106		ret = ufs_bsg_alloc_desc_buffer(hba, job, &desc_buff,
107						&desc_len, desc_op);
108		if (ret) {
109			pm_runtime_put_sync(hba->dev);
110			goto out;
111		}
112
113		fallthrough;
114	case UPIU_TRANSACTION_NOP_OUT:
115	case UPIU_TRANSACTION_TASK_REQ:
116		ret = ufshcd_exec_raw_upiu_cmd(hba, &bsg_request->upiu_req,
117					       &bsg_reply->upiu_rsp, msgcode,
118					       desc_buff, &desc_len, desc_op);
119		if (ret)
120			dev_err(hba->dev,
121				"exe raw upiu: error code %d\n", ret);
122
123		break;
124	case UPIU_TRANSACTION_UIC_CMD:
125		memcpy(&uc, &bsg_request->upiu_req.uc, UIC_CMD_SIZE);
126		ret = ufshcd_send_uic_cmd(hba, &uc);
127		if (ret)
128			dev_err(hba->dev,
129				"send uic cmd: error code %d\n", ret);
130
131		memcpy(&bsg_reply->upiu_rsp.uc, &uc, UIC_CMD_SIZE);
132
133		break;
134	default:
135		ret = -ENOTSUPP;
136		dev_err(hba->dev, "unsupported msgcode 0x%x\n", msgcode);
137
138		break;
139	}
140
141	pm_runtime_put_sync(hba->dev);
142
143	if (!desc_buff)
144		goto out;
145
146	if (desc_op == UPIU_QUERY_OPCODE_READ_DESC && desc_len)
147		bsg_reply->reply_payload_rcv_len =
148			sg_copy_from_buffer(job->request_payload.sg_list,
149					    job->request_payload.sg_cnt,
150					    desc_buff, desc_len);
151
152	kfree(desc_buff);
153
154out:
155	bsg_reply->result = ret;
156	job->reply_len = sizeof(struct ufs_bsg_reply);
157	/* complete the job here only if no error */
158	if (ret == 0)
159		bsg_job_done(job, ret, bsg_reply->reply_payload_rcv_len);
160
161	return ret;
162}
163
164/**
165 * ufs_bsg_remove - detach and remove the added ufs-bsg node
166 * @hba: per adapter object
167 *
168 * Should be called when unloading the driver.
169 */
170void ufs_bsg_remove(struct ufs_hba *hba)
171{
172	struct device *bsg_dev = &hba->bsg_dev;
173
174	if (!hba->bsg_queue)
175		return;
176
177	bsg_remove_queue(hba->bsg_queue);
178
179	device_del(bsg_dev);
180	put_device(bsg_dev);
181}
182
183static inline void ufs_bsg_node_release(struct device *dev)
184{
185	put_device(dev->parent);
186}
187
188/**
189 * ufs_bsg_probe - Add ufs bsg device node
190 * @hba: per adapter object
191 *
192 * Called during initial loading of the driver, and before scsi_scan_host.
193 */
194int ufs_bsg_probe(struct ufs_hba *hba)
195{
196	struct device *bsg_dev = &hba->bsg_dev;
197	struct Scsi_Host *shost = hba->host;
198	struct device *parent = &shost->shost_gendev;
199	struct request_queue *q;
200	int ret;
201
202	device_initialize(bsg_dev);
203
204	bsg_dev->parent = get_device(parent);
205	bsg_dev->release = ufs_bsg_node_release;
206
207	dev_set_name(bsg_dev, "ufs-bsg%u", shost->host_no);
208
209	ret = device_add(bsg_dev);
210	if (ret)
211		goto out;
212
213	q = bsg_setup_queue(bsg_dev, dev_name(bsg_dev), ufs_bsg_request, NULL, 0);
214	if (IS_ERR(q)) {
215		ret = PTR_ERR(q);
216		goto out;
217	}
218
219	hba->bsg_queue = q;
220
221	return 0;
222
223out:
224	dev_err(bsg_dev, "fail to initialize a bsg dev %d\n", shost->host_no);
225	put_device(bsg_dev);
226	return ret;
227}
228