Commit 9f475ebf authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Martin K. Petersen

scsi: gdth: refactor ioc_general

This function is a huge mess with duplicated error handling.  Split out
a few useful helpers and use goto labels to untangle the error handling
and no-data ioctl handling.
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent bfeffd15
...@@ -4155,131 +4155,145 @@ static int ioc_resetdrv(void __user *arg, char *cmnd) ...@@ -4155,131 +4155,145 @@ static int ioc_resetdrv(void __user *arg, char *cmnd)
return 0; return 0;
} }
static int ioc_general(void __user *arg, char *cmnd) static void gdth_ioc_cacheservice(gdth_ha_str *ha, gdth_ioctl_general *gen,
u64 paddr)
{ {
gdth_ioctl_general gen; if (ha->cache_feat & GDT_64BIT) {
char *buf = NULL; /* copy elements from 32-bit IOCTL structure */
u64 paddr; gen->command.u.cache64.BlockCnt = gen->command.u.cache.BlockCnt;
gdth_ha_str *ha; gen->command.u.cache64.BlockNo = gen->command.u.cache.BlockNo;
int rval; gen->command.u.cache64.DeviceNo = gen->command.u.cache.DeviceNo;
if (ha->cache_feat & SCATTER_GATHER) {
gen->command.u.cache64.DestAddr = (u64)-1;
gen->command.u.cache64.sg_canz = 1;
gen->command.u.cache64.sg_lst[0].sg_ptr = paddr;
gen->command.u.cache64.sg_lst[0].sg_len = gen->data_len;
gen->command.u.cache64.sg_lst[1].sg_len = 0;
} else {
gen->command.u.cache64.DestAddr = paddr;
gen->command.u.cache64.sg_canz = 0;
}
} else {
if (ha->cache_feat & SCATTER_GATHER) {
gen->command.u.cache.DestAddr = 0xffffffff;
gen->command.u.cache.sg_canz = 1;
gen->command.u.cache.sg_lst[0].sg_ptr = (u32)paddr;
gen->command.u.cache.sg_lst[0].sg_len = gen->data_len;
gen->command.u.cache.sg_lst[1].sg_len = 0;
} else {
gen->command.u.cache.DestAddr = paddr;
gen->command.u.cache.sg_canz = 0;
}
}
}
if (copy_from_user(&gen, arg, sizeof(gdth_ioctl_general))) static void gdth_ioc_scsiraw(gdth_ha_str *ha, gdth_ioctl_general *gen,
return -EFAULT; u64 paddr)
ha = gdth_find_ha(gen.ionode); {
if (!ha) if (ha->raw_feat & GDT_64BIT) {
return -EFAULT; /* copy elements from 32-bit IOCTL structure */
char cmd[16];
gen->command.u.raw64.sense_len = gen->command.u.raw.sense_len;
gen->command.u.raw64.bus = gen->command.u.raw.bus;
gen->command.u.raw64.lun = gen->command.u.raw.lun;
gen->command.u.raw64.target = gen->command.u.raw.target;
memcpy(cmd, gen->command.u.raw.cmd, 16);
memcpy(gen->command.u.raw64.cmd, cmd, 16);
gen->command.u.raw64.clen = gen->command.u.raw.clen;
gen->command.u.raw64.sdlen = gen->command.u.raw.sdlen;
gen->command.u.raw64.direction = gen->command.u.raw.direction;
/* addresses */
if (ha->raw_feat & SCATTER_GATHER) {
gen->command.u.raw64.sdata = (u64)-1;
gen->command.u.raw64.sg_ranz = 1;
gen->command.u.raw64.sg_lst[0].sg_ptr = paddr;
gen->command.u.raw64.sg_lst[0].sg_len = gen->data_len;
gen->command.u.raw64.sg_lst[1].sg_len = 0;
} else {
gen->command.u.raw64.sdata = paddr;
gen->command.u.raw64.sg_ranz = 0;
}
if (gen.data_len > INT_MAX) gen->command.u.raw64.sense_data = paddr + gen->data_len;
return -EINVAL; } else {
if (gen.sense_len > INT_MAX) if (ha->raw_feat & SCATTER_GATHER) {
return -EINVAL; gen->command.u.raw.sdata = 0xffffffff;
if (gen.data_len + gen.sense_len > INT_MAX) gen->command.u.raw.sg_ranz = 1;
return -EINVAL; gen->command.u.raw.sg_lst[0].sg_ptr = (u32)paddr;
gen->command.u.raw.sg_lst[0].sg_len = gen->data_len;
gen->command.u.raw.sg_lst[1].sg_len = 0;
} else {
gen->command.u.raw.sdata = paddr;
gen->command.u.raw.sg_ranz = 0;
}
if (gen.data_len + gen.sense_len != 0) { gen->command.u.raw.sense_data = (u32)paddr + gen->data_len;
if (!(buf = gdth_ioctl_alloc(ha, gen.data_len + gen.sense_len, }
FALSE, &paddr))) }
return -EFAULT;
if (copy_from_user(buf, arg + sizeof(gdth_ioctl_general),
gen.data_len + gen.sense_len)) {
gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr);
return -EFAULT;
}
if (gen.command.OpCode == GDT_IOCTL) { static int ioc_general(void __user *arg, char *cmnd)
gen.command.u.ioctl.p_param = paddr; {
} else if (gen.command.Service == CACHESERVICE) { gdth_ioctl_general gen;
if (ha->cache_feat & GDT_64BIT) { gdth_ha_str *ha;
/* copy elements from 32-bit IOCTL structure */ char *buf = NULL;
gen.command.u.cache64.BlockCnt = gen.command.u.cache.BlockCnt; u64 paddr;
gen.command.u.cache64.BlockNo = gen.command.u.cache.BlockNo; int rval;
gen.command.u.cache64.DeviceNo = gen.command.u.cache.DeviceNo;
/* addresses */ if (copy_from_user(&gen, arg, sizeof(gdth_ioctl_general)))
if (ha->cache_feat & SCATTER_GATHER) { return -EFAULT;
gen.command.u.cache64.DestAddr = (u64)-1; ha = gdth_find_ha(gen.ionode);
gen.command.u.cache64.sg_canz = 1; if (!ha)
gen.command.u.cache64.sg_lst[0].sg_ptr = paddr; return -EFAULT;
gen.command.u.cache64.sg_lst[0].sg_len = gen.data_len;
gen.command.u.cache64.sg_lst[1].sg_len = 0; if (gen.data_len > INT_MAX)
} else { return -EINVAL;
gen.command.u.cache64.DestAddr = paddr; if (gen.sense_len > INT_MAX)
gen.command.u.cache64.sg_canz = 0; return -EINVAL;
} if (gen.data_len + gen.sense_len > INT_MAX)
} else { return -EINVAL;
if (ha->cache_feat & SCATTER_GATHER) {
gen.command.u.cache.DestAddr = 0xffffffff; if (gen.data_len + gen.sense_len > 0) {
gen.command.u.cache.sg_canz = 1; buf = gdth_ioctl_alloc(ha, gen.data_len + gen.sense_len, FALSE,
gen.command.u.cache.sg_lst[0].sg_ptr = (u32)paddr; &paddr);
gen.command.u.cache.sg_lst[0].sg_len = gen.data_len; if (!buf)
gen.command.u.cache.sg_lst[1].sg_len = 0; return -EFAULT;
} else {
gen.command.u.cache.DestAddr = paddr; rval = -EFAULT;
gen.command.u.cache.sg_canz = 0; if (copy_from_user(buf, arg + sizeof(gdth_ioctl_general),
} gen.data_len + gen.sense_len))
} goto out_free_buf;
} else if (gen.command.Service == SCSIRAWSERVICE) {
if (ha->raw_feat & GDT_64BIT) { if (gen.command.OpCode == GDT_IOCTL)
/* copy elements from 32-bit IOCTL structure */ gen.command.u.ioctl.p_param = paddr;
char cmd[16]; else if (gen.command.Service == CACHESERVICE)
gen.command.u.raw64.sense_len = gen.command.u.raw.sense_len; gdth_ioc_cacheservice(ha, &gen, paddr);
gen.command.u.raw64.bus = gen.command.u.raw.bus; else if (gen.command.Service == SCSIRAWSERVICE)
gen.command.u.raw64.lun = gen.command.u.raw.lun; gdth_ioc_scsiraw(ha, &gen, paddr);
gen.command.u.raw64.target = gen.command.u.raw.target; else
memcpy(cmd, gen.command.u.raw.cmd, 16); goto out_free_buf;
memcpy(gen.command.u.raw64.cmd, cmd, 16); }
gen.command.u.raw64.clen = gen.command.u.raw.clen;
gen.command.u.raw64.sdlen = gen.command.u.raw.sdlen;
gen.command.u.raw64.direction = gen.command.u.raw.direction;
/* addresses */
if (ha->raw_feat & SCATTER_GATHER) {
gen.command.u.raw64.sdata = (u64)-1;
gen.command.u.raw64.sg_ranz = 1;
gen.command.u.raw64.sg_lst[0].sg_ptr = paddr;
gen.command.u.raw64.sg_lst[0].sg_len = gen.data_len;
gen.command.u.raw64.sg_lst[1].sg_len = 0;
} else {
gen.command.u.raw64.sdata = paddr;
gen.command.u.raw64.sg_ranz = 0;
}
gen.command.u.raw64.sense_data = paddr + gen.data_len;
} else {
if (ha->raw_feat & SCATTER_GATHER) {
gen.command.u.raw.sdata = 0xffffffff;
gen.command.u.raw.sg_ranz = 1;
gen.command.u.raw.sg_lst[0].sg_ptr = (u32)paddr;
gen.command.u.raw.sg_lst[0].sg_len = gen.data_len;
gen.command.u.raw.sg_lst[1].sg_len = 0;
} else {
gen.command.u.raw.sdata = paddr;
gen.command.u.raw.sg_ranz = 0;
}
gen.command.u.raw.sense_data = (u32)paddr + gen.data_len;
}
} else {
gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr);
return -EFAULT;
}
}
rval = __gdth_execute(ha->sdev, &gen.command, cmnd, gen.timeout, &gen.info); rval = __gdth_execute(ha->sdev, &gen.command, cmnd, gen.timeout,
if (rval < 0) { &gen.info);
if (rval < 0)
goto out_free_buf;
gen.status = rval;
rval = -EFAULT;
if (copy_to_user(arg + sizeof(gdth_ioctl_general), buf,
gen.data_len + gen.sense_len))
goto out_free_buf;
if (copy_to_user(arg, &gen,
sizeof(gdth_ioctl_general) - sizeof(gdth_cmd_str)))
goto out_free_buf;
rval = 0;
out_free_buf:
gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr); gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr);
return rval; return rval;
}
gen.status = rval;
if (copy_to_user(arg + sizeof(gdth_ioctl_general), buf,
gen.data_len + gen.sense_len)) {
gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr);
return -EFAULT;
}
if (copy_to_user(arg, &gen,
sizeof(gdth_ioctl_general) - sizeof(gdth_cmd_str))) {
gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr);
return -EFAULT;
}
gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr);
return 0;
} }
static int ioc_hdrlist(void __user *arg, char *cmnd) static int ioc_hdrlist(void __user *arg, char *cmnd)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment