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}