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

scsi: mpi3mr: Support for preallocation of SGL BSG data buffers part-3

The driver acquires the required NVMe SGLs from the pre-allocated
pool.

Co-developed-by: Sathya Prakash <sathya.prakash@broadcom.com>
Signed-off-by: Sathya Prakash <sathya.prakash@broadcom.com>
Signed-off-by: Chandrakanth patil <chandrakanth.patil@broadcom.com>
Link: https://lore.kernel.org/r/20231205191630.12201-4-chandrakanth.patil@broadcom.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>

authored by

Chandrakanth patil and committed by
Martin K. Petersen
9536af61 fb231d7d

+109 -27
+6 -4
drivers/scsi/mpi3mr/mpi3mr.h
··· 218 218 * @length: SGE length 219 219 * @rsvd: Reserved 220 220 * @rsvd1: Reserved 221 - * @sgl_type: sgl type 221 + * @sub_type: sgl sub type 222 + * @type: sgl type 222 223 */ 223 224 struct mpi3mr_nvme_pt_sge { 224 - u64 base_addr; 225 - u32 length; 225 + __le64 base_addr; 226 + __le32 length; 226 227 u16 rsvd; 227 228 u8 rsvd1; 228 - u8 sgl_type; 229 + u8 sub_type:4; 230 + u8 type:4; 229 231 }; 230 232 231 233 /**
+101 -23
drivers/scsi/mpi3mr/mpi3mr_app.c
··· 783 783 struct mpi3mr_buf_map *drv_bufs, u8 bufcnt) 784 784 { 785 785 struct mpi3mr_nvme_pt_sge *nvme_sgl; 786 - u64 sgl_ptr; 786 + __le64 sgl_dma; 787 787 u8 count; 788 788 size_t length = 0; 789 + u16 available_sges = 0, i; 790 + u32 sge_element_size = sizeof(struct mpi3mr_nvme_pt_sge); 789 791 struct mpi3mr_buf_map *drv_buf_iter = drv_bufs; 790 792 u64 sgemod_mask = ((u64)((mrioc->facts.sge_mod_mask) << 791 793 mrioc->facts.sge_mod_shift) << 32); 792 794 u64 sgemod_val = ((u64)(mrioc->facts.sge_mod_value) << 793 795 mrioc->facts.sge_mod_shift) << 32; 796 + u32 size; 797 + 798 + nvme_sgl = (struct mpi3mr_nvme_pt_sge *) 799 + ((u8 *)(nvme_encap_request->command) + MPI3MR_NVME_CMD_SGL_OFFSET); 794 800 795 801 /* 796 802 * Not all commands require a data transfer. If no data, just return ··· 805 799 for (count = 0; count < bufcnt; count++, drv_buf_iter++) { 806 800 if (drv_buf_iter->data_dir == DMA_NONE) 807 801 continue; 808 - sgl_ptr = (u64)drv_buf_iter->kern_buf_dma; 809 802 length = drv_buf_iter->kern_buf_len; 810 803 break; 811 804 } 812 - if (!length) 805 + if (!length || !drv_buf_iter->num_dma_desc) 813 806 return 0; 814 807 815 - if (sgl_ptr & sgemod_mask) { 808 + if (drv_buf_iter->num_dma_desc == 1) { 809 + available_sges = 1; 810 + goto build_sges; 811 + } 812 + 813 + sgl_dma = cpu_to_le64(mrioc->ioctl_chain_sge.dma_addr); 814 + if (sgl_dma & sgemod_mask) { 816 815 dprint_bsg_err(mrioc, 817 - "%s: SGL address collides with SGE modifier\n", 816 + "%s: SGL chain address collides with SGE modifier\n", 818 817 __func__); 819 818 return -1; 820 819 } 821 820 822 - sgl_ptr &= ~sgemod_mask; 823 - sgl_ptr |= sgemod_val; 824 - nvme_sgl = (struct mpi3mr_nvme_pt_sge *) 825 - ((u8 *)(nvme_encap_request->command) + MPI3MR_NVME_CMD_SGL_OFFSET); 821 + sgl_dma &= ~sgemod_mask; 822 + sgl_dma |= sgemod_val; 823 + 824 + memset(mrioc->ioctl_chain_sge.addr, 0, mrioc->ioctl_chain_sge.size); 825 + available_sges = mrioc->ioctl_chain_sge.size / sge_element_size; 826 + if (available_sges < drv_buf_iter->num_dma_desc) 827 + return -1; 826 828 memset(nvme_sgl, 0, sizeof(struct mpi3mr_nvme_pt_sge)); 827 - nvme_sgl->base_addr = sgl_ptr; 828 - nvme_sgl->length = length; 829 + nvme_sgl->base_addr = sgl_dma; 830 + size = drv_buf_iter->num_dma_desc * sizeof(struct mpi3mr_nvme_pt_sge); 831 + nvme_sgl->length = cpu_to_le32(size); 832 + nvme_sgl->type = MPI3MR_NVMESGL_LAST_SEGMENT; 833 + nvme_sgl = (struct mpi3mr_nvme_pt_sge *)mrioc->ioctl_chain_sge.addr; 834 + 835 + build_sges: 836 + for (i = 0; i < drv_buf_iter->num_dma_desc; i++) { 837 + sgl_dma = cpu_to_le64(drv_buf_iter->dma_desc[i].dma_addr); 838 + if (sgl_dma & sgemod_mask) { 839 + dprint_bsg_err(mrioc, 840 + "%s: SGL address collides with SGE modifier\n", 841 + __func__); 842 + return -1; 843 + } 844 + 845 + sgl_dma &= ~sgemod_mask; 846 + sgl_dma |= sgemod_val; 847 + 848 + nvme_sgl->base_addr = sgl_dma; 849 + nvme_sgl->length = cpu_to_le32(drv_buf_iter->dma_desc[i].size); 850 + nvme_sgl->type = MPI3MR_NVMESGL_DATA_SEGMENT; 851 + nvme_sgl++; 852 + available_sges--; 853 + } 854 + 829 855 return 0; 830 856 } 831 857 ··· 885 847 dma_addr_t prp_entry_dma, prp_page_dma, dma_addr; 886 848 u32 offset, entry_len, dev_pgsz; 887 849 u32 page_mask_result, page_mask; 888 - size_t length = 0; 850 + size_t length = 0, desc_len; 889 851 u8 count; 890 852 struct mpi3mr_buf_map *drv_buf_iter = drv_bufs; 891 853 u64 sgemod_mask = ((u64)((mrioc->facts.sge_mod_mask) << ··· 894 856 mrioc->facts.sge_mod_shift) << 32; 895 857 u16 dev_handle = nvme_encap_request->dev_handle; 896 858 struct mpi3mr_tgt_dev *tgtdev; 859 + u16 desc_count = 0; 897 860 898 861 tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, dev_handle); 899 862 if (!tgtdev) { ··· 913 874 914 875 dev_pgsz = 1 << (tgtdev->dev_spec.pcie_inf.pgsz); 915 876 mpi3mr_tgtdev_put(tgtdev); 877 + page_mask = dev_pgsz - 1; 878 + 879 + if (dev_pgsz > MPI3MR_IOCTL_SGE_SIZE) { 880 + dprint_bsg_err(mrioc, 881 + "%s: NVMe device page size(%d) is greater than ioctl data sge size(%d) for handle 0x%04x\n", 882 + __func__, dev_pgsz, MPI3MR_IOCTL_SGE_SIZE, dev_handle); 883 + return -1; 884 + } 885 + 886 + if (MPI3MR_IOCTL_SGE_SIZE % dev_pgsz) { 887 + dprint_bsg_err(mrioc, 888 + "%s: ioctl data sge size(%d) is not a multiple of NVMe device page size(%d) for handle 0x%04x\n", 889 + __func__, MPI3MR_IOCTL_SGE_SIZE, dev_pgsz, dev_handle); 890 + return -1; 891 + } 916 892 917 893 /* 918 894 * Not all commands require a data transfer. If no data, just return ··· 936 882 for (count = 0; count < bufcnt; count++, drv_buf_iter++) { 937 883 if (drv_buf_iter->data_dir == DMA_NONE) 938 884 continue; 939 - dma_addr = drv_buf_iter->kern_buf_dma; 940 885 length = drv_buf_iter->kern_buf_len; 941 886 break; 942 887 } 943 888 944 - if (!length) 889 + if (!length || !drv_buf_iter->num_dma_desc) 945 890 return 0; 891 + 892 + for (count = 0; count < drv_buf_iter->num_dma_desc; count++) { 893 + dma_addr = drv_buf_iter->dma_desc[count].dma_addr; 894 + if (dma_addr & page_mask) { 895 + dprint_bsg_err(mrioc, 896 + "%s:dma_addr 0x%llx is not aligned with page size 0x%x\n", 897 + __func__, dma_addr, dev_pgsz); 898 + return -1; 899 + } 900 + } 901 + 902 + dma_addr = drv_buf_iter->dma_desc[0].dma_addr; 903 + desc_len = drv_buf_iter->dma_desc[0].size; 946 904 947 905 mrioc->prp_sz = 0; 948 906 mrioc->prp_list_virt = dma_alloc_coherent(&mrioc->pdev->dev, ··· 985 919 * Check if we are within 1 entry of a page boundary we don't 986 920 * want our first entry to be a PRP List entry. 987 921 */ 988 - page_mask = dev_pgsz - 1; 989 922 page_mask_result = (uintptr_t)((u8 *)prp_page + prp_size) & page_mask; 990 923 if (!page_mask_result) { 991 924 dprint_bsg_err(mrioc, "%s: PRP page is not page aligned\n", ··· 1098 1033 prp_entry_dma += prp_size; 1099 1034 } 1100 1035 1101 - /* 1102 - * Bump the phys address of the command's data buffer by the 1103 - * entry_len. 1104 - */ 1105 - dma_addr += entry_len; 1106 - 1107 1036 /* decrement length accounting for last partial page. */ 1108 - if (entry_len > length) 1037 + if (entry_len >= length) { 1109 1038 length = 0; 1110 - else 1039 + } else { 1040 + if (entry_len <= desc_len) { 1041 + dma_addr += entry_len; 1042 + desc_len -= entry_len; 1043 + } 1044 + if (!desc_len) { 1045 + if ((++desc_count) >= 1046 + drv_buf_iter->num_dma_desc) { 1047 + dprint_bsg_err(mrioc, 1048 + "%s: Invalid len %ld while building PRP\n", 1049 + __func__, length); 1050 + goto err_out; 1051 + } 1052 + dma_addr = 1053 + drv_buf_iter->dma_desc[desc_count].dma_addr; 1054 + desc_len = 1055 + drv_buf_iter->dma_desc[desc_count].size; 1056 + } 1111 1057 length -= entry_len; 1058 + } 1112 1059 } 1060 + 1113 1061 return 0; 1114 1062 err_out: 1115 1063 if (mrioc->prp_list_virt) {
+2
include/uapi/scsi/scsi_bsg_mpi3mr.h
··· 491 491 #define MPI3MR_NVME_DATA_FORMAT_PRP 0 492 492 #define MPI3MR_NVME_DATA_FORMAT_SGL1 1 493 493 #define MPI3MR_NVME_DATA_FORMAT_SGL2 2 494 + #define MPI3MR_NVMESGL_DATA_SEGMENT 0x00 495 + #define MPI3MR_NVMESGL_LAST_SEGMENT 0x03 494 496 495 497 /* MPI3: task management related definitions */ 496 498 struct mpi3_scsi_task_mgmt_request {