From: hgchu Date: Fri, 12 Jan 2018 07:06:23 +0000 (+0900) Subject: [COMMON] scsi: add ioctl for UFS RPMB X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=071b73acf63416568425058aa9a3d50ab0a3b2dc;p=GitHub%2FLineageOS%2Fandroid_kernel_motorola_exynos9610.git [COMMON] scsi: add ioctl for UFS RPMB Change-Id: I8c2159112235b80b567571d9e87add1e85fd5fbb Signed-off-by: hgchu --- diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index 7440de44dd85..63da33334a0e 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c @@ -706,6 +706,8 @@ int scsi_verify_blk_ioctl(struct block_device *bd, unsigned int cmd) case SG_GET_RESERVED_SIZE: case SG_SET_RESERVED_SIZE: case SG_EMULATED_HOST: + case SCSI_IOCTL_SECURITY_PROTOCOL_IN: + case SCSI_IOCTL_SECURITY_PROTOCOL_OUT: return 0; case CDROM_GET_CAPABILITY: /* Keep this until we remove the printk below. udev sends it diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index 0a875491f5a7..0e6c2f15b46a 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "scsi_logging.h" @@ -29,6 +30,7 @@ #define IOCTL_NORMAL_TIMEOUT (10 * HZ) #define MAX_BUF PAGE_SIZE +#define MAX_BUFFLEN (32 * 512) /** * ioctl_probe -- return host identification @@ -138,6 +140,79 @@ static int ioctl_internal_command(struct scsi_device *sdev, char *cmd, return result; } + +static int ioctl_secu_prot_command(struct scsi_device *sdev, char *cmd, + int prot_in_out, void __user *arg, + int timeout, int retries) +{ + int result, dma_direction; + struct scsi_sense_hdr sshdr; + unsigned char *buf; + unsigned int bufflen; + Scsi_Ioctl_Command __user *s_ioc_arg; + + SCSI_LOG_IOCTL(1, printk("Trying ioctl with scsi command %d\n", *cmd)); + + s_ioc_arg = (Scsi_Ioctl_Command *)kmalloc(sizeof(*s_ioc_arg), GFP_KERNEL); + if (!s_ioc_arg) { + printk(KERN_INFO "%s kmalloc faild\n", __func__); + return -EFAULT; + } + + + if (copy_from_user(s_ioc_arg, arg, sizeof(*s_ioc_arg))) { + printk(KERN_INFO "Argument copy faild\n"); + result = -EFAULT; + goto err_pre_buf_alloc; + } + if (prot_in_out == SCSI_IOCTL_SECURITY_PROTOCOL_IN) { + dma_direction = DMA_FROM_DEVICE; + bufflen = s_ioc_arg->inlen; + buf = kzalloc(bufflen, GFP_KERNEL); + } else if (prot_in_out == SCSI_IOCTL_SECURITY_PROTOCOL_OUT) { + dma_direction = DMA_TO_DEVICE; + bufflen = s_ioc_arg->outlen; + buf = kzalloc(bufflen, GFP_KERNEL); + if (copy_from_user(buf, arg + sizeof(*s_ioc_arg), s_ioc_arg->outlen)) { + printk(KERN_INFO "copy_from_user failed\n"); + result = -EFAULT; + goto err_post_buf_alloc; + } + } else { + sdev_printk(KERN_INFO, sdev, + "prot_in_out not set!! %d\n", prot_in_out); + result = -EFAULT; + goto err_pre_buf_alloc; + } + + result = scsi_execute_req(sdev, cmd, dma_direction, buf, bufflen, + &sshdr, timeout, retries, NULL); + + if (prot_in_out == SCSI_IOCTL_SECURITY_PROTOCOL_IN) { + if (copy_to_user(arg + sizeof(*s_ioc_arg), buf, s_ioc_arg->inlen)) { + printk(KERN_INFO "copy_to_user failed\n"); + result = -EFAULT; + goto err_post_buf_alloc; + } + } + SCSI_LOG_IOCTL(2, printk("Ioctl returned 0x%x\n", result)); + + if ((driver_byte(result) & DRIVER_SENSE) && + (scsi_sense_valid(&sshdr))) { + sdev_printk(KERN_INFO, sdev, + "ioctl_secu_prot_command return code = %x\n", + result); + scsi_print_sense_hdr(sdev, NULL, &sshdr); + } + +err_post_buf_alloc: + kfree(buf); +err_pre_buf_alloc: + kfree(s_ioc_arg); + SCSI_LOG_IOCTL(2, printk("IOCTL Releasing command\n")); + return result; +} + int scsi_set_medium_removal(struct scsi_device *sdev, char state) { char scsi_cmd[MAX_COMMAND_SIZE]; @@ -203,6 +278,8 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) char scsi_cmd[MAX_COMMAND_SIZE]; struct scsi_sense_hdr sense_hdr; + memset(scsi_cmd, 0x0, MAX_COMMAND_SIZE); + /* Check for deprecated ioctls ... all the ioctls which don't * follow the new unique numbering scheme are deprecated */ switch (cmd) { @@ -261,7 +338,44 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) scsi_cmd[4] = 0; return ioctl_internal_command(sdev, scsi_cmd, START_STOP_TIMEOUT, NORMAL_RETRIES); - case SCSI_IOCTL_GET_PCI: + case SCSI_IOCTL_SECURITY_PROTOCOL_IN: + case SCSI_IOCTL_SECURITY_PROTOCOL_OUT: + { + unsigned short prot_spec; + unsigned long t_len; + int _cmd; + struct scsi_ioctl_command *ic = (struct scsi_ioctl_command *) arg; + + _cmd = SCSI_UFS_REQUEST_SENSE; + if(sdev->host->wlun_clr_uac) + sdev->host->hostt->ioctl(sdev, _cmd, NULL); + + prot_spec = SECU_PROT_SPEC_CERT_DATA; + if(cmd == SCSI_IOCTL_SECURITY_PROTOCOL_IN) + t_len = ic->inlen; + else + t_len = ic->outlen; + + scsi_cmd[0] = (cmd == SCSI_IOCTL_SECURITY_PROTOCOL_IN) ? + SECURITY_PROTOCOL_IN : + SECURITY_PROTOCOL_OUT; + scsi_cmd[1] = SECU_PROT_UFS; + scsi_cmd[2] = ((unsigned char)(prot_spec >> 8)) & 0xff; + scsi_cmd[3] = ((unsigned char)(prot_spec)) & 0xff; + scsi_cmd[4] = 0; + scsi_cmd[5] = 0; + scsi_cmd[6] = ((unsigned char)(t_len >> 24)) & 0xff; + scsi_cmd[7] = ((unsigned char)(t_len >> 16)) & 0xff; + scsi_cmd[8] = ((unsigned char)(t_len >> 8)) & 0xff; + scsi_cmd[9] = (unsigned char)t_len & 0xff; + scsi_cmd[10] = 0; + scsi_cmd[11] = 0; + return ioctl_secu_prot_command(sdev, scsi_cmd, + cmd, arg, + START_STOP_TIMEOUT, NORMAL_RETRIES); + } + + case SCSI_IOCTL_GET_PCI: return scsi_ioctl_get_pci(sdev, arg); case SG_SCSI_RESET: return scsi_ioctl_reset(sdev, arg); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 72db0f7d221a..8d352e7f1d98 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1494,6 +1494,8 @@ static int sd_ioctl(struct block_device *bdev, fmode_t mode, switch (cmd) { case SCSI_IOCTL_GET_IDLUN: case SCSI_IOCTL_GET_BUS_NUMBER: + case SCSI_IOCTL_SECURITY_PROTOCOL_IN: + case SCSI_IOCTL_SECURITY_PROTOCOL_OUT: error = scsi_ioctl(sdp, cmd, p); break; default: diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index ba52714674a5..5c0a189c5d7a 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -2374,6 +2374,16 @@ static inline u8 ufshcd_scsi_to_upiu_lun(unsigned int scsi_lun) return scsi_lun & UFS_UPIU_MAX_UNIT_NUM_ID; } +static inline unsigned int ufshcd_get_scsi_lun(struct scsi_cmnd *cmd) +{ + if (cmd->cmnd[0] == SECURITY_PROTOCOL_IN || + cmd->cmnd[0] == SECURITY_PROTOCOL_OUT) + return (SCSI_W_LUN_BASE | + (UFS_UPIU_RPMB_WLUN & UFS_UPIU_MAX_UNIT_NUM_ID)); + else + return cmd->device->lun; +} + /** * ufshcd_upiu_wlun_to_scsi_wlun - maps UPIU W-LUN id to SCSI W-LUN ID * @scsi_lun: UPIU W-LUN id @@ -6346,7 +6356,6 @@ static void ufshcd_init_icc_levels(struct ufs_hba *hba) static int ufshcd_scsi_add_wlus(struct ufs_hba *hba) { int ret = 0; - struct scsi_device *sdev_rpmb; struct scsi_device *sdev_boot; hba->sdev_ufs_device = __scsi_add_device(hba->host, 0, 0, @@ -6366,13 +6375,13 @@ static int ufshcd_scsi_add_wlus(struct ufs_hba *hba) } scsi_device_put(sdev_boot); - sdev_rpmb = __scsi_add_device(hba->host, 0, 0, + hba->sdev_rpmb = __scsi_add_device(hba->host, 0, 0, ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_RPMB_WLUN), NULL); - if (IS_ERR(sdev_rpmb)) { - ret = PTR_ERR(sdev_rpmb); + if (IS_ERR(hba->sdev_rpmb)) { + ret = PTR_ERR(hba->sdev_rpmb); goto remove_sdev_boot; } - scsi_device_put(sdev_rpmb); + scsi_device_put(hba->sdev_rpmb); goto out; remove_sdev_boot: @@ -6805,6 +6814,7 @@ retry: pm_runtime_put_sync(hba->dev); } + hba->host->wlun_clr_uac = true; if (!hba->is_init_prefetch) hba->is_init_prefetch = true; diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 9ee8315c6c01..1e4431a979ff 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -66,6 +66,7 @@ #include #include #include +#include #include "ufs.h" #include "ufshci.h" @@ -544,6 +545,7 @@ struct ufs_hba { * "UFS device" W-LU. */ struct scsi_device *sdev_ufs_device; + struct scsi_device *sdev_rpmb; enum ufs_dev_pwr_mode curr_dev_pwr_mode; enum uic_link_state uic_link_state; diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index bd5d91e119ca..4303079a457d 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -940,6 +940,8 @@ COMPATIBLE_IOCTL(SCSI_IOCTL_GET_BUS_NUMBER) COMPATIBLE_IOCTL(SCSI_IOCTL_SEND_COMMAND) COMPATIBLE_IOCTL(SCSI_IOCTL_PROBE_HOST) COMPATIBLE_IOCTL(SCSI_IOCTL_GET_PCI) +COMPATIBLE_IOCTL(SCSI_IOCTL_SECURITY_PROTOCOL_IN) +COMPATIBLE_IOCTL(SCSI_IOCTL_SECURITY_PROTOCOL_OUT) #endif /* Big V (don't complain on serial console) */ IGNORE_IOCTL(VT_OPENQRY) diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index a8b7bf879ced..b94e887a7b2b 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -701,6 +701,7 @@ struct Scsi_Host { enum scsi_host_state shost_state; + bool wlun_clr_uac; /* ldm bits */ struct device shost_gendev, shost_dev; diff --git a/include/scsi/scsi_ioctl.h b/include/scsi/scsi_ioctl.h index 5101e987c0ef..578817848e85 100644 --- a/include/scsi/scsi_ioctl.h +++ b/include/scsi/scsi_ioctl.h @@ -8,6 +8,8 @@ #define SCSI_IOCTL_SYNC 4 /* Request synchronous parameters */ #define SCSI_IOCTL_START_UNIT 5 #define SCSI_IOCTL_STOP_UNIT 6 +#define SCSI_IOCTL_SECURITY_PROTOCOL_IN 7 +#define SCSI_IOCTL_SECURITY_PROTOCOL_OUT 8 /* The door lock/unlock constants are compatible with Sun constants for the cdrom */ #define SCSI_IOCTL_DOORLOCK 0x5380 /* lock the eject mechanism */ @@ -16,6 +18,8 @@ #define SCSI_REMOVAL_PREVENT 1 #define SCSI_REMOVAL_ALLOW 0 +#define SCSI_UFS_REQUEST_SENSE 0x6000 /* clear UAC in w-lun */ + #ifdef __KERNEL__ struct scsi_device; diff --git a/include/scsi/scsi_proto.h b/include/scsi/scsi_proto.h index 1c41dbcfcb35..68e7e3e18004 100644 --- a/include/scsi/scsi_proto.h +++ b/include/scsi/scsi_proto.h @@ -86,6 +86,8 @@ #define VARIABLE_LENGTH_CMD 0x7f #define REPORT_LUNS 0xa0 #define SECURITY_PROTOCOL_IN 0xa2 +#define SECU_PROT_UFS 0xEC +#define SECU_PROT_SPEC_CERT_DATA 0x0001 #define MAINTENANCE_IN 0xa3 #define MAINTENANCE_OUT 0xa4 #define MOVE_MEDIUM 0xa5