scsi_bsg.c 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. // SPDX-License-Identifier: GPL-2.0
  2. #include <linux/bsg.h>
  3. #include <scsi/scsi.h>
  4. #include <scsi/scsi_ioctl.h>
  5. #include <scsi/scsi_cmnd.h>
  6. #include <scsi/scsi_device.h>
  7. #include <scsi/sg.h>
  8. #include "scsi_priv.h"
  9. #define uptr64(val) ((void __user *)(uintptr_t)(val))
  10. static int scsi_bsg_sg_io_fn(struct request_queue *q, struct sg_io_v4 *hdr,
  11. fmode_t mode, unsigned int timeout)
  12. {
  13. struct scsi_cmnd *scmd;
  14. struct request *rq;
  15. struct bio *bio;
  16. int ret;
  17. if (hdr->protocol != BSG_PROTOCOL_SCSI ||
  18. hdr->subprotocol != BSG_SUB_PROTOCOL_SCSI_CMD)
  19. return -EINVAL;
  20. if (hdr->dout_xfer_len && hdr->din_xfer_len) {
  21. pr_warn_once("BIDI support in bsg has been removed.\n");
  22. return -EOPNOTSUPP;
  23. }
  24. rq = scsi_alloc_request(q, hdr->dout_xfer_len ?
  25. REQ_OP_DRV_OUT : REQ_OP_DRV_IN, 0);
  26. if (IS_ERR(rq))
  27. return PTR_ERR(rq);
  28. rq->timeout = timeout;
  29. scmd = blk_mq_rq_to_pdu(rq);
  30. scmd->cmd_len = hdr->request_len;
  31. if (scmd->cmd_len > sizeof(scmd->cmnd)) {
  32. ret = -EINVAL;
  33. goto out_put_request;
  34. }
  35. ret = -EFAULT;
  36. if (copy_from_user(scmd->cmnd, uptr64(hdr->request), scmd->cmd_len))
  37. goto out_put_request;
  38. ret = -EPERM;
  39. if (!scsi_cmd_allowed(scmd->cmnd, mode))
  40. goto out_put_request;
  41. ret = 0;
  42. if (hdr->dout_xfer_len) {
  43. ret = blk_rq_map_user(rq->q, rq, NULL, uptr64(hdr->dout_xferp),
  44. hdr->dout_xfer_len, GFP_KERNEL);
  45. } else if (hdr->din_xfer_len) {
  46. ret = blk_rq_map_user(rq->q, rq, NULL, uptr64(hdr->din_xferp),
  47. hdr->din_xfer_len, GFP_KERNEL);
  48. }
  49. if (ret)
  50. goto out_put_request;
  51. bio = rq->bio;
  52. blk_execute_rq(rq, !(hdr->flags & BSG_FLAG_Q_AT_TAIL));
  53. /*
  54. * fill in all the output members
  55. */
  56. hdr->device_status = scmd->result & 0xff;
  57. hdr->transport_status = host_byte(scmd->result);
  58. hdr->driver_status = 0;
  59. if (scsi_status_is_check_condition(scmd->result))
  60. hdr->driver_status = DRIVER_SENSE;
  61. hdr->info = 0;
  62. if (hdr->device_status || hdr->transport_status || hdr->driver_status)
  63. hdr->info |= SG_INFO_CHECK;
  64. hdr->response_len = 0;
  65. if (scmd->sense_len && hdr->response) {
  66. int len = min_t(unsigned int, hdr->max_response_len,
  67. scmd->sense_len);
  68. if (copy_to_user(uptr64(hdr->response), scmd->sense_buffer,
  69. len))
  70. ret = -EFAULT;
  71. else
  72. hdr->response_len = len;
  73. }
  74. if (rq_data_dir(rq) == READ)
  75. hdr->din_resid = scmd->resid_len;
  76. else
  77. hdr->dout_resid = scmd->resid_len;
  78. blk_rq_unmap_user(bio);
  79. out_put_request:
  80. blk_mq_free_request(rq);
  81. return ret;
  82. }
  83. struct bsg_device *scsi_bsg_register_queue(struct scsi_device *sdev)
  84. {
  85. return bsg_register_queue(sdev->request_queue, &sdev->sdev_gendev,
  86. dev_name(&sdev->sdev_gendev), scsi_bsg_sg_io_fn);
  87. }