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

scsi: hisi_sas: Add support for DIF feature for v2 hw

For v3 hw, we support DIF operation for SAS, but not SATA.

In addition, DIF CRC16 is supported.

This patchset adds the SW support for the described features. The main
components are as follows:

- Get protection mask from module param
- Fill PI fields
- Fill related to DIF in DQ and protection iu memories

Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com>
Signed-off-by: John Garry <john.garry@huawei.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>

authored by

Xiang Chen and committed by
Martin K. Petersen
d6a9000b 4e87eb2f

+137 -3
+8
drivers/scsi/hisi_sas/hisi_sas.h
··· 69 69 #define HISI_SAS_SATA_PROTOCOL_FPDMA 0x8 70 70 #define HISI_SAS_SATA_PROTOCOL_ATAPI 0x10 71 71 72 + #define HISI_SAS_DIF_PROT_MASK (SHOST_DIF_TYPE1_PROTECTION | \ 73 + SHOST_DIF_TYPE2_PROTECTION | \ 74 + SHOST_DIF_TYPE3_PROTECTION) 75 + 76 + #define HISI_SAS_PROT_MASK (HISI_SAS_DIF_PROT_MASK) 77 + 72 78 struct hisi_hba; 73 79 74 80 enum { ··· 273 267 struct platform_device *platform_dev; 274 268 struct pci_dev *pci_dev; 275 269 struct device *dev; 270 + 271 + int prot_mask; 276 272 277 273 void __iomem *regs; 278 274 void __iomem *sgpio_regs;
+129 -3
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
··· 127 127 #define PHY_CTRL (PORT_BASE + 0x14) 128 128 #define PHY_CTRL_RESET_OFF 0 129 129 #define PHY_CTRL_RESET_MSK (0x1 << PHY_CTRL_RESET_OFF) 130 + #define CMD_HDR_PIR_OFF 8 131 + #define CMD_HDR_PIR_MSK (0x1 << CMD_HDR_PIR_OFF) 130 132 #define SL_CFG (PORT_BASE + 0x84) 131 133 #define AIP_LIMIT (PORT_BASE + 0x90) 132 134 #define SL_CONTROL (PORT_BASE + 0x94) ··· 335 333 #define ITCT_HDR_RTOLT_OFF 48 336 334 #define ITCT_HDR_RTOLT_MSK (0xffffULL << ITCT_HDR_RTOLT_OFF) 337 335 336 + struct hisi_sas_protect_iu_v3_hw { 337 + u32 dw0; 338 + u32 lbrtcv; 339 + u32 lbrtgv; 340 + u32 dw3; 341 + u32 dw4; 342 + u32 dw5; 343 + u32 rsv; 344 + }; 345 + 338 346 struct hisi_sas_complete_v3_hdr { 339 347 __le32 dw0; 340 348 __le32 dw1; ··· 384 372 ((fis.command == ATA_CMD_DEV_RESET) && \ 385 373 ((fis.control & ATA_SRST) != 0))) 386 374 375 + #define T10_INSRT_EN_OFF 0 376 + #define T10_INSRT_EN_MSK (1 << T10_INSRT_EN_OFF) 377 + #define T10_RMV_EN_OFF 1 378 + #define T10_RMV_EN_MSK (1 << T10_RMV_EN_OFF) 379 + #define T10_RPLC_EN_OFF 2 380 + #define T10_RPLC_EN_MSK (1 << T10_RPLC_EN_OFF) 381 + #define T10_CHK_EN_OFF 3 382 + #define T10_CHK_EN_MSK (1 << T10_CHK_EN_OFF) 383 + #define INCR_LBRT_OFF 5 384 + #define INCR_LBRT_MSK (1 << INCR_LBRT_OFF) 385 + #define USR_DATA_BLOCK_SZ_OFF 20 386 + #define USR_DATA_BLOCK_SZ_MSK (0x3 << USR_DATA_BLOCK_SZ_OFF) 387 + #define T10_CHK_MSK_OFF 16 388 + 387 389 static bool hisi_sas_intr_conv; 388 390 MODULE_PARM_DESC(intr_conv, "interrupt converge enable (0-1)"); 391 + 392 + /* permit overriding the host protection capabilities mask (EEDP/T10 PI) */ 393 + static int prot_mask; 394 + module_param(prot_mask, int, 0); 395 + MODULE_PARM_DESC(prot_mask, " host protection capabilities mask, def=0x0 "); 389 396 390 397 static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off) 391 398 { ··· 972 941 hdr->sg_len = cpu_to_le32(n_elem << CMD_HDR_DATA_SGL_LEN_OFF); 973 942 } 974 943 944 + static u32 get_prot_chk_msk_v3_hw(struct scsi_cmnd *scsi_cmnd) 945 + { 946 + unsigned char prot_flags = scsi_cmnd->prot_flags; 947 + 948 + if (prot_flags & SCSI_PROT_TRANSFER_PI) { 949 + if (prot_flags & SCSI_PROT_REF_CHECK) 950 + return 0xc << 16; 951 + return 0xfc << 16; 952 + } 953 + return 0; 954 + } 955 + 956 + static void fill_prot_v3_hw(struct scsi_cmnd *scsi_cmnd, 957 + struct hisi_sas_protect_iu_v3_hw *prot) 958 + { 959 + unsigned char prot_op = scsi_get_prot_op(scsi_cmnd); 960 + unsigned int interval = scsi_prot_interval(scsi_cmnd); 961 + u32 lbrt_chk_val = t10_pi_ref_tag(scsi_cmnd->request); 962 + 963 + switch (prot_op) { 964 + case SCSI_PROT_READ_STRIP: 965 + prot->dw0 |= (T10_RMV_EN_MSK | T10_CHK_EN_MSK); 966 + prot->lbrtcv = lbrt_chk_val; 967 + prot->dw4 |= get_prot_chk_msk_v3_hw(scsi_cmnd); 968 + break; 969 + case SCSI_PROT_WRITE_INSERT: 970 + prot->dw0 |= T10_INSRT_EN_MSK; 971 + prot->lbrtgv = lbrt_chk_val; 972 + break; 973 + default: 974 + WARN(1, "prot_op(0x%x) is not valid\n", prot_op); 975 + break; 976 + } 977 + 978 + switch (interval) { 979 + case 512: 980 + break; 981 + case 4096: 982 + prot->dw0 |= (0x1 << USR_DATA_BLOCK_SZ_OFF); 983 + break; 984 + case 520: 985 + prot->dw0 |= (0x2 << USR_DATA_BLOCK_SZ_OFF); 986 + break; 987 + default: 988 + WARN(1, "protection interval (0x%x) invalid\n", 989 + interval); 990 + break; 991 + } 992 + 993 + prot->dw0 |= INCR_LBRT_MSK; 994 + } 995 + 975 996 static void prep_ssp_v3_hw(struct hisi_hba *hisi_hba, 976 997 struct hisi_sas_slot *slot) 977 998 { ··· 1035 952 struct sas_ssp_task *ssp_task = &task->ssp_task; 1036 953 struct scsi_cmnd *scsi_cmnd = ssp_task->cmd; 1037 954 struct hisi_sas_tmf_task *tmf = slot->tmf; 955 + unsigned char prot_op = scsi_get_prot_op(scsi_cmnd); 1038 956 int has_data = 0, priority = !!tmf; 1039 957 u8 *buf_cmd; 1040 - u32 dw1 = 0, dw2 = 0; 958 + u32 dw1 = 0, dw2 = 0, len = 0; 1041 959 1042 960 hdr->dw0 = cpu_to_le32((1 << CMD_HDR_RESP_REPORT_OFF) | 1043 961 (2 << CMD_HDR_TLR_CTRL_OFF) | ··· 1068 984 1069 985 /* map itct entry */ 1070 986 dw1 |= sas_dev->device_id << CMD_HDR_DEV_ID_OFF; 1071 - hdr->dw1 = cpu_to_le32(dw1); 1072 987 1073 988 dw2 = (((sizeof(struct ssp_command_iu) + sizeof(struct ssp_frame_hdr) 1074 989 + 3) / 4) << CMD_HDR_CFL_OFF) | ··· 1080 997 prep_prd_sge_v3_hw(hisi_hba, slot, hdr, task->scatter, 1081 998 slot->n_elem); 1082 999 1083 - hdr->data_transfer_len = cpu_to_le32(task->total_xfer_len); 1084 1000 hdr->cmd_table_addr = cpu_to_le64(hisi_sas_cmd_hdr_addr_dma(slot)); 1085 1001 hdr->sts_buffer_addr = cpu_to_le64(hisi_sas_status_buf_addr_dma(slot)); 1086 1002 ··· 1104 1022 break; 1105 1023 } 1106 1024 } 1025 + 1026 + if (has_data && (prot_op != SCSI_PROT_NORMAL)) { 1027 + struct hisi_sas_protect_iu_v3_hw prot; 1028 + u8 *buf_cmd_prot; 1029 + 1030 + hdr->dw7 |= cpu_to_le32(1 << CMD_HDR_ADDR_MODE_SEL_OFF); 1031 + dw1 |= CMD_HDR_PIR_MSK; 1032 + buf_cmd_prot = hisi_sas_cmd_hdr_addr_mem(slot) + 1033 + sizeof(struct ssp_frame_hdr) + 1034 + sizeof(struct ssp_command_iu); 1035 + 1036 + memset(&prot, 0, sizeof(struct hisi_sas_protect_iu_v3_hw)); 1037 + fill_prot_v3_hw(scsi_cmnd, &prot); 1038 + memcpy(buf_cmd_prot, &prot, 1039 + sizeof(struct hisi_sas_protect_iu_v3_hw)); 1040 + 1041 + /* 1042 + * For READ, we need length of info read to memory, while for 1043 + * WRITE we need length of data written to the disk. 1044 + */ 1045 + if (prot_op == SCSI_PROT_WRITE_INSERT) { 1046 + unsigned int interval = scsi_prot_interval(scsi_cmnd); 1047 + unsigned int ilog2_interval = ilog2(interval); 1048 + 1049 + len = (task->total_xfer_len >> ilog2_interval) * 8; 1050 + } 1051 + 1052 + } 1053 + 1054 + hdr->dw1 = cpu_to_le32(dw1); 1055 + 1056 + hdr->data_transfer_len = cpu_to_le32(task->total_xfer_len + len); 1107 1057 } 1108 1058 1109 1059 static void prep_smp_v3_hw(struct hisi_hba *hisi_hba, ··· 2405 2291 hisi_hba->shost = shost; 2406 2292 SHOST_TO_SAS_HA(shost) = &hisi_hba->sha; 2407 2293 2294 + if (prot_mask & ~HISI_SAS_PROT_MASK) 2295 + dev_err(dev, "unsupported protection mask 0x%x, using default (0x0)\n", 2296 + prot_mask); 2297 + else 2298 + hisi_hba->prot_mask = prot_mask; 2299 + 2408 2300 timer_setup(&hisi_hba->timer, NULL, 0); 2409 2301 2410 2302 if (hisi_sas_get_fw_info(hisi_hba) < 0) ··· 2520 2400 rc = hisi_hba->hw->hw_init(hisi_hba); 2521 2401 if (rc) 2522 2402 goto err_out_register_ha; 2403 + 2404 + if (hisi_hba->prot_mask) { 2405 + dev_info(dev, "Registering for DIF/DIX prot_mask=0x%x\n", 2406 + prot_mask); 2407 + scsi_host_set_prot(hisi_hba->shost, prot_mask); 2408 + } 2523 2409 2524 2410 scsi_scan_host(shost); 2525 2411