cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ufs_bsg.c (5311B)


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