From 66cae4a348cd2d8fb4e5465312a8182dffeb0d85 Mon Sep 17 00:00:00 2001 From: Boojin Kim Date: Wed, 24 Jan 2018 17:04:54 +0900 Subject: [PATCH] [COMMON] ufs: add fmp interface Change-Id: I1500ed9af17d73f35d39fb7602ab7062027e8d8f Signed-off-by: Boojin Kim --- drivers/scsi/ufs/Kconfig | 21 +++++ drivers/scsi/ufs/Makefile | 2 + drivers/scsi/ufs/ufs-exynos-fmp.c | 116 +++++++++++++++++++++++++ drivers/scsi/ufs/ufs-exynos-fmp.h | 38 ++++++++ drivers/scsi/ufs/ufs-exynos-smu.c | 140 ++++++++++++++++++++++++++++++ drivers/scsi/ufs/ufs-exynos-smu.h | 60 +++++++++++++ drivers/scsi/ufs/ufs-exynos.c | 45 ++++++++++ drivers/scsi/ufs/ufs-exynos.h | 1 - drivers/scsi/ufs/ufshcd.c | 17 +++- drivers/scsi/ufs/ufshcd.h | 30 +++++++ drivers/scsi/ufs/ufshci.h | 40 ++++++++- 11 files changed, 504 insertions(+), 6 deletions(-) create mode 100644 drivers/scsi/ufs/ufs-exynos-fmp.c create mode 100644 drivers/scsi/ufs/ufs-exynos-fmp.h create mode 100644 drivers/scsi/ufs/ufs-exynos-smu.c create mode 100644 drivers/scsi/ufs/ufs-exynos-smu.h diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig index 5d8082ea4929..a5dd1caf2306 100644 --- a/drivers/scsi/ufs/Kconfig +++ b/drivers/scsi/ufs/Kconfig @@ -135,4 +135,25 @@ config SCSI_UFS_EXYNOS If you have a controller with this interface, say Y or M here. + If unsure, say N. +config SCSI_UFS_EXYNOS_FMP + tristate "EXYNOS Flash Memory Protector for UFS Host" + default y + depends on SCSI_UFS_EXYNOS && EXYNOS_FMP + ---help--- + This selects the EXYNOS UFS FMP Driver. + + If you have a controller with this interface, say Y or M here. + + If unsure, say N. + +config SCSI_UFS_EXYNOS_SMU + tristate "EXYNOS Secure Management Unit for UFS Host" + default y + depends on SCSI_UFS_EXYNOS && EXYNOS_SMU + ---help--- + This selects the EXYNOS UFS SMU Driver. + + If you have a controller with this interface, say Y or M here. + If unsure, say N. diff --git a/drivers/scsi/ufs/Makefile b/drivers/scsi/ufs/Makefile index 79955d9d7d58..35e29296ad1e 100644 --- a/drivers/scsi/ufs/Makefile +++ b/drivers/scsi/ufs/Makefile @@ -7,3 +7,5 @@ obj-$(CONFIG_SCSI_UFSHCD) += ufshcd.o obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += ufshcd-pltfrm.o obj-$(CONFIG_SCSI_UFS_EXYNOS) += ufs-exynos.o ufs-exynos-dbg.o ufs-cal-9810.o +obj-$(CONFIG_SCSI_UFS_EXYNOS_FMP) += ufs-exynos-fmp.o +obj-$(CONFIG_SCSI_UFS_EXYNOS_SMU) += ufs-exynos-smu.o diff --git a/drivers/scsi/ufs/ufs-exynos-fmp.c b/drivers/scsi/ufs/ufs-exynos-fmp.c new file mode 100644 index 000000000000..64c55650093a --- /dev/null +++ b/drivers/scsi/ufs/ufs-exynos-fmp.c @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2016 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include + +#include "ufshcd.h" +#include "ufs-exynos.h" + +int exynos_ufs_fmp_cfg(struct ufs_hba *hba, + struct ufshcd_lrb *lrbp, + struct scatterlist *sg, + uint32_t index, int sector_offset) +{ + struct fmp_request req; + struct scsi_cmnd *cmd = lrbp->cmd; + struct bio *bio; + struct crypto_diskcipher *dtfm; + sector_t iv; + + if (!cmd || !virt_addr_valid(cmd)) { + dev_err(hba->dev, "Invalid cmd:%p\n", cmd); + goto no_crypto; + } + + /* fill fmp_data_setting */ + bio = cmd->request->bio; + dtfm = crypto_diskcipher_get(bio); + if (dtfm) { +#ifdef EANBLE_DISKCIPHER_DEBUG + crypto_diskcipher_check(bio, sg_page(sg)); +#endif + iv = bio->bi_iter.bi_sector + (sector_t) sector_offset; + req.table = (void *)&lrbp->ucd_prdt_ptr[index]; + req.cmdq_enabled = 0; + req.iv = &iv; + req.ivsize = sizeof(iv); +#ifdef CONFIG_EXYNOS_FMP_FIPS + /* check fips flag. use fmp without diskcipher */ + if (!dtfm->algo) { + if (exynos_fmp_crypt((void *)dtfm, &req)) + goto no_crypto; + return 0; + } +#endif + if (crypto_diskcipher_set_crypt(dtfm, &req)) { + pr_warn("%s: fails to set crypt\n", __func__); + return -EINVAL; + } + + return 0; + } +no_crypto: + exynos_fmp_bypass(&lrbp->ucd_prdt_ptr[index], 0); + return 0; +} + +int exynos_ufs_fmp_clear(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) +{ + int ret = 0; + int sg_segments, idx; + struct scatterlist *sg; + struct ufshcd_sg_entry *prd_table; + struct crypto_diskcipher *dtfm; + struct fmp_crypto_info *ci; + struct fmp_request req; + + if (!lrbp->cmd) + goto out; + + sg_segments = scsi_sg_count(lrbp->cmd); + if (!sg_segments) + goto out; + + dtfm = crypto_diskcipher_get(lrbp->cmd->request->bio); + if (dtfm) { +#ifdef CONFIG_EXYNOS_FMP_FIPS + /* check fips flag. use fmp without diskcipher */ + if (!dtfm->algo) { + prd_table = + (struct ufshcd_sg_entry *)lrbp->ucd_prdt_ptr; + scsi_for_each_sg(lrbp->cmd, sg, sg_segments, idx) { + req.table = (void *)&prd_table[idx]; + ret = exynos_fmp_clear((void *)dtfm, &req); + if (ret) + break; + } + goto out; + } +#endif + /* clear key on descrptor */ + ci = crypto_tfm_ctx(crypto_diskcipher_tfm(dtfm)); + if (ci && (ci->enc_mode == EXYNOS_FMP_FILE_ENC)) { + prd_table = + (struct ufshcd_sg_entry *)lrbp->ucd_prdt_ptr; + scsi_for_each_sg(lrbp->cmd, sg, sg_segments, idx) { + req.table = (void *)&prd_table[idx]; + ret = crypto_diskcipher_clear_crypt(dtfm, &req); + if (ret) + break; + } + } + } +out: + if (ret) + pr_err("%s: Fail to clear desc (%d)\n", __func__, ret); + return ret; +} diff --git a/drivers/scsi/ufs/ufs-exynos-fmp.h b/drivers/scsi/ufs/ufs-exynos-fmp.h new file mode 100644 index 000000000000..801562dfb2b7 --- /dev/null +++ b/drivers/scsi/ufs/ufs-exynos-fmp.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2013-2014 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef _UFS_EXYNOS_FMP_H_ +#define _UFS_EXYNOS_FMP_H_ + +#include "ufshcd.h" +#include "ufs-exynos.h" + +#ifdef CONFIG_SCSI_UFS_EXYNOS_FMP +int exynos_ufs_fmp_cfg(struct ufs_hba *hba, + struct ufshcd_lrb *lrbp, + struct scatterlist *sg, + uint32_t index, + int sector_offset); +int exynos_ufs_fmp_clear(struct ufs_hba *hba, struct ufshcd_lrb *lrbp); +#else +inline int exynos_ufs_fmp_cfg(struct ufs_hba *hba, + struct ufshcd_lrb *lrbp, + struct scatterlist *sg, + uint32_t index, + int sector_offset) +{ + return 0; +} + +int exynos_ufs_fmp_clear(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) +{ + return 0; +} +#endif /* CONFIG_SCSI_UFS_EXYNOS_FMP */ +#endif /* _UFS_EXYNOS_FMP_H_ */ diff --git a/drivers/scsi/ufs/ufs-exynos-smu.c b/drivers/scsi/ufs/ufs-exynos-smu.c new file mode 100644 index 000000000000..740d939db8de --- /dev/null +++ b/drivers/scsi/ufs/ufs-exynos-smu.c @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2016 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include + +#include "ufshcd.h" +#include "ufs-exynos.h" +#include "ufs-exynos-smu.h" + +#define EXYNOS_UFS_SMU_LABEL "ufs-exynos-smu" + +static struct exynos_smu_variant_ops *exynos_ufs_smu_get_vops(struct device *dev) +{ + struct exynos_smu_variant_ops *smu_vops = NULL; + struct device_node *node; + + node = of_parse_phandle(dev->of_node, EXYNOS_UFS_SMU_LABEL, 0); + if (!node) { + dev_err(dev, "%s: exynos-ufs-smu property not specified\n", + __func__); + goto err; + } + + smu_vops = exynos_smu_get_variant_ops(node); + if (!smu_vops) + dev_err(dev, "%s: Fail to get smu_vops\n", __func__); + + of_node_put(node); +err: + return smu_vops; +} + +static struct platform_device *exynos_ufs_smu_get_pdevice(struct device *dev) +{ + struct device_node *node; + struct platform_device *smu_pdev = NULL; + + node = of_parse_phandle(dev->of_node, EXYNOS_UFS_SMU_LABEL, 0); + if (!node) { + dev_err(dev, "%s: exynos-ufs-smu property not specified\n", + __func__); + goto err; + } + + smu_pdev = exynos_smu_get_pdevice(node); +err: + return smu_pdev; +} + +int exynos_ufs_smu_get_dev(struct exynos_ufs *ufs) +{ + int ret; + struct device *dev; + + if (!ufs || !ufs->dev) { + pr_err("%s: invalid ufs host, host->dev\n", __func__); + ret = -EINVAL; + goto err; + } + + dev = ufs->dev; + ufs->smu.vops = exynos_ufs_smu_get_vops(dev); + ufs->smu.pdev = exynos_ufs_smu_get_pdevice(dev); + + if (ufs->smu.pdev == ERR_PTR(-EPROBE_DEFER)) { + dev_err(dev, "%s: SMU device not probed yet\n", __func__); + ret = -EPROBE_DEFER; + goto err; + } + + if (!ufs->smu.pdev || !ufs->smu.vops) { + dev_err(dev, "%s: Host device doesn't have SMU or fail to get SMU", + __func__); + ret = -ENODEV; + goto err; + } + + return 0; +err: + ufs->smu.pdev = NULL; + ufs->smu.vops = NULL; + + return ret; +} + +int exynos_ufs_smu_init(struct exynos_ufs *ufs) +{ + struct smu_data_setting smu_set; + + if (!ufs->smu.vops || !ufs->smu.pdev) + return 0; + + smu_set.id = SMU_EMBEDDED; + smu_set.command = SMU_INIT; + return ufs->smu.vops->init(ufs->smu.pdev, &smu_set); +} + +int exynos_ufs_smu_sec_cfg(struct exynos_ufs *ufs) +{ + struct smu_data_setting smu_set; + + if (!ufs->smu.vops || !ufs->smu.pdev) + return 0; + + smu_set.id = SMU_EMBEDDED; + smu_set.desc_type = CFG_DESCTYPE; + + return ufs->smu.vops->sec_config(ufs->smu.pdev, &smu_set); +} + +int exynos_ufs_smu_resume(struct exynos_ufs *ufs) +{ + struct smu_data_setting smu_set; + + if (!ufs->smu.vops || !ufs->smu.pdev) + return 0; + + smu_set.id = SMU_EMBEDDED; + return ufs->smu.vops->resume(ufs->smu.pdev, &smu_set); +} + +int exynos_ufs_smu_abort(struct exynos_ufs *ufs) +{ + struct smu_data_setting smu_set; + + if (!ufs->smu.vops || !ufs->smu.pdev) + return 0; + + smu_set.id = SMU_EMBEDDED; + smu_set.command = SMU_ABORT; + return ufs->smu.vops->abort(ufs->smu.pdev, &smu_set); +} diff --git a/drivers/scsi/ufs/ufs-exynos-smu.h b/drivers/scsi/ufs/ufs-exynos-smu.h new file mode 100644 index 000000000000..7b4bd4bd6b41 --- /dev/null +++ b/drivers/scsi/ufs/ufs-exynos-smu.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2016 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef _UFS_EXYNOS_SMU_H_ +#define _UFS_EXYNOS_SMU_H_ + +#ifdef CONFIG_SCSI_UFS_EXYNOS_SMU +int exynos_ufs_smu_get_dev(struct exynos_ufs *ufs); +int exynos_ufs_smu_init(struct exynos_ufs *ufs); +int exynos_ufs_smu_sec_cfg(struct exynos_ufs *ufs); +int exynos_ufs_smu_resume(struct exynos_ufs *ufs); +int exynos_ufs_smu_abort(struct exynos_ufs *ufs); +#else +inline int exynos_ufs_smu_get_dev(struct exynos_ufs *ufs) +{ + if (ufs) { + ufs->smu.pdev = NULL; + ufs->smu.vops = NULL; + } + return 0; +} + +inline int exynos_ufs_smu_init(struct exynos_ufs *ufs) +{ + writel(0x0, ufs->reg_ufsp + UFSPSBEGIN0); + writel(0xffffffff, ufs->reg_ufsp + UFSPSEND0); + writel(0xff, ufs->reg_ufsp + UFSPSLUN0); + writel(0xf1, ufs->reg_ufsp + UFSPSCTRL0); + + return 0; +} + +inline int exynos_ufs_smu_sec_cfg(struct exynos_ufs *ufs) +{ + return 0; +} + +inline int exynos_ufs_smu_resume(struct exynos_ufs *ufs) +{ + writel(0x0, ufs->reg_ufsp + UFSPSBEGIN0); + writel(0xffffffff, ufs->reg_ufsp + UFSPSEND0); + writel(0xff, ufs->reg_ufsp + UFSPSLUN0); + writel(0xf1, ufs->reg_ufsp + UFSPSCTRL0); + + return 0; +} + +inline int exynos_ufs_smu_abort(struct exynos_ufs *ufs) +{ + return 0; +} + +#endif /* CONFIG_SCSI_UFS_EXYNOS_SMU */ +#endif /* _UFS_EXYNOS_SMU_H_ */ diff --git a/drivers/scsi/ufs/ufs-exynos.c b/drivers/scsi/ufs/ufs-exynos.c index 999225d92f57..4e3eb39aae00 100644 --- a/drivers/scsi/ufs/ufs-exynos.c +++ b/drivers/scsi/ufs/ufs-exynos.c @@ -21,6 +21,8 @@ #include "mphy.h" #include "ufshcd-pltfrm.h" #include "ufs-exynos.h" +#include "ufs-exynos-fmp.h" +#include "ufs-exynos-smu.h" /* @@ -592,6 +594,20 @@ static int exynos_ufs_init(struct ufs_hba *hba) if (ret) return ret; + ret = exynos_ufs_smu_get_dev(ufs); + if (ret == -EPROBE_DEFER) { + dev_err(ufs->dev, "%s: SMU device not probed yet (%d)\n", + __func__, ret); + return ret; + } else if (ret) { + dev_err(ufs->dev, "%s, Fail to get SMU device (%d)\n", + __func__, ret); + return ret; + } + + /* FMPSECURITY & SMU */ + exynos_ufs_smu_sec_cfg(ufs); + exynos_ufs_smu_init(ufs); /* Enable log */ ret = exynos_ufs_init_dbg(hba); @@ -871,6 +887,11 @@ static int __exynos_ufs_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) if (ufshcd_is_clkgating_allowed(hba)) clk_prepare_enable(ufs->clk_hci); exynos_ufs_ctrl_auto_hci_clk(ufs, false); + + /* FMPSECURITY & SMU resume */ + exynos_ufs_smu_sec_cfg(ufs); + exynos_ufs_smu_resume(ufs); + /* secure log */ // exynos_smc(SMC_CMD_LOG, 0, 0, 2); @@ -896,6 +917,27 @@ static u8 exynos_ufs_get_unipro_direct(struct ufs_hba *hba, int num) return unipro_readl(ufs, offset[num]); } +static int exynos_ufs_crypto_engine_cfg(struct ufs_hba *hba, + struct ufshcd_lrb *lrbp, + struct scatterlist *sg, int index, + int sector_offset) +{ + return exynos_ufs_fmp_cfg(hba, lrbp, sg, index, sector_offset); +} + +static int exynos_ufs_crypto_engine_clear(struct ufs_hba *hba, + struct ufshcd_lrb *lrbp) +{ + return exynos_ufs_fmp_clear(hba, lrbp); +} + +static int exynos_ufs_access_control_abort(struct ufs_hba *hba) +{ + struct exynos_ufs *ufs = to_exynos_ufs(hba); + + return exynos_ufs_smu_abort(ufs); +} + static struct ufs_hba_variant_ops exynos_ufs_ops = { .init = exynos_ufs_init, .host_reset = exynos_ufs_host_reset, @@ -910,6 +952,9 @@ static struct ufs_hba_variant_ops exynos_ufs_ops = { .suspend = __exynos_ufs_suspend, .resume = __exynos_ufs_resume, .get_unipro_result = exynos_ufs_get_unipro_direct, + .crypto_engine_cfg = exynos_ufs_crypto_engine_cfg, + .crypto_engine_clear = exynos_ufs_crypto_engine_clear, + .access_control_abort = exynos_ufs_access_control_abort, }; static int exynos_ufs_populate_dt_sys_per_feature(struct device *dev, diff --git a/drivers/scsi/ufs/ufs-exynos.h b/drivers/scsi/ufs/ufs-exynos.h index 4f24951185a4..3ba04b0e8b21 100644 --- a/drivers/scsi/ufs/ufs-exynos.h +++ b/drivers/scsi/ufs/ufs-exynos.h @@ -558,7 +558,6 @@ struct exynos_ufs { struct uic_pwr_mode act_pmd_parm; struct exynos_smu_data smu; - struct exynos_fmp_data fmp; u32 rx_min_actv_time_cap; u32 rx_hibern8_time_cap; diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 5bb632d8f608..b12059e80c52 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -2121,7 +2121,8 @@ static int ufshcd_map_sg(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) struct scatterlist *sg; struct scsi_cmnd *cmd; int sg_segments; - int i; + int i, ret; + int sector_offset = 0; cmd = lrbp->cmd; sg_segments = scsi_dma_map(cmd); @@ -2149,6 +2150,14 @@ static int ufshcd_map_sg(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) prd_table[i].reserved = 0; hba->transferred_sector += prd_table[i].size; + ret = ufshcd_vops_crypto_engine_cfg(hba, lrbp, sg, i, sector_offset); + if (ret) { + dev_err(hba->dev, + "%s: failed to configure crypto engine (%d)\n", + __func__, ret); + return ret; + } + sector_offset += UFSHCI_SECTOR_SIZE / MIN_SECTOR_SIZE; } } else { lrbp->utr_descriptor_ptr->prd_table_length = 0; @@ -4967,6 +4976,12 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, int reason, cmd = lrbp->cmd; if (cmd) { ufshcd_add_command_trace(hba, index, "complete"); + result = ufshcd_vops_crypto_engine_clear(hba, lrbp); + if (result) { + dev_err(hba->dev, + "%s: failed to clear crypto engine (%d)\n", + __func__, result); + } result = ufshcd_transfer_rsp_status(hba, lrbp); cmd->result = result; if (reason) diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 7c88ddd77eed..649ea54c7132 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -339,6 +339,11 @@ struct ufs_hba_variant_ops { void (*dbg_register_dump)(struct ufs_hba *hba); u8 (*get_unipro_result)(struct ufs_hba *hba, int num); int (*phy_initialization)(struct ufs_hba *); + int (*crypto_engine_cfg)(struct ufs_hba *, struct ufshcd_lrb *, + struct scatterlist *, int, int); + int (*crypto_engine_clear)(struct ufs_hba *, struct ufshcd_lrb *); + int (*access_control_abort)(struct ufs_hba *); + }; /* clock gating state */ @@ -1035,4 +1040,29 @@ static inline u8 ufshcd_vops_get_unipro(struct ufs_hba *hba, int num) return 0; } int ufshcd_read_health_desc(struct ufs_hba *hba, u8 *buf, u32 size); +static inline int ufshcd_vops_crypto_engine_cfg(struct ufs_hba *hba, + struct ufshcd_lrb *lrbp, + struct scatterlist *sg, int index, + int sector_offset) +{ + if (hba->vops && hba->vops->crypto_engine_cfg) + return hba->vops->crypto_engine_cfg(hba, lrbp, sg, index, + sector_offset); + return 0; +} + +static inline int ufshcd_vops_crypto_engine_clear(struct ufs_hba *hba, + struct ufshcd_lrb *lrbp) +{ + if (hba->vops && hba->vops->crypto_engine_clear) + return hba->vops->crypto_engine_clear(hba, lrbp); + return 0; +} + +static inline int ufshcd_vops_access_control_abort(struct ufs_hba *hba) +{ + if (hba->vops && hba->vops->access_control_abort) + return hba->vops->access_control_abort(hba); + return 0; +} #endif /* End of Header */ diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h index f9b7f2686d1c..63a22b991014 100644 --- a/drivers/scsi/ufs/ufshci.h +++ b/drivers/scsi/ufs/ufshci.h @@ -258,6 +258,8 @@ enum link_status { UFSHCD_LINK_IS_DOWN = 1, UFSHCD_LINK_IS_UP = 2, }; +#define UFSHCI_SECTOR_SIZE 0x1000 +#define MIN_SECTOR_SIZE 0x200 /* UIC Commands */ enum uic_cmd_dme { @@ -367,10 +369,40 @@ enum { * @size: size of physical segment DW-3 */ struct ufshcd_sg_entry { - __le32 base_addr; - __le32 upper_addr; - __le32 reserved; - __le32 size; + __le32 base_addr; /* des0 */ + __le32 upper_addr; /* des1 */ + __le32 reserved; /* des2 */ + __le32 size; /* des3 */ +#ifdef CONFIG_SCSI_UFS_EXYNOS_FMP + __le32 file_iv0; /* des4 */ + __le32 file_iv1; /* des5 */ + __le32 file_iv2; /* des6 */ + __le32 file_iv3; /* des7 */ + __le32 file_enckey0; /* des8 */ + __le32 file_enckey1; /* des9 */ + __le32 file_enckey2; /* des10 */ + __le32 file_enckey3; /* des11 */ + __le32 file_enckey4; /* des12 */ + __le32 file_enckey5; /* des13 */ + __le32 file_enckey6; /* des14 */ + __le32 file_enckey7; /* des15 */ + __le32 file_twkey0; /* des16 */ + __le32 file_twkey1; /* des17 */ + __le32 file_twkey2; /* des18 */ + __le32 file_twkey3; /* des19 */ + __le32 file_twkey4; /* des20 */ + __le32 file_twkey5; /* des21 */ + __le32 file_twkey6; /* des22 */ + __le32 file_twkey7; /* des23 */ + __le32 disk_iv0; /* des24 */ + __le32 disk_iv1; /* des25 */ + __le32 disk_iv2; /* des26 */ + __le32 disk_iv3; /* des27 */ + __le32 reserved0; /* des28 */ + __le32 reserved1; /* des29 */ + __le32 reserved2; /* des30 */ + __le32 reserved3; /* des31 */ +#endif /* CONFIG_SCSI_UFS_EXYNOS_FMP */ }; /** -- 2.20.1