|
@@ -140,7 +140,8 @@ static void nvm_remove_tgt_dev(struct nvm_tgt_dev *tgt_dev, int clear)
|
|
|
}
|
|
|
|
|
|
static struct nvm_tgt_dev *nvm_create_tgt_dev(struct nvm_dev *dev,
|
|
|
- int lun_begin, int lun_end)
|
|
|
+ u16 lun_begin, u16 lun_end,
|
|
|
+ u16 op)
|
|
|
{
|
|
|
struct nvm_tgt_dev *tgt_dev = NULL;
|
|
|
struct nvm_dev_map *dev_rmap = dev->rmap;
|
|
@@ -219,6 +220,7 @@ static struct nvm_tgt_dev *nvm_create_tgt_dev(struct nvm_dev *dev,
|
|
|
tgt_dev->geo.nr_chnls = nr_chnls;
|
|
|
tgt_dev->geo.all_luns = nr_luns;
|
|
|
tgt_dev->geo.nr_luns = (lun_balanced) ? prev_nr_luns : -1;
|
|
|
+ tgt_dev->geo.op = op;
|
|
|
tgt_dev->total_secs = nr_luns * tgt_dev->geo.sec_per_lun;
|
|
|
tgt_dev->q = dev->q;
|
|
|
tgt_dev->map = dev_map;
|
|
@@ -266,9 +268,57 @@ static struct nvm_tgt_type *nvm_find_target_type(const char *name)
|
|
|
return tt;
|
|
|
}
|
|
|
|
|
|
+static int nvm_config_check_luns(struct nvm_geo *geo, int lun_begin,
|
|
|
+ int lun_end)
|
|
|
+{
|
|
|
+ if (lun_begin > lun_end || lun_end >= geo->all_luns) {
|
|
|
+ pr_err("nvm: lun out of bound (%u:%u > %u)\n",
|
|
|
+ lun_begin, lun_end, geo->all_luns - 1);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int __nvm_config_simple(struct nvm_dev *dev,
|
|
|
+ struct nvm_ioctl_create_simple *s)
|
|
|
+{
|
|
|
+ struct nvm_geo *geo = &dev->geo;
|
|
|
+
|
|
|
+ if (s->lun_begin == -1 && s->lun_end == -1) {
|
|
|
+ s->lun_begin = 0;
|
|
|
+ s->lun_end = geo->all_luns - 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ return nvm_config_check_luns(geo, s->lun_begin, s->lun_end);
|
|
|
+}
|
|
|
+
|
|
|
+static int __nvm_config_extended(struct nvm_dev *dev,
|
|
|
+ struct nvm_ioctl_create_extended *e)
|
|
|
+{
|
|
|
+ struct nvm_geo *geo = &dev->geo;
|
|
|
+
|
|
|
+ if (e->lun_begin == 0xFFFF && e->lun_end == 0xFFFF) {
|
|
|
+ e->lun_begin = 0;
|
|
|
+ e->lun_end = dev->geo.all_luns - 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* op not set falls into target's default */
|
|
|
+ if (e->op == 0xFFFF)
|
|
|
+ e->op = NVM_TARGET_DEFAULT_OP;
|
|
|
+
|
|
|
+ if (e->op < NVM_TARGET_MIN_OP ||
|
|
|
+ e->op > NVM_TARGET_MAX_OP) {
|
|
|
+ pr_err("nvm: invalid over provisioning value\n");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ return nvm_config_check_luns(geo, e->lun_begin, e->lun_end);
|
|
|
+}
|
|
|
+
|
|
|
static int nvm_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create)
|
|
|
{
|
|
|
- struct nvm_ioctl_create_simple *s = &create->conf.s;
|
|
|
+ struct nvm_ioctl_create_extended e;
|
|
|
struct request_queue *tqueue;
|
|
|
struct gendisk *tdisk;
|
|
|
struct nvm_tgt_type *tt;
|
|
@@ -277,6 +327,28 @@ static int nvm_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create)
|
|
|
void *targetdata;
|
|
|
int ret;
|
|
|
|
|
|
+ switch (create->conf.type) {
|
|
|
+ case NVM_CONFIG_TYPE_SIMPLE:
|
|
|
+ ret = __nvm_config_simple(dev, &create->conf.s);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ e.lun_begin = create->conf.s.lun_begin;
|
|
|
+ e.lun_end = create->conf.s.lun_end;
|
|
|
+ e.op = NVM_TARGET_DEFAULT_OP;
|
|
|
+ break;
|
|
|
+ case NVM_CONFIG_TYPE_EXTENDED:
|
|
|
+ ret = __nvm_config_extended(dev, &create->conf.e);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ e = create->conf.e;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ pr_err("nvm: config type not valid\n");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
tt = nvm_find_target_type(create->tgttype);
|
|
|
if (!tt) {
|
|
|
pr_err("nvm: target type %s not found\n", create->tgttype);
|
|
@@ -289,7 +361,7 @@ static int nvm_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create)
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
- ret = nvm_reserve_luns(dev, s->lun_begin, s->lun_end);
|
|
|
+ ret = nvm_reserve_luns(dev, e.lun_begin, e.lun_end);
|
|
|
if (ret)
|
|
|
return ret;
|
|
|
|
|
@@ -299,7 +371,7 @@ static int nvm_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create)
|
|
|
goto err_reserve;
|
|
|
}
|
|
|
|
|
|
- tgt_dev = nvm_create_tgt_dev(dev, s->lun_begin, s->lun_end);
|
|
|
+ tgt_dev = nvm_create_tgt_dev(dev, e.lun_begin, e.lun_end, e.op);
|
|
|
if (!tgt_dev) {
|
|
|
pr_err("nvm: could not create target device\n");
|
|
|
ret = -ENOMEM;
|
|
@@ -369,7 +441,7 @@ err_dev:
|
|
|
err_t:
|
|
|
kfree(t);
|
|
|
err_reserve:
|
|
|
- nvm_release_luns_err(dev, s->lun_begin, s->lun_end);
|
|
|
+ nvm_release_luns_err(dev, e.lun_begin, e.lun_end);
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
@@ -949,7 +1021,6 @@ EXPORT_SYMBOL(nvm_unregister);
|
|
|
static int __nvm_configure_create(struct nvm_ioctl_create *create)
|
|
|
{
|
|
|
struct nvm_dev *dev;
|
|
|
- struct nvm_ioctl_create_simple *s;
|
|
|
|
|
|
down_write(&nvm_lock);
|
|
|
dev = nvm_find_nvm_dev(create->dev);
|
|
@@ -960,23 +1031,6 @@ static int __nvm_configure_create(struct nvm_ioctl_create *create)
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
- if (create->conf.type != NVM_CONFIG_TYPE_SIMPLE) {
|
|
|
- pr_err("nvm: config type not valid\n");
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
- s = &create->conf.s;
|
|
|
-
|
|
|
- if (s->lun_begin == -1 && s->lun_end == -1) {
|
|
|
- s->lun_begin = 0;
|
|
|
- s->lun_end = dev->geo.all_luns - 1;
|
|
|
- }
|
|
|
-
|
|
|
- if (s->lun_begin > s->lun_end || s->lun_end >= dev->geo.all_luns) {
|
|
|
- pr_err("nvm: lun out of bound (%u:%u > %u)\n",
|
|
|
- s->lun_begin, s->lun_end, dev->geo.all_luns - 1);
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
-
|
|
|
return nvm_create_tgt(dev, create);
|
|
|
}
|
|
|
|
|
@@ -1076,6 +1130,12 @@ static long nvm_ioctl_dev_create(struct file *file, void __user *arg)
|
|
|
if (copy_from_user(&create, arg, sizeof(struct nvm_ioctl_create)))
|
|
|
return -EFAULT;
|
|
|
|
|
|
+ if (create.conf.type == NVM_CONFIG_TYPE_EXTENDED &&
|
|
|
+ create.conf.e.rsv != 0) {
|
|
|
+ pr_err("nvm: reserved config field in use\n");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
create.dev[DISK_NAME_LEN - 1] = '\0';
|
|
|
create.tgttype[NVM_TTYPE_NAME_MAX - 1] = '\0';
|
|
|
create.tgtname[DISK_NAME_LEN - 1] = '\0';
|