Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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