#include <scsi/scsi_ioctl.h>
#include <scsi/sg.h>
#include <scsi/scsi_dbg.h>
+#include <linux/compat.h>
#include "scsi_logging.h"
#define IOCTL_NORMAL_TIMEOUT (10 * HZ)
#define MAX_BUF PAGE_SIZE
+#define MAX_BUFFLEN (32 * 512)
/**
* ioctl_probe -- return host identification
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];
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) {
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);
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
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,
}
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:
pm_runtime_put_sync(hba->dev);
}
+ hba->host->wlun_clr_uac = true;
if (!hba->is_init_prefetch)
hba->is_init_prefetch = true;