root/drivers/scsi/ufs/ufs_bsg.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ufs_bsg_get_query_desc_size
  2. ufs_bsg_verify_query_size
  3. ufs_bsg_alloc_desc_buffer
  4. ufs_bsg_request
  5. ufs_bsg_remove
  6. ufs_bsg_node_release
  7. ufs_bsg_probe

   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 
   9 static 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 
  28 static 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 
  43 static 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 
  77 out:
  78         return 0;
  79 }
  80 
  81 static 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         pm_runtime_get_sync(hba->dev);
 102 
 103         msgcode = bsg_request->msgcode;
 104         switch (msgcode) {
 105         case UPIU_TRANSACTION_QUERY_REQ:
 106                 desc_op = bsg_request->upiu_req.qr.opcode;
 107                 ret = ufs_bsg_alloc_desc_buffer(hba, job, &desc_buff,
 108                                                 &desc_len, desc_op);
 109                 if (ret)
 110                         goto out;
 111 
 112                 /* fall through */
 113         case UPIU_TRANSACTION_NOP_OUT:
 114         case UPIU_TRANSACTION_TASK_REQ:
 115                 ret = ufshcd_exec_raw_upiu_cmd(hba, &bsg_request->upiu_req,
 116                                                &bsg_reply->upiu_rsp, msgcode,
 117                                                desc_buff, &desc_len, desc_op);
 118                 if (ret)
 119                         dev_err(hba->dev,
 120                                 "exe raw upiu: error code %d\n", ret);
 121 
 122                 break;
 123         case UPIU_TRANSACTION_UIC_CMD:
 124                 memcpy(&uc, &bsg_request->upiu_req.uc, UIC_CMD_SIZE);
 125                 ret = ufshcd_send_uic_cmd(hba, &uc);
 126                 if (ret)
 127                         dev_err(hba->dev,
 128                                 "send uic cmd: error code %d\n", ret);
 129 
 130                 memcpy(&bsg_reply->upiu_rsp.uc, &uc, UIC_CMD_SIZE);
 131 
 132                 break;
 133         default:
 134                 ret = -ENOTSUPP;
 135                 dev_err(hba->dev, "unsupported msgcode 0x%x\n", msgcode);
 136 
 137                 break;
 138         }
 139 
 140         pm_runtime_put_sync(hba->dev);
 141 
 142         if (!desc_buff)
 143                 goto out;
 144 
 145         if (desc_op == UPIU_QUERY_OPCODE_READ_DESC && desc_len)
 146                 bsg_reply->reply_payload_rcv_len =
 147                         sg_copy_from_buffer(job->request_payload.sg_list,
 148                                             job->request_payload.sg_cnt,
 149                                             desc_buff, desc_len);
 150 
 151         kfree(desc_buff);
 152 
 153 out:
 154         bsg_reply->result = ret;
 155         job->reply_len = sizeof(struct ufs_bsg_reply);
 156         /* complete the job here only if no error */
 157         if (ret == 0)
 158                 bsg_job_done(job, ret, bsg_reply->reply_payload_rcv_len);
 159 
 160         return ret;
 161 }
 162 
 163 /**
 164  * ufs_bsg_remove - detach and remove the added ufs-bsg node
 165  *
 166  * Should be called when unloading the driver.
 167  */
 168 void ufs_bsg_remove(struct ufs_hba *hba)
 169 {
 170         struct device *bsg_dev = &hba->bsg_dev;
 171 
 172         if (!hba->bsg_queue)
 173                 return;
 174 
 175         bsg_remove_queue(hba->bsg_queue);
 176 
 177         device_del(bsg_dev);
 178         put_device(bsg_dev);
 179 }
 180 
 181 static inline void ufs_bsg_node_release(struct device *dev)
 182 {
 183         put_device(dev->parent);
 184 }
 185 
 186 /**
 187  * ufs_bsg_probe - Add ufs bsg device node
 188  * @hba: per adapter object
 189  *
 190  * Called during initial loading of the driver, and before scsi_scan_host.
 191  */
 192 int ufs_bsg_probe(struct ufs_hba *hba)
 193 {
 194         struct device *bsg_dev = &hba->bsg_dev;
 195         struct Scsi_Host *shost = hba->host;
 196         struct device *parent = &shost->shost_gendev;
 197         struct request_queue *q;
 198         int ret;
 199 
 200         device_initialize(bsg_dev);
 201 
 202         bsg_dev->parent = get_device(parent);
 203         bsg_dev->release = ufs_bsg_node_release;
 204 
 205         dev_set_name(bsg_dev, "ufs-bsg%u", shost->host_no);
 206 
 207         ret = device_add(bsg_dev);
 208         if (ret)
 209                 goto out;
 210 
 211         q = bsg_setup_queue(bsg_dev, dev_name(bsg_dev), ufs_bsg_request, NULL, 0);
 212         if (IS_ERR(q)) {
 213                 ret = PTR_ERR(q);
 214                 goto out;
 215         }
 216 
 217         hba->bsg_queue = q;
 218 
 219         return 0;
 220 
 221 out:
 222         dev_err(bsg_dev, "fail to initialize a bsg dev %d\n", shost->host_no);
 223         put_device(bsg_dev);
 224         return ret;
 225 }

/* [<][>][^][v][top][bottom][index][help] */